* Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
- *
+ *
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#include <kern/thread.h>
#include <sys/errno.h>
#include <sys/vm.h>
+#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <vm/vm_pageout.h>
#define ACTION_MAX (32)
/* the list of different actions to take */
-struct action
-{
+struct action {
uint32_t sample;
uint32_t ucallstack_depth;
uint32_t kcallstack_depth;
};
/* the list of actions */
-static unsigned actionc = 0;
+static unsigned int actionc = 0;
static struct action *actionv = NULL;
/* should emit tracepoint on context switch */
int kperf_kdebug_cswitch = 0;
bool
-kperf_sample_has_non_system(unsigned actionid)
+kperf_action_has_non_system(unsigned int actionid)
{
if (actionid > actionc) {
return false;
}
}
+bool
+kperf_action_has_task(unsigned int actionid)
+{
+ if (actionid > actionc) {
+ return false;
+ }
+
+ return actionv[actionid - 1].sample & SAMPLER_TASK_MASK;
+}
+
+bool
+kperf_action_has_thread(unsigned int actionid)
+{
+ if (actionid > actionc) {
+ return false;
+ }
+
+ return actionv[actionid - 1].sample & SAMPLER_THREAD_MASK;
+}
+
static void
kperf_system_memory_log(void)
{
BUF_DATA(PERF_MI_SYS_DATA, (uintptr_t)vm_page_free_count,
- (uintptr_t)vm_page_wire_count, (uintptr_t)vm_page_external_count,
- (uintptr_t)(vm_page_active_count + vm_page_inactive_count +
- vm_page_speculative_count));
+ (uintptr_t)vm_page_wire_count, (uintptr_t)vm_page_external_count,
+ (uintptr_t)(vm_page_active_count + vm_page_inactive_count +
+ vm_page_speculative_count));
+ BUF_DATA(PERF_MI_SYS_DATA_2, (uintptr_t)vm_page_anonymous_count,
+ (uintptr_t)vm_page_internal_count,
+ (uintptr_t)vm_pageout_vminfo.vm_pageout_compressions,
+ (uintptr_t)VM_PAGE_COMPRESSOR_COUNT);
}
static kern_return_t
kperf_sample_internal(struct kperf_sample *sbuf,
- struct kperf_context *context,
- unsigned sample_what, unsigned sample_flags,
- unsigned actionid, uint32_t ucallstack_depth)
+ struct kperf_context *context,
+ unsigned sample_what, unsigned sample_flags,
+ unsigned actionid, uint32_t ucallstack_depth)
{
int pended_ucallstack = 0;
int pended_th_dispatch = 0;
bool on_idle_thread = false;
uint32_t userdata = actionid;
+ bool task_only = false;
/* not much point continuing here, but what to do ? return
* Shutdown? cut a tracepoint and continue?
sample_what &= SAMPLER_SYS_MEM;
}
- context->cur_thread->kperf_pet_gen = kperf_pet_gen;
- boolean_t is_kernel = (context->cur_pid == 0);
+ assert((sample_flags & (SAMPLE_FLAG_THREAD_ONLY | SAMPLE_FLAG_TASK_ONLY))
+ != (SAMPLE_FLAG_THREAD_ONLY | SAMPLE_FLAG_TASK_ONLY));
+ if (sample_flags & SAMPLE_FLAG_THREAD_ONLY) {
+ sample_what &= SAMPLER_THREAD_MASK;
+ }
+ if (sample_flags & SAMPLE_FLAG_TASK_ONLY) {
+ task_only = true;
+ sample_what &= SAMPLER_TASK_MASK;
+ }
+
+ if (!task_only) {
+ context->cur_thread->kperf_pet_gen = kperf_pet_gen;
+ }
+ bool is_kernel = (context->cur_pid == 0);
if (actionid && actionid <= actionc) {
sbuf->kcallstack.nframes = actionv[actionid - 1].kcallstack_depth;
if (sample_what & SAMPLER_KSTACK) {
if (sample_flags & SAMPLE_FLAG_CONTINUATION) {
kperf_continuation_sample(&(sbuf->kcallstack), context);
- /* outside of interrupt context, backtrace the current thread */
+ /* outside of interrupt context, backtrace the current thread */
} else if (sample_flags & SAMPLE_FLAG_NON_INTERRUPT) {
kperf_backtrace_sample(&(sbuf->kcallstack), context);
} else {
}
}
if (sample_what & SAMPLER_TK_SNAPSHOT) {
- kperf_task_snapshot_sample(&(sbuf->tk_snapshot), context);
+ kperf_task_snapshot_sample(context->cur_task, &(sbuf->tk_snapshot));
}
/* sensitive ones */
if (!is_kernel) {
if (sample_what & SAMPLER_MEMINFO) {
- kperf_meminfo_sample(&(sbuf->meminfo), context);
+ kperf_meminfo_sample(context->cur_task, &(sbuf->meminfo));
}
if (sample_flags & SAMPLE_FLAG_PEND_USER) {
/* avoid logging if this sample only pended samples */
if (sample_flags & SAMPLE_FLAG_PEND_USER &&
- !(sample_what & ~(SAMPLER_USTACK | SAMPLER_TH_DISPATCH)))
- {
+ !(sample_what & ~(SAMPLER_USTACK | SAMPLER_TH_DISPATCH))) {
return SAMPLE_CONTINUE;
}
boolean_t enabled = ml_set_interrupts_enabled(FALSE);
BUF_DATA(PERF_GEN_EVENT | DBG_FUNC_START, sample_what,
- actionid, userdata, sample_flags);
+ actionid, userdata, sample_flags);
if (sample_flags & SAMPLE_FLAG_SYSTEM) {
if (sample_what & SAMPLER_SYS_MEM) {
if (sample_what & SAMPLER_TK_SNAPSHOT) {
kperf_task_snapshot_log(&(sbuf->tk_snapshot));
}
+ if (sample_what & SAMPLER_TK_INFO) {
+ kperf_task_info_log(context);
+ }
/* dump user stuff */
if (!is_kernel) {
/* Translate actionid into sample bits and take a sample */
kern_return_t
kperf_sample(struct kperf_sample *sbuf,
- struct kperf_context *context,
- unsigned actionid, unsigned sample_flags)
+ struct kperf_context *context,
+ unsigned actionid, unsigned sample_flags)
{
/* work out what to sample, if anything */
if ((actionid > actionc) || (actionid == 0)) {
/* do the actual sample operation */
return kperf_sample_internal(sbuf, context, sample_what,
- sample_flags, actionid,
- actionv[actionid - 1].ucallstack_depth);
+ sample_flags, actionid,
+ actionv[actionid - 1].ucallstack_depth);
}
void
kperf_kdebug_handler(uint32_t debugid, uintptr_t *starting_fp)
{
uint32_t sample_flags = SAMPLE_FLAG_PEND_USER;
- struct kperf_context ctx;
struct kperf_sample *sample = NULL;
kern_return_t kr = KERN_SUCCESS;
int s;
BUF_VERB(PERF_KDBG_HNDLR | DBG_FUNC_START, debugid);
- ctx.cur_thread = current_thread();
- ctx.cur_pid = task_pid(get_threadtask(ctx.cur_thread));
- ctx.trigger_type = TRIGGER_TYPE_KDEBUG;
- ctx.trigger_id = 0;
+ thread_t thread = current_thread();
+ task_t task = get_threadtask(thread);
+ struct kperf_context ctx = {
+ .cur_thread = thread,
+ .cur_task = task,
+ .cur_pid = task_pid(task),
+ .trigger_type = TRIGGER_TYPE_KDEBUG,
+ .trigger_id = 0,
+ };
s = ml_set_interrupts_enabled(0);
}
/* make a context, take a sample */
- struct kperf_context ctx;
- ctx.cur_thread = thread;
- ctx.cur_pid = task_pid(task);
+ struct kperf_context ctx = {
+ .cur_thread = thread,
+ .cur_task = task,
+ .cur_pid = task_pid(task),
+ };
/* decode the flags to determine what to sample */
unsigned int sample_what = 0;