Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 46 additions & 46 deletions src/signal-handling.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,52 @@ static const uint64_t GIGA = 1000000000ULL;
JL_DLLEXPORT void jl_profile_stop_timer(void);
JL_DLLEXPORT int jl_profile_start_timer(void);

///////////////////////
// Utility functions //
///////////////////////
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;
bt_size_cur = 0;
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 void jl_profile_clear_data(void)
{
bt_size_cur = 0;
}

JL_DLLEXPORT int jl_profile_is_running(void)
{
return running;
}

// Any function that acquires this lock must be either a unmanaged thread
// or in the GC safe region and must NOT allocate anything through the GC
// while holding this lock.
Expand Down Expand Up @@ -426,52 +472,6 @@ void jl_critical_error(int sig, bt_context_t *context, jl_task_t *ct)
jl_gc_debug_critical_error();
}

///////////////////////
// Utility functions //
///////////////////////
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;
bt_size_cur = 0;
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 void jl_profile_clear_data(void)
{
bt_size_cur = 0;
}

JL_DLLEXPORT int jl_profile_is_running(void)
{
return running;
}

#ifdef __cplusplus
}
#endif
8 changes: 8 additions & 0 deletions src/signals-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,14 @@ void trigger_profile_peek(void)
jl_safe_printf("\n======================================================================================\n");
jl_safe_printf("Information request received. A stacktrace will print followed by a %.1f second profile\n", profile_peek_duration);
jl_safe_printf("======================================================================================\n");
if (bt_size_max == 0){
// If the buffer hasn't been initialized, initialize with default size
// Keep these values synchronized with Profile.default_init()
if (jl_profile_init(10000000 * jl_n_threads, 1000000) == -1){
jl_safe_printf("ERROR: could not initialize the profile buffer");
return;
}
}
bt_size_cur = 0; // clear profile buffer
if (jl_profile_start_timer() < 0)
jl_safe_printf("ERROR: Could not start profile timer\n");
Expand Down
39 changes: 33 additions & 6 deletions stdlib/Profile/src/Profile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ appended to an internal buffer of backtraces.
macro profile(ex)
return quote
try
status = start_timer()
if status < 0
error(error_codes[status])
end
start_timer()
$(esc(ex))
finally
stop_timer()
Expand Down Expand Up @@ -98,6 +95,11 @@ using keywords or in the order `(n, delay)`.
"""
function init(; n::Union{Nothing,Integer} = nothing, delay::Union{Nothing,Real} = nothing, limitwarn::Bool = true)
n_cur = ccall(:jl_profile_maxlen_data, Csize_t, ())
if n_cur == 0 && isnothing(n) && isnothing(delay)
# indicates that the buffer hasn't been initialized at all, so set the default
default_init()
n_cur = ccall(:jl_profile_maxlen_data, Csize_t, ())
end
delay_cur = ccall(:jl_profile_delay_nsec, UInt64, ())/10^9
if n === nothing && delay === nothing
nthreads = Sys.iswindows() ? 1 : Threads.nthreads() # windows only profiles the main thread
Expand Down Expand Up @@ -126,7 +128,7 @@ function init(n::Integer, delay::Real; limitwarn::Bool = true)
end
end

function __init__()
function default_init()
# init with default values
# Use a max size of 10M profile samples, and fire timer every 1ms
# (that should typically give around 100 seconds of record)
Expand All @@ -136,10 +138,25 @@ function __init__()
n = 1_000_000
delay = 0.01
else
# Keep these values synchronized with trigger_profile_peek
n = 10_000_000
delay = 0.001
end
init(n, delay, limitwarn = false)
end

# Checks whether the profile buffer has been initialized. If not, initializes it with the default size.
function check_init()
buffer_size = @ccall jl_profile_maxlen_data()::Int
if buffer_size == 0
default_init()
end
end

function __init__()
# Note: The profile buffer is no longer initialized during __init__ because Profile is in the sysimage,
# thus __init__ is called every startup. The buffer is lazily initialized the first time `@profile` is
# used, if not manually initialized before that.
@static if !Sys.iswindows()
# triggering a profile via signals is not implemented on windows
PROFILE_PRINT_COND[] = Base.AsyncCondition()
Expand Down Expand Up @@ -567,7 +584,14 @@ Julia, and examine the resulting `*.mem` files.
clear_malloc_data() = ccall(:jl_clear_malloc_data, Cvoid, ())

# C wrappers
start_timer() = ccall(:jl_profile_start_timer, Cint, ())
function start_timer()
check_init() # if the profile buffer hasn't been initialized, initialize with default size
status = ccall(:jl_profile_start_timer, Cint, ())
if status < 0
error(error_codes[status])
end
end


stop_timer() = ccall(:jl_profile_stop_timer, Cvoid, ())

Expand Down Expand Up @@ -599,6 +623,9 @@ By default metadata such as threadid and taskid is included. Set `include_meta`
"""
function fetch(;include_meta = true, limitwarn = true)
maxlen = maxlen_data()
if maxlen == 0
error("The profiling data buffer is not initialized. A profile has not been requested this session.")
end
len = len_data()
if limitwarn && is_buffer_full()
@warn """The profile data buffer is full; profiling probably terminated
Expand Down
2 changes: 2 additions & 0 deletions stdlib/Profile/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using Test, Profile, Serialization, Logging
using Base.StackTraces: StackFrame

@test_throws "The profiling data buffer is not initialized. A profile has not been requested this session." Profile.print()

Profile.clear()
Profile.init()

Expand Down