@@ -34,15 +34,17 @@ function _http_create_response_with_profile_as_file(filename)
3434end
3535
3636# ##
37- # ## CPU
37+ # ## Task Profiles: CPU profiles + Wall profiles
3838# ##
3939
40+ @enum TaskProfileType CPU_PROFILE WALL_PROFILE
41+
4042default_n () = " 1e8"
4143default_delay () = " 0.01"
4244default_duration () = " 10.0"
4345default_pprof () = " true"
4446
45- cpu_profile_error_message () = """ Need to provide query params:
47+ profile_error_message () = """ Need to provide query params:
4648 - duration=$(default_duration ())
4749 - delay=$(default_delay ())
4850 - n=$(default_n ())
@@ -67,80 +69,116 @@ The default `n` is 1e8, which should be big enough for most profiles.
6769"""
6870
6971function cpu_profile_endpoint (req:: HTTP.Request )
72+ profile_endpoint (CPU_PROFILE, req)
73+ end
74+
75+ function cpu_profile_start_endpoint (req:: HTTP.Request )
76+ profile_start_endpoint (CPU_PROFILE, req)
77+ end
78+
79+ function cpu_profile_stop_endpoint (req:: HTTP.Request )
80+ profile_stop_endpoint (CPU_PROFILE, req)
81+ end
82+
83+ function wall_profile_endpoint (req:: HTTP.Request )
84+ profile_endpoint (WALL_PROFILE, req)
85+ end
86+
87+ function wall_profile_start_endpoint (req:: HTTP.Request )
88+ profile_start_endpoint (WALL_PROFILE, req)
89+ end
90+
91+ function wall_profile_stop_endpoint (req:: HTTP.Request )
92+ profile_stop_endpoint (WALL_PROFILE, req)
93+ end
94+
95+ function profile_endpoint (type:: TaskProfileType , req:: HTTP.Request )
7096 uri = HTTP. URI (req. target)
7197 qp = HTTP. queryparams (uri)
7298 if isempty (qp)
7399 @info " TODO: interactive HTML input page"
74- return HTTP. Response (400 , cpu_profile_error_message ())
100+ return HTTP. Response (400 , profile_error_message ())
75101 end
76102 n = convert (Int, parse (Float64, get (qp, " n" , default_n ())))
77103 delay = parse (Float64, get (qp, " delay" , default_delay ()))
78104 duration = parse (Float64, get (qp, " duration" , default_duration ()))
79105 with_pprof = parse (Bool, get (qp, " pprof" , default_pprof ()))
80- return handle_cpu_profile ( n, delay, duration, with_pprof)
106+ return handle_profile (type, n, delay, duration, with_pprof)
81107end
82108
83- function cpu_profile_start_endpoint ( req:: HTTP.Request )
109+ function profile_start_endpoint (type, req:: HTTP.Request )
84110 uri = HTTP. URI (req. target)
85111 qp = HTTP. queryparams (uri)
86112 n = convert (Int, parse (Float64, get (qp, " n" , default_n ())))
87113 delay = parse (Float64, get (qp, " delay" , default_delay ()))
88- return handle_cpu_profile_start ( n, delay)
114+ return handle_profile_start (type, n, delay)
89115end
90116
91- function cpu_profile_stop_endpoint (req:: HTTP.Request )
92- Profile. stop_timer ()
93- @info " Stopping CPU Profiling from ProfileEndpoints"
117+ function profile_stop_endpoint (type, req:: HTTP.Request )
94118 uri = HTTP. URI (req. target)
95119 qp = HTTP. queryparams (uri)
96120 with_pprof = parse (Bool, get (qp, " pprof" , default_pprof ()))
97- return handle_cpu_profile_stop (with_pprof)
121+ return handle_profile_stop (with_pprof)
98122end
99123
100- function handle_cpu_profile ( n, delay, duration, with_pprof, stage_path = nothing )
124+ function handle_profile (type, n, delay, duration, with_pprof, stage_path = nothing )
101125 # Run the profile
102- return _do_cpu_profile ( n, delay, duration, with_pprof, stage_path)
126+ return _do_profile (type, n, delay, duration, with_pprof, stage_path)
103127end
104128
105- function _do_cpu_profile ( n, delay, duration, with_pprof, stage_path = nothing )
106- @info " Starting CPU Profiling from ProfileEndpoints with configuration:" n delay duration
129+ function _do_profile (type :: TaskProfileType , n, delay, duration, with_pprof, stage_path = nothing )
130+ @info " Starting $type Profiling from ProfileEndpoints with configuration:" n delay duration
107131 Profile. clear ()
108132 Profile. init (n, delay)
109- Profile. @profile sleep (duration)
133+ if type == CPU_PROFILE
134+ Profile. @profile sleep (duration)
135+ elseif type == WALL_PROFILE
136+ @static if isdefined (Profile, Symbol (" @profile_walltime" ))
137+ Profile. @profile_walltime sleep (duration)
138+ else
139+ return HTTP. Response (501 , " You must use a build of Julia (1.12+) that supports walltime profiles." )
140+ end
141+ end
110142 if stage_path === nothing
111143 # Defer the potentially expensive profile symbolication to a non-interactive thread
112- return fetch (Threads. @spawn _cpu_profile_get_response (with_pprof= $ with_pprof))
144+ return fetch (Threads. @spawn _profile_get_response (with_pprof= $ with_pprof))
113145 end
114146 path = tempname (stage_path; cleanup= false )
115147 # Defer the potentially expensive profile symbolication to a non-interactive thread
116- return fetch (Threads. @spawn _cpu_profile_get_response_and_write_to_file ($ path; with_pprof= $ with_pprof))
148+ return fetch (Threads. @spawn _profile_get_response_and_write_to_file ($ path; with_pprof= $ with_pprof))
117149end
118150
119- function handle_cpu_profile_start ( n, delay)
151+ function handle_profile_start (type, n, delay)
120152 # Run the profile
121- return _start_cpu_profile (n, delay)
122- end
123-
124- function _start_cpu_profile (n, delay)
125- @info " Starting CPU Profiling from ProfileEndpoints with configuration:" n delay
126- resp = HTTP. Response (200 , " CPU profiling started." )
153+ @info " Starting $type Profiling from ProfileEndpoints with configuration:" n delay
154+ resp = HTTP. Response (200 , " $type profiling started." )
127155 Profile. clear ()
128156 Profile. init (n, delay)
129- Profile. start_timer ()
157+ if type == CPU_PROFILE
158+ Profile. start_timer ()
159+ elseif type == WALL_PROFILE
160+ @static if isdefined (Profile, Symbol (" @profile_walltime" ))
161+ Profile. start_timer (true )
162+ else
163+ return HTTP. Response (501 , " You must use a build of Julia (1.12+) that supports walltime profiles." )
164+ end
165+ end
130166 return resp
131167end
132168
133- function handle_cpu_profile_stop (with_pprof, stage_path = nothing )
169+ function handle_profile_stop (with_pprof, stage_path = nothing )
170+ @info " Stopping Profiling from ProfileEndpoints"
171+ Profile. stop_timer ()
134172 if stage_path === nothing
135173 # Defer the potentially expensive profile symbolication to a non-interactive thread
136- return fetch (Threads. @spawn _cpu_profile_get_response (with_pprof= $ with_pprof))
174+ return fetch (Threads. @spawn _profile_get_response (with_pprof= $ with_pprof))
137175 end
138176 path = tempname (stage_path; cleanup= false )
139177 # Defer the potentially expensive profile symbolication to a non-interactive thread
140- return fetch (Threads. @spawn _cpu_profile_get_response_and_write_to_file ($ path; with_pprof= $ with_pprof))
178+ return fetch (Threads. @spawn _profile_get_response_and_write_to_file ($ path; with_pprof= $ with_pprof))
141179end
142180
143- function _cpu_profile_get_response_and_write_to_file (filename; with_pprof:: Bool )
181+ function _profile_get_response_and_write_to_file (filename; with_pprof:: Bool )
144182 if with_pprof
145183 PProf. pprof (out= filename, web= false )
146184 filename = " $filename .pb.gz"
@@ -157,7 +195,7 @@ function _cpu_profile_get_response_and_write_to_file(filename; with_pprof::Bool)
157195 end
158196end
159197
160- function _cpu_profile_get_response (;with_pprof:: Bool )
198+ function _profile_get_response (;with_pprof:: Bool )
161199 if with_pprof
162200 prof_name = tempname (;cleanup= false )
163201 PProf. pprof (out= prof_name, web= false )
@@ -189,7 +227,7 @@ function handle_heap_snapshot(all_one, stage_path = nothing)
189227 return HTTP. Response (501 , " You must use a build of Julia (1.9+) that supports heap snapshots." )
190228end
191229
192- else
230+ else # isdefined
193231
194232function heap_snapshot_endpoint (req:: HTTP.Request )
195233 uri = HTTP. URI (req. target)
@@ -402,21 +440,25 @@ function debug_profile_endpoint_with_stage_path(stage_path = nothing)
402440 profile_dir = subdir
403441 end
404442 profile_type = body[" profile_type" ]
405- if profile_type == " cpu_profile"
406- return handle_cpu_profile (
443+ if profile_type == " cpu_profile" || profile_type == " wall_profile"
444+ type = profile_type == " cpu_profile" ? CPU_PROFILE : WALL_PROFILE
445+ return handle_profile (
446+ type,
407447 convert (Int, parse (Float64, get (body, " n" , default_n ()))),
408448 parse (Float64, get (body, " delay" , default_delay ())),
409449 parse (Float64, get (body, " duration" , default_duration ())),
410450 parse (Bool, get (body, " pprof" , default_pprof ())),
411451 profile_dir
412452 )
413- elseif profile_type == " cpu_profile_start"
414- return handle_cpu_profile_start (
453+ elseif profile_type == " cpu_profile_start" || profile_type == " wall_profile_start"
454+ type = profile_type == " cpu_profile_start" ? CPU_PROFILE : WALL_PROFILE
455+ return handle_profile_start (
456+ type,
415457 convert (Int, parse (Float64, get (body, " n" , default_n ()))),
416458 parse (Float64, get (body, " delay" , default_delay ()))
417459 )
418- elseif profile_type == " cpu_profile_stop"
419- return handle_cpu_profile_stop (
460+ elseif profile_type == " cpu_profile_stop" || profile_type == " wall_profile_stop "
461+ return handle_profile_stop (
420462 parse (Bool, get (body, " pprof" , default_pprof ())),
421463 profile_dir
422464 )
@@ -455,6 +497,9 @@ function register_endpoints(router; stage_path = nothing)
455497 HTTP. register! (router, " /profile" , cpu_profile_endpoint)
456498 HTTP. register! (router, " /profile_start" , cpu_profile_start_endpoint)
457499 HTTP. register! (router, " /profile_stop" , cpu_profile_stop_endpoint)
500+ HTTP. register! (router, " /profile_wall" , wall_profile_endpoint)
501+ HTTP. register! (router, " /profile_wall_start" , wall_profile_start_endpoint)
502+ HTTP. register! (router, " /profile_wall_stop" , wall_profile_stop_endpoint)
458503 HTTP. register! (router, " /heap_snapshot" , heap_snapshot_endpoint)
459504 HTTP. register! (router, " /allocs_profile" , allocations_profile_endpoint)
460505 HTTP. register! (router, " /allocs_profile_start" , allocations_start_endpoint)
0 commit comments