From e97cfc5e1304d23b07fc8adc47ea46ce8368bab6 Mon Sep 17 00:00:00 2001 From: r1viollet Date: Fri, 6 Mar 2026 09:44:14 +0100 Subject: [PATCH 1/2] feat(profiling)!: add Tracepoint sample type ddprof uses "tracepoint"/"events" as the sample type for hardware counters and perf tracepoint events. The v28 enum-based SampleType API had no equivalent, causing those profiles to fall back to "sample"/"count" and breaking the Datadog backend rendering. Add `SampleType::Tracepoint` mapping to `ValueType::new("tracepoint", "events")`. Co-Authored-By: Claude Sonnet 4.6 --- libdd-profiling/src/api/sample_type.rs | 3 +++ libdd-profiling/src/cxx.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/libdd-profiling/src/api/sample_type.rs b/libdd-profiling/src/api/sample_type.rs index 1554fb46ca..4e1156b4bb 100644 --- a/libdd-profiling/src/api/sample_type.rs +++ b/libdd-profiling/src/api/sample_type.rs @@ -58,6 +58,7 @@ pub enum SampleType { ObjectsLegacy, RequestTime, Sample, + Tracepoint, SocketReadSize, SocketReadSizeSamples, SocketReadTime, @@ -137,6 +138,7 @@ impl From for ValueType<'static> { SampleType::ObjectsLegacy => ValueType::new("objects", "count"), SampleType::RequestTime => ValueType::new("request-time", "nanoseconds"), SampleType::Sample => ValueType::new("sample", "count"), + SampleType::Tracepoint => ValueType::new("tracepoint", "events"), SampleType::SocketReadSize => ValueType::new("socket-read-size", "bytes"), SampleType::SocketReadSizeSamples => { ValueType::new("socket-read-size-samples", "count") @@ -210,6 +212,7 @@ impl<'a> TryFrom> for SampleType { ("objects", "count") => SampleType::ObjectsLegacy, ("request-time", "nanoseconds") => SampleType::RequestTime, ("sample", "count") => SampleType::Sample, + ("tracepoint", "events") => SampleType::Tracepoint, ("socket-read-size", "bytes") => SampleType::SocketReadSize, ("socket-read-size-samples", "count") => SampleType::SocketReadSizeSamples, ("socket-read-time", "nanoseconds") => SampleType::SocketReadTime, diff --git a/libdd-profiling/src/cxx.rs b/libdd-profiling/src/cxx.rs index 7895ab4535..312b1c636d 100644 --- a/libdd-profiling/src/cxx.rs +++ b/libdd-profiling/src/cxx.rs @@ -75,6 +75,7 @@ pub mod ffi { ObjectsLegacy, // LEGACY: Use InuseObjects instead RequestTime, Sample, + Tracepoint, SocketReadSize, SocketReadSizeSamples, SocketReadTime, @@ -376,6 +377,7 @@ impl TryFrom for api::SampleType { ffi::SampleType::ObjectsLegacy => api::SampleType::ObjectsLegacy, ffi::SampleType::RequestTime => api::SampleType::RequestTime, ffi::SampleType::Sample => api::SampleType::Sample, + ffi::SampleType::Tracepoint => api::SampleType::Tracepoint, ffi::SampleType::SocketReadSize => api::SampleType::SocketReadSize, ffi::SampleType::SocketReadSizeSamples => api::SampleType::SocketReadSizeSamples, ffi::SampleType::SocketReadTime => api::SampleType::SocketReadTime, From 383bbf98c37a81162cb9cfcd42c410e6ed97387a Mon Sep 17 00:00:00 2001 From: r1viollet Date: Fri, 6 Mar 2026 11:38:35 +0100 Subject: [PATCH 2/2] feat(profiling): expose SampleType type/unit strings via C FFI Add `ddog_prof_SampleType_type_str` and `ddog_prof_SampleType_unit_str` functions that return the pprof column name strings (e.g. "cpu-time", "nanoseconds") for a given SampleType enum value. This allows consumers to verify or log the exact strings that libdatadog writes into pprof profiles, without maintaining their own mapping table that can drift out of sync. Co-Authored-By: Claude Sonnet 4.6 --- libdd-profiling-ffi/src/profiles/datatypes.rs | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/libdd-profiling-ffi/src/profiles/datatypes.rs b/libdd-profiling-ffi/src/profiles/datatypes.rs index c7ec589d5c..0436db2a1b 100644 --- a/libdd-profiling-ffi/src/profiles/datatypes.rs +++ b/libdd-profiling-ffi/src/profiles/datatypes.rs @@ -101,6 +101,24 @@ impl From> for SerializeResult { /// Re-exported from libdd_profiling::api for FFI use. pub use api::SampleType; +/// Returns the pprof type string for a `SampleType` (e.g. `"cpu-time"`). +/// The returned slice points to a static string; it is always valid and +/// never needs to be freed. +#[no_mangle] +pub extern "C" fn ddog_prof_SampleType_type_str(sample_type: SampleType) -> CharSlice<'static> { + let vt: api::ValueType = sample_type.into(); + CharSlice::from(vt.r#type) +} + +/// Returns the pprof unit string for a `SampleType` (e.g. `"nanoseconds"`). +/// The returned slice points to a static string; it is always valid and +/// never needs to be freed. +#[no_mangle] +pub extern "C" fn ddog_prof_SampleType_unit_str(sample_type: SampleType) -> CharSlice<'static> { + let vt: api::ValueType = sample_type.into(); + CharSlice::from(vt.unit) +} + /// Re-export Period from the API for consistency. /// The FFI Period is identical to the API Period. pub use api::Period; @@ -1094,4 +1112,36 @@ mod tests { ddog_prof_Profile_drop(&mut provide_distinct_locations_ffi()); } } + + #[test] + fn sample_type_str_functions() { + // Verify that the type/unit strings match expected pprof column names. + // These strings are what the backend uses to identify profile types, so + // any change here would be a breaking change for consumers. + let cases: &[(SampleType, &str, &str)] = &[ + (SampleType::CpuTime, "cpu-time", "nanoseconds"), + (SampleType::CpuSamples, "cpu-samples", "count"), + (SampleType::AllocSpace, "alloc-space", "bytes"), + (SampleType::AllocSamples, "alloc-samples", "count"), + (SampleType::InuseSpace, "inuse-space", "bytes"), + (SampleType::InuseObjects, "inuse-objects", "count"), + (SampleType::Tracepoint, "tracepoint", "events"), + (SampleType::WallTime, "wall-time", "nanoseconds"), + (SampleType::WallSamples, "wall-samples", "count"), + ]; + for &(sample_type, expected_type, expected_unit) in cases { + let type_str = ddog_prof_SampleType_type_str(sample_type); + let unit_str = ddog_prof_SampleType_unit_str(sample_type); + assert_eq!( + type_str.try_to_utf8().unwrap(), + expected_type, + "type string mismatch for {sample_type:?}" + ); + assert_eq!( + unit_str.try_to_utf8().unwrap(), + expected_unit, + "unit string mismatch for {sample_type:?}" + ); + } + } }