Skip to content

Commit 1947ea0

Browse files
committed
Move ddog_prof_ManagedStringStorage_advance_gen to happen outside the GVL
1 parent 3a6b887 commit 1947ea0

File tree

1 file changed

+12
-13
lines changed

1 file changed

+12
-13
lines changed

ext/datadog_profiling_native_extension/stack_recorder.c

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ typedef struct {
232232
ddog_prof_Profile_SerializeResult result;
233233
long heap_profile_build_time_ns;
234234
long serialize_no_gvl_time_ns;
235+
ddog_prof_MaybeError advance_gen_result;
235236

236237
// Set by both
237238
bool serialize_ran;
@@ -539,7 +540,7 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
539540
call_serialize_without_gvl_arguments args = {
540541
.state = state,
541542
.finish_timestamp = finish_timestamp,
542-
.serialize_ran = false
543+
.serialize_ran = false,
543544
};
544545

545546
while (!args.serialize_ran) {
@@ -563,13 +564,9 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
563564
// really cover the full serialization process but it gives a more useful number since it bypasses
564565
// the noise of acquiring GVLs and dealing with interruptions which is highly specific to runtime
565566
// 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;
573570

574571
ddog_prof_Profile_SerializeResult serialized_profile = args.result;
575572

@@ -578,7 +575,8 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
578575
return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&serialized_profile.err));
579576
}
580577

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.
582580

583581
state->stats_lifetime.serialization_successes++;
584582

@@ -591,15 +589,14 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
591589

592590
// It's now OK to again do things that can trigger exceptions
593591

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;
596593
if (result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
597594
rb_raise(rb_eRuntimeError, "Failed to advance string storage gen: %"PRIsVALUE, get_error_details_and_drop(&result.some));
598595
}
599596

600597
VALUE start = ruby_time_from(ddprof_start);
601598
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);
603600

604601
return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_pprof, profile_stats));
605602
}
@@ -796,8 +793,10 @@ static void *call_serialize_without_gvl(void *call_args) {
796793

797794
// Note: The profile gets reset by the serialize call
798795
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+
799798
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);
801800

802801
return NULL; // Unused
803802
}

0 commit comments

Comments
 (0)