aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--driver/Makefile8
-rw-r--r--driver/gator_annotate.c49
-rw-r--r--driver/gator_annotate_kernel.c91
-rw-r--r--driver/gator_backtrace.c50
-rw-r--r--driver/gator_cookies.c16
-rw-r--r--driver/gator_ebs.c35
-rw-r--r--driver/gator_events_armv7.c1
-rw-r--r--driver/gator_main.c91
-rw-r--r--driver/gator_trace_sched.c141
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]);