]> git.saurik.com Git - apple/libpthread.git/blame - tools/wqtrace.lua
libpthread-301.50.1.tar.gz
[apple/libpthread.git] / tools / wqtrace.lua
CommitLineData
964d3577
A
1#!/usr/local/bin/luatrace -s
2
3trace_codename = function(codename, callback)
4 local debugid = trace.debugid(codename)
a0619f9c 5 if debugid ~= 0 then
010efe49 6 trace.single(debugid,callback)
2546420a
A
7 else
8 printf("WARNING: Cannot locate debugid for '%s'\n", codename)
964d3577
A
9 end
10end
11
12initial_timestamp = 0
2546420a 13workqueue_ptr_map = {};
964d3577
A
14get_prefix = function(buf)
15 if initial_timestamp == 0 then
16 initial_timestamp = buf.timestamp
17 end
010efe49 18 local secs = trace.convert_timestamp_to_nanoseconds(buf.timestamp - initial_timestamp) / 1000000000
2546420a 19
964d3577 20 local prefix
010efe49
A
21 if trace.debugid_is_start(buf.debugid) then
22 prefix = "→"
23 elseif trace.debugid_is_end(buf.debugid) then
24 prefix = "←"
25 else
26 prefix = "↔"
964d3577 27 end
2546420a
A
28
29 local proc
30 if buf.command ~= "kernel_task" then
31 proc = buf.command
32 workqueue_ptr_map[buf[1]] = buf.command
33 elseif workqueue_ptr_map[buf[1]] ~= nil then
34 proc = workqueue_ptr_map[buf[1]]
35 else
36 proc = "UNKNOWN"
37 end
38
39 return string.format("%s %6.9f %-17s [%05d.%06x] %-24s",
40 prefix, secs, proc, buf.pid, buf.threadid, buf.debugname)
964d3577
A
41end
42
43parse_pthread_priority = function(pri)
2546420a
A
44 pri = pri & 0xffffffff
45 if (pri & 0x02000000) == 0x02000000 then
46 return "Manager"
47 end
48 local qos = (pri & 0x00ffff00) >> 8
964d3577 49 if qos == 0x20 then
a0619f9c 50 return string.format("UI[%x]", pri);
964d3577 51 elseif qos == 0x10 then
a0619f9c 52 return string.format("IN[%x]", pri);
964d3577 53 elseif qos == 0x08 then
a0619f9c 54 return string.format("DF[%x]", pri);
964d3577 55 elseif qos == 0x04 then
a0619f9c 56 return string.format("UT[%x]", pri);
964d3577 57 elseif qos == 0x02 then
2546420a 58 return string.format("BG[%x]", pri);
964d3577 59 elseif qos == 0x01 then
a0619f9c 60 return string.format("MT[%x]", pri);
964d3577 61 elseif qos == 0x00 then
a0619f9c 62 return string.format("--[%x]", pri);
964d3577 63 else
a0619f9c 64 return string.format("??[%x]", pri);
964d3577
A
65 end
66end
67
a0619f9c
A
68parse_qos_bucket = function(pri)
69 if pri == 0 then
70 return string.format("UI[%x]", pri);
71 elseif pri == 1 then
72 return string.format("IN[%x]", pri);
73 elseif pri == 2 then
74 return string.format("DF[%x]", pri);
75 elseif pri == 3 then
76 return string.format("UT[%x]", pri);
77 elseif pri == 4 then
78 return string.format("BG[%x]", pri);
79 elseif pri == 5 then
80 return string.format("MT[%x]", pri);
81 elseif pri == 6 then
82 return string.format("MG[%x]", pri);
83 else
84 return string.format("??[%x]", pri);
85 end
86end
87
88parse_thactive_req_bucket = function(pri)
89 if pri ~= 6 then
90 return parse_qos_bucket(pri)
91 end
92 return "None"
93end
94
95get_thactive = function(low, high)
96 return string.format("req: %s, MG: %d, UI: %d, IN: %d, DE: %d, UT: %d, BG: %d, MT: %d",
97 parse_thactive_req_bucket(high >> (16 * 3)), (high >> (2 * 16)) & 0xffff,
98 (low >> (0 * 16)) & 0xffff, (low >> (1 * 16)) & 0xffff,
99 (low >> (2 * 16)) & 0xffff, (low >> (3 * 16)) & 0xffff,
100 (high >> (0 * 16)) & 0xffff, (high >> (1 * 16)) & 0xffff)
101end
102
964d3577
A
103-- workqueue lifecycle
104
105trace_codename("wq_pthread_exit", function(buf)
106 local prefix = get_prefix(buf)
107 if trace.debugid_is_start(buf.debugid) then
108 printf("%s\tprocess is exiting\n",prefix)
109 else
110 printf("%s\tworkqueue marked as exiting and timer is complete\n",prefix)
111 end
112end)
113
114trace_codename("wq_workqueue_exit", function(buf)
115 local prefix = get_prefix(buf)
116 if trace.debugid_is_start(buf.debugid) then
117 printf("%s\tall threads have exited, cleaning up\n",prefix)
118 else
119 printf("%s\tclean up complete\n",prefix)
120 end
121end)
122
964d3577
A
123trace_codename("wq_start_add_timer", function(buf)
124 local prefix = get_prefix(buf)
125 printf("%s\tarming timer to fire in %d us (flags: %x, reqcount: %d)\n",
126 prefix, buf.arg4, buf.arg3, buf.arg2)
127end)
128
129trace_codename("wq_add_timer", function(buf)
130 local prefix = get_prefix(buf)
131 if trace.debugid_is_start(buf.debugid) then
132 printf("%s\tadd_timer fired (flags: %x, nthreads: %d, thidlecount: %d)\n",
133 prefix, buf.arg2, buf.arg3, buf.arg4)
134 elseif trace.debugid_is_end(buf.debugid) then
135 printf("%s\tadd_timer completed (start_timer: %x, nthreads: %d, thidlecount: %d)\n",
136 prefix, buf.arg2, buf.arg3, buf.arg4)
137 else
138 printf("%s\tadd_timer added threads (reqcount: %d, thidlecount: %d, busycount: %d)\n",
139 prefix, buf.arg2, buf.arg3, buf.arg4)
140
141 end
142end)
143
a0619f9c
A
144trace_codename("wq_run_threadreq", function(buf)
145 local prefix = get_prefix(buf)
146 if trace.debugid_is_start(buf.debugid) then
147 if buf[2] > 0 then
148 printf("%s\trun_threadreq: %x (priority: %s, flags: %d) on %x\n",
149 prefix, buf[2], parse_qos_bucket(buf[4] >> 16), buf[4] & 0xff, buf[3])
150 else
151 printf("%s\trun_threadreq: <none> on %x\n",
152 prefix, buf[3])
153 end
154 else
155 if buf[2] == 1 then
156 printf("%s\tpended event manager, already running\n", prefix)
157 elseif buf[2] == 2 then
158 printf("%s\tnothing to do\n", prefix)
159 elseif buf[2] == 3 then
160 printf("%s\tno eligible request found\n", prefix)
161 elseif buf[2] == 4 then
162 printf("%s\tadmission control failed\n", prefix)
163 elseif buf[2] == 5 then
164 printf("%s\tunable to add new thread (may_add_new_thread: %d, nthreads: %d)\n", prefix, buf[3], buf[4])
165 elseif buf[2] == 6 then
166 printf("%s\tthread creation failed\n", prefix)
167 elseif buf[2] == 0 then
168 printf("%s\tsuccess\n", prefix)
169 else
170 printf("%s\tWARNING: UNKNOWN END CODE:%d\n", prefix, buf.arg4)
171 end
172 end
173end)
174
175trace_codename("wq_run_threadreq_mgr_merge", function(buf)
176 local prefix = get_prefix(buf)
177 printf("%s\t\tmerging incoming manager request into existing\n", prefix)
178end)
179
180trace_codename("wq_run_threadreq_req_select", function(buf)
964d3577 181 local prefix = get_prefix(buf)
a0619f9c
A
182 if buf[3] == 1 then
183 printf("%s\t\tselected event manager request %x\n", prefix, buf[2])
184 elseif buf[3] == 2 then
185 printf("%s\t\tselected overcommit request %x\n", prefix, buf[2])
186 elseif buf[3] == 3 then
187 printf("%s\t\tselected constrained request %x\n", prefix, buf[2])
964d3577 188 else
a0619f9c 189 printf("%s\t\tWARNING: UNKNOWN DECISION CODE:%d\n", prefix, buf.arg[3])
964d3577
A
190 end
191end)
192
a0619f9c 193trace_codename("wq_run_threadreq_thread_select", function(buf)
964d3577 194 local prefix = get_prefix(buf)
a0619f9c
A
195 if buf[2] == 1 then
196 printf("%s\t\trunning on current thread %x\n", prefix, buf[3])
197 elseif buf[2] == 2 then
198 printf("%s\t\trunning on idle thread %x\n", prefix, buf[3])
199 elseif buf[2] == 3 then
200 printf("%s\t\tcreated new thread\n", prefix)
201 else
202 printf("%s\t\tWARNING: UNKNOWN DECISION CODE:%d\n", prefix, buf.arg[2])
203 end
964d3577
A
204end)
205
a0619f9c
A
206trace_codename("wq_thread_reset_priority", function(buf)
207 local prefix = get_prefix(buf)
208 local old_qos = buf[3] >> 16;
209 local new_qos = buf[3] & 0xff;
210 if buf[4] == 1 then
211 printf("%s\t\treset priority of %x from %s to %s\n", prefix, buf[2], parse_qos_bucket(old_qos), parse_qos_bucket(new_qos))
212 elseif buf[4] == 2 then
213 printf("%s\t\treset priority of %x from %s to %s for reserve manager\n", prefix, buf[2], parse_qos_bucket(old_qos), parse_qos_bucket(new_qos))
214 elseif buf[4] == 3 then
215 printf("%s\t\treset priority of %x from %s to %s for cleanup\n", prefix, buf[2], parse_qos_bucket(old_qos), parse_qos_bucket(new_qos))
216 end
217end)
964d3577 218
a0619f9c 219trace_codename("wq_thread_park", function(buf)
964d3577
A
220 local prefix = get_prefix(buf)
221 if trace.debugid_is_start(buf.debugid) then
a0619f9c 222 printf("%s\tthread parking\n", prefix)
964d3577 223 else
a0619f9c 224 printf("%s\tthread woken\n", prefix)
964d3577
A
225 end
226end)
227
a0619f9c
A
228trace_codename("wq_thread_squash", function(buf)
229 local prefix = get_prefix(buf)
230 printf("%s\tthread squashed from %s to %s\n", prefix,
231 parse_qos_bucket(buf[2]), parse_qos_bucket(buf[3]))
232end)
233
010efe49
A
234trace.enable_thread_cputime()
235runitem_time_map = {}
236runitem_cputime_map = {}
964d3577
A
237trace_codename("wq_runitem", function(buf)
238 local prefix = get_prefix(buf)
239 if trace.debugid_is_start(buf.debugid) then
010efe49
A
240 runitem_time_map[buf.threadid] = buf.timestamp;
241 runitem_cputime_map[buf.threadid] = trace.cputime_for_thread(buf.threadid);
242
a0619f9c 243 printf("%s\tSTART running item @ %s\n", prefix, parse_qos_bucket(buf[3]))
010efe49
A
244 elseif runitem_time_map[buf.threadid] then
245 local time = buf.timestamp - runitem_time_map[buf.threadid]
246 local cputime = trace.cputime_for_thread(buf.threadid) - runitem_cputime_map[buf.threadid]
247
248 local time_ms = trace.convert_timestamp_to_nanoseconds(time) / 1000000
249 local cputime_ms = trace.convert_timestamp_to_nanoseconds(cputime) / 1000000
250
a0619f9c
A
251 printf("%s\tDONE running item @ %s: time = %6.6f ms, cputime = %6.6f ms\n",
252 prefix, parse_qos_bucket(buf[2]), time_ms, cputime_ms)
010efe49
A
253
254 runitem_time_map[buf.threadid] = 0
255 runitem_cputime_map[buf.threadid] = 0
964d3577 256 else
a0619f9c 257 printf("%s\tDONE running item @ %s\n", prefix, parse_qos_bucket(buf[2]))
964d3577
A
258 end
259end)
260
a0619f9c 261trace_codename("wq_runthread", function(buf)
964d3577
A
262 local prefix = get_prefix(buf)
263 if trace.debugid_is_start(buf.debugid) then
a0619f9c
A
264 printf("%s\tSTART running thread\n", prefix)
265 elseif trace.debugid_is_end(buf.debugid) then
266 printf("%s\tDONE running thread\n", prefix)
964d3577
A
267 end
268end)
269
a0619f9c
A
270trace_codename("wq_thactive_update", function(buf)
271 local prefix = get_prefix(buf)
272 local thactive = get_thactive(buf[2], buf[3])
273 if buf[1] == 1 then
274 printf("%s\tthactive constrained pre-post (%s)\n", prefix, thactive)
275 elseif buf[1] == 2 then
276 printf("%s\tthactive constrained run (%s)\n", prefix, thactive)
277 else
278 return
279 end
964d3577
A
280end)
281
a0619f9c 282trace_codename("wq_thread_block", function(buf)
964d3577 283 local prefix = get_prefix(buf)
a0619f9c 284 local req_pri = parse_thactive_req_bucket(buf[3] >> 8)
964d3577 285 if trace.debugid_is_start(buf.debugid) then
a0619f9c
A
286 printf("%s\tthread blocked (activecount: %d, priority: %s, req_pri: %s, reqcount: %d, start_timer: %d)\n",
287 prefix, buf[2], parse_qos_bucket(buf[3] & 0xff), req_pri, buf[4] >> 1, buf[4] & 0x1)
964d3577 288 else
a0619f9c
A
289 printf("%s\tthread unblocked (activecount: %d, priority: %s, req_pri: %s, threads_scheduled: %d)\n",
290 prefix, buf[2], parse_qos_bucket(buf[3] & 0xff), req_pri, buf[4])
964d3577
A
291 end
292end)
293
a0619f9c 294trace_codename("wq_thread_create_failed", function(buf)
964d3577 295 local prefix = get_prefix(buf)
a0619f9c
A
296 if buf[3] == 0 then
297 printf("%s\tfailed to create new workqueue thread, kern_return: 0x%x\n",
298 prefix, buf[2])
299 elseif buf[3] == 1 then
300 printf("%s\tfailed to vm_map workq thread stack: 0x%x\n", prefix, buf[2])
301 elseif buf[3] == 2 then
302 printf("%s\tfailed to vm_protect workq thread guardsize: 0x%x\n", prefix, buf[2])
964d3577 303 end
964d3577
A
304end)
305
a0619f9c
A
306trace_codename("wq_thread_create", function(buf)
307 printf("%s\tcreated new workqueue thread\n", get_prefix(buf))
964d3577
A
308end)
309
a0619f9c 310trace_codename("wq_wqops_reqthreads", function(buf)
964d3577 311 local prefix = get_prefix(buf)
a0619f9c 312 printf("%s\tuserspace requested %d threads at %s\n", prefix, buf[2], parse_pthread_priority(buf[3]));
964d3577
A
313end)
314
a0619f9c 315trace_codename("wq_kevent_reqthreads", function(buf)
964d3577 316 local prefix = get_prefix(buf)
a0619f9c
A
317 if buf[4] == 0 then
318 printf("%s\tkevent requested a thread at %s\n", prefix, parse_pthread_priority(buf[3]));
319 elseif buf[4] == 1 then
320 printf("%s\tworkloop requested a thread for req %x at %s\n", prefix, buf[2], parse_pthread_priority(buf[3]));
321 elseif buf[4] == 2 then
322 printf("%s\tworkloop updated priority of req %x to %s\n", prefix, buf[2], parse_pthread_priority(buf[3]));
323 elseif buf[4] == 3 then
324 printf("%s\tworkloop canceled req %x\n", prefix, buf[2], parse_pthread_priority(buf[3]));
325 elseif buf[4] == 4 then
326 printf("%s\tworkloop redrove a thread request\n", prefix);
964d3577
A
327 end
328end)
329
a0619f9c 330trace_codename("wq_constrained_admission", function(buf)
2546420a 331 local prefix = get_prefix(buf)
a0619f9c
A
332 if buf[2] == 1 then
333 printf("fail: %s\twq_constrained_threads_scheduled=%d >= wq_max_constrained_threads=%d\n",
334 prefix, buf[3], buf[4])
335 elseif (buf[2] == 2) or (buf[2] == 3) then
336 local success = nil;
337 if buf[2] == 2 then success = "success"
338 else success = "fail" end
339 printf("%s: %s\tthactive_count=%d + busycount=%d >= wq->wq_max_concurrency\n",
340 prefix, success, buf[3], buf[4])
341 end
2546420a
A
342end)
343
964d3577
A
344-- The trace codes we need aren't enabled by default
345darwin.sysctlbyname("kern.pthread_debug_tracing", 1)
346completion_handler = function()
347 darwin.sysctlbyname("kern.pthread_debug_tracing", 0)
348end
349trace.set_completion_handler(completion_handler)