@@ -232,6 +232,7 @@ typedef struct {
232
232
ddog_prof_Profile_SerializeResult result ;
233
233
long heap_profile_build_time_ns ;
234
234
long serialize_no_gvl_time_ns ;
235
+ ddog_prof_MaybeError advance_gen_result ;
235
236
236
237
// Set by both
237
238
bool serialize_ran ;
@@ -539,7 +540,7 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
539
540
call_serialize_without_gvl_arguments args = {
540
541
.state = state ,
541
542
.finish_timestamp = finish_timestamp ,
542
- .serialize_ran = false
543
+ .serialize_ran = false,
543
544
};
544
545
545
546
while (!args .serialize_ran ) {
@@ -563,13 +564,9 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
563
564
// really cover the full serialization process but it gives a more useful number since it bypasses
564
565
// the noise of acquiring GVLs and dealing with interruptions which is highly specific to runtime
565
566
// conditions and over which we really have no control about.
566
- long serialization_time_ns = args .serialize_no_gvl_time_ns ;
567
- if (serialization_time_ns >= 0 ) {
568
- // Only update stats if our serialization time is valid.
569
- state -> stats_lifetime .serialization_time_ns_max = long_max_of (state -> stats_lifetime .serialization_time_ns_max , serialization_time_ns );
570
- state -> stats_lifetime .serialization_time_ns_min = long_min_of (state -> stats_lifetime .serialization_time_ns_min , serialization_time_ns );
571
- state -> stats_lifetime .serialization_time_ns_total += serialization_time_ns ;
572
- }
567
+ state -> stats_lifetime .serialization_time_ns_max = long_max_of (state -> stats_lifetime .serialization_time_ns_max , args .serialize_no_gvl_time_ns );
568
+ state -> stats_lifetime .serialization_time_ns_min = long_min_of (state -> stats_lifetime .serialization_time_ns_min , args .serialize_no_gvl_time_ns );
569
+ state -> stats_lifetime .serialization_time_ns_total += args .serialize_no_gvl_time_ns ;
573
570
574
571
ddog_prof_Profile_SerializeResult serialized_profile = args .result ;
575
572
@@ -578,7 +575,8 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
578
575
return rb_ary_new_from_args (2 , error_symbol , get_error_details_and_drop (& serialized_profile .err ));
579
576
}
580
577
581
- // Note: Don't raise exceptions until `ddog_prof_EncodedProfile_drop` gets called, as otherwise the memory will leak.
578
+ // Note: If we got here, the profile serialized correctly. Don't raise exceptions until
579
+ // `ddog_prof_EncodedProfile_drop` gets called, as otherwise the memory will leak, and profiles can be a few megabytes.
582
580
583
581
state -> stats_lifetime .serialization_successes ++ ;
584
582
@@ -591,15 +589,14 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
591
589
592
590
// It's now OK to again do things that can trigger exceptions
593
591
594
- // @ivoanjo: Maybe this could be done without the GVL being held?
595
- ddog_prof_MaybeError result = ddog_prof_ManagedStringStorage_advance_gen (state -> string_storage );
592
+ ddog_prof_MaybeError result = args .advance_gen_result ;
596
593
if (result .tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR ) {
597
594
rb_raise (rb_eRuntimeError , "Failed to advance string storage gen: %" PRIsVALUE , get_error_details_and_drop (& result .some ));
598
595
}
599
596
600
597
VALUE start = ruby_time_from (ddprof_start );
601
598
VALUE finish = ruby_time_from (ddprof_finish );
602
- VALUE profile_stats = build_profile_stats (args .slot , serialization_time_ns , heap_iteration_prep_time_ns , args .heap_profile_build_time_ns );
599
+ VALUE profile_stats = build_profile_stats (args .slot , args . serialize_no_gvl_time_ns , heap_iteration_prep_time_ns , args .heap_profile_build_time_ns );
603
600
604
601
return rb_ary_new_from_args (2 , ok_symbol , rb_ary_new_from_args (4 , start , finish , encoded_pprof , profile_stats ));
605
602
}
@@ -796,8 +793,10 @@ static void *call_serialize_without_gvl(void *call_args) {
796
793
797
794
// Note: The profile gets reset by the serialize call
798
795
args -> result = ddog_prof_Profile_serialize (& args -> slot -> profile , & args -> finish_timestamp , NULL /* duration_nanos is optional */ , NULL /* start_time is optional */ );
796
+ args -> advance_gen_result = ddog_prof_ManagedStringStorage_advance_gen (args -> state -> string_storage );
797
+
799
798
args -> serialize_ran = true;
800
- args -> serialize_no_gvl_time_ns = monotonic_wall_time_now_ns (DO_NOT_RAISE_ON_FAILURE ) - serialize_no_gvl_start_time_ns ;
799
+ args -> serialize_no_gvl_time_ns = long_max_of ( 0 , monotonic_wall_time_now_ns (DO_NOT_RAISE_ON_FAILURE ) - serialize_no_gvl_start_time_ns ) ;
801
800
802
801
return NULL ; // Unused
803
802
}
0 commit comments