Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a7dd17e
Refactor is bad filter (0.13.x) (#641)
atuchin-m May 11, 2026
a2d591a
Refactor more mask items (0.13.x) (#642)
atuchin-m May 12, 2026
43b21d2
Set mask default to save memory (#639)
atuchin-m May 12, 2026
7ca6656
[perf, memory] Add single/multi_pattern to optimize memory usage (0.1…
atuchin-m May 12, 2026
7881c97
add test for default flatbuffer NetworkFilterMask
antonok-edm May 12, 2026
91ec661
New API for FilterSet & Engine (#652)
atuchin-m May 28, 2026
be79a5c
Streaming filter parsing (#653)
atuchin-m Jun 5, 2026
b5f9c98
[perf] Use Cow/&str in network filter parsing (#664)
atuchin-m Jun 8, 2026
f7ca328
Speedup get_id() (#670)
atuchin-m Jun 11, 2026
1a9420b
Add HTTP method (HEAD, POST, GET) support to NetworkFilter parsing,
boocmp Jun 5, 2026
5b5bf20
Added support for HTTP methods (GET, HEAD, POST) in Request and Netwo…
boocmp Jun 5, 2026
b26ad89
Extended request API to accept optional HTTP method parameter.
boocmp Jun 5, 2026
7d25992
Removed new_with_method fn.
boocmp Jun 5, 2026
759e3cf
Improved NetworkFilter tests readability.
boocmp Jun 10, 2026
0c79cfb
Added deprecation warning for passing debug as the 4th argument.
boocmp Jun 11, 2026
3dad769
Renamed FROM_METHODS to FROM_ANY_METHODS.
boocmp Jun 11, 2026
86b1692
Extended RequestMethod enum to include all HTTP methods.
boocmp Jun 11, 2026
f62d5fa
Using 'get' method and added error handling for generichide method co…
boocmp Jun 11, 2026
198b7e4
[perf] Optimize optimizer::*
atuchin-m Jun 10, 2026
cb4e3f5
Fix raw_line issues
atuchin-m Jun 25, 2026
0b38737
Remove optimize param from Engine (#668)
atuchin-m Jun 27, 2026
e4bfad6
Added parser for $to option in NetworkFilter.
boocmp Jun 12, 2026
07fadd4
Added matching.
boocmp Jul 1, 2026
174706a
Separated to and from hashes.
boocmp Jul 1, 2026
f466e19
Perf and wildcards.
boocmp Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions benches/bench_cosmetic_matching.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use adblock::lists::FilterSet;
use adblock::Engine;
use criterion::*;

Expand All @@ -7,10 +8,12 @@ mod test_utils;
pub fn make_engine() -> Engine {
use adblock::resources::Resource;

let rules = test_utils::rules_from_lists(&["data/brave/brave-main-list.txt"]);
let rules = test_utils::rules_from_lists(["data/brave/brave-main-list.txt"]);
let resource_json = std::fs::read_to_string("data/brave/brave-resources.json").unwrap();
let resource_list: Vec<Resource> = serde_json::from_str(&resource_json).unwrap();
let mut engine = Engine::from_rules_parametrised(rules, Default::default(), true, true);
let mut filter_set = FilterSet::new(true);
filter_set.add_filter_list(rules, Default::default());
let mut engine = Engine::new_with_filter_set(filter_set);
engine.use_resources(resource_list);
engine
}
Expand Down
72 changes: 31 additions & 41 deletions benches/bench_matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};

use adblock::request::Request;
use adblock::url_parser::parse_url;
use adblock::{Engine, FilterSet};
use adblock::Engine;

#[path = "../tests/test_utils.rs"]
mod test_utils;
Expand All @@ -20,30 +20,20 @@ struct TestRequest {

impl From<&TestRequest> for Request {
fn from(v: &TestRequest) -> Self {
Request::new(&v.url, &v.frameUrl, &v.cpt).unwrap()
Request::new(&v.url, &v.frameUrl, &v.cpt, "").unwrap()
}
}

fn load_requests() -> Vec<TestRequest> {
let requests_str = rules_from_lists(&["data/requests.json"]);
let requests_str = rules_from_lists(["data/requests.json"]);
let reqs: Vec<TestRequest> = requests_str
.into_iter()
.map(|r| serde_json::from_str(&r))
.lines()
.map(serde_json::from_str)
.filter_map(Result::ok)
.collect();
reqs
}

fn get_engine(rules: impl IntoIterator<Item = impl AsRef<str>>) -> Engine {
let (network_filters, cosmetic_filters) =
adblock::lists::parse_filters(rules, false, Default::default());

Engine::from_filter_set(
FilterSet::new_with_rules(network_filters, cosmetic_filters, false),
true,
)
}

fn bench_rule_matching(engine: &Engine, requests: &[TestRequest]) -> (u32, u32) {
let mut matches = 0;
let mut passes = 0;
Expand Down Expand Up @@ -87,6 +77,7 @@ fn bench_rule_matching_browserlike(blocker: &Engine, requests: &[ParsedRequest])
source_hostname,
request_type,
*third_party,
"",
));
if check.matched {
matches += 1;
Expand All @@ -112,21 +103,21 @@ fn rule_match(c: &mut Criterion) {
group.sample_size(10);

group.bench_function("el+ep", move |b| {
let rules = rules_from_lists(&[
let rules = rules_from_lists([
"data/easylist.to/easylist/easylist.txt",
"data/easylist.to/easylist/easyprivacy.txt",
]);
let engine = Engine::from_rules(rules, Default::default());
let engine = Engine::new_with_list_text(rules);
b.iter(|| bench_rule_matching(&engine, &elep_req))
});
group.bench_function("easylist", move |b| {
let rules = rules_from_lists(&["data/easylist.to/easylist/easylist.txt"]);
let engine = Engine::from_rules(rules, Default::default());
let rules = rules_from_lists(["data/easylist.to/easylist/easylist.txt"]);
let engine = Engine::new_with_list_text(rules);
b.iter(|| bench_rule_matching(&engine, &el_req))
});
group.bench_function("slimlist", move |b| {
let rules = rules_from_lists(&["data/slim-list.txt"]);
let engine = Engine::from_rules(rules, Default::default());
let rules = rules_from_lists(["data/slim-list.txt"]);
let engine = Engine::new_with_list_text(rules);
b.iter(|| bench_rule_matching(&engine, &slim_req))
});

Expand All @@ -136,15 +127,15 @@ fn rule_match(c: &mut Criterion) {
fn rule_match_parsed_el(c: &mut Criterion) {
let mut group = c.benchmark_group("rule-match-parsed");

let rules = rules_from_lists(&["data/easylist.to/easylist/easylist.txt"]);
let rules = rules_from_lists(["data/easylist.to/easylist/easylist.txt"]);
let requests = load_requests();
let requests_parsed: Vec<_> = requests
.into_iter()
.map(|r| Request::new(&r.url, &r.frameUrl, &r.cpt))
.map(|r| Request::new(&r.url, &r.frameUrl, &r.cpt, ""))
.filter_map(Result::ok)
.collect();
let requests_len = requests_parsed.len() as u64;
let engine = get_engine(rules);
let engine = Engine::new_with_list_text(rules);

group.throughput(Throughput::Elements(requests_len));
group.sample_size(10);
Expand All @@ -159,27 +150,27 @@ fn rule_match_parsed_el(c: &mut Criterion) {
fn rule_match_parsed_elep_slimlist(c: &mut Criterion) {
let mut group = c.benchmark_group("rule-match-parsed");

let full_rules = rules_from_lists(&[
let full_rules = rules_from_lists([
"data/easylist.to/easylist/easylist.txt",
"data/easylist.to/easylist/easyprivacy.txt",
]);
let engine = get_engine(full_rules);
let engine = Engine::new_with_list_text(full_rules);

let requests = load_requests();
let requests_parsed: Vec<_> = requests
.into_iter()
.map(|r| Request::new(&r.url, &r.frameUrl, &r.cpt))
.map(|r| Request::new(&r.url, &r.frameUrl, &r.cpt, ""))
.filter_map(Result::ok)
.collect();
let requests_len = requests_parsed.len() as u64;

let slim_rules = rules_from_lists(&["data/slim-list.txt"]);
let slim_engine = get_engine(slim_rules);
let slim_rules = rules_from_lists(["data/slim-list.txt"]);
let slim_engine = Engine::new_with_list_text(slim_rules);

let requests_copy = load_requests();
let requests_parsed_copy: Vec<_> = requests_copy
.into_iter()
.map(|r| Request::new(&r.url, &r.frameUrl, &r.cpt))
.map(|r| Request::new(&r.url, &r.frameUrl, &r.cpt, ""))
.filter_map(Result::ok)
.collect();

Expand Down Expand Up @@ -245,26 +236,26 @@ fn rule_match_browserlike_comparable(c: &mut Criterion) {
let requests = requests_parsed(&requests);

group.bench_function("el+ep", |b| {
let rules = rules_from_lists(&[
let rules = rules_from_lists([
"data/easylist.to/easylist/easylist.txt",
"data/easylist.to/easylist/easyprivacy.txt",
]);
let engine = Engine::from_rules_parametrised(rules, Default::default(), false, true);
let engine = Engine::new_with_list_text(rules);
b.iter(|| bench_rule_matching_browserlike(&engine, &requests))
});
group.bench_function("el", |b| {
let rules = rules_from_lists(&["data/easylist.to/easylist/easylist.txt"]);
let engine = Engine::from_rules_parametrised(rules, Default::default(), false, true);
let rules = rules_from_lists(["data/easylist.to/easylist/easylist.txt"]);
let engine = Engine::new_with_list_text(rules);
b.iter(|| bench_rule_matching_browserlike(&engine, &requests))
});
group.bench_function("slimlist", |b| {
let rules = rules_from_lists(&["data/slim-list.txt"]);
let engine = Engine::from_rules_parametrised(rules, Default::default(), false, true);
let rules = rules_from_lists(["data/slim-list.txt"]);
let engine = Engine::new_with_list_text(rules);
b.iter(|| bench_rule_matching_browserlike(&engine, &requests))
});
group.bench_function("brave-list", |b| {
let rules = rules_from_lists(&["data/brave/brave-main-list.txt"]);
let engine = Engine::from_rules_parametrised(rules, Default::default(), false, true);
let rules = rules_from_lists(["data/brave/brave-main-list.txt"]);
let engine = Engine::new_with_list_text(rules);
b.iter(|| bench_rule_matching_browserlike(&engine, &requests))
});

Expand All @@ -288,9 +279,8 @@ fn rule_match_first_request(c: &mut Criterion) {
b.iter_custom(|iters| {
let mut total_time = std::time::Duration::ZERO;
for _ in 0..iters {
let rules = rules_from_lists(&["data/brave/brave-main-list.txt"]);
let engine =
Engine::from_rules_parametrised(rules, Default::default(), false, true);
let rules = rules_from_lists(["data/brave/brave-main-list.txt"]);
let engine = Engine::new_with_list_text(rules);

// Measure only the matching time, skip setup and destruction
let start_time = std::time::Instant::now();
Expand Down
12 changes: 6 additions & 6 deletions benches/bench_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,15 @@ struct TestRequest {

impl From<&TestRequest> for Request {
fn from(v: &TestRequest) -> Self {
Request::new(&v.url, &v.frameUrl, &v.cpt).unwrap()
Request::new(&v.url, &v.frameUrl, &v.cpt, "").unwrap()
}
}

fn load_requests() -> Vec<TestRequest> {
let requests_str = rules_from_lists(&["data/requests.json"]);
let requests_str = rules_from_lists(["data/requests.json"]);
let reqs: Vec<TestRequest> = requests_str
.into_iter()
.map(|r| serde_json::from_str(&r))
.lines()
.map(serde_json::from_str)
.filter_map(Result::ok)
.collect();
reqs
Expand Down Expand Up @@ -243,8 +243,8 @@ fn bench_cb(
) {
let single_run = || {
ALLOCATOR.reset();
let rules = rules_from_lists(&["data/brave/brave-main-list.txt"]);
let mut engine = Engine::from_rules(rules, Default::default());
let rules = rules_from_lists(["data/brave/brave-main-list.txt"]);
let mut engine = Engine::new_with_list_text(rules);
let resource_json = std::fs::read_to_string("data/brave/brave-resources.json").unwrap();
let resource_list: Vec<Resource> = serde_json::from_str(&resource_json).unwrap();
std::mem::drop(resource_json);
Expand Down
46 changes: 28 additions & 18 deletions benches/bench_redirect_performance.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use adblock::{Engine, FilterSet};
use std::borrow::Cow;
use std::sync::OnceLock;

use adblock::Engine;
use criterion::*;
use tokio::runtime::Runtime;

use adblock::filters::network::{NetworkFilter, NetworkFilterMask, NetworkFilterMaskHelper};
use adblock::filters::network::{NetworkFilter, NetworkFilterMask};
use adblock::request::Request;
use adblock::resources::Resource;

Expand Down Expand Up @@ -55,23 +58,31 @@ async fn get_all_filters() -> Vec<String> {
.collect()
}

/// Gets all rules with redirects, and modifies them to apply to resources at `a{0-n}.com/bad.js`
fn get_redirect_rules() -> Vec<NetworkFilter> {
let async_runtime = Runtime::new().expect("Could not start Tokio runtime");
static ALL_FILTERS: OnceLock<Box<[String]>> = OnceLock::new();

let filters = async_runtime.block_on(get_all_filters());
let (network_filters, _) = adblock::lists::parse_filters(&filters, true, Default::default());
fn all_filters() -> &'static [String] {
ALL_FILTERS.get_or_init(|| {
let async_runtime = Runtime::new().expect("Could not start Tokio runtime");
async_runtime.block_on(get_all_filters()).into_boxed_slice()
})
}

/// Gets all rules with redirects, and modifies them to apply to resources at `a{0-n}.com/bad.js`
fn get_redirect_rules() -> Vec<NetworkFilter<'static>> {
let filters = all_filters();
let (network_filters, _) =
adblock::lists::parse_filters(filters.iter().map(|s| s.as_str()), true, Default::default());

network_filters
.into_iter()
.filter(NetworkFilter::is_redirect)
.filter(NetworkFilter::also_block_redirect)
.filter(|rule| rule.modifier_option.as_ref().unwrap() != "none")
.filter(|rule| rule.modifier_option.unwrap() != "none")
.enumerate()
.map(|(index, mut rule)| {
rule.mask.insert(NetworkFilterMask::IS_LEFT_ANCHOR);
rule.mask.insert(NetworkFilterMask::IS_RIGHT_ANCHOR);
rule.hostname = Some(format!("a{index}.com/bad.js"));
rule.hostname = Some(Cow::Owned(format!("a{index}.com/bad.js")));

rule.filter = adblock::filters::network::FilterPart::Empty;
rule.mask.remove(NetworkFilterMask::IS_HOSTNAME_ANCHOR);
Expand All @@ -86,8 +97,7 @@ fn get_redirect_rules() -> Vec<NetworkFilter> {

/// Loads the supplied rules, and the test set of resources, into a Engine
fn get_preloaded_engine(rules: Vec<NetworkFilter>) -> Engine {
let filter_set = FilterSet::new_with_rules(rules, vec![], false);
Engine::from_filter_set(filter_set, true /* optimize */)
Engine::new_with_parsed_rules(rules, vec![])
}

fn get_resources_for_filters(#[allow(unused)] filters: &[NetworkFilter]) -> Vec<Resource> {
Expand Down Expand Up @@ -118,17 +128,17 @@ fn get_resources_for_filters(#[allow(unused)] filters: &[NetworkFilter]) -> Vec<
.iter()
.filter(|f| f.is_redirect())
.map(|f| {
let mut redirect = f.modifier_option.as_ref().unwrap().as_str();
let mut redirect = f.modifier_option.as_ref().unwrap().to_string();
// strip priority, if present
if let Some(i) = redirect.rfind(':') {
redirect = &redirect[0..i];
redirect.truncate(i);
}

Resource {
name: redirect.to_owned(),
name: redirect.clone(),
aliases: vec![],
kind: ResourceType::Mime(MimeType::from_extension(redirect)),
content: BASE64_STANDARD.encode(redirect),
kind: ResourceType::Mime(MimeType::from_extension(&redirect)),
content: BASE64_STANDARD.encode(&redirect),
dependencies: vec![],
permission: Default::default(),
}
Expand Down Expand Up @@ -175,7 +185,7 @@ pub fn build_custom_requests(rules: Vec<NetworkFilter>) -> Vec<Request> {
let domain = &rule_hostname[..rule_hostname.find('/').unwrap()];
let hostname = domain;

let raw_line = rule.raw_line.clone().unwrap();
let raw_line = rule.raw_line.as_deref().unwrap().to_string();
let source_hostname = if rule.opt_domains.is_some() {
let domain_start = raw_line.rfind("domain=").unwrap() + "domain=".len();
let from_start = &raw_line[domain_start..];
Expand All @@ -194,7 +204,7 @@ pub fn build_custom_requests(rules: Vec<NetworkFilter>) -> Vec<Request> {

let source_url = format!("https://{source_hostname}");

Request::new(&url, &source_url, raw_type).unwrap()
Request::new(&url, &source_url, raw_type, "").unwrap()
})
.collect::<Vec<_>>()
}
Expand Down
Loading
Loading