Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion libdd-profiling/benches/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,10 @@ use criterion::criterion_main;

mod add_samples;
mod interning_strings;
mod profiles_dictionary;

criterion_main!(interning_strings::benches, add_samples::benches);
criterion_main!(
interning_strings::benches,
add_samples::benches,
profiles_dictionary::benches
);
102 changes: 102 additions & 0 deletions libdd-profiling/benches/profiles_dictionary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2026-Present Datadog, Inc. https://www.datadoghq.com/
// SPDX-License-Identifier: Apache-2.0

use criterion::{black_box, criterion_group, BatchSize, BenchmarkId, Criterion, Throughput};
use libdd_profiling::profiles::datatypes::ProfilesDictionary;
use std::sync::Barrier;
use std::thread;
use std::time::Duration;

const THREAD_COUNTS: [usize; 4] = [1, 2, 4, 16];
Comment thread
taegyunkim marked this conversation as resolved.
const STRINGS_PER_THREAD: usize = 1024;
// Bound one generated function-name component so the input has repeated
// function-like fragments while each full string stays unique.
const FUNCTION_NAME_VARIANTS: usize = 97;
const STRING_SHAPE_VARIANTS: usize = 4;
// Knuth/Fibonacci multiplicative hash constant, used only to vary synthetic input.
const KNUTH_MULTIPLICATIVE_HASH: usize = 2_654_435_761;

// The outer Vec partitions precomputed input by benchmark worker thread; each
// inner Vec is the set of strings inserted by one worker.
fn make_partitioned_strings(thread_count: usize) -> Vec<Vec<String>> {
(0..thread_count)
.map(|thread_id| {
(0..STRINGS_PER_THREAD)
.map(|string_id| {
let function_id = string_id % FUNCTION_NAME_VARIANTS;
let mixed_id = string_id.wrapping_mul(KNUTH_MULTIPLICATIVE_HASH);

match string_id % STRING_SHAPE_VARIANTS {
0 => format!("function_{function_id}::{mixed_id}"),
1 => format!("/src/thread_{thread_id}/module_{function_id}/file_{string_id:04}.rs"),
2 => {
format!("datadog::profiling::module_{function_id}::function_{mixed_id}")
}
_ => format!(
"/opt/datadog/profiler/thread-{thread_id}/module-{function_id}/src/file_{string_id:04}.rs::function_{function_id}::{mixed_id}",
),
}
})
.collect()
})
.collect()
}

fn insert_profile_strings(dict: &ProfilesDictionary, strings: &[String]) {
Comment thread
taegyunkim marked this conversation as resolved.
for string in strings {
black_box(dict.try_insert_str2(string.as_str()).unwrap());
}
}

fn insert_dictionary_strings_concurrently(strings: &[Vec<String>]) -> ProfilesDictionary {
let dict = ProfilesDictionary::try_new().unwrap();

if let [strings] = strings {
Comment thread
taegyunkim marked this conversation as resolved.
insert_profile_strings(&dict, strings);
return dict;
}

let barrier = Barrier::new(strings.len());
thread::scope(|scope| {
for thread_strings in strings {
let dict = &dict;
let barrier = &barrier;
scope.spawn(move || {
barrier.wait();
insert_profile_strings(dict, thread_strings);
});
}
});

dict
}

pub fn bench_profiles_dictionary(c: &mut Criterion) {
let mut group = c.benchmark_group("profiles_dictionary/unique_string_inserts");
group.warm_up_time(Duration::from_secs(1));
group.measurement_time(Duration::from_secs(5));
group.sample_size(10);

for thread_count in THREAD_COUNTS {
// Precompute input outside the measured closure so the benchmark measures
// dictionary insertion rather than string formatting/allocation.
let strings = make_partitioned_strings(thread_count);
let total_strings = thread_count * STRINGS_PER_THREAD;
group.throughput(Throughput::Elements(total_strings as u64));
group.bench_with_input(
BenchmarkId::new("threads", thread_count),
&strings,
|b, strings| {
b.iter_batched(
|| strings,
|strings| black_box(insert_dictionary_strings_concurrently(strings)),
BatchSize::LargeInput,
);
},
);
}

group.finish();
}

criterion_group!(benches, bench_profiles_dictionary);
Loading