diff --git a/driver/gator_main.c b/driver/gator_main.c
index 46fe31d2505dbe4f49cfbfaba3c127e914b9d190..55772ef71d0d5ee683d704a1a40e091d2e593652 100644 (file)
--- a/driver/gator_main.c
+++ b/driver/gator_main.c
/**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2014. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
*/
// This version must match the gator daemon version
-static unsigned long gator_protocol_version = 14;
+#define PROTOCOL_VERSION 18
+static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/perf_event.h>
#include <linux/utsname.h>
+#include <linux/kthread.h>
#include <asm/stacktrace.h>
#include <asm/uaccess.h>
#include "gator.h"
-#include "gator_events.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
#error kernels prior to 2.6.32 are not supported
#endif
+#if defined(MODULE) && !defined(CONFIG_MODULES)
+#error Cannot build a module against a kernel that does not support modules. To resolve, either rebuild the kernel to support modules or build gator as part of the kernel.
+#endif
+
#if !defined(CONFIG_GENERIC_TRACER) && !defined(CONFIG_TRACING)
#error gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined
#endif
#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)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
#error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems
#endif
#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT))
#ifndef CONFIG_PERF_EVENTS
-#error gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
+#warning gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
#elif !defined CONFIG_HW_PERF_EVENTS
-#error gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
+#warning gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
#endif
#endif
#define NAME_BUFFER_SIZE (64*1024)
#define COUNTER_BUFFER_SIZE (64*1024) // counters have the core as part of the data and the core value in the frame header may be discarded
#define BLOCK_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 ANNOTATE_BUFFER_SIZE (128*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) // gpu trace counters have the core as part of the data and the core value in the frame header may be discarded
#define IDLE_BUFFER_SIZE (32*1024) // idle counters have the core as part of the data and the core value in the frame header may be discarded
#define NO_COOKIE 0U
-#define INVALID_COOKIE ~0U
+#define UNRESOLVED_COOKIE ~0U
#define FRAME_SUMMARY 1
#define FRAME_BACKTRACE 2
#define MESSAGE_END_BACKTRACE 1
+// Name Frame Messages
#define MESSAGE_COOKIE 1
#define MESSAGE_THREAD_NAME 2
-#define HRTIMER_CORE_NAME 3
+#define MESSAGE_LINK 4
+// GPU Trace Frame Messages
#define MESSAGE_GPU_START 1
#define MESSAGE_GPU_STOP 2
+// Scheduler Trace Frame Messages
#define MESSAGE_SCHED_SWITCH 1
#define MESSAGE_SCHED_EXIT 2
+#define MESSAGE_SCHED_START 3
+// Idle Frame Messages
#define MESSAGE_IDLE_ENTER 1
-#define MESSAGE_IDLE_EXIT 2
+#define MESSAGE_IDLE_EXIT 2
+
+// Summary Frame Messages
+#define MESSAGE_SUMMARY 1
+#define MESSAGE_CORE_NAME 3
#define MAXSIZE_PACK32 5
#define MAXSIZE_PACK64 10
static unsigned long gator_started;
static u64 gator_monotonic_started;
+static u64 gator_hibernate_time;
static unsigned long gator_buffer_opened;
static unsigned long gator_timer_count;
static unsigned long gator_response_type;
static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait);
static struct timer_list gator_buffer_wake_up_timer;
+static bool gator_buffer_wake_run;
+// Initialize semaphore unlocked to initialize memory values
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+static DECLARE_MUTEX(gator_buffer_wake_sem);
+#else
+static DEFINE_SEMAPHORE(gator_buffer_wake_sem);
+#endif
+static struct task_struct *gator_buffer_wake_thread;
static LIST_HEAD(gator_events);
static DEFINE_PER_CPU(u64, last_timestamp);
static bool sent_core_name[NR_CPUS];
+static DEFINE_PER_CPU(bool, in_scheduler_context);
+
/******************************************************************************
* Prototypes
******************************************************************************/
-static void buffer_check(int cpu, int buftype, u64 time);
-static void gator_commit_buffer(int cpu, int buftype, u64 time);
-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, int x);
-static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x);
-static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len);
-static void gator_buffer_write_string(int cpu, int buftype, const char *x);
-static void gator_add_trace(int cpu, unsigned long address);
-static void gator_add_sample(int cpu, struct pt_regs *const regs);
static u64 gator_get_time(void);
+static void gator_op_create_files(struct super_block *sb, struct dentry *root);
+
+// gator_buffer is protected by being per_cpu and by having IRQs disabled when writing to it.
+// Most marshal_* calls take care of this except for marshal_cookie*, marshal_backtrace* and marshal_frame where the caller is responsible for doing so.
+// No synchronization is needed with the backtrace buffer as it is per cpu and is only used from the hrtimer.
+// The annotate_lock must be held when using the annotation buffer as it is not per cpu.
+// collect_counters which is the sole writer to the block counter frame is additionally protected by the per cpu collecting flag
// Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup.
static uint32_t gator_buffer_size[NUM_GATOR_BUFS];
static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], buffer_space_available);
// The buffer. Allocated in gator_op_setup
static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer);
-
-#if GATOR_LIVE
// The time after which the buffer should be committed for live display
static DEFINE_PER_CPU(u64, gator_buffer_commit_time);
-#endif
+
+// List of all gator events - new events must be added to this list
+#define GATOR_EVENTS_LIST \
+ GATOR_EVENT(gator_events_armv6_init) \
+ GATOR_EVENT(gator_events_armv7_init) \
+ GATOR_EVENT(gator_events_block_init) \
+ GATOR_EVENT(gator_events_ccn504_init) \
+ GATOR_EVENT(gator_events_irq_init) \
+ GATOR_EVENT(gator_events_l2c310_init) \
+ GATOR_EVENT(gator_events_mali_init) \
+ GATOR_EVENT(gator_events_mali_t6xx_hw_init) \
+ GATOR_EVENT(gator_events_mali_t6xx_init) \
+ GATOR_EVENT(gator_events_meminfo_init) \
+ GATOR_EVENT(gator_events_mmapped_init) \
+ GATOR_EVENT(gator_events_net_init) \
+ GATOR_EVENT(gator_events_perf_pmu_init) \
+ GATOR_EVENT(gator_events_sched_init) \
+ GATOR_EVENT(gator_events_scorpion_init) \
+
+#define GATOR_EVENT(EVENT_INIT) __weak int EVENT_INIT(void);
+GATOR_EVENTS_LIST
+#undef GATOR_EVENT
+
+static int (*gator_events_list[])(void) = {
+#define GATOR_EVENT(EVENT_INIT) EVENT_INIT,
+GATOR_EVENTS_LIST
+#undef GATOR_EVENT
+};
/******************************************************************************
* Application Includes
******************************************************************************/
+#include "gator_fs.c"
+#include "gator_buffer_write.c"
+#include "gator_buffer.c"
#include "gator_marshaling.c"
-#include "gator_hrtimer_perf.c"
#include "gator_hrtimer_gator.c"
#include "gator_cookies.c"
+#include "gator_annotate.c"
#include "gator_trace_sched.c"
#include "gator_trace_power.c"
#include "gator_trace_gpu.c"
#include "gator_backtrace.c"
-#include "gator_annotate.c"
-#include "gator_fs.c"
-#include "gator_pack.c"
/******************************************************************************
* Misc
******************************************************************************/
-const struct gator_cpu gator_cpus[] = {
+static const struct gator_cpu gator_cpus[] = {
{
.cpuid = ARM1136,
.core_name = "ARM1136",
.pmnc_name = "ARM_ARM11",
+ .dt_name = "arm,arm1136",
.pmnc_counters = 3,
},
{
.cpuid = ARM1156,
.core_name = "ARM1156",
.pmnc_name = "ARM_ARM11",
+ .dt_name = "arm,arm1156",
.pmnc_counters = 3,
},
{
.cpuid = ARM1176,
.core_name = "ARM1176",
.pmnc_name = "ARM_ARM11",
+ .dt_name = "arm,arm1176",
.pmnc_counters = 3,
},
{
.cpuid = ARM11MPCORE,
.core_name = "ARM11MPCore",
.pmnc_name = "ARM_ARM11MPCore",
+ .dt_name = "arm,arm11mpcore",
.pmnc_counters = 3,
},
{
.cpuid = CORTEX_A5,
.core_name = "Cortex-A5",
- .pmu_name = "ARMv7_Cortex_A5",
- .pmnc_name = "ARM_Cortex-A5",
+ .pmnc_name = "ARMv7_Cortex_A5",
+ .dt_name = "arm,cortex-a5",
.pmnc_counters = 2,
},
{
.cpuid = CORTEX_A7,
.core_name = "Cortex-A7",
- .pmu_name = "ARMv7_Cortex_A7",
- .pmnc_name = "ARM_Cortex-A7",
+ .pmnc_name = "ARMv7_Cortex_A7",
+ .dt_name = "arm,cortex-a7",
.pmnc_counters = 4,
},
{
.cpuid = CORTEX_A8,
.core_name = "Cortex-A8",
- .pmu_name = "ARMv7_Cortex_A8",
- .pmnc_name = "ARM_Cortex-A8",
+ .pmnc_name = "ARMv7_Cortex_A8",
+ .dt_name = "arm,cortex-a8",
.pmnc_counters = 4,
},
{
.cpuid = CORTEX_A9,
.core_name = "Cortex-A9",
- .pmu_name = "ARMv7_Cortex_A9",
- .pmnc_name = "ARM_Cortex-A9",
+ .pmnc_name = "ARMv7_Cortex_A9",
+ .dt_name = "arm,cortex-a9",
+ .pmnc_counters = 6,
+ },
+ {
+ .cpuid = CORTEX_A12,
+ .core_name = "Cortex-A12",
+ .pmnc_name = "ARMv7_Cortex_A12",
+ .dt_name = "arm,cortex-a12",
.pmnc_counters = 6,
},
{
.cpuid = CORTEX_A15,
.core_name = "Cortex-A15",
- .pmu_name = "ARMv7_Cortex_A15",
- .pmnc_name = "ARM_Cortex-A15",
+ .pmnc_name = "ARMv7_Cortex_A15",
+ .dt_name = "arm,cortex-a15",
+ .pmnc_counters = 6,
+ },
+ {
+ .cpuid = CORTEX_A17,
+ .core_name = "Cortex-A17",
+ .pmnc_name = "ARMv7_Cortex_A17",
+ .dt_name = "arm,cortex-a17",
.pmnc_counters = 6,
},
{
.cpuid = CORTEX_A53,
.core_name = "Cortex-A53",
.pmnc_name = "ARM_Cortex-A53",
+ .dt_name = "arm,cortex-a53",
.pmnc_counters = 6,
},
{
.cpuid = CORTEX_A57,
.core_name = "Cortex-A57",
.pmnc_name = "ARM_Cortex-A57",
+ .dt_name = "arm,cortex-a57",
.pmnc_counters = 6,
},
{
for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
const struct gator_cpu *const gator_cpu = &gator_cpus[i];
- if (gator_cpu->pmu_name != NULL && strcmp(gator_cpu->pmu_name, name) == 0) {
+ if (gator_cpu->pmnc_name != NULL && strcmp(gator_cpu->pmnc_name, name) == 0) {
return gator_cpu;
}
}
wake_up(&gator_buffer_wait);
}
+static int gator_buffer_wake_func(void *data)
+{
+ for (;;) {
+ if (down_killable(&gator_buffer_wake_sem)) {
+ break;
+ }
+
+ // Eat up any pending events
+ while (!down_trylock(&gator_buffer_wake_sem));
+
+ if (!gator_buffer_wake_run) {
+ break;
+ }
+
+ gator_buffer_wake_up(0);
+ }
+
+ return 0;
+}
+
/******************************************************************************
* Commit interface
******************************************************************************/
return false;
}
-/******************************************************************************
- * Buffer management
- ******************************************************************************/
-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];
- }
-
- remaining = gator_buffer_size[buftype] - filled;
-
- if (per_cpu(buffer_space_available, cpu)[buftype]) {
- // Give some extra room; also allows space to insert the overflow error packet
- remaining -= 200;
- } else {
- // Hysteresis, prevents multiple overflow messages
- 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) {
- per_cpu(buffer_space_available, cpu)[buftype] = false;
- } else {
- per_cpu(buffer_space_available, cpu)[buftype] = true;
- }
-
- return per_cpu(buffer_space_available, cpu)[buftype];
-}
-
-static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len)
-{
- int i;
- u32 write = per_cpu(gator_buffer_write, cpu)[buftype];
- u32 mask = gator_buffer_mask[buftype];
- char *buffer = per_cpu(gator_buffer, cpu)[buftype];
-
- for (i = 0; i < len; i++) {
- buffer[write] = x[i];
- write = (write + 1) & mask;
- }
-
- per_cpu(gator_buffer_write, cpu)[buftype] = write;
-}
-
-static void gator_buffer_write_string(int cpu, int buftype, const char *x)
-{
- int len = strlen(x);
- gator_buffer_write_packed_int(cpu, buftype, len);
- gator_buffer_write_bytes(cpu, buftype, x, len);
-}
-
-static void gator_commit_buffer(int cpu, int buftype, u64 time)
-{
- int type_length, commit, length, byte;
-
- if (!per_cpu(gator_buffer, cpu)[buftype])
- return;
-
- // 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;
- commit = per_cpu(gator_buffer_commit, cpu)[buftype];
- length = per_cpu(gator_buffer_write, cpu)[buftype] - commit;
- if (length < 0) {
- length += gator_buffer_size[buftype];
- }
- length = length - type_length - sizeof(s32);
-
- if (length <= FRAME_HEADER_SIZE) {
- // Nothing to write, only the frame header is present
- return;
- }
-
- for (byte = 0; byte < sizeof(s32); byte++) {
- per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
- }
-
- per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
-
-#if GATOR_LIVE
- if (gator_live_rate > 0) {
- while (time > per_cpu(gator_buffer_commit_time, cpu)) {
- per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
- }
- }
-#endif
-
- marshal_frame(cpu, buftype);
-
- // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
- mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
-}
-
-static void buffer_check(int cpu, int buftype, u64 time)
-{
- int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype];
- if (filled < 0) {
- filled += gator_buffer_size[buftype];
- }
- if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
- gator_commit_buffer(cpu, buftype, time);
- }
-}
-
-static void gator_add_trace(int cpu, unsigned long address)
-{
- off_t offset = 0;
- unsigned long cookie = get_address_cookie(cpu, current, address & ~1, &offset);
-
- if (cookie == NO_COOKIE || cookie == INVALID_COOKIE) {
- offset = address;
- }
-
- marshal_backtrace(offset & ~1, cookie);
-}
-
-static void gator_add_sample(int cpu, struct pt_regs *const regs)
-{
- bool inKernel;
- unsigned long exec_cookie;
-
- if (!regs)
- return;
-
- inKernel = !user_mode(regs);
- exec_cookie = get_exec_cookie(cpu, current);
-
- if (!marshal_backtrace_header(exec_cookie, current->tgid, current->pid, inKernel))
- return;
-
- if (inKernel) {
- kernel_backtrace(cpu, regs);
- } else {
- // Cookie+PC
- gator_add_trace(cpu, PC_REG);
-
- // Backtrace
- if (gator_backtrace_depth)
- arm_backtrace_eabi(cpu, regs, gator_backtrace_depth);
- }
-
- marshal_backtrace_footer();
-}
-
/******************************************************************************
* hrtimer interrupt processing
******************************************************************************/
void gator_backtrace_handler(struct pt_regs *const regs)
{
+ u64 time = gator_get_time();
int cpu = get_physical_cpu();
// Output backtrace
- gator_add_sample(cpu, regs);
+ gator_add_sample(cpu, regs, time);
// Collect counters
if (!per_cpu(collecting, cpu)) {
- collect_counters();
+ collect_counters(time, NULL);
}
+
+ // No buffer flushing occurs during sched switch for RT-Preempt full. The block counter frame will be flushed by collect_counters, but the sched buffer needs to be explicitly flushed
+#ifdef CONFIG_PREEMPT_RT_FULL
+ buffer_check(cpu, SCHED_TRACE_BUF, time);
+#endif
}
static int gator_running;
}
}
+#if defined(__arm__) || defined(__aarch64__)
+static void gator_send_core_name(int cpu, const u32 cpuid, const struct gator_cpu *const gator_cpu)
+{
+ const char *core_name = NULL;
+ char core_name_buf[32];
+
+ if (!sent_core_name[cpu]) {
+ if (gator_cpu != NULL) {
+ core_name = gator_cpu->core_name;
+ } else {
+ snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.3x)", cpuid);
+ core_name = core_name_buf;
+ }
+
+ marshal_core_name(cpu, cpuid, core_name);
+ sent_core_name[cpu] = true;
+ }
+}
+#endif
+
// This function runs in interrupt context and on the appropriate core
static void gator_timer_online(void *migrate)
{
#if defined(__arm__) || defined(__aarch64__)
if (!sent_core_name[cpu]) {
- const char *core_name = NULL;
const u32 cpuid = gator_cpuid();
- const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(cpuid);
- char core_name_buf[32];
-
- if (gator_cpu != NULL) {
- core_name = gator_cpu->core_name;
- } else {
- snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.3x)", cpuid);
- core_name = core_name_buf;
- }
-
- marshal_core_name(cpuid, core_name);
- sent_core_name[cpu] = true;
+ gator_send_core_name(cpu, cpuid, gator_find_cpu_by_cpuid(cpuid));
}
#endif
}
}
}
-int gator_timer_start(unsigned long sample_rate)
+#include "gator_iks.c"
+
+static int gator_timer_start(unsigned long sample_rate)
{
int cpu;
if (gator_hrtimer_init(sample_rate, gator_timer_interrupt) == -1)
return -1;
+ gator_send_iks_core_names();
for_each_online_cpu(cpu) {
gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false);
}
// getrawmonotonic is not monotonic on all systems. Detect and attempt to correct these cases.
// up to 0.5ms delta has been seen on some systems, which can skew Streamline data when viewing at high resolution.
+ // This doesn't work well with interrupts, but that it's OK - the real concern is to catch big jumps in time
prev_timestamp = per_cpu(last_timestamp, cpu);
if (prev_timestamp <= timestamp) {
per_cpu(last_timestamp, cpu) = timestamp;
/******************************************************************************
* cpu hotplug and pm notifiers
******************************************************************************/
-#include "gator_iks.c"
-
static int __cpuinit gator_hotcpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
{
int cpu = lcpu_to_pcpu((long)hcpu);
static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy)
{
int cpu;
+ struct timespec ts;
switch (event) {
case PM_HIBERNATION_PREPARE:
@@ -800,9 +741,20 @@ static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void
for_each_online_cpu(cpu) {
gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false);
}
+
+ // Record the wallclock hibernate time
+ getnstimeofday(&ts);
+ gator_hibernate_time = timespec_to_ns(&ts) - gator_get_time();
break;
case PM_POST_HIBERNATION:
case PM_POST_SUSPEND:
+ // Adjust gator_monotonic_started for the time spent sleeping, as gator_get_time does not account for it
+ if (gator_hibernate_time > 0) {
+ getnstimeofday(&ts);
+ gator_monotonic_started += gator_hibernate_time + gator_get_time() - timespec_to_ns(&ts);
+ gator_hibernate_time = 0;
+ }
+
for_each_online_cpu(cpu) {
gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false);
}
struct timespec ts;
char uname_buf[512];
void (*m2b)(struct timespec *ts);
- unsigned long flags;
snprintf(uname_buf, sizeof(uname_buf), "%s %s %s %s %s GNU/Linux", utsname()->sysname, utsname()->nodename, utsname()->release, utsname()->version, utsname()->machine);
}
uptime = timespec_to_ns(&ts);
- // Disable interrupts as gator_get_time calls smp_processor_id to verify time is monotonic
- local_irq_save(flags);
+ // Disable preemption as gator_get_time calls smp_processor_id to verify time is monotonic
+ preempt_disable();
// Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started
gator_monotonic_started = 0;
gator_monotonic_started = gator_get_time();
- local_irq_restore(flags);
- marshal_summary(timestamp, uptime, uname_buf);
+ marshal_summary(timestamp, uptime, gator_monotonic_started, uname_buf);
+ preempt_enable();
}
int gator_events_install(struct gator_interface *interface)
int gator_events_get_key(void)
{
- // key of zero is reserved as a timestamp
- static int key = 1;
+ // key 0 is reserved as a timestamp
+ // key 1 is reserved as the marker for thread specific counters
+ // Odd keys are assigned by the driver, even keys by the daemon
+ static int key = 3;
const int ret = key;
key += 2;
calc_first_cluster_size();
- // events sources (gator_events.h, generated by gator_events.sh)
+ // events sources
for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
if (gator_events_list[i])
gator_events_list[i]();
unsigned long cpu, i;
struct gator_interface *gi;
+ gator_buffer_wake_run = true;
+ if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) {
+ goto bwake_failure;
+ }
+
if (gator_migrate_start())
goto migrate_failure;
events_failure:
gator_migrate_stop();
migrate_failure:
+ gator_buffer_wake_run = false;
+ up(&gator_buffer_wake_sem);
+ gator_buffer_wake_thread = NULL;
+bwake_failure:
return -1;
}
gi->stop();
gator_migrate_stop();
+
+ gator_buffer_wake_run = false;
+ up(&gator_buffer_wake_sem);
+ gator_buffer_wake_thread = NULL;
}
/******************************************************************************
per_cpu(gator_buffer_write, cpu)[i] = 0;
per_cpu(gator_buffer_commit, cpu)[i] = 0;
per_cpu(buffer_space_available, cpu)[i] = true;
-#if GATOR_LIVE
per_cpu(gator_buffer_commit_time, cpu) = gator_live_rate;
-#endif
// Annotation is a special case that only uses a single buffer
if (cpu > 0 && i == ANNOTATE_BUF) {
per_cpu(gator_buffer_write, cpu)[i] = 0;
per_cpu(gator_buffer_commit, cpu)[i] = 0;
per_cpu(buffer_space_available, cpu)[i] = true;
-#if GATOR_LIVE
per_cpu(gator_buffer_commit_time, cpu) = 0;
-#endif
}
mutex_unlock(&gator_buffer_mutex);
}
@@ -1297,7 +1259,7 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t
if (buftype == ANNOTATE_BUF) {
wake_up(&gator_annotate_wait);
}
- } while (buffer_commit_ready(&cpu, &buftype));
+ } while (buffer_commit_ready(&cpu, &buftype));
mutex_unlock(&gator_buffer_mutex);
@@ -1307,7 +1269,7 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t
return written > 0 ? written : -EFAULT;
}
-const struct file_operations gator_event_buffer_fops = {
+static const struct file_operations gator_event_buffer_fops = {
.open = userspace_buffer_open,
.release = userspace_buffer_release,
.read = userspace_buffer_read,
.write = depth_write
};
-void gator_op_create_files(struct super_block *sb, struct dentry *root)
+static void gator_op_create_files(struct super_block *sb, struct dentry *root)
{
struct dentry *dir;
struct gator_interface *gi;
/******************************************************************************
* Module
******************************************************************************/
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+
+#define GATOR_TRACEPOINTS \
+ GATOR_HANDLE_TRACEPOINT(block_rq_complete); \
+ GATOR_HANDLE_TRACEPOINT(cpu_frequency); \
+ GATOR_HANDLE_TRACEPOINT(cpu_idle); \
+ GATOR_HANDLE_TRACEPOINT(cpu_migrate_begin); \
+ GATOR_HANDLE_TRACEPOINT(cpu_migrate_current); \
+ GATOR_HANDLE_TRACEPOINT(cpu_migrate_finish); \
+ GATOR_HANDLE_TRACEPOINT(irq_handler_exit); \
+ GATOR_HANDLE_TRACEPOINT(mali_hw_counter); \
+ GATOR_HANDLE_TRACEPOINT(mali_job_slots_event); \
+ GATOR_HANDLE_TRACEPOINT(mali_mmu_as_in_use); \
+ GATOR_HANDLE_TRACEPOINT(mali_mmu_as_released); \
+ GATOR_HANDLE_TRACEPOINT(mali_page_fault_insert_pages); \
+ GATOR_HANDLE_TRACEPOINT(mali_pm_status); \
+ GATOR_HANDLE_TRACEPOINT(mali_sw_counter); \
+ GATOR_HANDLE_TRACEPOINT(mali_sw_counters); \
+ GATOR_HANDLE_TRACEPOINT(mali_timeline_event); \
+ GATOR_HANDLE_TRACEPOINT(mali_total_alloc_pages_change); \
+ GATOR_HANDLE_TRACEPOINT(mm_page_alloc); \
+ GATOR_HANDLE_TRACEPOINT(mm_page_free); \
+ GATOR_HANDLE_TRACEPOINT(mm_page_free_batched); \
+ GATOR_HANDLE_TRACEPOINT(sched_process_fork); \
+ GATOR_HANDLE_TRACEPOINT(sched_process_free); \
+ GATOR_HANDLE_TRACEPOINT(sched_switch); \
+ GATOR_HANDLE_TRACEPOINT(softirq_exit); \
+
+#define GATOR_HANDLE_TRACEPOINT(probe_name) \
+ struct tracepoint *gator_tracepoint_##probe_name
+GATOR_TRACEPOINTS;
+#undef GATOR_HANDLE_TRACEPOINT
+
+static void gator_fct(struct tracepoint *tp, void *priv)
+{
+#define GATOR_HANDLE_TRACEPOINT(probe_name) \
+ if (strcmp(tp->name, #probe_name) == 0) { \
+ gator_tracepoint_##probe_name = tp; \
+ return; \
+ }
+GATOR_TRACEPOINTS;
+#undef GATOR_HANDLE_TRACEPOINT
+}
+
+#else
+
+#define for_each_kernel_tracepoint(fct, priv)
+
+#endif
+
static int __init gator_module_init(void)
{
+ for_each_kernel_tracepoint(gator_fct, NULL);
+
if (gatorfs_register()) {
return -1;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ARM Ltd");
MODULE_DESCRIPTION("Gator system profiler");
+#define STRIFY2(ARG) #ARG
+#define STRIFY(ARG) STRIFY2(ARG)
+MODULE_VERSION(STRIFY(PROTOCOL_VERSION));