index dafacb754167936ee740b142b0c16982abc528a7..08b027094853f4f0454089eb1ff185255dc5e22e 100644 (file)
#include <trace/events/sched.h>
#include "gator.h"
-#define SCHED_OVERFLOW -1
#define SCHED_SWITCH 1
-#define SCHED_PROCESS_FREE 2
+#define SCHED_PROCESS_EXIT 2
-#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);
enum {
- STATE_CONTENTION = 0,
+ STATE_WAIT_ON_OTHER = 0,
+ STATE_CONTENTION,
STATE_WAIT_ON_IO,
- STATE_WAIT_ON_OTHER
+ STATE_WAIT_ON_MUTEX,
};
-int gator_trace_sched_read(long long **buffer);
-
void emit_pid_name(struct task_struct* task)
{
bool found = false;
- unsigned long flags;
char taskcomm[TASK_COMM_LEN + 3];
- int x, cpu = smp_processor_id();
+ unsigned long x, cpu = smp_processor_id();
uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]);
uint64_t value;
}
}
- if (!found && buffer_check_space(cpu, TIMER_BUF, TASK_COMM_LEN + 2 * MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
+ if (!found) {
// shift values, new value always in front
uint64_t oldv, newv = value;
for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
}
// 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)
+ 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, 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);
+ marshal_pid_name(task->pid, taskcomm);
+ }
+}
+
+
+static void collect_counters(void)
+{
+ int *buffer, len;
+ long long *buffer64;
+ struct gator_interface *gi;
+
+ if (marshal_event_header()) {
+ list_for_each_entry(gi, &gator_events, list) {
+ if (gi->read) {
+ len = gi->read(&buffer);
+ marshal_event(len, buffer);
+ } else if (gi->read64) {
+ len = gi->read64(&buffer64);
+ marshal_event64(len, buffer64);
+ }
+ }
}
}
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 cookie = 0, state = 0;
int cpu = smp_processor_id();
int pid = task->pid;
int tgid = task->tgid;
- if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
- return;
-
if (type == SCHED_SWITCH) {
// do as much work as possible before disabling interrupts
- cookie = get_exec_cookie(cpu, TIMER_BUF, task);
+ cookie = get_exec_cookie(cpu, BACKTRACE_BUF, task);
emit_pid_name(task);
- if (old_task->state == 0)
+ if (old_task->state == TASK_RUNNING) {
state = STATE_CONTENTION;
- else if (old_task->in_iowait)
+ } else if (old_task->in_iowait) {
state = STATE_WAIT_ON_IO;
- else
+#ifdef CONFIG_DEBUG_MUTEXES
+ } else if (old_task->blocked_on) {
+ state = STATE_WAIT_ON_MUTEX;
+#endif
+ } 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)) {
- // capture
- 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++] = SCHED_OVERFLOW;
- schedBuf[schedPos++] = time;
- schedBuf[schedPos++] = 0;
- schedBuf[schedPos++] = 0;
- schedBuf[schedPos++] = 0;
- schedBuf[schedPos++] = 0;
- pr_debug("gator: tracepoint overflow\n");
+ collect_counters();
}
- per_cpu(theSchedPos, cpu) = schedPos;
- local_irq_restore(flags);
+
+ // marshal_sched_trace() disables interrupts as the free may trigger while switch is writing to the buffer; disabling preemption is not sufficient
+ // is disable interrupts necessary now that exit is used instead of free?
+ marshal_sched_trace(type, pid, tgid, cookie, state);
}
// special case used during a suspend of the system
static void trace_sched_insert_idle(void)
{
- 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);
+ marshal_sched_trace(SCHED_SWITCH, 0, 0, 0, 0);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
@@ -167,23 +129,23 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_
probe_sched_write(SCHED_SWITCH, next, prev);
}
-GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
+GATOR_DEFINE_PROBE(sched_process_exit, TP_PROTO(struct task_struct *p))
{
- probe_sched_write(SCHED_PROCESS_FREE, p, 0);
+ probe_sched_write(SCHED_PROCESS_EXIT, p, 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;
+ if (GATOR_REGISTER_TRACE(sched_process_exit))
+ goto fail_sched_process_exit;
pr_debug("gator: registered tracepoints\n");
return 0;
// unregister tracepoints on error
-fail_sched_process_free:
+fail_sched_process_exit:
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");
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(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 register_scheduler_tracepoints();
}
-int gator_trace_sched_offline(long long **buffer)
+void gator_trace_sched_offline(void)
{
trace_sched_insert_idle();
- return gator_trace_sched_read(buffer);
}
static void unregister_scheduler_tracepoints(void)
{
GATOR_UNREGISTER_TRACE(sched_switch);
- GATOR_UNREGISTER_TRACE(sched_process_free);
+ GATOR_UNREGISTER_TRACE(sched_process_exit);
pr_debug("gator: unregistered tracepoints\n");
}
unregister_scheduler_tracepoints();
for_each_present_cpu(cpu) {
- kfree(per_cpu(theSchedBuf, cpu)[0]);
- 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(long long **buffer)
-{
- int cpu = smp_processor_id();
- unsigned long flags;
- uint64_t *schedBuf;
- int schedPos;
-
- if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
- return 0;
-
- local_irq_save(flags);
-
- schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
- schedPos = per_cpu(theSchedPos, cpu);
-
- per_cpu(theSchedSel, cpu) = !per_cpu(theSchedSel, cpu);
- per_cpu(theSchedPos, cpu) = 0;
- per_cpu(theSchedErr, cpu) = 0;
-
- local_irq_restore(flags);
-
- if (buffer)
- *buffer = schedBuf;
-
- return schedPos;
-}