@@ -31,6 +31,15 @@ use std::sync::atomic::AtomicU64;
3131use std:: sync:: { Arc , Mutex } ;
3232use std:: time:: { Duration , SystemTime } ;
3333
34+ #[ cfg( feature = "otel" ) ]
35+ use enum_map:: EnumMap ;
36+ #[ cfg( feature = "otel" ) ]
37+ use opentelemetry_proto:: tonic:: common:: v1:: { any_value, AnyValue } ;
38+ #[ cfg( feature = "otel" ) ]
39+ use prost:: Message ;
40+ #[ cfg( feature = "otel" ) ]
41+ use std:: io:: Write ;
42+
3443pub struct Profile {
3544 /// Translates from the new Id2 APIs to the older internal APIs. Long-term,
3645 /// this should probably use the dictionary directly.
@@ -45,7 +54,9 @@ pub struct Profile {
4554 mappings : FxIndexSet < Mapping > ,
4655 observations : Observations ,
4756 period : Option < api:: Period > ,
48- sample_types : Box < [ api:: SampleType ] > ,
57+ #[ cfg( feature = "otel" ) ]
58+ sample_type_index_map : EnumMap < api:: SampleType , Option < usize > > ,
59+ sample_types : std:: sync:: Arc < [ api:: SampleType ] > ,
4960 stack_traces : FxIndexSet < StackTrace > ,
5061 start_time : SystemTime ,
5162 strings : StringTable ,
@@ -391,7 +402,7 @@ impl Profile {
391402 sample_types : & [ api:: SampleType ] ,
392403 period : Option < api:: Period > ,
393404 ) -> io:: Result < Self > {
394- Self :: try_new_internal ( period, sample_types . to_vec ( ) . into_boxed_slice ( ) , None , None )
405+ Self :: try_new_internal ( period, std :: sync :: Arc :: from ( sample_types ) , None , None )
395406 }
396407
397408 /// Tries to create a profile with the given period and sample types.
@@ -404,7 +415,7 @@ impl Profile {
404415 ) -> io:: Result < Self > {
405416 Self :: try_new_internal (
406417 period,
407- sample_types . to_vec ( ) . into_boxed_slice ( ) ,
418+ std :: sync :: Arc :: from ( sample_types ) ,
408419 None ,
409420 Some ( ProfilesDictionaryTranslator :: new ( profiles_dictionary) ) ,
410421 )
@@ -418,7 +429,7 @@ impl Profile {
418429 ) -> io:: Result < Self > {
419430 Self :: try_new_internal (
420431 period,
421- sample_types . to_vec ( ) . into_boxed_slice ( ) ,
432+ std :: sync :: Arc :: from ( sample_types ) ,
422433 Some ( string_storage) ,
423434 None ,
424435 )
@@ -445,7 +456,7 @@ impl Profile {
445456
446457 let mut profile = Profile :: try_new_internal (
447458 self . period ,
448- self . sample_types . clone ( ) ,
459+ std :: sync :: Arc :: clone ( & self . sample_types ) ,
449460 self . string_storage . clone ( ) ,
450461 profiles_dictionary_translator,
451462 )
@@ -559,7 +570,7 @@ impl Profile {
559570 let period = self . period . map ( |period| period. value ) . unwrap_or ( 0 ) ;
560571
561572 let sample_types = self . sample_types . clone ( ) ;
562- let mut otel_profiles: HashMap < SampleType , crate :: otel:: Profile > = sample_types
573+ let mut otel_profiles: HashMap < api :: SampleType , crate :: otel:: Profile > = sample_types
563574 . iter ( )
564575 . map ( |st| {
565576 let sample_type = self . intern_sample_type ( * st) ;
@@ -651,13 +662,6 @@ impl Profile {
651662 } )
652663 . collect ( ) ;
653664
654- use std:: io:: Write ;
655-
656- use opentelemetry_proto:: tonic:: common:: v1:: { any_value, AnyValue } ;
657- use prost:: Message ;
658-
659- use crate :: api:: SampleType ;
660-
661665 let attribute_table: Vec < crate :: otel:: KeyValueAndUnit > =
662666 std:: iter:: once ( crate :: otel:: KeyValueAndUnit :: default ( ) )
663667 . chain ( std:: mem:: take ( & mut self . labels ) . into_iter ( ) . map ( |label| {
@@ -1283,10 +1287,17 @@ impl Profile {
12831287 /// the owned values.
12841288 fn try_new_internal (
12851289 period : Option < api:: Period > ,
1286- sample_types : Box < [ api:: SampleType ] > ,
1290+ sample_types : std :: sync :: Arc < [ api:: SampleType ] > ,
12871291 string_storage : Option < Arc < Mutex < ManagedStringStorage > > > ,
12881292 profiles_dictionary_translator : Option < ProfilesDictionaryTranslator > ,
12891293 ) -> io:: Result < Self > {
1294+ #[ cfg( feature = "otel" ) ]
1295+ let sample_type_index_map = sample_types
1296+ . iter ( )
1297+ . enumerate ( )
1298+ . map ( |( idx, & st) | ( st, Some ( idx) ) )
1299+ . collect :: < EnumMap < api:: SampleType , Option < usize > > > ( ) ;
1300+
12901301 let start_time = SystemTime :: now ( ) ;
12911302 let mut profile = Self {
12921303 profiles_dictionary_translator,
@@ -1301,6 +1312,8 @@ impl Profile {
13011312 mappings : Default :: default ( ) ,
13021313 observations : Default :: default ( ) ,
13031314 period,
1315+ #[ cfg( feature = "otel" ) ]
1316+ sample_type_index_map,
13041317 sample_types,
13051318 stack_traces : Default :: default ( ) ,
13061319 start_time,
@@ -1339,7 +1352,10 @@ impl Profile {
13391352 profile. observations = {
13401353 #[ cfg( feature = "otel" ) ]
13411354 {
1342- Observations :: new ( profile. sample_types . clone ( ) )
1355+ Observations :: new (
1356+ std:: sync:: Arc :: clone ( & profile. sample_types ) ,
1357+ profile. sample_type_index_map ,
1358+ )
13431359 }
13441360 #[ cfg( not( feature = "otel" ) ) ]
13451361 {
@@ -1616,10 +1632,7 @@ mod api_tests {
16161632
16171633 let dict = data. dictionary . as_ref ( ) . expect ( "dictionary" ) ;
16181634 let scope = & data. resource_profiles [ 0 ] . scope_profiles [ 0 ] ;
1619- let otel_profile = scope
1620- . profiles
1621- . first ( )
1622- . expect ( "one profile for CpuSamples" ) ;
1635+ let otel_profile = scope. profiles . first ( ) . expect ( "one profile for CpuSamples" ) ;
16231636
16241637 assert_eq ! ( otel_profile. sample. len( ) , 3 ) ;
16251638 assert_eq ! ( dict. mapping_table. len( ) , 2 ) ; // default + 1 real
@@ -1639,7 +1652,8 @@ mod api_tests {
16391652 assert_eq ! ( value, 101 ) ;
16401653 }
16411654
1642- // OTEL stores timestamps in timestamps_unix_nano, not as attributes (unlike pprof's end_timestamp_ns label)
1655+ // OTEL stores timestamps in timestamps_unix_nano, not as attributes (unlike pprof's
1656+ // end_timestamp_ns label)
16431657 let sample_with_timestamp = samples
16441658 . iter ( )
16451659 . find ( |s| !s. timestamps_unix_nano . is_empty ( ) )
@@ -1714,7 +1728,10 @@ mod api_tests {
17141728 . iter ( )
17151729 . find ( |s| otel_sample_attr_int ( dict, s, "local root span id" ) == Some ( 10 ) )
17161730 . expect ( "sample with span id 10" ) ;
1717- assert_eq ! ( otel_sample_attr_int( dict, s1, "local root span id" ) , Some ( 10 ) ) ;
1731+ assert_eq ! (
1732+ otel_sample_attr_int( dict, s1, "local root span id" ) ,
1733+ Some ( 10 )
1734+ ) ;
17181735 assert_eq ! ( otel_sample_attr_str( dict, s1, "other" ) , Some ( "test" ) ) ;
17191736 assert_eq ! (
17201737 otel_sample_attr_str( dict, s1, "trace endpoint" ) ,
@@ -1725,7 +1742,10 @@ mod api_tests {
17251742 . iter ( )
17261743 . find ( |s| otel_sample_attr_int ( dict, s, "local root span id" ) == Some ( 11 ) )
17271744 . expect ( "sample with span id 11" ) ;
1728- assert_eq ! ( otel_sample_attr_int( dict, s2, "local root span id" ) , Some ( 11 ) ) ;
1745+ assert_eq ! (
1746+ otel_sample_attr_int( dict, s2, "local root span id" ) ,
1747+ Some ( 11 )
1748+ ) ;
17291749 assert_eq ! ( otel_sample_attr_str( dict, s2, "other" ) , Some ( "test" ) ) ;
17301750 assert_eq ! ( otel_sample_attr_str( dict, s2, "trace endpoint" ) , None ) ;
17311751 Ok ( ( ) )
@@ -1798,7 +1818,10 @@ mod api_tests {
17981818 . iter ( )
17991819 . find ( |s| otel_sample_attr_int ( dict, s, "local root span id" ) == Some ( 10 ) )
18001820 . expect ( "sample with span id 10" ) ;
1801- assert_eq ! ( otel_sample_attr_int( dict, s1, "local root span id" ) , Some ( 10 ) ) ;
1821+ assert_eq ! (
1822+ otel_sample_attr_int( dict, s1, "local root span id" ) ,
1823+ Some ( 10 )
1824+ ) ;
18021825 assert_eq ! (
18031826 otel_sample_attr_str( dict, s1, "trace endpoint" ) ,
18041827 Some ( "endpoint 10" )
0 commit comments