Skip to content

Commit 367c8b2

Browse files
feat(common): add current thread id API (#1569)
# What does this PR do? Adds a new public helper API, `libdd_common::threading::get_current_thread_id() -> i64`, with platform-specific implementations for Linux, macOS, and Windows. It updates `libdd-profiling`'s `add_samples` benchmark to always include a numeric `"thread id"` label in both `try_add_sample` and `try_add_sample2` paths. # Motivation This PR improves the `add_samples` benchmark because in the future I want to modify the internals of our implementation, and I want labels to be represented in the benchmark. @gyuheon0h asked for it to be in common so it could be used in other places as well. This is fine with me, as long as we keep the i64 representation for profiling. # Additional Notes Supported implementations: - Linux: `syscall(SYS_gettid)`, since `gettid()` does not exist on older glibc versions. - macOS: `pthread_threadid_np` - Windows: `GetCurrentThreadId` via `windows-sys` Unsupported platforms fail at compile time via `compile_error!`. # How to test the change? 1. Check out branch `pr1/add-samples-benchmark`. 2. Run compile checks: - `cargo check -p libdd-common` - `cargo check -p libdd-profiling` - `cargo check -p libdd-profiling --benches` 3. Run benchmark: - `cargo bench -p libdd-profiling --bench main -- add_sample --noplot` 4. Confirm: - benchmark runs successfully - `add_samples` includes `"thread id"` labels for both legacy and api2 benchmark loops Co-authored-by: gyuheon.oh <[email protected]>
1 parent 8a6d94b commit 367c8b2

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed

libdd-common/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const_format = "0.2.34"
4747
nix = { version = "0.29", features = ["process"] }
4848
[target.'cfg(windows)'.dependencies.windows-sys]
4949
version = "0.52"
50-
features = ["Win32_Foundation", "Win32_System_Performance"]
50+
features = ["Win32_Foundation", "Win32_System_Performance", "Win32_System_Threading"]
5151

5252
[target.'cfg(unix)'.dependencies]
5353
rustls = { version = "0.23", default-features = false, optional = true, features = ["aws-lc-rs"] }

libdd-common/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub mod rate_limiter;
2828
pub mod tag;
2929
#[cfg(any(test, feature = "test-utils"))]
3030
pub mod test_utils;
31+
pub mod threading;
3132
pub mod timeout;
3233
pub mod unix_utils;
3334
pub mod worker;

libdd-common/src/threading.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2026-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
/// Returns a numeric identifier for the current OS thread.
5+
#[cfg(target_os = "linux")]
6+
pub fn get_current_thread_id() -> i64 {
7+
// SAFETY: syscall(SYS_gettid) has no preconditions for current thread.
8+
unsafe { libc::syscall(libc::SYS_gettid) as i64 }
9+
}
10+
11+
/// Returns a numeric identifier for the current OS thread.
12+
#[cfg(target_os = "macos")]
13+
pub fn get_current_thread_id() -> i64 {
14+
let mut tid: u64 = 0;
15+
// SAFETY: `pthread_threadid_np` has no preconditions for current thread
16+
// when pthread_t is 0 and output pointer is valid.
17+
let rc = unsafe { libc::pthread_threadid_np(0, &mut tid) };
18+
debug_assert_eq!(
19+
rc,
20+
0,
21+
"pthread_threadid_np failed: {rc} ({})",
22+
std::io::Error::from_raw_os_error(rc)
23+
);
24+
tid as i64
25+
}
26+
27+
/// Returns a numeric identifier for the current OS thread.
28+
#[cfg(target_os = "windows")]
29+
pub fn get_current_thread_id() -> i64 {
30+
// SAFETY: GetCurrentThreadId has no preconditions.
31+
unsafe { windows_sys::Win32::System::Threading::GetCurrentThreadId() as i64 }
32+
}
33+
34+
/// Returns a numeric identifier for the current OS thread.
35+
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
36+
compile_error!("libdd_common::threading::get_current_thread_id is unsupported on this platform");

libdd-profiling/benches/add_samples.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use criterion::*;
5+
use libdd_common::threading::get_current_thread_id;
56
use libdd_profiling::api2::Location2;
6-
use libdd_profiling::profiles::datatypes::{Function, FunctionId2, MappingId2};
7+
use libdd_profiling::profiles::datatypes::{Function, FunctionId2, MappingId2, StringId2};
78
use libdd_profiling::{self as profiling, api, api2};
89

910
fn make_sample_types() -> Vec<api::SampleType> {
@@ -103,6 +104,14 @@ pub fn bench_add_sample_vs_add2(c: &mut Criterion) {
103104

104105
let strings = dict.strings();
105106
let functions = dict.functions();
107+
let thread_id = get_current_thread_id();
108+
let thread_id_key: StringId2 = strings.try_insert("thread id").unwrap().into();
109+
let labels_api = vec![api::Label {
110+
key: "thread id",
111+
str: "",
112+
num: thread_id,
113+
num_unit: "",
114+
}];
106115

107116
let frames2 = frames.map(|f| {
108117
let set_id = functions
@@ -127,7 +136,7 @@ pub fn bench_add_sample_vs_add2(c: &mut Criterion) {
127136
let sample = api::Sample {
128137
locations: locations.clone(),
129138
values: &values,
130-
labels: vec![],
139+
labels: labels_api.clone(),
131140
};
132141
black_box(profile.try_add_sample(sample, None)).unwrap();
133142
}
@@ -145,8 +154,7 @@ pub fn bench_add_sample_vs_add2(c: &mut Criterion) {
145154
.unwrap();
146155
let (locations, values) = make_stack_api2(frames2.as_slice());
147156
for _ in 0..1000 {
148-
// Provide an empty iterator for labels conversion path
149-
let labels_iter = std::iter::empty::<anyhow::Result<api2::Label>>();
157+
let labels_iter = [Ok(api2::Label::num(thread_id_key, thread_id, ""))].into_iter();
150158
// SAFETY: all ids come from the profile's dictionary.
151159
black_box(unsafe {
152160
profile.try_add_sample2(&locations, &values, labels_iter, None)

0 commit comments

Comments
 (0)