Skip to content

Add heap snapshot endpoint #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 8, 2022
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
5 changes: 3 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ jobs:
fail-fast: false
matrix:
version:
- "1.6"
- "1"
- "1.6" # LTS
- "1" # Latest
- "~1.9.0-0" # To test heap snapshot; remove when v1.9 is latest Julia release.
- "nightly"
os:
- ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Currently provides:
- `/profile?n=1e8&delay=0.01&duration=10&pprof=true`
- `/allocs_profile` endpoint, with default query params:
- `/allocs_profile?sample_rate=0.0001&duration=10`
- `/heap_snapshot` endpoint, with default query params:
- `/heap_snapshot?all_one=false`


## Example
Expand Down
24 changes: 23 additions & 1 deletion src/PerformanceProfilingHttpEndpoints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,29 @@ end
### Allocs
###

# If `all_one=true`, then every object is given size 1 so they can be easily counted.
# Otherwise, if `false`, every object reports its actual size on the heap.
default_heap_all_one() = "false"

@static if !isdefined(Profile, :take_heap_snapshot)

function heap_snapshot_endpoint(::HTTP.Request)
return HTTP.Response(501, "You must use a build of Julia (1.9+) that supports heap snapshots.")
end

else

function heap_snapshot_endpoint(req::HTTP.Request)
# TODO: implement this once https://github.com/JuliaLang/julia/pull/42286 is merged
uri = HTTP.URI(req.target)
qp = HTTP.queryparams(uri)
all_one = parse(Bool, get(qp, "all_one", default_heap_all_one()))
filename = Profile.take_heap_snapshot(all_one)
@info "Taking heap snapshot from PerformanceProfilingHttpEndpoints" all_one filename
return _http_response(read(filename), filename)
end

end # if isdefined

default_alloc_sample_rate() = "0.0001"

allocs_profile_error_message() = """Need to provide query params:
Expand Down Expand Up @@ -233,6 +252,7 @@ function serve_profiling_server(;addr="127.0.0.1", port=16825, verbose=false, kw
HTTP.register!(router, "/profile", cpu_profile_endpoint)
HTTP.register!(router, "/profile_start", cpu_profile_start_endpoint)
HTTP.register!(router, "/profile_stop", cpu_profile_stop_endpoint)
HTTP.register!(router, "/heap_snapshot", heap_snapshot_endpoint)
HTTP.register!(router, "/allocs_profile", allocations_profile_endpoint)
HTTP.register!(router, "/allocs_profile_start", allocations_start_endpoint)
HTTP.register!(router, "/allocs_profile_stop", allocations_stop_endpoint)
Expand All @@ -251,6 +271,8 @@ function __init__()
precompile(_do_cpu_profile, (Int,Float64,Float64,Bool)) || error("precompilation of package functions is not supposed to fail")
precompile(_start_cpu_profile, (Int,Float64,)) || error("precompilation of package functions is not supposed to fail")

precompile(heap_snapshot_endpoint, (HTTP.Request,)) || error("precompilation of package functions is not supposed to fail")

precompile(allocations_profile_endpoint, (HTTP.Request,)) || error("precompilation of package functions is not supposed to fail")
precompile(allocations_start_endpoint, (HTTP.Request,)) || error("precompilation of package functions is not supposed to fail")
precompile(allocations_stop_endpoint, (HTTP.Request,)) || error("precompilation of package functions is not supposed to fail")
Expand Down
16 changes: 16 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,22 @@ const url = "http://127.0.0.1:$port"
end
end

@testset "Heap snapshot $query" for query in ("", "?all_one=true")
req = HTTP.get("$url/heap_snapshot$query", retry=false, status_exception=false)
if !isdefined(Profile, :take_heap_snapshot)
# Assert the version is before https://github.com/JuliaLang/julia/pull/46862
# Although we actually also need https://github.com/JuliaLang/julia/pull/47300
@assert VERSION < v"1.9.0-DEV.1643"
@test req.status == 501 # not implemented
else
@test req.status == 200
data = read(IOBuffer(req.body), String)
# Test that there's something here
# TODO: actually parse the profile
@test length(data) > 100
end
end

@testset "Allocation profiling" begin
done = Threads.Atomic{Bool}(false)
# Schedule some work that's known to be expensive, to profile it
Expand Down