Skip to content

Commit d6fe654

Browse files
committed
bench: add a benchmark for measuring the time it takes to handle a sync update in the event cache
1 parent 2710510 commit d6fe654

File tree

4 files changed

+170
-0
lines changed

4 files changed

+170
-0
lines changed

benchmarks/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,7 @@ harness = false
4747
[[bench]]
4848
name = "timeline"
4949
harness = false
50+
51+
[[bench]]
52+
name = "event_cache"
53+
harness = false

benchmarks/benches/event_cache.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
use std::{
2+
sync::Arc,
3+
time::{Duration, Instant},
4+
};
5+
6+
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
7+
use matrix_sdk::{
8+
SqliteEventCacheStore,
9+
store::StoreConfig,
10+
sync::{JoinedRoomUpdate, RoomUpdates},
11+
test_utils::mocks::MatrixMockServer,
12+
};
13+
use matrix_sdk_base::event_cache::store::{IntoEventCacheStore, MemoryStore};
14+
use matrix_sdk_test::{ALICE, JoinedRoomBuilder, event_factory::EventFactory};
15+
use ruma::{EventId, RoomId};
16+
use tempfile::tempdir;
17+
use tokio::runtime::Builder;
18+
19+
fn handle_room_updates(c: &mut Criterion) {
20+
// Create a new asynchronous runtime.
21+
let runtime = Builder::new_multi_thread()
22+
.enable_time()
23+
.enable_io()
24+
.build()
25+
.expect("Failed to create an asynchronous runtime");
26+
27+
let mut group = c.benchmark_group("reading");
28+
group.sample_size(10);
29+
30+
const NUM_EVENTS: usize = 1000;
31+
32+
for num_rooms in [1, 10, 100] {
33+
// Add some joined rooms, each with NUM_EVENTS in it, to the sync response.
34+
let mut room_updates = RoomUpdates::default();
35+
36+
for i in 0..num_rooms {
37+
let room_id = RoomId::parse(format!("!room{i}:example.com")).unwrap();
38+
let event_factory = EventFactory::new().room(&room_id).sender(&ALICE);
39+
40+
let mut joined_room_update = JoinedRoomUpdate::default();
41+
for j in 0..NUM_EVENTS {
42+
let event_id = EventId::parse(format!("$ev{i}_{j}")).unwrap();
43+
let event =
44+
event_factory.text_msg(format!("Message {j}")).event_id(&event_id).into();
45+
joined_room_update.timeline.events.push(event);
46+
}
47+
room_updates.joined.insert(room_id.clone(), joined_room_update);
48+
}
49+
50+
// Declare new stores for this set of events.
51+
let sqlite_temp_dir = tempdir().unwrap();
52+
let stores = vec![
53+
("memory store", MemoryStore::default().into_event_cache_store()),
54+
(
55+
"sqlite store",
56+
runtime.block_on(async {
57+
SqliteEventCacheStore::open(sqlite_temp_dir.path().join("bench"), None)
58+
.await
59+
.unwrap()
60+
.into_event_cache_store()
61+
}),
62+
),
63+
];
64+
65+
let server = Arc::new(runtime.block_on(MatrixMockServer::new()));
66+
67+
for (store_name, store) in &stores {
68+
// Define the throughput.
69+
group.throughput(Throughput::Elements(num_rooms));
70+
71+
// Bench the handling of room updates.
72+
group.bench_function(
73+
BenchmarkId::new(format!("handle_room_updates/{store_name}"), num_rooms),
74+
|bencher| {
75+
// Ideally we'd use `iter_with_setup` here, but it doesn't allow an async setup
76+
// (which we need to setup the client), see also
77+
// https://github.com/bheisler/criterion.rs/issues/751.
78+
bencher.to_async(&runtime).iter_custom(|num_iters| {
79+
let room_updates = room_updates.clone();
80+
let server = server.clone();
81+
82+
async move {
83+
let mut total_time = Duration::new(0, 0);
84+
85+
for _ in 0..num_iters {
86+
// Setup code.
87+
let client = server
88+
.client_builder()
89+
.store_config(
90+
StoreConfig::new(
91+
"cross-process-store-locks-holder-name".to_owned(),
92+
)
93+
.event_cache_store(store.clone()),
94+
)
95+
.build()
96+
.await;
97+
98+
client.event_cache().subscribe().unwrap();
99+
100+
// Make sure the client knows about all the to-be joined rooms.
101+
server
102+
.mock_sync()
103+
.ok_and_run(&client, |builder| {
104+
for room_id in room_updates.joined.keys() {
105+
builder
106+
.add_joined_room(JoinedRoomBuilder::new(room_id));
107+
}
108+
})
109+
.await;
110+
111+
let time_before = Instant::now();
112+
client
113+
.event_cache()
114+
.handle_room_updates(room_updates.clone())
115+
.await
116+
.unwrap();
117+
total_time += time_before.elapsed();
118+
}
119+
120+
total_time
121+
}
122+
})
123+
},
124+
);
125+
}
126+
127+
for (_store_name, store) in stores.into_iter() {
128+
let _guard = runtime.enter();
129+
drop(store);
130+
}
131+
}
132+
133+
group.finish()
134+
}
135+
136+
fn criterion() -> Criterion {
137+
#[cfg(target_os = "linux")]
138+
let criterion = Criterion::default().with_profiler(pprof::criterion::PProfProfiler::new(
139+
100,
140+
pprof::criterion::Output::Flamegraph(None),
141+
));
142+
#[cfg(not(target_os = "linux"))]
143+
let criterion = Criterion::default();
144+
145+
criterion
146+
}
147+
148+
criterion_group! {
149+
name = event_cache;
150+
config = criterion();
151+
targets = handle_room_updates,
152+
}
153+
154+
criterion_main!(event_cache);

crates/matrix-sdk-base/src/event_cache/store/traits.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,12 @@ pub trait IntoEventCacheStore {
464464
fn into_event_cache_store(self) -> Arc<DynEventCacheStore>;
465465
}
466466

467+
impl IntoEventCacheStore for Arc<DynEventCacheStore> {
468+
fn into_event_cache_store(self) -> Arc<DynEventCacheStore> {
469+
self
470+
}
471+
}
472+
467473
impl<T> IntoEventCacheStore for T
468474
where
469475
T: EventCacheStore + Sized + 'static,

crates/matrix-sdk/src/event_cache/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,12 @@ impl EventCache {
244244
.await;
245245
}
246246

247+
/// For benchmarking purposes only.
248+
#[doc(hidden)]
249+
pub async fn handle_room_updates(&self, updates: RoomUpdates) -> Result<()> {
250+
self.inner.handle_room_updates(updates).await
251+
}
252+
247253
#[instrument(skip_all)]
248254
async fn listen_task(
249255
inner: Arc<EventCacheInner>,

0 commit comments

Comments
 (0)