aboutsummaryrefslogtreecommitdiff
path: root/driver/gator_main.c
diff options
context:
space:
mode:
authorDrew Richardson <drew.richardson@arm.com>2012-05-15 12:00:00 -0700
committerDrew Richardson <drew.richardson@arm.com>2014-12-19 15:27:22 -0800
commit3abe11d177c6c93fab66d04fd42d11452a0c508e (patch)
tree9ddc541993bd0859f27bf7468e44b5155e5a0494 /driver/gator_main.c
parent3de04f9cecf0d50e895f9fe0164ecbbbae997319 (diff)
gator: Version 5.105.10
Signed-off-by: Drew Richardson <drew.richardson@arm.com>
Diffstat (limited to 'driver/gator_main.c')
-rw-r--r--driver/gator_main.c471
1 files changed, 224 insertions, 247 deletions
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 @@
*
*/
-static unsigned long gator_protocol_version = 8;
+static unsigned long gator_protocol_version = 9;
#include <linux/slab.h>
#include <linux/cpu.h>
@@ -39,7 +39,7 @@ static unsigned long gator_protocol_version = 8;
#endif
#ifndef CONFIG_HIGH_RES_TIMERS
-#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined
+#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined to support PC sampling
#endif
#if defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
@@ -48,37 +48,39 @@ static unsigned long gator_protocol_version = 8;
#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT))
#ifndef CONFIG_PERF_EVENTS
-#warning gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
+#error gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
#elif !defined CONFIG_HW_PERF_EVENTS
-#warning gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
+#error gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
#endif
#endif
-#if (!(GATOR_CPU_FREQ_SUPPORT))
-#warning gator requires kernel version 2.6.38 or greater and CONFIG_CPU_FREQ defined in order to enable the CPU Freq timeline chart
-#endif
-
/******************************************************************************
* DEFINES
******************************************************************************/
-#define TIMER_BUFFER_SIZE_DEFAULT (512*1024)
-#define EVENT_BUFFER_SIZE_DEFAULT (128*1024)
+#define BACKTRACE_BUFFER_SIZE (128*1024)
+#define COUNTER_BUFFER_SIZE (128*1024)
+#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
+#define SCHED_TRACE_BUFFER_SIZE (128*1024)
+#define GPU_TRACE_BUFFER_SIZE (64*1024)
+#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
+#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
#define NO_COOKIE 0UL
#define INVALID_COOKIE ~0UL
-#define FRAME_HRTIMER 1
-#define FRAME_EVENT 2
-#define FRAME_ANNOTATE 3
+#define FRAME_BACKTRACE 1
+#define FRAME_COUNTER 2
+#define FRAME_ANNOTATE 3
+#define FRAME_SCHED_TRACE 4
+#define FRAME_GPU_TRACE 5
+#define FRAME_COUNTER2 6
+#define FRAME_WFI 7
-#define MESSAGE_COOKIE 1
-#define MESSAGE_COUNTERS 3
-#define MESSAGE_START_BACKTRACE 5
-#define MESSAGE_END_BACKTRACE 7
-#define MESSAGE_SCHEDULER_TRACE 9
-#define MESSAGE_PID_NAME 11
-#define MESSAGE_GPU_TRACE 13
-#define MESSAGE_OVERFLOW 127
+#define MESSAGE_COOKIE 1
+#define MESSAGE_START_BACKTRACE 5
+#define MESSAGE_END_BACKTRACE 7
+#define MESSAGE_SUMMARY 9
+#define MESSAGE_PID_NAME 11
#define MAXSIZE_PACK32 5
#define MAXSIZE_PACK64 9
@@ -89,7 +91,7 @@ static unsigned long gator_protocol_version = 8;
#define PC_REG regs->ip
#endif
-enum {TIMER_BUF, EVENT_BUF, NUM_GATOR_BUFS};
+enum {BACKTRACE_BUF, COUNTER_BUF, SCHED_TRACE_BUF, GPU_TRACE_BUF, ANNOTATE_BUF, COUNTER2_BUF, WFI_BUF, NUM_GATOR_BUFS};
/******************************************************************************
* Globals
@@ -101,25 +103,26 @@ static unsigned long gator_backtrace_depth;
static unsigned long gator_started;
static unsigned long gator_buffer_opened;
static unsigned long gator_timer_count;
-static unsigned long gator_streaming;
+static unsigned long gator_response_type;
static DEFINE_MUTEX(start_mutex);
static DEFINE_MUTEX(gator_buffer_mutex);
bool event_based_sampling;
static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
-
-static void buffer_check(int cpu, int buftype);
+static LIST_HEAD(gator_events);
/******************************************************************************
* Prototypes
******************************************************************************/
+static void buffer_check(int cpu, int buftype);
+static int buffer_bytes_available(int cpu, int buftype);
static bool buffer_check_space(int cpu, int buftype, int bytes);
+static int contiguous_space_available(int cpu, int bufytpe);
static void gator_buffer_write_packed_int(int cpu, int buftype, unsigned int x);
static void gator_buffer_write_packed_int64(int cpu, int buftype, unsigned long long x);
+static void gator_buffer_write_bytes(int cpu, int buftype, char *x, int len);
static void gator_buffer_write_string(int cpu, int buftype, char *x);
-static int gator_write_packed_int(char *buffer, unsigned int x);
-static int gator_write_packed_int64(char *buffer, unsigned long long x);
static void gator_add_trace(int cpu, int buftype, unsigned int address);
static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs);
static uint64_t gator_get_time(void);
@@ -131,15 +134,16 @@ static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_write);
static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_commit);
static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], buffer_space_available);
static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer);
-static DEFINE_PER_CPU(uint64_t, emit_overflow);
/******************************************************************************
* Application Includes
******************************************************************************/
+#include "gator_marshaling.c"
#include "gator_hrtimer_perf.c"
#include "gator_hrtimer_gator.c"
#include "gator_cookies.c"
#include "gator_trace_sched.c"
+#include "gator_trace_power.c"
#include "gator_trace_gpu.c"
#include "gator_backtrace.c"
#include "gator_annotate.c"
@@ -179,10 +183,10 @@ static bool buffer_commit_ready(int* cpu, int* buftype)
/******************************************************************************
* Buffer management
******************************************************************************/
-static bool buffer_check_space(int cpu, int buftype, int bytes)
+static int buffer_bytes_available(int cpu, int buftype)
{
int remaining, filled;
-
+
filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype];
if (filled < 0) {
filled += gator_buffer_size[buftype];
@@ -198,12 +202,24 @@ static bool buffer_check_space(int cpu, int buftype, int bytes)
remaining -= 2000;
}
+ return remaining;
+}
+
+static int contiguous_space_available(int cpu, int buftype)
+{
+ int remaining = buffer_bytes_available(cpu, buftype);
+ int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype];
+ if (remaining < contiguous)
+ return remaining;
+ else
+ return contiguous;
+}
+
+static bool buffer_check_space(int cpu, int buftype, int bytes)
+{
+ int remaining = buffer_bytes_available(cpu, buftype);
+
if (remaining < bytes) {
- if (per_cpu(buffer_space_available, cpu)[buftype] == true) {
- // overflow packet to be emitted at a later time, as we may be in the middle of writing a message, e.g. counters
- per_cpu(emit_overflow, cpu) = gator_get_time();
- pr_err("overflow: remaining = %d\n", gator_buffer_size[buftype] - filled);
- }
per_cpu(buffer_space_available, cpu)[buftype] = false;
} else {
per_cpu(buffer_space_available, cpu)[buftype] = true;
@@ -238,19 +254,33 @@ static void gator_buffer_header(int cpu, int buftype)
{
int frame;
- if (buftype == TIMER_BUF)
- frame = FRAME_HRTIMER;
- else if (buftype == EVENT_BUF)
- frame = FRAME_EVENT;
+ if (buftype == BACKTRACE_BUF)
+ frame = FRAME_BACKTRACE;
+ else if (buftype == COUNTER_BUF)
+ frame = FRAME_COUNTER;
+ else if (buftype == ANNOTATE_BUF)
+ frame = FRAME_ANNOTATE;
+ else if (buftype == SCHED_TRACE_BUF)
+ frame = FRAME_SCHED_TRACE;
+ else if (buftype == GPU_TRACE_BUF)
+ frame = FRAME_GPU_TRACE;
+ else if (buftype == COUNTER2_BUF)
+ frame = FRAME_COUNTER2;
+ else if (buftype == WFI_BUF)
+ frame = FRAME_WFI;
else
frame = -1;
- gator_buffer_write_packed_int(cpu, buftype, frame);
- gator_buffer_write_packed_int(cpu, buftype, cpu);
+ if (per_cpu(gator_buffer, cpu)[buftype]) {
+ marshal_frame(cpu, buftype, frame);
+ }
}
static void gator_commit_buffer(int cpu, int buftype)
{
+ if (!per_cpu(gator_buffer, cpu)[buftype])
+ return;
+
per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
gator_buffer_header(cpu, buftype);
wake_up(&gator_buffer_wait);
@@ -276,8 +306,7 @@ static void gator_add_trace(int cpu, int buftype, unsigned int address)
offset = address;
}
- gator_buffer_write_packed_int(cpu, buftype, offset & ~1);
- gator_buffer_write_packed_int(cpu, buftype, cookie);
+ marshal_backtrace(offset & ~1, cookie);
}
static 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)
if (!regs)
return;
- gator_buffer_write_packed_int(cpu, buftype, MESSAGE_START_BACKTRACE);
- gator_buffer_write_packed_int64(cpu, buftype, gator_get_time());
- gator_buffer_write_packed_int(cpu, buftype, exec_cookie);
- gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->tgid);
- gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->pid);
- gator_buffer_write_packed_int(cpu, buftype, inKernel);
+ if (!marshal_backtrace_header(exec_cookie, current->tgid, current->pid, inKernel))
+ return;
if (inKernel) {
kernel_backtrace(cpu, buftype, regs);
@@ -306,142 +331,54 @@ static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs)
arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth);
}
- gator_buffer_write_packed_int(cpu, buftype, MESSAGE_END_BACKTRACE);
+ marshal_backtrace_footer();
}
/******************************************************************************
* hrtimer interrupt processing
******************************************************************************/
-static LIST_HEAD(gator_events);
-
static void gator_timer_interrupt(void)
{
struct pt_regs * const regs = get_irq_regs();
int cpu = smp_processor_id();
- int *buffer, len, i, buftype = TIMER_BUF;
- long long *buffer64;
- struct gator_interface *gi;
-
- // Output scheduler trace
- len = gator_trace_sched_read(&buffer64);
- if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
- gator_buffer_write_packed_int(cpu, buftype, MESSAGE_SCHEDULER_TRACE);
- gator_buffer_write_packed_int(cpu, buftype, len);
- for (i = 0; i < len; i++) {
- gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
- }
- }
-
- // Output GPU trace
- len = gator_trace_gpu_read(&buffer64);
- if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
- gator_buffer_write_packed_int(cpu, buftype, MESSAGE_GPU_TRACE);
- gator_buffer_write_packed_int(cpu, buftype, len);
- for (i = 0; i < len; i++) {
- gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
- }
- }
-
- // Output counters
- if (buffer_check_space(cpu, buftype, MAXSIZE_PACK32 * 2 + MAXSIZE_PACK64)) {
- gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COUNTERS);
- gator_buffer_write_packed_int64(cpu, buftype, gator_get_time());
- list_for_each_entry(gi, &gator_events, list) {
- if (gi->read) {
- len = gi->read(&buffer);
- if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK32 + MAXSIZE_PACK32)) {
- gator_buffer_write_packed_int(cpu, buftype, len);
- for (i = 0; i < len; i++) {
- gator_buffer_write_packed_int(cpu, buftype, buffer[i]);
- }
- }
- } else if (gi->read64) {
- len = gi->read64(&buffer64);
- if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK64 + MAXSIZE_PACK32)) {
- gator_buffer_write_packed_int(cpu, buftype, len);
- for (i = 0; i < len; i++) {
- gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
- }
- }
- }
- }
- gator_buffer_write_packed_int(cpu, buftype, 0);
- }
// Output backtrace
- if (!event_based_sampling && buffer_check_space(cpu, buftype, gator_backtrace_depth * 2 * MAXSIZE_PACK32))
- gator_add_sample(cpu, buftype, regs);
-
- // Overflow message
- if (per_cpu(emit_overflow, cpu)) {
- gator_buffer_write_packed_int(cpu, buftype, MESSAGE_OVERFLOW);
- gator_buffer_write_packed_int64(cpu, buftype, per_cpu(emit_overflow, cpu));
- per_cpu(emit_overflow, cpu) = 0;
- }
+ gator_add_sample(cpu, BACKTRACE_BUF, regs);
- // Check and commit; generally, commit is set to occur once per second
- buffer_check(cpu, buftype);
+ // Collect counters
+ collect_counters();
}
-DEFINE_PER_CPU(int, hrtimer_is_active);
-static int hrtimer_running;
+static int gator_running;
// This function runs in interrupt context and on the appropriate core
static void gator_timer_offline(void* unused)
{
+ struct gator_interface *gi;
int i, len, cpu = smp_processor_id();
int* buffer;
- long long* buffer64;
-
- if (per_cpu(hrtimer_is_active, cpu)) {
- struct gator_interface *gi;
- gator_hrtimer_offline(cpu);
- per_cpu(hrtimer_is_active, cpu) = 0;
-
- // Output scheduler trace
- len = gator_trace_sched_offline(&buffer64);
- if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
- gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_SCHEDULER_TRACE);
- gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
- for (i = 0; i < len; i++) {
- gator_buffer_write_packed_int64(cpu, TIMER_BUF, buffer64[i]);
- }
- }
- // Output GPU trace
- len = gator_trace_gpu_offline(&buffer64);
- if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
- gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_GPU_TRACE);
- gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
- for (i = 0; i < len; i++) {
- gator_buffer_write_packed_int64(cpu, TIMER_BUF, buffer64[i]);
- }
- }
+ gator_trace_sched_offline();
+ gator_trace_power_offline();
- // offline any events and output counters
- gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_COUNTERS);
- gator_buffer_write_packed_int64(cpu, TIMER_BUF, gator_get_time());
+ gator_hrtimer_offline(cpu);
+
+ // Offline any events and output counters
+ if (marshal_event_header()) {
list_for_each_entry(gi, &gator_events, list) {
if (gi->offline) {
len = gi->offline(&buffer);
- if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK32 + MAXSIZE_PACK32)) {
- gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
- for (i = 0; i < len; i++)
- gator_buffer_write_packed_int(cpu, TIMER_BUF, buffer[i]);
- }
+ marshal_event(len, buffer);
}
}
- gator_buffer_write_packed_int(cpu, TIMER_BUF, 0);
-
- gator_commit_buffer(cpu, TIMER_BUF);
}
- if (event_based_sampling) {
- gator_commit_buffer(cpu, EVENT_BUF);
- }
+ // Flush all buffers on this core
+ for (i = 0; i < NUM_GATOR_BUFS; i++)
+ gator_commit_buffer(cpu, i);
}
-// This function runs in interrupt context and may be running on a core other than core 'cpu'
+// This function runs in process context and may be running on a core other than core 'cpu'
static void gator_timer_offline_dispatch(int cpu)
{
struct gator_interface *gi;
@@ -457,13 +394,13 @@ static void gator_timer_stop(void)
{
int cpu;
- if (hrtimer_running) {
+ if (gator_running) {
on_each_cpu(gator_timer_offline, NULL, 1);
for_each_online_cpu(cpu) {
gator_timer_offline_dispatch(cpu);
}
- hrtimer_running = 0;
+ gator_running = 0;
gator_hrtimer_shutdown();
}
}
@@ -471,32 +408,23 @@ static void gator_timer_stop(void)
// This function runs in interrupt context and on the appropriate core
static void gator_timer_online(void* unused)
{
- int i, len, cpu = smp_processor_id();
+ struct gator_interface *gi;
+ int len, cpu = smp_processor_id();
int* buffer;
- if (!per_cpu(hrtimer_is_active, cpu)) {
- struct gator_interface *gi;
+ gator_trace_power_online();
- // online any events and output counters
- gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_COUNTERS);
- gator_buffer_write_packed_int64(cpu, TIMER_BUF, gator_get_time());
+ // online any events and output counters
+ if (marshal_event_header()) {
list_for_each_entry(gi, &gator_events, list) {
if (gi->online) {
len = gi->online(&buffer);
- if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK32 + MAXSIZE_PACK32)) {
- gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
- for (i = 0; i < len; i++)
- gator_buffer_write_packed_int(cpu, TIMER_BUF, buffer[i]);
- }
+ marshal_event(len, buffer);
}
}
- gator_buffer_write_packed_int(cpu, TIMER_BUF, 0);
-
- gator_event_sampling_online();
-
- gator_hrtimer_online(cpu);
- per_cpu(hrtimer_is_active, cpu) = 1;
}
+
+ gator_hrtimer_online(cpu);
}
// 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)
gator_event_sampling_online_dispatch(cpu);
}
-int gator_timer_start(unsigned long setup)
+int gator_timer_start(unsigned long sample_rate)
{
int cpu;
- if (!setup) {
- pr_err("gator: cannot start due to a system tick value of zero\n");
- return -1;
- } else if (hrtimer_running) {
- pr_notice("gator: high res timer already running\n");
+ if (gator_running) {
+ pr_notice("gator: already running\n");
return 0;
}
- hrtimer_running = 1;
+ gator_running = 1;
- if (gator_hrtimer_init(setup, gator_timer_interrupt) == -1)
+ // event based sampling trumps hr timer based sampling
+ if (event_based_sampling)
+ sample_rate = 0;
+
+ if (gator_hrtimer_init(sample_rate, gator_timer_interrupt) == -1)
return -1;
for_each_online_cpu(cpu) {
@@ -550,7 +479,7 @@ static uint64_t gator_get_time(void)
/******************************************************************************
* cpu hotplug and pm notifiers
******************************************************************************/
-static int __cpuinit gator_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
+static int __cpuinit gator_hotcpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
{
long cpu = (long)hcpu;
@@ -570,8 +499,8 @@ static int __cpuinit gator_cpu_notify(struct notifier_block *self, unsigned long
return NOTIFY_OK;
}
-static struct notifier_block __refdata gator_cpu_notifier = {
- .notifier_call = gator_cpu_notify,
+static struct notifier_block __refdata gator_hotcpu_notifier = {
+ .notifier_call = gator_hotcpu_notify,
};
// 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
switch (event) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
- unregister_hotcpu_notifier(&gator_cpu_notifier);
+ unregister_hotcpu_notifier(&gator_hotcpu_notifier);
unregister_scheduler_tracepoints();
on_each_cpu(gator_timer_offline, NULL, 1);
for_each_online_cpu(cpu) {
@@ -597,7 +526,7 @@ static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void
}
on_each_cpu(gator_timer_online, NULL, 1);
register_scheduler_tracepoints();
- register_hotcpu_notifier(&gator_cpu_notifier);
+ register_hotcpu_notifier(&gator_hotcpu_notifier);
break;
}
@@ -611,7 +540,7 @@ static struct notifier_block gator_pm_notifier = {
static int gator_notifier_start(void)
{
int retval;
- retval = register_hotcpu_notifier(&gator_cpu_notifier);
+ retval = register_hotcpu_notifier(&gator_hotcpu_notifier);
if (retval == 0)
retval = register_pm_notifier(&gator_pm_notifier);
return retval;
@@ -620,12 +549,30 @@ static int gator_notifier_start(void)
static void gator_notifier_stop(void)
{
unregister_pm_notifier(&gator_pm_notifier);
- unregister_hotcpu_notifier(&gator_cpu_notifier);
+ unregister_hotcpu_notifier(&gator_hotcpu_notifier);
}
/******************************************************************************
* Main
******************************************************************************/
+static void gator_summary(void)
+{
+ uint64_t timestamp, uptime = 0;
+ struct timespec uptime_ts;
+ void (*m2b)(struct timespec *ts);
+
+ timestamp = gator_get_time();
+
+ do_posix_clock_monotonic_gettime(&uptime_ts);
+ m2b = symbol_get(monotonic_to_bootbased);
+ if (m2b) {
+ m2b(&uptime_ts);
+ uptime = (long long)uptime_ts.tv_sec * 1000000000 + uptime_ts.tv_nsec;
+ }
+
+ marshal_summary(timestamp, uptime);
+}
+
int gator_events_install(struct gator_interface *interface)
{
list_add_tail(&interface->list, &gator_events);
@@ -635,7 +582,8 @@ int gator_events_install(struct gator_interface *interface)
int gator_events_get_key(void)
{
- static int key;
+ // key of zero is reserved as a timestamp
+ static int key = 1;
return key++;
}
@@ -644,21 +592,31 @@ static int gator_init(void)
{
int i;
- if (gator_annotate_init())
- return -1;
-
// events sources (gator_events.h, generated by gator_events.sh)
for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
if (gator_events_list[i])
gator_events_list[i]();
+ gator_trace_power_init();
+
return 0;
}
static int gator_start(void)
{
+ unsigned long cpu, i;
struct gator_interface *gi;
+ // Initialize the buffer with the frame type and core
+ for_each_present_cpu(cpu) {
+ for (i = 0; i < NUM_GATOR_BUFS; i++) {
+ gator_buffer_header(cpu, i);
+ }
+ }
+
+ // Capture the start time
+ gator_summary();
+
// start all events
list_for_each_entry(gi, &gator_events, list) {
if (gi->start && gi->start() != 0) {
@@ -683,6 +641,8 @@ static int gator_start(void)
goto annotate_failure;
if (gator_trace_sched_start())
goto sched_failure;
+ if (gator_trace_power_start())
+ goto power_failure;
if (gator_trace_gpu_start())
goto gpu_failure;
if (gator_event_sampling_start())
@@ -701,6 +661,8 @@ timer_failure:
event_sampling_failure:
gator_trace_gpu_stop();
gpu_failure:
+ gator_trace_power_stop();
+power_failure:
gator_trace_sched_stop();
sched_failure:
gator_annotate_stop();
@@ -727,6 +689,7 @@ static void gator_stop(void)
gator_annotate_stop();
gator_trace_sched_stop();
+ gator_trace_power_stop();
gator_trace_gpu_stop();
gator_event_sampling_stop();
@@ -735,11 +698,6 @@ static void gator_stop(void)
gator_timer_stop();
}
-static void gator_exit(void)
-{
- gator_annotate_exit();
-}
-
/******************************************************************************
* Filesystem
******************************************************************************/
@@ -751,33 +709,52 @@ static int gator_op_setup(void)
mutex_lock(&start_mutex);
- gator_buffer_size[TIMER_BUF] = userspace_buffer_size;
- gator_buffer_mask[TIMER_BUF] = userspace_buffer_size - 1;
+ gator_buffer_size[BACKTRACE_BUF] = BACKTRACE_BUFFER_SIZE;
+ gator_buffer_mask[BACKTRACE_BUF] = BACKTRACE_BUFFER_SIZE - 1;
- // must be a power of 2
- if (gator_buffer_size[TIMER_BUF] & (gator_buffer_size[TIMER_BUF] - 1)) {
- err = -ENOEXEC;
- goto setup_error;
- }
+ gator_buffer_size[COUNTER_BUF] = COUNTER_BUFFER_SIZE;
+ gator_buffer_mask[COUNTER_BUF] = COUNTER_BUFFER_SIZE - 1;
+
+ gator_buffer_size[SCHED_TRACE_BUF] = SCHED_TRACE_BUFFER_SIZE;
+ gator_buffer_mask[SCHED_TRACE_BUF] = SCHED_TRACE_BUFFER_SIZE - 1;
+
+ gator_buffer_size[GPU_TRACE_BUF] = GPU_TRACE_BUFFER_SIZE;
+ gator_buffer_mask[GPU_TRACE_BUF] = GPU_TRACE_BUFFER_SIZE - 1;
- gator_buffer_size[EVENT_BUF] = EVENT_BUFFER_SIZE_DEFAULT;
- gator_buffer_mask[EVENT_BUF] = gator_buffer_size[EVENT_BUF] - 1;
+ gator_buffer_size[ANNOTATE_BUF] = ANNOTATE_BUFFER_SIZE;
+ gator_buffer_mask[ANNOTATE_BUF] = ANNOTATE_BUFFER_SIZE - 1;
+
+ gator_buffer_size[COUNTER2_BUF] = COUNTER2_BUFFER_SIZE;
+ gator_buffer_mask[COUNTER2_BUF] = COUNTER2_BUFFER_SIZE - 1;
+
+ gator_buffer_size[WFI_BUF] = WFI_BUFFER_SIZE;
+ gator_buffer_mask[WFI_BUF] = WFI_BUFFER_SIZE - 1;
// Initialize percpu per buffer variables
for (i = 0; i < NUM_GATOR_BUFS; i++) {
+ // Verify buffers are a power of 2
+ if (gator_buffer_size[i] & (gator_buffer_size[i] - 1)) {
+ err = -ENOEXEC;
+ goto setup_error;
+ }
+
for_each_present_cpu(cpu) {
+ per_cpu(gator_buffer_read, cpu)[i] = 0;
+ per_cpu(gator_buffer_write, cpu)[i] = 0;
+ per_cpu(gator_buffer_commit, cpu)[i] = 0;
+ per_cpu(buffer_space_available, cpu)[i] = true;
+
+ // Annotation is a special case that only uses a single buffer
+ if (cpu > 0 && i == ANNOTATE_BUF) {
+ per_cpu(gator_buffer, cpu)[i] = NULL;
+ continue;
+ }
+
per_cpu(gator_buffer, cpu)[i] = vmalloc(gator_buffer_size[i]);
if (!per_cpu(gator_buffer, cpu)[i]) {
err = -ENOMEM;
goto setup_error;
}
-
- per_cpu(gator_buffer_read, cpu)[i] = 0;
- per_cpu(gator_buffer_write, cpu)[i] = 0;
- per_cpu(gator_buffer_commit, cpu)[i] = 0;
- per_cpu(buffer_space_available, cpu)[i] = true;
- per_cpu(emit_overflow, cpu) = 0;
- gator_buffer_header(cpu, i);
}
}
@@ -829,8 +806,6 @@ static void gator_shutdown(void)
mutex_lock(&start_mutex);
- gator_annotate_shutdown();
-
for_each_present_cpu(cpu) {
mutex_lock(&gator_buffer_mutex);
for (i = 0; i < NUM_GATOR_BUFS; i++) {
@@ -840,7 +815,6 @@ static void gator_shutdown(void)
per_cpu(gator_buffer_write, cpu)[i] = 0;
per_cpu(gator_buffer_commit, cpu)[i] = 0;
per_cpu(buffer_space_available, cpu)[i] = true;
- per_cpu(emit_overflow, cpu) = 0;
}
mutex_unlock(&gator_buffer_mutex);
}
@@ -932,7 +906,7 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
size_t count, loff_t *offset)
{
int retval = -EINVAL;
- int commit = 0, length1, length2, read;
+ int commit = 0, length, length1, length2, read, byte, type_length;
char *buffer1;
char *buffer2 = NULL;
int cpu, buftype;
@@ -944,7 +918,7 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
// sleep until the condition is true or a signal is received
// the condition is checked each time gator_buffer_wait is woken up
buftype = cpu = -1;
- wait_event_interruptible(gator_buffer_wait, buffer_commit_ready(&cpu, &buftype) || gator_annotate_ready() || !gator_started);
+ wait_event_interruptible(gator_buffer_wait, buffer_commit_ready(&cpu, &buftype) || !gator_started);
if (signal_pending(current))
return -EINTR;
@@ -954,33 +928,36 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
mutex_lock(&gator_buffer_mutex);
- if (buftype != -1 && cpu != -1) {
- read = per_cpu(gator_buffer_read, cpu)[buftype];
- commit = per_cpu(gator_buffer_commit, cpu)[buftype];
+ if (buftype == -1 || cpu == -1) {
+ retval = 0;
+ goto out;
+ }
- /* May happen if the buffer is freed during pending reads. */
- if (!per_cpu(gator_buffer, cpu)[buftype]) {
- retval = -EFAULT;
- goto out;
- }
+ read = per_cpu(gator_buffer_read, cpu)[buftype];
+ commit = per_cpu(gator_buffer_commit, cpu)[buftype];
- /* determine the size of two halves */
- length1 = commit - read;
- buffer1 = &(per_cpu(gator_buffer, cpu)[buftype][read]);
- buffer2 = &(per_cpu(gator_buffer, cpu)[buftype][0]);
- if (length1 < 0) {
- length1 = gator_buffer_size[buftype] - read;
- length2 = commit;
- }
- } else if (gator_annotate_ready()) {
- length1 = gator_annotate_read(&buffer1);
- if (!length1)
- goto out;
- } else {
- retval = 0;
+ /* May happen if the buffer is freed during pending reads. */
+ if (!per_cpu(gator_buffer, cpu)[buftype]) {
+ retval = -EFAULT;
goto out;
}
+ /* determine the size of two halves */
+ length1 = commit - read;
+ buffer1 = &(per_cpu(gator_buffer, cpu)[buftype][read]);
+ buffer2 = &(per_cpu(gator_buffer, cpu)[buftype][0]);
+ if (length1 < 0) {
+ length1 = gator_buffer_size[buftype] - read;
+ length2 = commit;
+ }
+
+ // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
+ type_length = gator_response_type ? 1 : 0;
+ length = length1 + length2 - type_length - sizeof(int);
+ for (byte = 0; byte < sizeof(int); byte++) {
+ per_cpu(gator_buffer, cpu)[buftype][(read + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
+ }
+
/* start, middle or end */
if (length1 > 0) {
if (copy_to_user(&buf[0], buffer1, length1)) {
@@ -995,9 +972,7 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
}
}
- if (buftype != -1 && cpu != -1)
- per_cpu(gator_buffer_read, cpu)[buftype] = commit;
-
+ per_cpu(gator_buffer_read, cpu)[buftype] = commit;
retval = length1 + length2;
/* 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)
for_each_present_cpu(cpu) {
gator_cpu_cores++;
}
- userspace_buffer_size = TIMER_BUFFER_SIZE_DEFAULT;
- gator_streaming = 1;
+ userspace_buffer_size = BACKTRACE_BUFFER_SIZE;
+ gator_response_type = 1;
gatorfs_create_file(sb, root, "enable", &enable_fops);
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)
gatorfs_create_ulong(sb, root, "cpu_cores", &gator_cpu_cores);
gatorfs_create_ulong(sb, root, "buffer_size", &userspace_buffer_size);
gatorfs_create_ulong(sb, root, "tick", &gator_timer_count);
- gatorfs_create_ulong(sb, root, "streaming", &gator_streaming);
+ gatorfs_create_ulong(sb, root, "response_type", &gator_response_type);
gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version);
// Annotate interface
@@ -1075,6 +1050,9 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
list_for_each_entry(gi, &gator_events, list)
if (gi->create_files)
gi->create_files(sb, dir);
+
+ // Power interface
+ gator_trace_power_create_files(sb, dir);
}
/******************************************************************************
@@ -1098,7 +1076,6 @@ static void __exit gator_module_exit(void)
{
tracepoint_synchronize_unregister();
gatorfs_unregister();
- gator_exit();
}
module_init(gator_module_init);