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
10 changes: 6 additions & 4 deletions doc/src/manual/profile.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,12 @@ Passing `sample_rate=1.0` will make it record everything (which is slow);
!!! note

The current implementation of the Allocations Profiler _does not
capture all allocations._ You can read more about the missing allocations
and the plan to improve this, here: https://github.com/JuliaLang/julia/issues/43688.
Calling `Profile.Allocs.fetch()` will print a log line reporting the percentage
of missed allocations, so you can understand the accuracy of your profile.
capture types for all allocations._ Allocations for which the profiler
could not capture the type are represented as having type
`Profile.Allocs.UnknownType`.

You can read more about the missing types and the plan to improve this, here:
https://github.com/JuliaLang/julia/issues/43688.

## External Profiling

Expand Down
48 changes: 9 additions & 39 deletions stdlib/Profile/src/Allocs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ julia> results = Profile.Allocs.fetch()
julia> last(sort(results.allocs, by=x->x.size))
Profile.Allocs.Alloc(Vector{Any}, Base.StackTraces.StackFrame[_new_array_ at array.c:127, ...], 5576)
```

Note: The current implementation of the Allocations Profiler _does not
capture types for all allocations._ Allocations for which the profiler
could not capture the type are represented as having type
`Profile.Allocs.UnknownType`.

You can read more about the missing types and the plan to improve this, here:
https://github.com/JuliaLang/julia/issues/43688.
"""
macro profile(opts, ex)
_prof_expr(ex, opts)
Expand All @@ -52,12 +60,6 @@ macro profile(ex)
_prof_expr(ex, :(sample_rate=0.0001))
end

# globals used for tracking how many allocs we're missing
# vs the alloc counters used by @time
const _g_gc_num_before = Ref{Base.GC_Num}()
const _g_sample_rate = Ref{Real}()
const _g_expected_sampled_allocs = Ref{Float64}(0)

function _prof_expr(expr, opts)
quote
$start(; $(esc(opts)))
Expand All @@ -77,9 +79,6 @@ A sample rate of 1.0 will record everything; 0.0 will record nothing.
"""
function start(; sample_rate::Real)
ccall(:jl_start_alloc_profile, Cvoid, (Cdouble,), Float64(sample_rate))

_g_sample_rate[] = sample_rate
_g_gc_num_before[] = Base.gc_num()
end

"""
Expand All @@ -89,15 +88,6 @@ Stop recording allocations.
"""
function stop()
ccall(:jl_stop_alloc_profile, Cvoid, ())

# increment a counter of how many allocs we would expect
# the memory profiler to see, based on how many allocs
# actually happened.
gc_num_after = Base.gc_num()
gc_diff = Base.GC_Diff(gc_num_after, _g_gc_num_before[])
alloc_count = Base.gc_alloc_count(gc_diff)
expected_samples = alloc_count * _g_sample_rate[]
_g_expected_sampled_allocs[] += expected_samples
end

"""
Expand All @@ -107,8 +97,6 @@ Clear all previously profiled allocation information from memory.
"""
function clear()
ccall(:jl_free_alloc_profile, Cvoid, ())

_g_expected_sampled_allocs[] = 0
return nothing
end

Expand All @@ -120,25 +108,7 @@ objects which can be analyzed.
"""
function fetch()
raw_results = ccall(:jl_fetch_alloc_profile, RawResults, ())
decoded_results = decode(raw_results)

# avoid divide-by-0 errors
if _g_expected_sampled_allocs[] > 0
missed_allocs = max(0, _g_expected_sampled_allocs[] - length(decoded_results.allocs))
missed_percentage = max(0, round(Int, missed_allocs / _g_expected_sampled_allocs[] * 100))
if missed_percentage > 0
@warn("The allocation profiler is not fully implemented, and missed approximately" *
" $(missed_percentage)% (estimated $(round(Int, missed_allocs)) / $(round(Int,
_g_expected_sampled_allocs[]))) " *
"of sampled allocs in the last run. " *
"For more info see https://github.com/JuliaLang/julia/issues/43688")
else
@warn("The allocation profiler is not fully implemented, and may have missed" *
" some of the allocs. " *
"For more info see https://github.com/JuliaLang/julia/issues/43688")
end
end
return decoded_results
return decode(raw_results)
end

# decoded results
Expand Down
25 changes: 0 additions & 25 deletions stdlib/Profile/test/allocs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,31 +111,6 @@ end
Allocs.clear()
end

@testset "alloc profiler warning message" begin
@testset "no allocs" begin
Profile.Allocs.clear()
Profile.Allocs.fetch()
end
@testset "catches all allocations" begin
foo() = []
precompile(foo, ())
Profile.Allocs.clear()
Profile.Allocs.@profile sample_rate=1 foo()
# Fake that we expected exactly 1 alloc, since we should have recorded >= 1
Profile.Allocs._g_expected_sampled_allocs[] = 1
@assert length(Profile.Allocs.fetch().allocs) >= 1
end
@testset "misses some allocations" begin
foo() = []
precompile(foo, ())
Profile.Allocs.clear()
Profile.Allocs.@profile sample_rate=1 foo()
# Fake some allocs that we missed, to force the print statement
Profile.Allocs._g_expected_sampled_allocs[] += 10
@assert 1 <= length(Profile.Allocs.fetch().allocs) < 10
end
end

@testset "alloc profiler catches strings" begin
Allocs.@profile sample_rate=1 "$(rand())"

Expand Down