diff --git a/profiling-ffi/src/profiles.rs b/profiling-ffi/src/profiles.rs index 4da028970..7c4ca9f19 100644 --- a/profiling-ffi/src/profiles.rs +++ b/profiling-ffi/src/profiles.rs @@ -245,10 +245,10 @@ impl<'a> TryFrom<&'a Mapping<'a>> for api::Mapping<'a> { impl<'a> From<&'a ValueType<'a>> for api::ValueType<'a> { fn from(vt: &'a ValueType<'a>) -> Self { - Self { - r#type: vt.type_.try_to_utf8().unwrap_or(""), - unit: vt.unit.try_to_utf8().unwrap_or(""), - } + Self::new( + vt.type_.try_to_utf8().unwrap_or(""), + vt.unit.try_to_utf8().unwrap_or(""), + ) } } @@ -693,7 +693,9 @@ pub unsafe extern "C" fn ddog_prof_Profile_serialize( ) -> SerializeResult { (|| { let profile = profile_ptr_to_inner(profile)?; - let old_profile = profile.reset_and_return_previous(start_time.map(SystemTime::from))?; + + let start_time = start_time.map(SystemTime::from); + let old_profile = profile.reset_and_return_previous(start_time)?; let end_time = end_time.map(SystemTime::from); let duration = match duration_nanos { None => None, diff --git a/profiling-replayer/src/replayer.rs b/profiling-replayer/src/replayer.rs index 2aba4eb1a..2d7cada21 100644 --- a/profiling-replayer/src/replayer.rs +++ b/profiling-replayer/src/replayer.rs @@ -60,10 +60,10 @@ impl<'pprof> Replayer<'pprof> { ) -> anyhow::Result>> { let mut sample_types = Vec::with_capacity(profile_index.pprof.sample_types.len()); for sample_type in profile_index.pprof.sample_types.iter() { - sample_types.push(api::ValueType { - r#type: profile_index.get_string(sample_type.r#type)?, - unit: profile_index.get_string(sample_type.unit)?, - }) + sample_types.push(api::ValueType::new( + profile_index.get_string(sample_type.r#type)?, + profile_index.get_string(sample_type.unit)?, + )) } Ok(sample_types) } @@ -75,10 +75,10 @@ impl<'pprof> Replayer<'pprof> { match profile_index.pprof.period_type { Some(period_type) => { - let r#type = api::ValueType { - r#type: profile_index.get_string(period_type.r#type)?, - unit: profile_index.get_string(period_type.unit)?, - }; + let r#type = api::ValueType::new( + profile_index.get_string(period_type.r#type)?, + profile_index.get_string(period_type.unit)?, + ); Ok(Some(api::Period { r#type, value })) } None => Ok(None), diff --git a/profiling/examples/profiles.rs b/profiling/examples/profiles.rs index c4612478b..955d46927 100644 --- a/profiling/examples/profiles.rs +++ b/profiling/examples/profiles.rs @@ -9,17 +9,8 @@ use std::time::SystemTime; // Keep this in-sync with profiles.c fn main() { - let walltime = api::ValueType { - r#type: "wall-time", - unit: "nanoseconds", - }; - let sample_types = vec![ - api::ValueType { - r#type: "samples", - unit: "count", - }, - walltime, - ]; + let walltime = api::ValueType::new("wall-time", "nanoseconds"); + let sample_types = [api::ValueType::new("samples", "count"), walltime]; let period = api::Period { r#type: walltime, diff --git a/profiling/src/api.rs b/profiling/src/api.rs index 566eb6cdf..a2ed310f5 100644 --- a/profiling/src/api.rs +++ b/profiling/src/api.rs @@ -11,6 +11,13 @@ pub struct ValueType<'a> { pub unit: &'a str, } +impl<'a> ValueType<'a> { + #[inline(always)] + pub fn new(r#type: &'a str, unit: &'a str) -> Self { + Self { r#type, unit } + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Period<'a> { pub r#type: ValueType<'a>, @@ -280,10 +287,10 @@ impl<'a> TryFrom<&'a pprof::Profile> for Profile<'a> { let period = match pprof.period_type { Some(t) => { - let r#type = ValueType { - r#type: string_table_fetch(pprof, t.r#type)?, - unit: string_table_fetch(pprof, t.unit)?, - }; + let r#type = ValueType::new( + string_table_fetch(pprof, t.r#type)?, + string_table_fetch(pprof, t.unit)?, + ); Some((pprof.period, r#type)) } None => None, @@ -291,10 +298,10 @@ impl<'a> TryFrom<&'a pprof::Profile> for Profile<'a> { let mut sample_types = Vec::with_capacity(pprof.samples.len()); for t in pprof.sample_types.iter() { - sample_types.push(ValueType { - r#type: string_table_fetch(pprof, t.r#type)?, - unit: string_table_fetch(pprof, t.unit)?, - }); + sample_types.push(ValueType::new( + string_table_fetch(pprof, t.r#type)?, + string_table_fetch(pprof, t.unit)?, + )); } let mut samples = Vec::with_capacity(pprof.samples.len()); diff --git a/profiling/src/internal/mod.rs b/profiling/src/internal/mod.rs index f6769de6b..72f11a9c1 100644 --- a/profiling/src/internal/mod.rs +++ b/profiling/src/internal/mod.rs @@ -8,6 +8,7 @@ mod label; mod location; mod mapping; mod observation; +mod owned_types; mod profile; mod sample; mod stack_trace; @@ -22,6 +23,7 @@ pub use label::*; pub use location::*; pub use mapping::*; pub use observation::*; +pub use owned_types::*; pub use profile::*; pub use sample::*; pub use stack_trace::*; diff --git a/profiling/src/internal/owned_types.rs b/profiling/src/internal/owned_types.rs new file mode 100644 index 000000000..4df1058ca --- /dev/null +++ b/profiling/src/internal/owned_types.rs @@ -0,0 +1,36 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::api::{Period, ValueType}; + +#[derive(Clone)] +pub struct OwnedValueType { + pub typ: Box, + pub unit: Box, +} + +impl<'a> From<&'a ValueType<'a>> for OwnedValueType { + #[inline] + fn from(value_type: &'a ValueType<'a>) -> Self { + Self { + typ: String::from(value_type.r#type).into(), + unit: String::from(value_type.unit).into(), + } + } +} + +#[derive(Clone)] +pub struct OwnedPeriod { + pub typ: OwnedValueType, + pub value: i64, +} + +impl<'a> From<&'a Period<'a>> for OwnedPeriod { + #[inline] + fn from(period: &'a Period<'a>) -> Self { + Self { + typ: OwnedValueType::from(&period.r#type), + value: period.value, + } + } +} diff --git a/profiling/src/internal/profile.rs b/profiling/src/internal/profile.rs index fcb67ebdc..2c74561a5 100644 --- a/profiling/src/internal/profile.rs +++ b/profiling/src/internal/profile.rs @@ -12,6 +12,14 @@ use std::collections::HashMap; use std::time::{Duration, SystemTime}; pub struct Profile { + /// When profiles are reset, the sample-types need to be preserved. This + /// maintains them in a way that does not depend on the string table. The + /// Option part is this is taken from the old profile and moved to the new + /// one. + owned_sample_types: Option>, + /// When profiles are reset, the period needs to be preserved. This + /// stores it in a way that does not depend on the string table. + owned_period: Option, endpoints: Endpoints, functions: FxIndexSet, labels: FxIndexSet