]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/trace/kqtrace.lua
xnu-4570.1.46.tar.gz
[apple/xnu.git] / tools / trace / kqtrace.lua
diff --git a/tools/trace/kqtrace.lua b/tools/trace/kqtrace.lua
new file mode 100755 (executable)
index 0000000..bb5b954
--- /dev/null
@@ -0,0 +1,339 @@
+#!/usr/local/bin/luatrace -s
+
+trace_eventname = function(codename, callback)
+       local debugid = trace.debugid(codename)
+       if debugid ~= 0 then
+               trace.single(debugid,callback)
+       else
+               printf("WARNING: Cannot locate debugid for '%s'\n", codename)
+       end
+end
+
+initial_timestamp = 0
+
+function event_prefix_string(buf, workq)
+       if initial_timestamp == 0 then
+               initial_timestamp = buf.timestamp
+       end
+       local secs = trace.convert_timestamp_to_nanoseconds(buf.timestamp - initial_timestamp) / 1000000000
+
+       local type
+       if trace.debugid_is_start(buf.debugid) then
+               type = "→"
+       elseif trace.debugid_is_end(buf.debugid) then
+               type = "←"
+       else
+               type = "↔"
+       end
+
+       proc = buf.command
+
+       local prefix = string.format("%s %6.9f %-17s [%05d.%06x] %-28s\t",
+               type, secs, proc, buf.pid, buf.threadid, buf.debugname)
+       if not workq then
+               prefix = prefix .. string.format(" 0x%16x", buf.arg1)
+       end
+
+       return prefix
+end
+
+function qos_string(qos)
+       if qos == 0 then
+               return "--"
+       elseif qos == 1 then
+               return "MT"
+       elseif qos == 2 then
+               return "BG"
+       elseif qos == 3 then
+               return "UT"
+       elseif qos == 4 then
+               return "DF"
+       elseif qos == 5 then
+               return "IN"
+       elseif qos == 6 then
+               return "UI"
+       elseif qos == 7 then
+               return "MG"
+       else
+               return string.format("??[0x%x]", qos)
+       end
+end
+
+function state_string(strings, state)
+       local str = ''
+       local first = true
+       for name, bit in pairs(strings) do
+               if (state & bit) == bit then
+                       if not first then
+                               str = str .. ' '
+                       end
+                       str = str .. name
+                       first = false
+               end
+       end
+       return str
+end
+
+kqrequest_state_strings = {
+       ['PROCESSING'] = 0x1,
+       ['THREQUESTED'] = 0x2,
+       ['WAKEUP'] = 0x4
+}
+
+kqueue_state_strings = {
+       ['SEL'] = 0x001,
+       ['SLEEP'] = 0x002,
+       ['PROCWAIT'] = 0x004,
+       ['KEV32'] = 0x008,
+       ['KEV64'] = 0x010,
+       ['KEV_QOS'] = 0x020,
+       ['WORKQ'] = 0x040,
+       ['WORKLOOP'] = 0x080,
+       ['PROCESSING'] = 0x100,
+       ['DRAIN'] = 0x200,
+       ['WAKEUP'] = 0x400,
+       ['DYNAMIC'] = 0x800,
+}
+
+knote_state_strings = {
+       ['ACTIVE'] = 0x0001,
+       ['QUEUED'] = 0x0002,
+       ['DISABLED'] = 0x0004,
+       ['DROPPING'] = 0x0008,
+       ['USEWAIT'] = 0x0010,
+       ['ATTACHING'] = 0x0020,
+       ['STAYACTIVE'] = 0x0040,
+       ['DEFERDELETE'] = 0x0080,
+       ['ATTACHED'] = 0x0100,
+       ['DISPATCH'] = 0x0200,
+       ['UDATA_SPECIFIC'] = 0x0400,
+       ['SUPPRESSED'] = 0x0800,
+       ['STOLENDROP'] = 0x1000,
+       ['REQVANISH'] = 0x2000,
+       ['VANISHED'] = 0x4000,
+}
+knote_state_strings = {
+       ['ACTIVE'] = 0x0001,
+       ['QUEUED'] = 0x0002,
+       ['DISABLED'] = 0x0004,
+       ['DROPPING'] = 0x0008,
+       ['USEWAIT'] = 0x0010,
+       ['ATTACHING'] = 0x0020,
+       ['STAYACTIVE'] = 0x0040,
+       ['DEFERDELETE'] = 0x0080,
+       ['ATTACHED'] = 0x0100,
+       ['DISPATCH'] = 0x0200,
+       ['UDATA_SPECIFIC'] = 0x0400,
+       ['SUPPRESSED'] = 0x0800,
+       ['STOLENDROP'] = 0x1000,
+       ['REQVANISH'] = 0x2000,
+       ['VANISHED'] = 0x4000,
+}
+
+
+kevent_flags_strings = {
+       ['ADD'] = 0x0001,
+       ['DELETE'] = 0x0002,
+       ['ENABLE'] = 0x0004,
+       ['DISABLE'] = 0x0008,
+       ['ONESHOT'] = 0x0010,
+       ['CLEAR'] = 0x0020,
+       ['RECEIPT'] = 0x0040,
+       ['DISPATCH'] = 0x0080,
+       ['UDATA_SPECIFIC'] = 0x0100,
+       ['VANISHED'] = 0x0200,
+       ['FLAG0'] = 0x1000,
+       ['FLAG1'] = 0x2000,
+       ['EOF'] = 0x8000,
+       ['ERROR'] = 0x4000,
+}
+
+function kevent_filter_string(filt)
+       if filt == -1 then
+               return 'READ'
+       elseif filt == -2 then
+               return 'WRITE'
+       elseif filt == -3 then
+               return 'AIO'
+       elseif filt == -4 then
+               return 'VNODE'
+       elseif filt == -5 then
+               return 'PROC'
+       elseif filt == -6 then
+               return 'SIGNAL'
+       elseif filt == -7 then
+               return 'TIMER'
+       elseif filt == -8 then
+               return 'MACHPORT'
+       elseif filt == -9 then
+               return 'FS'
+       elseif filt == -10 then
+               return 'USER'
+       -- -11 unused
+       elseif filt == -12 then
+               return 'VM'
+       elseif filt == -13 then
+               return 'SOCK'
+       elseif filt == -14 then
+               return 'MEMORYSTATUS'
+       elseif filt == 15 then
+               return 'KQREAD'
+       elseif filt == 16 then
+               return 'PIPE_R'
+       elseif filt == 17 then
+               return 'PIPE_W'
+       elseif filt == 18 then
+               return 'PTSD'
+       elseif filt == 19 then
+               return 'SOWRITE'
+       elseif filt == 20 then
+               return 'SOEXCEPT'
+       elseif filt == 21 then
+               return 'SPEC'
+       elseif filt == 22 then
+               return 'BPFREAD'
+       elseif filt == 23 then
+               return 'NECP_FD'
+       elseif filt == 24 then
+               return 'SKYWALK_CHANNEL_W'
+       elseif filt == 25 then
+               return 'SKYWALK_CHANNEL_R'
+       elseif filt == 26 then
+               return 'FSEVENT'
+       elseif filt == 27 then
+               return 'VN'
+       elseif filt == 28 then
+               return 'SKYWALK_CHANNEL_E'
+       elseif filt == 29 then
+               return 'TTY'
+       else
+               return string.format('[%d]', filt)
+       end
+end
+
+-- kqueue lifecycle
+
+function processing_begin(workq)
+       return function(buf)
+               local prefix = event_prefix_string(buf, workq)
+               if trace.debugid_is_start(buf.debugid) then
+                       local qos
+                       if workq then
+                               qos = buf.arg2
+                       else
+                               qos = buf.arg3
+                       end
+                       printf("%s QoS = %s\n", prefix, qos_string(qos))
+               else
+                       printf("%s request thread = 0x%x, kqrequest state = %s\n", prefix,
+                                       buf.arg1, state_string(kqrequest_state_strings, buf.arg2))
+               end
+       end
+end
+
+trace_eventname("KEVENT_kq_processing_begin", processing_begin(false))
+trace_eventname("KEVENT_kqwq_processing_begin", processing_begin(true))
+trace_eventname("KEVENT_kqwl_processing_begin", processing_begin(false))
+
+function processing_end(workq)
+       return function(buf)
+               local qos
+               if workq then
+                       qos = buf.arg2
+               else
+                       qos = buf.arg3
+               end
+               printf("%s QoS = %s\n", event_prefix_string(buf, workq), qos_string(qos))
+       end
+end
+
+trace_eventname("KEVENT_kq_processing_end", processing_end(false))
+trace_eventname("KEVENT_kqwq_processing_end", processing_end(true))
+trace_eventname("KEVENT_kqwl_processing_end", processing_end(false))
+
+trace_eventname("KEVENT_kqwq_bind", function(buf)
+       printf("%s thread = 0x%x, QoS = %s, kqrequest state = %s\n",
+                       event_prefix_string(buf, true), buf.arg1, qos_string(buf.arg3),
+                       state_string(kqrequest_state_strings, buf.arg4))
+end)
+
+trace_eventname("KEVENT_kqwq_unbind", function(buf)
+       printf("%s thread = 0x%x, QoS = %s\n", event_prefix_string(buf, true),
+                       buf.arg1, qos_string(buf.arg3))
+end)
+
+trace_eventname("KEVENT_kqwl_bind", function(buf)
+       qos = buf.arg3 & 0xff
+       duplicate = buf.arg3 & (1 << 8)
+       kqr_override_qos_delta = buf.arg4 >> 8
+       kqr_state = buf.arg4 & 0xff
+
+       printf("%s thread = 0x%x, QoS = %s, override QoS delta = %d, kqrequest state = %s%s\n",
+                       event_prefix_string(buf, false), buf.arg2, qos_string(qos),
+                       kqr_override_qos_delta,
+                       state_string(kqrequest_state_strings, kqr_state),
+                       duplicate ? ", duplicate" : "")
+end)
+
+trace_eventname("KEVENT_kqwl_unbind", function(buf)
+       flags = buf.arg3
+       qos = buf.arg4
+
+       printf("%s thread = 0x%x, QoS = %s, flags = 0x%x\n", event_prefix_string(buf, false),
+                       buf.arg2, qos_string(qos), flags)
+end)
+
+function thread_request(workq)
+       return function(buf)
+               printf("%s QoS = %s, kqrequest state = %s, override QoS delta = %d\n",
+                               event_prefix_string(buf, workq), qos_string(buf.arg2),
+                               state_string(kqrequest_state_strings, buf.arg3), buf.arg3 >> 8)
+       end
+end
+
+function thread_adjust(buf)
+       tid = buf.arg2
+       kqr_qos = buf.arg3 >> 8
+       new_qos = buf.arg3 & 0xff
+       kqr_qos_override = buf.arg4 >> 8
+       kqr_state = buf.arg4 & 0xff
+
+       printf("%s thread = 0x%x, old/new QoS = %s/%s, old/new override QoS delta = %d/%d, kqrequest state = %s\n",
+                       event_prefix_string(buf, false),
+                       tid,
+                       qos_string(kqr_qos),
+                       qos_string(new_qos),
+                       kqr_qos_override,
+                       new_qos - kqr_qos,
+                       state_string(kqrequest_state_strings, kqr_state))
+end
+
+trace_eventname("KEVENT_kqwq_thread_request", thread_request(true))
+trace_eventname("KEVENT_kqwl_thread_request", thread_request(false))
+trace_eventname("KEVENT_kqwl_thread_adjust", thread_adjust)
+
+function kevent_register(workq)
+       return function(buf)
+               printf("%s kevent udata = 0x%x, kevent filter = %s, kevent flags = %s\n",
+                               event_prefix_string(buf, workq), buf.arg2,
+                               kevent_filter_string(buf.arg4),
+                               state_string(kevent_flags_strings, buf.arg3))
+       end
+end
+
+trace_eventname("KEVENT_kq_register", kevent_register(false))
+trace_eventname("KEVENT_kqwq_register", kevent_register(true))
+trace_eventname("KEVENT_kqwl_register", kevent_register(false))
+
+function kevent_process(workq)
+       return function(buf)
+               printf("%s kevent ident = 0x%x, udata = 0x%x, kevent filter = %s, knote status = %s\n",
+                               event_prefix_string(buf, workq), buf.arg3 >> 32, buf.arg2,
+                               kevent_filter_string(buf.arg4),
+                               state_string(knote_state_strings, buf.arg3 & 0xffffffff))
+       end
+end
+
+trace_eventname("KEVENT_kq_process", kevent_process(false))
+trace_eventname("KEVENT_kqwq_process", kevent_process(true))
+trace_eventname("KEVENT_kqwl_process", kevent_process(false))