]>
Commit | Line | Data |
---|---|---|
316670eb A |
1 | /* |
2 | * Copyright (c) 2011 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
39037602 | 5 | * |
316670eb A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
39037602 | 14 | * |
316670eb A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
39037602 | 17 | * |
316670eb A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
39037602 | 25 | * |
316670eb A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
28 | ||
29 | /* sysctl interface for paramters from user-land */ | |
30 | ||
39037602 A |
31 | #include <kern/debug.h> |
32 | #include <libkern/libkern.h> | |
33 | #include <pexpert/pexpert.h> | |
316670eb A |
34 | #include <sys/param.h> |
35 | #include <sys/mman.h> | |
36 | #include <sys/stat.h> | |
37 | #include <sys/sysctl.h> | |
39236c6e | 38 | #include <sys/kauth.h> |
316670eb | 39 | |
316670eb | 40 | #include <kperf/action.h> |
39037602 A |
41 | #include <kperf/context.h> |
42 | #include <kperf/kdebug_trigger.h> | |
316670eb | 43 | #include <kperf/kperf.h> |
39037602 A |
44 | #include <kperf/kperfbsd.h> |
45 | #include <kperf/kperf_timer.h> | |
46 | #include <kperf/pet.h> | |
d9a64523 | 47 | #include <kperf/lazy.h> |
316670eb | 48 | |
39037602 | 49 | #include <sys/ktrace.h> |
39236c6e | 50 | |
d9a64523 A |
51 | /* Requests from kperf sysctls. */ |
52 | enum kperf_request { | |
53 | REQ_SAMPLING, | |
54 | REQ_RESET, | |
55 | ||
56 | REQ_ACTION_COUNT, | |
57 | REQ_ACTION_SAMPLERS, | |
58 | REQ_ACTION_USERDATA, | |
59 | REQ_ACTION_FILTER_BY_TASK, | |
60 | REQ_ACTION_FILTER_BY_PID, | |
61 | REQ_ACTION_UCALLSTACK_DEPTH, | |
62 | REQ_ACTION_KCALLSTACK_DEPTH, | |
63 | ||
64 | REQ_TIMER_COUNT, | |
65 | REQ_TIMER_PERIOD, | |
66 | REQ_TIMER_PET, | |
67 | REQ_TIMER_ACTION, | |
68 | ||
69 | REQ_KDBG_CSWITCH, | |
70 | ||
71 | REQ_BLESS, | |
72 | REQ_BLESS_PREEMPT, | |
73 | ||
74 | REQ_PET_IDLE_RATE, | |
75 | REQ_LIGHTWEIGHT_PET, | |
76 | ||
77 | REQ_KDEBUG_FILTER, | |
78 | REQ_KDEBUG_ACTION, | |
79 | ||
80 | REQ_LAZY_WAIT_TIME_THRESHOLD, | |
81 | REQ_LAZY_WAIT_ACTION, | |
82 | REQ_LAZY_CPU_TIME_THRESHOLD, | |
83 | REQ_LAZY_CPU_ACTION, | |
84 | }; | |
39236c6e | 85 | |
39037602 | 86 | int kperf_debug_level = 0; |
39236c6e | 87 | |
39037602 A |
88 | #if DEVELOPMENT || DEBUG |
89 | _Atomic long long kperf_pending_ipis = 0; | |
90 | #endif /* DEVELOPMENT || DEBUG */ | |
fe8ab488 | 91 | |
39037602 | 92 | /* |
d9a64523 | 93 | * kperf has unique requirements from sysctl. |
39037602 A |
94 | * |
95 | * For simple queries like the number of actions, the normal sysctl style | |
96 | * of get/set works well. | |
39236c6e | 97 | * |
39037602 A |
98 | * However, when requesting information about something specific, like an |
99 | * action, user space needs to provide some contextual information. This | |
100 | * information is stored in a uint64_t array that includes the context, like | |
101 | * the action ID it is interested in. If user space is getting the value from | |
102 | * the kernel, then the get side of the sysctl is valid. If it is setting the | |
103 | * value, then the get pointers are left NULL. | |
39236c6e | 104 | * |
39037602 A |
105 | * These functions handle marshalling and unmarshalling data from sysctls. |
106 | */ | |
39236c6e | 107 | |
39037602 A |
108 | static int |
109 | kperf_sysctl_get_set_uint32(struct sysctl_req *req, | |
0a7de745 | 110 | uint32_t (*get)(void), int (*set)(uint32_t)) |
39236c6e | 111 | { |
39037602 A |
112 | assert(req != NULL); |
113 | assert(get != NULL); | |
114 | assert(set != NULL); | |
39236c6e | 115 | |
39037602 A |
116 | uint32_t value = 0; |
117 | if (req->oldptr) { | |
118 | value = get(); | |
119 | } | |
316670eb | 120 | |
39037602 A |
121 | int error = sysctl_io_number(req, value, sizeof(value), &value, NULL); |
122 | ||
123 | if (error || !req->newptr) { | |
124 | return error; | |
125 | } | |
126 | ||
127 | return set(value); | |
128 | } | |
316670eb A |
129 | |
130 | static int | |
39037602 | 131 | kperf_sysctl_get_set_int(struct sysctl_req *req, |
0a7de745 | 132 | int (*get)(void), int (*set)(int)) |
316670eb | 133 | { |
39037602 A |
134 | assert(req != NULL); |
135 | assert(get != NULL); | |
136 | assert(set != NULL); | |
316670eb | 137 | |
39037602 A |
138 | int value = 0; |
139 | if (req->oldptr) { | |
140 | value = get(); | |
141 | } | |
316670eb | 142 | |
39037602 | 143 | int error = sysctl_io_number(req, value, sizeof(value), &value, NULL); |
39236c6e | 144 | |
39037602 A |
145 | if (error || !req->newptr) { |
146 | return error; | |
147 | } | |
148 | ||
149 | return set(value); | |
39236c6e A |
150 | } |
151 | ||
d9a64523 A |
152 | static int |
153 | kperf_sysctl_get_set_uint64(struct sysctl_req *req, | |
0a7de745 | 154 | uint64_t (*get)(void), int (*set)(uint64_t)) |
d9a64523 A |
155 | { |
156 | assert(req != NULL); | |
157 | assert(get != NULL); | |
158 | assert(set != NULL); | |
159 | ||
160 | uint64_t value = 0; | |
161 | if (req->oldptr) { | |
162 | value = get(); | |
163 | } | |
164 | ||
165 | int error = sysctl_io_number(req, value, sizeof(value), &value, NULL); | |
166 | ||
167 | if (error || !req->newptr) { | |
168 | return error; | |
169 | } | |
170 | ||
171 | return set(value); | |
172 | } | |
173 | ||
39236c6e | 174 | static int |
39037602 | 175 | kperf_sysctl_get_set_unsigned_uint32(struct sysctl_req *req, |
0a7de745 | 176 | int (*get)(unsigned int, uint32_t *), int (*set)(unsigned int, uint32_t)) |
39236c6e | 177 | { |
39037602 A |
178 | assert(req != NULL); |
179 | assert(get != NULL); | |
180 | assert(set != NULL); | |
181 | ||
5ba3f43e A |
182 | int error = 0; |
183 | uint64_t inputs[2] = {}; | |
184 | ||
185 | if (req->newptr == USER_ADDR_NULL) { | |
186 | return EFAULT; | |
187 | } | |
188 | ||
189 | if ((error = copyin(req->newptr, inputs, sizeof(inputs)))) { | |
39037602 A |
190 | return error; |
191 | } | |
192 | ||
193 | unsigned int action_id = (unsigned int)inputs[0]; | |
194 | uint32_t new_value = (uint32_t)inputs[1]; | |
316670eb | 195 | |
39037602 A |
196 | if (req->oldptr != USER_ADDR_NULL) { |
197 | uint32_t value_out = 0; | |
198 | if ((error = get(action_id, &value_out))) { | |
199 | return error; | |
200 | } | |
39236c6e | 201 | |
39037602 | 202 | inputs[1] = value_out; |
39236c6e | 203 | |
5ba3f43e | 204 | return copyout(inputs, req->oldptr, sizeof(inputs)); |
39037602 | 205 | } else { |
5ba3f43e | 206 | return set(action_id, new_value); |
39037602 | 207 | } |
316670eb A |
208 | } |
209 | ||
39037602 A |
210 | /* |
211 | * These functions are essentially the same as the generic | |
212 | * kperf_sysctl_get_set_unsigned_uint32, except they have unique input sizes. | |
213 | */ | |
214 | ||
316670eb | 215 | static int |
39037602 | 216 | sysctl_timer_period(struct sysctl_req *req) |
316670eb | 217 | { |
5ba3f43e A |
218 | int error; |
219 | uint64_t inputs[2] = {}; | |
220 | ||
39037602 | 221 | assert(req != NULL); |
316670eb | 222 | |
5ba3f43e A |
223 | if (req->newptr == USER_ADDR_NULL) { |
224 | return EFAULT; | |
225 | } | |
226 | ||
227 | if ((error = copyin(req->newptr, inputs, sizeof(inputs)))) { | |
39037602 A |
228 | return error; |
229 | } | |
230 | ||
231 | unsigned int timer = (unsigned int)inputs[0]; | |
232 | uint64_t new_period = inputs[1]; | |
316670eb | 233 | |
39037602 A |
234 | if (req->oldptr != USER_ADDR_NULL) { |
235 | uint64_t period_out = 0; | |
236 | if ((error = kperf_timer_get_period(timer, &period_out))) { | |
237 | return error; | |
238 | } | |
239 | ||
240 | inputs[1] = period_out; | |
5ba3f43e A |
241 | |
242 | return copyout(inputs, req->oldptr, sizeof(inputs)); | |
39037602 | 243 | } else { |
5ba3f43e | 244 | return kperf_timer_set_period(timer, new_period); |
39037602 | 245 | } |
39236c6e A |
246 | } |
247 | ||
248 | static int | |
5ba3f43e | 249 | sysctl_action_filter(struct sysctl_req *req, bool is_task_t) |
39236c6e | 250 | { |
5ba3f43e A |
251 | int error = 0; |
252 | uint64_t inputs[2] = {}; | |
253 | ||
39037602 A |
254 | assert(req != NULL); |
255 | ||
5ba3f43e A |
256 | if (req->newptr == USER_ADDR_NULL) { |
257 | return EFAULT; | |
258 | } | |
259 | ||
260 | if ((error = copyin(req->newptr, inputs, sizeof(inputs)))) { | |
39037602 A |
261 | return error; |
262 | } | |
263 | ||
264 | unsigned int actionid = (unsigned int)inputs[0]; | |
265 | int new_filter = (int)inputs[1]; | |
39236c6e | 266 | |
39037602 A |
267 | if (req->oldptr != USER_ADDR_NULL) { |
268 | int filter_out; | |
269 | if ((error = kperf_action_get_filter(actionid, &filter_out))) { | |
270 | return error; | |
271 | } | |
272 | ||
273 | inputs[1] = filter_out; | |
5ba3f43e | 274 | return copyout(inputs, req->oldptr, sizeof(inputs)); |
39037602 A |
275 | } else { |
276 | int pid = is_task_t ? kperf_port_to_pid((mach_port_name_t)new_filter) | |
0a7de745 | 277 | : new_filter; |
39236c6e | 278 | |
5ba3f43e | 279 | return kperf_action_set_filter(actionid, pid); |
39037602 | 280 | } |
39236c6e A |
281 | } |
282 | ||
283 | static int | |
39037602 | 284 | sysctl_bless(struct sysctl_req *req) |
39236c6e | 285 | { |
39037602 A |
286 | int value = ktrace_get_owning_pid(); |
287 | int error = sysctl_io_number(req, value, sizeof(value), &value, NULL); | |
39236c6e | 288 | |
39037602 A |
289 | if (error || !req->newptr) { |
290 | return error; | |
291 | } | |
39236c6e | 292 | |
39037602 | 293 | return ktrace_set_owning_pid(value); |
316670eb A |
294 | } |
295 | ||
39037602 A |
296 | /* sysctl handlers that use the generic functions */ |
297 | ||
316670eb | 298 | static int |
39037602 | 299 | sysctl_action_samplers(struct sysctl_req *req) |
316670eb | 300 | { |
39037602 | 301 | return kperf_sysctl_get_set_unsigned_uint32(req, |
0a7de745 | 302 | kperf_action_get_samplers, kperf_action_set_samplers); |
316670eb A |
303 | } |
304 | ||
305 | static int | |
39037602 | 306 | sysctl_action_userdata(struct sysctl_req *req) |
316670eb | 307 | { |
39037602 | 308 | return kperf_sysctl_get_set_unsigned_uint32(req, |
0a7de745 | 309 | kperf_action_get_userdata, kperf_action_set_userdata); |
316670eb A |
310 | } |
311 | ||
312 | static int | |
39037602 | 313 | sysctl_action_ucallstack_depth(struct sysctl_req *req) |
316670eb | 314 | { |
39037602 | 315 | return kperf_sysctl_get_set_unsigned_uint32(req, |
0a7de745 | 316 | kperf_action_get_ucallstack_depth, kperf_action_set_ucallstack_depth); |
316670eb A |
317 | } |
318 | ||
319 | static int | |
39037602 | 320 | sysctl_action_kcallstack_depth(struct sysctl_req *req) |
316670eb | 321 | { |
39037602 | 322 | return kperf_sysctl_get_set_unsigned_uint32(req, |
0a7de745 | 323 | kperf_action_get_kcallstack_depth, kperf_action_set_kcallstack_depth); |
316670eb A |
324 | } |
325 | ||
39236c6e | 326 | static int |
39037602 | 327 | sysctl_kdebug_action(struct sysctl_req *req) |
39236c6e | 328 | { |
39037602 | 329 | return kperf_sysctl_get_set_int(req, kperf_kdebug_get_action, |
0a7de745 | 330 | kperf_kdebug_set_action); |
39236c6e A |
331 | } |
332 | ||
333 | static int | |
39037602 | 334 | sysctl_kdebug_filter(struct sysctl_req *req) |
39236c6e | 335 | { |
39037602 | 336 | assert(req != NULL); |
39236c6e | 337 | |
39037602 A |
338 | if (req->oldptr != USER_ADDR_NULL) { |
339 | struct kperf_kdebug_filter *filter = NULL; | |
340 | uint32_t n_debugids = kperf_kdebug_get_filter(&filter); | |
341 | size_t filter_size = KPERF_KDEBUG_FILTER_SIZE(n_debugids); | |
39236c6e | 342 | |
39037602 A |
343 | if (n_debugids == 0) { |
344 | return EINVAL; | |
345 | } | |
39236c6e | 346 | |
39037602 | 347 | return SYSCTL_OUT(req, filter, filter_size); |
d9a64523 A |
348 | } else if (req->newptr != USER_ADDR_NULL) { |
349 | return kperf_kdebug_set_filter(req->newptr, (uint32_t)req->newlen); | |
350 | } else { | |
351 | return EINVAL; | |
39037602 | 352 | } |
39236c6e A |
353 | } |
354 | ||
39236c6e | 355 | static int |
39037602 | 356 | kperf_sampling_set(uint32_t sample_start) |
39236c6e | 357 | { |
39037602 A |
358 | if (sample_start) { |
359 | return kperf_sampling_enable(); | |
360 | } else { | |
361 | return kperf_sampling_disable(); | |
362 | } | |
39236c6e A |
363 | } |
364 | ||
365 | static int | |
39037602 | 366 | sysctl_sampling(struct sysctl_req *req) |
39236c6e | 367 | { |
39037602 | 368 | return kperf_sysctl_get_set_uint32(req, kperf_sampling_status, |
0a7de745 | 369 | kperf_sampling_set); |
39037602 | 370 | } |
39236c6e | 371 | |
39037602 A |
372 | static int |
373 | sysctl_action_count(struct sysctl_req *req) | |
374 | { | |
375 | return kperf_sysctl_get_set_uint32(req, kperf_action_get_count, | |
0a7de745 | 376 | kperf_action_set_count); |
39037602 | 377 | } |
39236c6e | 378 | |
39037602 A |
379 | static int |
380 | sysctl_timer_count(struct sysctl_req *req) | |
381 | { | |
382 | return kperf_sysctl_get_set_uint32(req, kperf_timer_get_count, | |
0a7de745 | 383 | kperf_timer_set_count); |
39236c6e A |
384 | } |
385 | ||
3e170ce0 | 386 | static int |
39037602 | 387 | sysctl_timer_action(struct sysctl_req *req) |
3e170ce0 | 388 | { |
39037602 | 389 | return kperf_sysctl_get_set_unsigned_uint32(req, kperf_timer_get_action, |
0a7de745 | 390 | kperf_timer_set_action); |
39037602 | 391 | } |
3e170ce0 | 392 | |
39037602 A |
393 | static int |
394 | sysctl_timer_pet(struct sysctl_req *req) | |
395 | { | |
396 | return kperf_sysctl_get_set_uint32(req, kperf_timer_get_petid, | |
0a7de745 | 397 | kperf_timer_set_petid); |
39037602 | 398 | } |
3e170ce0 | 399 | |
39037602 A |
400 | static int |
401 | sysctl_bless_preempt(struct sysctl_req *req) | |
402 | { | |
403 | return sysctl_io_number(req, ktrace_root_set_owner_allowed, | |
0a7de745 A |
404 | sizeof(ktrace_root_set_owner_allowed), |
405 | &ktrace_root_set_owner_allowed, NULL); | |
3e170ce0 A |
406 | } |
407 | ||
408 | static int | |
39037602 | 409 | sysctl_kperf_reset(struct sysctl_req *req) |
3e170ce0 | 410 | { |
39037602 | 411 | int should_reset = 0; |
3e170ce0 | 412 | |
39037602 | 413 | int error = sysctl_io_number(req, should_reset, sizeof(should_reset), |
0a7de745 | 414 | &should_reset, NULL); |
39037602 A |
415 | if (error) { |
416 | return error; | |
417 | } | |
3e170ce0 | 418 | |
39037602 A |
419 | if (should_reset) { |
420 | ktrace_reset(KTRACE_KPERF); | |
421 | } | |
422 | return 0; | |
3e170ce0 A |
423 | } |
424 | ||
425 | static int | |
39037602 | 426 | sysctl_pet_idle_rate(struct sysctl_req *req) |
3e170ce0 | 427 | { |
39037602 | 428 | return kperf_sysctl_get_set_int(req, kperf_get_pet_idle_rate, |
0a7de745 | 429 | kperf_set_pet_idle_rate); |
39037602 | 430 | } |
3e170ce0 | 431 | |
39037602 A |
432 | static int |
433 | sysctl_lightweight_pet(struct sysctl_req *req) | |
434 | { | |
435 | return kperf_sysctl_get_set_int(req, kperf_get_lightweight_pet, | |
0a7de745 | 436 | kperf_set_lightweight_pet); |
39037602 | 437 | } |
3e170ce0 | 438 | |
39037602 A |
439 | static int |
440 | sysctl_kdbg_cswitch(struct sysctl_req *req) | |
441 | { | |
442 | return kperf_sysctl_get_set_int(req, kperf_kdbg_cswitch_get, | |
0a7de745 | 443 | kperf_kdbg_cswitch_set); |
3e170ce0 A |
444 | } |
445 | ||
d9a64523 A |
446 | static int |
447 | sysctl_lazy_wait_time_threshold(struct sysctl_req *req) | |
448 | { | |
449 | return kperf_sysctl_get_set_uint64(req, kperf_lazy_get_wait_time_threshold, | |
0a7de745 | 450 | kperf_lazy_set_wait_time_threshold); |
d9a64523 A |
451 | } |
452 | ||
453 | static int | |
454 | sysctl_lazy_wait_action(struct sysctl_req *req) | |
455 | { | |
456 | return kperf_sysctl_get_set_int(req, kperf_lazy_get_wait_action, | |
0a7de745 | 457 | kperf_lazy_set_wait_action); |
d9a64523 A |
458 | } |
459 | ||
460 | static int | |
461 | sysctl_lazy_cpu_time_threshold(struct sysctl_req *req) | |
462 | { | |
463 | return kperf_sysctl_get_set_uint64(req, kperf_lazy_get_cpu_time_threshold, | |
0a7de745 | 464 | kperf_lazy_set_cpu_time_threshold); |
d9a64523 A |
465 | } |
466 | ||
467 | static int | |
468 | sysctl_lazy_cpu_action(struct sysctl_req *req) | |
469 | { | |
470 | return kperf_sysctl_get_set_int(req, kperf_lazy_get_cpu_action, | |
0a7de745 | 471 | kperf_lazy_set_cpu_action); |
d9a64523 A |
472 | } |
473 | ||
316670eb A |
474 | static int |
475 | kperf_sysctl SYSCTL_HANDLER_ARGS | |
476 | { | |
39037602 | 477 | #pragma unused(oidp, arg2) |
39236c6e | 478 | int ret; |
d9a64523 | 479 | enum kperf_request type = (enum kperf_request)arg1; |
39236c6e | 480 | |
5ba3f43e | 481 | ktrace_lock(); |
39236c6e | 482 | |
39037602 A |
483 | if (req->oldptr == USER_ADDR_NULL && req->newptr != USER_ADDR_NULL) { |
484 | if ((ret = ktrace_configure(KTRACE_KPERF))) { | |
5ba3f43e | 485 | ktrace_unlock(); |
39037602 A |
486 | return ret; |
487 | } | |
488 | } else { | |
489 | if ((ret = ktrace_read_check())) { | |
5ba3f43e | 490 | ktrace_unlock(); |
39037602 A |
491 | return ret; |
492 | } | |
39236c6e A |
493 | } |
494 | ||
316670eb | 495 | /* which request */ |
39037602 | 496 | switch (type) { |
316670eb | 497 | case REQ_ACTION_COUNT: |
39037602 | 498 | ret = sysctl_action_count(req); |
39236c6e | 499 | break; |
316670eb | 500 | case REQ_ACTION_SAMPLERS: |
39037602 | 501 | ret = sysctl_action_samplers(req); |
39236c6e A |
502 | break; |
503 | case REQ_ACTION_USERDATA: | |
39037602 | 504 | ret = sysctl_action_userdata(req); |
39236c6e | 505 | break; |
316670eb | 506 | case REQ_TIMER_COUNT: |
39037602 | 507 | ret = sysctl_timer_count(req); |
39236c6e | 508 | break; |
316670eb | 509 | case REQ_TIMER_PERIOD: |
39037602 | 510 | ret = sysctl_timer_period(req); |
39236c6e | 511 | break; |
316670eb | 512 | case REQ_TIMER_PET: |
39037602 | 513 | ret = sysctl_timer_pet(req); |
39236c6e A |
514 | break; |
515 | case REQ_TIMER_ACTION: | |
39037602 | 516 | ret = sysctl_timer_action(req); |
39236c6e | 517 | break; |
316670eb | 518 | case REQ_SAMPLING: |
39037602 | 519 | ret = sysctl_sampling(req); |
39236c6e | 520 | break; |
3e170ce0 | 521 | case REQ_KDBG_CSWITCH: |
39037602 | 522 | ret = sysctl_kdbg_cswitch(req); |
3e170ce0 | 523 | break; |
39236c6e | 524 | case REQ_ACTION_FILTER_BY_TASK: |
5ba3f43e | 525 | ret = sysctl_action_filter(req, true); |
39236c6e A |
526 | break; |
527 | case REQ_ACTION_FILTER_BY_PID: | |
5ba3f43e | 528 | ret = sysctl_action_filter(req, false); |
39037602 A |
529 | break; |
530 | case REQ_KDEBUG_ACTION: | |
531 | ret = sysctl_kdebug_action(req); | |
532 | break; | |
533 | case REQ_KDEBUG_FILTER: | |
534 | ret = sysctl_kdebug_filter(req); | |
39236c6e A |
535 | break; |
536 | case REQ_PET_IDLE_RATE: | |
39037602 | 537 | ret = sysctl_pet_idle_rate(req); |
39236c6e A |
538 | break; |
539 | case REQ_BLESS_PREEMPT: | |
39037602 A |
540 | ret = sysctl_bless_preempt(req); |
541 | break; | |
542 | case REQ_RESET: | |
543 | ret = sysctl_kperf_reset(req); | |
39236c6e | 544 | break; |
39037602 A |
545 | case REQ_ACTION_UCALLSTACK_DEPTH: |
546 | ret = sysctl_action_ucallstack_depth(req); | |
3e170ce0 | 547 | break; |
39037602 A |
548 | case REQ_ACTION_KCALLSTACK_DEPTH: |
549 | ret = sysctl_action_kcallstack_depth(req); | |
3e170ce0 | 550 | break; |
39037602 A |
551 | case REQ_LIGHTWEIGHT_PET: |
552 | ret = sysctl_lightweight_pet(req); | |
0a7de745 | 553 | break; |
d9a64523 A |
554 | case REQ_LAZY_WAIT_TIME_THRESHOLD: |
555 | ret = sysctl_lazy_wait_time_threshold(req); | |
0a7de745 | 556 | break; |
d9a64523 A |
557 | case REQ_LAZY_WAIT_ACTION: |
558 | ret = sysctl_lazy_wait_action(req); | |
0a7de745 | 559 | break; |
d9a64523 A |
560 | case REQ_LAZY_CPU_TIME_THRESHOLD: |
561 | ret = sysctl_lazy_cpu_time_threshold(req); | |
0a7de745 | 562 | break; |
d9a64523 A |
563 | case REQ_LAZY_CPU_ACTION: |
564 | ret = sysctl_lazy_cpu_action(req); | |
0a7de745 | 565 | break; |
316670eb | 566 | default: |
39236c6e A |
567 | ret = ENOENT; |
568 | break; | |
569 | } | |
570 | ||
5ba3f43e | 571 | ktrace_unlock(); |
39236c6e A |
572 | |
573 | return ret; | |
574 | } | |
575 | ||
576 | static int | |
577 | kperf_sysctl_bless_handler SYSCTL_HANDLER_ARGS | |
578 | { | |
39037602 | 579 | #pragma unused(oidp, arg2) |
39236c6e | 580 | int ret; |
39236c6e | 581 | |
5ba3f43e | 582 | ktrace_lock(); |
39037602 A |
583 | |
584 | /* if setting a new "blessed pid" (ktrace owning pid) */ | |
585 | if (req->newptr != USER_ADDR_NULL) { | |
586 | /* | |
587 | * root can bypass the ktrace check when a flag is set (for | |
588 | * backwards compatibility) or when ownership is maintained over | |
589 | * subsystems resets (to allow the user space process that set | |
590 | * ownership to unset it). | |
591 | */ | |
592 | if (!((ktrace_root_set_owner_allowed || | |
0a7de745 A |
593 | ktrace_keep_ownership_on_reset) && |
594 | kauth_cred_issuser(kauth_cred_get()))) { | |
39037602 | 595 | if ((ret = ktrace_configure(KTRACE_KPERF))) { |
5ba3f43e | 596 | ktrace_unlock(); |
39037602 A |
597 | return ret; |
598 | } | |
599 | } | |
600 | } else { | |
601 | if ((ret = ktrace_read_check())) { | |
5ba3f43e | 602 | ktrace_unlock(); |
39236c6e | 603 | return ret; |
39236c6e A |
604 | } |
605 | } | |
606 | ||
39037602 A |
607 | /* which request */ |
608 | if ((uintptr_t)arg1 == REQ_BLESS) { | |
609 | ret = sysctl_bless(req); | |
610 | } else { | |
611 | ret = ENOENT; | |
316670eb | 612 | } |
39236c6e | 613 | |
5ba3f43e | 614 | ktrace_unlock(); |
fe8ab488 | 615 | |
39037602 | 616 | return ret; |
316670eb A |
617 | } |
618 | ||
619 | /* root kperf node */ | |
39037602 A |
620 | |
621 | SYSCTL_NODE(, OID_AUTO, kperf, CTLFLAG_RW | CTLFLAG_LOCKED, 0, | |
0a7de745 | 622 | "kperf"); |
316670eb | 623 | |
39037602 A |
624 | /* actions */ |
625 | ||
626 | SYSCTL_NODE(_kperf, OID_AUTO, action, CTLFLAG_RW | CTLFLAG_LOCKED, 0, | |
0a7de745 | 627 | "action"); |
316670eb A |
628 | |
629 | SYSCTL_PROC(_kperf_action, OID_AUTO, count, | |
0a7de745 A |
630 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED | |
631 | CTLFLAG_MASKED, | |
632 | (void *)REQ_ACTION_COUNT, | |
633 | sizeof(int), kperf_sysctl, "I", "Number of actions"); | |
316670eb A |
634 | |
635 | SYSCTL_PROC(_kperf_action, OID_AUTO, samplers, | |
0a7de745 A |
636 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
637 | (void *)REQ_ACTION_SAMPLERS, | |
638 | 3 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
639 | "What to sample when a trigger fires an action"); | |
316670eb | 640 | |
39236c6e | 641 | SYSCTL_PROC(_kperf_action, OID_AUTO, userdata, |
0a7de745 A |
642 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
643 | (void *)REQ_ACTION_USERDATA, | |
644 | 3 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
645 | "User data to attribute to action"); | |
39236c6e A |
646 | |
647 | SYSCTL_PROC(_kperf_action, OID_AUTO, filter_by_task, | |
0a7de745 A |
648 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
649 | (void *)REQ_ACTION_FILTER_BY_TASK, | |
650 | 3 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
651 | "Apply a task filter to the action"); | |
39236c6e A |
652 | |
653 | SYSCTL_PROC(_kperf_action, OID_AUTO, filter_by_pid, | |
0a7de745 A |
654 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
655 | (void *)REQ_ACTION_FILTER_BY_PID, | |
656 | 3 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
657 | "Apply a pid filter to the action"); | |
39236c6e | 658 | |
39037602 | 659 | SYSCTL_PROC(_kperf_action, OID_AUTO, ucallstack_depth, |
0a7de745 A |
660 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
661 | (void *)REQ_ACTION_UCALLSTACK_DEPTH, | |
662 | sizeof(int), kperf_sysctl, "I", | |
663 | "Maximum number of frames to include in user callstacks"); | |
39037602 A |
664 | |
665 | SYSCTL_PROC(_kperf_action, OID_AUTO, kcallstack_depth, | |
0a7de745 A |
666 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
667 | (void *)REQ_ACTION_KCALLSTACK_DEPTH, | |
668 | sizeof(int), kperf_sysctl, "I", | |
669 | "Maximum number of frames to include in kernel callstacks"); | |
39037602 A |
670 | |
671 | /* timers */ | |
672 | ||
673 | SYSCTL_NODE(_kperf, OID_AUTO, timer, CTLFLAG_RW | CTLFLAG_LOCKED, 0, | |
0a7de745 | 674 | "timer"); |
316670eb A |
675 | |
676 | SYSCTL_PROC(_kperf_timer, OID_AUTO, count, | |
0a7de745 A |
677 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED |
678 | | CTLFLAG_MASKED, | |
679 | (void *)REQ_TIMER_COUNT, | |
680 | sizeof(int), kperf_sysctl, "I", "Number of time triggers"); | |
316670eb A |
681 | |
682 | SYSCTL_PROC(_kperf_timer, OID_AUTO, period, | |
0a7de745 A |
683 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
684 | (void *)REQ_TIMER_PERIOD, | |
685 | 2 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
686 | "Timer number and period"); | |
316670eb | 687 | |
39236c6e | 688 | SYSCTL_PROC(_kperf_timer, OID_AUTO, action, |
0a7de745 A |
689 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
690 | (void *)REQ_TIMER_ACTION, | |
691 | 2 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
692 | "Timer number and actionid"); | |
39236c6e | 693 | |
316670eb | 694 | SYSCTL_PROC(_kperf_timer, OID_AUTO, pet_timer, |
0a7de745 A |
695 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED |
696 | | CTLFLAG_MASKED, | |
697 | (void *)REQ_TIMER_PET, | |
698 | sizeof(int), kperf_sysctl, "I", "Which timer ID does PET"); | |
316670eb | 699 | |
39037602 A |
700 | /* kdebug trigger */ |
701 | ||
702 | SYSCTL_NODE(_kperf, OID_AUTO, kdebug, CTLFLAG_RW | CTLFLAG_LOCKED, 0, | |
0a7de745 | 703 | "kdebug"); |
39037602 A |
704 | |
705 | SYSCTL_PROC(_kperf_kdebug, OID_AUTO, action, | |
0a7de745 A |
706 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED |
707 | | CTLFLAG_MASKED, | |
708 | (void*)REQ_KDEBUG_ACTION, | |
709 | sizeof(int), kperf_sysctl, "I", "ID of action to trigger on kdebug events"); | |
39037602 A |
710 | |
711 | SYSCTL_PROC(_kperf_kdebug, OID_AUTO, filter, | |
0a7de745 A |
712 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
713 | (void*)REQ_KDEBUG_FILTER, | |
714 | sizeof(int), kperf_sysctl, "P", "The filter that determines which kdebug events trigger a sample"); | |
39037602 | 715 | |
d9a64523 A |
716 | /* lazy sampling */ |
717 | ||
718 | SYSCTL_NODE(_kperf, OID_AUTO, lazy, CTLFLAG_RW | CTLFLAG_LOCKED, 0, | |
0a7de745 | 719 | "lazy"); |
d9a64523 A |
720 | |
721 | SYSCTL_PROC(_kperf_lazy, OID_AUTO, wait_time_threshold, | |
0a7de745 A |
722 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
723 | (void *)REQ_LAZY_WAIT_TIME_THRESHOLD, | |
724 | sizeof(uint64_t), kperf_sysctl, "UQ", | |
725 | "How many ticks a thread must wait to take a sample"); | |
d9a64523 A |
726 | |
727 | SYSCTL_PROC(_kperf_lazy, OID_AUTO, wait_action, | |
0a7de745 A |
728 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
729 | (void *)REQ_LAZY_WAIT_ACTION, | |
730 | sizeof(uint64_t), kperf_sysctl, "UQ", | |
731 | "Which action to fire when a thread waits longer than threshold"); | |
d9a64523 A |
732 | |
733 | SYSCTL_PROC(_kperf_lazy, OID_AUTO, cpu_time_threshold, | |
0a7de745 A |
734 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
735 | (void *)REQ_LAZY_CPU_TIME_THRESHOLD, | |
736 | sizeof(uint64_t), kperf_sysctl, "UQ", | |
737 | "Minimum number of ticks a CPU must run between samples"); | |
d9a64523 A |
738 | |
739 | SYSCTL_PROC(_kperf_lazy, OID_AUTO, cpu_action, | |
0a7de745 A |
740 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
741 | (void *)REQ_LAZY_CPU_ACTION, | |
742 | sizeof(uint64_t), kperf_sysctl, "UQ", | |
743 | "Which action to fire for lazy CPU samples"); | |
d9a64523 | 744 | |
316670eb | 745 | /* misc */ |
39037602 | 746 | |
316670eb | 747 | SYSCTL_PROC(_kperf, OID_AUTO, sampling, |
0a7de745 A |
748 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED |
749 | | CTLFLAG_MASKED, | |
750 | (void *)REQ_SAMPLING, | |
751 | sizeof(int), kperf_sysctl, "I", "Sampling running"); | |
316670eb | 752 | |
39037602 | 753 | SYSCTL_PROC(_kperf, OID_AUTO, reset, |
0a7de745 A |
754 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
755 | (void *)REQ_RESET, | |
756 | 0, kperf_sysctl, "-", "Reset kperf"); | |
39037602 | 757 | |
39236c6e | 758 | SYSCTL_PROC(_kperf, OID_AUTO, blessed_pid, |
0a7de745 A |
759 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED /* must be root */ |
760 | | CTLFLAG_MASKED, | |
761 | (void *)REQ_BLESS, | |
762 | sizeof(int), kperf_sysctl_bless_handler, "I", "Blessed pid"); | |
39236c6e A |
763 | |
764 | SYSCTL_PROC(_kperf, OID_AUTO, blessed_preempt, | |
0a7de745 A |
765 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED | |
766 | CTLFLAG_MASKED, | |
767 | (void *)REQ_BLESS_PREEMPT, | |
768 | sizeof(int), kperf_sysctl, "I", "Blessed preemption"); | |
39236c6e | 769 | |
3e170ce0 | 770 | SYSCTL_PROC(_kperf, OID_AUTO, kdbg_cswitch, |
0a7de745 A |
771 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED |
772 | | CTLFLAG_MASKED, | |
773 | (void *)REQ_KDBG_CSWITCH, | |
774 | sizeof(int), kperf_sysctl, "I", "Generate context switch info"); | |
39236c6e A |
775 | |
776 | SYSCTL_PROC(_kperf, OID_AUTO, pet_idle_rate, | |
0a7de745 A |
777 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED |
778 | | CTLFLAG_MASKED, | |
779 | (void *)REQ_PET_IDLE_RATE, | |
780 | sizeof(int), kperf_sysctl, "I", | |
781 | "Rate at which unscheduled threads are forced to be sampled in " | |
782 | "PET mode"); | |
39037602 A |
783 | |
784 | SYSCTL_PROC(_kperf, OID_AUTO, lightweight_pet, | |
0a7de745 A |
785 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED |
786 | | CTLFLAG_MASKED, | |
787 | (void *)REQ_LIGHTWEIGHT_PET, | |
788 | sizeof(int), kperf_sysctl, "I", | |
789 | "Status of lightweight PET mode"); | |
3e170ce0 | 790 | |
5ba3f43e A |
791 | /* limits */ |
792 | ||
793 | SYSCTL_NODE(_kperf, OID_AUTO, limits, CTLFLAG_RW | CTLFLAG_LOCKED, 0, | |
0a7de745 | 794 | "limits"); |
5ba3f43e | 795 | |
d9a64523 A |
796 | enum kperf_limit_request { |
797 | REQ_LIM_PERIOD_NS, | |
798 | REQ_LIM_BG_PERIOD_NS, | |
799 | REQ_LIM_PET_PERIOD_NS, | |
800 | REQ_LIM_BG_PET_PERIOD_NS, | |
801 | }; | |
5ba3f43e A |
802 | |
803 | static int | |
804 | kperf_sysctl_limits SYSCTL_HANDLER_ARGS | |
805 | { | |
806 | #pragma unused(oidp, arg2) | |
d9a64523 | 807 | enum kperf_limit_request type = (enum kperf_limit_request)arg1; |
5ba3f43e A |
808 | uint64_t limit = 0; |
809 | ||
810 | switch (type) { | |
811 | case REQ_LIM_PERIOD_NS: | |
812 | limit = KP_MIN_PERIOD_NS; | |
813 | break; | |
814 | ||
815 | case REQ_LIM_BG_PERIOD_NS: | |
816 | limit = KP_MIN_PERIOD_BG_NS; | |
817 | break; | |
818 | ||
819 | case REQ_LIM_PET_PERIOD_NS: | |
820 | limit = KP_MIN_PERIOD_PET_NS; | |
821 | break; | |
822 | ||
823 | case REQ_LIM_BG_PET_PERIOD_NS: | |
824 | limit = KP_MIN_PERIOD_PET_BG_NS; | |
825 | break; | |
826 | ||
827 | default: | |
828 | return ENOENT; | |
829 | } | |
830 | ||
831 | return sysctl_io_number(req, limit, sizeof(limit), &limit, NULL); | |
832 | } | |
833 | ||
834 | SYSCTL_PROC(_kperf_limits, OID_AUTO, timer_min_period_ns, | |
0a7de745 A |
835 | CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
836 | (void *)REQ_LIM_PERIOD_NS, sizeof(uint64_t), kperf_sysctl_limits, | |
837 | "Q", "Minimum timer period in nanoseconds"); | |
5ba3f43e | 838 | SYSCTL_PROC(_kperf_limits, OID_AUTO, timer_min_bg_period_ns, |
0a7de745 A |
839 | CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
840 | (void *)REQ_LIM_BG_PERIOD_NS, sizeof(uint64_t), kperf_sysctl_limits, | |
841 | "Q", "Minimum background timer period in nanoseconds"); | |
5ba3f43e | 842 | SYSCTL_PROC(_kperf_limits, OID_AUTO, timer_min_pet_period_ns, |
0a7de745 A |
843 | CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
844 | (void *)REQ_LIM_PET_PERIOD_NS, sizeof(uint64_t), kperf_sysctl_limits, | |
845 | "Q", "Minimum PET timer period in nanoseconds"); | |
5ba3f43e | 846 | SYSCTL_PROC(_kperf_limits, OID_AUTO, timer_min_bg_pet_period_ns, |
0a7de745 A |
847 | CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
848 | (void *)REQ_LIM_BG_PET_PERIOD_NS, sizeof(uint64_t), kperf_sysctl_limits, | |
849 | "Q", "Minimum background PET timer period in nanoseconds"); | |
5ba3f43e | 850 | |
39236c6e | 851 | /* debug */ |
39037602 | 852 | SYSCTL_INT(_kperf, OID_AUTO, debug_level, CTLFLAG_RW | CTLFLAG_LOCKED, |
0a7de745 | 853 | &kperf_debug_level, 0, "debug level"); |
39236c6e | 854 | |
39037602 A |
855 | #if DEVELOPMENT || DEBUG |
856 | SYSCTL_QUAD(_kperf, OID_AUTO, already_pending_ipis, | |
0a7de745 A |
857 | CTLFLAG_RD | CTLFLAG_LOCKED, |
858 | &kperf_pending_ipis, ""); | |
39037602 | 859 | #endif /* DEVELOPMENT || DEBUG */ |