atagen

matrix-rust-sdk

public
Star0
Watch0
ssh://brewery@pls.lobotomise.me:33/atagen/matrix-rust-sdk.git

Blame: benchmarks/benches/timeline.rs

7ff8adafe9e4atagen2026-10-22 12:30 UTC1
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
7ff8adafe9e4atagen2026-10-22 12:30 UTC2
use matrix_sdk::test_utils::mocks::MatrixMockServer;
7ff8adafe9e4atagen2026-10-22 12:30 UTC3
use matrix_sdk_test::{JoinedRoomBuilder, event_factory::EventFactory};
7ff8adafe9e4atagen2026-10-22 12:30 UTC4
use matrix_sdk_ui::timeline::{TimelineBuilder, TimelineReadReceiptTracking};
7ff8adafe9e4atagen2026-10-22 12:30 UTC5
use ruma::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC6
    OwnedEventId, events::room::message::RoomMessageEventContentWithoutRelation, owned_room_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC7
    owned_user_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC8
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC9
use tokio::runtime::Builder;
7ff8adafe9e4atagen2026-10-22 12:30 UTC10
7ff8adafe9e4atagen2026-10-22 12:30 UTC11
/// Benchmark the time it takes to create a timeline (with read receipt
7ff8adafe9e4atagen2026-10-22 12:30 UTC12
/// support), when there are many initial events at rest in the event cache.
7ff8adafe9e4atagen2026-10-22 12:30 UTC13
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC14
/// `NUM_EVENTS` is the number of events that will be stored initially in the
7ff8adafe9e4atagen2026-10-22 12:30 UTC15
/// event cache. It will be a mix of messages, reactions, edits and redactions,
7ff8adafe9e4atagen2026-10-22 12:30 UTC16
/// so there are some aggregations to take into account by the timeline as well.
7ff8adafe9e4atagen2026-10-22 12:30 UTC17
pub fn create_timeline_with_initial_events(c: &mut Criterion) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC18
    const NUM_EVENTS: usize = 10000;
7ff8adafe9e4atagen2026-10-22 12:30 UTC19
7ff8adafe9e4atagen2026-10-22 12:30 UTC20
    let runtime = Builder::new_multi_thread().enable_all().build().expect("Can't create runtime");
7ff8adafe9e4atagen2026-10-22 12:30 UTC21
    let room_id = owned_room_id!("!fortesfortunajuvat:example.com");
7ff8adafe9e4atagen2026-10-22 12:30 UTC22
7ff8adafe9e4atagen2026-10-22 12:30 UTC23
    let sender_id = owned_user_id!("@sender:example.com");
7ff8adafe9e4atagen2026-10-22 12:30 UTC24
    let other_sender_id = owned_user_id!("@other_sender:example.com");
7ff8adafe9e4atagen2026-10-22 12:30 UTC25
    let another_sender_id = owned_user_id!("@another_sender:example.com");
7ff8adafe9e4atagen2026-10-22 12:30 UTC26
7ff8adafe9e4atagen2026-10-22 12:30 UTC27
    let f = EventFactory::new().room(&room_id);
7ff8adafe9e4atagen2026-10-22 12:30 UTC28
7ff8adafe9e4atagen2026-10-22 12:30 UTC29
    let mut events = Vec::new();
7ff8adafe9e4atagen2026-10-22 12:30 UTC30
    for i in 0..NUM_EVENTS {
7ff8adafe9e4atagen2026-10-22 12:30 UTC31
        let sender = match i % 3 {
7ff8adafe9e4atagen2026-10-22 12:30 UTC32
            0 => &sender_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC33
            1 => &other_sender_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC34
            2 => &another_sender_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC35
            _ => unreachable!("math genius over here"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC36
        };
7ff8adafe9e4atagen2026-10-22 12:30 UTC37
7ff8adafe9e4atagen2026-10-22 12:30 UTC38
        let j = i % 10;
7ff8adafe9e4atagen2026-10-22 12:30 UTC39
        if j < 6 {
7ff8adafe9e4atagen2026-10-22 12:30 UTC40
            // Messages.
7ff8adafe9e4atagen2026-10-22 12:30 UTC41
            events.push(f.text_msg(format!("Message {i}")).sender(sender).into_raw_sync());
7ff8adafe9e4atagen2026-10-22 12:30 UTC42
        } else if j < 8 {
7ff8adafe9e4atagen2026-10-22 12:30 UTC43
            // Reactions.
7ff8adafe9e4atagen2026-10-22 12:30 UTC44
            let prev_event_id = events[i - 2]
7ff8adafe9e4atagen2026-10-22 12:30 UTC45
                .get_field::<OwnedEventId>("event_id")
7ff8adafe9e4atagen2026-10-22 12:30 UTC46
                .expect("invalid event ID")
7ff8adafe9e4atagen2026-10-22 12:30 UTC47
                .expect("missing event ID");
7ff8adafe9e4atagen2026-10-22 12:30 UTC48
            events.push(f.reaction(&prev_event_id, "👍").sender(sender).into_raw_sync());
7ff8adafe9e4atagen2026-10-22 12:30 UTC49
        } else if j == 8 {
7ff8adafe9e4atagen2026-10-22 12:30 UTC50
            // Edit.
7ff8adafe9e4atagen2026-10-22 12:30 UTC51
            // Note: (i-3)%3 is the same as i%3 -> same sender!
7ff8adafe9e4atagen2026-10-22 12:30 UTC52
            let prev_event_id = events[i - 3]
7ff8adafe9e4atagen2026-10-22 12:30 UTC53
                .get_field::<OwnedEventId>("event_id")
7ff8adafe9e4atagen2026-10-22 12:30 UTC54
                .expect("invalid event ID")
7ff8adafe9e4atagen2026-10-22 12:30 UTC55
                .expect("missing event ID");
7ff8adafe9e4atagen2026-10-22 12:30 UTC56
            events.push(
7ff8adafe9e4atagen2026-10-22 12:30 UTC57
                f.text_msg(format!("* Message {}v2", i - 3))
7ff8adafe9e4atagen2026-10-22 12:30 UTC58
                    .edit(
7ff8adafe9e4atagen2026-10-22 12:30 UTC59
                        &prev_event_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC60
                        RoomMessageEventContentWithoutRelation::text_plain(format!(
7ff8adafe9e4atagen2026-10-22 12:30 UTC61
                            "Message {}v2",
7ff8adafe9e4atagen2026-10-22 12:30 UTC62
                            i - 3
7ff8adafe9e4atagen2026-10-22 12:30 UTC63
                        )),
7ff8adafe9e4atagen2026-10-22 12:30 UTC64
                    )
7ff8adafe9e4atagen2026-10-22 12:30 UTC65
                    .sender(sender)
7ff8adafe9e4atagen2026-10-22 12:30 UTC66
                    .into_raw_sync(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC67
            );
7ff8adafe9e4atagen2026-10-22 12:30 UTC68
        } else if j == 9 {
7ff8adafe9e4atagen2026-10-22 12:30 UTC69
            // Redaction.
7ff8adafe9e4atagen2026-10-22 12:30 UTC70
            // Note: (i-6)%3 is the same as i%6 -> same sender!
7ff8adafe9e4atagen2026-10-22 12:30 UTC71
            let prev_event_id = events[i - 6]
7ff8adafe9e4atagen2026-10-22 12:30 UTC72
                .get_field::<OwnedEventId>("event_id")
7ff8adafe9e4atagen2026-10-22 12:30 UTC73
                .expect("invalid event ID")
7ff8adafe9e4atagen2026-10-22 12:30 UTC74
                .expect("missing event ID");
7ff8adafe9e4atagen2026-10-22 12:30 UTC75
            events.push(f.redaction(&prev_event_id).sender(sender).into_raw_sync());
7ff8adafe9e4atagen2026-10-22 12:30 UTC76
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC77
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC78
7ff8adafe9e4atagen2026-10-22 12:30 UTC79
    let builder = JoinedRoomBuilder::new(&room_id)
7ff8adafe9e4atagen2026-10-22 12:30 UTC80
        .add_state_event(f.room_encryption().sender(&sender_id))
7ff8adafe9e4atagen2026-10-22 12:30 UTC81
        .add_timeline_bulk(events);
7ff8adafe9e4atagen2026-10-22 12:30 UTC82
7ff8adafe9e4atagen2026-10-22 12:30 UTC83
    let room = runtime.block_on(async move {
7ff8adafe9e4atagen2026-10-22 12:30 UTC84
        let server = MatrixMockServer::new().await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC85
        let client = server.client_builder().build().await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC86
7ff8adafe9e4atagen2026-10-22 12:30 UTC87
        client.event_cache().subscribe().unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC88
7ff8adafe9e4atagen2026-10-22 12:30 UTC89
        let room = server.sync_room(&client, builder).await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC90
        drop(server);
7ff8adafe9e4atagen2026-10-22 12:30 UTC91
7ff8adafe9e4atagen2026-10-22 12:30 UTC92
        room
7ff8adafe9e4atagen2026-10-22 12:30 UTC93
    });
7ff8adafe9e4atagen2026-10-22 12:30 UTC94
7ff8adafe9e4atagen2026-10-22 12:30 UTC95
    let mut group = c.benchmark_group("Create a timeline");
7ff8adafe9e4atagen2026-10-22 12:30 UTC96
    group.throughput(Throughput::Elements(NUM_EVENTS as _));
7ff8adafe9e4atagen2026-10-22 12:30 UTC97
    group.sample_size(10);
7ff8adafe9e4atagen2026-10-22 12:30 UTC98
7ff8adafe9e4atagen2026-10-22 12:30 UTC99
    group.bench_function(
7ff8adafe9e4atagen2026-10-22 12:30 UTC100
        BenchmarkId::new("Create a timeline with initial events", format!("{NUM_EVENTS} events")),
7ff8adafe9e4atagen2026-10-22 12:30 UTC101
        |b| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC102
            b.to_async(&runtime).iter(|| async {
7ff8adafe9e4atagen2026-10-22 12:30 UTC103
                let timeline = TimelineBuilder::new(&room)
7ff8adafe9e4atagen2026-10-22 12:30 UTC104
                    .track_read_marker_and_receipts(TimelineReadReceiptTracking::AllEvents)
7ff8adafe9e4atagen2026-10-22 12:30 UTC105
                    .build()
7ff8adafe9e4atagen2026-10-22 12:30 UTC106
                    .await
7ff8adafe9e4atagen2026-10-22 12:30 UTC107
                    .expect("Could not create timeline");
7ff8adafe9e4atagen2026-10-22 12:30 UTC108
7ff8adafe9e4atagen2026-10-22 12:30 UTC109
                let (items, _) = timeline.subscribe().await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC110
                assert_eq!(items.len(), 20);
7ff8adafe9e4atagen2026-10-22 12:30 UTC111
            });
7ff8adafe9e4atagen2026-10-22 12:30 UTC112
        },
7ff8adafe9e4atagen2026-10-22 12:30 UTC113
    );
7ff8adafe9e4atagen2026-10-22 12:30 UTC114
7ff8adafe9e4atagen2026-10-22 12:30 UTC115
    group.finish();
7ff8adafe9e4atagen2026-10-22 12:30 UTC116
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC117
7ff8adafe9e4atagen2026-10-22 12:30 UTC118
criterion_group! {
7ff8adafe9e4atagen2026-10-22 12:30 UTC119
    name = room;
7ff8adafe9e4atagen2026-10-22 12:30 UTC120
    config = Criterion::default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC121
    targets = create_timeline_with_initial_events
7ff8adafe9e4atagen2026-10-22 12:30 UTC122
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC123
criterion_main!(room);