diff options
author | Lucas Meijer <lucas@unity3d.com> | 2014-07-01 15:07:15 +0400 |
---|---|---|
committer | Lucas Meijer <lucas@unity3d.com> | 2014-07-01 15:09:50 +0400 |
commit | fd4903870d93f44ffae042e10b5ec6975a2fe7b4 (patch) | |
tree | c1dbf6b6bb814b2b5742d1784355c7e2c1faaa6f | |
parent | 6c5a455c722172f0defcfb77aa28b2709a191e7c (diff) |
Implement event callbacks to be used to profile the collectorprofiling-callbacks
-rw-r--r-- | alloc.c | 40 | ||||
-rw-r--r-- | darwin_stop_world.c | 6 | ||||
-rw-r--r-- | include/gc.h | 22 | ||||
-rw-r--r-- | misc.c | 21 | ||||
-rw-r--r-- | pthread_stop_world.c | 23 | ||||
-rw-r--r-- | win32_threads.c | 10 |
6 files changed, 114 insertions, 8 deletions
@@ -88,6 +88,8 @@ STATIC GC_bool GC_need_full_gc = FALSE; STATIC word GC_used_heap_size_after_full = 0; +extern GC_on_collection_event_proc GC_on_collection_event; + /* GC_copyright symbol is externally visible. */ char * const GC_copyright[] = {"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers ", @@ -429,6 +431,9 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func) } } GC_notify_full_gc(); + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_COLLECTION_BEGIN, NULL); + # ifndef SMALL_CONFIG if (GC_print_stats) { GET_TIME(start_time); @@ -581,6 +586,17 @@ GC_API int GC_CALL GC_collect_a_little(void) # define COMMA_IF_USE_MUNMAP(x) /* empty */ #endif +static void start_world() +{ + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_STARTWORLD_BEGIN, NULL); + + START_WORLD(); + + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_STARTWORLD_END, NULL); +} + /* * Assumes lock is held. We stop the world and mark from all roots. * If stop_func() ever returns TRUE, we may fail and return FALSE. @@ -606,7 +622,14 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func) GET_TIME(start_time); # endif + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_STOPWORLD_BEGIN, NULL); + STOP_WORLD(); + + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_STOPWORLD_END, NULL); + # ifdef THREAD_LOCAL_ALLOC GC_world_stopped = TRUE; # endif @@ -625,6 +648,9 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func) GC_clear_a_few_frames(); GC_noop6(0,0,0,0,0,0); + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_MARK_BEGIN, NULL); + GC_initiate_gc(); for (i = 0;;i++) { if ((*stop_func)()) { @@ -634,12 +660,19 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func) # ifdef THREAD_LOCAL_ALLOC GC_world_stopped = FALSE; # endif - START_WORLD(); + + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_MARK_END, NULL); + + start_world(); return(FALSE); } if (GC_mark_some(GC_approx_sp())) break; } + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_MARK_END, NULL); + GC_gc_no++; GC_DBGLOG_PRINTF("GC #%lu freed %ld bytes, heap %lu KiB" IF_USE_MUNMAP(" (+ %lu KiB unmapped)") "\n", @@ -655,7 +688,7 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func) # ifdef THREAD_LOCAL_ALLOC GC_world_stopped = FALSE; # endif - START_WORLD(); + start_world(); # ifndef SMALL_CONFIG if (GC_PRINT_STATS_FLAG) { unsigned long time_diff; @@ -961,6 +994,9 @@ STATIC void GC_finish_collection(void) MS_TIME_DIFF(done_time,finalize_time)); } # endif + + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_COLLECTION_END, NULL); } /* If stop_func == 0 then GC_default_stop_func is used instead. */ diff --git a/darwin_stop_world.c b/darwin_stop_world.c index a6b0a5c7..35a4ba7d 100644 --- a/darwin_stop_world.c +++ b/darwin_stop_world.c @@ -458,6 +458,8 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count, #endif /* !GC_NO_THREADS_DISCOVERY */ +extern GC_on_collection_event_proc GC_on_collection_event; + /* Caller holds allocation lock. */ GC_INNER void GC_stop_world(void) { @@ -540,6 +542,8 @@ GC_INNER void GC_stop_world(void) kern_result = thread_suspend(p->stop_info.mach_thread); if (kern_result != KERN_SUCCESS) ABORT("thread_suspend failed"); + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)p->stop_info.mach_thread); } } } @@ -654,6 +658,8 @@ GC_INNER void GC_start_world(void) if ((p->flags & FINISHED) == 0 && !p->thread_blocked && p->stop_info.mach_thread != my_thread) GC_thread_resume(p->stop_info.mach_thread); + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)p->stop_info.mach_thread); } } diff --git a/include/gc.h b/include/gc.h index 52c82a05..a034eb0f 100644 --- a/include/gc.h +++ b/include/gc.h @@ -129,6 +129,28 @@ GC_API GC_on_heap_resize_proc GC_CALL GC_get_on_heap_resize(void); /* Both the supplied setter and the getter */ /* acquire the GC lock (to avoid data races). */ +typedef enum +{ + GC_EVENT_COLLECTION_BEGIN, + GC_EVENT_STOPWORLD_BEGIN, + GC_EVENT_STOPWORLD_END, + GC_EVENT_MARK_BEGIN, + GC_EVENT_MARK_END, + GC_EVENT_STARTWORLD_BEGIN, + GC_EVENT_STARTWORLD_END, + GC_EVENT_COLLECTION_END, + GC_EVENT_THREAD_SUSPENDED, + GC_EVENT_THREAD_UNSUSPENDED +} GCEventKind; + +typedef void (GC_CALLBACK * GC_on_collection_event_proc)(GCEventKind, void*); + /* Invoked to indicate progress through the */ + /* collection process. */ + /* Called with the world stopped (and the */ + /* allocation lock held). May be 0. */ +GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc); +GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void); + GC_API GC_ATTR_DEPRECATED int GC_find_leak; /* Do not actually garbage collect, but simply */ /* report inaccessible memory that was not */ @@ -2034,6 +2034,27 @@ GC_API GC_on_heap_resize_proc GC_CALL GC_get_on_heap_resize(void) return fn; } +GC_on_collection_event_proc GC_on_collection_event = NULL; + +GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc fn) +{ + /* fn may be 0 (means no event notifier). */ + DCL_LOCK_STATE; + LOCK(); + GC_on_collection_event = fn; + UNLOCK(); +} + +GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void) +{ + GC_on_collection_event_proc fn; + DCL_LOCK_STATE; + LOCK(); + fn = GC_on_collection_event; + UNLOCK(); + return fn; +} + GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc fn) { /* fn may be 0 (means no finalizer notifier). */ diff --git a/pthread_stop_world.c b/pthread_stop_world.c index a68e9222..9bce8741 100644 --- a/pthread_stop_world.c +++ b/pthread_stop_world.c @@ -466,7 +466,7 @@ STATIC int GC_suspend_all(void) { int n_live_threads = 0; int i; - + int thread_id; # ifndef NACL GC_thread p; # ifndef GC_OPENBSD_UTHREADS @@ -499,13 +499,20 @@ STATIC int GC_suspend_all(void) if (pthread_stackseg_np(p->id, &stack)) ABORT("pthread_stackseg_np failed"); p -> stop_info.stack_ptr = (ptr_t)stack.ss_sp - stack.ss_size; + + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_THREAD_SUSPENDED, (void *)p->id); } # else # ifndef PLATFORM_ANDROID - result = pthread_kill(p -> id, GC_sig_suspend); + thread_id = p -> id; + result = pthread_kill(thread_id, GC_sig_suspend); # else - result = android_thread_kill(p -> kernel_id, GC_sig_suspend); + thread_id = p -> kernel_id; + result = android_thread_kill(thread_id, GC_sig_suspend); # endif + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_THREAD_SUSPENDED, (void *)threadid); switch(result) { case ESRCH: /* Not really there anymore. Possible? */ @@ -825,11 +832,15 @@ GC_INNER void GC_start_world(void) ABORT("pthread_resume_np failed"); # else # ifndef PLATFORM_ANDROID - result = pthread_kill(p -> id, GC_sig_thr_restart); + thread_id = p -> id; + result = pthread_kill(thread_id, GC_sig_thr_restart); # else - result = android_thread_kill(p -> kernel_id, - GC_sig_thr_restart); + thread_id = p -> kernel_id; + result = android_thread_kill(thread_id, GC_sig_thr_restart); # endif + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)thread_id); + switch(result) { case ESRCH: /* Not really there anymore. Possible? */ diff --git a/win32_threads.c b/win32_threads.c index df11a5e7..19da9cea 100644 --- a/win32_threads.c +++ b/win32_threads.c @@ -1182,6 +1182,8 @@ STATIC void GC_suspend(GC_thread t) /* TRUE only if GC_stop_world() acquired GC_write_cs. */ #endif +extern GC_on_collection_event_proc GC_on_collection_event; + GC_INNER void GC_stop_world(void) { DWORD thread_id = GetCurrentThreadId(); @@ -1227,6 +1229,8 @@ GC_INNER void GC_stop_world(void) if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL && t -> id != thread_id) { GC_suspend((GC_thread)t); + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_THREAD_SUSPENDED, (void *)THREAD_HANDLE(t)); } } } else @@ -1240,6 +1244,8 @@ GC_INNER void GC_stop_world(void) if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL && !KNOWN_FINISHED(t) && t -> id != thread_id) { GC_suspend(t); + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_THREAD_SUSPENDED, (void *)THREAD_HANDLE(t)); } } } @@ -1273,6 +1279,8 @@ GC_INNER void GC_start_world(void) if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1) ABORT("ResumeThread failed"); t -> suspended = FALSE; + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)THREAD_HANDLE(t)); } } } else { @@ -1287,6 +1295,8 @@ GC_INNER void GC_start_world(void) ABORT("ResumeThread failed"); UNPROTECT_THREAD(t); t -> suspended = FALSE; + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)THREAD_HANDLE(t)); } } } |