Skip to content

Commit

Permalink
[Profile] allocate exactly the space requested
Browse files Browse the repository at this point in the history
With dynamic thread counts, we cannot ensure this count is constant
after initialization, and we might like to even profile adding and
removing threads.
  • Loading branch information
vtjnash authored and JeffBezanson committed Oct 5, 2022
1 parent 956e0a3 commit 1755994
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 28 deletions.
12 changes: 4 additions & 8 deletions src/signal-handling.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,10 @@ static int *profile_get_randperm(int size)

JL_DLLEXPORT int jl_profile_is_buffer_full(void)
{
// declare buffer full if there isn't enough room to take samples across all threads
#if defined(_OS_WINDOWS_)
uint64_t nthreads = 1; // windows only profiles the main thread
#else
uint64_t nthreads = jl_n_threads;
#endif
// the `+ 6` is for the two block terminators `0` plus 4 metadata entries
return bt_size_cur + (((JL_BT_MAX_ENTRY_SIZE + 1) + 6) * nthreads) > bt_size_max;
// Declare buffer full if there isn't enough room to sample even just the
// thread metadata and one max-sized frame. The `+ 6` is for the two block
// terminator `0`'s plus the 4 metadata entries.
return bt_size_cur + ((JL_BT_MAX_ENTRY_SIZE + 1) + 6) > bt_size_max;
}

static uint64_t jl_last_sigint_trigger = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/signals-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ void trigger_profile_peek(void)
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){
if (jl_profile_init(10000000, 1000000) == -1) {
jl_safe_printf("ERROR: could not initialize the profile buffer");
return;
}
Expand Down
20 changes: 6 additions & 14 deletions stdlib/Profile/src/Profile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,6 @@ stored per thread. Each instruction pointer corresponds to a single line of code
list of instruction pointers. Note that 6 spaces for instruction pointers per backtrace are used to store metadata and two
NULL end markers. Current settings can be obtained by calling this function with no arguments, and each can be set independently
using keywords or in the order `(n, delay)`.
!!! compat "Julia 1.8"
As of Julia 1.8, this function allocates space for `n` instruction pointers per thread being profiled.
Previously this was `n` total.
"""
function init(; n::Union{Nothing,Integer} = nothing, delay::Union{Nothing,Real} = nothing, limitwarn::Bool = true)
n_cur = ccall(:jl_profile_maxlen_data, Csize_t, ())
Expand All @@ -102,29 +98,25 @@ function init(; n::Union{Nothing,Integer} = nothing, delay::Union{Nothing,Real}
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
return round(Int, n_cur / nthreads), delay_cur
return n_cur, delay_cur
end
nnew = (n === nothing) ? n_cur : n
delaynew = (delay === nothing) ? delay_cur : delay
init(nnew, delaynew; limitwarn)
end

function init(n::Integer, delay::Real; limitwarn::Bool = true)
nthreads = Sys.iswindows() ? 1 : Threads.nthreads() # windows only profiles the main thread
sample_size_bytes = sizeof(Ptr) # == Sys.WORD_SIZE / 8
buffer_samples = n * nthreads
buffer_samples = n
buffer_size_bytes = buffer_samples * sample_size_bytes
if buffer_size_bytes > 2^29 && Sys.WORD_SIZE == 32
buffer_size_bytes_per_thread = floor(Int, 2^29 / nthreads)
buffer_samples_per_thread = floor(Int, buffer_size_bytes_per_thread / sample_size_bytes)
buffer_samples = buffer_samples_per_thread * nthreads
buffer_samples = floor(Int, 2^29 / sample_size_bytes)
buffer_size_bytes = buffer_samples * sample_size_bytes
limitwarn && @warn "Requested profile buffer limited to 512MB (n = $buffer_samples_per_thread per thread) given that this system is 32-bit"
limitwarn && @warn "Requested profile buffer limited to 512MB (n = $buffer_samples) given that this system is 32-bit"
end
status = ccall(:jl_profile_init, Cint, (Csize_t, UInt64), buffer_samples, round(UInt64,10^9*delay))
status = ccall(:jl_profile_init, Cint, (Csize_t, UInt64), buffer_samples, round(UInt64, 10^9*delay))
if status == -1
error("could not allocate space for ", n, " instruction pointers per thread being profiled ($nthreads threads, $(Base.format_bytes(buffer_size_bytes)) total)")
error("could not allocate space for ", n, " instruction pointers ($(Base.format_bytes(buffer_size_bytes)))")
end
end

Expand Down
9 changes: 4 additions & 5 deletions stdlib/Profile/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,10 @@ end
@testset "setting sample count and delay in init" begin
n_, delay_ = Profile.init()
n_original = n_
nthreads = Sys.iswindows() ? 1 : Threads.nthreads()
sample_size_bytes = sizeof(Ptr)
def_n = Sys.iswindows() && Sys.WORD_SIZE == 32 ? 1_000_000 : 10_000_000
if Sys.WORD_SIZE == 32 && (def_n * nthreads * sample_size_bytes) > 2^29
@test n_ * nthreads * sample_size_bytes <= 2^29
if Sys.WORD_SIZE == 32 && (def_n * sample_size_bytes) > 2^29
@test n_ * sample_size_bytes <= 2^29
else
@test n_ == def_n
end
Expand All @@ -133,8 +132,8 @@ end
@test delay_ == def_delay
Profile.init(n=1_000_001, delay=0.0005)
n_, delay_ = Profile.init()
if Sys.WORD_SIZE == 32 && (1_000_001 * nthreads * sample_size_bytes) > 2^29
@test n_ * nthreads * sample_size_bytes <= 2^29
if Sys.WORD_SIZE == 32 && (1_000_001 * sample_size_bytes) > 2^29
@test n_ * sample_size_bytes <= 2^29
else
@test n_ == 1_000_001
end
Expand Down

0 comments on commit 1755994

Please sign in to comment.