1 #!/usr/local/bin/luatrace -s
3 trace_codename = function(codename, callback)
4 local debugid = trace.debugid(codename)
6 trace.single(debugid,callback)
11 get_prefix = function(buf)
12 if initial_timestamp == 0 then
13 initial_timestamp = buf.timestamp
16 if trace.debugid_is_start(buf.debugid) then
18 elseif trace.debugid_is_end(buf.debugid) then
23 local secs = (buf.timestamp - initial_timestamp) / 1000 / 1000000
24 local usecs = (buf.timestamp - initial_timestamp) / 1000 % 1000000
25 return string.format("%s %6d.%06d %-16s[%06x] %-24s",
26 prefix, secs, usecs, buf.command, buf.threadid, buf.debugname)
29 parse_pthread_priority = function(pri)
30 local qos = bit32.rshift(bit32.band(pri, 0x00ffff00), 8)
33 elseif qos == 0x10 then
35 elseif qos == 0x08 then
37 elseif qos == 0x04 then
39 elseif qos == 0x02 then
41 elseif qos == 0x01 then
43 elseif qos == 0x00 then
50 -- workqueue lifecycle
52 trace_codename("wq_pthread_exit", function(buf)
53 local prefix = get_prefix(buf)
54 if trace.debugid_is_start(buf.debugid) then
55 printf("%s\tprocess is exiting\n",prefix)
57 printf("%s\tworkqueue marked as exiting and timer is complete\n",prefix)
61 trace_codename("wq_workqueue_exit", function(buf)
62 local prefix = get_prefix(buf)
63 if trace.debugid_is_start(buf.debugid) then
64 printf("%s\tall threads have exited, cleaning up\n",prefix)
66 printf("%s\tclean up complete\n",prefix)
72 trace_codename("wq_kevent_req_threads", function(buf)
73 local prefix = get_prefix(buf)
74 if trace.debugid_is_start(buf.debugid) then
75 printf("%s\tkevent requesting threads (requests[] length = %d)\n", prefix, buf.arg2)
77 printf("%s\tkevent request complete (start_timer: %d)\n", prefix, buf.arg2)
81 trace_codename("wq_req_threads", function(buf)
82 local prefix = get_prefix(buf)
83 printf("%s\trecording %d constrained request(s) at %s, total %d requests\n",
84 prefix, buf.arg4, parse_pthread_priority(buf.arg2), buf.arg3)
87 trace_codename("wq_req_octhreads", function(buf)
88 local prefix = get_prefix(buf)
89 printf("%s\tattempting %d overcommit request(s) at %s, total %d requests\n",
90 prefix, buf.arg4, parse_pthread_priority(buf.arg2), buf.arg3)
92 trace_codename("wq_delay_octhreads", function(buf)
93 local prefix = get_prefix(buf)
94 printf("%s\trecording %d delayed overcommit request(s) at %s, total %d requests\n",
95 prefix, buf.arg4, parse_pthread_priority(buf.arg2), buf.arg3)
98 trace_codename("wq_req_kevent_threads", function(buf)
99 local prefix = get_prefix(buf)
100 printf("%s\trecording kevent constrained request at %s, total %d requests\n",
101 prefix, parse_pthread_priority(buf.arg2), buf.arg3)
103 trace_codename("wq_req_kevent_octhreads", function(buf)
104 local prefix = get_prefix(buf)
105 printf("%s\trecording kevent overcommit request at %s, total %d requests\n",
106 prefix, parse_pthread_priority(buf.arg2), buf.arg3)
108 trace_codename("wq_req_event_manager", function(buf)
109 local prefix = get_prefix(buf)
110 printf("%s\trecording event manager request at %s, existing at %d, %d running\n",
111 prefix, parse_pthread_priority(buf.arg2), buf.arg3, buf.arg4)
114 trace_codename("wq_start_add_timer", function(buf)
115 local prefix = get_prefix(buf)
116 printf("%s\tarming timer to fire in %d us (flags: %x, reqcount: %d)\n",
117 prefix, buf.arg4, buf.arg3, buf.arg2)
120 trace_codename("wq_add_timer", function(buf)
121 local prefix = get_prefix(buf)
122 if trace.debugid_is_start(buf.debugid) then
123 printf("%s\tadd_timer fired (flags: %x, nthreads: %d, thidlecount: %d)\n",
124 prefix, buf.arg2, buf.arg3, buf.arg4)
125 elseif trace.debugid_is_end(buf.debugid) then
126 printf("%s\tadd_timer completed (start_timer: %x, nthreads: %d, thidlecount: %d)\n",
127 prefix, buf.arg2, buf.arg3, buf.arg4)
129 printf("%s\tadd_timer added threads (reqcount: %d, thidlecount: %d, busycount: %d)\n",
130 prefix, buf.arg2, buf.arg3, buf.arg4)
135 trace_codename("wq_overcommitted", function(buf)
136 local prefix = get_prefix(buf)
137 if bit32.band(buf.arg2, 0x80) then
138 printf("%s\tworkqueue overcimmitted @ %s, starting timer (thactive_count: %d, busycount; %d)",
139 prefix, parse_pthread_priority(buf.arg2), buf.arg3, buf.arg4)
141 printf("%s\tworkqueue overcimmitted @ %s (thactive_count: %d, busycount; %d)",
142 prefix, parse_pthread_priority(buf.arg2), buf.arg3, buf.arg4)
146 trace_codename("wq_stalled", function(buf)
147 local prefix = get_prefix(buf)
148 printf("%s\tworkqueue stalled (nthreads: %d)\n", prefix, buf.arg3)
153 trace_codename("wq_run_nextitem", function(buf)
154 local prefix = get_prefix(buf)
155 if trace.debugid_is_start(buf.debugid) then
156 if buf.arg2 == 0 then
157 printf("%s\tthread %d looking for next request (idlecount: %d, reqcount: %d)\n",
158 prefix, buf.threadid, buf.arg3, buf.arg4)
160 printf("%s\ttrying to run a request on an idle thread (idlecount: %d, reqcount: %d)\n",
161 prefix, buf.arg3, buf.arg4)
164 if buf.arg4 == 1 then
165 printf("%s\tkicked off work on thread %d (overcommit: %d)\n", prefix, buf.arg2, buf.arg3)
166 elseif buf.arg4 == 2 then
167 printf("%s\tno work/threads (start_timer: %d)\n", prefix, buf.arg3)
168 elseif buf.arg4 == 3 then
169 printf("%s\tthread parked\n", prefix)
170 elseif buf.arg4 == 4 then
171 printf("%s\treturning with new request\n", prefix)
173 printf("%s\tWARNING: UNKNOWN END CODE:%d\n", prefix, buf.arg4)
178 trace_codename("wq_runitem", function(buf)
179 local prefix = get_prefix(buf)
180 if trace.debugid_is_start(buf.debugid) then
181 printf("%s\trunning an item at %s (flags: %x)\n", prefix, parse_pthread_priority(buf.arg3), buf.arg2)
183 printf("%s\tthread returned\n", prefix)
187 trace_codename("wq_thread_yielded", function(buf)
188 local prefix = get_prefix(buf)
189 if trace.debugid_is_start(buf.debugid) then
190 printf("%s\tthread_yielded called (yielded_count: %d, reqcount: %d)\n",
191 prefix, buf.arg2, buf.arg3)
193 if (buf.arg4 == 1) then
194 printf("%s\tthread_yielded completed kicking thread (yielded_count: %d, reqcount: %d)\n",
195 prefix, buf.arg2, buf.arg3)
196 elseif (buf.arg4 == 2) then
197 printf("%s\tthread_yielded completed (yielded_count: %d, reqcount: %d)\n",
198 prefix, buf.arg2, buf.arg3)
200 printf("%s\tthread_yielded completed unusually (yielded_count: %d, reqcount: %d)\n",
201 prefix, buf.arg2, buf.arg3)
206 trace_codename("wq_thread_block", function(buf)
207 local prefix = get_prefix(buf)
208 if trace.debugid_is_start(buf.debugid) then
209 printf("%s\tthread blocked (activecount: %d, prioritiy: %d, start_time: %d)\n",
210 prefix, buf.arg2, buf.arg3, buf.arg3)
212 printf("%s\tthread unblocked (threads_scheduled: %d, priority: %d)\n",
213 prefix, buf.arg2, buf.arg3)
217 trace_codename("wq_thread_suspend", function(buf)
218 local prefix = get_prefix(buf)
219 if trace.debugid_is_start(buf.debugid) then
220 printf("%s\tcreated new suspended thread (nthreads:%d)\n",
223 if buf.arg4 == 0xdead then
224 printf("%s\tthread exited suspension to die (nthreads: %d)\n",
230 trace_codename("wq_thread_park", function(buf)
231 local prefix = get_prefix(buf)
232 if trace.debugid_is_start(buf.debugid) then
233 printf("%s\tthread parked (threads_scheduled: %d, thidlecount: %d, us_to_wait: %d)\n",
234 prefix, buf.arg2, buf.arg3, buf.arg4)
236 if buf.arg4 == 0xdead then
237 printf("%s\tthread exited park to die (nthreads: %d)\n", prefix, buf.arg3)
243 trace_codename("wq_thread_limit_exceeded", function(buf)
244 local prefix = get_prefix(buf)
245 printf("%s\ttotal thread limit exceeded, %d threads, total %d max threads, (kern limit: %d)\n",
246 prefix, buf.arg2, buf.arg3, buf.arg4)
249 trace_codename("wq_thread_constrained_maxed", function(buf)
250 local prefix = get_prefix(buf)
251 printf("%s\tattempted to add thread at max constrained limit, total %d threads (limit: %d)\n",
252 prefix, buf.arg2, buf.arg3)
255 trace_codename("wq_thread_add_during_exit", function(buf)
256 local prefix = get_prefix(buf)
257 printf("%s\tattempted to add thread during WQ_EXITING\n", prefix)
260 trace_codename("wq_thread_create_failed", function(buf)
261 local prefix = get_prefix(buf)
262 if buf.arg3 == 0 then
263 printf("%s\tfailed to create new workqueue thread, kern_return: 0x%x\n",
265 elseif buf.arg3 == 1 then
266 printf("%s\tfailed to vm_map workq thread stack: 0x%x", prefix, buf.arg2)
267 elseif buf.arg3 == 2 then
268 printf("%s\tfailed to vm_protect workq thread guardsize: 0x%x", prefix, buf.arg2)
273 -- The trace codes we need aren't enabled by default
274 darwin.sysctlbyname("kern.pthread_debug_tracing", 1)
275 completion_handler = function()
276 darwin.sysctlbyname("kern.pthread_debug_tracing", 0)
278 trace.set_completion_handler(completion_handler)