Skip to content

Commit 927f23a

Browse files
committed
Add a memory bench
1 parent d16e389 commit 927f23a

File tree

3 files changed

+167
-1
lines changed

3 files changed

+167
-1
lines changed

.github/workflows/perf-ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# * startup speed (== to parse and load all rules)
44
# * network filter matching (== the avg time to check a request)
55
# * first request matching delay (== time to check the first request)
6+
# * memory usage after loading rules and after a few requests
67
name: Performance CI
78

89
on:
@@ -36,8 +37,11 @@ jobs:
3637
- name: Bench startup speed
3738
run: cargo bench --bench bench_rules blocker_new/brave-list -- --output-format bencher | tee -a output.txt
3839

40+
- name: Bench memory usage
41+
run: cargo bench --bench bench_memory -- --output-format bencher | tee -a output.txt
42+
3943
- name: Store benchmark result
40-
uses: benchmark-action/github-action-benchmark@6bae118c112083251560ad8b3a1ff2e43aa23351 # v1
44+
uses: benchmark-action/github-action-benchmark@v1.20.4
4145
with:
4246
name: Rust Benchmark
4347
tool: 'cargo'

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ harness = false
7575
name = "bench_redirect_performance"
7676
harness = false
7777

78+
79+
[[bench]]
80+
name = "bench_memory"
81+
harness = false
82+
7883
# Currently disabled, as cosmetic filter internals
7984
# are no longer part of the crate's public API
8085
#[[bench]]

benches/bench_memory.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/* Copyright (c) 2025 The Brave Authors. All rights reserved.
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
* You can obtain one at https://mozilla.org/MPL/2.0/. */
5+
6+
use criterion::*;
7+
use std::alloc::{GlobalAlloc, Layout, System};
8+
use std::sync::atomic::{AtomicUsize, Ordering};
9+
use serde::{Deserialize, Serialize};
10+
11+
use adblock::Engine;
12+
use adblock::request::Request;
13+
14+
#[path = "../tests/test_utils.rs"]
15+
mod test_utils;
16+
use test_utils::rules_from_lists;
17+
18+
// Custom allocator to track memory usage
19+
#[global_allocator]
20+
static ALLOCATOR: MemoryTracker = MemoryTracker::new();
21+
22+
struct MemoryTracker {
23+
allocated: AtomicUsize,
24+
internal: System,
25+
}
26+
27+
impl MemoryTracker {
28+
const fn new() -> Self {
29+
Self {
30+
allocated: AtomicUsize::new(0),
31+
internal: System,
32+
}
33+
}
34+
35+
fn current_usage(&self) -> usize {
36+
self.allocated.load(Ordering::SeqCst)
37+
}
38+
39+
fn reset(&self) {
40+
self.allocated.store(0, Ordering::SeqCst);
41+
}
42+
}
43+
44+
unsafe impl GlobalAlloc for MemoryTracker {
45+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
46+
let ret = self.internal.alloc(layout);
47+
if !ret.is_null() {
48+
self.allocated.fetch_add(layout.size(), Ordering::SeqCst);
49+
}
50+
ret
51+
}
52+
53+
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
54+
self.internal.dealloc(ptr, layout);
55+
self.allocated.fetch_sub(layout.size(), Ordering::SeqCst);
56+
}
57+
58+
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
59+
let ret = self.internal.realloc(ptr, layout, new_size);
60+
if !ret.is_null() {
61+
self.allocated.fetch_sub(layout.size(), Ordering::SeqCst);
62+
self.allocated.fetch_add(new_size, Ordering::SeqCst);
63+
}
64+
ret
65+
}
66+
67+
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
68+
let ret = self.internal.alloc_zeroed(layout);
69+
if !ret.is_null() {
70+
self.allocated.fetch_add(layout.size(), Ordering::SeqCst);
71+
}
72+
ret
73+
}
74+
}
75+
76+
#[allow(non_snake_case)]
77+
#[derive(Serialize, Deserialize, Clone)]
78+
struct TestRequest {
79+
frameUrl: String,
80+
url: String,
81+
cpt: String,
82+
}
83+
84+
impl From<&TestRequest> for Request {
85+
fn from(v: &TestRequest) -> Self {
86+
Request::new(&v.url, &v.frameUrl, &v.cpt).unwrap()
87+
}
88+
}
89+
90+
fn load_requests() -> Vec<TestRequest> {
91+
let requests_str = rules_from_lists(&["data/requests.json"]);
92+
let reqs: Vec<TestRequest> = requests_str
93+
.into_iter()
94+
.map(|r| serde_json::from_str(&r))
95+
.filter_map(Result::ok)
96+
.collect();
97+
reqs
98+
}
99+
100+
fn bench_memory_usage(c: &mut Criterion) {
101+
let mut group = c.benchmark_group("memory-usage");
102+
group.sample_size(10);
103+
group.measurement_time(std::time::Duration::from_secs(1));
104+
105+
let mut noise = 0;
106+
let all_requests = load_requests();
107+
let first_1000_requests: Vec<_> = all_requests.iter().take(1000).collect();
108+
109+
group.bench_function("brave-list-initial", |b| {
110+
let mut result = 0;
111+
b.iter_custom(|iters| {
112+
for _ in 0..iters {
113+
ALLOCATOR.reset();
114+
let rules = rules_from_lists(&["data/brave/brave-main-list.txt"]);
115+
let engine = Engine::from_rules(rules, Default::default());
116+
117+
noise += 1; // add some noise to make criterion happy
118+
result += ALLOCATOR.current_usage() + noise;
119+
120+
// Prevent engine from being optimized
121+
criterion::black_box(&engine);
122+
}
123+
124+
// Return the memory usage as a Duration
125+
std::time::Duration::from_nanos(result as u64)
126+
});
127+
});
128+
129+
group.bench_function("brave-list-after-1000-requests", |b| {
130+
b.iter_custom(|iters| {
131+
let mut result = 0;
132+
for _ in 0..iters {
133+
ALLOCATOR.reset();
134+
let rules = rules_from_lists(&["data/brave/brave-main-list.txt"]);
135+
let engine = Engine::from_rules(rules, Default::default());
136+
137+
for request in first_1000_requests.clone() {
138+
criterion::black_box(engine.check_network_request(&request.into()));
139+
}
140+
141+
noise += 1; // add some noise to make criterion happy
142+
result += ALLOCATOR.current_usage() + noise;
143+
144+
// Prevent engine from being optimized
145+
criterion::black_box(&engine);
146+
}
147+
148+
// Return the memory usage as a Duration
149+
std::time::Duration::from_nanos(result as u64)
150+
})
151+
});
152+
153+
group.finish();
154+
}
155+
156+
criterion_group!(benches, bench_memory_usage);
157+
criterion_main!(benches);

0 commit comments

Comments
 (0)