diff options
author | Drew Richardson <drew.richardson@arm.com> | 2012-05-15 12:00:00 -0700 |
---|---|---|
committer | Drew Richardson <drew.richardson@arm.com> | 2014-12-19 15:27:22 -0800 |
commit | 3abe11d177c6c93fab66d04fd42d11452a0c508e (patch) | |
tree | 9ddc541993bd0859f27bf7468e44b5155e5a0494 /driver/gator_main.c | |
parent | 3de04f9cecf0d50e895f9fe0164ecbbbae997319 (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.c | 471 |
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); |