Files
zed/crates/rope/benches/rope_benchmark.rs
Mohamad Khani b72a46db68
Some checks failed
Update All Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Triage Project Sync (#84) / Sync triage project (push) Has been cancelled
release_nightly / notify_on_failure (push) Has been cancelled
release_nightly / check_style (push) Has been cancelled
release_nightly / run_tests_windows (push) Has been cancelled
release_nightly / clippy_windows (push) Has been cancelled
release_nightly / bundle_linux_aarch64 (push) Has been cancelled
release_nightly / bundle_linux_x86_64 (push) Has been cancelled
release_nightly / bundle_mac_aarch64 (push) Has been cancelled
release_nightly / bundle_mac_x86_64 (push) Has been cancelled
release_nightly / bundle_windows_aarch64 (push) Has been cancelled
release_nightly / bundle_windows_x86_64 (push) Has been cancelled
release_nightly / build_nix_linux_x86_64 (push) Has been cancelled
release_nightly / build_nix_mac_aarch64 (push) Has been cancelled
release_nightly / update_nightly_tag (push) Has been cancelled
Hotfix Review Monitor / check-hotfix-reviews (push) Has been cancelled
Stale PR Review Reminder / check-stale-prs (push) Has been cancelled
Update Weekly Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Bump collab-staging Tag / update-collab-staging-tag (push) Has been cancelled
compliance_check / scheduled_compliance_check (push) Has been cancelled
logiguard fork: GPUI xdg-activation keyboard-focus serial fix
Single-commit orphan branch: full zed-industries/zed @ 8c74db0 source tree
with a 3-file patch applied (no upstream history).

Patch (crates/gpui_linux/src/linux/wayland/):
  - serial.rs: add SerialKind::KeyboardEnter
  - client.rs: store wl_keyboard.enter serial; add latest_serial_of()
  - window.rs: activate() uses keyboard-enter serial (Mutter focus gate)

Mutter honors window activation only when the token carries the keyboard-
focus serial from wl_keyboard.enter; GPUI used a stale mouse-press serial.
See docs/tray-window-focus-wayland.md in logiguard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 02:22:17 +03:30

274 lines
8.6 KiB
Rust

use std::ops::Range;
use criterion::{
BatchSize, BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main,
};
use rand::prelude::*;
use rand::rngs::StdRng;
use rope::{Point, Rope};
use sum_tree::Bias;
use util::RandomCharIter;
/// Returns a biased random string whose UTF-8 length is close to but no more than `len` bytes.
///
/// The string is biased towards characters expected to occur in text or likely to exercise edge
/// cases.
fn generate_random_text(rng: &mut StdRng, len: usize) -> String {
let mut str = String::with_capacity(len);
let mut chars = RandomCharIter::new(rng);
loop {
let ch = chars.next().unwrap();
if str.len() + ch.len_utf8() > len {
break;
}
str.push(ch);
}
str
}
fn generate_random_rope(rng: &mut StdRng, text_len: usize) -> Rope {
let text = generate_random_text(rng, text_len);
let mut rope = Rope::new();
rope.push(&text);
rope
}
fn generate_random_rope_ranges(rng: &mut StdRng, rope: &Rope) -> Vec<Range<usize>> {
let range_max_len = 50;
let num_ranges = rope.len() / range_max_len;
let mut ranges = Vec::new();
let mut start = 0;
for _ in 0..num_ranges {
let range_start = rope.clip_offset(
rng.random_range(start..=(start + range_max_len)),
sum_tree::Bias::Left,
);
let range_end = rope.clip_offset(
rng.random_range(range_start..(range_start + range_max_len)),
sum_tree::Bias::Right,
);
let range = range_start..range_end;
if !range.is_empty() {
ranges.push(range);
}
start = range_end + 1;
}
ranges
}
fn generate_random_rope_points(rng: &mut StdRng, rope: &Rope) -> Vec<Point> {
let num_points = rope.len() / 10;
let mut points = Vec::new();
for _ in 0..num_points {
points.push(rope.offset_to_point(rng.random_range(0..rope.len())));
}
points
}
fn rope_benchmarks(c: &mut Criterion) {
static SEED: u64 = 9999;
static KB: usize = 1024;
let sizes = [4 * KB, 64 * KB];
let mut group = c.benchmark_group("push");
for size in sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
let mut rng = StdRng::seed_from_u64(SEED);
let text = generate_random_text(&mut rng, *size);
b.iter(|| {
let mut rope = Rope::new();
for _ in 0..10 {
rope.push(&text);
}
});
});
}
group.finish();
let mut group = c.benchmark_group("append");
for size in sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
let mut rng = StdRng::seed_from_u64(SEED);
let mut random_ropes = Vec::new();
for _ in 0..5 {
let rope = generate_random_rope(&mut rng, *size);
random_ropes.push(rope);
}
b.iter(|| {
let mut rope_b = Rope::new();
for rope in &random_ropes {
rope_b.append(rope.clone())
}
});
});
}
group.finish();
let mut group = c.benchmark_group("slice");
for size in sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
let mut rng = StdRng::seed_from_u64(SEED);
let rope = generate_random_rope(&mut rng, *size);
b.iter_batched(
|| generate_random_rope_ranges(&mut rng, &rope),
|ranges| {
for range in ranges.iter() {
rope.slice(range.clone());
}
},
BatchSize::SmallInput,
);
});
}
group.finish();
let mut group = c.benchmark_group("bytes_in_range");
for size in sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
let mut rng = StdRng::seed_from_u64(SEED);
let rope = generate_random_rope(&mut rng, *size);
b.iter_batched(
|| generate_random_rope_ranges(&mut rng, &rope),
|ranges| {
for range in ranges.iter() {
let bytes = rope.bytes_in_range(range.clone());
assert!(bytes.into_iter().count() > 0);
}
},
BatchSize::SmallInput,
);
});
}
group.finish();
let mut group = c.benchmark_group("chars");
for size in sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
let mut rng = StdRng::seed_from_u64(SEED);
let rope = generate_random_rope(&mut rng, *size);
b.iter(|| {
let chars = rope.chars().count();
assert!(chars > 0);
});
});
}
group.finish();
let mut group = c.benchmark_group("clip_point");
for size in sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
let mut rng = StdRng::seed_from_u64(SEED);
let rope = generate_random_rope(&mut rng, *size);
b.iter_batched(
|| generate_random_rope_points(&mut rng, &rope),
|offsets| {
for offset in offsets.iter() {
black_box(rope.clip_point(*offset, Bias::Left));
black_box(rope.clip_point(*offset, Bias::Right));
}
},
BatchSize::SmallInput,
);
});
}
group.finish();
let mut group = c.benchmark_group("point_to_offset");
for size in sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
let mut rng = StdRng::seed_from_u64(SEED);
let rope = generate_random_rope(&mut rng, *size);
b.iter_batched(
|| generate_random_rope_points(&mut rng, &rope),
|offsets| {
for offset in offsets.iter() {
black_box(rope.point_to_offset(*offset));
}
},
BatchSize::SmallInput,
);
});
}
group.finish();
let mut group = c.benchmark_group("cursor");
for size in sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
let mut rng = StdRng::seed_from_u64(SEED);
let rope = generate_random_rope(&mut rng, *size);
b.iter_batched(
|| {
let num_points = rope.len() / 10;
let mut points = Vec::new();
for _ in 0..num_points {
points.push(rng.random_range(0..rope.len()));
}
points
},
|offsets| {
for offset in offsets.iter() {
black_box(rope.cursor(*offset));
}
},
BatchSize::SmallInput,
);
});
}
group.finish();
let mut group = c.benchmark_group("append many");
group.throughput(Throughput::Bytes(128 * 100_000));
group.bench_function("small to large", |b| {
b.iter(|| {
let mut rope = Rope::new();
let small = Rope::from("A".repeat(128));
for _ in 0..100_000 {
rope.append(small.clone());
}
assert_eq!(rope.len(), 128 * 100_000);
});
});
group.bench_function("large to small", |b| {
b.iter(|| {
let mut rope = Rope::new();
let small = Rope::from("A".repeat(128));
for _ in 0..100_000 {
let large = rope;
rope = small.clone();
rope.append(large);
}
assert_eq!(rope.len(), 128 * 100_000);
});
});
group.finish();
}
criterion_group!(benches, rope_benchmarks);
criterion_main!(benches);