aboutsummaryrefslogtreecommitdiff
path: root/driver/gator_trace_sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/gator_trace_sched.c')
-rw-r--r--driver/gator_trace_sched.c228
1 files changed, 93 insertions, 135 deletions
diff --git a/driver/gator_trace_sched.c b/driver/gator_trace_sched.c
index 19d8d89..7c0bd47 100644
--- a/driver/gator_trace_sched.c
+++ b/driver/gator_trace_sched.c
@@ -10,36 +10,89 @@
#include <trace/events/sched.h>
#include "gator.h"
-#define SCHED_TIMER_EVENT 0
-#define SCHED_WAIT_TASK 1
-#define SCHED_WAKEUP 2
-#define SCHED_WAKEUP_NEW 3
-#define SCHED_SWITCH 4
-#define SCHED_MIGRATE_TASK 5
-#define SCHED_PROCESS_FREE 6
-#define SCHED_PROCESS_EXIT 7
-#define SCHED_PROCESS_WAIT 8
-#define SCHED_PROCESS_FORK 9
#define SCHED_OVERFLOW -1
+#define SCHED_SWITCH 1
+#define SCHED_PROCESS_FREE 2
-#define SCHEDSIZE (16*1024)
+#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
-static DEFINE_PER_CPU(int *[2], theSchedBuf);
+#define SCHEDSIZE (8*1024)
+#define TASK_MAP_ENTRIES 1024 /* must be power of 2 */
+#define TASK_MAX_COLLISIONS 2
+
+static DEFINE_PER_CPU(uint64_t *[2], theSchedBuf);
static DEFINE_PER_CPU(int, theSchedSel);
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)
+{
+ bool found = false;
+ unsigned long flags;
+ char taskcomm[TASK_COMM_LEN + 3];
+ int x, cpu = smp_processor_id();
+ uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]);
+ uint64_t value;
+
+ value = gator_chksum_crc32(task->comm);
+ value = (value << 32) | (uint32_t)task->pid;
+
+ // determine if the thread name was emitted already
+ for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
+ if (keys[x] == value) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ // shift values, new value always in front
+ uint64_t oldv, newv = value;
+ for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
+ oldv = keys[x];
+ keys[x] = newv;
+ newv = oldv;
+ }
+
+ // emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions
+ if (strlcpy(taskcomm, task->comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1)
+ // append ellipses if task->comm has length of TASK_COMM_LEN - 1
+ strcat(taskcomm, "...");
+
+ // 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_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)
{
unsigned long flags;
int cpu = smp_processor_id();
uint64_t time = gator_get_time();
- int *schedBuf;
- int schedPos;
+ uint64_t *schedBuf;
+ int schedPos, cookie = param3;
if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
return;
+ if (param3) {
+ // 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);
+ }
+
// disable interrupts to synchronize with gator_trace_sched_read(); spinlocks not needed since percpu buffers are used
local_irq_save(flags);
@@ -48,88 +101,37 @@ static void probe_sched_write(int type, int param1, int param2, int param3)
if (schedPos < (SCHEDSIZE-100)) {
// capture
- schedBuf[schedPos+0] = type;
- schedBuf[schedPos+1] = (int)time;
- schedBuf[schedPos+2] = (int)(time >> 32);
- schedBuf[schedPos+3] = param1;
- schedBuf[schedPos+4] = param2;
- schedBuf[schedPos+5] = param3;
- per_cpu(theSchedPos, cpu) = schedPos + 6;
+ 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;
} else if (!per_cpu(theSchedErr, cpu)) {
per_cpu(theSchedErr, cpu) = 1;
- schedBuf[schedPos+0] = SCHED_OVERFLOW;
- schedBuf[schedPos+1] = 0;
- schedBuf[schedPos+2] = 0;
- schedBuf[schedPos+3] = 0;
- schedBuf[schedPos+4] = 0;
- schedBuf[schedPos+5] = 0;
- per_cpu(theSchedPos, cpu) = schedPos + 6;
+ 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;
pr_debug("gator: tracepoint overflow\n");
}
local_irq_restore(flags);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-GATOR_DEFINE_PROBE(sched_wait_task, TP_PROTO(struct rq *rq, struct task_struct *p))
-#else
-GATOR_DEFINE_PROBE(sched_wait_task, TP_PROTO(struct task_struct *p))
-#endif
-{
- probe_sched_write(SCHED_WAIT_TASK, 0, p->pid, 0);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-GATOR_DEFINE_PROBE(sched_wakeup, TP_PROTO(struct rq *rq, struct task_struct *p, int success))
-#else
-GATOR_DEFINE_PROBE(sched_wakeup, TP_PROTO(struct task_struct *p, int success))
-#endif
-{
- if (success)
- probe_sched_write(SCHED_WAKEUP, 0, p->pid, 0);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-GATOR_DEFINE_PROBE(sched_wakeup_new, TP_PROTO(struct rq *rq, struct task_struct *p, int success))
-#else
-GATOR_DEFINE_PROBE(sched_wakeup_new, TP_PROTO(struct task_struct *p, int success))
-#endif
-{
- if (success)
- probe_sched_write(SCHED_WAKEUP_NEW, 0, p->tgid, p->pid);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
#else
GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
#endif
{
- probe_sched_write(SCHED_SWITCH, (int)next, next->tgid, next->pid);
-}
-
-GATOR_DEFINE_PROBE(sched_migrate_task, TP_PROTO(struct task_struct *p, int dest_cpu))
-{
- probe_sched_write(SCHED_MIGRATE_TASK, 0, dest_cpu, p->pid);
+ probe_sched_write(SCHED_SWITCH, next->pid, next->tgid, (int)next);
}
GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
{
- probe_sched_write(SCHED_PROCESS_FREE, 0, p->pid, 0);
-}
-
-GATOR_DEFINE_PROBE(sched_process_exit, TP_PROTO(struct task_struct *p))
-{
- probe_sched_write(SCHED_PROCESS_EXIT, 0, p->pid, 0);
-}
-
-GATOR_DEFINE_PROBE(sched_process_wait, TP_PROTO(struct pid *pid))
-{
- probe_sched_write(SCHED_PROCESS_WAIT, 0, pid_nr(pid), 0);
-}
-
-GATOR_DEFINE_PROBE(sched_process_fork, TP_PROTO(struct task_struct *parent, struct task_struct *child))
-{
- probe_sched_write(SCHED_PROCESS_FORK, (int)child, parent->pid, child->pid);
+ probe_sched_write(SCHED_PROCESS_FREE, p->pid, 0, 0);
}
int gator_trace_sched_init(void)
@@ -139,59 +141,37 @@ int gator_trace_sched_init(void)
int gator_trace_sched_start(void)
{
- int cpu;
+ int cpu, size;
for_each_present_cpu(cpu) {
per_cpu(theSchedSel, cpu) = 0;
per_cpu(theSchedPos, cpu) = 0;
per_cpu(theSchedErr, cpu) = 0;
- per_cpu(theSchedBuf, cpu)[0] = kmalloc(SCHEDSIZE * sizeof(int), GFP_KERNEL);
- per_cpu(theSchedBuf, cpu)[1] = kmalloc(SCHEDSIZE * sizeof(int), GFP_KERNEL);
+ per_cpu(theSchedBuf, cpu)[0] = kmalloc(SCHEDSIZE * sizeof(uint64_t), GFP_KERNEL);
+ per_cpu(theSchedBuf, cpu)[1] = kmalloc(SCHEDSIZE * sizeof(uint64_t), GFP_KERNEL);
if (!per_cpu(theSchedBuf, cpu))
return -1;
+
+ size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t);
+ per_cpu(taskname_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL);
+ if (!per_cpu(taskname_keys, cpu))
+ return -1;
+ memset(per_cpu(taskname_keys, cpu), 0, size);
}
// register tracepoints
- if (GATOR_REGISTER_TRACE(sched_wait_task))
- goto fail_sched_wait_task;
- if (GATOR_REGISTER_TRACE(sched_wakeup))
- goto fail_sched_wakeup;
- if (GATOR_REGISTER_TRACE(sched_wakeup_new))
- goto fail_sched_wakeup_new;
if (GATOR_REGISTER_TRACE(sched_switch))
goto fail_sched_switch;
- if (GATOR_REGISTER_TRACE(sched_migrate_task))
- goto fail_sched_migrate_task;
if (GATOR_REGISTER_TRACE(sched_process_free))
goto fail_sched_process_free;
- if (GATOR_REGISTER_TRACE(sched_process_exit))
- goto fail_sched_process_exit;
- if (GATOR_REGISTER_TRACE(sched_process_wait))
- goto fail_sched_process_wait;
- if (GATOR_REGISTER_TRACE(sched_process_fork))
- goto fail_sched_process_fork;
pr_debug("gator: registered tracepoints\n");
return 0;
// unregister tracepoints on error
-fail_sched_process_fork:
- GATOR_UNREGISTER_TRACE(sched_process_wait);
-fail_sched_process_wait:
- GATOR_UNREGISTER_TRACE(sched_process_exit);
-fail_sched_process_exit:
- GATOR_UNREGISTER_TRACE(sched_process_free);
fail_sched_process_free:
- GATOR_UNREGISTER_TRACE(sched_migrate_task);
-fail_sched_migrate_task:
GATOR_UNREGISTER_TRACE(sched_switch);
fail_sched_switch:
- GATOR_UNREGISTER_TRACE(sched_wakeup_new);
-fail_sched_wakeup_new:
- GATOR_UNREGISTER_TRACE(sched_wakeup);
-fail_sched_wakeup:
- GATOR_UNREGISTER_TRACE(sched_wait_task);
-fail_sched_wait_task:
pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
return -1;
@@ -200,15 +180,8 @@ fail_sched_wait_task:
void gator_trace_sched_stop(void)
{
int cpu;
- GATOR_UNREGISTER_TRACE(sched_wait_task);
- GATOR_UNREGISTER_TRACE(sched_wakeup);
- GATOR_UNREGISTER_TRACE(sched_wakeup_new);
GATOR_UNREGISTER_TRACE(sched_switch);
- GATOR_UNREGISTER_TRACE(sched_migrate_task);
GATOR_UNREGISTER_TRACE(sched_process_free);
- GATOR_UNREGISTER_TRACE(sched_process_exit);
- GATOR_UNREGISTER_TRACE(sched_process_wait);
- GATOR_UNREGISTER_TRACE(sched_process_fork);
pr_debug("gator: unregistered tracepoints\n");
for_each_present_cpu(cpu) {
@@ -216,17 +189,16 @@ void gator_trace_sched_stop(void)
kfree(per_cpu(theSchedBuf, cpu)[1]);
per_cpu(theSchedBuf, cpu)[0] = NULL;
per_cpu(theSchedBuf, cpu)[1] = NULL;
+ kfree(per_cpu(taskname_keys, cpu));
}
}
-int gator_trace_sched_read(int **buffer)
+int gator_trace_sched_read(long long **buffer)
{
- uint64_t time = gator_get_time();
int cpu = smp_processor_id();
unsigned long flags;
- int *schedBuf;
+ uint64_t *schedBuf;
int schedPos;
- int i;
if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
return 0;
@@ -242,20 +214,6 @@ int gator_trace_sched_read(int **buffer)
local_irq_restore(flags);
- // find mm and replace with cookies
- for (i = 0; i < schedPos; i += 6) {
- uint32_t cookie = schedBuf[i+3];
- if (cookie) {
- struct task_struct *task = (struct task_struct *)cookie;
- schedBuf[i+3] = get_exec_cookie(cpu, task);
- }
- }
-
- // timer/end event
- schedBuf[schedPos++] = SCHED_TIMER_EVENT;
- schedBuf[schedPos++] = (int)time;
- schedBuf[schedPos++] = (int)(time >> 32);
-
if (buffer)
*buffer = schedBuf;