diff options
Diffstat (limited to 'driver/gator_trace_sched.c')
-rw-r--r-- | driver/gator_trace_sched.c | 228 |
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; |