]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kperf/kperfbsd.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / osfmk / kperf / kperfbsd.c
index b89125126fe1adb8e8a334e31323735c59885cb6..6fe1b5c291c3d6c8930699b68a346e988e16ba10 100644 (file)
 #include <kperf/kperfbsd.h>
 #include <kperf/kperf_timer.h>
 #include <kperf/pet.h>
+#include <kperf/lazy.h>
 
 #include <sys/ktrace.h>
 
-/* IDs for dispatch from SYSCTL macros */
-#define REQ_SAMPLING                (1)
-#define REQ_ACTION_COUNT            (2)
-#define REQ_ACTION_SAMPLERS         (3)
-#define REQ_TIMER_COUNT             (4)
-#define REQ_TIMER_PERIOD            (5)
-#define REQ_TIMER_PET               (6)
-#define REQ_TIMER_ACTION            (7)
-#define REQ_BLESS                   (8)
-#define REQ_ACTION_USERDATA         (9)
-#define REQ_ACTION_FILTER_BY_TASK   (10)
-#define REQ_ACTION_FILTER_BY_PID    (11)
-/* 12 unused */
-#define REQ_PET_IDLE_RATE           (13)
-#define REQ_BLESS_PREEMPT           (14)
-#define REQ_KDBG_CSWITCH            (15)
-#define REQ_RESET                   (16)
-/* 17 unused */
-#define REQ_ACTION_UCALLSTACK_DEPTH (18)
-#define REQ_ACTION_KCALLSTACK_DEPTH (19)
-#define REQ_LIGHTWEIGHT_PET         (20)
-#define REQ_KDEBUG_ACTION           (21)
-#define REQ_KDEBUG_FILTER           (22)
+/* Requests from kperf sysctls. */
+enum kperf_request {
+       REQ_SAMPLING,
+       REQ_RESET,
+
+       REQ_ACTION_COUNT,
+       REQ_ACTION_SAMPLERS,
+       REQ_ACTION_USERDATA,
+       REQ_ACTION_FILTER_BY_TASK,
+       REQ_ACTION_FILTER_BY_PID,
+       REQ_ACTION_UCALLSTACK_DEPTH,
+       REQ_ACTION_KCALLSTACK_DEPTH,
+
+       REQ_TIMER_COUNT,
+       REQ_TIMER_PERIOD,
+       REQ_TIMER_PET,
+       REQ_TIMER_ACTION,
+
+       REQ_KDBG_CSWITCH,
+
+       REQ_BLESS,
+       REQ_BLESS_PREEMPT,
+
+       REQ_PET_IDLE_RATE,
+       REQ_LIGHTWEIGHT_PET,
+
+       REQ_KDEBUG_FILTER,
+       REQ_KDEBUG_ACTION,
+
+       REQ_LAZY_WAIT_TIME_THRESHOLD,
+       REQ_LAZY_WAIT_ACTION,
+       REQ_LAZY_CPU_TIME_THRESHOLD,
+       REQ_LAZY_CPU_ACTION,
+};
 
 int kperf_debug_level = 0;
 
@@ -78,7 +90,7 @@ _Atomic long long kperf_pending_ipis = 0;
 #endif /* DEVELOPMENT || DEBUG */
 
 /*
- * kperf has a different sysctl model than others.
+ * kperf has unique requirements from sysctl.
  *
  * For simple queries like the number of actions, the normal sysctl style
  * of get/set works well.
@@ -137,6 +149,28 @@ kperf_sysctl_get_set_int(struct sysctl_req *req,
        return set(value);
 }
 
+static int
+kperf_sysctl_get_set_uint64(struct sysctl_req *req,
+       uint64_t (*get)(void), int (*set)(uint64_t))
+{
+       assert(req != NULL);
+       assert(get != NULL);
+       assert(set != NULL);
+
+       uint64_t value = 0;
+       if (req->oldptr) {
+               value = get();
+       }
+
+       int error = sysctl_io_number(req, value, sizeof(value), &value, NULL);
+
+       if (error || !req->newptr) {
+               return error;
+       }
+
+       return set(value);
+}
+
 static int
 kperf_sysctl_get_set_unsigned_uint32(struct sysctl_req *req,
        int (*get)(unsigned int, uint32_t *), int (*set)(unsigned int, uint32_t))
@@ -311,9 +345,11 @@ sysctl_kdebug_filter(struct sysctl_req *req)
                }
 
                return SYSCTL_OUT(req, filter, filter_size);
+       } else if (req->newptr != USER_ADDR_NULL) {
+               return kperf_kdebug_set_filter(req->newptr, (uint32_t)req->newlen);
+       } else {
+               return EINVAL;
        }
-
-       return kperf_kdebug_set_filter(req->newptr, (uint32_t)req->newlen);
 }
 
 static int
@@ -407,12 +443,40 @@ sysctl_kdbg_cswitch(struct sysctl_req *req)
                kperf_kdbg_cswitch_set);
 }
 
+static int
+sysctl_lazy_wait_time_threshold(struct sysctl_req *req)
+{
+       return kperf_sysctl_get_set_uint64(req, kperf_lazy_get_wait_time_threshold,
+               kperf_lazy_set_wait_time_threshold);
+}
+
+static int
+sysctl_lazy_wait_action(struct sysctl_req *req)
+{
+       return kperf_sysctl_get_set_int(req, kperf_lazy_get_wait_action,
+               kperf_lazy_set_wait_action);
+}
+
+static int
+sysctl_lazy_cpu_time_threshold(struct sysctl_req *req)
+{
+       return kperf_sysctl_get_set_uint64(req, kperf_lazy_get_cpu_time_threshold,
+               kperf_lazy_set_cpu_time_threshold);
+}
+
+static int
+sysctl_lazy_cpu_action(struct sysctl_req *req)
+{
+       return kperf_sysctl_get_set_int(req, kperf_lazy_get_cpu_action,
+               kperf_lazy_set_cpu_action);
+}
+
 static int
 kperf_sysctl SYSCTL_HANDLER_ARGS
 {
 #pragma unused(oidp, arg2)
        int ret;
-       uintptr_t type = (uintptr_t)arg1;
+       enum kperf_request type = (enum kperf_request)arg1;
 
        ktrace_lock();
 
@@ -487,6 +551,18 @@ kperf_sysctl SYSCTL_HANDLER_ARGS
        case REQ_LIGHTWEIGHT_PET:
                ret = sysctl_lightweight_pet(req);
         break;
+       case REQ_LAZY_WAIT_TIME_THRESHOLD:
+               ret = sysctl_lazy_wait_time_threshold(req);
+        break;
+       case REQ_LAZY_WAIT_ACTION:
+               ret = sysctl_lazy_wait_action(req);
+        break;
+       case REQ_LAZY_CPU_TIME_THRESHOLD:
+               ret = sysctl_lazy_cpu_time_threshold(req);
+        break;
+       case REQ_LAZY_CPU_ACTION:
+               ret = sysctl_lazy_cpu_action(req);
+        break;
        default:
                ret = ENOENT;
                break;
@@ -552,7 +628,8 @@ SYSCTL_NODE(_kperf, OID_AUTO, action, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
             "action");
 
 SYSCTL_PROC(_kperf_action, OID_AUTO, count,
-            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
+            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED |
+            CTLFLAG_MASKED,
             (void *)REQ_ACTION_COUNT,
             sizeof(int), kperf_sysctl, "I", "Number of actions");
 
@@ -598,7 +675,8 @@ SYSCTL_NODE(_kperf, OID_AUTO, timer, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
             "timer");
 
 SYSCTL_PROC(_kperf_timer, OID_AUTO, count,
-            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
+            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED
+            | CTLFLAG_MASKED,
             (void *)REQ_TIMER_COUNT,
             sizeof(int), kperf_sysctl, "I", "Number of time triggers");
 
@@ -615,7 +693,8 @@ SYSCTL_PROC(_kperf_timer, OID_AUTO, action,
             "Timer number and actionid");
 
 SYSCTL_PROC(_kperf_timer, OID_AUTO, pet_timer,
-            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
+            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED
+            | CTLFLAG_MASKED,
             (void *)REQ_TIMER_PET,
             sizeof(int), kperf_sysctl, "I", "Which timer ID does PET");
 
@@ -625,7 +704,8 @@ SYSCTL_NODE(_kperf, OID_AUTO, kdebug, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
             "kdebug");
 
 SYSCTL_PROC(_kperf_kdebug, OID_AUTO, action,
-            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
+            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED
+            | CTLFLAG_MASKED,
             (void*)REQ_KDEBUG_ACTION,
             sizeof(int), kperf_sysctl, "I", "ID of action to trigger on kdebug events");
 
@@ -634,10 +714,40 @@ SYSCTL_PROC(_kperf_kdebug, OID_AUTO, filter,
             (void*)REQ_KDEBUG_FILTER,
             sizeof(int), kperf_sysctl, "P", "The filter that determines which kdebug events trigger a sample");
 
+/* lazy sampling */
+
+SYSCTL_NODE(_kperf, OID_AUTO, lazy, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
+            "lazy");
+
+SYSCTL_PROC(_kperf_lazy, OID_AUTO, wait_time_threshold,
+            CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED,
+            (void *)REQ_LAZY_WAIT_TIME_THRESHOLD,
+            sizeof(uint64_t), kperf_sysctl, "UQ",
+            "How many ticks a thread must wait to take a sample");
+
+SYSCTL_PROC(_kperf_lazy, OID_AUTO, wait_action,
+            CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED,
+            (void *)REQ_LAZY_WAIT_ACTION,
+            sizeof(uint64_t), kperf_sysctl, "UQ",
+            "Which action to fire when a thread waits longer than threshold");
+
+SYSCTL_PROC(_kperf_lazy, OID_AUTO, cpu_time_threshold,
+            CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED,
+            (void *)REQ_LAZY_CPU_TIME_THRESHOLD,
+            sizeof(uint64_t), kperf_sysctl, "UQ",
+            "Minimum number of ticks a CPU must run between samples");
+
+SYSCTL_PROC(_kperf_lazy, OID_AUTO, cpu_action,
+            CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED,
+            (void *)REQ_LAZY_CPU_ACTION,
+            sizeof(uint64_t), kperf_sysctl, "UQ",
+            "Which action to fire for lazy CPU samples");
+
 /* misc */
 
 SYSCTL_PROC(_kperf, OID_AUTO, sampling,
-            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
+            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED
+            | CTLFLAG_MASKED,
             (void *)REQ_SAMPLING,
             sizeof(int), kperf_sysctl, "I", "Sampling running");
 
@@ -647,29 +757,34 @@ SYSCTL_PROC(_kperf, OID_AUTO, reset,
             0, kperf_sysctl, "-", "Reset kperf");
 
 SYSCTL_PROC(_kperf, OID_AUTO, blessed_pid,
-            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, /* must be root */
+            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED /* must be root */
+            | CTLFLAG_MASKED,
             (void *)REQ_BLESS,
             sizeof(int), kperf_sysctl_bless_handler, "I", "Blessed pid");
 
 SYSCTL_PROC(_kperf, OID_AUTO, blessed_preempt,
-            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
+            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED |
+            CTLFLAG_MASKED,
             (void *)REQ_BLESS_PREEMPT,
             sizeof(int), kperf_sysctl, "I", "Blessed preemption");
 
 SYSCTL_PROC(_kperf, OID_AUTO, kdbg_cswitch,
-            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
+            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED
+            | CTLFLAG_MASKED,
             (void *)REQ_KDBG_CSWITCH,
             sizeof(int), kperf_sysctl, "I", "Generate context switch info");
 
 SYSCTL_PROC(_kperf, OID_AUTO, pet_idle_rate,
-            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
+            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED
+            | CTLFLAG_MASKED,
             (void *)REQ_PET_IDLE_RATE,
             sizeof(int), kperf_sysctl, "I",
             "Rate at which unscheduled threads are forced to be sampled in "
             "PET mode");
 
 SYSCTL_PROC(_kperf, OID_AUTO, lightweight_pet,
-            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
+            CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED
+            | CTLFLAG_MASKED,
             (void *)REQ_LIGHTWEIGHT_PET,
             sizeof(int), kperf_sysctl, "I",
             "Status of lightweight PET mode");
@@ -679,16 +794,18 @@ SYSCTL_PROC(_kperf, OID_AUTO, lightweight_pet,
 SYSCTL_NODE(_kperf, OID_AUTO, limits, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
             "limits");
 
-#define REQ_LIM_PERIOD_NS (1)
-#define REQ_LIM_BG_PERIOD_NS (2)
-#define REQ_LIM_PET_PERIOD_NS (3)
-#define REQ_LIM_BG_PET_PERIOD_NS (4)
+enum kperf_limit_request {
+       REQ_LIM_PERIOD_NS,
+       REQ_LIM_BG_PERIOD_NS,
+       REQ_LIM_PET_PERIOD_NS,
+       REQ_LIM_BG_PET_PERIOD_NS,
+};
 
 static int
 kperf_sysctl_limits SYSCTL_HANDLER_ARGS
 {
 #pragma unused(oidp, arg2)
-       int type = (int)arg1;
+       enum kperf_limit_request type = (enum kperf_limit_request)arg1;
        uint64_t limit = 0;
 
        switch (type) {