7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 1 | use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 2 | use matrix_sdk::test_utils::mocks::MatrixMockServer; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 3 | use matrix_sdk_test::{JoinedRoomBuilder, event_factory::EventFactory}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 4 | use matrix_sdk_ui::timeline::{TimelineBuilder, TimelineReadReceiptTracking}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 5 | use ruma::{ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 6 | OwnedEventId, events::room::message::RoomMessageEventContentWithoutRelation, owned_room_id, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 7 | owned_user_id, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 8 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 9 | use tokio::runtime::Builder; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 10 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 11 | /// Benchmark the time it takes to create a timeline (with read receipt |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 12 | /// support), when there are many initial events at rest in the event cache. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 13 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 14 | /// `NUM_EVENTS` is the number of events that will be stored initially in the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 15 | /// event cache. It will be a mix of messages, reactions, edits and redactions, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 16 | /// so there are some aggregations to take into account by the timeline as well. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 17 | pub fn create_timeline_with_initial_events(c: &mut Criterion) { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 18 | const NUM_EVENTS: usize = 10000; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 19 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 20 | let runtime = Builder::new_multi_thread().enable_all().build().expect("Can't create runtime"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 21 | let room_id = owned_room_id!("!fortesfortunajuvat:example.com"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 22 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 23 | let sender_id = owned_user_id!("@sender:example.com"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 24 | let other_sender_id = owned_user_id!("@other_sender:example.com"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 25 | let another_sender_id = owned_user_id!("@another_sender:example.com"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 26 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 27 | let f = EventFactory::new().room(&room_id); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 28 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 29 | let mut events = Vec::new(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 30 | for i in 0..NUM_EVENTS { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 31 | let sender = match i % 3 { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 32 | 0 => &sender_id, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 33 | 1 => &other_sender_id, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 34 | 2 => &another_sender_id, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 35 | _ => unreachable!("math genius over here"), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 36 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 37 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 38 | let j = i % 10; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 39 | if j < 6 { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 40 | // Messages. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 41 | events.push(f.text_msg(format!("Message {i}")).sender(sender).into_raw_sync()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 42 | } else if j < 8 { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 43 | // Reactions. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 44 | let prev_event_id = events[i - 2] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 45 | .get_field::<OwnedEventId>("event_id") |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 46 | .expect("invalid event ID") |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 47 | .expect("missing event ID"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 48 | events.push(f.reaction(&prev_event_id, "👍").sender(sender).into_raw_sync()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 49 | } else if j == 8 { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 50 | // Edit. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 51 | // Note: (i-3)%3 is the same as i%3 -> same sender! |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 52 | let prev_event_id = events[i - 3] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 53 | .get_field::<OwnedEventId>("event_id") |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 54 | .expect("invalid event ID") |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 55 | .expect("missing event ID"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 56 | events.push( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 57 | f.text_msg(format!("* Message {}v2", i - 3)) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 58 | .edit( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 59 | &prev_event_id, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 60 | RoomMessageEventContentWithoutRelation::text_plain(format!( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 61 | "Message {}v2", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 62 | i - 3 |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 63 | )), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 64 | ) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 65 | .sender(sender) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 66 | .into_raw_sync(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 67 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 68 | } else if j == 9 { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 69 | // Redaction. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 70 | // Note: (i-6)%3 is the same as i%6 -> same sender! |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 71 | let prev_event_id = events[i - 6] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 72 | .get_field::<OwnedEventId>("event_id") |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 73 | .expect("invalid event ID") |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 74 | .expect("missing event ID"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 75 | events.push(f.redaction(&prev_event_id).sender(sender).into_raw_sync()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 76 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 77 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 78 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 79 | let builder = JoinedRoomBuilder::new(&room_id) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 80 | .add_state_event(f.room_encryption().sender(&sender_id)) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 81 | .add_timeline_bulk(events); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 82 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 83 | let room = runtime.block_on(async move { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 84 | let server = MatrixMockServer::new().await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 85 | let client = server.client_builder().build().await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 86 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 87 | client.event_cache().subscribe().unwrap(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 88 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 89 | let room = server.sync_room(&client, builder).await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 90 | drop(server); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 91 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 92 | room |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 93 | }); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 94 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 95 | let mut group = c.benchmark_group("Create a timeline"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 96 | group.throughput(Throughput::Elements(NUM_EVENTS as _)); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 97 | group.sample_size(10); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 98 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 99 | group.bench_function( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 100 | BenchmarkId::new("Create a timeline with initial events", format!("{NUM_EVENTS} events")), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 101 | |b| { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 102 | b.to_async(&runtime).iter(|| async { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 103 | let timeline = TimelineBuilder::new(&room) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 104 | .track_read_marker_and_receipts(TimelineReadReceiptTracking::AllEvents) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 105 | .build() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 106 | .await |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 107 | .expect("Could not create timeline"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 108 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 109 | let (items, _) = timeline.subscribe().await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 110 | assert_eq!(items.len(), 20); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 111 | }); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 112 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 113 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 114 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 115 | group.finish(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 116 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 117 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 118 | criterion_group! { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 119 | name = room; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 120 | config = Criterion::default(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 121 | targets = create_timeline_with_initial_events |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 122 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 123 | criterion_main!(room); |