aboutsummaryrefslogtreecommitdiff
path: root/drivers/gator/gator_trace_sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gator/gator_trace_sched.c')
-rw-r--r--drivers/gator/gator_trace_sched.c104
1 files changed, 64 insertions, 40 deletions
diff --git a/drivers/gator/gator_trace_sched.c b/drivers/gator/gator_trace_sched.c
index 655008628933..6d7cbd7348e1 100644
--- a/drivers/gator/gator_trace_sched.c
+++ b/drivers/gator/gator_trace_sched.c
@@ -8,6 +8,10 @@
*/
#include <trace/events/sched.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+#include <trace/events/task.h>
+#endif
+
#include "gator.h"
#define TASK_MAP_ENTRIES 1024 /* must be power of 2 */
@@ -23,8 +27,10 @@ enum {
static DEFINE_PER_CPU(uint64_t *, taskname_keys);
static DEFINE_PER_CPU(int, collecting);
-// this array is never read as the cpu wait charts are derived counters
-// the files are needed, nonetheless, to show that these counters are available
+/* this array is never read as the cpu wait charts are derived
+ * counters the files are needed, nonetheless, to show that these
+ * counters are available
+ */
static ulong cpu_wait_enabled[CPU_WAIT_TOTAL];
static ulong sched_cpu_key[CPU_WAIT_TOTAL];
@@ -32,26 +38,24 @@ static int sched_trace_create_files(struct super_block *sb, struct dentry *root)
{
struct dentry *dir;
- // CPU Wait - Contention
+ /* CPU Wait - Contention */
dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_contention");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_CONTENTION]);
gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_CONTENTION]);
- // CPU Wait - I/O
+ /* CPU Wait - I/O */
dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_io");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_WAIT_ON_IO]);
gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_WAIT_ON_IO]);
return 0;
}
-static void emit_pid_name(struct task_struct *task)
+static void emit_pid_name(const char *comm, struct task_struct *task)
{
bool found = false;
char taskcomm[TASK_COMM_LEN + 3];
@@ -59,10 +63,10 @@ static void emit_pid_name(struct task_struct *task)
uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]);
uint64_t value;
- value = gator_chksum_crc32(task->comm);
+ value = gator_chksum_crc32(comm);
value = (value << 32) | (uint32_t)task->pid;
- // determine if the thread name was emitted already
+ /* determine if the thread name was emitted already */
for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
if (keys[x] == value) {
found = true;
@@ -71,17 +75,18 @@ static void emit_pid_name(struct task_struct *task)
}
if (!found) {
- // shift values, new value always in front
+ /* 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
+ /* emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions */
+ if (strlcpy(taskcomm, comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1) {
+ /* append ellipses if comm has length of TASK_COMM_LEN - 1 */
strcat(taskcomm, "...");
}
@@ -89,7 +94,7 @@ static void emit_pid_name(struct task_struct *task)
}
}
-static void collect_counters(u64 time, struct task_struct *task)
+static void collect_counters(u64 time, struct task_struct *task, bool sched_switch)
{
int *buffer, len, cpu = get_physical_cpu();
long long *buffer64;
@@ -98,7 +103,7 @@ static void collect_counters(u64 time, struct task_struct *task)
if (marshal_event_header(time)) {
list_for_each_entry(gi, &gator_events, list) {
if (gi->read) {
- len = gi->read(&buffer);
+ len = gi->read(&buffer, sched_switch);
marshal_event(len, buffer);
} else if (gi->read64) {
len = gi->read64(&buffer64);
@@ -109,22 +114,26 @@ static void collect_counters(u64 time, struct task_struct *task)
marshal_event64(len, buffer64);
}
}
- // Only check after writing all counters so that time and corresponding counters appear in the same frame
+ if (cpu == 0)
+ gator_emit_perf_time(time);
+ /* Only check after writing all counters so that time and corresponding counters appear in the same frame */
buffer_check(cpu, BLOCK_COUNTER_BUF, time);
- // Commit buffers on timeout
+ /* Commit buffers on timeout */
if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) {
static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF, ACTIVITY_BUF };
int i;
- for (i = 0; i < ARRAY_SIZE(buftypes); ++i) {
+ for (i = 0; i < ARRAY_SIZE(buftypes); ++i)
gator_commit_buffer(cpu, buftypes[i], time);
- }
- // spinlocks are noops on uniprocessor machines and mutexes do not work in sched_switch context in
- // RT-Preempt full, so disable proactive flushing of the annotate frame on uniprocessor machines.
+ /* spinlocks are noops on uniprocessor machines and mutexes do
+ * not work in sched_switch context in RT-Preempt full, so
+ * disable proactive flushing of the annotate frame on
+ * uniprocessor machines.
+ */
#ifdef CONFIG_SMP
- // Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full
+ /* Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full */
if (on_primary_core() && spin_trylock(&annotate_lock)) {
gator_commit_buffer(0, ANNOTATE_BUF, time);
spin_unlock(&annotate_lock);
@@ -134,7 +143,7 @@ static void collect_counters(u64 time, struct task_struct *task)
}
}
-// special case used during a suspend of the system
+/* special case used during a suspend of the system */
static void trace_sched_insert_idle(void)
{
marshal_sched_trace_switch(0, 0);
@@ -146,7 +155,7 @@ static void gator_trace_emit_link(struct task_struct *p)
int cpu = get_physical_cpu();
cookie = get_exec_cookie(cpu, p);
- emit_pid_name(p);
+ emit_pid_name(p->comm, p);
marshal_link(cookie, p->tgid, p->pid);
}
@@ -161,6 +170,15 @@ GATOR_DEFINE_PROBE(sched_process_exec, TP_PROTO(struct task_struct *p, pid_t old
{
gator_trace_emit_link(p);
}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)
+GATOR_DEFINE_PROBE(task_rename, TP_PROTO(struct task_struct *task, char *comm))
+#else
+GATOR_DEFINE_PROBE(task_rename, TP_PROTO(struct task_struct *task, const char *comm))
+#endif
+{
+ emit_pid_name(comm, task);
+}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
@@ -174,17 +192,16 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_
per_cpu(in_scheduler_context, cpu) = true;
- // do as much work as possible before disabling interrupts
- if (prev->state == TASK_RUNNING) {
+ /* do as much work as possible before disabling interrupts */
+ if (prev->state == TASK_RUNNING)
state = STATE_CONTENTION;
- } else if (prev->in_iowait) {
+ else if (prev->in_iowait)
state = STATE_WAIT_ON_IO;
- } else {
+ else
state = STATE_WAIT_ON_OTHER;
- }
per_cpu(collecting, cpu) = 1;
- collect_counters(gator_get_time(), prev);
+ collect_counters(gator_get_time(), prev, true);
per_cpu(collecting, cpu) = 0;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
@@ -202,18 +219,20 @@ GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
static void do_nothing(void *info)
{
- // Intentionally do nothing
+ /* Intentionally do nothing */
(void)info;
}
static int register_scheduler_tracepoints(void)
{
- // register tracepoints
+ /* register tracepoints */
if (GATOR_REGISTER_TRACE(sched_process_fork))
goto fail_sched_process_fork;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
if (GATOR_REGISTER_TRACE(sched_process_exec))
goto fail_sched_process_exec;
+ if (GATOR_REGISTER_TRACE(task_rename))
+ goto fail_task_rename;
#endif
if (GATOR_REGISTER_TRACE(sched_switch))
goto fail_sched_switch;
@@ -221,21 +240,24 @@ static int register_scheduler_tracepoints(void)
goto fail_sched_process_free;
pr_debug("gator: registered tracepoints\n");
- // Now that the scheduler tracepoint is registered, force a context switch
- // on all cpus to capture what is currently running.
+ /* Now that the scheduler tracepoint is registered, force a context
+ * switch on all cpus to capture what is currently running.
+ */
on_each_cpu(do_nothing, NULL, 0);
return 0;
- // unregister tracepoints on error
+ /* unregister tracepoints on error */
fail_sched_process_free:
GATOR_UNREGISTER_TRACE(sched_switch);
fail_sched_switch:
- GATOR_UNREGISTER_TRACE(sched_process_fork);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
-fail_sched_process_exec:
+ GATOR_UNREGISTER_TRACE(task_rename);
+fail_task_rename:
GATOR_UNREGISTER_TRACE(sched_process_exec);
+fail_sched_process_exec:
#endif
+ GATOR_UNREGISTER_TRACE(sched_process_fork);
fail_sched_process_fork:
pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
@@ -247,6 +269,7 @@ static void unregister_scheduler_tracepoints(void)
GATOR_UNREGISTER_TRACE(sched_process_fork);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
GATOR_UNREGISTER_TRACE(sched_process_exec);
+ GATOR_UNREGISTER_TRACE(task_rename);
#endif
GATOR_UNREGISTER_TRACE(sched_switch);
GATOR_UNREGISTER_TRACE(sched_process_free);
@@ -271,7 +294,7 @@ static int gator_trace_sched_start(void)
for_each_present_cpu(cpu) {
size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t);
- per_cpu(taskname_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL);
+ per_cpu(taskname_keys, cpu) = kmalloc(size, GFP_KERNEL);
if (!per_cpu(taskname_keys, cpu))
return -1;
memset(per_cpu(taskname_keys, cpu), 0, size);
@@ -290,6 +313,7 @@ static void gator_trace_sched_offline(void)
static void gator_trace_sched_init(void)
{
int i;
+
for (i = 0; i < CPU_WAIT_TOTAL; i++) {
cpu_wait_enabled[i] = 0;
sched_cpu_key[i] = gator_events_get_key();