From d0f71f1df918e59b6f58ba6a4d91f09a75022a57 Mon Sep 17 00:00:00 2001 From: Paul Bone Date: Fri, 10 Nov 2017 10:12:57 +0300 Subject: [PATCH] Add basic calculation of the total full-collection time Issue #139 (bdwgc). New API functions: GC_start_performance_measurement, GC_get_full_gc_total_time. This patch is based on code originally written by Zoltan Somogyi on 2008-03-18. * alloc.c [!NO_CLOCK] (full_gc_total_time, measure_performance): New static variable definition; add comment. * alloc.c [!NO_CLOCK] (GC_start_performance_measurement, GC_get_full_gc_total_time): New API function definition. * alloc.c [!NO_CLOCK] (GC_try_to_collect_inner): Declare start_time_valid local variable; set start_time_valid to true if GET_TIME(start_time) is called; call GET_TIME(start_time) also if measure_performance; declare time_diff local variable (used to store the result of MS_TIME_DIFF()); GET_TIME(current_time) is called only if start_time_valid; update full_gc_total_time if measure_performance. * include/gc.h (GC_start_performance_measurement, GC_get_full_gc_total_time): New API function declaration. * tests/test.c (INIT_PERF_MEASUREMENT): New macro. * tests/test.c (GC_COND_INIT): Call INIT_PERF_MEASUREMENT. * tests/test.c [!NO_CLOCK] (check_heap_stats): Call GC_get_full_gc_total_time() and print the total time of full collections. --- alloc.c | 35 ++++++++++++++++++++++++++++++----- include/gc.h | 14 ++++++++++++++ tests/test.c | 12 +++++++++++- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/alloc.c b/alloc.c index 551092f7..bca4f02f 100644 --- a/alloc.c +++ b/alloc.c @@ -63,6 +63,23 @@ word GC_non_gc_bytes = 0; /* Number of bytes not intended to be collected */ word GC_gc_no = 0; +#ifndef NO_CLOCK + static unsigned long full_gc_total_time = 0; /* in msecs, may wrap */ + static GC_bool measure_performance = FALSE; + /* Do performance measurements if set to true (e.g., */ + /* accumulation of the total time of full collections). */ + + GC_API void GC_CALL GC_start_performance_measurement(void) + { + measure_performance = TRUE; + } + + GC_API unsigned long GC_CALL GC_get_full_gc_total_time(void) + { + return full_gc_total_time; + } +#endif /* !NO_CLOCK */ + #ifndef GC_DISABLE_INCREMENTAL GC_INNER GC_bool GC_incremental = FALSE; /* By default, stop the world. */ #endif @@ -442,6 +459,7 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func) { # ifndef NO_CLOCK CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */ + GC_bool start_time_valid; # endif ASSERT_CANCEL_DISABLED(); @@ -463,9 +481,12 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func) } GC_notify_full_gc(); # ifndef NO_CLOCK - if (GC_print_stats) { + start_time_valid = FALSE; + if ((GC_print_stats | (int)measure_performance) != 0) { + if (GC_print_stats) + GC_log_printf("Initiating full world-stop collection!\n"); + start_time_valid = TRUE; GET_TIME(start_time); - GC_log_printf("Initiating full world-stop collection!\n"); } # endif GC_promote_black_lists(); @@ -504,12 +525,16 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func) } GC_finish_collection(); # ifndef NO_CLOCK - if (GC_print_stats) { + if (start_time_valid) { CLOCK_TYPE current_time; + unsigned long time_diff; GET_TIME(current_time); - GC_log_printf("Complete collection took %lu msecs\n", - MS_TIME_DIFF(current_time,start_time)); + time_diff = MS_TIME_DIFF(current_time, start_time); + if (measure_performance) + full_gc_total_time += time_diff; /* may wrap */ + if (GC_print_stats) + GC_log_printf("Complete collection took %lu msecs\n", time_diff); } # endif if (GC_on_collection_event) diff --git a/include/gc.h b/include/gc.h index 956458de..6b50d29d 100644 --- a/include/gc.h +++ b/include/gc.h @@ -395,6 +395,20 @@ GC_API unsigned long GC_CALL GC_get_time_limit(void); /* Public procedures */ +/* Tell the collector to start various performance measurements. */ +/* Only the total time taken by full collections is calculated, as */ +/* of now. And, currently, there is no way to stop the measurements. */ +/* The function does not use any synchronization. Defined only if the */ +/* library has been compiled without NO_CLOCK. */ +GC_API void GC_CALL GC_start_performance_measurement(void); + +/* Get the total time of all full collections since the start of the */ +/* performance measurements. The measurement unit is one millisecond. */ +/* Note that the returned value wraps around on overflow. */ +/* The function does not use any synchronization. Defined only if the */ +/* library has been compiled without NO_CLOCK. */ +GC_API unsigned long GC_CALL GC_get_full_gc_total_time(void); + /* Set whether the GC will allocate executable memory pages or not. */ /* A non-zero argument instructs the collector to allocate memory with */ /* the executable flag on. Must be called before the collector is */ diff --git a/tests/test.c b/tests/test.c index 453bfe73..71a04b54 100644 --- a/tests/test.c +++ b/tests/test.c @@ -155,8 +155,15 @@ # define GC_OPT_INIT /* empty */ #endif +#ifdef NO_CLOCK +# define INIT_PERF_MEASUREMENT (void)0 +#else +# define INIT_PERF_MEASUREMENT GC_start_performance_measurement() +#endif + #define GC_COND_INIT() \ - INIT_FORK_SUPPORT; GC_OPT_INIT; CHECK_GCLIB_VERSION; INIT_PRINT_STATS + INIT_FORK_SUPPORT; GC_OPT_INIT; CHECK_GCLIB_VERSION; \ + INIT_PRINT_STATS; INIT_PERF_MEASUREMENT #define CHECK_OUT_OF_MEMORY(p) \ if ((p) == NULL) { \ @@ -1726,6 +1733,9 @@ void check_heap_stats(void) GC_unregister_my_thread(); /* just to check it works (for main) */ # endif GC_printf("Completed %u collections", (unsigned)GC_get_gc_no()); +# ifndef NO_CLOCK + GC_printf(" in %lu msecs", GC_get_full_gc_total_time()); +# endif # ifdef PARALLEL_MARK GC_printf(" (using %d marker threads)", GC_get_parallel() + 1); # endif -- 2.40.0