@@ -34,15 +34,17 @@ function _http_create_response_with_profile_as_file(filename)
34
34
end
35
35
36
36
# ##
37
- # ## CPU
37
+ # ## Task Profiles: CPU profiles + Wall profiles
38
38
# ##
39
39
40
+ @enum TaskProfileType CPU_PROFILE WALL_PROFILE
41
+
40
42
default_n () = " 1e8"
41
43
default_delay () = " 0.01"
42
44
default_duration () = " 10.0"
43
45
default_pprof () = " true"
44
46
45
- cpu_profile_error_message () = """ Need to provide query params:
47
+ profile_error_message () = """ Need to provide query params:
46
48
- duration=$(default_duration ())
47
49
- delay=$(default_delay ())
48
50
- n=$(default_n ())
@@ -67,80 +69,116 @@ The default `n` is 1e8, which should be big enough for most profiles.
67
69
"""
68
70
69
71
function 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 )
70
96
uri = HTTP. URI (req. target)
71
97
qp = HTTP. queryparams (uri)
72
98
if isempty (qp)
73
99
@info " TODO: interactive HTML input page"
74
- return HTTP. Response (400 , cpu_profile_error_message ())
100
+ return HTTP. Response (400 , profile_error_message ())
75
101
end
76
102
n = convert (Int, parse (Float64, get (qp, " n" , default_n ())))
77
103
delay = parse (Float64, get (qp, " delay" , default_delay ()))
78
104
duration = parse (Float64, get (qp, " duration" , default_duration ()))
79
105
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)
81
107
end
82
108
83
- function cpu_profile_start_endpoint ( req:: HTTP.Request )
109
+ function profile_start_endpoint (type, req:: HTTP.Request )
84
110
uri = HTTP. URI (req. target)
85
111
qp = HTTP. queryparams (uri)
86
112
n = convert (Int, parse (Float64, get (qp, " n" , default_n ())))
87
113
delay = parse (Float64, get (qp, " delay" , default_delay ()))
88
- return handle_cpu_profile_start ( n, delay)
114
+ return handle_profile_start (type, n, delay)
89
115
end
90
116
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 )
94
118
uri = HTTP. URI (req. target)
95
119
qp = HTTP. queryparams (uri)
96
120
with_pprof = parse (Bool, get (qp, " pprof" , default_pprof ()))
97
- return handle_cpu_profile_stop (with_pprof)
121
+ return handle_profile_stop (with_pprof)
98
122
end
99
123
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 )
101
125
# 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)
103
127
end
104
128
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
107
131
Profile. clear ()
108
132
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
110
142
if stage_path === nothing
111
143
# 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))
113
145
end
114
146
path = tempname (stage_path; cleanup= false )
115
147
# 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))
117
149
end
118
150
119
- function handle_cpu_profile_start ( n, delay)
151
+ function handle_profile_start (type, n, delay)
120
152
# 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." )
127
155
Profile. clear ()
128
156
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
130
166
return resp
131
167
end
132
168
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 ()
134
172
if stage_path === nothing
135
173
# 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))
137
175
end
138
176
path = tempname (stage_path; cleanup= false )
139
177
# 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))
141
179
end
142
180
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 )
144
182
if with_pprof
145
183
PProf. pprof (out= filename, web= false )
146
184
filename = " $filename .pb.gz"
@@ -157,7 +195,7 @@ function _cpu_profile_get_response_and_write_to_file(filename; with_pprof::Bool)
157
195
end
158
196
end
159
197
160
- function _cpu_profile_get_response (;with_pprof:: Bool )
198
+ function _profile_get_response (;with_pprof:: Bool )
161
199
if with_pprof
162
200
prof_name = tempname (;cleanup= false )
163
201
PProf. pprof (out= prof_name, web= false )
@@ -189,7 +227,7 @@ function handle_heap_snapshot(all_one, stage_path = nothing)
189
227
return HTTP. Response (501 , " You must use a build of Julia (1.9+) that supports heap snapshots." )
190
228
end
191
229
192
- else
230
+ else # isdefined
193
231
194
232
function heap_snapshot_endpoint (req:: HTTP.Request )
195
233
uri = HTTP. URI (req. target)
@@ -402,21 +440,25 @@ function debug_profile_endpoint_with_stage_path(stage_path = nothing)
402
440
profile_dir = subdir
403
441
end
404
442
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,
407
447
convert (Int, parse (Float64, get (body, " n" , default_n ()))),
408
448
parse (Float64, get (body, " delay" , default_delay ())),
409
449
parse (Float64, get (body, " duration" , default_duration ())),
410
450
parse (Bool, get (body, " pprof" , default_pprof ())),
411
451
profile_dir
412
452
)
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,
415
457
convert (Int, parse (Float64, get (body, " n" , default_n ()))),
416
458
parse (Float64, get (body, " delay" , default_delay ()))
417
459
)
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 (
420
462
parse (Bool, get (body, " pprof" , default_pprof ())),
421
463
profile_dir
422
464
)
@@ -455,6 +497,9 @@ function register_endpoints(router; stage_path = nothing)
455
497
HTTP. register! (router, " /profile" , cpu_profile_endpoint)
456
498
HTTP. register! (router, " /profile_start" , cpu_profile_start_endpoint)
457
499
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)
458
503
HTTP. register! (router, " /heap_snapshot" , heap_snapshot_endpoint)
459
504
HTTP. register! (router, " /allocs_profile" , allocations_profile_endpoint)
460
505
HTTP. register! (router, " /allocs_profile_start" , allocations_start_endpoint)
0 commit comments