#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;
#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.
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))
}
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
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();
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;
"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");
"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");
"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");
"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");
(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");
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");
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) {