11use crate :: config:: AgentEndpoint ;
2- use crate :: profiling:: { UploadMessage , UploadRequest } ;
2+ use crate :: profiling:: {
3+ update_cpu_time_counter, UploadMessage , UploadRequest , DDPROF_TIME_CPU_TIME_NS ,
4+ DDPROF_UPLOAD_CPU_TIME_NS , STACK_WALK_COUNT , STACK_WALK_CPU_TIME_NS ,
5+ } ;
36use crate :: { PROFILER_NAME_STR , PROFILER_VERSION_STR } ;
47use chrono:: { DateTime , Utc } ;
8+ use cpu_time:: ThreadTime ;
59use crossbeam_channel:: { select, Receiver } ;
610use libdd_common:: Endpoint ;
711use log:: { debug, info, warn} ;
@@ -14,7 +18,6 @@ use std::sync::{Arc, Barrier};
1418use crate :: allocation:: { ALLOCATION_PROFILING_COUNT , ALLOCATION_PROFILING_SIZE } ;
1519#[ cfg( feature = "debug_stats" ) ]
1620use crate :: exception:: EXCEPTION_PROFILING_EXCEPTION_COUNT ;
17- #[ cfg( feature = "debug_stats" ) ]
1821use std:: sync:: atomic:: Ordering ;
1922
2023pub struct Uploader {
@@ -44,13 +47,41 @@ impl Uploader {
4447
4548 /// This function will not only create the internal metadata JSON representation, but is also
4649 /// in charge to reset all those counters back to 0.
47- #[ cfg( feature = "debug_stats" ) ]
4850 fn create_internal_metadata ( ) -> Option < serde_json:: Value > {
49- Some ( json ! ( {
50- "exceptions_count" : EXCEPTION_PROFILING_EXCEPTION_COUNT . swap( 0 , Ordering :: Relaxed ) ,
51- "allocations_count" : ALLOCATION_PROFILING_COUNT . swap( 0 , Ordering :: Relaxed ) ,
52- "allocations_size" : ALLOCATION_PROFILING_SIZE . swap( 0 , Ordering :: Relaxed ) ,
53- } ) )
51+ let capacity = 4 + cfg ! ( feature = "debug_stats" ) as usize * 3 ;
52+ let mut metadata = serde_json:: Map :: with_capacity ( capacity) ;
53+ metadata. insert (
54+ "stack_walk_count" . to_string ( ) ,
55+ json ! ( STACK_WALK_COUNT . swap( 0 , Ordering :: Relaxed ) ) ,
56+ ) ;
57+ metadata. insert (
58+ "stack_walk_cpu_time_ns" . to_string ( ) ,
59+ json ! ( STACK_WALK_CPU_TIME_NS . swap( 0 , Ordering :: Relaxed ) ) ,
60+ ) ;
61+ metadata. insert (
62+ "ddprof_time_cpu_time_ns" . to_string ( ) ,
63+ json ! ( DDPROF_TIME_CPU_TIME_NS . swap( 0 , Ordering :: Relaxed ) ) ,
64+ ) ;
65+ metadata. insert (
66+ "ddprof_upload_cpu_time_ns" . to_string ( ) ,
67+ json ! ( DDPROF_UPLOAD_CPU_TIME_NS . swap( 0 , Ordering :: Relaxed ) ) ,
68+ ) ;
69+ #[ cfg( feature = "debug_stats" ) ]
70+ {
71+ metadata. insert (
72+ "exceptions_count" . to_string ( ) ,
73+ json ! ( EXCEPTION_PROFILING_EXCEPTION_COUNT . swap( 0 , Ordering :: Relaxed ) ) ,
74+ ) ;
75+ metadata. insert (
76+ "allocations_count" . to_string ( ) ,
77+ json ! ( ALLOCATION_PROFILING_COUNT . swap( 0 , Ordering :: Relaxed ) ) ,
78+ ) ;
79+ metadata. insert (
80+ "allocations_size" . to_string ( ) ,
81+ json ! ( ALLOCATION_PROFILING_SIZE . swap( 0 , Ordering :: Relaxed ) ) ,
82+ ) ;
83+ }
84+ Some ( serde_json:: Value :: Object ( metadata) )
5485 }
5586
5687 fn create_profiler_info ( & self ) -> Option < serde_json:: Value > {
@@ -62,7 +93,11 @@ impl Uploader {
6293 Some ( metadata)
6394 }
6495
65- fn upload ( & self , message : Box < UploadRequest > ) -> anyhow:: Result < u16 > {
96+ fn upload (
97+ & self ,
98+ message : Box < UploadRequest > ,
99+ last_cpu : & mut Option < ThreadTime > ,
100+ ) -> anyhow:: Result < u16 > {
66101 let index = message. index ;
67102 let profile = message. profile ;
68103
@@ -83,16 +118,18 @@ impl Uploader {
83118 let serialized =
84119 profile. serialize_into_compressed_pprof ( Some ( message. end_time ) , message. duration ) ?;
85120 exporter. set_timeout ( 10000 ) ; // 10 seconds in milliseconds
121+
122+ // Capture CPU time up to this point. Note: metadata generation, exporter
123+ // building, and HTTP request time will be attributed to the next profile.
124+ update_cpu_time_counter ( last_cpu, & DDPROF_UPLOAD_CPU_TIME_NS ) ;
125+
86126 let request = exporter. build (
87127 serialized,
88128 & [ ] ,
89129 & [ ] ,
90130 None ,
91131 None ,
92- #[ cfg( feature = "debug_stats" ) ]
93132 Self :: create_internal_metadata ( ) ,
94- #[ cfg( not( feature = "debug_stats" ) ) ]
95- None ,
96133 self . create_profiler_info ( ) ,
97134 ) ?;
98135 debug ! ( "Sending profile to: {agent_endpoint}" ) ;
@@ -106,7 +143,7 @@ impl Uploader {
106143 */
107144 let pprof_filename = & self . output_pprof ;
108145 let mut i = 0 ;
109-
146+ let mut last_cpu = ThreadTime :: try_now ( ) . ok ( ) ;
110147 loop {
111148 /* Since profiling uploads are going over the Internet and not just
112149 * the local network, it would be ideal if they were the lowest
@@ -132,7 +169,7 @@ impl Uploader {
132169 std:: fs:: write( & name, r. buffer) . expect( "write to succeed" ) ;
133170 info!( "Successfully wrote profile to {name}" ) ;
134171 } ,
135- None => match self . upload( request) {
172+ None => match self . upload( request, & mut last_cpu ) {
136173 Ok ( status) => {
137174 if status >= 400 {
138175 warn!( "Unexpected HTTP status when sending profile (HTTP {status})." )
@@ -169,6 +206,10 @@ mod tests {
169206 #[ test]
170207 fn test_create_internal_metadata ( ) {
171208 // Set up all counters with known values
209+ STACK_WALK_COUNT . store ( 7 , Ordering :: Relaxed ) ;
210+ STACK_WALK_CPU_TIME_NS . store ( 9000 , Ordering :: Relaxed ) ;
211+ DDPROF_TIME_CPU_TIME_NS . store ( 1234 , Ordering :: Relaxed ) ;
212+ DDPROF_UPLOAD_CPU_TIME_NS . store ( 5678 , Ordering :: Relaxed ) ;
172213 EXCEPTION_PROFILING_EXCEPTION_COUNT . store ( 42 , Ordering :: Relaxed ) ;
173214 ALLOCATION_PROFILING_COUNT . store ( 100 , Ordering :: Relaxed ) ;
174215 ALLOCATION_PROFILING_SIZE . store ( 1024 , Ordering :: Relaxed ) ;
@@ -181,6 +222,28 @@ mod tests {
181222 let metadata = metadata. unwrap ( ) ;
182223
183224 // The metadata should contain all counts
225+ assert_eq ! (
226+ metadata. get( "stack_walk_count" ) . and_then( |v| v. as_u64( ) ) ,
227+ Some ( 7 )
228+ ) ;
229+ assert_eq ! (
230+ metadata
231+ . get( "stack_walk_cpu_time_ns" )
232+ . and_then( |v| v. as_u64( ) ) ,
233+ Some ( 9000 )
234+ ) ;
235+ assert_eq ! (
236+ metadata
237+ . get( "ddprof_time_cpu_time_ns" )
238+ . and_then( |v| v. as_u64( ) ) ,
239+ Some ( 1234 )
240+ ) ;
241+ assert_eq ! (
242+ metadata
243+ . get( "ddprof_upload_cpu_time_ns" )
244+ . and_then( |v| v. as_u64( ) ) ,
245+ Some ( 5678 )
246+ ) ;
184247
185248 assert_eq ! (
186249 metadata. get( "exceptions_count" ) . and_then( |v| v. as_u64( ) ) ,
0 commit comments