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
{
# ifndef NO_CLOCK
CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
+ GC_bool start_time_valid;
# endif
ASSERT_CANCEL_DISABLED();
}
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();
}
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)
/* 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 */
# 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) { \
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