diff --git a/src/Makefile b/src/Makefile index d8f185257dcc1..87bb0c54cb688 100644 --- a/src/Makefile +++ b/src/Makefile @@ -45,7 +45,7 @@ RUNTIME_C_SRCS := \ simplevector runtime_intrinsics precompile \ threading partr stackwalk gc gc-debug gc-pages gc-stacks method \ jlapi signal-handling safepoint jloptions timing subtype \ - crc32c + crc32c profile RUNTIME_SRCS := APInt-C runtime_ccall processor rtutils $(RUNTIME_C_SRCS) SRCS := $(RUNTIME_SRCS) diff --git a/src/profile.c b/src/profile.c new file mode 100644 index 0000000000000..4bce8c619f4e7 --- /dev/null +++ b/src/profile.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include "julia.h" +#include "julia_internal.h" +#include "threading.h" +#include "gc.h" + + +// +// Shared infrastructure +// + +// data structures +volatile jl_bt_element_t *bt_data_prof = NULL; +volatile size_t bt_size_max = 0; +volatile size_t bt_size_cur = 0; +volatile uint8_t bt_overflow = 0; +/// only for sampling profiler +static volatile uint64_t profile_delay_nsec = 0; + +volatile int profile_running = 0; + +JL_DLLEXPORT void jl_profile_clear_data(void) +{ + bt_size_cur = 0; + bt_overflow = 0; +} + +JL_DLLEXPORT int jl_profile_init(size_t maxsize, uint64_t delay_nsec) +{ + bt_size_max = maxsize; + profile_delay_nsec = delay_nsec; + + // Free previous profile buffers, if we have any + if (bt_data_prof != NULL) + free((void*)bt_data_prof); + + // Initialize new profile buffers. We assume at least 10x + bt_data_prof = (jl_bt_element_t*) calloc(bt_size_max, sizeof(jl_bt_element_t)); + if (bt_data_prof == NULL && bt_size_max > 0) + return -1; + + jl_profile_clear_data(); + return 0; +} + +JL_DLLEXPORT uint8_t *jl_profile_get_data(void) +{ + return (uint8_t*) bt_data_prof; +} + +JL_DLLEXPORT size_t jl_profile_len_data(void) +{ + return bt_size_cur; +} + +JL_DLLEXPORT size_t jl_profile_maxlen_data(void) +{ + return bt_size_max; +} + +JL_DLLEXPORT int jl_profile_did_overflow(void) +{ + return bt_overflow; +} + + +// +// Sampling profiler +// + +JL_DLLEXPORT uint64_t jl_profile_delay_nsec(void) +{ + return profile_delay_nsec; +} + +JL_DLLEXPORT int jl_profile_is_running(void) +{ + return profile_running; +} + +// jl_profile_start_timer and jl_profile_stop_timer defined in signal-handling.c diff --git a/src/signal-handling.c b/src/signal-handling.c index 0001a309b7b85..105cafe1d0239 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -17,17 +17,19 @@ extern "C" { #include -// Profiler control variables // -static volatile jl_bt_element_t *bt_data_prof = NULL; -static volatile size_t bt_size_max = 0; -static volatile size_t bt_size_cur = 0; -static volatile uint8_t bt_overflow = 0; -static volatile uint64_t nsecprof = 0; -static volatile int running = 0; -static const uint64_t GIGA = 1000000000ULL; +extern volatile jl_bt_element_t *bt_data_prof; +extern volatile size_t bt_size_max; +extern volatile size_t bt_size_cur; +extern volatile uint8_t bt_overflow; + +extern volatile int profile_running; + +extern uint64_t jl_profile_delay_nsec(void); +static const uint64_t GIGA = 1000000000ULL; + // Timers to take samples at intervals -JL_DLLEXPORT void jl_profile_stop_timer(void); -JL_DLLEXPORT int jl_profile_start_timer(void); +void _jl_profile_stop_timer(void); +int _jl_profile_start_timer(void); static uint64_t jl_last_sigint_trigger = 0; static uint64_t jl_disable_sigint_time = 0; @@ -244,60 +246,6 @@ void jl_critical_error(int sig, bt_context_t *context, jl_bt_element_t *bt_data, gc_debug_critical_error(); } -/////////////////////// -// Utility functions // -/////////////////////// - -JL_DLLEXPORT void jl_profile_clear_data(void) -{ - bt_size_cur = 0; - bt_overflow = 0; -} - -JL_DLLEXPORT int jl_profile_init(size_t maxsize, uint64_t delay_nsec) -{ - bt_size_max = maxsize; - nsecprof = delay_nsec; - if (bt_data_prof != NULL) - free((void*)bt_data_prof); - bt_data_prof = (jl_bt_element_t*) calloc(maxsize, sizeof(jl_bt_element_t)); - if (bt_data_prof == NULL && maxsize > 0) - return -1; - - jl_profile_clear_data(); - return 0; -} - -JL_DLLEXPORT uint8_t *jl_profile_get_data(void) -{ - return (uint8_t*) bt_data_prof; -} - -JL_DLLEXPORT size_t jl_profile_len_data(void) -{ - return bt_size_cur; -} - -JL_DLLEXPORT size_t jl_profile_maxlen_data(void) -{ - return bt_size_max; -} - -JL_DLLEXPORT uint64_t jl_profile_delay_nsec(void) -{ - return nsecprof; -} - -JL_DLLEXPORT int jl_profile_is_running(void) -{ - return running; -} - -JL_DLLEXPORT int jl_profile_did_overflow(void) -{ - return bt_overflow; -} - #ifdef __cplusplus } #endif diff --git a/src/signals-mach.c b/src/signals-mach.c index 3a3aff3616c80..2a1d2aca3ad41 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -425,7 +425,7 @@ void *mach_profile_listener(void *arg) unw_context_t *uc; jl_thread_suspend_and_get_state(i, &uc); - if (running) { + if (profile_running) { // Get the backtrace size_t bt_size_step = 0; int incomplete = 0; @@ -512,10 +512,11 @@ JL_DLLEXPORT int jl_profile_start_timer(void) profile_started = 1; } + uint64_t nsecprof = jl_profile_delay_nsec(); timerprof.tv_sec = nsecprof/GIGA; timerprof.tv_nsec = nsecprof%GIGA; - running = 1; + profile_running = 1; ret = clock_alarm(clk, TIME_RELATIVE, timerprof, profile_port); HANDLE_MACH_ERROR("clock_alarm", ret); @@ -524,5 +525,5 @@ JL_DLLEXPORT int jl_profile_start_timer(void) JL_DLLEXPORT void jl_profile_stop_timer(void) { - running = 0; + profile_running = 0; } diff --git a/src/signals-unix.c b/src/signals-unix.c index a4a6a9fe0577d..be1f9abb3365e 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -422,6 +422,7 @@ JL_DLLEXPORT int jl_profile_start_timer(void) return -2; // Start the timer + uint64_t nsecprof = jl_profile_delay_nsec(); itsprof.it_interval.tv_sec = nsecprof/GIGA; itsprof.it_interval.tv_nsec = nsecprof%GIGA; itsprof.it_value.tv_sec = nsecprof/GIGA; @@ -429,15 +430,15 @@ JL_DLLEXPORT int jl_profile_start_timer(void) if (timer_settime(timerprof, 0, &itsprof, NULL) == -1) return -3; - running = 1; + profile_running = 1; return 0; } JL_DLLEXPORT void jl_profile_stop_timer(void) { - if (running) + if (profile_running) timer_delete(timerprof); - running = 0; + profile_running = 0; } #elif defined(HAVE_ITIMER) @@ -448,6 +449,7 @@ struct itimerval timerprof; JL_DLLEXPORT int jl_profile_start_timer(void) { + uint64_t nsecprof = jl_profile_delay_nsec(); timerprof.it_interval.tv_sec = nsecprof/GIGA; timerprof.it_interval.tv_usec = (nsecprof%GIGA)/1000; timerprof.it_value.tv_sec = nsecprof/GIGA; @@ -455,18 +457,18 @@ JL_DLLEXPORT int jl_profile_start_timer(void) if (setitimer(ITIMER_PROF, &timerprof, 0) == -1) return -3; - running = 1; + profile_running = 1; return 0; } JL_DLLEXPORT void jl_profile_stop_timer(void) { - if (running) { + if (profile_running) { memset(&timerprof, 0, sizeof(timerprof)); setitimer(ITIMER_PROF, &timerprof, 0); } - running = 0; + profile_running = 0; } #else @@ -675,7 +677,7 @@ static void *signal_listener(void *arg) } // do backtrace for profiler - if (profile && running) { + if (profile && profile_running) { if (bt_size_cur < bt_size_max - 1) { size_t bt_size_step = 0; int incomplete = 0; diff --git a/src/signals-win.c b/src/signals-win.c index 3382d1550b8aa..ef5982e5e4be5 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -329,6 +329,7 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) while (1) { assert(bt_size_cur < bt_size_max - 1); + uint64_t nsecprof = jl_profile_delay_nsec(); DWORD timeout = nsecprof/GIGA; timeout = min(max(timeout, tc.wPeriodMin*2), tc.wPeriodMax/2); Sleep(timeout); @@ -340,7 +341,7 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) // Get the backtrace data size_t bt_size_step; int incomplete; - if (running) { + if (profile_running) { CONTEXT ctxThread; memset(&ctxThread, 0, sizeof(CONTEXT)); ctxThread.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; @@ -361,7 +362,7 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) } // Save the backtrace data - if (running) { + if (profile_running) { if (incomplete) { bt_overflow = 1; jl_profile_stop_timer(); @@ -379,7 +380,7 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) JL_DLLEXPORT int jl_profile_start_timer(void) { - running = 1; + profile_running = 1; if (hBtThread == 0) { hBtThread = CreateThread( NULL, // default security attributes @@ -401,7 +402,7 @@ JL_DLLEXPORT int jl_profile_start_timer(void) JL_DLLEXPORT void jl_profile_stop_timer(void) { - running = 0; + profile_running = 0; } void jl_install_default_signal_handlers(void)