1 /**
2 * Copyright (C) ARM Limited 2010. All rights reserved.
3 *
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.
7 *
8 */
10 #include <linux/version.h>
11 #include <linux/slab.h>
12 #include <linux/fs.h>
13 #include <linux/mm.h>
14 #include <linux/dcookies.h>
15 #include <trace/events/sched.h>
17 #include "gator.h"
18 #include "gator_trace.h"
20 #define SCHED_SWITCH 0
21 #define SCHED_TOTAL (SCHED_SWITCH+1)
23 static ulong sched_switch_enabled;
24 static ulong sched_switch_key;
25 static DEFINE_PER_CPU(int[SCHED_TOTAL], schedCnt);
26 static DEFINE_PER_CPU(int[SCHED_TOTAL * 2], schedGet);
28 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
29 GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
30 #else
31 GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
32 #endif
33 {
34 unsigned long flags;
36 // disable interrupts to synchronize with gator_events_sched_read()
37 // spinlocks not needed since percpu buffers are used
38 local_irq_save(flags);
39 per_cpu(schedCnt, raw_smp_processor_id())[SCHED_SWITCH]++;
40 local_irq_restore(flags);
41 }
43 static int gator_events_sched_create_files(struct super_block *sb, struct dentry *root)
44 {
45 struct dentry *dir;
47 /* switch */
48 dir = gatorfs_mkdir(sb, root, "Linux_sched_switch");
49 if (!dir) {
50 return -1;
51 }
52 gatorfs_create_ulong(sb, dir, "enabled", &sched_switch_enabled);
53 gatorfs_create_ro_ulong(sb, dir, "key", &sched_switch_key);
55 return 0;
56 }
58 static int gator_events_sched_init(int *key)
59 {
60 sched_switch_enabled = 0;
62 sched_switch_key = *key;
63 *key = *key + 1;
65 return 0;
66 }
68 static int gator_events_sched_start(void)
69 {
70 // register tracepoints
71 if (sched_switch_enabled)
72 if (GATOR_REGISTER_TRACE(sched_switch))
73 goto sched_switch_exit;
74 pr_debug("gator: registered scheduler event tracepoints\n");
76 return 0;
78 // unregister tracepoints on error
79 sched_switch_exit:
80 pr_err("gator: scheduler event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
82 return -1;
83 }
85 static void gator_events_sched_stop(void)
86 {
87 if (sched_switch_enabled)
88 GATOR_UNREGISTER_TRACE(sched_switch);
89 pr_debug("gator: unregistered scheduler event tracepoints\n");
91 sched_switch_enabled = 0;
92 }
94 static int gator_events_sched_read(int **buffer)
95 {
96 unsigned long flags;
97 int len, value;
98 int cpu = raw_smp_processor_id();
100 len = 0;
101 if (sched_switch_enabled) {
102 local_irq_save(flags);
103 value = per_cpu(schedCnt, cpu)[SCHED_SWITCH];
104 per_cpu(schedCnt, cpu)[SCHED_SWITCH] = 0;
105 local_irq_restore(flags);
106 per_cpu(schedGet, cpu)[len++] = sched_switch_key;
107 per_cpu(schedGet, cpu)[len++] = value;
108 }
110 if (buffer)
111 *buffer = per_cpu(schedGet, cpu);
113 return len;
114 }
116 int gator_events_sched_install(gator_interface *gi) {
117 gi->create_files = gator_events_sched_create_files;
118 gi->init = gator_events_sched_init;
119 gi->start = gator_events_sched_start;
120 gi->stop = gator_events_sched_stop;
121 gi->read = gator_events_sched_read;
122 return 0;
123 }