2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
10 #include <trace/events/sched.h>
13 #define TASK_MAP_ENTRIES 1024 /* must be power of 2 */
14 #define TASK_MAX_COLLISIONS 2
17 STATE_WAIT_ON_OTHER = 0,
23 static DEFINE_PER_CPU(uint64_t *, taskname_keys);
24 static DEFINE_PER_CPU(int, collecting);
26 // this array is never read as the cpu wait charts are derived counters
27 // the files are needed, nonetheless, to show that these counters are available
28 static ulong cpu_wait_enabled[CPU_WAIT_TOTAL];
29 static ulong sched_cpu_key[CPU_WAIT_TOTAL];
31 static int sched_trace_create_files(struct super_block *sb, struct dentry *root)
35 // CPU Wait - Contention
36 dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_contention");
40 gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_CONTENTION]);
41 gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_CONTENTION]);
44 dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_io");
48 gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_WAIT_ON_IO]);
49 gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_WAIT_ON_IO]);
54 void emit_pid_name(struct task_struct *task)
57 char taskcomm[TASK_COMM_LEN + 3];
58 unsigned long x, cpu = get_physical_cpu();
59 uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]);
62 value = gator_chksum_crc32(task->comm);
63 value = (value << 32) | (uint32_t)task->pid;
65 // determine if the thread name was emitted already
66 for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
67 if (keys[x] == value) {
74 // shift values, new value always in front
75 uint64_t oldv, newv = value;
76 for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
82 // emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions
83 if (strlcpy(taskcomm, task->comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1) {
84 // append ellipses if task->comm has length of TASK_COMM_LEN - 1
85 strcat(taskcomm, "...");
88 marshal_thread_name(task->pid, taskcomm);
92 static void collect_counters(u64 time)
94 int *buffer, len, cpu = get_physical_cpu();
96 struct gator_interface *gi;
98 if (marshal_event_header(time)) {
99 list_for_each_entry(gi, &gator_events, list) {
101 len = gi->read(&buffer);
102 marshal_event(len, buffer);
103 } else if (gi->read64) {
104 len = gi->read64(&buffer64);
105 marshal_event64(len, buffer64);
108 // Only check after writing all counters so that time and corresponding counters appear in the same frame
109 buffer_check(cpu, BLOCK_COUNTER_BUF, time);
111 // Commit buffers on timeout
112 if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) {
113 static const int buftypes[] = { COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF };
115 for (i = 0; i < ARRAY_SIZE(buftypes); ++i) {
116 gator_commit_buffer(cpu, buftypes[i], time);
118 // Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full
119 if (on_primary_core() && spin_trylock(&annotate_lock)) {
120 gator_commit_buffer(0, ANNOTATE_BUF, time);
121 spin_unlock(&annotate_lock);
127 // special case used during a suspend of the system
128 static void trace_sched_insert_idle(void)
130 marshal_sched_trace_switch(0, 0, 0, 0);
133 GATOR_DEFINE_PROBE(sched_process_fork, TP_PROTO(struct task_struct *parent, struct task_struct *child))
136 int cpu = get_physical_cpu();
138 cookie = get_exec_cookie(cpu, child);
139 emit_pid_name(child);
141 marshal_sched_trace_start(child->tgid, child->pid, cookie);
144 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
145 GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
147 GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
152 int cpu = get_physical_cpu();
154 // do as much work as possible before disabling interrupts
155 cookie = get_exec_cookie(cpu, next);
157 if (prev->state == TASK_RUNNING) {
158 state = STATE_CONTENTION;
159 } else if (prev->in_iowait) {
160 state = STATE_WAIT_ON_IO;
162 state = STATE_WAIT_ON_OTHER;
165 per_cpu(collecting, cpu) = 1;
166 collect_counters(gator_get_time());
167 per_cpu(collecting, cpu) = 0;
169 marshal_sched_trace_switch(next->tgid, next->pid, cookie, state);
172 GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
174 marshal_sched_trace_exit(p->tgid, p->pid);
177 static void do_nothing(void *info)
179 // Intentionally do nothing
183 static int register_scheduler_tracepoints(void)
185 // register tracepoints
186 if (GATOR_REGISTER_TRACE(sched_process_fork))
187 goto fail_sched_process_fork;
188 if (GATOR_REGISTER_TRACE(sched_switch))
189 goto fail_sched_switch;
190 if (GATOR_REGISTER_TRACE(sched_process_free))
191 goto fail_sched_process_free;
192 pr_debug("gator: registered tracepoints\n");
194 // Now that the scheduler tracepoint is registered, force a context switch
195 // on all cpus to capture what is currently running.
196 on_each_cpu(do_nothing, NULL, 0);
200 // unregister tracepoints on error
201 fail_sched_process_free:
202 GATOR_UNREGISTER_TRACE(sched_switch);
204 GATOR_UNREGISTER_TRACE(sched_process_fork);
205 fail_sched_process_fork:
206 pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
211 int gator_trace_sched_start(void)
215 for_each_present_cpu(cpu) {
216 size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t);
217 per_cpu(taskname_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL);
218 if (!per_cpu(taskname_keys, cpu))
220 memset(per_cpu(taskname_keys, cpu), 0, size);
223 return register_scheduler_tracepoints();
226 void gator_trace_sched_offline(void)
228 trace_sched_insert_idle();
231 static void unregister_scheduler_tracepoints(void)
233 GATOR_UNREGISTER_TRACE(sched_process_fork);
234 GATOR_UNREGISTER_TRACE(sched_switch);
235 GATOR_UNREGISTER_TRACE(sched_process_free);
236 pr_debug("gator: unregistered tracepoints\n");
239 void gator_trace_sched_stop(void)
242 unregister_scheduler_tracepoints();
244 for_each_present_cpu(cpu) {
245 kfree(per_cpu(taskname_keys, cpu));
249 void gator_trace_sched_init(void)
252 for (i = 0; i < CPU_WAIT_TOTAL; i++) {
253 cpu_wait_enabled[i] = 0;
254 sched_cpu_key[i] = gator_events_get_key();