Skip to content
Closed
20 changes: 20 additions & 0 deletions .github/workflows/codspeed-repeatability-1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: R03 original session walltime base 1

on:
pull_request:
branches: [main]
types: [labeled]

permissions:
contents: read
id-token: write

jobs:
diagnostic:
if: >-
github.head_ref == 'bench/session-repeatability' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.label.name == 'r03-walltime-fixed-revisions'
uses: ./.github/workflows/codspeed-repeatability-run.yml
with:
source-revision: f1080df166bbc2c88e762eda6eb5bb7f6efc2f05
20 changes: 20 additions & 0 deletions .github/workflows/codspeed-repeatability-2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: R03 original session walltime head 1

on:
pull_request:
branches: [main]
types: [labeled]

permissions:
contents: read
id-token: write

jobs:
diagnostic:
if: >-
github.head_ref == 'bench/session-repeatability' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.label.name == 'r03-walltime-fixed-revisions'
uses: ./.github/workflows/codspeed-repeatability-run.yml
with:
source-revision: c42dd44c59acff7825eae7d09e940a08c71d91a2
20 changes: 20 additions & 0 deletions .github/workflows/codspeed-repeatability-3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: R03 original session walltime base 2

on:
pull_request:
branches: [main]
types: [labeled]

permissions:
contents: read
id-token: write

jobs:
diagnostic:
if: >-
github.head_ref == 'bench/session-repeatability' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.label.name == 'r03-walltime-fixed-revisions'
uses: ./.github/workflows/codspeed-repeatability-run.yml
with:
source-revision: f1080df166bbc2c88e762eda6eb5bb7f6efc2f05
20 changes: 20 additions & 0 deletions .github/workflows/codspeed-repeatability-4.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: R03 original session walltime head 2

on:
pull_request:
branches: [main]
types: [labeled]

permissions:
contents: read
id-token: write

jobs:
diagnostic:
if: >-
github.head_ref == 'bench/session-repeatability' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.label.name == 'r03-walltime-fixed-revisions'
uses: ./.github/workflows/codspeed-repeatability-run.yml
with:
source-revision: c42dd44c59acff7825eae7d09e940a08c71d91a2
20 changes: 20 additions & 0 deletions .github/workflows/codspeed-repeatability-5.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: R03 original session walltime base 3

on:
pull_request:
branches: [main]
types: [labeled]

permissions:
contents: read
id-token: write

jobs:
diagnostic:
if: >-
github.head_ref == 'bench/session-repeatability' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.label.name == 'r03-walltime-fixed-revisions'
uses: ./.github/workflows/codspeed-repeatability-run.yml
with:
source-revision: f1080df166bbc2c88e762eda6eb5bb7f6efc2f05
20 changes: 20 additions & 0 deletions .github/workflows/codspeed-repeatability-6.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: R03 original session walltime head 3

on:
pull_request:
branches: [main]
types: [labeled]

permissions:
contents: read
id-token: write

jobs:
diagnostic:
if: >-
github.head_ref == 'bench/session-repeatability' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.label.name == 'r03-walltime-fixed-revisions'
uses: ./.github/workflows/codspeed-repeatability-run.yml
with:
source-revision: c42dd44c59acff7825eae7d09e940a08c71d91a2
80 changes: 80 additions & 0 deletions .github/workflows/codspeed-repeatability-run.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: Fixed-revision original session walltime

on:
workflow_call:
inputs:
source-revision:
required: true
type: string

permissions:
contents: read
id-token: write

env:
CARGO_TERM_COLOR: never
PROTOC_VERSION: "3.25.3"
MALLOC_ARENA_MAX: "1"
MALLOC_MMAP_THRESHOLD_: "131072"
MALLOC_TRIM_THRESHOLD_: "131072"
MALLOC_TOP_PAD_: "131072"

jobs:
diagnostic:
# Only the two reviewed same-repository revisions may execute with OIDC.
if: >-
github.repository == 'oxidezap/whatsapp-rust' &&
github.event.pull_request.head.repo.full_name == github.repository &&
(inputs.source-revision == 'f1080df166bbc2c88e762eda6eb5bb7f6efc2f05' ||
inputs.source-revision == 'c42dd44c59acff7825eae7d09e940a08c71d91a2')
runs-on: ubuntu-24.04
timeout-minutes: 25
steps:
- uses: actions/checkout@v7
with:
repository: oxidezap/whatsapp-rust
ref: ${{ inputs.source-revision }}
persist-credentials: false
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2026-06-16
- name: Key libc debug cache
id: libc6
run: cargo xt ci workflow libc-version
- uses: actions/cache@v6
with:
path: ~/.cache/libc6-dbg
key: libc6-dbg-${{ runner.arch }}-${{ steps.libc6.outputs.version }}
- name: Install libc debug symbols
env:
LIBC6_VERSION: ${{ steps.libc6.outputs.version }}
run: cargo xt ci workflow install-libc-debug
- uses: taiki-e/install-action@v2
with:
tool: protoc@${{ env.PROTOC_VERSION }},cargo-codspeed@5.0.1
- uses: Swatinem/rust-cache@v2
with:
prefix-key: Linux-cargo-codspeed-repeatability
cache-targets: "false"
- name: Build diagnostic targets
# Match the normal proto-signal shard's dependency feature unification.
run: >
cargo codspeed build -m walltime
-p wacore-binary -p wacore-libsignal -p wacore-appstate
-p whatsapp-rust-sqlite-storage
- name: Record fixed source and toolchain
run: |
git rev-parse HEAD
sha256sum Cargo.lock wacore/libsignal/benches/libsignal_benchmark.rs
find target/codspeed -maxdepth 3 -type f -executable -exec sha256sum {} +
rustc -Vv
ldd --version
lscpu
# CodSpeed's run is attached to this diagnostic PR. The recorded checkout
# above, not that PR's head label, identifies the source being measured.
- name: Measure only original self and non-self session cases
uses: CodSpeedHQ/action@v5
with:
runner-version: 5.4.0
mode: walltime
run: cargo codspeed run -p wacore-libsignal --bench libsignal_benchmark 'bench_session_with_self'
8 changes: 8 additions & 0 deletions wacore/libsignal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,13 @@ futures = { workspace = true, features = ["executor"] }
name = "libsignal_benchmark"
harness = false

[[bench]]
name = "session_identity_isolated"
harness = false

[[bench]]
name = "session_root_key_isolated"
harness = false

[lints]
workspace = true
55 changes: 55 additions & 0 deletions wacore/libsignal/benches/libsignal_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,61 @@ fn bench_sender_key_serialize_without_backlog(bencher: divan::Bencher) {
.bench_refs(|record| black_box(record.serialize().expect("serialize sender key")));
}

// A single call's simulation cost is dominated by cold cache-line placement.
// Visit independent sessions once each to amortize code-cache startup without
// repeatedly warming the same record. Keep the batch size in the benchmark ID:
// the result is a batch total, and CodSpeed's simulation adapter ignores counters.
fn session_state_batch(count: usize, is_self: bool) -> Vec<SessionState> {
let mut rng = <rand::rngs::StdRng as rand::SeedableRng>::seed_from_u64(0x5345_4c46);
(0..count)
.map(|_| {
let local = IdentityKey::new(KeyPair::generate(&mut rng).public_key);
let remote = if is_self {
local
} else {
IdentityKey::new(KeyPair::generate(&mut rng).public_key)
};
SessionState::new(
3,
&local,
&remote,
&RootKey::new([0x11; 32]),
local.public_key(),
)
})
.collect()
}

// Keep one- and two-pass cases together while validating the candidate. The
// second pass is a deliberate extra-work control, not a production workload.
#[divan::bench(args = [(false, 1), (true, 1), (false, 2), (true, 2)])]
fn bench_session_with_self_batch_32(bencher: divan::Bencher, (is_self, passes): (bool, usize)) {
bencher
.with_inputs(|| session_state_batch(32, is_self))
.bench_refs(|states| {
for _ in 0..passes {
for state in states.iter() {
black_box(black_box(state).session_with_self().expect("identities"));
}
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.
});
}

#[divan::bench(args = [1, 2])]
fn bench_session_root_key_update_batch_32(bencher: divan::Bencher, passes: usize) {
bencher
.with_inputs(|| session_state_batch(32, true))
.bench_refs(|states| {
for pass in 0..passes {
let key = RootKey::new([0x22 + pass as u8; 32]);
for state in states.iter_mut() {
black_box(&mut *state).set_root_key(black_box(&key));
black_box(&*state);
}
}
});
}

#[divan::bench(args = [false, true])]
fn bench_session_with_self(bencher: divan::Bencher, is_self: bool) {
bencher
Expand Down
47 changes: 47 additions & 0 deletions wacore/libsignal/benches/session_identity_isolated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use divan::black_box;
use wacore_libsignal::protocol::{IdentityKey, KeyPair, RootKey, SessionState};

#[path = "support/session_fixture.rs"]
mod session_fixture;

fn main() {
divan::main();
}

// Retain the original single-call workload while testing process isolation.
#[divan::bench(args = [false, true])]
fn bench_session_with_self(bencher: divan::Bencher, is_self: bool) {
bencher
.with_inputs(|| {
let mut rng = <rand::rngs::StdRng as rand::SeedableRng>::seed_from_u64(0x5345_4c46);
let local = IdentityKey::new(KeyPair::generate(&mut rng).public_key);
let remote = if is_self {
local
} else {
IdentityKey::new(KeyPair::generate(&mut rng).public_key)
};
SessionState::new(
3,
&local,
&remote,
&RootKey::new([0x11; 32]),
local.public_key(),
)
})
.bench_refs(|state| black_box(state.session_with_self().expect("identities")));
}

// A separate binary removes unrelated benchmark code and allocator history.
// The original cold-call cases remain in libsignal_benchmark.
#[divan::bench(args = [(false, 1), (true, 1), (false, 2), (true, 2)])]
fn independent_sessions_32(bencher: divan::Bencher, (is_self, passes): (bool, usize)) {
bencher
.with_inputs(|| session_fixture::sessions(32, is_self))
.bench_refs(|states| {
for _ in 0..passes {
for state in states.iter() {
black_box(black_box(state).session_with_self().expect("identities"));
}
}
});
}
48 changes: 48 additions & 0 deletions wacore/libsignal/benches/session_root_key_isolated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use divan::black_box;
use wacore_libsignal::protocol::{IdentityKey, KeyPair, RootKey, SessionState};

#[path = "support/session_fixture.rs"]
mod session_fixture;

fn main() {
divan::main();
}

// Retain the original single-call workload while testing process isolation.
#[divan::bench]
fn bench_session_root_key_update(bencher: divan::Bencher) {
bencher
.with_inputs(|| {
let mut rng = <rand::rngs::StdRng as rand::SeedableRng>::seed_from_u64(0x524f_4f54);
let local = IdentityKey::new(KeyPair::generate(&mut rng).public_key);
SessionState::new(
3,
&local,
&local,
&RootKey::new([0x11; 32]),
local.public_key(),
)
})
.bench_refs(|state| {
state.set_root_key(black_box(&RootKey::new([0x22; 32])));
black_box(&*state);
});
}

// One pass preserves the independent-record experiment. Thirty-two passes
// separately measure successive updates on resident sessions; neither replaces
// the original cold-call case. Doubling passes is an explicit slowdown control.
#[divan::bench(args = [1, 2, 32, 64])]
fn successive_updates_32_sessions(bencher: divan::Bencher, passes: usize) {
bencher
.with_inputs(|| session_fixture::sessions(32, true))
.bench_refs(|states| {
for pass in 0..passes {
let key = RootKey::new([0x22 + pass as u8; 32]);
for state in states.iter_mut() {
black_box(&mut *state).set_root_key(black_box(&key));
black_box(&*state);
}
}
});
}
Loading
Loading