diff options
-rw-r--r-- | driver/Makefile | 8 | ||||
-rw-r--r-- | driver/gator_annotate.c | 49 | ||||
-rw-r--r-- | driver/gator_annotate_kernel.c | 91 | ||||
-rw-r--r-- | driver/gator_backtrace.c | 50 | ||||
-rw-r--r-- | driver/gator_cookies.c | 16 | ||||
-rw-r--r-- | driver/gator_ebs.c | 35 | ||||
-rw-r--r-- | driver/gator_events_armv7.c | 1 | ||||
-rw-r--r-- | driver/gator_main.c | 91 | ||||
-rw-r--r-- | driver/gator_trace_sched.c | 141 |
9 files changed, 367 insertions, 115 deletions
diff --git a/driver/Makefile b/driver/Makefile index de59957..b3981ff 100644 --- a/driver/Makefile +++ b/driver/Makefile @@ -1,5 +1,8 @@ ifneq ($(KERNELRELEASE),) +# Uncomment the following line to enable kernel stack unwinding within gator, or update gator_backtrace.c +# EXTRA_CFLAGS += -DGATOR_KERNEL_STACK_UNWINDING + obj-m := gator.o gator-y := gator_main.o \ @@ -12,8 +15,13 @@ gator-y := gator_main.o \ gator-y += gator_events_mmaped.o ifneq ($(GATOR_WITH_MALI_SUPPORT),) +ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx) +gator-y += gator_events_mali_t6xx.o +else gator-y += gator_events_mali.o endif +EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT) +endif gator-$(CONFIG_ARM) += gator_events_armv6.o \ gator_events_armv7.o \ diff --git a/driver/gator_annotate.c b/driver/gator_annotate.c index e096d15..ee5a160 100644 --- a/driver/gator_annotate.c +++ b/driver/gator_annotate.c @@ -27,27 +27,35 @@ static bool collect_annotations = false; static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset) { char tempBuffer[512]; - int retval, remaining, size; + int remaining, size; + uint32_t tid; if (*offset) return -EINVAL; // determine size to capture - remaining = ANNOTATE_SIZE - annotatePos - 256; // pad for headers and release size = count < sizeof(tempBuffer) ? count : sizeof(tempBuffer); - size = size < remaining ? size : remaining; - if (size <= 0) { - wake_up(&gator_buffer_wait); - return 0; + + // note: copy may be for naught if remaining is zero, but better to do the copy outside of the spinlock + if (file == NULL) { + // copy from kernel + memcpy(tempBuffer, buf, size); + + // set the thread id to the kernel thread, not the current thread + tid = -1; + } else { + // copy from user space + if (copy_from_user(tempBuffer, buf, size) != 0) + return -EINVAL; + tid = current->pid; } - // copy from user space - retval = copy_from_user(tempBuffer, buf, size); - if (retval == 0) { - // synchronize shared variables annotateBuf and annotatePos - spin_lock(&annotate_lock); - if (collect_annotations && annotateBuf) { - uint32_t tid = current->pid; + // synchronize shared variables annotateBuf and annotatePos + spin_lock(&annotate_lock); + if (collect_annotations && annotateBuf) { + remaining = ANNOTATE_SIZE - annotatePos - 256; // pad for headers and release + size = size < remaining ? size : remaining; + if (size > 0) { uint64_t time = gator_get_time(); uint32_t cpuid = smp_processor_id(); int pos = annotatePos; @@ -58,17 +66,20 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t memcpy(&annotateBuf[pos], tempBuffer, size); annotatePos = pos + size; } - spin_unlock(&annotate_lock); + } + spin_unlock(&annotate_lock); - // return the number of bytes written - retval = size; - } else { - retval = -EINVAL; + if (size <= 0) { + wake_up(&gator_buffer_wait); + return 0; } - return retval; + // return the number of bytes written + return size; } +#include "gator_annotate_kernel.c" + static int annotate_release(struct inode *inode, struct file *file) { int remaining = ANNOTATE_SIZE - annotatePos; diff --git a/driver/gator_annotate_kernel.c b/driver/gator_annotate_kernel.c new file mode 100644 index 0000000..4f690e8 --- /dev/null +++ b/driver/gator_annotate_kernel.c @@ -0,0 +1,91 @@ +/** + * Copyright (C) ARM Limited 2011. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +static void kannotate_write(char* ptr, unsigned int size) +{ + int retval; + int pos = 0; + loff_t offset = 0; + while (pos < size) { + retval = annotate_write(NULL, &ptr[pos], size - pos, &offset); + if (retval < 0) { + printk(KERN_WARNING "gator: kannotate_write failed with return value %d\n", retval); + return; + } + pos += retval; + } +} + +// String annotation +void gator_annotate(char* string) +{ + printk(KERN_ERR "module: %s\n", string); + kannotate_write(string, strlen(string) + 1); +} +EXPORT_SYMBOL(gator_annotate); + +// String annotation with color +void gator_annotate_color(int color, char* string) +{ + kannotate_write((char*)&color, sizeof(color)); + kannotate_write(string, strlen(string) + 1); +} +EXPORT_SYMBOL(gator_annotate_color); + +// Terminate an annotation +void gator_annotate_end(void) +{ + char nul = 0; + kannotate_write(&nul, sizeof(nul)); +} +EXPORT_SYMBOL(gator_annotate_end); + +// Image annotation with optional string +void gator_annotate_visual(char* data, unsigned int length, char* string) +{ + long long visual_annotation = 0x011c | (strlen(string) << 16) | ((long long)length << 32); + kannotate_write((char*)&visual_annotation, 8); + kannotate_write(string, strlen(string)); + kannotate_write(data, length); +} +EXPORT_SYMBOL(gator_annotate_visual); + +// Marker annotation +void gator_annotate_marker(void) +{ + int marker_annotation = 0x00021c; + kannotate_write((char*)&marker_annotation, 3); +} +EXPORT_SYMBOL(gator_annotate_marker); + +// Marker annotation with a string +void gator_annotate_marker_str(char* string) +{ + int marker_annotation = 0x021c; + kannotate_write((char*)&marker_annotation, 2); + kannotate_write(string, strlen(string) + 1); +} +EXPORT_SYMBOL(gator_annotate_marker_str); + +// Marker annotation with a color +void gator_annotate_marker_color(int color) +{ + long long marker_annotation = (0x021c | ((long long)color << 16)) & 0x0000ffffffffffffLL; + kannotate_write((char*)&marker_annotation, 7); +} +EXPORT_SYMBOL(gator_annotate_marker_color); + +// Marker annotationw ith a string and color +void gator_annotate_marker_color_str(int color, char* string) +{ + long long marker_annotation = 0x021c | ((long long)color << 16); + kannotate_write((char*)&marker_annotation, 6); + kannotate_write(string, strlen(string) + 1); +} +EXPORT_SYMBOL(gator_annotate_marker_color_str); diff --git a/driver/gator_backtrace.c b/driver/gator_backtrace.c index b5b0e63..fc81233 100644 --- a/driver/gator_backtrace.c +++ b/driver/gator_backtrace.c @@ -23,6 +23,7 @@ static void arm_backtrace_eabi(int cpu, int buftype, struct pt_regs * const regs struct frame_tail_eabi *ptrtail; struct frame_tail_eabi buftail; unsigned long fp = regs->ARM_fp; + unsigned long sp = regs->ARM_sp; unsigned long lr = regs->ARM_lr; int is_user_mode = user_mode(regs); @@ -34,7 +35,7 @@ static void arm_backtrace_eabi(int cpu, int buftype, struct pt_regs * const regs gator_add_trace(cpu, buftype, lr); /* check tail is valid */ - if (fp == 0) { + if (fp == 0 || fp < sp) { return; } @@ -66,3 +67,50 @@ static void arm_backtrace_eabi(int cpu, int buftype, struct pt_regs * const regs } #endif } + +#if defined(__arm__) +static DEFINE_PER_CPU(int, backtrace_buffer); +static int report_trace(struct stackframe *frame, void *d) +{ + struct module *mod; + unsigned int *depth = d, addr = frame->pc, cookie = NO_COOKIE, cpu = smp_processor_id(); + + if (*depth) { + mod = __module_address(addr); + if (mod) { + cookie = get_cookie(cpu, per_cpu(backtrace_buffer, cpu), current, NULL, mod, true); + addr = addr - (unsigned long)mod->module_core; + } + gator_buffer_write_packed_int(cpu, per_cpu(backtrace_buffer, cpu), addr & ~1); + gator_buffer_write_packed_int(cpu, per_cpu(backtrace_buffer, cpu), cookie); + (*depth)--; + } + + return *depth == 0; +} +#endif + +// Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile +// #define GATOR_KERNEL_STACK_UNWINDING +static void kernel_backtrace(int cpu, int buftype, struct pt_regs * const regs) +{ +#if defined(__arm__) +#ifdef GATOR_KERNEL_STACK_UNWINDING + int depth = gator_backtrace_depth; +#else + int depth = 1; +#endif + struct stackframe frame; + if (depth == 0) + depth = 1; + frame.fp = regs->ARM_fp; + frame.sp = regs->ARM_sp; + frame.lr = regs->ARM_lr; + frame.pc = regs->ARM_pc; + per_cpu(backtrace_buffer, cpu) = buftype; + walk_stackframe(&frame, report_trace, &depth); +#else + gator_buffer_write_packed_int(cpu, buftype, PC_REG & ~1); + gator_buffer_write_packed_int(cpu, buftype, NO_COOKIE); +#endif +} diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c index a646fb2..c0c4b9c 100644 --- a/driver/gator_cookies.c +++ b/driver/gator_cookies.c @@ -122,12 +122,18 @@ static void wq_cookie_handler(struct work_struct *unused) int cpu = smp_processor_id(); unsigned int cookie, commit; - commit = per_cpu(translate_buffer_write, cpu); - while (per_cpu(translate_buffer_read, cpu) != commit) { - task = (struct task_struct *)translate_buffer_read_int(cpu); - vma = (struct vm_area_struct *)translate_buffer_read_int(cpu); - cookie = get_cookie(cpu, TIMER_BUF, task, vma, NULL, false); + mutex_lock(&start_mutex); + + if (gator_started != 0) { + commit = per_cpu(translate_buffer_write, cpu); + while (per_cpu(translate_buffer_read, cpu) != commit) { + task = (struct task_struct *)translate_buffer_read_int(cpu); + vma = (struct vm_area_struct *)translate_buffer_read_int(cpu); + cookie = get_cookie(cpu, TIMER_BUF, task, vma, NULL, false); + } } + + mutex_unlock(&start_mutex); } // Retrieve full name from proc/pid/cmdline for java processes on Android diff --git a/driver/gator_ebs.c b/driver/gator_ebs.c index 9b55347..8b4b5ff 100644 --- a/driver/gator_ebs.c +++ b/driver/gator_ebs.c @@ -95,16 +95,19 @@ static int gator_event_sampling_start(void) int irq, i; if (IS_ERR(pmu_device)) { - pr_err("gator: event based sampling is not supported as the kernel function reserve_pmu() failed"); + pr_err("gator: event based sampling is not supported as the kernel function reserve_pmu() failed\n"); return -1; } - init_pmu(ARM_PMU_DEVICE_CPU); + // init_pmu sets the irq affinity, therefore we do not care if it fails for single core + if (init_pmu(ARM_PMU_DEVICE_CPU) != 0 && gator_cpu_cores > 1) { + pr_err("gator: unable to initialize the pmu\n"); + goto out_ebs_start; + } + if (pmu_device->num_resources == 0) { pr_err("gator: no irqs for PMUs defined\n"); - release_pmu(pmu_device); - pmu_device = NULL; - return -1; + goto out_ebs_start; } for (i = 0; i < pmu_device->num_resources; ++i) { @@ -121,9 +124,7 @@ static int gator_event_sampling_start(void) if (irq >= 0) free_irq(irq, NULL); } - release_pmu(pmu_device); - pmu_device = NULL; - return -1; + goto out_ebs_start; } } } @@ -135,6 +136,17 @@ static int gator_event_sampling_start(void) #endif return 0; + +#if LINUX_PMU_SUPPORT +out_ebs_start: +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) + release_pmu(pmu_device); +#else + release_pmu(ARM_PMU_DEVICE_CPU); +#endif + pmu_device = NULL; + return -1; +#endif } static void gator_event_sampling_stop(void) @@ -148,8 +160,13 @@ static void gator_event_sampling_stop(void) free_irq(irq, NULL); } } - if (!IS_ERR(pmu_device)) + if (!IS_ERR(pmu_device)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) release_pmu(pmu_device); +#else + release_pmu(ARM_PMU_DEVICE_CPU); +#endif + } pmu_device = NULL; #endif } diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c index 58855f8..e1434e2 100644 --- a/driver/gator_events_armv7.c +++ b/driver/gator_events_armv7.c @@ -204,6 +204,7 @@ static void gator_events_armv7_online(void) static void gator_events_armv7_offline(void) { + // disbale all counters, including PMCCNTR; overflow IRQs will not be signaled armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); } diff --git a/driver/gator_main.c b/driver/gator_main.c index 91744ad..36e951b 100644 --- a/driver/gator_main.c +++ b/driver/gator_main.c @@ -7,7 +7,7 @@ * */ -static unsigned long gator_protocol_version = 6; +static unsigned long gator_protocol_version = 7; #include <linux/slab.h> #include <linux/cpu.h> @@ -17,6 +17,8 @@ static unsigned long gator_protocol_version = 6; #include <linux/hardirq.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/suspend.h> +#include <asm/stacktrace.h> #include <asm/uaccess.h> #include "gator.h" @@ -51,7 +53,7 @@ static unsigned long gator_protocol_version = 6; /****************************************************************************** * DEFINES ******************************************************************************/ -#define TIMER_BUFFER_SIZE_DEFAULT (256*1024) +#define TIMER_BUFFER_SIZE_DEFAULT (512*1024) #define EVENT_BUFFER_SIZE_DEFAULT (128*1024) #define NO_COOKIE 0UL @@ -267,11 +269,12 @@ static void gator_add_trace(int cpu, int buftype, unsigned int address) static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs) { - struct module *mod; - unsigned int addr, cookie = 0; int inKernel = regs ? !user_mode(regs) : 1; unsigned long exec_cookie = inKernel ? NO_COOKIE : get_exec_cookie(cpu, buftype, current); + if (!regs) + return; + gator_buffer_write_packed_int(cpu, buftype, MESSAGE_START_BACKTRACE); gator_buffer_write_packed_int64(cpu, buftype, gator_get_time()); gator_buffer_write_packed_int(cpu, buftype, exec_cookie); @@ -279,25 +282,15 @@ static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs) gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->pid); gator_buffer_write_packed_int(cpu, buftype, inKernel); - // get_irq_regs() will return NULL outside of IRQ context (e.g. nested IRQ) - if (regs) { - if (inKernel) { - addr = PC_REG; - mod = __module_address(addr); - if (mod) { - cookie = get_cookie(cpu, buftype, current, NULL, mod, true); - addr = addr - (unsigned long)mod->module_core; - } - gator_buffer_write_packed_int(cpu, buftype, addr & ~1); - gator_buffer_write_packed_int(cpu, buftype, cookie); - } else { - // Cookie+PC - gator_add_trace(cpu, buftype, PC_REG); - - // Backtrace - if (gator_backtrace_depth) - arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth); - } + if (inKernel) { + kernel_backtrace(cpu, buftype, regs); + } else { + // Cookie+PC + gator_add_trace(cpu, buftype, PC_REG); + + // Backtrace + if (gator_backtrace_depth) + arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth); } gator_buffer_write_packed_int(cpu, buftype, MESSAGE_END_BACKTRACE); @@ -352,11 +345,12 @@ static void gator_timer_interrupt(void) } } else if (gi->read64) { len = gi->read64(&buffer64); - if (len > 0) + if (len > 0) { gator_buffer_write_packed_int(cpu, buftype, len); for (i = 0; i < len; i++) { gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]); } + } } } gator_buffer_write_packed_int(cpu, buftype, 0); @@ -460,29 +454,28 @@ static uint64_t gator_get_time(void) struct timespec ts; uint64_t timestamp; - ktime_get_ts(&ts); + getnstimeofday(&ts); timestamp = timespec_to_ns(&ts); return timestamp; } /****************************************************************************** - * cpu online notifier + * cpu online and pm notifiers ******************************************************************************/ -static int __cpuinit gator_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) +static int __cpuinit gator_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { long cpu = (long)hcpu; switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - smp_call_function_single(cpu, __gator_timer_online, NULL, 1); - break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: smp_call_function_single(cpu, __gator_timer_offline, NULL, 1); break; + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + smp_call_function_single(cpu, __gator_timer_online, NULL, 1); + break; } return NOTIFY_OK; @@ -492,13 +485,45 @@ static struct notifier_block __refdata gator_cpu_notifier = { .notifier_call = gator_cpu_notify, }; +// n.b. calling "on_each_cpu" only runs on those that are online +// Registered linux events are not disabled, so their counters will continue to collect +static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) +{ + switch (event) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + unregister_hotcpu_notifier(&gator_cpu_notifier); + unregister_scheduler_tracepoints(); + on_each_cpu(trace_sched_insert_idle, NULL, 1); + on_each_cpu(__gator_timer_offline, NULL, 1); + break; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + on_each_cpu(__gator_timer_online, NULL, 1); + register_scheduler_tracepoints(); + register_hotcpu_notifier(&gator_cpu_notifier); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block gator_pm_notifier = { + .notifier_call = gator_pm_notify, +}; + static int gator_notifier_start(void) { - return register_hotcpu_notifier(&gator_cpu_notifier); + int retval; + retval = register_hotcpu_notifier(&gator_cpu_notifier); + if (retval == 0) + retval = register_pm_notifier(&gator_pm_notifier); + return retval; } static void gator_notifier_stop(void) { + unregister_pm_notifier(&gator_pm_notifier); unregister_hotcpu_notifier(&gator_cpu_notifier); } diff --git a/driver/gator_trace_sched.c b/driver/gator_trace_sched.c index 7c0bd47..0225bfb 100644 --- a/driver/gator_trace_sched.c +++ b/driver/gator_trace_sched.c @@ -14,13 +14,6 @@ #define SCHED_SWITCH 1 #define SCHED_PROCESS_FREE 2 -#define FIELD_TYPE 0 -#define FIELD_TIME 1 -#define FIELD_PARAM1 2 -#define FIELD_PARAM2 3 -#define FIELD_PARAM3 4 -#define FIELDS_PER_SCHED 5 - #define SCHEDSIZE (8*1024) #define TASK_MAP_ENTRIES 1024 /* must be power of 2 */ #define TASK_MAX_COLLISIONS 2 @@ -31,7 +24,13 @@ static DEFINE_PER_CPU(int, theSchedPos); static DEFINE_PER_CPU(int, theSchedErr); static DEFINE_PER_CPU(uint64_t *, taskname_keys); -void emit_pid_name(uint64_t time, struct task_struct* task) +enum { + STATE_CONTENTION = 0, + STATE_WAIT_ON_IO, + STATE_WAIT_ON_OTHER +}; + +void emit_pid_name(struct task_struct* task) { bool found = false; unsigned long flags; @@ -68,55 +67,92 @@ void emit_pid_name(uint64_t time, struct task_struct* task) // disable interrupts to synchronize with hrtimer populating timer buf local_irq_save(flags); gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_PID_NAME); - gator_buffer_write_packed_int64(cpu, TIMER_BUF, time); + gator_buffer_write_packed_int64(cpu, TIMER_BUF, gator_get_time()); gator_buffer_write_packed_int(cpu, TIMER_BUF, task->pid); gator_buffer_write_string(cpu, TIMER_BUF, taskcomm); local_irq_restore(flags); } } -static void probe_sched_write(int type, int param1, int param2, int param3) +static void probe_sched_write(int type, struct task_struct* task, struct task_struct* old_task) { + int schedPos, cookie = 0, state = 0; unsigned long flags; + uint64_t *schedBuf, time; int cpu = smp_processor_id(); - uint64_t time = gator_get_time(); - uint64_t *schedBuf; - int schedPos, cookie = param3; + int pid = task->pid; + int tgid = task->tgid; if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)]) return; - if (param3) { + if (type == SCHED_SWITCH) { // do as much work as possible before disabling interrupts - struct task_struct *task = (struct task_struct *)param3; cookie = get_exec_cookie(cpu, TIMER_BUF, task); - emit_pid_name(time, task); + emit_pid_name(task); + if (old_task->state == 0) + state = STATE_CONTENTION; + else if (old_task->in_iowait) + state = STATE_WAIT_ON_IO; + else + state = STATE_WAIT_ON_OTHER; } // disable interrupts to synchronize with gator_trace_sched_read(); spinlocks not needed since percpu buffers are used local_irq_save(flags); + time = gator_get_time(); schedPos = per_cpu(theSchedPos, cpu); schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)]; - if (schedPos < (SCHEDSIZE-100)) { + if (schedPos < (SCHEDSIZE - 100)) { // capture - schedBuf[schedPos+FIELD_TYPE] = type; - schedBuf[schedPos+FIELD_TIME] = time; - schedBuf[schedPos+FIELD_PARAM1] = param1; - schedBuf[schedPos+FIELD_PARAM2] = param2; - schedBuf[schedPos+FIELD_PARAM3] = cookie; - per_cpu(theSchedPos, cpu) = schedPos + FIELDS_PER_SCHED; + schedBuf[schedPos++] = type; + schedBuf[schedPos++] = time; + schedBuf[schedPos++] = pid; + schedBuf[schedPos++] = tgid; + schedBuf[schedPos++] = cookie; + schedBuf[schedPos++] = state; } else if (!per_cpu(theSchedErr, cpu)) { per_cpu(theSchedErr, cpu) = 1; - schedBuf[schedPos+FIELD_TYPE] = SCHED_OVERFLOW; - schedBuf[schedPos+FIELD_TIME] = time; - schedBuf[schedPos+FIELD_PARAM1] = 0; - schedBuf[schedPos+FIELD_PARAM2] = 0; - schedBuf[schedPos+FIELD_PARAM3] = 0; - per_cpu(theSchedPos, cpu) = schedPos + FIELDS_PER_SCHED; + schedBuf[schedPos++] = SCHED_OVERFLOW; + schedBuf[schedPos++] = time; + schedBuf[schedPos++] = 0; + schedBuf[schedPos++] = 0; + schedBuf[schedPos++] = 0; + schedBuf[schedPos++] = 0; pr_debug("gator: tracepoint overflow\n"); } + per_cpu(theSchedPos, cpu) = schedPos; + local_irq_restore(flags); +} + +// special case used during a suspend of the system +static void trace_sched_insert_idle(void* unused) +{ + unsigned long flags; + uint64_t *schedBuf; + int schedPos, cpu = smp_processor_id(); + + if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)]) + return; + + local_irq_save(flags); + + schedPos = per_cpu(theSchedPos, cpu); + schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)]; + + if (schedPos < (SCHEDSIZE - (6 * 8))) { + // capture + schedBuf[schedPos++] = SCHED_SWITCH; + schedBuf[schedPos++] = gator_get_time(); + schedBuf[schedPos++] = 0; // idle pid is zero + schedBuf[schedPos++] = 0; // idle tid is zero + schedBuf[schedPos++] = 0; // idle cookie is zero + schedBuf[schedPos++] = STATE_WAIT_ON_OTHER; + } + + per_cpu(theSchedPos, cpu) = schedPos; local_irq_restore(flags); } @@ -126,12 +162,12 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *pre GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next)) #endif { - probe_sched_write(SCHED_SWITCH, next->pid, next->tgid, (int)next); + probe_sched_write(SCHED_SWITCH, next, prev); } GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p)) { - probe_sched_write(SCHED_PROCESS_FREE, p->pid, 0, 0); + probe_sched_write(SCHED_PROCESS_FREE, p, 0); } int gator_trace_sched_init(void) @@ -139,6 +175,25 @@ int gator_trace_sched_init(void) return 0; } +static int register_scheduler_tracepoints(void) { + // register tracepoints + if (GATOR_REGISTER_TRACE(sched_switch)) + goto fail_sched_switch; + if (GATOR_REGISTER_TRACE(sched_process_free)) + goto fail_sched_process_free; + pr_debug("gator: registered tracepoints\n"); + + return 0; + + // unregister tracepoints on error +fail_sched_process_free: + GATOR_UNREGISTER_TRACE(sched_switch); +fail_sched_switch: + pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); + + return -1; +} + int gator_trace_sched_start(void) { int cpu, size; @@ -159,30 +214,20 @@ int gator_trace_sched_start(void) memset(per_cpu(taskname_keys, cpu), 0, size); } - // register tracepoints - if (GATOR_REGISTER_TRACE(sched_switch)) - goto fail_sched_switch; - if (GATOR_REGISTER_TRACE(sched_process_free)) - goto fail_sched_process_free; - pr_debug("gator: registered tracepoints\n"); - - return 0; + return register_scheduler_tracepoints(); +} - // unregister tracepoints on error -fail_sched_process_free: +static void unregister_scheduler_tracepoints(void) +{ GATOR_UNREGISTER_TRACE(sched_switch); -fail_sched_switch: - pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); - - return -1; + GATOR_UNREGISTER_TRACE(sched_process_free); + pr_debug("gator: unregistered tracepoints\n"); } void gator_trace_sched_stop(void) { int cpu; - GATOR_UNREGISTER_TRACE(sched_switch); - GATOR_UNREGISTER_TRACE(sched_process_free); - pr_debug("gator: unregistered tracepoints\n"); + unregister_scheduler_tracepoints(); for_each_present_cpu(cpu) { kfree(per_cpu(theSchedBuf, cpu)[0]); |