summaryrefslogtreecommitdiffstats
path: root/driver
diff options
context:
space:
mode:
authorJon Medhurst2012-05-10 08:15:56 -0500
committerJon Medhurst2012-05-16 08:22:59 -0500
commitd18974d3f05535eda819f2d0b92a9d49719b0f26 (patch)
treeee0d02ac702b3802b0f002a0f8edf2171d7e58c3 /driver
parent970700feed8c3523b06476ae340bf46f6d262550 (diff)
downloadarm-ds5-gator-d18974d3f05535eda819f2d0b92a9d49719b0f26.tar.gz
arm-ds5-gator-d18974d3f05535eda819f2d0b92a9d49719b0f26.tar.xz
arm-ds5-gator-d18974d3f05535eda819f2d0b92a9d49719b0f26.zip
gator: Version 5.10
New gator release (build 1385) for ARM DS-5 v5.10 Signed-off-by: Jon Medhurst <tixy@linaro.org>
Diffstat (limited to 'driver')
-rw-r--r--driver/Makefile11
-rw-r--r--driver/gator.h1
-rw-r--r--driver/gator_annotate.c184
-rw-r--r--driver/gator_backtrace.c6
-rw-r--r--driver/gator_cookies.c10
-rw-r--r--driver/gator_ebs.c64
-rw-r--r--driver/gator_events_armv6.c16
-rw-r--r--driver/gator_events_armv7.c15
-rw-r--r--driver/gator_events_block.c6
-rw-r--r--driver/gator_events_irq.c19
-rwxr-xr-x[-rw-r--r--]driver/gator_events_mali.c165
-rw-r--r--driver/gator_events_meminfo.c9
-rw-r--r--driver/gator_events_mmaped.c77
-rw-r--r--driver/gator_events_net.c17
-rwxr-xr-x[-rw-r--r--]driver/gator_events_perf_pmu.c16
-rw-r--r--driver/gator_events_power.c178
-rw-r--r--driver/gator_events_scorpion.c18
-rw-r--r--driver/gator_fs.c8
-rwxr-xr-x[-rw-r--r--]driver/gator_hrtimer_gator.c23
-rw-r--r--driver/gator_main.c471
-rwxr-xr-xdriver/gator_marshaling.c239
-rw-r--r--driver/gator_pack.c98
-rw-r--r--driver/gator_trace_gpu.c164
-rwxr-xr-xdriver/gator_trace_power.c160
-rw-r--r--driver/gator_trace_sched.c182
25 files changed, 1087 insertions, 1070 deletions
diff --git a/driver/Makefile b/driver/Makefile
index 8824f8e..667637e 100644
--- a/driver/Makefile
+++ b/driver/Makefile
@@ -11,21 +11,10 @@ gator-y := gator_main.o \
11 gator_events_net.o \ 11 gator_events_net.o \
12 gator_events_block.o \ 12 gator_events_block.o \
13 gator_events_meminfo.o \ 13 gator_events_meminfo.o \
14 gator_events_power.o \
15 gator_events_perf_pmu.o 14 gator_events_perf_pmu.o
16 15
17gator-y += gator_events_mmaped.o 16gator-y += gator_events_mmaped.o
18 17
19ifeq ($(GATOR_WITH_MALI_SUPPORT),)
20ifeq ($(GATOR_MALI_INCLUDE),)
21GATOR_MALI_INCLUDE = $(abspath $(shell find -L . -name "mali_linux_trace.h" | sed -n -e '1s,\(.*\)/linux/mali_linux_trace.h$$,\1,p'))
22endif
23ifneq ($(GATOR_MALI_INCLUDE),)
24GATOR_WITH_MALI_SUPPORT = MALI_400 # for now, assume all devices with Mali have the Mali-400
25EXTRA_CFLAGS += -I$(GATOR_MALI_INCLUDE)
26endif
27endif
28
29ifneq ($(GATOR_WITH_MALI_SUPPORT),) 18ifneq ($(GATOR_WITH_MALI_SUPPORT),)
30ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx) 19ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx)
31gator-y += gator_events_mali_t6xx.o 20gator-y += gator_events_mali_t6xx.o
diff --git a/driver/gator.h b/driver/gator.h
index a7a323c..6b96109 100644
--- a/driver/gator.h
+++ b/driver/gator.h
@@ -88,6 +88,7 @@ struct gator_interface {
88 struct list_head list; 88 struct list_head list;
89}; 89};
90 90
91// gator_events_init is used as a search term in gator_events.sh
91#define gator_events_init(initfn) \ 92#define gator_events_init(initfn) \
92 static inline int __gator_events_init_test(void) \ 93 static inline int __gator_events_init_test(void) \
93 { return initfn(); } 94 { return initfn(); }
diff --git a/driver/gator_annotate.c b/driver/gator_annotate.c
index 36a921c..b2288b3 100644
--- a/driver/gator_annotate.c
+++ b/driver/gator_annotate.c
@@ -15,65 +15,93 @@
15#include <asm/current.h> 15#include <asm/current.h>
16#include <linux/spinlock.h> 16#include <linux/spinlock.h>
17 17
18#define ANNOTATE_SIZE (16*1024)
19static DEFINE_SPINLOCK(annotate_lock); 18static DEFINE_SPINLOCK(annotate_lock);
20static char *annotateBuf;
21static char *annotateBuf0;
22static char *annotateBuf1;
23static int annotatePos;
24static int annotateSel;
25static bool collect_annotations = false; 19static bool collect_annotations = false;
26 20
27static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset) 21static int annotate_copy(struct file *file, char const __user *buf, size_t count)
28{ 22{
29 char tempBuffer[512]; 23 int cpu = 0;
30 int remaining, size; 24 int write = per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF];
31 uint32_t tid; 25
26 if (file == NULL) {
27 // copy from kernel
28 memcpy(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count);
29 } else {
30 // copy from user space
31 if (copy_from_user(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count) != 0)
32 return -1;
33 }
34 per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF] = (write + count) & gator_buffer_mask[ANNOTATE_BUF];
35
36 return 0;
37}
38
39static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count_orig, loff_t *offset)
40{
41 int tid, cpu, header_size, available, contiguous, length1, length2, size, count = count_orig & 0x7fffffff;
32 42
33 if (*offset) 43 if (*offset)
34 return -EINVAL; 44 return -EINVAL;
35 45
36 // determine size to capture 46 if (!collect_annotations) {
37 size = count < sizeof(tempBuffer) ? count : sizeof(tempBuffer); 47 return count_orig;
48 }
49
50 cpu = 0; // Annotation only uses a single per-cpu buffer as the data must be in order to the engine
38 51
39 // note: copy may be for naught if remaining is zero, but better to do the copy outside of the spinlock
40 if (file == NULL) { 52 if (file == NULL) {
41 // copy from kernel 53 tid = -1; // set the thread id to the kernel thread
42 memcpy(tempBuffer, buf, size);
43
44 // set the thread id to the kernel thread, not the current thread
45 tid = -1;
46 } else { 54 } else {
47 // copy from user space
48 if (copy_from_user(tempBuffer, buf, size) != 0)
49 return -EINVAL;
50 tid = current->pid; 55 tid = current->pid;
51 } 56 }
52 57
53 // synchronize shared variables annotateBuf and annotatePos 58 // synchronize between cores
54 spin_lock(&annotate_lock); 59 spin_lock(&annotate_lock);
55 if (collect_annotations && annotateBuf) { 60
56 remaining = ANNOTATE_SIZE - annotatePos - 256; // pad for headers and release 61 // determine total size of the payload
57 size = size < remaining ? size : remaining; 62 header_size = MAXSIZE_PACK32 * 3 + MAXSIZE_PACK64;
58 if (size > 0) { 63 available = buffer_bytes_available(cpu, ANNOTATE_BUF) - header_size;
59 uint64_t time = gator_get_time(); 64 size = count < available ? count : available;
60 uint32_t cpuid = smp_processor_id();
61 int pos = annotatePos;
62 pos += gator_write_packed_int(&annotateBuf[pos], tid);
63 pos += gator_write_packed_int64(&annotateBuf[pos], time);
64 pos += gator_write_packed_int(&annotateBuf[pos], cpuid);
65 pos += gator_write_packed_int(&annotateBuf[pos], size);
66 memcpy(&annotateBuf[pos], tempBuffer, size);
67 annotatePos = pos + size;
68 }
69 }
70 spin_unlock(&annotate_lock);
71 65
72 if (size <= 0) { 66 if (size <= 0) {
73 wake_up(&gator_buffer_wait); 67 size = 0;
74 return 0; 68 goto annotate_write_out;
75 } 69 }
76 70
71 // synchronize shared variables annotateBuf and annotatePos
72 if (collect_annotations && per_cpu(gator_buffer, cpu)[ANNOTATE_BUF]) {
73 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, smp_processor_id());
74 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, tid);
75 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, gator_get_time());
76 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, size);
77
78 // determine the sizes to capture, length1 + length2 will equal size
79 contiguous = contiguous_space_available(cpu, ANNOTATE_BUF);
80 if (size < contiguous) {
81 length1 = size;
82 length2 = 0;
83 } else {
84 length1 = contiguous;
85 length2 = size - contiguous;
86 }
87
88 if (annotate_copy(file, buf, length1) != 0) {
89 size = -EINVAL;
90 goto annotate_write_out;
91 }
92
93 if (length2 > 0 && annotate_copy(file, &buf[length1], length2) != 0) {
94 size = -EINVAL;
95 goto annotate_write_out;
96 }
97
98 // Check and commit; commit is set to occur once buffer is 3/4 full
99 buffer_check(cpu, ANNOTATE_BUF);
100 }
101
102annotate_write_out:
103 spin_unlock(&annotate_lock);
104
77 // return the number of bytes written 105 // return the number of bytes written
78 return size; 106 return size;
79} 107}
@@ -82,21 +110,18 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
82 110
83static int annotate_release(struct inode *inode, struct file *file) 111static int annotate_release(struct inode *inode, struct file *file)
84{ 112{
85 int remaining = ANNOTATE_SIZE - annotatePos; 113 int cpu = 0;
86 if (remaining < 16) {
87 return -EFAULT;
88 }
89 114
115 // synchronize between cores
90 spin_lock(&annotate_lock); 116 spin_lock(&annotate_lock);
91 if (annotateBuf) { 117
118 if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
92 uint32_t tid = current->pid; 119 uint32_t tid = current->pid;
93 int pos = annotatePos; 120 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, tid);
94 pos += gator_write_packed_int(&annotateBuf[pos], tid); 121 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time
95 pos += gator_write_packed_int64(&annotateBuf[pos], 0); // time 122 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size
96 pos += gator_write_packed_int(&annotateBuf[pos], 0); // cpuid
97 pos += gator_write_packed_int(&annotateBuf[pos], 0); // size
98 annotatePos = pos;
99 } 123 }
124
100 spin_unlock(&annotate_lock); 125 spin_unlock(&annotate_lock);
101 126
102 return 0; 127 return 0;
@@ -109,25 +134,11 @@ static const struct file_operations annotate_fops = {
109 134
110static int gator_annotate_create_files(struct super_block *sb, struct dentry *root) 135static int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
111{ 136{
112 annotateBuf = NULL;
113 return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666); 137 return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666);
114} 138}
115 139
116static int gator_annotate_init(void)
117{
118 annotateBuf0 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
119 annotateBuf1 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
120 if (!annotateBuf0 || !annotateBuf1)
121 return -1;
122 return 0;
123}
124
125static int gator_annotate_start(void) 140static int gator_annotate_start(void)
126{ 141{
127 annotateSel = 0;
128 annotatePos = 1;
129 annotateBuf = annotateBuf0;
130 annotateBuf[0] = FRAME_ANNOTATE;
131 collect_annotations = true; 142 collect_annotations = true;
132 return 0; 143 return 0;
133} 144}
@@ -136,46 +147,3 @@ static void gator_annotate_stop(void)
136{ 147{
137 collect_annotations = false; 148 collect_annotations = false;
138} 149}
139
140static void gator_annotate_shutdown(void)
141{
142 spin_lock(&annotate_lock);
143 annotateBuf = NULL;
144 spin_unlock(&annotate_lock);
145}
146
147static void gator_annotate_exit(void)
148{
149 spin_lock(&annotate_lock);
150 kfree(annotateBuf0);
151 kfree(annotateBuf1);
152 annotateBuf = annotateBuf0 = annotateBuf1 = NULL;
153 spin_unlock(&annotate_lock);
154}
155
156static int gator_annotate_ready(void)
157{
158 return annotatePos > 1 && annotateBuf;
159}
160
161static int gator_annotate_read(char **buffer)
162{
163 int len;
164
165 if (!gator_annotate_ready())
166 return 0;
167
168 annotateSel = !annotateSel;
169
170 if (buffer)
171 *buffer = annotateBuf;
172
173 spin_lock(&annotate_lock);
174 len = annotatePos;
175 annotateBuf = annotateSel ? annotateBuf1 : annotateBuf0;
176 annotateBuf[0] = FRAME_ANNOTATE;
177 annotatePos = 1;
178 spin_unlock(&annotate_lock);
179
180 return len;
181}
diff --git a/driver/gator_backtrace.c b/driver/gator_backtrace.c
index 26503ef..50783d6 100644
--- a/driver/gator_backtrace.c
+++ b/driver/gator_backtrace.c
@@ -81,8 +81,7 @@ static int report_trace(struct stackframe *frame, void *d)
81 cookie = get_cookie(cpu, per_cpu(backtrace_buffer, cpu), current, NULL, mod, true); 81 cookie = get_cookie(cpu, per_cpu(backtrace_buffer, cpu), current, NULL, mod, true);
82 addr = addr - (unsigned long)mod->module_core; 82 addr = addr - (unsigned long)mod->module_core;
83 } 83 }
84 gator_buffer_write_packed_int(cpu, per_cpu(backtrace_buffer, cpu), addr & ~1); 84 marshal_backtrace(addr & ~1, cookie);
85 gator_buffer_write_packed_int(cpu, per_cpu(backtrace_buffer, cpu), cookie);
86 (*depth)--; 85 (*depth)--;
87 } 86 }
88 87
@@ -110,7 +109,6 @@ static void kernel_backtrace(int cpu, int buftype, struct pt_regs * const regs)
110 per_cpu(backtrace_buffer, cpu) = buftype; 109 per_cpu(backtrace_buffer, cpu) = buftype;
111 walk_stackframe(&frame, report_trace, &depth); 110 walk_stackframe(&frame, report_trace, &depth);
112#else 111#else
113 gator_buffer_write_packed_int(cpu, buftype, PC_REG & ~1); 112 marshal_backtrace(PC_REG & ~1, NO_COOKIE);
114 gator_buffer_write_packed_int(cpu, buftype, NO_COOKIE);
115#endif 113#endif
116} 114}
diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c
index 1beb34f..7b50916 100644
--- a/driver/gator_cookies.c
+++ b/driver/gator_cookies.c
@@ -129,7 +129,7 @@ static void wq_cookie_handler(struct work_struct *unused)
129 while (per_cpu(translate_buffer_read, cpu) != commit) { 129 while (per_cpu(translate_buffer_read, cpu) != commit) {
130 task = (struct task_struct *)translate_buffer_read_int(cpu); 130 task = (struct task_struct *)translate_buffer_read_int(cpu);
131 vma = (struct vm_area_struct *)translate_buffer_read_int(cpu); 131 vma = (struct vm_area_struct *)translate_buffer_read_int(cpu);
132 cookie = get_cookie(cpu, TIMER_BUF, task, vma, NULL, false); 132 cookie = get_cookie(cpu, BACKTRACE_BUF, task, vma, NULL, false);
133 } 133 }
134 } 134 }
135 135
@@ -251,13 +251,10 @@ static inline uint32_t get_cookie(int cpu, int buftype, struct task_struct *task
251 local_irq_save(flags); 251 local_irq_save(flags);
252 252
253 cookie = INVALID_COOKIE; 253 cookie = INVALID_COOKIE;
254 if (buffer_check_space(cpu, buftype, strlen(text) + 2 * MAXSIZE_PACK32)) { 254 if (marshal_cookie_header(text)) {
255 cookie = per_cpu(cookie_next_key, cpu) += nr_cpu_ids; 255 cookie = per_cpu(cookie_next_key, cpu) += nr_cpu_ids;
256 cookiemap_add(key, cookie); 256 cookiemap_add(key, cookie);
257 257 marshal_cookie(cookie, text);
258 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COOKIE);
259 gator_buffer_write_packed_int(cpu, buftype, cookie);
260 gator_buffer_write_string(cpu, buftype, text);
261 } 258 }
262 259
263 local_irq_restore(flags); 260 local_irq_restore(flags);
@@ -271,6 +268,7 @@ static int get_exec_cookie(int cpu, int buftype, struct task_struct *task)
271 struct mm_struct *mm = task->mm; 268 struct mm_struct *mm = task->mm;
272 struct vm_area_struct *vma; 269 struct vm_area_struct *vma;
273 270
271 // kernel threads have no address space
274 if (!mm) 272 if (!mm)
275 return cookie; 273 return cookie;
276 274
diff --git a/driver/gator_ebs.c b/driver/gator_ebs.c
index 8c2997c..1208d69 100644
--- a/driver/gator_ebs.c
+++ b/driver/gator_ebs.c
@@ -14,6 +14,8 @@
14 14
15#include <asm/pmu.h> 15#include <asm/pmu.h>
16 16
17static DEFINE_MUTEX(perf_mutex);
18
17extern int pmnc_counters; 19extern int pmnc_counters;
18extern int ccnt; 20extern int ccnt;
19extern unsigned long pmnc_enabled[]; 21extern unsigned long pmnc_enabled[];
@@ -32,59 +34,16 @@ static void ebs_overflow_handler(struct perf_event *event, int unused, struct pe
32static void ebs_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs) 34static void ebs_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
33#endif 35#endif
34{ 36{
35 unsigned int value, delta, cpu = smp_processor_id(), buftype = EVENT_BUF; 37 int cpu = smp_processor_id();
36 38
37 if (event != per_cpu(pevent, cpu)) 39 if (event != per_cpu(pevent, cpu))
38 return; 40 return;
39 41
40 if (buffer_check_space(cpu, buftype, 5 * MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
41 value = local64_read(&event->count);
42 delta = value - per_cpu(prev_value, cpu);
43 per_cpu(prev_value, cpu) = value;
44
45 // Counters header
46 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COUNTERS); // type
47 gator_buffer_write_packed_int64(cpu, buftype, gator_get_time()); // time
48
49 // Output counter
50 gator_buffer_write_packed_int(cpu, buftype, 2); // length
51 gator_buffer_write_packed_int(cpu, buftype, per_cpu(key, cpu)); // key
52 gator_buffer_write_packed_int(cpu, buftype, delta); // delta
53
54 // End Counters, length of zero
55 gator_buffer_write_packed_int(cpu, buftype, 0);
56 }
57
58 // Output backtrace 42 // Output backtrace
59 if (buffer_check_space(cpu, buftype, gator_backtrace_depth * 2 * MAXSIZE_PACK32)) 43 gator_add_sample(cpu, BACKTRACE_BUF, regs);
60 gator_add_sample(cpu, buftype, regs);
61 44
62 // Check and commit; commit is set to occur once buffer is 3/4 full 45 // Collect counters
63 buffer_check(cpu, buftype); 46 collect_counters();
64}
65
66static void gator_event_sampling_online(void)
67{
68 int cpu = smp_processor_id(), buftype = EVENT_BUF;
69
70 // read the counter and toss the invalid data, return zero instead
71 struct perf_event * ev = per_cpu(pevent, cpu);
72 if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
73 ev->pmu->read(ev);
74 per_cpu(prev_value, cpu) = local64_read(&ev->count);
75
76 // Counters header
77 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COUNTERS); // type
78 gator_buffer_write_packed_int64(cpu, buftype, gator_get_time()); // time
79
80 // Output counter
81 gator_buffer_write_packed_int(cpu, buftype, 2); // length
82 gator_buffer_write_packed_int(cpu, buftype, per_cpu(key, cpu)); // key
83 gator_buffer_write_packed_int(cpu, buftype, 0); // delta - zero for initialization
84
85 // End Counters, length of zero
86 gator_buffer_write_packed_int(cpu, buftype, 0);
87 }
88} 47}
89 48
90static void gator_event_sampling_online_dispatch(int cpu) 49static void gator_event_sampling_online_dispatch(int cpu)
@@ -117,10 +76,18 @@ static void gator_event_sampling_online_dispatch(int cpu)
117 76
118static void gator_event_sampling_offline_dispatch(int cpu) 77static void gator_event_sampling_offline_dispatch(int cpu)
119{ 78{
79 struct perf_event * pe = NULL;
80
81 mutex_lock(&perf_mutex);
120 if (per_cpu(pevent, cpu)) { 82 if (per_cpu(pevent, cpu)) {
121 perf_event_release_kernel(per_cpu(pevent, cpu)); 83 pe = per_cpu(pevent, cpu);
122 per_cpu(pevent, cpu) = NULL; 84 per_cpu(pevent, cpu) = NULL;
123 } 85 }
86 mutex_unlock(&perf_mutex);
87
88 if (pe) {
89 perf_event_release_kernel(pe);
90 }
124} 91}
125 92
126static int gator_event_sampling_start(void) 93static int gator_event_sampling_start(void)
@@ -184,7 +151,6 @@ static void gator_event_sampling_stop(void)
184} 151}
185 152
186#else 153#else
187static void gator_event_sampling_online(void) {}
188static void gator_event_sampling_online_dispatch(int cpu) {} 154static void gator_event_sampling_online_dispatch(int cpu) {}
189static void gator_event_sampling_offline_dispatch(int cpu) {} 155static void gator_event_sampling_offline_dispatch(int cpu) {}
190static int gator_event_sampling_start(void) {return 0;} 156static int gator_event_sampling_start(void) {return 0;}
diff --git a/driver/gator_events_armv6.c b/driver/gator_events_armv6.c
index ef51898..5f989ba 100644
--- a/driver/gator_events_armv6.c
+++ b/driver/gator_events_armv6.c
@@ -33,7 +33,6 @@ static unsigned long pmnc_enabled[CNTMAX];
33static unsigned long pmnc_event[CNTMAX]; 33static unsigned long pmnc_event[CNTMAX];
34static unsigned long pmnc_key[CNTMAX]; 34static unsigned long pmnc_key[CNTMAX];
35 35
36static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
37static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt); 36static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
38 37
39static inline void armv6_pmnc_write(u32 val) 38static inline void armv6_pmnc_write(u32 val)
@@ -111,8 +110,6 @@ static int gator_events_armv6_online(int** buffer)
111 for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) { 110 for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
112 unsigned long event; 111 unsigned long event;
113 112
114 per_cpu(perfPrev, cpu)[cnt] = 0;
115
116 if (!pmnc_enabled[cnt]) 113 if (!pmnc_enabled[cnt])
117 continue; 114 continue;
118 115
@@ -171,6 +168,11 @@ static int gator_events_armv6_read(int **buffer)
171 int cnt, len = 0; 168 int cnt, len = 0;
172 int cpu = smp_processor_id(); 169 int cpu = smp_processor_id();
173 170
171 // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
172 if (!(armv6_pmnc_read() & PMCR_E)) {
173 return 0;
174 }
175
174 for (cnt = PMN0; cnt <= CCNT; cnt++) { 176 for (cnt = PMN0; cnt <= CCNT; cnt++) {
175 if (pmnc_enabled[cnt]) { 177 if (pmnc_enabled[cnt]) {
176 u32 value = 0; 178 u32 value = 0;
@@ -186,11 +188,9 @@ static int gator_events_armv6_read(int **buffer)
186 break; 188 break;
187 } 189 }
188 armv6_pmnc_reset_counter(cnt); 190 armv6_pmnc_reset_counter(cnt);
189 if (value != per_cpu(perfPrev, cpu)[cnt]) { 191
190 per_cpu(perfPrev, cpu)[cnt] = value; 192 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
191 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; 193 per_cpu(perfCnt, cpu)[len++] = value;
192 per_cpu(perfCnt, cpu)[len++] = value;
193 }
194 } 194 }
195 } 195 }
196 196
diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c
index cdf450f..590421d 100644
--- a/driver/gator_events_armv7.c
+++ b/driver/gator_events_armv7.c
@@ -38,7 +38,6 @@ static unsigned long pmnc_enabled[CNTMAX];
38static unsigned long pmnc_event[CNTMAX]; 38static unsigned long pmnc_event[CNTMAX];
39static unsigned long pmnc_key[CNTMAX]; 39static unsigned long pmnc_key[CNTMAX];
40 40
41static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
42static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt); 41static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
43 42
44inline void armv7_pmnc_write(u32 val) 43inline void armv7_pmnc_write(u32 val)
@@ -177,8 +176,6 @@ static int gator_events_armv7_online(int** buffer)
177 for (cnt = CCNT; cnt < CNTMAX; cnt++) { 176 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
178 unsigned long event; 177 unsigned long event;
179 178
180 per_cpu(perfPrev, cpu)[cnt] = 0;
181
182 if (!pmnc_enabled[cnt]) 179 if (!pmnc_enabled[cnt])
183 continue; 180 continue;
184 181
@@ -240,6 +237,11 @@ static int gator_events_armv7_read(int **buffer)
240 int cnt, len = 0; 237 int cnt, len = 0;
241 int cpu = smp_processor_id(); 238 int cpu = smp_processor_id();
242 239
240 // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
241 if (!(armv7_pmnc_read() & PMNC_E)) {
242 return 0;
243 }
244
243 for (cnt = 0; cnt < pmnc_counters; cnt++) { 245 for (cnt = 0; cnt < pmnc_counters; cnt++) {
244 if (pmnc_enabled[cnt]) { 246 if (pmnc_enabled[cnt]) {
245 int value; 247 int value;
@@ -248,11 +250,8 @@ static int gator_events_armv7_read(int **buffer)
248 } else { 250 } else {
249 value = armv7_cntn_read(cnt, 0); 251 value = armv7_cntn_read(cnt, 0);
250 } 252 }
251 if (value != per_cpu(perfPrev, cpu)[cnt]) { 253 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
252 per_cpu(perfPrev, cpu)[cnt] = value; 254 per_cpu(perfCnt, cpu)[len++] = value;
253 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
254 per_cpu(perfCnt, cpu)[len++] = value;
255 }
256 } 255 }
257 } 256 }
258 257
diff --git a/driver/gator_events_block.c b/driver/gator_events_block.c
index f1bbbc8..a8b8114 100644
--- a/driver/gator_events_block.c
+++ b/driver/gator_events_block.c
@@ -26,7 +26,7 @@ static ulong block_rq_rd_enabled;
26static ulong block_rq_wr_key; 26static ulong block_rq_wr_key;
27static ulong block_rq_rd_key; 27static ulong block_rq_rd_key;
28static DEFINE_PER_CPU(int[BLOCK_TOTAL], blockCnt); 28static DEFINE_PER_CPU(int[BLOCK_TOTAL], blockCnt);
29static DEFINE_PER_CPU(int[BLOCK_TOTAL * 2], blockGet); 29static DEFINE_PER_CPU(int[BLOCK_TOTAL * 4], blockGet);
30static DEFINE_PER_CPU(bool, new_data_avail); 30static DEFINE_PER_CPU(bool, new_data_avail);
31 31
32GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq)) 32GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq))
@@ -129,6 +129,8 @@ static int gator_events_block_read(int **buffer)
129 per_cpu(blockCnt, cpu)[BLOCK_RQ_WR] = 0; 129 per_cpu(blockCnt, cpu)[BLOCK_RQ_WR] = 0;
130 local_irq_restore(flags); 130 local_irq_restore(flags);
131 per_cpu(blockGet, cpu)[len++] = block_rq_wr_key; 131 per_cpu(blockGet, cpu)[len++] = block_rq_wr_key;
132 per_cpu(blockGet, cpu)[len++] = 0; // indicates to Streamline that value bytes were written now, not since the last message
133 per_cpu(blockGet, cpu)[len++] = block_rq_wr_key;
132 per_cpu(blockGet, cpu)[len++] = value; 134 per_cpu(blockGet, cpu)[len++] = value;
133 data += value; 135 data += value;
134 } 136 }
@@ -138,6 +140,8 @@ static int gator_events_block_read(int **buffer)
138 per_cpu(blockCnt, cpu)[BLOCK_RQ_RD] = 0; 140 per_cpu(blockCnt, cpu)[BLOCK_RQ_RD] = 0;
139 local_irq_restore(flags); 141 local_irq_restore(flags);
140 per_cpu(blockGet, cpu)[len++] = block_rq_rd_key; 142 per_cpu(blockGet, cpu)[len++] = block_rq_rd_key;
143 per_cpu(blockGet, cpu)[len++] = 0; // indicates to Streamline that value bytes were read now, not since the last message
144 per_cpu(blockGet, cpu)[len++] = block_rq_rd_key;
141 per_cpu(blockGet, cpu)[len++] = value; 145 per_cpu(blockGet, cpu)[len++] = value;
142 data += value; 146 data += value;
143 } 147 }
diff --git a/driver/gator_events_irq.c b/driver/gator_events_irq.c
index 59461b9..435bc86 100644
--- a/driver/gator_events_irq.c
+++ b/driver/gator_events_irq.c
@@ -19,7 +19,6 @@ static ulong softirq_enabled;
19static ulong hardirq_key; 19static ulong hardirq_key;
20static ulong softirq_key; 20static ulong softirq_key;
21static DEFINE_PER_CPU(int[TOTALIRQ], irqCnt); 21static DEFINE_PER_CPU(int[TOTALIRQ], irqCnt);
22static DEFINE_PER_CPU(int[TOTALIRQ], irqPrev);
23static DEFINE_PER_CPU(int[TOTALIRQ * 2], irqGet); 22static DEFINE_PER_CPU(int[TOTALIRQ * 2], irqGet);
24 23
25GATOR_DEFINE_PROBE(irq_handler_exit, TP_PROTO(int irq, 24GATOR_DEFINE_PROBE(irq_handler_exit, TP_PROTO(int irq,
@@ -82,7 +81,6 @@ static int gator_events_irq_online(int** buffer)
82 local_irq_save(flags); 81 local_irq_save(flags);
83 per_cpu(irqCnt, cpu)[HARDIRQ] = 0; 82 per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
84 local_irq_restore(flags); 83 local_irq_restore(flags);
85 per_cpu(irqPrev, cpu)[HARDIRQ] = 0;
86 per_cpu(irqGet, cpu)[len++] = hardirq_key; 84 per_cpu(irqGet, cpu)[len++] = hardirq_key;
87 per_cpu(irqGet, cpu)[len++] = 0; 85 per_cpu(irqGet, cpu)[len++] = 0;
88 } 86 }
@@ -91,7 +89,6 @@ static int gator_events_irq_online(int** buffer)
91 local_irq_save(flags); 89 local_irq_save(flags);
92 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0; 90 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
93 local_irq_restore(flags); 91 local_irq_restore(flags);
94 per_cpu(irqPrev, cpu)[SOFTIRQ] = 0;
95 per_cpu(irqGet, cpu)[len++] = softirq_key; 92 per_cpu(irqGet, cpu)[len++] = softirq_key;
96 per_cpu(irqGet, cpu)[len++] = 0; 93 per_cpu(irqGet, cpu)[len++] = 0;
97 } 94 }
@@ -149,11 +146,9 @@ static int gator_events_irq_read(int **buffer)
149 value = per_cpu(irqCnt, cpu)[HARDIRQ]; 146 value = per_cpu(irqCnt, cpu)[HARDIRQ];
150 per_cpu(irqCnt, cpu)[HARDIRQ] = 0; 147 per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
151 local_irq_restore(flags); 148 local_irq_restore(flags);
152 if (value != per_cpu(irqPrev, cpu)[HARDIRQ]) { 149
153 per_cpu(irqPrev, cpu)[HARDIRQ] = value; 150 per_cpu(irqGet, cpu)[len++] = hardirq_key;
154 per_cpu(irqGet, cpu)[len++] = hardirq_key; 151 per_cpu(irqGet, cpu)[len++] = value;
155 per_cpu(irqGet, cpu)[len++] = value;
156 }
157 } 152 }
158 153
159 if (softirq_enabled) { 154 if (softirq_enabled) {
@@ -161,11 +156,9 @@ static int gator_events_irq_read(int **buffer)
161 value = per_cpu(irqCnt, cpu)[SOFTIRQ]; 156 value = per_cpu(irqCnt, cpu)[SOFTIRQ];
162 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0; 157 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
163 local_irq_restore(flags); 158 local_irq_restore(flags);
164 if (value != per_cpu(irqPrev, cpu)[SOFTIRQ]) { 159
165 per_cpu(irqPrev, cpu)[SOFTIRQ] = value; 160 per_cpu(irqGet, cpu)[len++] = softirq_key;
166 per_cpu(irqGet, cpu)[len++] = softirq_key; 161 per_cpu(irqGet, cpu)[len++] = value;
167 per_cpu(irqGet, cpu)[len++] = value;
168 }
169 } 162 }
170 163
171 if (buffer) 164 if (buffer)
diff --git a/driver/gator_events_mali.c b/driver/gator_events_mali.c
index 31e8f0d..21a6324 100644..100755
--- a/driver/gator_events_mali.c
+++ b/driver/gator_events_mali.c
@@ -14,17 +14,41 @@
14 14
15#include "linux/mali_linux_trace.h" 15#include "linux/mali_linux_trace.h"
16 16
17#define ACTIVITY_START 1 17/*
18#define ACTIVITY_STOP 2 18 * There are (currently) three different variants of the comms between gator and Mali:
19 * 1 (deprecated): No software counter support
20 * 2 (deprecated): Tracepoint called for each separate s/w counter value as it appears
21 * 3 (default): Single tracepoint for all s/w counters in a bundle.
22 * Interface style 3 is the default if no other is specified. 1 and 2 will be eliminated when
23 * existing Mali DDKs are upgraded.
24 */
19 25
20#ifndef MALI_SUPPORT 26#if !defined(GATOR_MALI_INTERFACE_STYLE)
21#error MALI_SUPPORT not defined! 27#define GATOR_MALI_INTERFACE_STYLE (3)
22#endif 28#endif
23 29
24#define MALI_200 0x0a07 30#define MALI_200 (0x0a07)
25#define MALI_300 0x0b06 //This is not actually true; Mali-300 is also 0x0b07 31#define MALI_300 (0x0b06) //This is not actually true; Mali-300 is also 0x0b07
26#define MALI_400 0x0b07 32#define MALI_400 (0x0b07)
27#define MALI_T6xx 0x0056 33#define MALI_T6xx (0x0056)
34
35/*
36 * List of possible actions allowing DDK to be controlled by Streamline.
37 * The following numbers are used by DDK to control the frame buffer dumping.
38 */
39#define FBDUMP_CONTROL_ENABLE (1)
40#define FBDUMP_CONTROL_RATE (2)
41#define SW_EVENTS_ENABLE (3)
42#define FBDUMP_CONTROL_RESIZE_FACTOR (4)
43
44/*
45 * Check that the MALI_SUPPORT define is set to one of the allowable device codes.
46 */
47#if !defined(MALI_SUPPORT)
48#error MALI_SUPPORT not defined!
49#elif (MALI_SUPPORT != MALI_200) && (MALI_SUPPORT != MALI_300) && (MALI_SUPPORT != MALI_400) && (MALI_SUPPORT != MALI_T6xx)
50#error MALI_SUPPORT set to an invalid device code
51#endif
28 52
29static const char *mali_name; 53static const char *mali_name;
30 54
@@ -226,12 +250,31 @@ GATOR_DEFINE_PROBE(mali_hw_counter, TP_PROTO(unsigned int event_id, unsigned int
226 } 250 }
227} 251}
228 252
253#if GATOR_MALI_INTERFACE_STYLE == 2
229GATOR_DEFINE_PROBE(mali_sw_counter, TP_PROTO(unsigned int event_id, signed long long value)) 254GATOR_DEFINE_PROBE(mali_sw_counter, TP_PROTO(unsigned int event_id, signed long long value))
230{ 255{
231 if (is_sw_counter(event_id)) { 256 if (is_sw_counter(event_id)) {
232 counter_data[event_id] = scale_sw_counter_value(event_id, value); 257 counter_data[event_id] = scale_sw_counter_value(event_id, value);
233 } 258 }
234} 259}
260#endif /* GATOR_MALI_INTERFACE_STYLE == 2 */
261
262
263#if GATOR_MALI_INTERFACE_STYLE == 3
264GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void * surface_id, unsigned int * counters))
265{
266 u32 i;
267
268 /* Copy over the values for those counters which are enabled. */
269 for(i=FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++)
270 {
271 if(counter_enabled[i])
272 {
273 counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]);
274 }
275 }
276}
277#endif /* GATOR_MALI_INTERFACE_STYLE == 3 */
235 278
236//TODO need to work out how many fp units we have 279//TODO need to work out how many fp units we have
237u32 gator_mali_get_n_fp(void) { 280u32 gator_mali_get_n_fp(void) {
@@ -363,10 +406,30 @@ int gator_events_mali_create_files(struct super_block *sb, struct dentry *root)
363//TODO 406//TODO
364void _mali_profiling_set_event(unsigned int, unsigned int); 407void _mali_profiling_set_event(unsigned int, unsigned int);
365void _mali_osk_fb_control_set(unsigned int, unsigned int); 408void _mali_osk_fb_control_set(unsigned int, unsigned int);
409void _mali_profiling_control(unsigned int, unsigned int);
366 410
367void _mali_profiling_get_counters(unsigned int*, unsigned int*, unsigned int*, unsigned int*); 411void _mali_profiling_get_counters(unsigned int*, unsigned int*, unsigned int*, unsigned int*);
368void (*_mali_profiling_get_counters_function_pointer)(unsigned int*, unsigned int*, unsigned int*, unsigned int*); 412void (*_mali_profiling_get_counters_function_pointer)(unsigned int*, unsigned int*, unsigned int*, unsigned int*);
369 413
414/*
415 * Examine list of software counters and determine if any one is enabled.
416 * Returns 1 if any counter is enabled, 0 if none is.
417 */
418static int is_any_sw_counter_enabled(void)
419{
420 unsigned int i;
421
422 for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++)
423 {
424 if (counter_enabled[i])
425 {
426 return 1; /* At least one counter is enabled */
427 }
428 }
429
430 return 0; /* No s/w counters enabled */
431}
432
370static void mali_counter_initialize(void) 433static void mali_counter_initialize(void)
371{ 434{
372 /* If a Mali driver is present and exporting the appropriate symbol 435 /* If a Mali driver is present and exporting the appropriate symbol
@@ -375,6 +438,7 @@ static void mali_counter_initialize(void)
375 */ 438 */
376 void (*set_hw_event)(unsigned int, unsigned int); 439 void (*set_hw_event)(unsigned int, unsigned int);
377 void (*set_fb_event)(unsigned int, unsigned int); 440 void (*set_fb_event)(unsigned int, unsigned int);
441 void (*mali_control)(unsigned int, unsigned int);
378 442
379 set_hw_event = symbol_get(_mali_profiling_set_event); 443 set_hw_event = symbol_get(_mali_profiling_set_event);
380 444
@@ -408,6 +472,27 @@ static void mali_counter_initialize(void)
408 printk("gator: mali online _mali_osk_fb_control_set symbol not found\n"); 472 printk("gator: mali online _mali_osk_fb_control_set symbol not found\n");
409 } 473 }
410 474
475 /* Generic control interface for Mali DDK. */
476 mali_control = symbol_get(_mali_profiling_control);
477 if (mali_control) {
478 /* The event attribute in the XML file keeps the actual frame rate. */
479 unsigned int rate = counter_event[COUNTER_FILMSTRIP] & 0xff;
480 unsigned int resize_factor = (counter_event[COUNTER_FILMSTRIP] >> 8) & 0xff;
481
482 pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control);
483
484 mali_control(SW_EVENTS_ENABLE, (is_any_sw_counter_enabled()?1:0));
485 mali_control(FBDUMP_CONTROL_ENABLE, (counter_enabled[COUNTER_FILMSTRIP]?1:0));
486 mali_control(FBDUMP_CONTROL_RATE, rate);
487 mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor);
488
489 pr_debug("gator: sent mali_control enabled=%d, rate=%d\n", (counter_enabled[COUNTER_FILMSTRIP]?1:0), rate);
490
491 symbol_put(_mali_profiling_control);
492 } else {
493 printk("gator: mali online _mali_profiling_control symbol not found\n");
494 }
495
411 _mali_profiling_get_counters_function_pointer = symbol_get(_mali_profiling_get_counters); 496 _mali_profiling_get_counters_function_pointer = symbol_get(_mali_profiling_get_counters);
412 if (_mali_profiling_get_counters_function_pointer){ 497 if (_mali_profiling_get_counters_function_pointer){
413 pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", _mali_profiling_get_counters_function_pointer); 498 pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", _mali_profiling_get_counters_function_pointer);
@@ -417,13 +502,13 @@ static void mali_counter_initialize(void)
417 else{ 502 else{
418 pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined"); 503 pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined");
419 } 504 }
420
421} 505}
422 506
423static void mali_counter_deinitialize(void) 507static void mali_counter_deinitialize(void)
424{ 508{
425 void (*set_hw_event)(unsigned int, unsigned int); 509 void (*set_hw_event)(unsigned int, unsigned int);
426 void (*set_fb_event)(unsigned int, unsigned int); 510 void (*set_fb_event)(unsigned int, unsigned int);
511 void (*mali_control)(unsigned int, unsigned int);
427 512
428 set_hw_event = symbol_get(_mali_profiling_set_event); 513 set_hw_event = symbol_get(_mali_profiling_set_event);
429 514
@@ -452,6 +537,22 @@ static void mali_counter_deinitialize(void)
452 printk("gator: mali offline _mali_osk_fb_control_set symbol not found\n"); 537 printk("gator: mali offline _mali_osk_fb_control_set symbol not found\n");
453 } 538 }
454 539
540 /* Generic control interface for Mali DDK. */
541 mali_control = symbol_get(_mali_profiling_control);
542
543 if (mali_control) {
544 pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", set_fb_event);
545
546 /* Reset the DDK state - disable counter collection */
547 mali_control(SW_EVENTS_ENABLE, 0);
548
549 mali_control(FBDUMP_CONTROL_ENABLE, 0);
550
551 symbol_put(_mali_profiling_control);
552 } else {
553 printk("gator: mali offline _mali_profiling_control symbol not found\n");
554 }
555
455 if (_mali_profiling_get_counters_function_pointer){ 556 if (_mali_profiling_get_counters_function_pointer){
456 symbol_put(_mali_profiling_get_counters); 557 symbol_put(_mali_profiling_get_counters);
457 } 558 }
@@ -465,10 +566,23 @@ static int gator_events_mali_start(void) {
465 return -1; 566 return -1;
466 } 567 }
467 568
569#if GATOR_MALI_INTERFACE_STYLE == 1
570 /* None. */
571#elif GATOR_MALI_INTERFACE_STYLE == 2
572 /* For patched Mali driver. */
468 if (GATOR_REGISTER_TRACE(mali_sw_counter)) { 573 if (GATOR_REGISTER_TRACE(mali_sw_counter)) {
469 printk("gator: mali_sw_counter tracepoint failed to activate\n"); 574 printk("gator: mali_sw_counter tracepoint failed to activate\n");
470 return -1; 575 return -1;
471 } 576 }
577#elif GATOR_MALI_INTERFACE_STYLE == 3
578/* For Mali drivers with built-in support. */
579 if (GATOR_REGISTER_TRACE(mali_sw_counters)) {
580 printk("gator: mali_sw_counters tracepoint failed to activate\n");
581 return -1;
582 }
583#else
584#error Unknown GATOR_MALI_INTERFACE_STYLE option.
585#endif
472 586
473 trace_registered = 1; 587 trace_registered = 1;
474 588
@@ -483,8 +597,19 @@ static void gator_events_mali_stop(void) {
483 597
484 if (trace_registered) { 598 if (trace_registered) {
485 GATOR_UNREGISTER_TRACE(mali_hw_counter); 599 GATOR_UNREGISTER_TRACE(mali_hw_counter);
486 GATOR_UNREGISTER_TRACE(mali_sw_counter); 600
487 601#if GATOR_MALI_INTERFACE_STYLE == 1
602 /* None. */
603#elif GATOR_MALI_INTERFACE_STYLE == 2
604 /* For patched Mali driver. */
605 GATOR_UNREGISTER_TRACE(mali_sw_counter);
606#elif GATOR_MALI_INTERFACE_STYLE == 3
607 /* For Mali drivers with built-in support. */
608 GATOR_UNREGISTER_TRACE(mali_sw_counters);
609#else
610#error Unknown GATOR_MALI_INTERFACE_STYLE option.
611#endif
612
488 pr_debug("gator: mali timeline tracepoint deactivated\n"); 613 pr_debug("gator: mali timeline tracepoint deactivated\n");
489 614
490 trace_registered = 0; 615 trace_registered = 0;
@@ -538,22 +663,10 @@ static int gator_events_mali_read(int **buffer) {
538 // Process other (non-timeline) counters. 663 // Process other (non-timeline) counters.
539 for (cnt = COUNTER_VP_C0; cnt <= LAST_SW_COUNTER; cnt++) { 664 for (cnt = COUNTER_VP_C0; cnt <= LAST_SW_COUNTER; cnt++) {
540 if (counter_enabled[cnt]) { 665 if (counter_enabled[cnt]) {
541 u32 value = 0; 666 counter_dump[len++] = counter_key[cnt];
542 667 counter_dump[len++] = counter_data[cnt];
543 // Determine the current value of the counter.
544 if( counter_address[cnt] != NULL && 0 ) { // Never true!
545 value = *counter_address[cnt];
546 } else if (counter_data[cnt]!=0) {
547 value = counter_data[cnt];
548 counter_data[cnt] = 0;
549 }
550 668
551 // Send the counter value only if it differs from last time. 669 counter_data[cnt] = 0;
552 if (value != counter_prev[cnt]) {
553 counter_prev[cnt] = value;
554 counter_dump[len++] = counter_key[cnt];
555 counter_dump[len++] = value;
556 }
557 } 670 }
558 } 671 }
559 672
diff --git a/driver/gator_events_meminfo.c b/driver/gator_events_meminfo.c
index c763634..ad552ef 100644
--- a/driver/gator_events_meminfo.c
+++ b/driver/gator_events_meminfo.c
@@ -10,6 +10,7 @@
10#include "gator.h" 10#include "gator.h"
11#include <linux/workqueue.h> 11#include <linux/workqueue.h>
12#include <trace/events/kmem.h> 12#include <trace/events/kmem.h>
13#include <linux/hardirq.h>
13 14
14#define MEMINFO_MEMFREE 0 15#define MEMINFO_MEMFREE 0
15#define MEMINFO_MEMUSED 1 16#define MEMINFO_MEMUSED 1
@@ -145,7 +146,7 @@ static void gator_events_meminfo_stop(void)
145 } 146 }
146} 147}
147 148
148// Must be run in a work queue as the kernel function si_meminfo() can sleep 149// Must be run in process context (work queue) as the kernel function si_meminfo() can sleep
149static void wq_sched_handler(struct work_struct *wsptr) 150static void wq_sched_handler(struct work_struct *wsptr)
150{ 151{
151 struct sysinfo info; 152 struct sysinfo info;
@@ -189,7 +190,11 @@ static int gator_events_meminfo_read(long long **buffer)
189 190
190 if (last_mem_event != mem_event) { 191 if (last_mem_event != mem_event) {
191 last_mem_event = mem_event; 192 last_mem_event = mem_event;
192 schedule_work(&work); 193 if (in_interrupt()) {
194 schedule_work(&work);
195 } else {
196 wq_sched_handler(NULL);
197 }
193 } 198 }
194 199
195 if (!new_data_avail) 200 if (!new_data_avail)
diff --git a/driver/gator_events_mmaped.c b/driver/gator_events_mmaped.c
index cbb22b1..f81c402 100644
--- a/driver/gator_events_mmaped.c
+++ b/driver/gator_events_mmaped.c
@@ -14,11 +14,12 @@
14 * <counter_set name="mmaped_cntX"> 14 * <counter_set name="mmaped_cntX">
15 * <counter name="mmaped_cnt0"/> 15 * <counter name="mmaped_cnt0"/>
16 * <counter name="mmaped_cnt1"/> 16 * <counter name="mmaped_cnt1"/>
17 * <counter name="mmaped_cnt2"/>
17 * </counter_set> 18 * </counter_set>
18 * <category name="mmaped" counter_set="mmaped_cntX" per_cpu="no"> 19 * <category name="mmaped" counter_set="mmaped_cntX" per_cpu="no">
19 * <event event="0x0" title="Simulated" name="Sine" description="Sort-of-sine"/> 20 * <event event="0x0" title="Simulated" name="Sine" display="maximum" average_selection="yes" description="Sort-of-sine"/>
20 * <event event="0x1" title="Simulated" name="Triangle" description="Triangular wave"/> 21 * <event event="0x1" title="Simulated" name="Triangle" display="maximum" average_selection="yes" description="Triangular wave"/>
21 * <event event="0x2" title="Simulated" name="PWM" description="PWM Signal"/> 22 * <event event="0x2" title="Simulated" name="PWM" display="maximum" average_selection="yes" description="PWM Signal"/>
22 * </category> 23 * </category>
23 */ 24 */
24 25
@@ -42,6 +43,10 @@ static int mmaped_buffer[MMAPED_COUNTERS_NUM * 2];
42static void __iomem *mmaped_base; 43static void __iomem *mmaped_base;
43#endif 44#endif
44 45
46#ifndef TODO
47static s64 prev_time;
48#endif
49
45/* Adds mmaped_cntX directories and enabled, event, and key files to /dev/gator/events */ 50/* Adds mmaped_cntX directories and enabled, event, and key files to /dev/gator/events */
46static int gator_events_mmaped_create_files(struct super_block *sb, 51static int gator_events_mmaped_create_files(struct super_block *sb,
47 struct dentry *root) 52 struct dentry *root)
@@ -77,6 +82,12 @@ static int gator_events_mmaped_start(void)
77 writel(ENABLED, COUNTERS_CONTROL_OFFSET); 82 writel(ENABLED, COUNTERS_CONTROL_OFFSET);
78#endif 83#endif
79 84
85#ifndef TODO
86 struct timespec ts;
87 getnstimeofday(&ts);
88 prev_time = timespec_to_ns(&ts);
89#endif
90
80 return 0; 91 return 0;
81} 92}
82 93
@@ -90,50 +101,60 @@ static void gator_events_mmaped_stop(void)
90#ifndef TODO 101#ifndef TODO
91/* This function "simulates" counters, generating values of fancy 102/* This function "simulates" counters, generating values of fancy
92 * functions like sine or triangle... */ 103 * functions like sine or triangle... */
93static int mmaped_simulate(int counter) 104static int mmaped_simulate(int counter, int delta_in_us)
94{ 105{
95 int result = 0; 106 int result = 0;
96 107
97 switch (counter) { 108 switch (counter) {
98 case 0: /* sort-of-sine */ 109 case 0: /* sort-of-sine */
99 { 110 {
100 static int t; 111 static int t = 0;
101 int x; 112 int x;
102 113
103 if (t % 1024 < 512) 114 t += delta_in_us;
104 x = 512 - (t % 512); 115 if (t > 2048000)
116 t = 0;
117
118 if (t % 1024000 < 512000)
119 x = 512000 - (t % 512000);
105 else 120 else
106 x = t % 512; 121 x = t % 512000;
107 122
108 result = 32 * x / 512; 123 result = 32 * x / 512000;
109 result = result * result; 124 result = result * result;
110 125
111 if (t < 1024) 126 if (t < 1024000)
112 result = 1922 - result; 127 result = 1922 - result;
113
114 t = (t + 1) % 2048;
115 } 128 }
116 break; 129 break;
117 case 1: /* triangle */ 130 case 1: /* triangle */
118 { 131 {
119 static int v, d = 1; 132 static int v, d = 1;
120 133
121 v += d; 134 v = v + d * delta_in_us;
122 if (v % 2000 == 0) 135 if (v < 0) {
123 d = -d; 136 v = 0;
137 d = 1;
138 } else if (v > 1000000) {
139 v = 1000000;
140 d = -1;
141 }
124 142
125 result = v; 143 result = v;
126 } 144 }
127 break; 145 break;
128 case 2: /* PWM signal */ 146 case 2: /* PWM signal */
129 { 147 {
130 static int t, dc; 148 static int t, dc, x;
131 149
132 t = (t + 1) % 2000; 150 t += delta_in_us;
133 if (t % 100) 151 if (t > 1000000)
134 dc = (dc + 200) % 2000; 152 t = 0;
153 if (x / 1000000 != (x + delta_in_us) / 1000000)
154 dc = (dc + 100000) % 1000000;
155 x += delta_in_us;
135 156
136 result = t < dc ? 0 : 2000; 157 result = t < dc ? 0 : 10;
137 } 158 }
138 break; 159 break;
139 } 160 }
@@ -146,11 +167,23 @@ static int gator_events_mmaped_read(int **buffer)
146{ 167{
147 int i; 168 int i;
148 int len = 0; 169 int len = 0;
170#ifndef TODO
171 int delta_in_us;
172 struct timespec ts;
173 s64 time;
174#endif
149 175
150 /* System wide counters - read from one core only */ 176 /* System wide counters - read from one core only */
151 if (smp_processor_id()) 177 if (smp_processor_id())
152 return 0; 178 return 0;
153 179
180#ifndef TODO
181 getnstimeofday(&ts);
182 time = timespec_to_ns(&ts);
183 delta_in_us = (int)(time - prev_time) / 1000;
184 prev_time = time;
185#endif
186
154 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) { 187 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
155 if (mmaped_counters[i].enabled) { 188 if (mmaped_counters[i].enabled) {
156 mmaped_buffer[len++] = mmaped_counters[i].key; 189 mmaped_buffer[len++] = mmaped_counters[i].key;
@@ -159,7 +192,7 @@ static int gator_events_mmaped_read(int **buffer)
159 COUNTERS_VALUE_OFFSET[i]); 192 COUNTERS_VALUE_OFFSET[i]);
160#else 193#else
161 mmaped_buffer[len++] = mmaped_simulate( 194 mmaped_buffer[len++] = mmaped_simulate(
162 mmaped_counters[i].event); 195 mmaped_counters[i].event, delta_in_us);
163#endif 196#endif
164 } 197 }
165 } 198 }
diff --git a/driver/gator_events_net.c b/driver/gator_events_net.c
index ef1623b..9298905 100644
--- a/driver/gator_events_net.c
+++ b/driver/gator_events_net.c
@@ -9,6 +9,7 @@
9 9
10#include "gator.h" 10#include "gator.h"
11#include <linux/netdevice.h> 11#include <linux/netdevice.h>
12#include <linux/hardirq.h>
12 13
13#define NETRX 0 14#define NETRX 0
14#define NETTX 1 15#define NETTX 1
@@ -20,7 +21,7 @@ static ulong netrx_key;
20static ulong nettx_key; 21static ulong nettx_key;
21static int rx_total, tx_total; 22static int rx_total, tx_total;
22static ulong netPrev[TOTALNET]; 23static ulong netPrev[TOTALNET];
23static int netGet[TOTALNET * 2]; 24static int netGet[TOTALNET * 4];
24 25
25static void get_network_stats(struct work_struct *wsptr) { 26static void get_network_stats(struct work_struct *wsptr) {
26 int rx = 0, tx = 0; 27 int rx = 0, tx = 0;
@@ -102,19 +103,31 @@ static int gator_events_net_read(int **buffer)
102 if (smp_processor_id() != 0) 103 if (smp_processor_id() != 0)
103 return 0; 104 return 0;
104 105
105 schedule_work(&wq_get_stats); 106 if (!netrx_enabled && !nettx_enabled)
107 return 0;
108
109 if (in_interrupt()){
110 schedule_work(&wq_get_stats);
111 } else {
112 get_network_stats(NULL);
113 }
114
106 calculate_delta(&rx_delta, &tx_delta); 115 calculate_delta(&rx_delta, &tx_delta);
107 116
108 len = 0; 117 len = 0;
109 if (netrx_enabled && last_rx_delta != rx_delta) { 118 if (netrx_enabled && last_rx_delta != rx_delta) {
110 last_rx_delta = rx_delta; 119 last_rx_delta = rx_delta;
111 netGet[len++] = netrx_key; 120 netGet[len++] = netrx_key;
121 netGet[len++] = 0; // indicates to Streamline that rx_delta bytes were transmitted now, not since the last message
122 netGet[len++] = netrx_key;
112 netGet[len++] = rx_delta; 123 netGet[len++] = rx_delta;
113 } 124 }
114 125
115 if (nettx_enabled && last_tx_delta != tx_delta) { 126 if (nettx_enabled && last_tx_delta != tx_delta) {
116 last_tx_delta = tx_delta; 127 last_tx_delta = tx_delta;
117 netGet[len++] = nettx_key; 128 netGet[len++] = nettx_key;
129 netGet[len++] = 0; // indicates to Streamline that tx_delta bytes were transmitted now, not since the last message
130 netGet[len++] = nettx_key;
118 netGet[len++] = tx_delta; 131 netGet[len++] = tx_delta;
119 } 132 }
120 133
diff --git a/driver/gator_events_perf_pmu.c b/driver/gator_events_perf_pmu.c
index 322ebc4..da76a9c 100644..100755
--- a/driver/gator_events_perf_pmu.c
+++ b/driver/gator_events_perf_pmu.c
@@ -19,6 +19,8 @@ int ccnt = 0;
19 19
20#define CNTMAX (6+1) 20#define CNTMAX (6+1)
21 21
22static DEFINE_MUTEX(perf_mutex);
23
22unsigned long pmnc_enabled[CNTMAX]; 24unsigned long pmnc_enabled[CNTMAX];
23unsigned long pmnc_event[CNTMAX]; 25unsigned long pmnc_event[CNTMAX];
24unsigned long pmnc_count[CNTMAX]; 26unsigned long pmnc_count[CNTMAX];
@@ -122,12 +124,20 @@ static void gator_events_perf_pmu_online_dispatch(int cpu)
122static void gator_events_perf_pmu_offline_dispatch(int cpu) 124static void gator_events_perf_pmu_offline_dispatch(int cpu)
123{ 125{
124 int cnt; 126 int cnt;
127 struct perf_event * pe;
125 128
126 for (cnt = 0; cnt < pmnc_counters; cnt++) { 129 for (cnt = 0; cnt < pmnc_counters; cnt++) {
127 if (per_cpu(pevent, cpu)[cnt] != NULL) { 130 pe = NULL;
128 perf_event_release_kernel(per_cpu(pevent, cpu)[cnt]); 131 mutex_lock(&perf_mutex);
132 if (per_cpu(pevent, cpu)[cnt]) {
133 pe = per_cpu(pevent, cpu)[cnt];
129 per_cpu(pevent, cpu)[cnt] = NULL; 134 per_cpu(pevent, cpu)[cnt] = NULL;
130 } 135 }
136 mutex_unlock(&perf_mutex);
137
138 if (pe) {
139 perf_event_release_kernel(pe);
140 }
131 } 141 }
132} 142}
133 143
@@ -139,7 +149,7 @@ static int gator_events_perf_pmu_start(void)
139 for_each_present_cpu(cpu) { 149 for_each_present_cpu(cpu) {
140 for (cnt = 0; cnt < pmnc_counters; cnt++) { 150 for (cnt = 0; cnt < pmnc_counters; cnt++) {
141 per_cpu(pevent, cpu)[cnt] = NULL; 151 per_cpu(pevent, cpu)[cnt] = NULL;
142 if (!pmnc_enabled[cnt] || pmnc_count[cnt] > 0) // Skip disabled counters and EBS counters 152 if (!pmnc_enabled[cnt]) // Skip disabled counters
143 continue; 153 continue;
144 154
145 per_cpu(perfPrev, cpu)[cnt] = 0; 155 per_cpu(perfPrev, cpu)[cnt] = 0;
diff --git a/driver/gator_events_power.c b/driver/gator_events_power.c
deleted file mode 100644
index a0ae684..0000000
--- a/driver/gator_events_power.c
+++ /dev/null
@@ -1,178 +0,0 @@
1/**
2 * Copyright (C) ARM Limited 2011-2012. 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 */
9
10#include "gator.h"
11#include <linux/slab.h>
12#include <linux/cpufreq.h>
13#include <trace/events/power.h>
14
15// cpu_frequency and cpu_idle trace points were introduced in Linux kernel v2.6.38
16// the now deprecated power_frequency trace point was available prior to 2.6.38, but only for x86
17// CPU Idle is currently disabled in the .xml
18#if GATOR_CPU_FREQ_SUPPORT
19enum {
20 POWER_CPU_FREQ,
21 POWER_CPU_IDLE,
22 POWER_TOTAL
23};
24
25static ulong power_cpu_enabled[POWER_TOTAL];
26static ulong power_cpu_key[POWER_TOTAL];
27static DEFINE_PER_CPU(ulong[POWER_TOTAL], power);
28static DEFINE_PER_CPU(ulong[POWER_TOTAL], prev);
29static DEFINE_PER_CPU(int *, powerGet);
30
31GATOR_DEFINE_PROBE(cpu_frequency, TP_PROTO(unsigned int frequency, unsigned int cpu))
32{
33 per_cpu(power, cpu)[POWER_CPU_FREQ] = frequency * 1000;
34}
35
36GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu))
37{
38 per_cpu(power, cpu)[POWER_CPU_IDLE] = state;
39}
40
41static int gator_events_power_create_files(struct super_block *sb, struct dentry *root)
42{
43 struct dentry *dir;
44
45 // cpu_frequency
46 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_freq");
47 if (!dir) {
48 return -1;
49 }
50 gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_FREQ]);
51 gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_FREQ]);
52
53 // cpu_idle
54 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_idle");
55 if (!dir) {
56 return -1;
57 }
58 gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_IDLE]);
59 gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_IDLE]);
60
61 return 0;
62}
63
64static int gator_events_power_populate(int cpu, int** buffer)
65{
66 int i, len = 0;
67
68 for (i = 0; i < POWER_TOTAL; i++) {
69 if (power_cpu_enabled[i]) {
70 if (per_cpu(power, cpu)[i] != per_cpu(prev, cpu)[i]) {
71 per_cpu(prev, cpu)[i] = per_cpu(power, cpu)[i];
72 per_cpu(powerGet, cpu)[len++] = power_cpu_key[i];
73 per_cpu(powerGet, cpu)[len++] = per_cpu(power, cpu)[i];
74 }
75 }
76 }
77
78 if (buffer)
79 *buffer = per_cpu(powerGet, cpu);
80
81 return len;
82}
83
84static int gator_events_power_online(int** buffer)
85{
86 int i, cpu = smp_processor_id();
87 for (i = 0; i < POWER_TOTAL; i++)
88 per_cpu(prev, cpu)[i] = -1;
89 per_cpu(power, cpu)[POWER_CPU_FREQ] = cpufreq_quick_get(cpu) * 1000;
90 return gator_events_power_populate(cpu, buffer);
91}
92
93static int gator_events_power_offline(int** buffer)
94{
95 int cpu = smp_processor_id();
96 // Set frequency to zero on an offline
97 per_cpu(power, cpu)[POWER_CPU_FREQ] = 0;
98 return gator_events_power_populate(cpu, buffer);
99}
100
101static int gator_events_power_start(void)
102{
103 int cpu;
104
105 for_each_present_cpu(cpu) {
106 per_cpu(powerGet, cpu) = kmalloc(POWER_TOTAL * 2, GFP_KERNEL);
107 if (!per_cpu(powerGet, cpu))
108 return -1;
109 }
110
111 // register tracepoints
112 if (power_cpu_enabled[POWER_CPU_FREQ])
113 if (GATOR_REGISTER_TRACE(cpu_frequency))
114 goto fail_cpu_frequency_exit;
115 if (power_cpu_enabled[POWER_CPU_IDLE])
116 if (GATOR_REGISTER_TRACE(cpu_idle))
117 goto fail_cpu_idle_exit;
118 pr_debug("gator: registered power event tracepoints\n");
119
120 return 0;
121
122 // unregister tracepoints on error
123fail_cpu_idle_exit:
124 GATOR_UNREGISTER_TRACE(cpu_frequency);
125fail_cpu_frequency_exit:
126 pr_err("gator: power event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
127
128 return -1;
129}
130
131static void gator_events_power_stop(void)
132{
133 int i, cpu;
134 if (power_cpu_enabled[POWER_CPU_FREQ])
135 GATOR_UNREGISTER_TRACE(cpu_frequency);
136 if (power_cpu_enabled[POWER_CPU_IDLE])
137 GATOR_UNREGISTER_TRACE(cpu_idle);
138 pr_debug("gator: unregistered power event tracepoints\n");
139
140 for (i = 0; i < POWER_TOTAL; i++) {
141 power_cpu_enabled[i] = 0;
142 }
143
144 for_each_present_cpu(cpu) {
145 kfree(per_cpu(powerGet, cpu));
146 }
147}
148
149static int gator_events_power_read(int **buffer)
150{
151 return gator_events_power_populate(smp_processor_id(), buffer);
152}
153
154static struct gator_interface gator_events_power_interface = {
155 .create_files = gator_events_power_create_files,
156 .online = gator_events_power_online,
157 .offline = gator_events_power_offline,
158 .start = gator_events_power_start,
159 .stop = gator_events_power_stop,
160 .read = gator_events_power_read,
161};
162#endif
163
164int gator_events_power_init(void)
165{
166#if (GATOR_CPU_FREQ_SUPPORT)
167 int i;
168 for (i = 0; i < POWER_TOTAL; i++) {
169 power_cpu_enabled[i] = 0;
170 power_cpu_key[i] = gator_events_get_key();
171 }
172
173 return gator_events_install(&gator_events_power_interface);
174#else
175 return -1;
176#endif
177}
178gator_events_init(gator_events_power_init);
diff --git a/driver/gator_events_scorpion.c b/driver/gator_events_scorpion.c
index 477e7c9..ed0d8de 100644
--- a/driver/gator_events_scorpion.c
+++ b/driver/gator_events_scorpion.c
@@ -34,7 +34,6 @@ static unsigned long pmnc_enabled[CNTMAX];
34static unsigned long pmnc_event[CNTMAX]; 34static unsigned long pmnc_event[CNTMAX];
35static unsigned long pmnc_key[CNTMAX]; 35static unsigned long pmnc_key[CNTMAX];
36 36
37static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
38static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt); 37static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
39 38
40enum scorpion_perf_types { 39enum scorpion_perf_types {
@@ -538,8 +537,6 @@ static int gator_events_scorpion_online(int** buffer)
538 for (cnt = CCNT; cnt < CNTMAX; cnt++) { 537 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
539 unsigned long event; 538 unsigned long event;
540 539
541 per_cpu(perfPrev, smp_processor_id())[cnt] = 0;
542
543 if (!pmnc_enabled[cnt]) 540 if (!pmnc_enabled[cnt])
544 continue; 541 continue;
545 542
@@ -574,7 +571,7 @@ static int gator_events_scorpion_online(int** buffer)
574 value = 0; 571 value = 0;
575 } 572 }
576 scorpion_pmnc_reset_counter(cnt); 573 scorpion_pmnc_reset_counter(cnt);
577 per_cpu(perfPrev, cpu)[cnt] = 0; 574
578 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; 575 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
579 per_cpu(perfCnt, cpu)[len++] = 0; 576 per_cpu(perfCnt, cpu)[len++] = 0;
580 } 577 }
@@ -607,6 +604,11 @@ static int gator_events_scorpion_read(int **buffer)
607 int cnt, len = 0; 604 int cnt, len = 0;
608 int cpu = smp_processor_id(); 605 int cpu = smp_processor_id();
609 606
607 // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
608 if (!(scorpion_pmnc_read() & PMNC_E)) {
609 return 0;
610 }
611
610 for (cnt = 0; cnt < pmnc_counters; cnt++) { 612 for (cnt = 0; cnt < pmnc_counters; cnt++) {
611 if (pmnc_enabled[cnt]) { 613 if (pmnc_enabled[cnt]) {
612 int value; 614 int value;
@@ -618,11 +620,9 @@ static int gator_events_scorpion_read(int **buffer)
618 value = 0; 620 value = 0;
619 } 621 }
620 scorpion_pmnc_reset_counter(cnt); 622 scorpion_pmnc_reset_counter(cnt);
621 if (value != per_cpu(perfPrev, cpu)[cnt]) { 623
622 per_cpu(perfPrev, cpu)[cnt] = value; 624 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
623 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; 625 per_cpu(perfCnt, cpu)[len++] = value;
624 per_cpu(perfCnt, cpu)[len++] = value;
625 }
626 } 626 }
627 } 627 }
628 628
diff --git a/driver/gator_fs.c b/driver/gator_fs.c
index 8277c3a..39adfbe 100644
--- a/driver/gator_fs.c
+++ b/driver/gator_fs.c
@@ -233,9 +233,17 @@ static int gatorfs_fill_super(struct super_block *sb, void *data, int silent)
233 return -ENOMEM; 233 return -ENOMEM;
234 root_inode->i_op = &simple_dir_inode_operations; 234 root_inode->i_op = &simple_dir_inode_operations;
235 root_inode->i_fop = &simple_dir_operations; 235 root_inode->i_fop = &simple_dir_operations;
236
237#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
236 root_dentry = d_alloc_root(root_inode); 238 root_dentry = d_alloc_root(root_inode);
239#else
240 root_dentry = d_make_root(root_inode);
241#endif
242
237 if (!root_dentry) { 243 if (!root_dentry) {
244#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
238 iput(root_inode); 245 iput(root_inode);
246#endif
239 return -ENOMEM; 247 return -ENOMEM;
240 } 248 }
241 249
diff --git a/driver/gator_hrtimer_gator.c b/driver/gator_hrtimer_gator.c
index 5896b3c..846fba4 100644..100755
--- a/driver/gator_hrtimer_gator.c
+++ b/driver/gator_hrtimer_gator.c
@@ -13,6 +13,7 @@
13 13
14void (*callback)(void); 14void (*callback)(void);
15DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer); 15DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
16DEFINE_PER_CPU(int, hrtimer_is_active);
16static ktime_t profiling_interval; 17static ktime_t profiling_interval;
17static void gator_hrtimer_online(int cpu); 18static void gator_hrtimer_online(int cpu);
18static void gator_hrtimer_offline(int cpu); 19static void gator_hrtimer_offline(int cpu);
@@ -32,11 +33,16 @@ static void gator_hrtimer_switch_cpus_online(void *unused)
32static void gator_hrtimer_online(int cpu) 33static void gator_hrtimer_online(int cpu)
33{ 34{
34 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); 35 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
36
35 if (cpu != smp_processor_id()) { 37 if (cpu != smp_processor_id()) {
36 smp_call_function_single(cpu, gator_hrtimer_switch_cpus_online, NULL, 1); 38 smp_call_function_single(cpu, gator_hrtimer_switch_cpus_online, NULL, 1);
37 return; 39 return;
38 } 40 }
39 41
42 if (per_cpu(hrtimer_is_active, cpu) || profiling_interval.tv64 == 0)
43 return;
44
45 per_cpu(hrtimer_is_active, cpu) = 1;
40 hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 46 hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
41 hrtimer->function = gator_hrtimer_notify; 47 hrtimer->function = gator_hrtimer_notify;
42 hrtimer_start(hrtimer, profiling_interval, HRTIMER_MODE_REL_PINNED); 48 hrtimer_start(hrtimer, profiling_interval, HRTIMER_MODE_REL_PINNED);
@@ -50,20 +56,35 @@ static void gator_hrtimer_switch_cpus_offline(void *unused)
50static void gator_hrtimer_offline(int cpu) 56static void gator_hrtimer_offline(int cpu)
51{ 57{
52 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); 58 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
59
53 if (cpu != smp_processor_id()) { 60 if (cpu != smp_processor_id()) {
54 smp_call_function_single(cpu, gator_hrtimer_switch_cpus_offline, NULL, 1); 61 smp_call_function_single(cpu, gator_hrtimer_switch_cpus_offline, NULL, 1);
55 return; 62 return;
56 } 63 }
57 64
65 if (!per_cpu(hrtimer_is_active, cpu))
66 return;
67
68 per_cpu(hrtimer_is_active, cpu) = 0;
58 hrtimer_cancel(hrtimer); 69 hrtimer_cancel(hrtimer);
59} 70}
60 71
61static int gator_hrtimer_init(int interval, void (*func)(void)) 72static int gator_hrtimer_init(int interval, void (*func)(void))
62{ 73{
74 int cpu;
75
63 (callback) = (func); 76 (callback) = (func);
64 77
78 for_each_present_cpu(cpu) {
79 per_cpu(hrtimer_is_active, cpu) = 0;
80 }
81
65 // calculate profiling interval 82 // calculate profiling interval
66 profiling_interval = ns_to_ktime(1000000000UL / interval); 83 if (interval > 0) {
84 profiling_interval = ns_to_ktime(1000000000UL / interval);
85 } else {
86 profiling_interval.tv64 = 0;
87 }
67 88
68 return 0; 89 return 0;
69} 90}
diff --git a/driver/gator_main.c b/driver/gator_main.c
index fff2d19..7d48812 100644
--- a/driver/gator_main.c
+++ b/driver/gator_main.c
@@ -7,7 +7,7 @@
7 * 7 *
8 */ 8 */
9 9
10static unsigned long gator_protocol_version = 8; 10static unsigned long gator_protocol_version = 9;
11 11
12#include <linux/slab.h> 12#include <linux/slab.h>
13#include <linux/cpu.h> 13#include <linux/cpu.h>
@@ -39,7 +39,7 @@ static unsigned long gator_protocol_version = 8;
39#endif 39#endif
40 40
41#ifndef CONFIG_HIGH_RES_TIMERS 41#ifndef CONFIG_HIGH_RES_TIMERS
42#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined 42#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined to support PC sampling
43#endif 43#endif
44 44
45#if defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) 45#if defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
@@ -48,37 +48,39 @@ static unsigned long gator_protocol_version = 8;
48 48
49#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT)) 49#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT))
50#ifndef CONFIG_PERF_EVENTS 50#ifndef CONFIG_PERF_EVENTS
51#warning gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters 51#error gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
52#elif !defined CONFIG_HW_PERF_EVENTS 52#elif !defined CONFIG_HW_PERF_EVENTS
53#warning gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters 53#error gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
54#endif 54#endif
55#endif 55#endif
56 56
57#if (!(GATOR_CPU_FREQ_SUPPORT))
58#warning gator requires kernel version 2.6.38 or greater and CONFIG_CPU_FREQ defined in order to enable the CPU Freq timeline chart
59#endif
60
61/****************************************************************************** 57/******************************************************************************
62 * DEFINES 58 * DEFINES
63 ******************************************************************************/ 59 ******************************************************************************/
64#define TIMER_BUFFER_SIZE_DEFAULT (512*1024) 60#define BACKTRACE_BUFFER_SIZE (128*1024)
65#define EVENT_BUFFER_SIZE_DEFAULT (128*1024) 61#define COUNTER_BUFFER_SIZE (128*1024)
62#define ANNOTATE_BUFFER_SIZE (64*1024) // annotate counters have the core as part of the data and the core value in the frame header may be discarded
63#define SCHED_TRACE_BUFFER_SIZE (128*1024)
64#define GPU_TRACE_BUFFER_SIZE (64*1024)
65#define COUNTER2_BUFFER_SIZE (64*1024) // counters2 counters have the core as part of the data and the core value in the frame header may be discarded
66#define WFI_BUFFER_SIZE (32*1024) // wfi counters have the core as part of the data and the core value in the frame header may be discarded
66 67
67#define NO_COOKIE 0UL 68#define NO_COOKIE 0UL
68#define INVALID_COOKIE ~0UL 69#define INVALID_COOKIE ~0UL
69 70
70#define FRAME_HRTIMER 1 71#define FRAME_BACKTRACE 1
71#define FRAME_EVENT 2 72#define FRAME_COUNTER 2
72#define FRAME_ANNOTATE 3 73#define FRAME_ANNOTATE 3
74#define FRAME_SCHED_TRACE 4
75#define FRAME_GPU_TRACE 5
76#define FRAME_COUNTER2 6
77#define FRAME_WFI 7
73 78
74#define MESSAGE_COOKIE 1 79#define MESSAGE_COOKIE 1
75#define MESSAGE_COUNTERS 3 80#define MESSAGE_START_BACKTRACE 5
76#define MESSAGE_START_BACKTRACE 5 81#define MESSAGE_END_BACKTRACE 7
77#define MESSAGE_END_BACKTRACE 7 82#define MESSAGE_SUMMARY 9
78#define MESSAGE_SCHEDULER_TRACE 9 83#define MESSAGE_PID_NAME 11
79#define MESSAGE_PID_NAME 11
80#define MESSAGE_GPU_TRACE 13
81#define MESSAGE_OVERFLOW 127
82 84
83#define MAXSIZE_PACK32 5 85#define MAXSIZE_PACK32 5
84#define MAXSIZE_PACK64 9 86#define MAXSIZE_PACK64 9
@@ -89,7 +91,7 @@ static unsigned long gator_protocol_version = 8;
89#define PC_REG regs->ip 91#define PC_REG regs->ip
90#endif 92#endif
91 93
92enum {TIMER_BUF, EVENT_BUF, NUM_GATOR_BUFS}; 94enum {BACKTRACE_BUF, COUNTER_BUF, SCHED_TRACE_BUF, GPU_TRACE_BUF, ANNOTATE_BUF, COUNTER2_BUF, WFI_BUF, NUM_GATOR_BUFS};
93 95
94/****************************************************************************** 96/******************************************************************************
95 * Globals 97 * Globals
@@ -101,25 +103,26 @@ static unsigned long gator_backtrace_depth;
101static unsigned long gator_started; 103static unsigned long gator_started;
102static unsigned long gator_buffer_opened; 104static unsigned long gator_buffer_opened;
103static unsigned long gator_timer_count; 105static unsigned long gator_timer_count;
104static unsigned long gator_streaming; 106static unsigned long gator_response_type;
105static DEFINE_MUTEX(start_mutex); 107static DEFINE_MUTEX(start_mutex);
106static DEFINE_MUTEX(gator_buffer_mutex); 108static DEFINE_MUTEX(gator_buffer_mutex);
107 109
108bool event_based_sampling; 110bool event_based_sampling;
109 111
110static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait); 112static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
111 113static LIST_HEAD(gator_events);
112static void buffer_check(int cpu, int buftype);
113 114
114/****************************************************************************** 115/******************************************************************************
115 * Prototypes 116 * Prototypes
116 ******************************************************************************/ 117 ******************************************************************************/
118static void buffer_check(int cpu, int buftype);
119static int buffer_bytes_available(int cpu, int buftype);
117static bool buffer_check_space(int cpu, int buftype, int bytes); 120static bool buffer_check_space(int cpu, int buftype, int bytes);
121static int contiguous_space_available(int cpu, int bufytpe);
118static void gator_buffer_write_packed_int(int cpu, int buftype, unsigned int x); 122static void gator_buffer_write_packed_int(int cpu, int buftype, unsigned int x);
119static void gator_buffer_write_packed_int64(int cpu, int buftype, unsigned long long x); 123static void gator_buffer_write_packed_int64(int cpu, int buftype, unsigned long long x);
124static void gator_buffer_write_bytes(int cpu, int buftype, char *x, int len);
120static void gator_buffer_write_string(int cpu, int buftype, char *x); 125static void gator_buffer_write_string(int cpu, int buftype, char *x);
121static int gator_write_packed_int(char *buffer, unsigned int x);
122static int gator_write_packed_int64(char *buffer, unsigned long long x);
123static void gator_add_trace(int cpu, int buftype, unsigned int address); 126static void gator_add_trace(int cpu, int buftype, unsigned int address);
124static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs); 127static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs);
125static uint64_t gator_get_time(void); 128static uint64_t gator_get_time(void);
@@ -131,15 +134,16 @@ static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_write);
131static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_commit); 134static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_commit);
132static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], buffer_space_available); 135static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], buffer_space_available);
133static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer); 136static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer);
134static DEFINE_PER_CPU(uint64_t, emit_overflow);
135 137
136/****************************************************************************** 138/******************************************************************************
137 * Application Includes 139 * Application Includes
138 ******************************************************************************/ 140 ******************************************************************************/
141#include "gator_marshaling.c"
139#include "gator_hrtimer_perf.c" 142#include "gator_hrtimer_perf.c"
140#include "gator_hrtimer_gator.c" 143#include "gator_hrtimer_gator.c"
141#include "gator_cookies.c" 144#include "gator_cookies.c"
142#include "gator_trace_sched.c" 145#include "gator_trace_sched.c"
146#include "gator_trace_power.c"
143#include "gator_trace_gpu.c" 147#include "gator_trace_gpu.c"
144#include "gator_backtrace.c" 148#include "gator_backtrace.c"
145#include "gator_annotate.c" 149#include "gator_annotate.c"
@@ -179,10 +183,10 @@ static bool buffer_commit_ready(int* cpu, int* buftype)
179/****************************************************************************** 183/******************************************************************************
180 * Buffer management 184 * Buffer management
181 ******************************************************************************/ 185 ******************************************************************************/
182static bool buffer_check_space(int cpu, int buftype, int bytes) 186static int buffer_bytes_available(int cpu, int buftype)
183{ 187{
184 int remaining, filled; 188 int remaining, filled;
185 189
186 filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype]; 190 filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype];
187 if (filled < 0) { 191 if (filled < 0) {
188 filled += gator_buffer_size[buftype]; 192 filled += gator_buffer_size[buftype];
@@ -198,12 +202,24 @@ static bool buffer_check_space(int cpu, int buftype, int bytes)
198 remaining -= 2000; 202 remaining -= 2000;
199 } 203 }
200 204
205 return remaining;
206}
207
208static int contiguous_space_available(int cpu, int buftype)
209{
210 int remaining = buffer_bytes_available(cpu, buftype);
211 int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype];
212 if (remaining < contiguous)
213 return remaining;
214 else
215 return contiguous;
216}
217
218static bool buffer_check_space(int cpu, int buftype, int bytes)
219{
220 int remaining = buffer_bytes_available(cpu, buftype);
221
201 if (remaining < bytes) { 222 if (remaining < bytes) {
202 if (per_cpu(buffer_space_available, cpu)[buftype] == true) {
203 // overflow packet to be emitted at a later time, as we may be in the middle of writing a message, e.g. counters
204 per_cpu(emit_overflow, cpu) = gator_get_time();
205 pr_err("overflow: remaining = %d\n", gator_buffer_size[buftype] - filled);
206 }
207 per_cpu(buffer_space_available, cpu)[buftype] = false; 223 per_cpu(buffer_space_available, cpu)[buftype] = false;
208 } else { 224 } else {
209 per_cpu(buffer_space_available, cpu)[buftype] = true; 225 per_cpu(buffer_space_available, cpu)[buftype] = true;
@@ -238,19 +254,33 @@ static void gator_buffer_header(int cpu, int buftype)
238{ 254{
239 int frame; 255 int frame;
240 256
241 if (buftype == TIMER_BUF) 257 if (buftype == BACKTRACE_BUF)
242 frame = FRAME_HRTIMER; 258 frame = FRAME_BACKTRACE;
243 else if (buftype == EVENT_BUF) 259 else if (buftype == COUNTER_BUF)
244 frame = FRAME_EVENT; 260 frame = FRAME_COUNTER;
261 else if (buftype == ANNOTATE_BUF)
262 frame = FRAME_ANNOTATE;
263 else if (buftype == SCHED_TRACE_BUF)
264 frame = FRAME_SCHED_TRACE;
265 else if (buftype == GPU_TRACE_BUF)
266 frame = FRAME_GPU_TRACE;
267 else if (buftype == COUNTER2_BUF)
268 frame = FRAME_COUNTER2;
269 else if (buftype == WFI_BUF)
270 frame = FRAME_WFI;
245 else 271 else
246 frame = -1; 272 frame = -1;
247 273
248 gator_buffer_write_packed_int(cpu, buftype, frame); 274 if (per_cpu(gator_buffer, cpu)[buftype]) {
249 gator_buffer_write_packed_int(cpu, buftype, cpu); 275 marshal_frame(cpu, buftype, frame);
276 }
250} 277}
251 278
252static void gator_commit_buffer(int cpu, int buftype) 279static void gator_commit_buffer(int cpu, int buftype)
253{ 280{
281 if (!per_cpu(gator_buffer, cpu)[buftype])
282 return;
283
254 per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype]; 284 per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
255 gator_buffer_header(cpu, buftype); 285 gator_buffer_header(cpu, buftype);
256 wake_up(&gator_buffer_wait); 286 wake_up(&gator_buffer_wait);
@@ -276,8 +306,7 @@ static void gator_add_trace(int cpu, int buftype, unsigned int address)
276 offset = address; 306 offset = address;
277 } 307 }
278 308
279 gator_buffer_write_packed_int(cpu, buftype, offset & ~1); 309 marshal_backtrace(offset & ~1, cookie);
280 gator_buffer_write_packed_int(cpu, buftype, cookie);
281} 310}
282 311
283static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs) 312static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs)
@@ -288,12 +317,8 @@ static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs)
288 if (!regs) 317 if (!regs)
289 return; 318 return;
290 319
291 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_START_BACKTRACE); 320 if (!marshal_backtrace_header(exec_cookie, current->tgid, current->pid, inKernel))
292 gator_buffer_write_packed_int64(cpu, buftype, gator_get_time()); 321 return;
293 gator_buffer_write_packed_int(cpu, buftype, exec_cookie);
294 gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->tgid);
295 gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->pid);
296 gator_buffer_write_packed_int(cpu, buftype, inKernel);
297 322
298 if (inKernel) { 323 if (inKernel) {
299 kernel_backtrace(cpu, buftype, regs); 324 kernel_backtrace(cpu, buftype, regs);
@@ -306,142 +331,54 @@ static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs)
306 arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth); 331 arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth);
307 } 332 }
308 333
309 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_END_BACKTRACE); 334 marshal_backtrace_footer();
310} 335}
311 336
312/****************************************************************************** 337/******************************************************************************
313 * hrtimer interrupt processing 338 * hrtimer interrupt processing
314 ******************************************************************************/ 339 ******************************************************************************/
315static LIST_HEAD(gator_events);
316
317static void gator_timer_interrupt(void) 340static void gator_timer_interrupt(void)
318{ 341{
319 struct pt_regs * const regs = get_irq_regs(); 342 struct pt_regs * const regs = get_irq_regs();
320 int cpu = smp_processor_id(); 343 int cpu = smp_processor_id();
321 int *buffer, len, i, buftype = TIMER_BUF;
322 long long *buffer64;
323 struct gator_interface *gi;
324
325 // Output scheduler trace
326 len = gator_trace_sched_read(&buffer64);
327 if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
328 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_SCHEDULER_TRACE);
329 gator_buffer_write_packed_int(cpu, buftype, len);
330 for (i = 0; i < len; i++) {
331 gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
332 }
333 }
334
335 // Output GPU trace
336 len = gator_trace_gpu_read(&buffer64);
337 if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
338 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_GPU_TRACE);
339 gator_buffer_write_packed_int(cpu, buftype, len);
340 for (i = 0; i < len; i++) {
341 gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
342 }
343 }
344
345 // Output counters
346 if (buffer_check_space(cpu, buftype, MAXSIZE_PACK32 * 2 + MAXSIZE_PACK64)) {
347 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COUNTERS);
348 gator_buffer_write_packed_int64(cpu, buftype, gator_get_time());
349 list_for_each_entry(gi, &gator_events, list) {
350 if (gi->read) {
351 len = gi->read(&buffer);
352 if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK32 + MAXSIZE_PACK32)) {
353 gator_buffer_write_packed_int(cpu, buftype, len);
354 for (i = 0; i < len; i++) {
355 gator_buffer_write_packed_int(cpu, buftype, buffer[i]);
356 }
357 }
358 } else if (gi->read64) {
359 len = gi->read64(&buffer64);
360 if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK64 + MAXSIZE_PACK32)) {
361 gator_buffer_write_packed_int(cpu, buftype, len);
362 for (i = 0; i < len; i++) {
363 gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
364 }
365 }
366 }
367 }
368 gator_buffer_write_packed_int(cpu, buftype, 0);
369 }
370 344
371 // Output backtrace 345 // Output backtrace
372 if (!event_based_sampling && buffer_check_space(cpu, buftype, gator_backtrace_depth * 2 * MAXSIZE_PACK32)) 346 gator_add_sample(cpu, BACKTRACE_BUF, regs);
373 gator_add_sample(cpu, buftype, regs);
374
375 // Overflow message
376 if (per_cpu(emit_overflow, cpu)) {
377 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_OVERFLOW);
378 gator_buffer_write_packed_int64(cpu, buftype, per_cpu(emit_overflow, cpu));
379 per_cpu(emit_overflow, cpu) = 0;
380 }
381 347
382 // Check and commit; generally, commit is set to occur once per second 348 // Collect counters
383 buffer_check(cpu, buftype); 349 collect_counters();
384} 350}
385 351
386DEFINE_PER_CPU(int, hrtimer_is_active); 352static int gator_running;
387static int hrtimer_running;
388 353
389// This function runs in interrupt context and on the appropriate core 354// This function runs in interrupt context and on the appropriate core
390static void gator_timer_offline(void* unused) 355static void gator_timer_offline(void* unused)
391{ 356{
357 struct gator_interface *gi;
392 int i, len, cpu = smp_processor_id(); 358 int i, len, cpu = smp_processor_id();
393 int* buffer; 359 int* buffer;
394 long long* buffer64;
395
396 if (per_cpu(hrtimer_is_active, cpu)) {
397 struct gator_interface *gi;
398 gator_hrtimer_offline(cpu);
399 per_cpu(hrtimer_is_active, cpu) = 0;
400
401 // Output scheduler trace
402 len = gator_trace_sched_offline(&buffer64);
403 if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
404 gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_SCHEDULER_TRACE);
405 gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
406 for (i = 0; i < len; i++) {
407 gator_buffer_write_packed_int64(cpu, TIMER_BUF, buffer64[i]);
408 }
409 }
410 360
411 // Output GPU trace 361 gator_trace_sched_offline();
412 len = gator_trace_gpu_offline(&buffer64); 362 gator_trace_power_offline();
413 if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
414 gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_GPU_TRACE);
415 gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
416 for (i = 0; i < len; i++) {
417 gator_buffer_write_packed_int64(cpu, TIMER_BUF, buffer64[i]);
418 }
419 }
420 363
421 // offline any events and output counters 364 gator_hrtimer_offline(cpu);
422 gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_COUNTERS); 365
423 gator_buffer_write_packed_int64(cpu, TIMER_BUF, gator_get_time()); 366 // Offline any events and output counters
367 if (marshal_event_header()) {
424 list_for_each_entry(gi, &gator_events, list) { 368 list_for_each_entry(gi, &gator_events, list) {
425 if (gi->offline) { 369 if (gi->offline) {
426 len = gi->offline(&buffer); 370 len = gi->offline(&buffer);
427 if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK32 + MAXSIZE_PACK32)) { 371 marshal_event(len, buffer);
428 gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
429 for (i = 0; i < len; i++)
430 gator_buffer_write_packed_int(cpu, TIMER_BUF, buffer[i]);
431 }
432 } 372 }
433 } 373 }
434 gator_buffer_write_packed_int(cpu, TIMER_BUF, 0);
435
436 gator_commit_buffer(cpu, TIMER_BUF);
437 } 374 }
438 375
439 if (event_based_sampling) { 376 // Flush all buffers on this core
440 gator_commit_buffer(cpu, EVENT_BUF); 377 for (i = 0; i < NUM_GATOR_BUFS; i++)
441 } 378 gator_commit_buffer(cpu, i);
442} 379}
443 380
444// This function runs in interrupt context and may be running on a core other than core 'cpu' 381// This function runs in process context and may be running on a core other than core 'cpu'
445static void gator_timer_offline_dispatch(int cpu) 382static void gator_timer_offline_dispatch(int cpu)
446{ 383{
447 struct gator_interface *gi; 384 struct gator_interface *gi;
@@ -457,13 +394,13 @@ static void gator_timer_stop(void)
457{ 394{
458 int cpu; 395 int cpu;
459 396
460 if (hrtimer_running) { 397 if (gator_running) {
461 on_each_cpu(gator_timer_offline, NULL, 1); 398 on_each_cpu(gator_timer_offline, NULL, 1);
462 for_each_online_cpu(cpu) { 399 for_each_online_cpu(cpu) {
463 gator_timer_offline_dispatch(cpu); 400 gator_timer_offline_dispatch(cpu);
464 } 401 }
465 402
466 hrtimer_running = 0; 403 gator_running = 0;
467 gator_hrtimer_shutdown(); 404 gator_hrtimer_shutdown();
468 } 405 }
469} 406}
@@ -471,32 +408,23 @@ static void gator_timer_stop(void)
471// This function runs in interrupt context and on the appropriate core 408// This function runs in interrupt context and on the appropriate core
472static void gator_timer_online(void* unused) 409static void gator_timer_online(void* unused)
473{ 410{
474 int i, len, cpu = smp_processor_id(); 411 struct gator_interface *gi;
412 int len, cpu = smp_processor_id();
475 int* buffer; 413 int* buffer;
476 414
477 if (!per_cpu(hrtimer_is_active, cpu)) { 415 gator_trace_power_online();
478 struct gator_interface *gi;
479 416
480 // online any events and output counters 417 // online any events and output counters
481 gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_COUNTERS); 418 if (marshal_event_header()) {
482 gator_buffer_write_packed_int64(cpu, TIMER_BUF, gator_get_time());
483 list_for_each_entry(gi, &gator_events, list) { 419 list_for_each_entry(gi, &gator_events, list) {
484 if (gi->online) { 420 if (gi->online) {
485 len = gi->online(&buffer); 421 len = gi->online(&buffer);
486 if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK32 + MAXSIZE_PACK32)) { 422 marshal_event(len, buffer);
487 gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
488 for (i = 0; i < len; i++)
489 gator_buffer_write_packed_int(cpu, TIMER_BUF, buffer[i]);
490 }
491 } 423 }
492 } 424 }
493 gator_buffer_write_packed_int(cpu, TIMER_BUF, 0);
494
495 gator_event_sampling_online();
496
497 gator_hrtimer_online(cpu);
498 per_cpu(hrtimer_is_active, cpu) = 1;
499 } 425 }
426
427 gator_hrtimer_online(cpu);
500} 428}
501 429
502// This function runs in interrupt context and may be running on a core other than core 'cpu' 430// This function runs in interrupt context and may be running on a core other than core 'cpu'
@@ -511,21 +439,22 @@ static void gator_timer_online_dispatch(int cpu)
511 gator_event_sampling_online_dispatch(cpu); 439 gator_event_sampling_online_dispatch(cpu);
512} 440}
513 441
514int gator_timer_start(unsigned long setup) 442int gator_timer_start(unsigned long sample_rate)
515{ 443{
516 int cpu; 444 int cpu;
517 445
518 if (!setup) { 446 if (gator_running) {
519 pr_err("gator: cannot start due to a system tick value of zero\n"); 447 pr_notice("gator: already running\n");
520 return -1;
521 } else if (hrtimer_running) {
522 pr_notice("gator: high res timer already running\n");
523 return 0; 448 return 0;
524 } 449 }
525 450
526 hrtimer_running = 1; 451 gator_running = 1;
527 452
528 if (gator_hrtimer_init(setup, gator_timer_interrupt) == -1) 453 // event based sampling trumps hr timer based sampling
454 if (event_based_sampling)
455 sample_rate = 0;
456
457 if (gator_hrtimer_init(sample_rate, gator_timer_interrupt) == -1)
529 return -1; 458 return -1;
530 459
531 for_each_online_cpu(cpu) { 460 for_each_online_cpu(cpu) {
@@ -550,7 +479,7 @@ static uint64_t gator_get_time(void)
550/****************************************************************************** 479/******************************************************************************
551 * cpu hotplug and pm notifiers 480 * cpu hotplug and pm notifiers
552 ******************************************************************************/ 481 ******************************************************************************/
553static int __cpuinit gator_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) 482static int __cpuinit gator_hotcpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
554{ 483{
555 long cpu = (long)hcpu; 484 long cpu = (long)hcpu;
556 485
@@ -570,8 +499,8 @@ static int __cpuinit gator_cpu_notify(struct notifier_block *self, unsigned long
570 return NOTIFY_OK; 499 return NOTIFY_OK;
571} 500}
572 501
573static struct notifier_block __refdata gator_cpu_notifier = { 502static struct notifier_block __refdata gator_hotcpu_notifier = {
574 .notifier_call = gator_cpu_notify, 503 .notifier_call = gator_hotcpu_notify,
575}; 504};
576 505
577// n.b. calling "on_each_cpu" only runs on those that are online 506// n.b. calling "on_each_cpu" only runs on those that are online
@@ -583,7 +512,7 @@ static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void
583 switch (event) { 512 switch (event) {
584 case PM_HIBERNATION_PREPARE: 513 case PM_HIBERNATION_PREPARE:
585 case PM_SUSPEND_PREPARE: 514 case PM_SUSPEND_PREPARE:
586 unregister_hotcpu_notifier(&gator_cpu_notifier); 515 unregister_hotcpu_notifier(&gator_hotcpu_notifier);
587 unregister_scheduler_tracepoints(); 516 unregister_scheduler_tracepoints();
588 on_each_cpu(gator_timer_offline, NULL, 1); 517 on_each_cpu(gator_timer_offline, NULL, 1);
589 for_each_online_cpu(cpu) { 518 for_each_online_cpu(cpu) {
@@ -597,7 +526,7 @@ static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void
597 } 526 }
598 on_each_cpu(gator_timer_online, NULL, 1); 527 on_each_cpu(gator_timer_online, NULL, 1);
599 register_scheduler_tracepoints(); 528 register_scheduler_tracepoints();
600 register_hotcpu_notifier(&gator_cpu_notifier); 529 register_hotcpu_notifier(&gator_hotcpu_notifier);
601 break; 530 break;
602 } 531 }
603 532
@@ -611,7 +540,7 @@ static struct notifier_block gator_pm_notifier = {
611static int gator_notifier_start(void) 540static int gator_notifier_start(void)
612{ 541{
613 int retval; 542 int retval;
614 retval = register_hotcpu_notifier(&gator_cpu_notifier); 543 retval = register_hotcpu_notifier(&gator_hotcpu_notifier);
615 if (retval == 0) 544 if (retval == 0)
616 retval = register_pm_notifier(&gator_pm_notifier); 545 retval = register_pm_notifier(&gator_pm_notifier);
617 return retval; 546 return retval;
@@ -620,12 +549,30 @@ static int gator_notifier_start(void)
620static void gator_notifier_stop(void) 549static void gator_notifier_stop(void)
621{ 550{
622 unregister_pm_notifier(&gator_pm_notifier); 551 unregister_pm_notifier(&gator_pm_notifier);
623 unregister_hotcpu_notifier(&gator_cpu_notifier); 552 unregister_hotcpu_notifier(&gator_hotcpu_notifier);
624} 553}
625 554
626/****************************************************************************** 555/******************************************************************************
627 * Main 556 * Main
628 ******************************************************************************/ 557 ******************************************************************************/
558static void gator_summary(void)
559{
560 uint64_t timestamp, uptime = 0;
561 struct timespec uptime_ts;
562 void (*m2b)(struct timespec *ts);
563
564 timestamp = gator_get_time();
565
566 do_posix_clock_monotonic_gettime(&uptime_ts);
567 m2b = symbol_get(monotonic_to_bootbased);
568 if (m2b) {
569 m2b(&uptime_ts);
570 uptime = (long long)uptime_ts.tv_sec * 1000000000 + uptime_ts.tv_nsec;
571 }
572
573 marshal_summary(timestamp, uptime);
574}
575
629int gator_events_install(struct gator_interface *interface) 576int gator_events_install(struct gator_interface *interface)
630{ 577{
631 list_add_tail(&interface->list, &gator_events); 578 list_add_tail(&interface->list, &gator_events);
@@ -635,7 +582,8 @@ int gator_events_install(struct gator_interface *interface)
635 582
636int gator_events_get_key(void) 583int gator_events_get_key(void)
637{ 584{
638 static int key; 585 // key of zero is reserved as a timestamp
586 static int key = 1;
639 587
640 return key++; 588 return key++;
641} 589}
@@ -644,21 +592,31 @@ static int gator_init(void)
644{ 592{
645 int i; 593 int i;
646 594
647 if (gator_annotate_init())
648 return -1;
649
650 // events sources (gator_events.h, generated by gator_events.sh) 595 // events sources (gator_events.h, generated by gator_events.sh)
651 for (i = 0; i < ARRAY_SIZE(gator_events_list); i++) 596 for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
652 if (gator_events_list[i]) 597 if (gator_events_list[i])
653 gator_events_list[i](); 598 gator_events_list[i]();
654 599
600 gator_trace_power_init();
601
655 return 0; 602 return 0;
656} 603}
657 604
658static int gator_start(void) 605static int gator_start(void)
659{ 606{
607 unsigned long cpu, i;
660 struct gator_interface *gi; 608 struct gator_interface *gi;
661 609
610 // Initialize the buffer with the frame type and core
611 for_each_present_cpu(cpu) {
612 for (i = 0; i < NUM_GATOR_BUFS; i++) {
613 gator_buffer_header(cpu, i);
614 }
615 }
616
617 // Capture the start time
618 gator_summary();
619
662 // start all events 620 // start all events
663 list_for_each_entry(gi, &gator_events, list) { 621 list_for_each_entry(gi, &gator_events, list) {
664 if (gi->start && gi->start() != 0) { 622 if (gi->start && gi->start() != 0) {
@@ -683,6 +641,8 @@ static int gator_start(void)
683 goto annotate_failure; 641 goto annotate_failure;
684 if (gator_trace_sched_start()) 642 if (gator_trace_sched_start())
685 goto sched_failure; 643 goto sched_failure;
644 if (gator_trace_power_start())
645 goto power_failure;
686 if (gator_trace_gpu_start()) 646 if (gator_trace_gpu_start())
687 goto gpu_failure; 647 goto gpu_failure;
688 if (gator_event_sampling_start()) 648 if (gator_event_sampling_start())
@@ -701,6 +661,8 @@ timer_failure:
701event_sampling_failure: 661event_sampling_failure:
702 gator_trace_gpu_stop(); 662 gator_trace_gpu_stop();
703gpu_failure: 663gpu_failure:
664 gator_trace_power_stop();
665power_failure:
704 gator_trace_sched_stop(); 666 gator_trace_sched_stop();
705sched_failure: 667sched_failure:
706 gator_annotate_stop(); 668 gator_annotate_stop();
@@ -727,6 +689,7 @@ static void gator_stop(void)
727 689
728 gator_annotate_stop(); 690 gator_annotate_stop();
729 gator_trace_sched_stop(); 691 gator_trace_sched_stop();
692 gator_trace_power_stop();
730 gator_trace_gpu_stop(); 693 gator_trace_gpu_stop();
731 gator_event_sampling_stop(); 694 gator_event_sampling_stop();
732 695
@@ -735,11 +698,6 @@ static void gator_stop(void)
735 gator_timer_stop(); 698 gator_timer_stop();
736} 699}
737 700
738static void gator_exit(void)
739{
740 gator_annotate_exit();
741}
742
743/****************************************************************************** 701/******************************************************************************
744 * Filesystem 702 * Filesystem
745 ******************************************************************************/ 703 ******************************************************************************/
@@ -751,33 +709,52 @@ static int gator_op_setup(void)
751 709
752 mutex_lock(&start_mutex); 710 mutex_lock(&start_mutex);
753 711
754 gator_buffer_size[TIMER_BUF] = userspace_buffer_size; 712 gator_buffer_size[BACKTRACE_BUF] = BACKTRACE_BUFFER_SIZE;
755 gator_buffer_mask[TIMER_BUF] = userspace_buffer_size - 1; 713 gator_buffer_mask[BACKTRACE_BUF] = BACKTRACE_BUFFER_SIZE - 1;
756 714
757 // must be a power of 2 715 gator_buffer_size[COUNTER_BUF] = COUNTER_BUFFER_SIZE;
758 if (gator_buffer_size[TIMER_BUF] & (gator_buffer_size[TIMER_BUF] - 1)) { 716 gator_buffer_mask[COUNTER_BUF] = COUNTER_BUFFER_SIZE - 1;
759 err = -ENOEXEC; 717
760 goto setup_error; 718 gator_buffer_size[SCHED_TRACE_BUF] = SCHED_TRACE_BUFFER_SIZE;
761 } 719 gator_buffer_mask[SCHED_TRACE_BUF] = SCHED_TRACE_BUFFER_SIZE - 1;
720
721 gator_buffer_size[GPU_TRACE_BUF] = GPU_TRACE_BUFFER_SIZE;
722 gator_buffer_mask[GPU_TRACE_BUF] = GPU_TRACE_BUFFER_SIZE - 1;
762 723
763 gator_buffer_size[EVENT_BUF] = EVENT_BUFFER_SIZE_DEFAULT; 724 gator_buffer_size[ANNOTATE_BUF] = ANNOTATE_BUFFER_SIZE;
764 gator_buffer_mask[EVENT_BUF] = gator_buffer_size[EVENT_BUF] - 1; 725 gator_buffer_mask[ANNOTATE_BUF] = ANNOTATE_BUFFER_SIZE - 1;
726
727 gator_buffer_size[COUNTER2_BUF] = COUNTER2_BUFFER_SIZE;
728 gator_buffer_mask[COUNTER2_BUF] = COUNTER2_BUFFER_SIZE - 1;
729
730 gator_buffer_size[WFI_BUF] = WFI_BUFFER_SIZE;
731 gator_buffer_mask[WFI_BUF] = WFI_BUFFER_SIZE - 1;
765 732
766 // Initialize percpu per buffer variables 733 // Initialize percpu per buffer variables
767 for (i = 0; i < NUM_GATOR_BUFS; i++) { 734 for (i = 0; i < NUM_GATOR_BUFS; i++) {
735 // Verify buffers are a power of 2
736 if (gator_buffer_size[i] & (gator_buffer_size[i] - 1)) {
737 err = -ENOEXEC;
738 goto setup_error;
739 }
740
768 for_each_present_cpu(cpu) { 741 for_each_present_cpu(cpu) {
742 per_cpu(gator_buffer_read, cpu)[i] = 0;
743 per_cpu(gator_buffer_write, cpu)[i] = 0;
744 per_cpu(gator_buffer_commit, cpu)[i] = 0;
745 per_cpu(buffer_space_available, cpu)[i] = true;
746
747 // Annotation is a special case that only uses a single buffer
748 if (cpu > 0 && i == ANNOTATE_BUF) {
749 per_cpu(gator_buffer, cpu)[i] = NULL;
750 continue;
751 }
752
769 per_cpu(gator_buffer, cpu)[i] = vmalloc(gator_buffer_size[i]); 753 per_cpu(gator_buffer, cpu)[i] = vmalloc(gator_buffer_size[i]);
770 if (!per_cpu(gator_buffer, cpu)[i]) { 754 if (!per_cpu(gator_buffer, cpu)[i]) {
771 err = -ENOMEM; 755 err = -ENOMEM;
772 goto setup_error; 756 goto setup_error;
773 } 757 }
774
775 per_cpu(gator_buffer_read, cpu)[i] = 0;
776 per_cpu(gator_buffer_write, cpu)[i] = 0;
777 per_cpu(gator_buffer_commit, cpu)[i] = 0;
778 per_cpu(buffer_space_available, cpu)[i] = true;
779 per_cpu(emit_overflow, cpu) = 0;
780 gator_buffer_header(cpu, i);
781 } 758 }
782 } 759 }
783 760
@@ -829,8 +806,6 @@ static void gator_shutdown(void)
829 806
830 mutex_lock(&start_mutex); 807 mutex_lock(&start_mutex);
831 808
832 gator_annotate_shutdown();
833
834 for_each_present_cpu(cpu) { 809 for_each_present_cpu(cpu) {
835 mutex_lock(&gator_buffer_mutex); 810 mutex_lock(&gator_buffer_mutex);
836 for (i = 0; i < NUM_GATOR_BUFS; i++) { 811 for (i = 0; i < NUM_GATOR_BUFS; i++) {
@@ -840,7 +815,6 @@ static void gator_shutdown(void)
840 per_cpu(gator_buffer_write, cpu)[i] = 0; 815 per_cpu(gator_buffer_write, cpu)[i] = 0;
841 per_cpu(gator_buffer_commit, cpu)[i] = 0; 816 per_cpu(gator_buffer_commit, cpu)[i] = 0;
842 per_cpu(buffer_space_available, cpu)[i] = true; 817 per_cpu(buffer_space_available, cpu)[i] = true;
843 per_cpu(emit_overflow, cpu) = 0;
844 } 818 }
845 mutex_unlock(&gator_buffer_mutex); 819 mutex_unlock(&gator_buffer_mutex);
846 } 820 }
@@ -932,7 +906,7 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
932 size_t count, loff_t *offset) 906 size_t count, loff_t *offset)
933{ 907{
934 int retval = -EINVAL; 908 int retval = -EINVAL;
935 int commit = 0, length1, length2, read; 909 int commit = 0, length, length1, length2, read, byte, type_length;
936 char *buffer1; 910 char *buffer1;
937 char *buffer2 = NULL; 911 char *buffer2 = NULL;
938 int cpu, buftype; 912 int cpu, buftype;
@@ -944,7 +918,7 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
944 // sleep until the condition is true or a signal is received 918 // sleep until the condition is true or a signal is received
945 // the condition is checked each time gator_buffer_wait is woken up 919 // the condition is checked each time gator_buffer_wait is woken up
946 buftype = cpu = -1; 920 buftype = cpu = -1;
947 wait_event_interruptible(gator_buffer_wait, buffer_commit_ready(&cpu, &buftype) || gator_annotate_ready() || !gator_started); 921 wait_event_interruptible(gator_buffer_wait, buffer_commit_ready(&cpu, &buftype) || !gator_started);
948 922
949 if (signal_pending(current)) 923 if (signal_pending(current))
950 return -EINTR; 924 return -EINTR;
@@ -954,33 +928,36 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
954 928
955 mutex_lock(&gator_buffer_mutex); 929 mutex_lock(&gator_buffer_mutex);
956 930
957 if (buftype != -1 && cpu != -1) { 931 if (buftype == -1 || cpu == -1) {
958 read = per_cpu(gator_buffer_read, cpu)[buftype]; 932 retval = 0;
959 commit = per_cpu(gator_buffer_commit, cpu)[buftype]; 933 goto out;
934 }
960 935
961 /* May happen if the buffer is freed during pending reads. */ 936 read = per_cpu(gator_buffer_read, cpu)[buftype];
962 if (!per_cpu(gator_buffer, cpu)[buftype]) { 937 commit = per_cpu(gator_buffer_commit, cpu)[buftype];
963 retval = -EFAULT;
964 goto out;
965 }
966 938
967 /* determine the size of two halves */ 939 /* May happen if the buffer is freed during pending reads. */
968 length1 = commit - read; 940 if (!per_cpu(gator_buffer, cpu)[buftype]) {
969 buffer1 = &(per_cpu(gator_buffer, cpu)[buftype][read]); 941 retval = -EFAULT;
970 buffer2 = &(per_cpu(gator_buffer, cpu)[buftype][0]);
971 if (length1 < 0) {
972 length1 = gator_buffer_size[buftype] - read;
973 length2 = commit;
974 }
975 } else if (gator_annotate_ready()) {
976 length1 = gator_annotate_read(&buffer1);
977 if (!length1)
978 goto out;
979 } else {
980 retval = 0;
981 goto out; 942 goto out;
982 } 943 }
983 944
945 /* determine the size of two halves */
946 length1 = commit - read;
947 buffer1 = &(per_cpu(gator_buffer, cpu)[buftype][read]);
948 buffer2 = &(per_cpu(gator_buffer, cpu)[buftype][0]);
949 if (length1 < 0) {
950 length1 = gator_buffer_size[buftype] - read;
951 length2 = commit;
952 }
953
954 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
955 type_length = gator_response_type ? 1 : 0;
956 length = length1 + length2 - type_length - sizeof(int);
957 for (byte = 0; byte < sizeof(int); byte++) {
958 per_cpu(gator_buffer, cpu)[buftype][(read + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
959 }
960
984 /* start, middle or end */ 961 /* start, middle or end */
985 if (length1 > 0) { 962 if (length1 > 0) {
986 if (copy_to_user(&buf[0], buffer1, length1)) { 963 if (copy_to_user(&buf[0], buffer1, length1)) {
@@ -995,9 +972,7 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
995 } 972 }
996 } 973 }
997 974
998 if (buftype != -1 && cpu != -1) 975 per_cpu(gator_buffer_read, cpu)[buftype] = commit;
999 per_cpu(gator_buffer_read, cpu)[buftype] = commit;
1000
1001 retval = length1 + length2; 976 retval = length1 + length2;
1002 977
1003 /* kick just in case we've lost an SMP event */ 978 /* kick just in case we've lost an SMP event */
@@ -1055,8 +1030,8 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
1055 for_each_present_cpu(cpu) { 1030 for_each_present_cpu(cpu) {
1056 gator_cpu_cores++; 1031 gator_cpu_cores++;
1057 } 1032 }
1058 userspace_buffer_size = TIMER_BUFFER_SIZE_DEFAULT; 1033 userspace_buffer_size = BACKTRACE_BUFFER_SIZE;
1059 gator_streaming = 1; 1034 gator_response_type = 1;
1060 1035
1061 gatorfs_create_file(sb, root, "enable", &enable_fops); 1036 gatorfs_create_file(sb, root, "enable", &enable_fops);
1062 gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops); 1037 gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops);
@@ -1064,7 +1039,7 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
1064 gatorfs_create_ulong(sb, root, "cpu_cores", &gator_cpu_cores); 1039 gatorfs_create_ulong(sb, root, "cpu_cores", &gator_cpu_cores);
1065 gatorfs_create_ulong(sb, root, "buffer_size", &userspace_buffer_size); 1040 gatorfs_create_ulong(sb, root, "buffer_size", &userspace_buffer_size);
1066 gatorfs_create_ulong(sb, root, "tick", &gator_timer_count); 1041 gatorfs_create_ulong(sb, root, "tick", &gator_timer_count);
1067 gatorfs_create_ulong(sb, root, "streaming", &gator_streaming); 1042 gatorfs_create_ulong(sb, root, "response_type", &gator_response_type);
1068 gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version); 1043 gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version);
1069 1044
1070 // Annotate interface 1045 // Annotate interface
@@ -1075,6 +1050,9 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
1075 list_for_each_entry(gi, &gator_events, list) 1050 list_for_each_entry(gi, &gator_events, list)
1076 if (gi->create_files) 1051 if (gi->create_files)
1077 gi->create_files(sb, dir); 1052 gi->create_files(sb, dir);
1053
1054 // Power interface
1055 gator_trace_power_create_files(sb, dir);
1078} 1056}
1079 1057
1080/****************************************************************************** 1058/******************************************************************************
@@ -1098,7 +1076,6 @@ static void __exit gator_module_exit(void)
1098{ 1076{
1099 tracepoint_synchronize_unregister(); 1077 tracepoint_synchronize_unregister();
1100 gatorfs_unregister(); 1078 gatorfs_unregister();
1101 gator_exit();
1102} 1079}
1103 1080
1104module_init(gator_module_init); 1081module_init(gator_module_init);
diff --git a/driver/gator_marshaling.c b/driver/gator_marshaling.c
new file mode 100755
index 0000000..630d142
--- /dev/null
+++ b/driver/gator_marshaling.c
@@ -0,0 +1,239 @@
1/**
2 * Copyright (C) ARM Limited 2012. 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 */
9
10static void marshal_summary(long long timestamp, long long uptime) {
11 int cpu = 0;
12 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_SUMMARY);
13 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, timestamp);
14 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, uptime);
15}
16
17static bool marshal_cookie_header(char* text) {
18 int cpu = smp_processor_id();
19 return buffer_check_space(cpu, BACKTRACE_BUF, strlen(text) + 2 * MAXSIZE_PACK32);
20}
21
22static void marshal_cookie(int cookie, char* text) {
23 int cpu = smp_processor_id();
24 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_COOKIE);
25 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie);
26 gator_buffer_write_string(cpu, BACKTRACE_BUF, text);
27}
28
29static void marshal_pid_name(int pid, char* name) {
30 unsigned long flags, cpu;
31 local_irq_save(flags);
32 cpu = smp_processor_id();
33 if (buffer_check_space(cpu, BACKTRACE_BUF, TASK_COMM_LEN + 2 * MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
34 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_PID_NAME);
35 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, gator_get_time());
36 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, pid);
37 gator_buffer_write_string(cpu, BACKTRACE_BUF, name);
38 }
39 local_irq_restore(flags);
40}
41
42static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inKernel) {
43 int cpu = smp_processor_id();
44 if (buffer_check_space(cpu, BACKTRACE_BUF, gator_backtrace_depth * 2 * MAXSIZE_PACK32)) {
45 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_START_BACKTRACE);
46 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, gator_get_time());
47 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, exec_cookie);
48 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, tgid);
49 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, pid);
50 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, inKernel);
51 return true;
52 }
53
54 // Check and commit; commit is set to occur once buffer is 3/4 full
55 buffer_check(cpu, BACKTRACE_BUF);
56
57 return false;
58}
59
60static void marshal_backtrace(int address, int cookie) {
61 int cpu = smp_processor_id();
62 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, address);
63 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie);
64}
65
66static void marshal_backtrace_footer(void) {
67 int cpu = smp_processor_id();
68 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_END_BACKTRACE);
69
70 // Check and commit; commit is set to occur once buffer is 3/4 full
71 buffer_check(cpu, BACKTRACE_BUF);
72}
73
74static bool marshal_event_header(void) {
75 unsigned long flags, cpu = smp_processor_id();
76 bool retval = false;
77
78 local_irq_save(flags);
79 if (buffer_check_space(cpu, COUNTER_BUF, MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
80 gator_buffer_write_packed_int(cpu, COUNTER_BUF, 0); // key of zero indicates a timestamp
81 gator_buffer_write_packed_int64(cpu, COUNTER_BUF, gator_get_time());
82 retval = true;
83 }
84 local_irq_restore(flags);
85
86 // Check and commit; commit is set to occur once buffer is 3/4 full
87 buffer_check(cpu, COUNTER_BUF);
88
89 return retval;
90}
91
92static void marshal_event(int len, int* buffer) {
93 unsigned long i, flags, cpu = smp_processor_id();
94
95 if (len <= 0)
96 return;
97
98 // length must be even since all data is a (key, value) pair
99 if (len & 0x1) {
100 pr_err("gator: invalid counter data detected and discarded");
101 return;
102 }
103
104 // events must be written in key,value pairs
105 for (i = 0; i < len; i += 2) {
106 local_irq_save(flags);
107 if (!buffer_check_space(cpu, COUNTER_BUF, MAXSIZE_PACK32 * 2)) {
108 local_irq_restore(flags);
109 break;
110 }
111 gator_buffer_write_packed_int(cpu, COUNTER_BUF, buffer[i]);
112 gator_buffer_write_packed_int(cpu, COUNTER_BUF, buffer[i + 1]);
113 local_irq_restore(flags);
114 }
115
116 // Check and commit; commit is set to occur once buffer is 3/4 full
117 buffer_check(cpu, COUNTER_BUF);
118}
119
120static void marshal_event64(int len, long long* buffer64) {
121 unsigned long i, flags, cpu = smp_processor_id();
122
123 if (len <= 0)
124 return;
125
126 // length must be even since all data is a (key, value) pair
127 if (len & 0x1) {
128 pr_err("gator: invalid counter data detected and discarded");
129 return;
130 }
131
132 // events must be written in key,value pairs
133 for (i = 0; i < len; i += 2) {
134 local_irq_save(flags);
135 if (!buffer_check_space(cpu, COUNTER_BUF, MAXSIZE_PACK64 * 2)) {
136 local_irq_restore(flags);
137 break;
138 }
139 gator_buffer_write_packed_int64(cpu, COUNTER_BUF, buffer64[i]);
140 gator_buffer_write_packed_int64(cpu, COUNTER_BUF, buffer64[i + 1]);
141 local_irq_restore(flags);
142 }
143
144 // Check and commit; commit is set to occur once buffer is 3/4 full
145 buffer_check(cpu, COUNTER_BUF);
146}
147
148#if GATOR_CPU_FREQ_SUPPORT
149static void marshal_event_single(int core, int key, int value) {
150 unsigned long flags, cpu;
151
152 local_irq_save(flags);
153 cpu = smp_processor_id();
154 if (buffer_check_space(cpu, COUNTER2_BUF, MAXSIZE_PACK64 + MAXSIZE_PACK32 * 3)) {
155 gator_buffer_write_packed_int64(cpu, COUNTER2_BUF, gator_get_time());
156 gator_buffer_write_packed_int(cpu, COUNTER2_BUF, core);
157 gator_buffer_write_packed_int(cpu, COUNTER2_BUF, key);
158 gator_buffer_write_packed_int(cpu, COUNTER2_BUF, value);
159 }
160 local_irq_restore(flags);
161
162 // Check and commit; commit is set to occur once buffer is 3/4 full
163 buffer_check(cpu, COUNTER2_BUF);
164}
165#endif
166
167static void marshal_sched_gpu(int type, int unit, int core, int tgid, int pid) {
168 unsigned long cpu = smp_processor_id(), flags;
169
170 if (!per_cpu(gator_buffer, cpu)[GPU_TRACE_BUF])
171 return;
172
173 local_irq_save(flags);
174 if (buffer_check_space(cpu, GPU_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) {
175 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, type);
176 gator_buffer_write_packed_int64(cpu, GPU_TRACE_BUF, gator_get_time());
177 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit);
178 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core);
179 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, tgid);
180 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, pid);
181 }
182 local_irq_restore(flags);
183
184 // Check and commit; commit is set to occur once buffer is 3/4 full
185 buffer_check(cpu, GPU_TRACE_BUF);
186}
187
188static void marshal_sched_trace(int type, int pid, int tgid, int cookie, int state) {
189 unsigned long cpu = smp_processor_id(), flags;
190
191 if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF])
192 return;
193
194 local_irq_save(flags);
195 if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) {
196 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, type);
197 gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, gator_get_time());
198 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid);
199 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, tgid);
200 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie);
201 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, state);
202 }
203 local_irq_restore(flags);
204
205 // Check and commit; commit is set to occur once buffer is 3/4 full
206 buffer_check(cpu, SCHED_TRACE_BUF);
207}
208
209#if GATOR_CPU_FREQ_SUPPORT
210static void marshal_wfi(int core, int state) {
211 unsigned long flags, cpu;
212
213 local_irq_save(flags);
214 cpu = smp_processor_id();
215 if (buffer_check_space(cpu, WFI_BUF, MAXSIZE_PACK64 + MAXSIZE_PACK32 * 2)) {
216 gator_buffer_write_packed_int64(cpu, WFI_BUF, gator_get_time());
217 gator_buffer_write_packed_int(cpu, WFI_BUF, core);
218 gator_buffer_write_packed_int(cpu, WFI_BUF, state);
219 }
220 local_irq_restore(flags);
221
222 // Check and commit; commit is set to occur once buffer is 3/4 full
223 buffer_check(cpu, WFI_BUF);
224}
225#endif
226
227static void marshal_frame(int cpu, int buftype, int frame) {
228 // add response type
229 if (gator_response_type > 0) {
230 gator_buffer_write_packed_int(cpu, buftype, gator_response_type);
231 }
232
233 // leave space for 4-byte unpacked length
234 per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + 4) & gator_buffer_mask[buftype];
235
236 // add frame type and core number
237 gator_buffer_write_packed_int(cpu, buftype, frame);
238 gator_buffer_write_packed_int(cpu, buftype, cpu);
239}
diff --git a/driver/gator_pack.c b/driver/gator_pack.c
index 985e960..925469a 100644
--- a/driver/gator_pack.c
+++ b/driver/gator_pack.c
@@ -162,101 +162,3 @@ static void gator_buffer_write_packed_int64(int cpu, int buftype, unsigned long
162 per_cpu(gator_buffer_write, cpu)[buftype] = write9; 162 per_cpu(gator_buffer_write, cpu)[buftype] = write9;
163 } 163 }
164} 164}
165
166static int gator_write_packed_int(char *buffer, unsigned int x)
167{
168 if ((x & 0xffffff80) == 0) {
169 buffer[0] = x & 0x7f;
170 return 1;
171 } else if ((x & 0xffffc000) == 0) {
172 buffer[0] = x | 0x80;
173 buffer[1] = (x>>7) & 0x7f;
174 return 2;
175 } else if ((x & 0xffe00000) == 0) {
176 buffer[0] = x | 0x80;
177 buffer[1] = (x>>7) | 0x80;
178 buffer[2] = (x>>14) & 0x7f;
179 return 3;
180 } else if ((x & 0xf0000000) == 0) {
181 buffer[0] = x | 0x80;
182 buffer[1] = (x>>7) | 0x80;
183 buffer[2] = (x>>14) | 0x80;
184 buffer[3] = (x>>21) & 0x7f;
185 return 4;
186 } else {
187 buffer[0] = x | 0x80;
188 buffer[1] = (x>>7) | 0x80;
189 buffer[2] = (x>>14) | 0x80;
190 buffer[3] = (x>>21) | 0x80;
191 buffer[4] = (x>>28) & 0x0f;
192 return 5;
193 }
194}
195
196static int gator_write_packed_int64(char *buffer, unsigned long long x)
197{
198 if ((x & 0xffffffffffffff80LL) == 0) {
199 buffer[0] = x & 0x7f;
200 return 1;
201 } else if ((x & 0xffffffffffffc000LL) == 0) {
202 buffer[0] = x | 0x80;
203 buffer[1] = (x>>7) & 0x7f;
204 return 2;
205 } else if ((x & 0xffffffffffe00000LL) == 0) {
206 buffer[0] = x | 0x80;
207 buffer[1] = (x>>7) | 0x80;
208 buffer[2] = (x>>14) & 0x7f;
209 return 3;
210 } else if ((x & 0xfffffffff0000000LL) == 0) {
211 buffer[0] = x | 0x80;
212 buffer[1] = (x>>7) | 0x80;
213 buffer[2] = (x>>14) | 0x80;
214 buffer[3] = (x>>21) & 0x7f;
215 return 4;
216 } else if ((x & 0xfffffff800000000LL) == 0) {
217 buffer[0] = x | 0x80;
218 buffer[1] = (x>>7) | 0x80;
219 buffer[2] = (x>>14) | 0x80;
220 buffer[3] = (x>>21) | 0x80;
221 buffer[4] = (x>>28) & 0x7f;
222 return 5;
223 } else if ((x & 0xfffffc0000000000LL) == 0) {
224 buffer[0] = x | 0x80;
225 buffer[1] = (x>>7) | 0x80;
226 buffer[2] = (x>>14) | 0x80;
227 buffer[3] = (x>>21) | 0x80;
228 buffer[4] = (x>>28) | 0x80;
229 buffer[5] = (x>>35) & 0x7f;
230 return 6;
231 } else if ((x & 0xfffe000000000000LL) == 0) {
232 buffer[0] = x | 0x80;
233 buffer[1] = (x>>7) | 0x80;
234 buffer[2] = (x>>14) | 0x80;
235 buffer[3] = (x>>21) | 0x80;
236 buffer[4] = (x>>28) | 0x80;
237 buffer[5] = (x>>35) | 0x80;
238 buffer[6] = (x>>42) & 0x7f;
239 return 7;
240 } else if ((x & 0xff00000000000000LL) == 0) {
241 buffer[0] = x | 0x80;
242 buffer[1] = (x>>7) | 0x80;
243 buffer[2] = (x>>14) | 0x80;
244 buffer[3] = (x>>21) | 0x80;
245 buffer[4] = (x>>28) | 0x80;
246 buffer[5] = (x>>35) | 0x80;
247 buffer[6] = (x>>42) | 0x80;
248 buffer[7] = (x>>49) & 0x7f;
249 return 8;
250 } else {
251 buffer[0] = x | 0x80;
252 buffer[1] = (x>>7) | 0x80;
253 buffer[2] = (x>>14) | 0x80;
254 buffer[3] = (x>>21) | 0x80;
255 buffer[4] = (x>>28) | 0x80;
256 buffer[5] = (x>>35) | 0x80;
257 buffer[6] = (x>>42) | 0x80;
258 buffer[7] = (x>>49) | 0x80;
259 buffer[8] = (x>>56) & 0xff;
260 return 9;
261 }
262}
diff --git a/driver/gator_trace_gpu.c b/driver/gator_trace_gpu.c
index bc63995..921932c 100644
--- a/driver/gator_trace_gpu.c
+++ b/driver/gator_trace_gpu.c
@@ -25,68 +25,12 @@
25static int mali_trace_registered; 25static int mali_trace_registered;
26static int gpu_trace_registered; 26static int gpu_trace_registered;
27 27
28#define GPU_OVERFLOW -1
29#define GPU_START 1 28#define GPU_START 1
30#define GPU_STOP 2 29#define GPU_STOP 2
31 30
32#define GPU_UNIT_VP 1 31#define GPU_UNIT_VP 1
33#define GPU_UNIT_FP 2 32#define GPU_UNIT_FP 2
34 33#define GPU_UNIT_CL 3
35#define TRACESIZE (8*1024)
36
37static DEFINE_PER_CPU(uint64_t *[2], theGpuTraceBuf);
38static DEFINE_PER_CPU(int, theGpuTraceSel);
39static DEFINE_PER_CPU(int, theGpuTracePos);
40static DEFINE_PER_CPU(int, theGpuTraceErr);
41
42int gator_trace_gpu_read(long long **buffer);
43
44static void probe_gpu_write(int type, int unit, int core, struct task_struct* task)
45{
46 int tracePos;
47 unsigned long flags;
48 uint64_t *traceBuf, time;
49 int pid, tgid;
50 int cpu = smp_processor_id();
51
52 if (!per_cpu(theGpuTraceBuf, cpu)[per_cpu(theGpuTraceSel, cpu)])
53 return;
54
55 if (task) {
56 tgid = (int)task->tgid;
57 pid = (int)task->pid;
58 } else {
59 tgid = pid = 0;
60 }
61
62 // disable interrupts to synchronize with gator_trace_gpu_read(); spinlocks not needed since percpu buffers are used
63 local_irq_save(flags);
64
65 time = gator_get_time();
66 tracePos = per_cpu(theGpuTracePos, cpu);
67 traceBuf = per_cpu(theGpuTraceBuf, cpu)[per_cpu(theGpuTraceSel, cpu)];
68
69 if (tracePos < (TRACESIZE - 100)) {
70 // capture
71 traceBuf[tracePos++] = type;
72 traceBuf[tracePos++] = time;
73 traceBuf[tracePos++] = unit;
74 traceBuf[tracePos++] = core;
75 traceBuf[tracePos++] = tgid;
76 traceBuf[tracePos++] = pid;
77 } else if (!per_cpu(theGpuTraceErr, cpu)) {
78 per_cpu(theGpuTraceErr, cpu) = 1;
79 traceBuf[tracePos++] = GPU_OVERFLOW;
80 traceBuf[tracePos++] = time;
81 traceBuf[tracePos++] = 0;
82 traceBuf[tracePos++] = 0;
83 traceBuf[tracePos++] = 0;
84 traceBuf[tracePos++] = 0;
85 pr_debug("gator: gpu trace overflow\n");
86 }
87 per_cpu(theGpuTracePos, cpu) = tracePos;
88 local_irq_restore(flags);
89}
90 34
91#ifdef MALI_SUPPORT 35#ifdef MALI_SUPPORT
92 36
@@ -105,19 +49,23 @@ enum components {
105GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4)) 49GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4))
106{ 50{
107 unsigned int component, state; 51 unsigned int component, state;
52 int tgid = 0, pid = 0;
108 53
109 // do as much work as possible before disabling interrupts 54 // do as much work as possible before disabling interrupts
110 component = (event_id >> 16) & 0xF; 55 component = (event_id >> 16) & 0xFF; // component is an 8-bit field
111 state = (event_id >> 24) & 0xF; 56 state = (event_id >> 24) & 0xF; // state is a 4-bit field
112 57
113 if ((component == COMPONENT_VP0) || (component >= COMPONENT_FP0 && component <= COMPONENT_FP7)) { 58 if ((component == COMPONENT_VP0) || (component >= COMPONENT_FP0 && component <= COMPONENT_FP7)) {
114 if (state == ACTIVITY_START || state == ACTIVITY_STOP) { 59 if (state == ACTIVITY_START || state == ACTIVITY_STOP) {
115 unsigned int type = (state == ACTIVITY_START) ? GPU_START : GPU_STOP; 60 unsigned int type = (state == ACTIVITY_START) ? GPU_START : GPU_STOP;
116 unsigned int unit = (component < COMPONENT_FP0) ? GPU_UNIT_VP : GPU_UNIT_FP; 61 unsigned int unit = (component < COMPONENT_FP0) ? GPU_UNIT_VP : GPU_UNIT_FP;
117 unsigned int core = (component < COMPONENT_FP0) ? component - COMPONENT_VP0 : component - COMPONENT_FP0; 62 unsigned int core = (component < COMPONENT_FP0) ? component - COMPONENT_VP0 : component - COMPONENT_FP0;
118 struct task_struct* task = (state == ACTIVITY_START) ? (struct task_struct*)d2 : NULL; 63 if (state == ACTIVITY_START) {
64 tgid = d0;
65 pid = d1;
66 }
119 67
120 probe_gpu_write(type, unit, core, task); 68 marshal_sched_gpu(type, unit, core, tgid, pid);
121 } 69 }
122 } 70 }
123} 71}
@@ -125,20 +73,18 @@ GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned
125 73
126GATOR_DEFINE_PROBE(gpu_activity_start, TP_PROTO(int gpu_unit, int gpu_core, struct task_struct *p)) 74GATOR_DEFINE_PROBE(gpu_activity_start, TP_PROTO(int gpu_unit, int gpu_core, struct task_struct *p))
127{ 75{
128 probe_gpu_write(GPU_START, gpu_unit, gpu_core, p); 76 marshal_sched_gpu(GPU_START, gpu_unit, gpu_core, (int)p->tgid, (int)p->pid);
129} 77}
130 78
131GATOR_DEFINE_PROBE(gpu_activity_stop, TP_PROTO(int gpu_unit, int gpu_core)) 79GATOR_DEFINE_PROBE(gpu_activity_stop, TP_PROTO(int gpu_unit, int gpu_core))
132{ 80{
133 probe_gpu_write(GPU_STOP, gpu_unit, gpu_core, NULL); 81 marshal_sched_gpu(GPU_STOP, gpu_unit, gpu_core, 0, 0);
134} 82}
135 83
136int gator_trace_gpu_start(void) 84int gator_trace_gpu_start(void)
137{ 85{
138 int cpu;
139
140 /* 86 /*
141 * Returns 0 for installation failed 87 * Returns nonzero for installation failed
142 * Absence of gpu trace points is not an error 88 * Absence of gpu trace points is not an error
143 */ 89 */
144 90
@@ -161,90 +107,20 @@ int gator_trace_gpu_start(void)
161 gpu_trace_registered = 1; 107 gpu_trace_registered = 1;
162 } 108 }
163 109
164 if (!gpu_trace_registered && !mali_trace_registered) {
165 return 0;
166 }
167
168 for_each_present_cpu(cpu) {
169 per_cpu(theGpuTraceSel, cpu) = 0;
170 per_cpu(theGpuTracePos, cpu) = 0;
171 per_cpu(theGpuTraceErr, cpu) = 0;
172 per_cpu(theGpuTraceBuf, cpu)[0] = kmalloc(TRACESIZE * sizeof(uint64_t), GFP_KERNEL);
173 per_cpu(theGpuTraceBuf, cpu)[1] = kmalloc(TRACESIZE * sizeof(uint64_t), GFP_KERNEL);
174 if (!per_cpu(theGpuTraceBuf, cpu)[0] || !per_cpu(theGpuTraceBuf, cpu)[1]) {
175#ifdef MALI_SUPPORT
176 if (mali_trace_registered) {
177 GATOR_UNREGISTER_TRACE(mali_timeline_event);
178 }
179#endif
180 if (gpu_trace_registered) {
181 GATOR_UNREGISTER_TRACE(gpu_activity_stop);
182 GATOR_UNREGISTER_TRACE(gpu_activity_start);
183 }
184
185 gpu_trace_registered = mali_trace_registered = 0;
186
187 return -1;
188 }
189 }
190
191 return 0; 110 return 0;
192} 111}
193 112
194int gator_trace_gpu_offline(long long **buffer)
195{
196 return gator_trace_gpu_read(buffer);
197}
198
199void gator_trace_gpu_stop(void) 113void gator_trace_gpu_stop(void)
200{ 114{
201 int cpu;
202
203 if (gpu_trace_registered || mali_trace_registered) {
204 for_each_present_cpu(cpu) {
205 kfree(per_cpu(theGpuTraceBuf, cpu)[0]);
206 kfree(per_cpu(theGpuTraceBuf, cpu)[1]);
207 per_cpu(theGpuTraceBuf, cpu)[0] = NULL;
208 per_cpu(theGpuTraceBuf, cpu)[1] = NULL;
209 }
210
211#ifdef MALI_SUPPORT 115#ifdef MALI_SUPPORT
212 if (mali_trace_registered) { 116 if (mali_trace_registered) {
213 GATOR_UNREGISTER_TRACE(mali_timeline_event); 117 GATOR_UNREGISTER_TRACE(mali_timeline_event);
214 } 118 }
215#endif 119#endif
216 if (gpu_trace_registered) { 120 if (gpu_trace_registered) {
217 GATOR_UNREGISTER_TRACE(gpu_activity_stop); 121 GATOR_UNREGISTER_TRACE(gpu_activity_stop);
218 GATOR_UNREGISTER_TRACE(gpu_activity_start); 122 GATOR_UNREGISTER_TRACE(gpu_activity_start);
219 } 123 }
220
221 gpu_trace_registered = mali_trace_registered = 0;
222 }
223}
224
225int gator_trace_gpu_read(long long **buffer)
226{
227 int cpu = smp_processor_id();
228 unsigned long flags;
229 uint64_t *traceBuf;
230 int tracePos;
231
232 if (!per_cpu(theGpuTraceBuf, cpu)[per_cpu(theGpuTraceSel, cpu)])
233 return 0;
234
235 local_irq_save(flags);
236
237 traceBuf = per_cpu(theGpuTraceBuf, cpu)[per_cpu(theGpuTraceSel, cpu)];
238 tracePos = per_cpu(theGpuTracePos, cpu);
239
240 per_cpu(theGpuTraceSel, cpu) = !per_cpu(theGpuTraceSel, cpu);
241 per_cpu(theGpuTracePos, cpu) = 0;
242 per_cpu(theGpuTraceErr, cpu) = 0;
243
244 local_irq_restore(flags);
245
246 if (buffer)
247 *buffer = traceBuf;
248 124
249 return tracePos; 125 gpu_trace_registered = mali_trace_registered = 0;
250} 126}
diff --git a/driver/gator_trace_power.c b/driver/gator_trace_power.c
new file mode 100755
index 0000000..ca89b19
--- /dev/null
+++ b/driver/gator_trace_power.c
@@ -0,0 +1,160 @@
1/**
2 * Copyright (C) ARM Limited 2011-2012. 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 */
9
10#include <linux/cpufreq.h>
11#include <trace/events/power.h>
12
13// cpu_frequency and cpu_idle trace points were introduced in Linux kernel v2.6.38
14// the now deprecated power_frequency trace point was available prior to 2.6.38, but only for x86
15#if GATOR_CPU_FREQ_SUPPORT
16enum {
17 POWER_CPU_FREQ,
18 POWER_CPU_IDLE,
19 POWER_TOTAL
20};
21
22static DEFINE_PER_CPU(ulong, idle_prev_state);
23static ulong power_cpu_enabled[POWER_TOTAL];
24static ulong power_cpu_key[POWER_TOTAL];
25
26static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root)
27{
28 struct dentry *dir;
29
30 // cpu_frequency
31 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_freq");
32 if (!dir) {
33 return -1;
34 }
35 gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_FREQ]);
36 gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_FREQ]);
37
38 // cpu_idle
39 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_idle");
40 if (!dir) {
41 return -1;
42 }
43 gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_IDLE]);
44 gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_IDLE]);
45
46 return 0;
47}
48
49// 'cpu' may not equal smp_processor_id(), i.e. may not be running on the core that is having the freq/idle state change
50GATOR_DEFINE_PROBE(cpu_frequency, TP_PROTO(unsigned int frequency, unsigned int cpu))
51{
52 marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], frequency * 1000);
53}
54
55#define WFI_ACTIVE_THRESHOLD 2 // may vary on platform/OS
56#define WFI_EXIT 0
57#define WFI_ENTER 1
58GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu))
59{
60 // the streamline engine treats all counter values as unsigned
61 if (state & 0x80000000) {
62 state = 0;
63 }
64
65 if (state == per_cpu(idle_prev_state, cpu)) {
66 return;
67 }
68
69 if (state < WFI_ACTIVE_THRESHOLD && per_cpu(idle_prev_state, cpu) >= WFI_ACTIVE_THRESHOLD) {
70 // transition from wfi to non-wfi
71 marshal_wfi(cpu, WFI_EXIT);
72 } else if (state >= WFI_ACTIVE_THRESHOLD && per_cpu(idle_prev_state, cpu) < WFI_ACTIVE_THRESHOLD) {
73 // transition from non-wfi to wfi
74 marshal_wfi(cpu, WFI_ENTER);
75 }
76
77 per_cpu(idle_prev_state, cpu) = state;
78
79 if (power_cpu_enabled[POWER_CPU_IDLE]) {
80 marshal_event_single(cpu, power_cpu_key[POWER_CPU_IDLE], state);
81 }
82}
83
84static void gator_trace_power_online(void)
85{
86 int cpu = smp_processor_id();
87 if (power_cpu_enabled[POWER_CPU_FREQ]) {
88 marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], cpufreq_quick_get(cpu) * 1000);
89 }
90}
91
92static void gator_trace_power_offline(void)
93{
94 // Set frequency to zero on an offline
95 int cpu = smp_processor_id();
96 if (power_cpu_enabled[POWER_CPU_FREQ]) {
97 marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], 0);
98 }
99}
100
101static int gator_trace_power_start(void)
102{
103 int cpu;
104
105 // register tracepoints
106 if (power_cpu_enabled[POWER_CPU_FREQ])
107 if (GATOR_REGISTER_TRACE(cpu_frequency))
108 goto fail_cpu_frequency_exit;
109
110 // Always register for cpu:idle for detecting WFI, independent of power_cpu_enabled[POWER_CPU_IDLE]
111 if (GATOR_REGISTER_TRACE(cpu_idle))
112 goto fail_cpu_idle_exit;
113 pr_debug("gator: registered power event tracepoints\n");
114
115 for_each_present_cpu(cpu) {
116 per_cpu(idle_prev_state, cpu) = 0;
117 }
118
119 return 0;
120
121 // unregister tracepoints on error
122fail_cpu_idle_exit:
123 if (power_cpu_enabled[POWER_CPU_FREQ])
124 GATOR_UNREGISTER_TRACE(cpu_frequency);
125fail_cpu_frequency_exit:
126 pr_err("gator: power event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
127
128 return -1;
129}
130
131static void gator_trace_power_stop(void)
132{
133 int i;
134
135 if (power_cpu_enabled[POWER_CPU_FREQ])
136 GATOR_UNREGISTER_TRACE(cpu_frequency);
137 GATOR_UNREGISTER_TRACE(cpu_idle);
138 pr_debug("gator: unregistered power event tracepoints\n");
139
140 for (i = 0; i < POWER_TOTAL; i++) {
141 power_cpu_enabled[i] = 0;
142 }
143}
144
145void gator_trace_power_init(void)
146{
147 int i;
148 for (i = 0; i < POWER_TOTAL; i++) {
149 power_cpu_enabled[i] = 0;
150 power_cpu_key[i] = gator_events_get_key();
151 }
152}
153#else
154static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root) {return 0;}
155static void gator_trace_power_online(void) {}
156static void gator_trace_power_offline(void) {}
157static int gator_trace_power_start(void) {return 0;}
158static void gator_trace_power_stop(void) {}
159void gator_trace_power_init(void) {}
160#endif
diff --git a/driver/gator_trace_sched.c b/driver/gator_trace_sched.c
index dafacb7..08b0270 100644
--- a/driver/gator_trace_sched.c
+++ b/driver/gator_trace_sched.c
@@ -10,34 +10,26 @@
10#include <trace/events/sched.h> 10#include <trace/events/sched.h>
11#include "gator.h" 11#include "gator.h"
12 12
13#define SCHED_OVERFLOW -1
14#define SCHED_SWITCH 1 13#define SCHED_SWITCH 1
15#define SCHED_PROCESS_FREE 2 14#define SCHED_PROCESS_EXIT 2
16 15
17#define SCHEDSIZE (8*1024)
18#define TASK_MAP_ENTRIES 1024 /* must be power of 2 */ 16#define TASK_MAP_ENTRIES 1024 /* must be power of 2 */
19#define TASK_MAX_COLLISIONS 2 17#define TASK_MAX_COLLISIONS 2
20 18
21static DEFINE_PER_CPU(uint64_t *[2], theSchedBuf);
22static DEFINE_PER_CPU(int, theSchedSel);
23static DEFINE_PER_CPU(int, theSchedPos);
24static DEFINE_PER_CPU(int, theSchedErr);
25static DEFINE_PER_CPU(uint64_t *, taskname_keys); 19static DEFINE_PER_CPU(uint64_t *, taskname_keys);
26 20
27enum { 21enum {
28 STATE_CONTENTION = 0, 22 STATE_WAIT_ON_OTHER = 0,
23 STATE_CONTENTION,
29 STATE_WAIT_ON_IO, 24 STATE_WAIT_ON_IO,
30 STATE_WAIT_ON_OTHER 25 STATE_WAIT_ON_MUTEX,
31}; 26};
32 27
33int gator_trace_sched_read(long long **buffer);
34
35void emit_pid_name(struct task_struct* task) 28void emit_pid_name(struct task_struct* task)
36{ 29{
37 bool found = false; 30 bool found = false;
38 unsigned long flags;
39 char taskcomm[TASK_COMM_LEN + 3]; 31 char taskcomm[TASK_COMM_LEN + 3];
40 int x, cpu = smp_processor_id(); 32 unsigned long x, cpu = smp_processor_id();
41 uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]); 33 uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]);
42 uint64_t value; 34 uint64_t value;
43 35
@@ -52,7 +44,7 @@ void emit_pid_name(struct task_struct* task)
52 } 44 }
53 } 45 }
54 46
55 if (!found && buffer_check_space(cpu, TIMER_BUF, TASK_COMM_LEN + 2 * MAXSIZE_PACK32 + MAXSIZE_PACK64)) { 47 if (!found) {
56 // shift values, new value always in front 48 // shift values, new value always in front
57 uint64_t oldv, newv = value; 49 uint64_t oldv, newv = value;
58 for (x = 0; x < TASK_MAX_COLLISIONS; x++) { 50 for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
@@ -62,100 +54,70 @@ void emit_pid_name(struct task_struct* task)
62 } 54 }
63 55
64 // emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions 56 // emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions
65 if (strlcpy(taskcomm, task->comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1) 57 if (strlcpy(taskcomm, task->comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1) {
66 // append ellipses if task->comm has length of TASK_COMM_LEN - 1 58 // append ellipses if task->comm has length of TASK_COMM_LEN - 1
67 strcat(taskcomm, "..."); 59 strcat(taskcomm, "...");
60 }
68 61
69 // disable interrupts to synchronize with hrtimer populating timer buf 62 marshal_pid_name(task->pid, taskcomm);
70 local_irq_save(flags); 63 }
71 gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_PID_NAME); 64}
72 gator_buffer_write_packed_int64(cpu, TIMER_BUF, gator_get_time()); 65
73 gator_buffer_write_packed_int(cpu, TIMER_BUF, task->pid); 66
74 gator_buffer_write_string(cpu, TIMER_BUF, taskcomm); 67static void collect_counters(void)
75 local_irq_restore(flags); 68{
69 int *buffer, len;
70 long long *buffer64;
71 struct gator_interface *gi;
72
73 if (marshal_event_header()) {
74 list_for_each_entry(gi, &gator_events, list) {
75 if (gi->read) {
76 len = gi->read(&buffer);
77 marshal_event(len, buffer);
78 } else if (gi->read64) {
79 len = gi->read64(&buffer64);
80 marshal_event64(len, buffer64);
81 }
82 }
76 } 83 }
77} 84}
78 85
79static void probe_sched_write(int type, struct task_struct* task, struct task_struct* old_task) 86static void probe_sched_write(int type, struct task_struct* task, struct task_struct* old_task)
80{ 87{
81 int schedPos, cookie = 0, state = 0; 88 int cookie = 0, state = 0;
82 unsigned long flags;
83 uint64_t *schedBuf, time;
84 int cpu = smp_processor_id(); 89 int cpu = smp_processor_id();
85 int pid = task->pid; 90 int pid = task->pid;
86 int tgid = task->tgid; 91 int tgid = task->tgid;
87 92
88 if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
89 return;
90
91 if (type == SCHED_SWITCH) { 93 if (type == SCHED_SWITCH) {
92 // do as much work as possible before disabling interrupts 94 // do as much work as possible before disabling interrupts
93 cookie = get_exec_cookie(cpu, TIMER_BUF, task); 95 cookie = get_exec_cookie(cpu, BACKTRACE_BUF, task);
94 emit_pid_name(task); 96 emit_pid_name(task);
95 if (old_task->state == 0) 97 if (old_task->state == TASK_RUNNING) {
96 state = STATE_CONTENTION; 98 state = STATE_CONTENTION;
97 else if (old_task->in_iowait) 99 } else if (old_task->in_iowait) {
98 state = STATE_WAIT_ON_IO; 100 state = STATE_WAIT_ON_IO;
99 else 101#ifdef CONFIG_DEBUG_MUTEXES
102 } else if (old_task->blocked_on) {
103 state = STATE_WAIT_ON_MUTEX;
104#endif
105 } else {
100 state = STATE_WAIT_ON_OTHER; 106 state = STATE_WAIT_ON_OTHER;
101 } 107 }
102
103 // disable interrupts to synchronize with gator_trace_sched_read(); spinlocks not needed since percpu buffers are used
104 local_irq_save(flags);
105
106 time = gator_get_time();
107 schedPos = per_cpu(theSchedPos, cpu);
108 schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
109 108
110 if (schedPos < (SCHEDSIZE - 100)) { 109 collect_counters();
111 // capture
112 schedBuf[schedPos++] = type;
113 schedBuf[schedPos++] = time;
114 schedBuf[schedPos++] = pid;
115 schedBuf[schedPos++] = tgid;
116 schedBuf[schedPos++] = cookie;
117 schedBuf[schedPos++] = state;
118 } else if (!per_cpu(theSchedErr, cpu)) {
119 per_cpu(theSchedErr, cpu) = 1;
120 schedBuf[schedPos++] = SCHED_OVERFLOW;
121 schedBuf[schedPos++] = time;
122 schedBuf[schedPos++] = 0;
123 schedBuf[schedPos++] = 0;
124 schedBuf[schedPos++] = 0;
125 schedBuf[schedPos++] = 0;
126 pr_debug("gator: tracepoint overflow\n");
127 } 110 }
128 per_cpu(theSchedPos, cpu) = schedPos; 111
129 local_irq_restore(flags); 112 // marshal_sched_trace() disables interrupts as the free may trigger while switch is writing to the buffer; disabling preemption is not sufficient
113 // is disable interrupts necessary now that exit is used instead of free?
114 marshal_sched_trace(type, pid, tgid, cookie, state);
130} 115}
131 116
132// special case used during a suspend of the system 117// special case used during a suspend of the system
133static void trace_sched_insert_idle(void) 118static void trace_sched_insert_idle(void)
134{ 119{
135 unsigned long flags; 120 marshal_sched_trace(SCHED_SWITCH, 0, 0, 0, 0);
136 uint64_t *schedBuf;
137 int schedPos, cpu = smp_processor_id();
138
139 if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
140 return;
141
142 local_irq_save(flags);
143
144 schedPos = per_cpu(theSchedPos, cpu);
145 schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
146
147 if (schedPos < (SCHEDSIZE - (6 * 8))) {
148 // capture
149 schedBuf[schedPos++] = SCHED_SWITCH;
150 schedBuf[schedPos++] = gator_get_time();
151 schedBuf[schedPos++] = 0; // idle pid is zero
152 schedBuf[schedPos++] = 0; // idle tid is zero
153 schedBuf[schedPos++] = 0; // idle cookie is zero
154 schedBuf[schedPos++] = STATE_WAIT_ON_OTHER;
155 }
156
157 per_cpu(theSchedPos, cpu) = schedPos;
158 local_irq_restore(flags);
159} 121}
160 122
161#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) 123#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_
167 probe_sched_write(SCHED_SWITCH, next, prev); 129 probe_sched_write(SCHED_SWITCH, next, prev);
168} 130}
169 131
170GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p)) 132GATOR_DEFINE_PROBE(sched_process_exit, TP_PROTO(struct task_struct *p))
171{ 133{
172 probe_sched_write(SCHED_PROCESS_FREE, p, 0); 134 probe_sched_write(SCHED_PROCESS_EXIT, p, 0);
173} 135}
174 136
175static int register_scheduler_tracepoints(void) { 137static int register_scheduler_tracepoints(void) {
176 // register tracepoints 138 // register tracepoints
177 if (GATOR_REGISTER_TRACE(sched_switch)) 139 if (GATOR_REGISTER_TRACE(sched_switch))
178 goto fail_sched_switch; 140 goto fail_sched_switch;
179 if (GATOR_REGISTER_TRACE(sched_process_free)) 141 if (GATOR_REGISTER_TRACE(sched_process_exit))
180 goto fail_sched_process_free; 142 goto fail_sched_process_exit;
181 pr_debug("gator: registered tracepoints\n"); 143 pr_debug("gator: registered tracepoints\n");
182 144
183 return 0; 145 return 0;
184 146
185 // unregister tracepoints on error 147 // unregister tracepoints on error
186fail_sched_process_free: 148fail_sched_process_exit:
187 GATOR_UNREGISTER_TRACE(sched_switch); 149 GATOR_UNREGISTER_TRACE(sched_switch);
188fail_sched_switch: 150fail_sched_switch:
189 pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); 151 pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
@@ -196,14 +158,6 @@ int gator_trace_sched_start(void)
196 int cpu, size; 158 int cpu, size;
197 159
198 for_each_present_cpu(cpu) { 160 for_each_present_cpu(cpu) {
199 per_cpu(theSchedSel, cpu) = 0;
200 per_cpu(theSchedPos, cpu) = 0;
201 per_cpu(theSchedErr, cpu) = 0;
202 per_cpu(theSchedBuf, cpu)[0] = kmalloc(SCHEDSIZE * sizeof(uint64_t), GFP_KERNEL);
203 per_cpu(theSchedBuf, cpu)[1] = kmalloc(SCHEDSIZE * sizeof(uint64_t), GFP_KERNEL);
204 if (!per_cpu(theSchedBuf, cpu))
205 return -1;
206
207 size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t); 161 size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t);
208 per_cpu(taskname_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL); 162 per_cpu(taskname_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL);
209 if (!per_cpu(taskname_keys, cpu)) 163 if (!per_cpu(taskname_keys, cpu))
@@ -214,16 +168,15 @@ int gator_trace_sched_start(void)
214 return register_scheduler_tracepoints(); 168 return register_scheduler_tracepoints();
215} 169}
216 170
217int gator_trace_sched_offline(long long **buffer) 171void gator_trace_sched_offline(void)
218{ 172{
219 trace_sched_insert_idle(); 173 trace_sched_insert_idle();
220 return gator_trace_sched_read(buffer);
221} 174}
222 175
223static void unregister_scheduler_tracepoints(void) 176static void unregister_scheduler_tracepoints(void)
224{ 177{
225 GATOR_UNREGISTER_TRACE(sched_switch); 178 GATOR_UNREGISTER_TRACE(sched_switch);
226 GATOR_UNREGISTER_TRACE(sched_process_free); 179 GATOR_UNREGISTER_TRACE(sched_process_exit);
227 pr_debug("gator: unregistered tracepoints\n"); 180 pr_debug("gator: unregistered tracepoints\n");
228} 181}
229 182
@@ -233,37 +186,6 @@ void gator_trace_sched_stop(void)
233 unregister_scheduler_tracepoints(); 186 unregister_scheduler_tracepoints();
234 187
235 for_each_present_cpu(cpu) { 188 for_each_present_cpu(cpu) {
236 kfree(per_cpu(theSchedBuf, cpu)[0]);
237 kfree(per_cpu(theSchedBuf, cpu)[1]);
238 per_cpu(theSchedBuf, cpu)[0] = NULL;
239 per_cpu(theSchedBuf, cpu)[1] = NULL;
240 kfree(per_cpu(taskname_keys, cpu)); 189 kfree(per_cpu(taskname_keys, cpu));
241 } 190 }
242} 191}
243
244int gator_trace_sched_read(long long **buffer)
245{
246 int cpu = smp_processor_id();
247 unsigned long flags;
248 uint64_t *schedBuf;
249 int schedPos;
250
251 if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
252 return 0;
253
254 local_irq_save(flags);
255
256 schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
257 schedPos = per_cpu(theSchedPos, cpu);
258
259 per_cpu(theSchedSel, cpu) = !per_cpu(theSchedSel, cpu);
260 per_cpu(theSchedPos, cpu) = 0;
261