aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Medhurst <tixy@linaro.org>2014-04-10 12:45:17 +0100
committerJon Medhurst <tixy@linaro.org>2014-04-10 12:45:17 +0100
commit03925e64e3aff28a204a61f4b833aabe6aface2c (patch)
treec688642f88636407bd99c5f289a99ca44e8c59f7
parentdffc698f098d93044e28f4f97206eca6373c7cdf (diff)
parent6d0ae28ce59feba55f718ffaf43dfb6ad394cb4f (diff)
Merge in gator version 5.18
-rw-r--r--drivers/gator/Kconfig10
-rw-r--r--drivers/gator/gator.h13
-rw-r--r--drivers/gator/gator_annotate.c2
-rw-r--r--drivers/gator/gator_annotate_kernel.c8
-rw-r--r--drivers/gator/gator_backtrace.c48
-rw-r--r--drivers/gator/gator_buffer.c168
-rw-r--r--drivers/gator/gator_buffer_write.c (renamed from drivers/gator/gator_pack.c)24
-rw-r--r--drivers/gator/gator_cookies.c8
-rw-r--r--drivers/gator/gator_events_armv6.c2
-rw-r--r--drivers/gator/gator_events_armv7.c18
-rw-r--r--drivers/gator/gator_events_block.c2
-rw-r--r--drivers/gator/gator_events_ccn-504.c2
-rw-r--r--drivers/gator/gator_events_irq.c2
-rw-r--r--drivers/gator/gator_events_l2c-310.c2
-rw-r--r--drivers/gator/gator_events_mali_4xx.c2
-rw-r--r--drivers/gator/gator_events_mali_4xx.h2
-rw-r--r--drivers/gator/gator_events_mali_common.c2
-rw-r--r--drivers/gator/gator_events_mali_common.h2
-rw-r--r--drivers/gator/gator_events_mali_t6xx.c8
-rw-r--r--drivers/gator/gator_events_mali_t6xx_hw.c10
-rw-r--r--drivers/gator/gator_events_mali_t6xx_hw_test.c2
-rw-r--r--drivers/gator/gator_events_meminfo.c28
-rw-r--r--drivers/gator/gator_events_mmapped.c2
-rw-r--r--drivers/gator/gator_events_net.c2
-rw-r--r--drivers/gator/gator_events_perf_pmu.c2
-rw-r--r--drivers/gator/gator_events_sched.c2
-rw-r--r--drivers/gator/gator_events_scorpion.c2
-rw-r--r--drivers/gator/gator_fs.c47
-rw-r--r--drivers/gator/gator_hrtimer_gator.c8
-rw-r--r--drivers/gator/gator_hrtimer_perf.c113
-rw-r--r--drivers/gator/gator_iks.c2
-rw-r--r--drivers/gator/gator_main.c290
-rw-r--r--drivers/gator/gator_marshaling.c97
-rw-r--r--drivers/gator/gator_trace_gpu.c13
-rw-r--r--drivers/gator/gator_trace_gpu.h2
-rw-r--r--drivers/gator/gator_trace_power.c6
-rw-r--r--drivers/gator/gator_trace_sched.c20
-rw-r--r--drivers/gator/mali/mali_mjollnir_profiling_gator_api.h2
-rw-r--r--drivers/gator/mali/mali_utgard_profiling_gator_api.h2
-rw-r--r--drivers/gator/mali_t6xx.mk9
-rw-r--r--tools/gator/daemon/Android.mk15
-rw-r--r--tools/gator/daemon/Buffer.cpp259
-rw-r--r--tools/gator/daemon/Buffer.h99
-rw-r--r--tools/gator/daemon/CapturedXML.cpp11
-rw-r--r--tools/gator/daemon/CapturedXML.h2
-rw-r--r--tools/gator/daemon/Child.cpp174
-rw-r--r--tools/gator/daemon/Child.h4
-rw-r--r--tools/gator/daemon/Collector.h38
-rw-r--r--tools/gator/daemon/Config.h17
-rw-r--r--tools/gator/daemon/ConfigurationXML.cpp16
-rw-r--r--tools/gator/daemon/ConfigurationXML.h2
-rw-r--r--tools/gator/daemon/Counter.h4
-rw-r--r--tools/gator/daemon/Driver.cpp2
-rw-r--r--tools/gator/daemon/Driver.h4
-rw-r--r--tools/gator/daemon/DriverSource.cpp (renamed from tools/gator/daemon/Collector.cpp)225
-rw-r--r--tools/gator/daemon/DriverSource.h52
-rw-r--r--tools/gator/daemon/DynBuf.cpp139
-rw-r--r--tools/gator/daemon/DynBuf.h52
-rw-r--r--tools/gator/daemon/EventsXML.cpp4
-rw-r--r--tools/gator/daemon/EventsXML.h2
-rw-r--r--tools/gator/daemon/ExternalSource.cpp56
-rw-r--r--tools/gator/daemon/ExternalSource.h40
-rw-r--r--tools/gator/daemon/Fifo.cpp2
-rw-r--r--tools/gator/daemon/Fifo.h4
-rw-r--r--tools/gator/daemon/Hwmon.cpp40
-rw-r--r--tools/gator/daemon/Hwmon.h6
-rw-r--r--tools/gator/daemon/KMod.cpp25
-rw-r--r--tools/gator/daemon/KMod.h4
-rw-r--r--tools/gator/daemon/LocalCapture.cpp6
-rw-r--r--tools/gator/daemon/LocalCapture.h2
-rw-r--r--tools/gator/daemon/Logging.cpp6
-rw-r--r--tools/gator/daemon/Logging.h13
-rw-r--r--tools/gator/daemon/Monitor.cpp61
-rw-r--r--tools/gator/daemon/Monitor.h32
-rw-r--r--tools/gator/daemon/OlySocket.cpp101
-rw-r--r--tools/gator/daemon/OlySocket.h43
-rw-r--r--tools/gator/daemon/OlyUtility.cpp2
-rw-r--r--tools/gator/daemon/OlyUtility.h2
-rw-r--r--tools/gator/daemon/PerfBuffer.cpp139
-rw-r--r--tools/gator/daemon/PerfBuffer.h39
-rw-r--r--tools/gator/daemon/PerfDriver.cpp355
-rw-r--r--tools/gator/daemon/PerfDriver.h56
-rw-r--r--tools/gator/daemon/PerfGroup.cpp206
-rw-r--r--tools/gator/daemon/PerfGroup.h55
-rw-r--r--tools/gator/daemon/PerfSource.cpp271
-rw-r--r--tools/gator/daemon/PerfSource.h54
-rw-r--r--tools/gator/daemon/Proc.cpp179
-rw-r--r--tools/gator/daemon/Proc.h17
-rw-r--r--tools/gator/daemon/Sender.cpp29
-rw-r--r--tools/gator/daemon/Sender.h2
-rw-r--r--tools/gator/daemon/SessionData.cpp29
-rw-r--r--tools/gator/daemon/SessionData.h14
-rw-r--r--tools/gator/daemon/SessionXML.cpp12
-rw-r--r--tools/gator/daemon/SessionXML.h8
-rw-r--r--tools/gator/daemon/Source.cpp33
-rw-r--r--tools/gator/daemon/Source.h40
-rw-r--r--tools/gator/daemon/StreamlineSetup.cpp36
-rw-r--r--tools/gator/daemon/StreamlineSetup.h7
-rw-r--r--tools/gator/daemon/UEvent.cpp76
-rw-r--r--tools/gator/daemon/UEvent.h36
-rw-r--r--tools/gator/daemon/UserSpaceSource.cpp97
-rw-r--r--tools/gator/daemon/UserSpaceSource.h38
-rw-r--r--tools/gator/daemon/common.mk4
-rw-r--r--tools/gator/daemon/defaults.xml (renamed from tools/gator/daemon/configuration.xml)51
-rw-r--r--tools/gator/daemon/escape.c2
-rw-r--r--tools/gator/daemon/events-Cortex-A12.xml6
-rw-r--r--tools/gator/daemon/events-Cortex-A15.xml6
-rw-r--r--tools/gator/daemon/events-Cortex-A5.xml6
-rw-r--r--tools/gator/daemon/events-Cortex-A7.xml6
-rw-r--r--tools/gator/daemon/events-Cortex-A8.xml6
-rw-r--r--tools/gator/daemon/events-Cortex-A9.xml6
-rw-r--r--tools/gator/daemon/events-Linux.xml14
-rw-r--r--tools/gator/daemon/events-Mali-4xx.xml2
-rw-r--r--tools/gator/daemon/events-Mali-T6xx.xml16
-rw-r--r--tools/gator/daemon/events-Perf-Hardware.xml12
-rw-r--r--tools/gator/daemon/k/perf_event.3.12.h792
l---------tools/gator/daemon/k/perf_event.h1
-rw-r--r--tools/gator/daemon/main.cpp80
118 files changed, 4275 insertions, 1115 deletions
diff --git a/drivers/gator/Kconfig b/drivers/gator/Kconfig
index 7ea0fcc3d01d..e46ccb9b8064 100644
--- a/drivers/gator/Kconfig
+++ b/drivers/gator/Kconfig
@@ -4,7 +4,11 @@ config GATOR
depends on PROFILING
depends on HIGH_RES_TIMERS
depends on LOCAL_TIMERS || !(ARM && SMP)
+ depends on PERF_EVENTS
+ depends on HW_PERF_EVENTS || !(ARM || ARM64)
select TRACING
+ help
+ Gator module for ARM's Streamline Performance Analyzer
config GATOR_WITH_MALI_SUPPORT
bool
@@ -13,9 +17,11 @@ choice
prompt "Enable Mali GPU support in Gator"
depends on GATOR
optional
+ help
+ Enable Mali GPU support in Gator
-config GATOR_MALI_400MP
- bool "Mali-400MP"
+config GATOR_MALI_4XXMP
+ bool "Mali-400MP or Mali-450MP"
select GATOR_WITH_MALI_SUPPORT
config GATOR_MALI_T6XX
diff --git a/drivers/gator/gator.h b/drivers/gator/gator.h
index d8981ed85a6a..586cd9e742fb 100644
--- a/drivers/gator/gator.h
+++ b/drivers/gator/gator.h
@@ -1,5 +1,5 @@
/**
- * 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
@@ -31,6 +31,7 @@
#define CORTEX_A9 0xc09
#define CORTEX_A12 0xc0d
#define CORTEX_A15 0xc0f
+#define CORTEX_A17 0xc0e
#define SCORPION 0x00f
#define SCORPIONMP 0x02d
#define KRAITSIM 0x049
@@ -47,9 +48,7 @@ struct gator_cpu {
const int cpuid;
// Human readable name
const char core_name[MAXSIZE_CORE_NAME];
- // Perf PMU name
- const char * const pmu_name;
- // gatorfs event name
+ // gatorfs event and Perf PMU name
const char * const pmnc_name;
// compatible from Documentation/devicetree/bindings/arm/cpus.txt
const char * const dt_name;
@@ -62,10 +61,6 @@ const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name);
/******************************************************************************
* Filesystem
******************************************************************************/
-int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
- char const *name,
- const struct file_operations *fops, int perm);
-
struct dentry *gatorfs_mkdir(struct super_block *sb, struct dentry *root,
char const *name);
@@ -75,8 +70,6 @@ int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
char const *name, unsigned long *val);
-void gator_op_create_files(struct super_block *sb, struct dentry *root);
-
/******************************************************************************
* Tracepoints
******************************************************************************/
diff --git a/drivers/gator/gator_annotate.c b/drivers/gator/gator_annotate.c
index 5b9399bea230..7e2c6e5d8715 100644
--- a/drivers/gator/gator_annotate.c
+++ b/drivers/gator/gator_annotate.c
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/drivers/gator/gator_annotate_kernel.c b/drivers/gator/gator_annotate_kernel.c
index a406e4882974..010806825529 100644
--- a/drivers/gator/gator_annotate_kernel.c
+++ b/drivers/gator/gator_annotate_kernel.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
@@ -29,12 +29,14 @@ static void kannotate_write(const char *ptr, unsigned int size)
}
}
-static void marshal_u16(char *buf, u16 val) {
+static void marshal_u16(char *buf, u16 val)
+{
buf[0] = val & 0xff;
buf[1] = (val >> 8) & 0xff;
}
-static void marshal_u32(char *buf, u32 val) {
+static void marshal_u32(char *buf, u32 val)
+{
buf[0] = val & 0xff;
buf[1] = (val >> 8) & 0xff;
buf[2] = (val >> 16) & 0xff;
diff --git a/drivers/gator/gator_backtrace.c b/drivers/gator/gator_backtrace.c
index ffacb490194c..9f305cf7242c 100644
--- a/drivers/gator/gator_backtrace.c
+++ b/drivers/gator/gator_backtrace.c
@@ -1,5 +1,5 @@
/**
- * 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
@@ -30,6 +30,18 @@ struct stack_frame_eabi {
};
};
+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 == UNRESOLVED_COOKIE) {
+ offset = address;
+ }
+
+ marshal_backtrace(offset & ~1, cookie, 0);
+}
+
static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth)
{
#if defined(__arm__) || defined(__aarch64__)
@@ -122,7 +134,7 @@ static int report_trace(struct stackframe *frame, void *d)
addr = addr - (unsigned long)mod->module_core;
}
#endif
- marshal_backtrace(addr & ~1, cookie);
+ marshal_backtrace(addr & ~1, cookie, 1);
(*depth)--;
}
@@ -136,7 +148,7 @@ static int report_trace(struct stackframe *frame, void *d)
#if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING)
// Disabled by default
MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding.");
-bool kernel_stack_unwinding = 0;
+static bool kernel_stack_unwinding = 0;
module_param(kernel_stack_unwinding, bool, 0644);
#endif
@@ -163,6 +175,34 @@ static void kernel_backtrace(int cpu, struct pt_regs *const regs)
#endif
walk_stackframe(&frame, report_trace, &depth);
#else
- marshal_backtrace(PC_REG & ~1, NO_COOKIE);
+ marshal_backtrace(PC_REG & ~1, NO_COOKIE, 1);
#endif
}
+
+static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time)
+{
+ bool in_kernel;
+ unsigned long exec_cookie;
+
+ if (!regs)
+ return;
+
+ in_kernel = !user_mode(regs);
+ exec_cookie = get_exec_cookie(cpu, current);
+
+ if (!marshal_backtrace_header(exec_cookie, current->tgid, current->pid, time))
+ return;
+
+ if (in_kernel) {
+ 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(time);
+}
diff --git a/drivers/gator/gator_buffer.c b/drivers/gator/gator_buffer.c
new file mode 100644
index 000000000000..eba22dfe3bf2
--- /dev/null
+++ b/drivers/gator/gator_buffer.c
@@ -0,0 +1,168 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ *
+ */
+
+static void marshal_frame(int cpu, int buftype)
+{
+ int frame;
+
+ if (!per_cpu(gator_buffer, cpu)[buftype]) {
+ return;
+ }
+
+ switch (buftype) {
+ case SUMMARY_BUF:
+ frame = FRAME_SUMMARY;
+ break;
+ case BACKTRACE_BUF:
+ frame = FRAME_BACKTRACE;
+ break;
+ case NAME_BUF:
+ frame = FRAME_NAME;
+ break;
+ case COUNTER_BUF:
+ frame = FRAME_COUNTER;
+ break;
+ case BLOCK_COUNTER_BUF:
+ frame = FRAME_BLOCK_COUNTER;
+ break;
+ case ANNOTATE_BUF:
+ frame = FRAME_ANNOTATE;
+ break;
+ case SCHED_TRACE_BUF:
+ frame = FRAME_SCHED_TRACE;
+ break;
+ case GPU_TRACE_BUF:
+ frame = FRAME_GPU_TRACE;
+ break;
+ case IDLE_BUF:
+ frame = FRAME_IDLE;
+ break;
+ default:
+ frame = -1;
+ break;
+ }
+
+ // add response type
+ if (gator_response_type > 0) {
+ gator_buffer_write_packed_int(cpu, buftype, gator_response_type);
+ }
+
+ // leave space for 4-byte unpacked length
+ per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype];
+
+ // add frame type and core number
+ gator_buffer_write_packed_int(cpu, buftype, frame);
+ gator_buffer_write_packed_int(cpu, buftype, cpu);
+}
+
+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 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 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 void gator_commit_buffer(int cpu, int buftype, u64 time)
+{
+ int type_length, commit, length, byte;
+ unsigned long flags;
+
+ 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
+ local_irq_save(flags);
+ 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
+ local_irq_restore(flags);
+ 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_rate > 0) {
+ while (time > per_cpu(gator_buffer_commit_time, cpu)) {
+ per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
+ }
+ }
+
+ marshal_frame(cpu, buftype);
+ local_irq_restore(flags);
+
+ // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
+ if (per_cpu(in_scheduler_context, cpu)) {
+#ifndef CONFIG_PREEMPT_RT_FULL
+ // mod_timer can not be used in interrupt context in RT-Preempt full
+ mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
+#endif
+ } else {
+ up(&gator_buffer_wake_sem);
+ }
+}
+
+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);
+ }
+}
diff --git a/drivers/gator/gator_pack.c b/drivers/gator/gator_buffer_write.c
index 2c082f283adc..b621ba93ee5e 100644
--- a/drivers/gator/gator_pack.c
+++ b/drivers/gator/gator_buffer_write.c
@@ -1,5 +1,5 @@
/**
- * 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
@@ -56,3 +56,25 @@ static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x)
per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask;
}
+
+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);
+}
diff --git a/drivers/gator/gator_cookies.c b/drivers/gator/gator_cookies.c
index eb9b946170c1..5c7d842070e0 100644
--- a/drivers/gator/gator_cookies.c
+++ b/drivers/gator/gator_cookies.c
@@ -1,5 +1,5 @@
/**
- * 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
@@ -30,7 +30,7 @@ static DEFINE_PER_CPU(struct cookie_args *, translate_buffer);
static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq);
static void wq_cookie_handler(struct work_struct *unused);
-DECLARE_WORK(cookie_work, wq_cookie_handler);
+static DECLARE_WORK(cookie_work, wq_cookie_handler);
static struct timer_list app_process_wake_up_timer;
static void app_process_wake_up_handler(unsigned long unused_data);
@@ -131,7 +131,9 @@ static void translate_buffer_write_args(int cpu, struct task_struct *task, const
args = &per_cpu(translate_buffer, cpu)[write];
args->task = task;
args->text = text;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
get_task_struct(task);
+#endif
per_cpu(translate_buffer_write, cpu) = next_write;
}
@@ -165,7 +167,9 @@ static void wq_cookie_handler(struct work_struct *unused)
translate_buffer_read_args(cpu, &args);
cookie = get_cookie(cpu, args.task, args.text, true);
marshal_link(cookie, args.task->tgid, args.task->pid);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
put_task_struct(args.task);
+#endif
}
}
diff --git a/drivers/gator/gator_events_armv6.c b/drivers/gator/gator_events_armv6.c
index dd7974090b82..353645622306 100644
--- a/drivers/gator/gator_events_armv6.c
+++ b/drivers/gator/gator_events_armv6.c
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/drivers/gator/gator_events_armv7.c b/drivers/gator/gator_events_armv7.c
index 30881c8fd3fd..153119b463e6 100644
--- a/drivers/gator/gator_events_armv7.c
+++ b/drivers/gator/gator_events_armv7.c
@@ -1,5 +1,5 @@
/**
- * 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
@@ -141,9 +141,9 @@ static int gator_events_armv7_create_files(struct super_block *sb, struct dentry
for (i = 0; i < pmnc_counters; i++) {
char buf[40];
if (i == 0) {
- snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
+ snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
} else {
- snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i - 1);
+ snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1);
}
dir = gatorfs_mkdir(sb, root, buf);
if (!dir) {
@@ -275,25 +275,27 @@ int gator_events_armv7_init(void)
switch (gator_cpuid()) {
case CORTEX_A5:
- pmnc_name = "Cortex-A5";
+ pmnc_name = "ARMv7_Cortex_A5";
pmnc_counters = 2;
break;
case CORTEX_A7:
- pmnc_name = "Cortex-A7";
+ pmnc_name = "ARMv7_Cortex_A7";
pmnc_counters = 4;
break;
case CORTEX_A8:
- pmnc_name = "Cortex-A8";
+ pmnc_name = "ARMv7_Cortex_A8";
pmnc_counters = 4;
break;
case CORTEX_A9:
- pmnc_name = "Cortex-A9";
+ pmnc_name = "ARMv7_Cortex_A9";
pmnc_counters = 6;
break;
+ // ARM Cortex A12 is not supported by version of Linux before 3.0
case CORTEX_A15:
- pmnc_name = "Cortex-A15";
+ pmnc_name = "ARMv7_Cortex_A15";
pmnc_counters = 6;
break;
+ // ARM Cortex A17 is not supported by version of Linux before 3.0
default:
return -1;
}
diff --git a/drivers/gator/gator_events_block.c b/drivers/gator/gator_events_block.c
index 691ef2574536..b2bc414e462e 100644
--- a/drivers/gator/gator_events_block.c
+++ b/drivers/gator/gator_events_block.c
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/drivers/gator/gator_events_ccn-504.c b/drivers/gator/gator_events_ccn-504.c
index b89231967c75..024ffc2856aa 100644
--- a/drivers/gator/gator_events_ccn-504.c
+++ b/drivers/gator/gator_events_ccn-504.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
diff --git a/drivers/gator/gator_events_irq.c b/drivers/gator/gator_events_irq.c
index b11879a248f8..facbdd62325e 100644
--- a/drivers/gator/gator_events_irq.c
+++ b/drivers/gator/gator_events_irq.c
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/drivers/gator/gator_events_l2c-310.c b/drivers/gator/gator_events_l2c-310.c
index ee521af22517..553f9707bdbf 100644
--- a/drivers/gator/gator_events_l2c-310.c
+++ b/drivers/gator/gator_events_l2c-310.c
@@ -1,7 +1,7 @@
/**
* l2c310 (L2 Cache Controller) event counters for gator
*
- * 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
diff --git a/drivers/gator/gator_events_mali_4xx.c b/drivers/gator/gator_events_mali_4xx.c
index 6719c1ec73a2..85d47645a9d9 100644
--- a/drivers/gator/gator_events_mali_4xx.c
+++ b/drivers/gator/gator_events_mali_4xx.c
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/drivers/gator/gator_events_mali_4xx.h b/drivers/gator/gator_events_mali_4xx.h
index 413ad0ffe794..976ca8c4cfa1 100644
--- a/drivers/gator/gator_events_mali_4xx.h
+++ b/drivers/gator/gator_events_mali_4xx.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2011-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2011-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
diff --git a/drivers/gator/gator_events_mali_common.c b/drivers/gator/gator_events_mali_common.c
index 466ca1683c7e..dc58dcf0c662 100644
--- a/drivers/gator/gator_events_mali_common.c
+++ b/drivers/gator/gator_events_mali_common.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
diff --git a/drivers/gator/gator_events_mali_common.h b/drivers/gator/gator_events_mali_common.h
index 509f9b61884a..41c2a3c13fae 100644
--- a/drivers/gator/gator_events_mali_common.h
+++ b/drivers/gator/gator_events_mali_common.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
diff --git a/drivers/gator/gator_events_mali_t6xx.c b/drivers/gator/gator_events_mali_t6xx.c
index 7bf7d6a6dbf9..76f14eee7676 100644
--- a/drivers/gator/gator_events_mali_t6xx.c
+++ b/drivers/gator/gator_events_mali_t6xx.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2011-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2011-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
@@ -15,7 +15,13 @@
#include <linux/slab.h>
#include <asm/io.h>
+#ifdef MALI_DIR_MIDGARD
+/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
+#include "mali_linux_trace.h"
+#else
+/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
#include "linux/mali_linux_trace.h"
+#endif
#include "gator_events_mali_common.h"
diff --git a/drivers/gator/gator_events_mali_t6xx_hw.c b/drivers/gator/gator_events_mali_t6xx_hw.c
index e406991398d9..dfbc91ffd765 100644
--- a/drivers/gator/gator_events_mali_t6xx_hw.c
+++ b/drivers/gator/gator_events_mali_t6xx_hw.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
@@ -16,9 +16,17 @@
#include <asm/io.h>
/* Mali T6xx DDK includes */
+#ifdef MALI_DIR_MIDGARD
+/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
+#include "mali_linux_trace.h"
+#include "mali_kbase.h"
+#include "mali_kbase_mem_linux.h"
+#else
+/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
#include "linux/mali_linux_trace.h"
#include "kbase/src/common/mali_kbase.h"
#include "kbase/src/linux/mali_kbase_mem_linux.h"
+#endif
#include "gator_events_mali_common.h"
diff --git a/drivers/gator/gator_events_mali_t6xx_hw_test.c b/drivers/gator/gator_events_mali_t6xx_hw_test.c
index efb32ddf5483..ba6553f3540f 100644
--- a/drivers/gator/gator_events_mali_t6xx_hw_test.c
+++ b/drivers/gator/gator_events_mali_t6xx_hw_test.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
diff --git a/drivers/gator/gator_events_meminfo.c b/drivers/gator/gator_events_meminfo.c
index 451290d9af17..c633dfdce306 100644
--- a/drivers/gator/gator_events_meminfo.c
+++ b/drivers/gator/gator_events_meminfo.c
@@ -1,5 +1,5 @@
/**
- * 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
@@ -274,6 +274,28 @@ static int gator_events_meminfo_read(long long **buffer)
return meminfo_length;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
+
+static inline unsigned long gator_get_mm_counter(struct mm_struct *mm, int member)
+{
+#ifdef SPLIT_RSS_COUNTING
+ long val = atomic_long_read(&mm->rss_stat.count[member]);
+ if (val < 0)
+ val = 0;
+ return (unsigned long)val;
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
+ return mm->rss_stat.count[member];
+#else
+ return atomic_long_read(&mm->rss_stat.count[member]);
+#endif
+#endif
+}
+
+#define get_mm_counter(mm, member) gator_get_mm_counter(mm, member)
+
+#endif
+
static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct *task)
{
struct mm_struct *mm;
@@ -302,7 +324,7 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
// Derived from task_statm in fs/proc/task_mmu.c
if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) {
share = get_mm_counter(mm,
-#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
file_rss
#else
MM_FILEPAGES
@@ -338,7 +360,7 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
if (meminfo_enabled[MEMINFO_MEMUSED]) {
value = share + get_mm_counter(mm,
-#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
anon_rss
#else
MM_ANONPAGES
diff --git a/drivers/gator/gator_events_mmapped.c b/drivers/gator/gator_events_mmapped.c
index f055e48d317a..3b248ec24e6e 100644
--- a/drivers/gator/gator_events_mmapped.c
+++ b/drivers/gator/gator_events_mmapped.c
@@ -1,7 +1,7 @@
/*
* Example events provider
*
- * 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
diff --git a/drivers/gator/gator_events_net.c b/drivers/gator/gator_events_net.c
index 9c8d3a43eaeb..11c10e375511 100644
--- a/drivers/gator/gator_events_net.c
+++ b/drivers/gator/gator_events_net.c
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/drivers/gator/gator_events_perf_pmu.c b/drivers/gator/gator_events_perf_pmu.c
index d472df918ab0..8b2d67a058b3 100644
--- a/drivers/gator/gator_events_perf_pmu.c
+++ b/drivers/gator/gator_events_perf_pmu.c
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/drivers/gator/gator_events_sched.c b/drivers/gator/gator_events_sched.c
index 29f4e39e261c..9e3915830182 100644
--- a/drivers/gator/gator_events_sched.c
+++ b/drivers/gator/gator_events_sched.c
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/drivers/gator/gator_events_scorpion.c b/drivers/gator/gator_events_scorpion.c
index c91db1219d08..8ca251af0e26 100644
--- a/drivers/gator/gator_events_scorpion.c
+++ b/drivers/gator/gator_events_scorpion.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2011-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2011-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
diff --git a/drivers/gator/gator_fs.c b/drivers/gator/gator_fs.c
index fe6f83d547e9..166cfe7d681d 100644
--- a/drivers/gator/gator_fs.c
+++ b/drivers/gator/gator_fs.c
@@ -39,12 +39,7 @@ static const struct super_operations s_ops = {
.drop_inode = generic_delete_inode,
};
-ssize_t gatorfs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset)
-{
- return simple_read_from_buffer(buf, count, offset, str, strlen(str));
-}
-
-ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
+static ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
{
char tmpbuf[TMPBUFSIZE];
size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
@@ -53,7 +48,7 @@ ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count,
return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
}
-ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff_t *offset)
+static ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff_t *offset)
{
char tmpbuf[TMPBUFSIZE];
size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%llu\n", val);
@@ -62,7 +57,7 @@ ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff_t *off
return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
}
-int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
+static int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
{
char tmpbuf[TMPBUFSIZE];
unsigned long flags;
@@ -84,7 +79,7 @@ int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t c
return 0;
}
-int gatorfs_u64_from_user(u64 *val, char const __user *buf, size_t count)
+static int gatorfs_u64_from_user(u64 *val, char const __user *buf, size_t count)
{
char tmpbuf[TMPBUFSIZE];
unsigned long flags;
@@ -211,8 +206,8 @@ int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
return 0;
}
-int gatorfs_create_u64(struct super_block *sb, struct dentry *root,
- char const *name, u64 *val)
+static int gatorfs_create_u64(struct super_block *sb, struct dentry *root,
+ char const *name, u64 *val)
{
struct dentry *d = __gatorfs_create_file(sb, root, name,
&u64_fops, 0644);
@@ -235,8 +230,8 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
return 0;
}
-int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root,
- char const *name, u64 * val)
+static int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root,
+ char const *name, u64 * val)
{
struct dentry *d =
__gatorfs_create_file(sb, root, name, &u64_ro_fops, 0444);
@@ -258,29 +253,17 @@ static const struct file_operations atomic_ro_fops = {
.open = default_open,
};
-int gatorfs_create_ro_atomic(struct super_block *sb, struct dentry *root,
- char const *name, atomic_t *val)
-{
- struct dentry *d = __gatorfs_create_file(sb, root, name,
- &atomic_ro_fops, 0444);
- if (!d)
- return -EFAULT;
-
- d->d_inode->i_private = val;
- return 0;
-}
-
-int gatorfs_create_file(struct super_block *sb, struct dentry *root,
- char const *name, const struct file_operations *fops)
+static int gatorfs_create_file(struct super_block *sb, struct dentry *root,
+ char const *name, const struct file_operations *fops)
{
if (!__gatorfs_create_file(sb, root, name, fops, 0644))
return -EFAULT;
return 0;
}
-int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
- char const *name,
- const struct file_operations *fops, int perm)
+static int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
+ char const *name,
+ const struct file_operations *fops, int perm)
{
if (!__gatorfs_create_file(sb, root, name, fops, perm))
return -EFAULT;
@@ -371,12 +354,12 @@ static struct file_system_type gatorfs_type = {
.kill_sb = kill_litter_super,
};
-int __init gatorfs_register(void)
+static int __init gatorfs_register(void)
{
return register_filesystem(&gatorfs_type);
}
-void gatorfs_unregister(void)
+static void gatorfs_unregister(void)
{
unregister_filesystem(&gatorfs_type);
}
diff --git a/drivers/gator/gator_hrtimer_gator.c b/drivers/gator/gator_hrtimer_gator.c
index b0c947afe1e1..76584554b00f 100644
--- a/drivers/gator/gator_hrtimer_gator.c
+++ b/drivers/gator/gator_hrtimer_gator.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2011-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2011-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
@@ -7,10 +7,6 @@
*
*/
-// gator_hrtimer_perf.c is used if perf is supported
-// update, gator_hrtimer_gator.c always used until issues resolved with perf hrtimers
-#if 1
-
void (*callback)(void);
DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
DEFINE_PER_CPU(ktime_t, hrtimer_expire);
@@ -82,5 +78,3 @@ static void gator_hrtimer_shutdown(void)
{
/* empty */
}
-
-#endif
diff --git a/drivers/gator/gator_hrtimer_perf.c b/drivers/gator/gator_hrtimer_perf.c
deleted file mode 100644
index 7b95399478e4..000000000000
--- a/drivers/gator/gator_hrtimer_perf.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2011-2013. 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
- * published by the Free Software Foundation.
- *
- */
-
-// gator_hrtimer_gator.c is used if perf is not supported
-// update, gator_hrtimer_gator.c always used until issues resolved with perf hrtimers
-#if 0
-
-// Note: perf Cortex support added in 2.6.35 and PERF_COUNT_SW_CPU_CLOCK/hrtimer broken on 2.6.35 and 2.6.36
-// not relevant as this code is not active until 3.0.0, but wanted to document the issue
-
-void (*callback)(void);
-static int profiling_interval;
-static DEFINE_PER_CPU(struct perf_event *, perf_hrtimer);
-static DEFINE_PER_CPU(struct perf_event_attr *, perf_hrtimer_attr);
-
-static void gator_hrtimer_shutdown(void);
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
-static void hrtimer_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
-#else
-static void hrtimer_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
-#endif
-{
- (*callback)();
-}
-
-static int gator_online_single_hrtimer(int cpu)
-{
- if (per_cpu(perf_hrtimer, cpu) != 0 || per_cpu(perf_hrtimer_attr, cpu) == 0)
- return 0;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
- per_cpu(perf_hrtimer, cpu) = perf_event_create_kernel_counter(per_cpu(perf_hrtimer_attr, cpu), cpu, 0, hrtimer_overflow_handler);
-#else
- per_cpu(perf_hrtimer, cpu) = perf_event_create_kernel_counter(per_cpu(perf_hrtimer_attr, cpu), cpu, 0, hrtimer_overflow_handler, 0);
-#endif
- if (IS_ERR(per_cpu(perf_hrtimer, cpu))) {
- per_cpu(perf_hrtimer, cpu) = NULL;
- return -1;
- }
-
- if (per_cpu(perf_hrtimer, cpu)->state != PERF_EVENT_STATE_ACTIVE) {
- perf_event_release_kernel(per_cpu(perf_hrtimer, cpu));
- per_cpu(perf_hrtimer, cpu) = NULL;
- return -1;
- }
-
- return 0;
-}
-
-static void gator_hrtimer_online(int cpu)
-{
- if (gator_online_single_hrtimer(cpu) < 0) {
- pr_debug("gator: unable to online the hrtimer on cpu%d\n", cpu);
- }
-}
-
-static void gator_hrtimer_offline(int cpu)
-{
- if (per_cpu(perf_hrtimer, cpu)) {
- perf_event_release_kernel(per_cpu(perf_hrtimer, cpu));
- per_cpu(perf_hrtimer, cpu) = NULL;
- }
-}
-
-static int gator_hrtimer_init(int interval, void (*func)(void))
-{
- u32 size = sizeof(struct perf_event_attr);
- int cpu;
-
- callback = func;
-
- // calculate profiling interval
- profiling_interval = 1000000000 / interval;
-
- for_each_present_cpu(cpu) {
- per_cpu(perf_hrtimer, cpu) = 0;
- per_cpu(perf_hrtimer_attr, cpu) = kmalloc(size, GFP_KERNEL);
- if (per_cpu(perf_hrtimer_attr, cpu) == 0) {
- gator_hrtimer_shutdown();
- return -1;
- }
-
- memset(per_cpu(perf_hrtimer_attr, cpu), 0, size);
- per_cpu(perf_hrtimer_attr, cpu)->type = PERF_TYPE_SOFTWARE;
- per_cpu(perf_hrtimer_attr, cpu)->size = size;
- per_cpu(perf_hrtimer_attr, cpu)->config = PERF_COUNT_SW_CPU_CLOCK;
- per_cpu(perf_hrtimer_attr, cpu)->sample_period = profiling_interval;
- per_cpu(perf_hrtimer_attr, cpu)->pinned = 1;
- }
-
- return 0;
-}
-
-static void gator_hrtimer_shutdown(void)
-{
- int cpu;
-
- for_each_present_cpu(cpu) {
- if (per_cpu(perf_hrtimer_attr, cpu)) {
- kfree(per_cpu(perf_hrtimer_attr, cpu));
- per_cpu(perf_hrtimer_attr, cpu) = NULL;
- }
- }
-}
-
-#endif
diff --git a/drivers/gator/gator_iks.c b/drivers/gator/gator_iks.c
index 0a90bdd1904e..e90dfcce9381 100644
--- a/drivers/gator/gator_iks.c
+++ b/drivers/gator/gator_iks.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
diff --git a/drivers/gator/gator_main.c b/drivers/gator/gator_main.c
index 19f51c7cd8ee..e67f7c5cc61d 100644
--- a/drivers/gator/gator_main.c
+++ b/drivers/gator/gator_main.c
@@ -1,5 +1,5 @@
/**
- * 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
@@ -8,7 +8,7 @@
*/
// This version must match the gator daemon version
-#define PROTOCOL_VERSION 17
+#define PROTOCOL_VERSION 18
static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#include <linux/slab.h>
@@ -55,9 +55,9 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#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
@@ -89,20 +89,27 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#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
@@ -154,7 +161,13 @@ bool event_based_sampling;
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_stop;
+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);
@@ -164,21 +177,19 @@ static bool printed_monotonic_warning;
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, u64 time);
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];
@@ -229,8 +240,10 @@ GATOR_EVENTS_LIST
/******************************************************************************
* 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"
@@ -238,14 +251,12 @@ GATOR_EVENTS_LIST
#include "gator_trace_power.c"
#include "gator_trace_gpu.c"
#include "gator_backtrace.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",
@@ -277,52 +288,53 @@ const struct gator_cpu gator_cpus[] = {
{
.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",
- .pmu_name = "ARMv7_Cortex_A12",
- .pmnc_name = "ARM_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 = SCORPION,
.core_name = "Scorpion",
.pmnc_name = "Scorpion",
@@ -401,7 +413,7 @@ const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name)
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;
}
}
@@ -431,10 +443,15 @@ static void gator_buffer_wake_up(unsigned long data)
static int gator_buffer_wake_func(void *data)
{
- while (!gator_buffer_wake_stop) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- if (gator_buffer_wake_stop) {
+ 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;
}
@@ -464,173 +481,6 @@ static bool buffer_commit_ready(int *cpu, int *buftype)
}
/******************************************************************************
- * 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_rate > 0) {
- while (time > per_cpu(gator_buffer_commit_time, cpu)) {
- per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
- }
- }
-
- 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
- if (per_cpu(in_scheduler_context, cpu)) {
-#ifndef CONFIG_PREEMPT_RT_FULL
- // mod_timer can not be used in interrupt context in RT-Preempt full
- mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
-#endif
- } else {
- wake_up_process(gator_buffer_wake_thread);
- }
-}
-
-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 == UNRESOLVED_COOKIE) {
- offset = address;
- }
-
- marshal_backtrace(offset & ~1, cookie);
-}
-
-static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time)
-{
- 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, time))
- 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(time);
-}
-
-/******************************************************************************
* hrtimer interrupt processing
******************************************************************************/
static void gator_timer_interrupt(void)
@@ -721,7 +571,8 @@ static void gator_timer_stop(void)
}
#if defined(__arm__) || defined(__aarch64__)
-static void gator_send_core_name(int cpu, const u32 cpuid, const struct gator_cpu *const gator_cpu) {
+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];
@@ -788,7 +639,7 @@ static void gator_timer_online_dispatch(int cpu, bool migrate)
#include "gator_iks.c"
-int gator_timer_start(unsigned long sample_rate)
+static int gator_timer_start(unsigned long sample_rate)
{
int cpu;
@@ -944,7 +795,6 @@ static void gator_summary(void)
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);
@@ -959,14 +809,14 @@ static void gator_summary(void)
}
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, gator_monotonic_started, uname_buf);
+ preempt_enable();
}
int gator_events_install(struct gator_interface *interface)
@@ -1019,7 +869,7 @@ static int gator_start(void)
unsigned long cpu, i;
struct gator_interface *gi;
- gator_buffer_wake_stop = false;
+ gator_buffer_wake_run = true;
if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) {
goto bwake_failure;
}
@@ -1094,8 +944,9 @@ cookies_failure:
events_failure:
gator_migrate_stop();
migrate_failure:
- gator_buffer_wake_stop = true;
- wake_up_process(gator_buffer_wake_thread);
+ gator_buffer_wake_run = false;
+ up(&gator_buffer_wake_sem);
+ gator_buffer_wake_thread = NULL;
bwake_failure:
return -1;
@@ -1121,8 +972,9 @@ static void gator_stop(void)
gator_migrate_stop();
- gator_buffer_wake_stop = true;
- wake_up_process(gator_buffer_wake_thread);
+ gator_buffer_wake_run = false;
+ up(&gator_buffer_wake_sem);
+ gator_buffer_wake_thread = NULL;
}
/******************************************************************************
@@ -1417,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,
@@ -1452,7 +1304,7 @@ static const struct file_operations depth_fops = {
.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;
diff --git a/drivers/gator/gator_marshaling.c b/drivers/gator/gator_marshaling.c
index af80ff62e712..fd413ad1331c 100644
--- a/drivers/gator/gator_marshaling.c
+++ b/drivers/gator/gator_marshaling.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
@@ -29,6 +29,7 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
int cpu = 0;
local_irq_save(flags);
+ gator_buffer_write_packed_int(cpu, SUMMARY_BUF, MESSAGE_SUMMARY);
gator_buffer_write_string(cpu, SUMMARY_BUF, NEWLINE_CANARY);
gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, timestamp);
gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, uptime);
@@ -52,8 +53,8 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
#endif
gator_buffer_write_string(cpu, SUMMARY_BUF, "");
// Commit the buffer now so it can be one of the first frames read by Streamline
- gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
local_irq_restore(flags);
+ gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
}
static bool marshal_cookie_header(const char *text)
@@ -85,8 +86,8 @@ static void marshal_thread_name(int pid, char *name)
gator_buffer_write_packed_int(cpu, NAME_BUF, pid);
gator_buffer_write_string(cpu, NAME_BUF, name);
}
- buffer_check(cpu, NAME_BUF, time);
local_irq_restore(flags);
+ buffer_check(cpu, NAME_BUF, time);
}
static void marshal_link(int cookie, int tgid, int pid)
@@ -103,12 +104,12 @@ static void marshal_link(int cookie, int tgid, int pid)
gator_buffer_write_packed_int(cpu, NAME_BUF, tgid);
gator_buffer_write_packed_int(cpu, NAME_BUF, pid);
}
+ local_irq_restore(flags);
// Check and commit; commit is set to occur once buffer is 3/4 full
buffer_check(cpu, NAME_BUF, time);
- local_irq_restore(flags);
}
-static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inKernel, u64 time)
+static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, u64 time)
{
int cpu = get_physical_cpu();
if (!buffer_check_space(cpu, BACKTRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32 + gator_backtrace_depth * 2 * MAXSIZE_PACK32)) {
@@ -122,14 +123,16 @@ static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inK
gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, exec_cookie);
gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, tgid);
gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, pid);
- gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, inKernel);
return true;
}
-static void marshal_backtrace(unsigned long address, int cookie)
+static void marshal_backtrace(unsigned long address, int cookie, int in_kernel)
{
int cpu = get_physical_cpu();
+ if (cookie == 0 && !in_kernel) {
+ cookie = UNRESOLVED_COOKIE;
+ }
gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie);
gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, address);
}
@@ -224,9 +227,9 @@ static void marshal_event_single(int core, int key, int value)
gator_buffer_write_packed_int(cpu, COUNTER_BUF, key);
gator_buffer_write_packed_int(cpu, COUNTER_BUF, value);
}
+ local_irq_restore(flags);
// Check and commit; commit is set to occur once buffer is 3/4 full
buffer_check(cpu, COUNTER_BUF, time);
- local_irq_restore(flags);
}
#endif
@@ -248,9 +251,9 @@ static void marshal_sched_gpu_start(int unit, int core, int tgid, int pid)
gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, tgid);
gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, pid);
}
+ local_irq_restore(flags);
// Check and commit; commit is set to occur once buffer is 3/4 full
buffer_check(cpu, GPU_TRACE_BUF, time);
- local_irq_restore(flags);
}
static void marshal_sched_gpu_stop(int unit, int core)
@@ -269,9 +272,9 @@ static void marshal_sched_gpu_stop(int unit, int core)
gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit);
gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core);
}
+ local_irq_restore(flags);
// Check and commit; commit is set to occur once buffer is 3/4 full
buffer_check(cpu, GPU_TRACE_BUF, time);
- local_irq_restore(flags);
}
static void marshal_sched_trace_start(int tgid, int pid, int cookie)
@@ -291,9 +294,9 @@ static void marshal_sched_trace_start(int tgid, int pid, int cookie)
gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid);
gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie);
}
+ local_irq_restore(flags);
// Check and commit; commit is set to occur once buffer is 3/4 full
buffer_check(cpu, SCHED_TRACE_BUF, time);
- local_irq_restore(flags);
}
static void marshal_sched_trace_switch(int tgid, int pid, int cookie, int state)
@@ -314,9 +317,9 @@ static void marshal_sched_trace_switch(int tgid, int pid, int cookie, int state)
gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie);
gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, state);
}
+ local_irq_restore(flags);
// Check and commit; commit is set to occur once buffer is 3/4 full
buffer_check(cpu, SCHED_TRACE_BUF, time);
- local_irq_restore(flags);
}
static void marshal_sched_trace_exit(int tgid, int pid)
@@ -334,9 +337,9 @@ static void marshal_sched_trace_exit(int tgid, int pid)
gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time);
gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid);
}
+ local_irq_restore(flags);
// Check and commit; commit is set to occur once buffer is 3/4 full
buffer_check(cpu, SCHED_TRACE_BUF, time);
- local_irq_restore(flags);
}
#if GATOR_CPU_FREQ_SUPPORT
@@ -353,80 +356,26 @@ static void marshal_idle(int core, int state)
gator_buffer_write_packed_int64(cpu, IDLE_BUF, time);
gator_buffer_write_packed_int(cpu, IDLE_BUF, core);
}
+ local_irq_restore(flags);
// Check and commit; commit is set to occur once buffer is 3/4 full
buffer_check(cpu, IDLE_BUF, time);
- local_irq_restore(flags);
}
#endif
-static void marshal_frame(int cpu, int buftype)
-{
- int frame;
-
- if (!per_cpu(gator_buffer, cpu)[buftype]) {
- return;
- }
-
- switch (buftype) {
- case SUMMARY_BUF:
- frame = FRAME_SUMMARY;
- break;
- case BACKTRACE_BUF:
- frame = FRAME_BACKTRACE;
- break;
- case NAME_BUF:
- frame = FRAME_NAME;
- break;
- case COUNTER_BUF:
- frame = FRAME_COUNTER;
- break;
- case BLOCK_COUNTER_BUF:
- frame = FRAME_BLOCK_COUNTER;
- break;
- case ANNOTATE_BUF:
- frame = FRAME_ANNOTATE;
- break;
- case SCHED_TRACE_BUF:
- frame = FRAME_SCHED_TRACE;
- break;
- case GPU_TRACE_BUF:
- frame = FRAME_GPU_TRACE;
- break;
- case IDLE_BUF:
- frame = FRAME_IDLE;
- break;
- default:
- frame = -1;
- break;
- }
-
- // add response type
- if (gator_response_type > 0) {
- gator_buffer_write_packed_int(cpu, buftype, gator_response_type);
- }
-
- // leave space for 4-byte unpacked length
- per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype];
-
- // add frame type and core number
- gator_buffer_write_packed_int(cpu, buftype, frame);
- gator_buffer_write_packed_int(cpu, buftype, cpu);
-}
-
#if defined(__arm__) || defined(__aarch64__)
static void marshal_core_name(const int core, const int cpuid, const char *name)
{
int cpu = get_physical_cpu();
unsigned long flags;
local_irq_save(flags);
- if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK32 + MAXSIZE_CORE_NAME)) {
- gator_buffer_write_packed_int(cpu, NAME_BUF, HRTIMER_CORE_NAME);
- gator_buffer_write_packed_int(cpu, NAME_BUF, core);
- gator_buffer_write_packed_int(cpu, NAME_BUF, cpuid);
- gator_buffer_write_string(cpu, NAME_BUF, name);
+ if (buffer_check_space(cpu, SUMMARY_BUF, MAXSIZE_PACK32 + MAXSIZE_CORE_NAME)) {
+ gator_buffer_write_packed_int(cpu, SUMMARY_BUF, MESSAGE_CORE_NAME);
+ gator_buffer_write_packed_int(cpu, SUMMARY_BUF, core);
+ gator_buffer_write_packed_int(cpu, SUMMARY_BUF, cpuid);
+ gator_buffer_write_string(cpu, SUMMARY_BUF, name);
}
// Commit core names now so that they can show up in live
- gator_commit_buffer(cpu, NAME_BUF, gator_get_time());
local_irq_restore(flags);
+ gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
}
#endif
diff --git a/drivers/gator/gator_trace_gpu.c b/drivers/gator/gator_trace_gpu.c
index be135b4aac56..6332098e5958 100644
--- a/drivers/gator/gator_trace_gpu.c
+++ b/drivers/gator/gator_trace_gpu.c
@@ -1,5 +1,5 @@
/**
- * 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
@@ -14,8 +14,15 @@
#include <linux/math64.h>
#ifdef MALI_SUPPORT
+#ifdef MALI_DIR_MIDGARD
+/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
+#include "mali_linux_trace.h"
+#else
+/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
#include "linux/mali_linux_trace.h"
#endif
+#endif
+
#include "gator_trace_gpu.h"
/*
@@ -235,7 +242,7 @@ GATOR_DEFINE_PROBE(gpu_activity_stop, TP_PROTO(int gpu_unit, int gpu_core))
mali_gpu_stop(gpu_unit, gpu_core);
}
-int gator_trace_gpu_start(void)
+static int gator_trace_gpu_start(void)
{
/*
* Returns nonzero for installation failed
@@ -271,7 +278,7 @@ int gator_trace_gpu_start(void)
return 0;
}
-void gator_trace_gpu_stop(void)
+static void gator_trace_gpu_stop(void)
{
#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
if (mali_timeline_trace_registered) {
diff --git a/drivers/gator/gator_trace_gpu.h b/drivers/gator/gator_trace_gpu.h
index bb0f42d290da..5113d459e24c 100644
--- a/drivers/gator/gator_trace_gpu.h
+++ b/drivers/gator/gator_trace_gpu.h
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/drivers/gator/gator_trace_power.c b/drivers/gator/gator_trace_power.c
index 272e05684ee8..1895bb988c9f 100644
--- a/drivers/gator/gator_trace_power.c
+++ b/drivers/gator/gator_trace_power.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2011-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2011-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
@@ -166,7 +166,7 @@ static void gator_trace_power_stop(void)
}
}
-void gator_trace_power_init(void)
+static void gator_trace_power_init(void)
{
int i;
for (i = 0; i < POWER_TOTAL; i++) {
@@ -197,7 +197,7 @@ static void gator_trace_power_stop(void)
{
}
-void gator_trace_power_init(void)
+static void gator_trace_power_init(void)
{
}
#endif
diff --git a/drivers/gator/gator_trace_sched.c b/drivers/gator/gator_trace_sched.c
index 332b3f6ba965..52990e9d4811 100644
--- a/drivers/gator/gator_trace_sched.c
+++ b/drivers/gator/gator_trace_sched.c
@@ -1,5 +1,5 @@
/**
- * 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
@@ -22,7 +22,6 @@ enum {
static DEFINE_PER_CPU(uint64_t *, taskname_keys);
static DEFINE_PER_CPU(int, collecting);
-static DEFINE_PER_CPU(bool, in_scheduler_context);
// this array is never read as the cpu wait charts are derived counters
// the files are needed, nonetheless, to show that these counters are available
@@ -52,7 +51,7 @@ static int sched_trace_create_files(struct super_block *sb, struct dentry *root)
return 0;
}
-void emit_pid_name(struct task_struct *task)
+static void emit_pid_name(struct task_struct *task)
{
bool found = false;
char taskcomm[TASK_COMM_LEN + 3];
@@ -116,20 +115,21 @@ static void collect_counters(u64 time, struct task_struct *task)
// Commit buffers on timeout
if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) {
static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF };
- unsigned long flags;
int i;
- local_irq_save(flags);
for (i = 0; i < ARRAY_SIZE(buftypes); ++i) {
gator_commit_buffer(cpu, buftypes[i], time);
}
- local_irq_restore(flags);
+ // spinlocks are noops on uniprocessor machines and mutexes do not work in sched_switch context in
+ // RT-Preempt full, so disable proactive flushing of the annotate frame on uniprocessor machines.
+#ifdef CONFIG_SMP
// Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full
if (on_primary_core() && spin_trylock(&annotate_lock)) {
gator_commit_buffer(0, ANNOTATE_BUF, time);
spin_unlock(&annotate_lock);
}
+#endif
}
}
}
@@ -222,7 +222,7 @@ fail_sched_process_fork:
return -1;
}
-int gator_trace_sched_start(void)
+static int gator_trace_sched_start(void)
{
int cpu, size;
@@ -237,7 +237,7 @@ int gator_trace_sched_start(void)
return register_scheduler_tracepoints();
}
-void gator_trace_sched_offline(void)
+static void gator_trace_sched_offline(void)
{
trace_sched_insert_idle();
}
@@ -250,7 +250,7 @@ static void unregister_scheduler_tracepoints(void)
pr_debug("gator: unregistered tracepoints\n");
}
-void gator_trace_sched_stop(void)
+static void gator_trace_sched_stop(void)
{
int cpu;
unregister_scheduler_tracepoints();
@@ -260,7 +260,7 @@ void gator_trace_sched_stop(void)
}
}
-void gator_trace_sched_init(void)
+static void gator_trace_sched_init(void)
{
int i;
for (i = 0; i < CPU_WAIT_TOTAL; i++) {
diff --git a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h
index 347a4fe404bc..ff00d90cee78 100644
--- a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h
+++ b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
diff --git a/drivers/gator/mali/mali_utgard_profiling_gator_api.h b/drivers/gator/mali/mali_utgard_profiling_gator_api.h
index 559647a76d29..43c576042880 100644
--- a/drivers/gator/mali/mali_utgard_profiling_gator_api.h
+++ b/drivers/gator/mali/mali_utgard_profiling_gator_api.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
diff --git a/drivers/gator/mali_t6xx.mk b/drivers/gator/mali_t6xx.mk
index 1a98c1c6a73f..059d47aec910 100644
--- a/drivers/gator/mali_t6xx.mk
+++ b/drivers/gator/mali_t6xx.mk
@@ -10,8 +10,17 @@ EXTRA_CFLAGS += -DMALI_USE_UMP=1 \
-DMALI_NO_MALI=0
DDK_DIR ?= .
+ifneq ($(wildcard $(DDK_DIR)/drivers/gpu/arm/t6xx),)
KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase
OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase/osk
+endif
+
+ifneq ($(wildcard $(DDK_DIR)/drivers/gpu/arm/midgard),)
+KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/midgard
+OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/midgard/osk
+EXTRA_CFLAGS += -DMALI_DIR_MIDGARD=1
+endif
+
UMP_DIR = $(DDK_DIR)/include/linux
# Include directories in the DDK
diff --git a/tools/gator/daemon/Android.mk b/tools/gator/daemon/Android.mk
index a0429712fa82..045d028fda5f 100644
--- a/tools/gator/daemon/Android.mk
+++ b/tools/gator/daemon/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h configuration_xml.h)
+XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h)
LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -DETCDIR=\"/etc\" -Ilibsensors
@@ -9,22 +9,33 @@ LOCAL_SRC_FILES := \
Buffer.cpp \
CapturedXML.cpp \
Child.cpp \
- Collector.cpp \
ConfigurationXML.cpp \
Driver.cpp \
+ DriverSource.cpp \
+ DynBuf.cpp \
EventsXML.cpp \
+ ExternalSource.cpp \
Fifo.cpp \
Hwmon.cpp \
KMod.cpp \
LocalCapture.cpp \
Logging.cpp \
main.cpp \
+ Monitor.cpp \
OlySocket.cpp \
OlyUtility.cpp \
+ PerfBuffer.cpp \
+ PerfDriver.cpp \
+ PerfGroup.cpp \
+ PerfSource.cpp \
+ Proc.cpp \
Sender.cpp \
SessionData.cpp \
SessionXML.cpp \
+ Source.cpp \
StreamlineSetup.cpp \
+ UEvent.cpp \
+ UserSpaceSource.cpp \
libsensors/access.c \
libsensors/conf-lex.c \
libsensors/conf-parse.c \
diff --git a/tools/gator/daemon/Buffer.cpp b/tools/gator/daemon/Buffer.cpp
index 090a71553277..93557dabed9f 100644
--- a/tools/gator/daemon/Buffer.cpp
+++ b/tools/gator/daemon/Buffer.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
@@ -12,33 +12,60 @@
#include "Sender.h"
#include "SessionData.h"
-#define mask (size - 1)
-
-Buffer::Buffer (const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : core(core), buftype(buftype), size(size), readPos(0), writePos(0), commitPos(0), available(true), done(false), buf(new char[size]), commitTime(gSessionData->mLiveRate), readerSem(readerSem) {
- if ((size & mask) != 0) {
+#define mask (mSize - 1)
+
+enum {
+ CODE_PEA = 1,
+ CODE_KEYS = 2,
+ CODE_FORMAT = 3,
+ CODE_MAPS = 4,
+ CODE_COMM = 5,
+};
+
+// Summary Frame Messages
+enum {
+ MESSAGE_SUMMARY = 1,
+ MESSAGE_CORE_NAME = 3,
+};
+
+// From gator_marshaling.c
+#define NEWLINE_CANARY \
+ /* Unix */ \
+ "1\n" \
+ /* Windows */ \
+ "2\r\n" \
+ /* Mac OS */ \
+ "3\r" \
+ /* RISC OS */ \
+ "4\n\r" \
+ /* Add another character so the length isn't 0x0a bytes */ \
+ "5"
+
+Buffer::Buffer(const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : mCore(core), mBufType(buftype), mSize(size), mReadPos(0), mWritePos(0), mCommitPos(0), mAvailable(true), mIsDone(false), mBuf(new char[mSize]), mCommitTime(gSessionData->mLiveRate), mReaderSem(readerSem) {
+ if ((mSize & mask) != 0) {
logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
handleException();
}
frame();
}
-Buffer::~Buffer () {
- delete [] buf;
+Buffer::~Buffer() {
+ delete [] mBuf;
}
-void Buffer::write (Sender * const sender) {
+void Buffer::write(Sender *const sender) {
if (!commitReady()) {
return;
}
// determine the size of two halves
- int length1 = commitPos - readPos;
- char * buffer1 = buf + readPos;
+ int length1 = mCommitPos - mReadPos;
+ char *buffer1 = mBuf + mReadPos;
int length2 = 0;
- char * buffer2 = buf;
+ char *buffer2 = mBuf;
if (length1 < 0) {
- length1 = size - readPos;
- length2 = commitPos;
+ length1 = mSize - mReadPos;
+ length2 = mCommitPos;
}
logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
@@ -53,22 +80,22 @@ void Buffer::write (Sender * const sender) {
sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
}
- readPos = commitPos;
+ mReadPos = mCommitPos;
}
-bool Buffer::commitReady () const {
- return commitPos != readPos;
+bool Buffer::commitReady() const {
+ return mCommitPos != mReadPos;
}
-int Buffer::bytesAvailable () const {
- int filled = writePos - readPos;
+int Buffer::bytesAvailable() const {
+ int filled = mWritePos - mReadPos;
if (filled < 0) {
- filled += size;
+ filled += mSize;
}
- int remaining = size - filled;
+ int remaining = mSize - filled;
- if (available) {
+ if (mAvailable) {
// Give some extra room; also allows space to insert the overflow error packet
remaining -= 200;
} else {
@@ -79,58 +106,68 @@ int Buffer::bytesAvailable () const {
return remaining;
}
-bool Buffer::checkSpace (const int bytes) {
+bool Buffer::checkSpace(const int bytes) {
const int remaining = bytesAvailable();
if (remaining < bytes) {
- available = false;
+ mAvailable = false;
} else {
- available = true;
+ mAvailable = true;
}
- return available;
+ return mAvailable;
+}
+
+int Buffer::contiguousSpaceAvailable() const {
+ int remaining = bytesAvailable();
+ int contiguous = mSize - mWritePos;
+ if (remaining < contiguous) {
+ return remaining;
+ } else {
+ return contiguous;
+ }
}
-void Buffer::commit (const uint64_t time) {
+void Buffer::commit(const uint64_t time) {
// post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
- int length = writePos - commitPos;
+ int length = mWritePos - mCommitPos;
if (length < 0) {
- length += size;
+ length += mSize;
}
length = length - typeLength - sizeof(int32_t);
for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
- buf[(commitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
+ mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
}
- logg->logMessage("Committing data readPos: %i writePos: %i commitPos: %i", readPos, writePos, commitPos);
- commitPos = writePos;
+ logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
+ mCommitPos = mWritePos;
if (gSessionData->mLiveRate > 0) {
- while (time > commitTime) {
- commitTime += gSessionData->mLiveRate;
+ while (time > mCommitTime) {
+ mCommitTime += gSessionData->mLiveRate;
}
}
- if (!done) {
+ if (!mIsDone) {
frame();
}
// send a notification that data is ready
- sem_post(readerSem);
+ sem_post(mReaderSem);
}
-void Buffer::check (const uint64_t time) {
- int filled = writePos - commitPos;
+void Buffer::check(const uint64_t time) {
+ int filled = mWritePos - mCommitPos;
if (filled < 0) {
- filled += size;
+ filled += mSize;
}
- if (filled >= ((size * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= commitTime)) {
+ if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
commit(time);
}
}
-void Buffer::packInt (int32_t x) {
+void Buffer::packInt(int32_t x) {
int packedBytes = 0;
int more = true;
while (more) {
@@ -144,14 +181,14 @@ void Buffer::packInt (int32_t x) {
b |= 0x80;
}
- buf[(writePos + packedBytes) & mask] = b;
+ mBuf[(mWritePos + packedBytes) & mask] = b;
packedBytes++;
}
- writePos = (writePos + packedBytes) & mask;
+ mWritePos = (mWritePos + packedBytes) & mask;
}
-void Buffer::packInt64 (int64_t x) {
+void Buffer::packInt64(int64_t x) {
int packedBytes = 0;
int more = true;
while (more) {
@@ -165,24 +202,61 @@ void Buffer::packInt64 (int64_t x) {
b |= 0x80;
}
- buf[(writePos + packedBytes) & mask] = b;
+ mBuf[(mWritePos + packedBytes) & mask] = b;
packedBytes++;
}
- writePos = (writePos + packedBytes) & mask;
+ mWritePos = (mWritePos + packedBytes) & mask;
+}
+
+void Buffer::writeBytes(const void *const data, size_t count) {
+ size_t i;
+ for (i = 0; i < count; ++i) {
+ mBuf[(mWritePos + i) & mask] = static_cast<const char *>(data)[i];
+ }
+
+ mWritePos = (mWritePos + i) & mask;
}
-void Buffer::frame () {
+void Buffer::writeString(const char *const str) {
+ const int len = strlen(str);
+ packInt(len);
+ writeBytes(str, len);
+}
+
+void Buffer::frame() {
if (!gSessionData->mLocalCapture) {
packInt(RESPONSE_APC_DATA);
}
// Reserve space for the length
- writePos += sizeof(int32_t);
- packInt(buftype);
- packInt(core);
+ mWritePos += sizeof(int32_t);
+ packInt(mBufType);
+ packInt(mCore);
}
-bool Buffer::eventHeader (const uint64_t curr_time) {
+void Buffer::summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
+ packInt(MESSAGE_SUMMARY);
+ writeString(NEWLINE_CANARY);
+ packInt64(timestamp);
+ packInt64(uptime);
+ packInt64(monotonicDelta);
+ writeString("uname");
+ writeString(uname);
+ writeString("");
+ check(1);
+}
+
+void Buffer::coreName(const int core, const int cpuid, const char *const name) {
+ if (checkSpace(3 * MAXSIZE_PACK32 + 0x100)) {
+ packInt(MESSAGE_CORE_NAME);
+ packInt(core);
+ packInt(cpuid);
+ writeString(name);
+ }
+ check(1);
+}
+
+bool Buffer::eventHeader(const uint64_t curr_time) {
bool retval = false;
if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
packInt(0); // key of zero indicates a timestamp
@@ -193,9 +267,9 @@ bool Buffer::eventHeader (const uint64_t curr_time) {
return retval;
}
-bool Buffer::eventTid (const int tid) {
+bool Buffer::eventTid(const int tid) {
bool retval = false;
- if (checkSpace(2*MAXSIZE_PACK32)) {
+ if (checkSpace(2 * MAXSIZE_PACK32)) {
packInt(1); // key of 1 indicates a tid
packInt(tid);
retval = true;
@@ -204,25 +278,94 @@ bool Buffer::eventTid (const int tid) {
return retval;
}
-void Buffer::event (const int32_t key, const int32_t value) {
+void Buffer::event(const int32_t key, const int32_t value) {
if (checkSpace(2 * MAXSIZE_PACK32)) {
packInt(key);
packInt(value);
}
}
-void Buffer::event64 (const int64_t key, const int64_t value) {
+void Buffer::event64(const int64_t key, const int64_t value) {
if (checkSpace(2 * MAXSIZE_PACK64)) {
packInt64(key);
packInt64(value);
}
}
-void Buffer::setDone () {
- done = true;
+void Buffer::pea(const struct perf_event_attr *const pea, int key) {
+ if (checkSpace(2 * MAXSIZE_PACK32 + pea->size)) {
+ packInt(CODE_PEA);
+ writeBytes(pea, pea->size);
+ packInt(key);
+ } else {
+ logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
+ handleException();
+ }
+ // Don't know the real perf time so use 1 as it will work for now
+ check(1);
+}
+
+void Buffer::keys(const int count, const __u64 *const ids, const int *const keys) {
+ if (checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) {
+ packInt(CODE_KEYS);
+ packInt(count);
+ for (int i = 0; i < count; ++i) {
+ packInt64(ids[i]);
+ packInt(keys[i]);
+ }
+ } else {
+ logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
+ handleException();
+ }
+ check(1);
+}
+
+void Buffer::format(const int length, const char *const format) {
+ if (checkSpace(MAXSIZE_PACK32 + length + 1)) {
+ packInt(CODE_FORMAT);
+ writeBytes(format, length + 1);
+ } else {
+ logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
+ handleException();
+ }
+ check(1);
+}
+
+void Buffer::maps(const int pid, const int tid, const char *const maps) {
+ const int mapsLen = strlen(maps) + 1;
+ if (checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) {
+ packInt(CODE_MAPS);
+ packInt(pid);
+ packInt(tid);
+ writeBytes(maps, mapsLen);
+ } else {
+ logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
+ handleException();
+ }
+ check(1);
+}
+
+void Buffer::comm(const int pid, const int tid, const char *const image, const char *const comm) {
+ const int imageLen = strlen(image) + 1;
+ const int commLen = strlen(comm) + 1;
+ if (checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) {
+ packInt(CODE_COMM);
+ packInt(pid);
+ packInt(tid);
+ writeBytes(image, imageLen);
+ writeBytes(comm, commLen);
+ } else {
+ logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
+ handleException();
+ }
+ check(1);
+}
+
+void Buffer::setDone() {
+ mIsDone = true;
commit(0);
}
-bool Buffer::isDone () const {
- return done && readPos == commitPos && commitPos == writePos;
+bool Buffer::isDone() const {
+ return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;
}
diff --git a/tools/gator/daemon/Buffer.h b/tools/gator/daemon/Buffer.h
index b3c8d78cf758..50237771860c 100644
--- a/tools/gator/daemon/Buffer.h
+++ b/tools/gator/daemon/Buffer.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
@@ -9,54 +9,89 @@
#ifndef BUFFER_H
#define BUFFER_H
-#include <stddef.h>
#include <stdint.h>
#include <semaphore.h>
+#include "k/perf_event.h"
+
class Sender;
+enum {
+ FRAME_SUMMARY = 1,
+ FRAME_BLOCK_COUNTER = 5,
+ FRAME_EXTERNAL = 10,
+ FRAME_PERF_ATTRS = 11,
+ FRAME_PERF = 12,
+};
+
class Buffer {
public:
static const size_t MAXSIZE_PACK32 = 5;
static const size_t MAXSIZE_PACK64 = 10;
- Buffer (int32_t core, int32_t buftype, const int size, sem_t *const readerSem);
- ~Buffer ();
+ Buffer(int32_t core, int32_t buftype, const int size, sem_t *const readerSem);
+ ~Buffer();
+
+ void write(Sender *sender);
+
+ int bytesAvailable() const;
+ int contiguousSpaceAvailable() const;
+ void commit(const uint64_t time);
+ void check(const uint64_t time);
- void write (Sender * sender);
+ void frame();
- int bytesAvailable () const;
- void commit (const uint64_t time);
- void check (const uint64_t time);
+ // Summary messages
+ void summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname);
+ void coreName(const int core, const int cpuid, const char *const name);
- void frame ();
+ // Block Counter messages
+ bool eventHeader(uint64_t curr_time);
+ bool eventTid(int tid);
+ void event(int32_t key, int32_t value);
+ void event64(int64_t key, int64_t value);
- bool eventHeader (uint64_t curr_time);
- bool eventTid (int tid);
- void event (int32_t key, int32_t value);
- void event64 (int64_t key, int64_t value);
+ // Perf Attrs messages
+ void pea(const struct perf_event_attr *const pea, int key);
+ void keys(const int count, const __u64 *const ids, const int *const keys);
+ void format(const int length, const char *const format);
+ void maps(const int pid, const int tid, const char *const maps);
+ void comm(const int pid, const int tid, const char *const image, const char *const comm);
- void setDone ();
- bool isDone () const;
+ void setDone();
+ bool isDone() const;
+
+ // Prefer a new member to using these functions if possible
+ char *getWritePos() { return mBuf + mWritePos; }
+ void advanceWrite(int bytes) { mWritePos = (mWritePos + bytes) & /*mask*/(mSize - 1); }
+
+ static void writeLEInt(unsigned char *buf, int v) {
+ buf[0] = (v >> 0) & 0xFF;
+ buf[1] = (v >> 8) & 0xFF;
+ buf[2] = (v >> 16) & 0xFF;
+ buf[3] = (v >> 24) & 0xFF;
+ }
private:
- bool commitReady () const;
- bool checkSpace (int bytes);
-
- void packInt (int32_t x);
- void packInt64 (int64_t x);
-
- const int32_t core;
- const int32_t buftype;
- const int size;
- int readPos;
- int writePos;
- int commitPos;
- bool available;
- bool done;
- char *const buf;
- uint64_t commitTime;
- sem_t *const readerSem;
+ bool commitReady() const;
+ bool checkSpace(int bytes);
+
+ void packInt(int32_t x);
+ void packInt64(int64_t x);
+ void writeBytes(const void *const data, size_t count);
+ void writeString(const char *const str);
+
+ const int32_t mCore;
+ const int32_t mBufType;
+ const int mSize;
+ int mReadPos;
+ int mWritePos;
+ int mCommitPos;
+ bool mAvailable;
+ bool mIsDone;
+ char *const mBuf;
+ uint64_t mCommitTime;
+ sem_t *const mReaderSem;
// Intentionally unimplemented
Buffer(const Buffer &);
diff --git a/tools/gator/daemon/CapturedXML.cpp b/tools/gator/daemon/CapturedXML.cpp
index 30c4c44c5d92..cf79b72a1166 100644
--- a/tools/gator/daemon/CapturedXML.cpp
+++ b/tools/gator/daemon/CapturedXML.cpp
@@ -1,16 +1,18 @@
/**
- * 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
* published by the Free Software Foundation.
*/
+#include "CapturedXML.h"
+
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
+
#include "SessionData.h"
-#include "CapturedXML.h"
#include "Logging.h"
#include "OlyUtility.h"
@@ -30,6 +32,9 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
captured = mxmlNewElement(xml, "captured");
mxmlElementSetAttr(captured, "version", "1");
+ if (gSessionData->perf.isSetup()) {
+ mxmlElementSetAttr(captured, "type", "Perf");
+ }
mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION);
if (includeTime) { // Send the following only after the capture is complete
if (time(NULL) > 1267000000) { // If the time is reasonable (after Feb 23, 2010)
@@ -41,7 +46,7 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
mxmlElementSetAttr(target, "name", gSessionData->mCoreName);
mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate);
mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores);
- mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mCpuId);
+ mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mMaxCpuId);
if (!gSessionData->mOneShot && (gSessionData->mSampleRate > 0)) {
mxmlElementSetAttr(target, "supports_live", "yes");
diff --git a/tools/gator/daemon/CapturedXML.h b/tools/gator/daemon/CapturedXML.h
index b0482f593c6f..efc1e52bdba3 100644
--- a/tools/gator/daemon/CapturedXML.h
+++ b/tools/gator/daemon/CapturedXML.h
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/tools/gator/daemon/Child.cpp b/tools/gator/daemon/Child.cpp
index 9ee2ef8afb9d..ca33561ffdca 100644
--- a/tools/gator/daemon/Child.cpp
+++ b/tools/gator/daemon/Child.cpp
@@ -1,38 +1,39 @@
/**
- * 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
* published by the Free Software Foundation.
*/
+#include "Child.h"
+
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/prctl.h>
+
#include "Logging.h"
#include "CapturedXML.h"
#include "SessionData.h"
-#include "Child.h"
#include "LocalCapture.h"
-#include "Collector.h"
#include "Sender.h"
#include "OlyUtility.h"
+#include "OlySocket.h"
#include "StreamlineSetup.h"
#include "ConfigurationXML.h"
#include "Driver.h"
-#include "Fifo.h"
-#include "Buffer.h"
-
-#define NS_PER_S ((uint64_t)1000000000)
-#define NS_PER_US 1000
+#include "PerfSource.h"
+#include "DriverSource.h"
+#include "UserSpaceSource.h"
+#include "ExternalSource.h"
static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads
-static Fifo* collectorFifo = NULL; // Shared by Child.cpp and spawned threads
-static Buffer* buffer = NULL;
+static Source *primarySource = NULL;
+static Source *userSpaceSource = NULL;
+static Source *externalSource = NULL;
static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
-static Collector* collector = NULL;
Child* child = NULL; // shared by Child.cpp and main.cpp
extern void cleanUp();
@@ -78,7 +79,7 @@ static void child_handler(int signum) {
}
beenHere = true;
logg->logMessage("Gator is shutting down.");
- if (signum == SIGALRM || !collector) {
+ if (signum == SIGALRM || !primarySource) {
exit(1);
} else {
child->endSession();
@@ -139,77 +140,22 @@ static void *stopThread(void *) {
return 0;
}
-static void *countersThread(void *) {
- prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
-
- gSessionData->hwmon.start();
-
- int64_t monotonic_started = 0;
- while (monotonic_started <= 0) {
- usleep(10);
-
- if (Collector::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
- logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
- handleException();
- }
- }
-
- uint64_t next_time = 0;
- while (gSessionData->mSessionIsActive) {
- struct timespec ts;
-#ifndef CLOCK_MONOTONIC_RAW
- // Android doesn't have this defined but it was added in Linux 2.6.28
-#define CLOCK_MONOTONIC_RAW 4
-#endif
- if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
- logg->logError(__FILE__, __LINE__, "Failed to get uptime");
- handleException();
- }
- const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started;
- // Sample ten times a second ignoring gSessionData->mSampleRate
- next_time += NS_PER_S/10;//gSessionData->mSampleRate;
- if (next_time < curr_time) {
- logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
- next_time = curr_time;
- }
-
- if (buffer->eventHeader(curr_time)) {
- gSessionData->hwmon.read(buffer);
- // Only check after writing all counters so that time and corresponding counters appear in the same frame
- buffer->check(curr_time);
- }
-
- if (buffer->bytesAvailable() <= 0) {
- logg->logMessage("One shot (counters)");
- child->endSession();
- }
-
- usleep((next_time - curr_time)/NS_PER_US);
- }
-
- buffer->setDone();
-
- return NULL;
-}
-
static void *senderThread(void *) {
- int length = 1;
- char* data;
char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0};
sem_post(&senderThreadStarted);
prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0);
sem_wait(&haltPipeline);
- while (length > 0 || !buffer->isDone()) {
+ while (!primarySource->isDone() || (userSpaceSource != NULL && !userSpaceSource->isDone()) || (externalSource != NULL && !externalSource->isDone())) {
sem_wait(&senderSem);
- data = collectorFifo->read(&length);
- if (data != NULL) {
- sender->writeData(data, length, RESPONSE_APC_DATA);
- collectorFifo->release();
+
+ primarySource->write(sender);
+ if (userSpaceSource != NULL) {
+ userSpaceSource->write(sender);
}
- if (!buffer->isDone()) {
- buffer->write(sender);
+ if (externalSource != NULL) {
+ externalSource->write(sender);
}
}
@@ -255,15 +201,13 @@ void Child::initialization() {
void Child::endSession() {
gSessionData->mSessionIsActive = false;
- collector->stop();
+ primarySource->interrupt();
sem_post(&haltPipeline);
}
void Child::run() {
- char* collectBuffer;
- int bytesCollected = 0;
LocalCapture* localCapture = NULL;
- pthread_t durationThreadID, stopThreadID, senderThreadID, countersThreadID;
+ pthread_t durationThreadID, stopThreadID, senderThreadID;
prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0);
@@ -282,7 +226,11 @@ void Child::run() {
{ ConfigurationXML configuration; }
// Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
- collector = new Collector();
+ if (!gSessionData->perf.isSetup()) {
+ primarySource = new DriverSource(&senderSem, &startProfile);
+ } else {
+ primarySource = new PerfSource(&senderSem, &startProfile);
+ }
// Initialize all drivers
for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
@@ -317,15 +265,11 @@ void Child::run() {
free(xmlString);
}
- // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
- logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, collector->getBufferSize());
- collectorFifo = new Fifo(collector->getBufferSize() + 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem);
-
- // Get the initial pointer to the collect buffer
- collectBuffer = collectorFifo->start();
-
- // Create a new Block Counter Buffer
- buffer = new Buffer(0, 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem);
+ // Must be after session XML is parsed
+ if (!primarySource->prepare()) {
+ logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
+ handleException();
+ }
// Sender thread shall be halted until it is signaled for one shot mode
sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
@@ -340,14 +284,21 @@ void Child::run() {
thread_creation_success = false;
}
- bool startcountersThread = gSessionData->hwmon.countersEnabled();
- if (startcountersThread) {
- if (pthread_create(&countersThreadID, NULL, countersThread, this)) {
- thread_creation_success = false;
+ if (gSessionData->hwmon.countersEnabled()) {
+ userSpaceSource = new UserSpaceSource(&senderSem);
+ if (!userSpaceSource->prepare()) {
+ logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
+ handleException();
}
- } else {
- // Let senderThread know there is no buffer data to send
- buffer->setDone();
+ userSpaceSource->start();
+ }
+ if (access("/tmp/gator", F_OK) == 0) {
+ externalSource = new ExternalSource(&senderSem);
+ if (!externalSource->prepare()) {
+ logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
+ handleException();
+ }
+ externalSource->start();
}
if (!thread_creation_success) {
@@ -359,28 +310,13 @@ void Child::run() {
sem_wait(&senderThreadStarted);
// Start profiling
- logg->logMessage("********** Profiling started **********");
- collector->start();
- sem_post(&startProfile);
-
- // Collect Data
- do {
- // This command will stall until data is received from the driver
- bytesCollected = collector->collect(collectBuffer);
-
- // In one shot mode, stop collection once all the buffers are filled
- if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
- if (bytesCollected == -1 || collectorFifo->willFill(bytesCollected)) {
- logg->logMessage("One shot");
- endSession();
- }
- }
- collectBuffer = collectorFifo->write(bytesCollected);
- } while (bytesCollected > 0);
- logg->logMessage("Exit collect data loop");
+ primarySource->run();
- if (startcountersThread) {
- pthread_join(countersThreadID, NULL);
+ if (externalSource != NULL) {
+ externalSource->join();
+ }
+ if (userSpaceSource != NULL) {
+ userSpaceSource->join();
}
// Wait for the other threads to exit
@@ -401,9 +337,9 @@ void Child::run() {
logg->logMessage("Profiling ended.");
- delete buffer;
- delete collectorFifo;
+ delete externalSource;
+ delete userSpaceSource;
+ delete primarySource;
delete sender;
- delete collector;
delete localCapture;
}
diff --git a/tools/gator/daemon/Child.h b/tools/gator/daemon/Child.h
index 0330e9d78027..9e206d7113b8 100644
--- a/tools/gator/daemon/Child.h
+++ b/tools/gator/daemon/Child.h
@@ -1,5 +1,5 @@
/**
- * 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
@@ -9,8 +9,6 @@
#ifndef __CHILD_H__
#define __CHILD_H__
-#include <pthread.h>
-
class OlySocket;
class Child {
diff --git a/tools/gator/daemon/Collector.h b/tools/gator/daemon/Collector.h
deleted file mode 100644
index c5e9eac573dd..000000000000
--- a/tools/gator/daemon/Collector.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2010-2013. 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
- * published by the Free Software Foundation.
- */
-
-#ifndef __COLLECTOR_H__
-#define __COLLECTOR_H__
-
-#include <stdio.h>
-
-class Collector {
-public:
- Collector();
- ~Collector();
- void start();
- void stop();
- int collect(char* buffer);
- int getBufferSize() {return mBufferSize;}
-
- static int readIntDriver(const char* path, int* value);
- static int readInt64Driver(const char* path, int64_t* value);
- static int writeDriver(const char* path, int value);
- static int writeDriver(const char* path, int64_t value);
- static int writeDriver(const char* path, const char* data);
- static int writeReadDriver(const char* path, int* value);
- static int writeReadDriver(const char* path, int64_t* value);
-
-private:
- int mBufferSize;
- int mBufferFD;
-
- void checkVersion();
-};
-
-#endif //__COLLECTOR_H__
diff --git a/tools/gator/daemon/Config.h b/tools/gator/daemon/Config.h
new file mode 100644
index 000000000000..6f5e2aae50e1
--- /dev/null
+++ b/tools/gator/daemon/Config.h
@@ -0,0 +1,17 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#define ARRAY_LENGTH(A) static_cast<int>(sizeof(A)/sizeof((A)[0]))
+
+#define MAX_PERFORMANCE_COUNTERS 50
+#define NR_CPUS 16
+
+#endif // CONFIG_H
diff --git a/tools/gator/daemon/ConfigurationXML.cpp b/tools/gator/daemon/ConfigurationXML.cpp
index 2a5252a5bb04..fd479f2452cd 100644
--- a/tools/gator/daemon/ConfigurationXML.cpp
+++ b/tools/gator/daemon/ConfigurationXML.cpp
@@ -1,15 +1,17 @@
/**
- * 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
* published by the Free Software Foundation.
*/
+#include "ConfigurationXML.h"
+
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
-#include "ConfigurationXML.h"
+
#include "Driver.h"
#include "Logging.h"
#include "OlyUtility.h"
@@ -67,6 +69,7 @@ int ConfigurationXML::parse(const char* configurationXML) {
// clear counter overflow
gSessionData->mCounterOverflow = 0;
+ gSessionData->mIsEBS = false;
mIndex = 0;
// disable all counters prior to parsing the configuration xml
@@ -155,6 +158,9 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER));
if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16));
if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10));
+ if (counter.getCount() > 0) {
+ gSessionData->mIsEBS = true;
+ }
counter.setEnabled(true);
// Associate a driver with each counter
@@ -181,9 +187,9 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
}
void ConfigurationXML::getDefaultConfigurationXml(const char * & xml, unsigned int & len) {
-#include "configuration_xml.h" // defines and initializes char configuration_xml[] and int configuration_xml_len
- xml = (const char *)configuration_xml;
- len = configuration_xml_len;
+#include "defaults_xml.h" // defines and initializes char defaults_xml[] and int defaults_xml_len
+ xml = (const char *)defaults_xml;
+ len = defaults_xml_len;
}
void ConfigurationXML::getPath(char* path) {
diff --git a/tools/gator/daemon/ConfigurationXML.h b/tools/gator/daemon/ConfigurationXML.h
index 5650f487b990..efa415e508b6 100644
--- a/tools/gator/daemon/ConfigurationXML.h
+++ b/tools/gator/daemon/ConfigurationXML.h
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/tools/gator/daemon/Counter.h b/tools/gator/daemon/Counter.h
index 231a85d6e3b5..689174573e4e 100644
--- a/tools/gator/daemon/Counter.h
+++ b/tools/gator/daemon/Counter.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
@@ -25,7 +25,7 @@ public:
void clear () {
mType[0] = '\0';
mEnabled = false;
- mEvent = 0;
+ mEvent = -1;
mCount = 0;
mKey = 0;
mDriver = NULL;
diff --git a/tools/gator/daemon/Driver.cpp b/tools/gator/daemon/Driver.cpp
index c262467dc219..09e040162912 100644
--- a/tools/gator/daemon/Driver.cpp
+++ b/tools/gator/daemon/Driver.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
diff --git a/tools/gator/daemon/Driver.h b/tools/gator/daemon/Driver.h
index f3a932f852cb..e5ed7b6c1295 100644
--- a/tools/gator/daemon/Driver.h
+++ b/tools/gator/daemon/Driver.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
@@ -27,7 +27,7 @@ public:
virtual void setupCounter(Counter &counter) = 0;
// Emits available counters
- virtual void writeCounters(mxml_node_t *root) const = 0;
+ virtual int writeCounters(mxml_node_t *root) const = 0;
// Emits possible dynamically generated events/counters
virtual void writeEvents(mxml_node_t *) const {}
diff --git a/tools/gator/daemon/Collector.cpp b/tools/gator/daemon/DriverSource.cpp
index bf73534692a0..f78ec6b7ce41 100644
--- a/tools/gator/daemon/Collector.cpp
+++ b/tools/gator/daemon/DriverSource.cpp
@@ -1,5 +1,5 @@
/**
- * 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
@@ -8,23 +8,47 @@
#define __STDC_FORMAT_MACROS
+#include "DriverSource.h"
+
#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/time.h>
#include <inttypes.h>
-#include "Collector.h"
-#include "SessionData.h"
+#include <unistd.h>
+
+#include "Child.h"
+#include "Fifo.h"
#include "Logging.h"
#include "Sender.h"
+#include "SessionData.h"
+
+extern Child *child;
-// Driver initialization independent of session settings
-Collector::Collector() {
- mBufferFD = 0;
+DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) {
+ int driver_version = 0;
- checkVersion();
+ if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
+ logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
+ handleException();
+ }
+
+ // Verify the driver version matches the daemon version
+ if (driver_version != PROTOCOL_VERSION) {
+ if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
+ // One of the mismatched versions is development version
+ logg->logError(__FILE__, __LINE__,
+ "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
+ ">> The following must be synchronized from engineering repository:\n"
+ ">> * gator driver\n"
+ ">> * gator daemon\n"
+ ">> * Streamline", driver_version, PROTOCOL_VERSION);
+ handleException();
+ } else {
+ // Release version mismatch
+ logg->logError(__FILE__, __LINE__,
+ "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
+ ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
+ handleException();
+ }
+ }
int enable = -1;
if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) {
@@ -37,14 +61,15 @@ Collector::Collector() {
gSessionData->mCores = 1;
}
- mBufferSize = 0;
if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) {
logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size");
handleException();
}
}
-Collector::~Collector() {
+DriverSource::~DriverSource() {
+ delete mFifo;
+
// Write zero for safety, as a zero should have already been written
writeDriver("/dev/gator/enable", "0");
@@ -54,36 +79,21 @@ Collector::~Collector() {
}
}
-void Collector::checkVersion() {
- int driver_version = 0;
-
- if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
- logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
- handleException();
- }
+bool DriverSource::prepare() {
+ // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
+ logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, mBufferSize);
+ mFifo = new Fifo(mBufferSize + 5, gSessionData->mTotalBufferSize*1024*1024, mSenderSem);
- // Verify the driver version matches the daemon version
- if (driver_version != PROTOCOL_VERSION) {
- if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
- // One of the mismatched versions is development version
- logg->logError(__FILE__, __LINE__,
- "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
- ">> The following must be synchronized from engineering repository:\n"
- ">> * gator driver\n"
- ">> * gator daemon\n"
- ">> * Streamline", driver_version, PROTOCOL_VERSION);
- handleException();
- } else {
- // Release version mismatch
- logg->logError(__FILE__, __LINE__,
- "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
- ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
- handleException();
- }
- }
+ return true;
}
-void Collector::start() {
+void DriverSource::run() {
+ // Get the initial pointer to the collect buffer
+ char *collectBuffer = mFifo->start();
+ int bytesCollected = 0;
+
+ logg->logMessage("********** Profiling started **********");
+
// Set the maximum backtrace depth
if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) {
logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
@@ -125,79 +135,112 @@ void Collector::start() {
}
lseek(mBufferFD, 0, SEEK_SET);
+
+ sem_post(mStartProfile);
+
+ // Collect Data
+ do {
+ // This command will stall until data is received from the driver
+ // Calls event_buffer_read in the driver
+ errno = 0;
+ bytesCollected = read(mBufferFD, collectBuffer, mBufferSize);
+
+ // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
+ if (bytesCollected == -1 && errno == EINTR) {
+ bytesCollected = read(mBufferFD, collectBuffer, mBufferSize);
+ }
+
+ // return the total bytes written
+ logg->logMessage("Driver read of %d bytes", bytesCollected);
+
+ // In one shot mode, stop collection once all the buffers are filled
+ if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
+ if (bytesCollected == -1 || mFifo->willFill(bytesCollected)) {
+ logg->logMessage("One shot");
+ child->endSession();
+ }
+ }
+ collectBuffer = mFifo->write(bytesCollected);
+ } while (bytesCollected > 0);
+
+ logg->logMessage("Exit collect data loop");
}
-// These commands should cause the read() function in collect() to return
-void Collector::stop() {
- // This will stop the driver from profiling
+void DriverSource::interrupt() {
+ // This command should cause the read() function in collect() to return and stop the driver from profiling
if (writeDriver("/dev/gator/enable", "0") != 0) {
logg->logMessage("Stopping kernel failed");
}
}
-int Collector::collect(char* buffer) {
- // Calls event_buffer_read in the driver
- int bytesRead;
-
- errno = 0;
- bytesRead = read(mBufferFD, buffer, mBufferSize);
+bool DriverSource::isDone() {
+ return mLength <= 0;
+}
- // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
- if (bytesRead == -1 && errno == EINTR) {
- bytesRead = read(mBufferFD, buffer, mBufferSize);
+void DriverSource::write(Sender *sender) {
+ char *data = mFifo->read(&mLength);
+ if (data != NULL) {
+ sender->writeData(data, mLength, RESPONSE_APC_DATA);
+ mFifo->release();
}
-
- // return the total bytes written
- logg->logMessage("Driver read of %d bytes", bytesRead);
- return bytesRead;
}
-int Collector::readIntDriver(const char* fullpath, int* value) {
- FILE* file = fopen(fullpath, "r");
- if (file == NULL) {
+int DriverSource::readIntDriver(const char *fullpath, int *value) {
+ char data[40]; // Sufficiently large to hold any integer
+ const int fd = open(fullpath, O_RDONLY);
+ if (fd < 0) {
+ return -1;
+ }
+
+ const ssize_t bytes = read(fd, data, sizeof(data) - 1);
+ close(fd);
+ if (bytes < 0) {
return -1;
}
- if (fscanf(file, "%u", value) != 1) {
- fclose(file);
+ data[bytes] = '\0';
+
+ char *endptr;
+ errno = 0;
+ *value = strtol(data, &endptr, 10);
+ if (errno != 0 || *endptr != '\n') {
logg->logMessage("Invalid value in file %s", fullpath);
return -1;
}
- fclose(file);
+
return 0;
}
-int Collector::readInt64Driver(const char* fullpath, int64_t* value) {
- FILE* file = fopen(fullpath, "r");
- if (file == NULL) {
+int DriverSource::readInt64Driver(const char *fullpath, int64_t *value) {
+ char data[40]; // Sufficiently large to hold any integer
+ const int fd = open(fullpath, O_RDONLY);
+ if (fd < 0) {
return -1;
}
- if (fscanf(file, "%" SCNi64, value) != 1) {
- fclose(file);
- logg->logMessage("Invalid value in file %s", fullpath);
+
+ const ssize_t bytes = read(fd, data, sizeof(data) - 1);
+ close(fd);
+ if (bytes < 0) {
return -1;
}
- fclose(file);
- return 0;
-}
+ data[bytes] = '\0';
-int Collector::writeDriver(const char* path, int value) {
- char data[40]; // Sufficiently large to hold any integer
- snprintf(data, sizeof(data), "%d", value);
- return writeDriver(path, data);
-}
+ char *endptr;
+ errno = 0;
+ *value = strtoll(data, &endptr, 10);
+ if (errno != 0 || *endptr != '\n') {
+ logg->logMessage("Invalid value in file %s", fullpath);
+ return -1;
+ }
-int Collector::writeDriver(const char* path, int64_t value) {
- char data[40]; // Sufficiently large to hold any integer
- snprintf(data, sizeof(data), "%" PRIi64, value);
- return writeDriver(path, data);
+ return 0;
}
-int Collector::writeDriver(const char* fullpath, const char* data) {
+int DriverSource::writeDriver(const char *fullpath, const char *data) {
int fd = open(fullpath, O_WRONLY);
if (fd < 0) {
return -1;
}
- if (write(fd, data, strlen(data)) < 0) {
+ if (::write(fd, data, strlen(data)) < 0) {
close(fd);
logg->logMessage("Opened but could not write to %s", fullpath);
return -1;
@@ -206,14 +249,26 @@ int Collector::writeDriver(const char* fullpath, const char* data) {
return 0;
}
-int Collector::writeReadDriver(const char* path, int* value) {
+int DriverSource::writeDriver(const char *path, int value) {
+ char data[40]; // Sufficiently large to hold any integer
+ snprintf(data, sizeof(data), "%d", value);
+ return writeDriver(path, data);
+}
+
+int DriverSource::writeDriver(const char *path, int64_t value) {
+ char data[40]; // Sufficiently large to hold any integer
+ snprintf(data, sizeof(data), "%" PRIi64, value);
+ return writeDriver(path, data);
+}
+
+int DriverSource::writeReadDriver(const char *path, int *value) {
if (writeDriver(path, *value) || readIntDriver(path, value)) {
return -1;
}
return 0;
}
-int Collector::writeReadDriver(const char* path, int64_t* value) {
+int DriverSource::writeReadDriver(const char *path, int64_t *value) {
if (writeDriver(path, *value) || readInt64Driver(path, value)) {
return -1;
}
diff --git a/tools/gator/daemon/DriverSource.h b/tools/gator/daemon/DriverSource.h
new file mode 100644
index 000000000000..dcf1078a239c
--- /dev/null
+++ b/tools/gator/daemon/DriverSource.h
@@ -0,0 +1,52 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef DRIVERSOURCE_H
+#define DRIVERSOURCE_H
+
+#include <semaphore.h>
+#include <stdint.h>
+
+#include "Source.h"
+
+class Fifo;
+
+class DriverSource : public Source {
+public:
+ DriverSource(sem_t *senderSem, sem_t *startProfile);
+ ~DriverSource();
+
+ bool prepare();
+ void run();
+ void interrupt();
+
+ bool isDone();
+ void write(Sender *sender);
+
+ static int readIntDriver(const char *fullpath, int *value);
+ static int readInt64Driver(const char *fullpath, int64_t *value);
+ static int writeDriver(const char *fullpath, const char *data);
+ static int writeDriver(const char *path, int value);
+ static int writeDriver(const char *path, int64_t value);
+ static int writeReadDriver(const char *path, int *value);
+ static int writeReadDriver(const char *path, int64_t *value);
+
+private:
+ Fifo *mFifo;
+ sem_t *const mSenderSem;
+ sem_t *const mStartProfile;
+ int mBufferSize;
+ int mBufferFD;
+ int mLength;
+
+ // Intentionally unimplemented
+ DriverSource(const DriverSource &);
+ DriverSource &operator=(const DriverSource &);
+};
+
+#endif // DRIVERSOURCE_H
diff --git a/tools/gator/daemon/DynBuf.cpp b/tools/gator/daemon/DynBuf.cpp
new file mode 100644
index 000000000000..6f92b336ae19
--- /dev/null
+++ b/tools/gator/daemon/DynBuf.cpp
@@ -0,0 +1,139 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#include "DynBuf.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "Logging.h"
+
+// Pick an aggressive size as buffer is primarily used for disk IO
+#define MIN_BUFFER_FREE (1 << 12)
+
+int DynBuf::resize(const size_t minCapacity) {
+ size_t scaledCapacity = 2 * capacity;
+ if (scaledCapacity < minCapacity) {
+ scaledCapacity = minCapacity;
+ }
+ if (scaledCapacity < 2 * MIN_BUFFER_FREE) {
+ scaledCapacity = 2 * MIN_BUFFER_FREE;
+ }
+ capacity = scaledCapacity;
+
+ buf = static_cast<char *>(realloc(buf, capacity));
+ if (buf == NULL) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+bool DynBuf::read(const char *const path) {
+ int result = false;
+
+ const int fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ length = 0;
+
+ for (;;) {
+ const size_t minCapacity = length + MIN_BUFFER_FREE + 1;
+ if (capacity < minCapacity) {
+ if (resize(minCapacity) != 0) {
+ logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+ }
+
+ const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1);
+ if (bytes < 0) {
+ logg->logMessage("%s(%s:%i): read failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ } else if (bytes == 0) {
+ break;
+ }
+ length += bytes;
+ }
+
+ buf[length] = '\0';
+ result = true;
+
+ fail:
+ close(fd);
+
+ return result;
+}
+
+int DynBuf::readlink(const char *const path) {
+ ssize_t bytes = MIN_BUFFER_FREE;
+
+ for (;;) {
+ if (static_cast<size_t>(bytes) >= capacity) {
+ const int err = resize(2 * bytes);
+ if (err != 0) {
+ return err;
+ }
+ }
+ bytes = ::readlink(path, buf, capacity);
+ if (bytes < 0) {
+ return -errno;
+ } else if (static_cast<size_t>(bytes) < capacity) {
+ break;
+ }
+ }
+
+ length = bytes;
+ buf[bytes] = '\0';
+
+ return 0;
+}
+
+bool DynBuf::printf(const char *format, ...) {
+ va_list ap;
+
+ if (capacity <= 0) {
+ if (resize(2 * MIN_BUFFER_FREE) != 0) {
+ logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ }
+
+ va_start(ap, format);
+ int bytes = vsnprintf(buf, capacity, format, ap);
+ va_end(ap);
+ if (bytes < 0) {
+ logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ if (static_cast<size_t>(bytes) > capacity) {
+ if (resize(bytes + 1) != 0) {
+ logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ va_start(ap, format);
+ bytes = vsnprintf(buf, capacity, format, ap);
+ va_end(ap);
+ if (bytes < 0) {
+ logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ }
+
+ length = bytes;
+
+ return true;
+}
diff --git a/tools/gator/daemon/DynBuf.h b/tools/gator/daemon/DynBuf.h
new file mode 100644
index 000000000000..2f4554ab2e49
--- /dev/null
+++ b/tools/gator/daemon/DynBuf.h
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef DYNBUF_H
+#define DYNBUF_H
+
+#include <stdlib.h>
+
+class DynBuf {
+public:
+ DynBuf() : capacity(0), length(0), buf(NULL) {}
+ ~DynBuf() {
+ reset();
+ }
+
+ inline void reset() {
+ capacity = 0;
+ length = 0;
+ if (buf != NULL) {
+ free(buf);
+ buf = NULL;
+ }
+ }
+
+ bool read(const char *const path);
+ // On error instead of printing the error and returning false, this returns -errno
+ int readlink(const char *const path);
+ __attribute__ ((format(printf, 2, 3)))
+ bool printf(const char *format, ...);
+
+ size_t getLength() const { return length; }
+ const char *getBuf() const { return buf; }
+ char *getBuf() { return buf; }
+
+private:
+ int resize(const size_t minCapacity);
+
+ size_t capacity;
+ size_t length;
+ char *buf;
+
+ // Intentionally undefined
+ DynBuf(const DynBuf &);
+ DynBuf &operator=(const DynBuf &);
+};
+
+#endif // DYNBUF_H
diff --git a/tools/gator/daemon/EventsXML.cpp b/tools/gator/daemon/EventsXML.cpp
index 2a80482e0b8d..a07a046f3353 100644
--- a/tools/gator/daemon/EventsXML.cpp
+++ b/tools/gator/daemon/EventsXML.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
@@ -35,7 +35,7 @@ char* EventsXML::getXML() {
fclose(fl);
} else {
logg->logMessage("Unable to locate events.xml, using default");
- xml = mxmlLoadString(NULL, (char *)events_xml, MXML_NO_CALLBACK);
+ xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK);
}
// Add dynamic events from the drivers
diff --git a/tools/gator/daemon/EventsXML.h b/tools/gator/daemon/EventsXML.h
index 8e693efab202..6cd1560f7d4e 100644
--- a/tools/gator/daemon/EventsXML.h
+++ b/tools/gator/daemon/EventsXML.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
diff --git a/tools/gator/daemon/ExternalSource.cpp b/tools/gator/daemon/ExternalSource.cpp
new file mode 100644
index 000000000000..fe5824b04812
--- /dev/null
+++ b/tools/gator/daemon/ExternalSource.cpp
@@ -0,0 +1,56 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include "ExternalSource.h"
+
+#include <sys/prctl.h>
+
+#include "Logging.h"
+#include "OlySocket.h"
+#include "SessionData.h"
+
+ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 1024, senderSem), mSock("/tmp/gator") {
+}
+
+ExternalSource::~ExternalSource() {
+}
+
+bool ExternalSource::prepare() {
+ return true;
+}
+
+void ExternalSource::run() {
+ prctl(PR_SET_NAME, (unsigned long)&"gatord-uds", 0, 0, 0);
+
+ while (gSessionData->mSessionIsActive) {
+ // Will be aborted when the socket is closed at the end of the capture
+ int length = mSock.receive(mBuffer.getWritePos(), mBuffer.contiguousSpaceAvailable());
+ if (length <= 0) {
+ break;
+ }
+
+ mBuffer.advanceWrite(length);
+ mBuffer.check(0);
+ }
+
+ mBuffer.setDone();
+}
+
+void ExternalSource::interrupt() {
+ // Do nothing
+}
+
+bool ExternalSource::isDone() {
+ return mBuffer.isDone();
+}
+
+void ExternalSource::write(Sender *sender) {
+ if (!mBuffer.isDone()) {
+ mBuffer.write(sender);
+ }
+}
diff --git a/tools/gator/daemon/ExternalSource.h b/tools/gator/daemon/ExternalSource.h
new file mode 100644
index 000000000000..2052bdf2823e
--- /dev/null
+++ b/tools/gator/daemon/ExternalSource.h
@@ -0,0 +1,40 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef EXTERNALSOURCE_H
+#define EXTERNALSOURCE_H
+
+#include <semaphore.h>
+
+#include "Buffer.h"
+#include "OlySocket.h"
+#include "Source.h"
+
+// Unix domain socket counters from external sources like graphics drivers
+class ExternalSource : public Source {
+public:
+ ExternalSource(sem_t *senderSem);
+ ~ExternalSource();
+
+ bool prepare();
+ void run();
+ void interrupt();
+
+ bool isDone();
+ void write(Sender *sender);
+
+private:
+ Buffer mBuffer;
+ OlySocket mSock;
+
+ // Intentionally unimplemented
+ ExternalSource(const ExternalSource &);
+ ExternalSource &operator=(const ExternalSource &);
+};
+
+#endif // EXTERNALSOURCE_H
diff --git a/tools/gator/daemon/Fifo.cpp b/tools/gator/daemon/Fifo.cpp
index 250a4d023bf2..f672e92a6807 100644
--- a/tools/gator/daemon/Fifo.cpp
+++ b/tools/gator/daemon/Fifo.cpp
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/tools/gator/daemon/Fifo.h b/tools/gator/daemon/Fifo.h
index d25cd6882561..7dd7426132d8 100644
--- a/tools/gator/daemon/Fifo.h
+++ b/tools/gator/daemon/Fifo.h
@@ -1,5 +1,5 @@
/**
- * 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
@@ -12,7 +12,7 @@
#ifdef WIN32
#include <windows.h>
#define sem_t HANDLE
-#define sem_init(sem, pshared, value) ((*(sem) = CreateSemaphore(NULL, value, INFINITE, NULL)) == NULL)
+#define sem_init(sem, pshared, value) ((*(sem) = CreateSemaphore(NULL, value, LONG_MAX, NULL)) == NULL)
#define sem_wait(sem) WaitForSingleObject(*(sem), INFINITE)
#define sem_post(sem) ReleaseSemaphore(*(sem), 1, NULL)
#define sem_destroy(sem) CloseHandle(*(sem))
diff --git a/tools/gator/daemon/Hwmon.cpp b/tools/gator/daemon/Hwmon.cpp
index 1d7c0da9cc83..778f30755dfe 100644
--- a/tools/gator/daemon/Hwmon.cpp
+++ b/tools/gator/daemon/Hwmon.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
@@ -17,7 +17,7 @@
class HwmonCounter {
public:
- HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature);
+ HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature);
~HwmonCounter();
HwmonCounter *getNext() const { return next; }
@@ -69,7 +69,7 @@ private:
HwmonCounter &operator=(const HwmonCounter &);
};
-HwmonCounter::HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(key), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) {
+HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(getEventKey()), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) {
int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
char *chip_name = new char[len];
@@ -205,6 +205,23 @@ bool HwmonCounter::canRead() {
}
Hwmon::Hwmon() : counters(NULL) {
+}
+
+Hwmon::~Hwmon() {
+ while (counters != NULL) {
+ HwmonCounter * counter = counters;
+ counters = counter->getNext();
+ delete counter;
+ }
+ sensors_cleanup();
+}
+
+void Hwmon::setup() {
+ // hwmon does not currently work with perf
+ if (gSessionData->perf.isSetup()) {
+ return;
+ }
+
int err = sensors_init(NULL);
if (err) {
logg->logMessage("Failed to initialize libsensors! (%d)", err);
@@ -218,20 +235,11 @@ Hwmon::Hwmon() : counters(NULL) {
int feature_nr = 0;
const sensors_feature *feature;
while ((feature = sensors_get_features(chip, &feature_nr))) {
- counters = new HwmonCounter(counters, getEventKey(), chip, feature);
+ counters = new HwmonCounter(counters, chip, feature);
}
}
}
-Hwmon::~Hwmon() {
- while (counters != NULL) {
- HwmonCounter * counter = counters;
- counters = counter->getNext();
- delete counter;
- }
- sensors_cleanup();
-}
-
HwmonCounter *Hwmon::findCounter(const Counter &counter) const {
for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) {
if (hwmonCounter->canRead() && strcmp(hwmonCounter->getName(), counter.getType()) == 0) {
@@ -271,14 +279,18 @@ void Hwmon::setupCounter(Counter &counter) {
counter.setKey(hwmonCounter->getKey());
}
-void Hwmon::writeCounters(mxml_node_t *root) const {
+int Hwmon::writeCounters(mxml_node_t *root) const {
+ int count = 0;
for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
if (!counter->canRead()) {
continue;
}
mxml_node_t *node = mxmlNewElement(root, "counter");
mxmlElementSetAttr(node, "name", counter->getName());
+ ++count;
}
+
+ return count;
}
void Hwmon::writeEvents(mxml_node_t *root) const {
diff --git a/tools/gator/daemon/Hwmon.h b/tools/gator/daemon/Hwmon.h
index 46bb42e898d7..a22a3609f99f 100644
--- a/tools/gator/daemon/Hwmon.h
+++ b/tools/gator/daemon/Hwmon.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
@@ -19,12 +19,14 @@ public:
Hwmon();
~Hwmon();
+ void setup();
+
bool claimCounter(const Counter &counter) const;
bool countersEnabled() const;
void resetCounters();
void setupCounter(Counter &counter);
- void writeCounters(mxml_node_t *root) const;
+ int writeCounters(mxml_node_t *root) const;
void writeEvents(mxml_node_t *root) const;
void start();
diff --git a/tools/gator/daemon/KMod.cpp b/tools/gator/daemon/KMod.cpp
index 559297fe2274..9300002f3fb2 100644
--- a/tools/gator/daemon/KMod.cpp
+++ b/tools/gator/daemon/KMod.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
@@ -12,9 +12,9 @@
#include <dirent.h>
#include <unistd.h>
-#include "Collector.h"
#include "ConfigurationXML.h"
#include "Counter.h"
+#include "DriverSource.h"
#include "Logging.h"
// Claim all the counters in /dev/gator/events
@@ -38,9 +38,9 @@ void KMod::resetCounters() {
continue;
snprintf(base, sizeof(base), "/dev/gator/events/%s", ent->d_name);
snprintf(text, sizeof(text), "%s/enabled", base);
- Collector::writeDriver(text, 0);
+ DriverSource::writeDriver(text, 0);
snprintf(text, sizeof(text), "%s/count", base);
- Collector::writeDriver(text, 0);
+ DriverSource::writeDriver(text, 0);
}
closedir(dir);
}
@@ -53,22 +53,22 @@ void KMod::setupCounter(Counter &counter) {
snprintf(text, sizeof(text), "%s/enabled", base);
int enabled = true;
- if (Collector::writeReadDriver(text, &enabled) || !enabled) {
+ if (DriverSource::writeReadDriver(text, &enabled) || !enabled) {
counter.setEnabled(false);
return;
}
snprintf(text, sizeof(text), "%s/key", base);
int key = 0;
- Collector::readIntDriver(text, &key);
+ DriverSource::readIntDriver(text, &key);
counter.setKey(key);
snprintf(text, sizeof(text), "%s/event", base);
- Collector::writeDriver(text, counter.getEvent());
+ DriverSource::writeDriver(text, counter.getEvent());
snprintf(text, sizeof(text), "%s/count", base);
if (access(text, F_OK) == 0) {
int count = counter.getCount();
- if (Collector::writeReadDriver(text, &count) && counter.getCount() > 0) {
+ if (DriverSource::writeReadDriver(text, &count) && counter.getCount() > 0) {
logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount());
handleException();
}
@@ -80,23 +80,26 @@ void KMod::setupCounter(Counter &counter) {
}
}
-void KMod::writeCounters(mxml_node_t *root) const {
+int KMod::writeCounters(mxml_node_t *root) const {
struct dirent *ent;
mxml_node_t *counter;
// counters.xml is simply a file listing of /dev/gator/events
DIR* dir = opendir("/dev/gator/events");
if (dir == NULL) {
- logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events");
- handleException();
+ return 0;
}
+ int count = 0;
while ((ent = readdir(dir)) != NULL) {
// skip hidden files, current dir, and parent dir
if (ent->d_name[0] == '.')
continue;
counter = mxmlNewElement(root, "counter");
mxmlElementSetAttr(counter, "name", ent->d_name);
+ ++count;
}
closedir(dir);
+
+ return count;
}
diff --git a/tools/gator/daemon/KMod.h b/tools/gator/daemon/KMod.h
index 797426290dfc..fb7fc8a8f9c6 100644
--- a/tools/gator/daemon/KMod.h
+++ b/tools/gator/daemon/KMod.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * Copyright (C) ARM Limited 2013-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
@@ -21,7 +21,7 @@ public:
void resetCounters();
void setupCounter(Counter &counter);
- void writeCounters(mxml_node_t *root) const;
+ int writeCounters(mxml_node_t *root) const;
};
#endif // KMOD_H
diff --git a/tools/gator/daemon/LocalCapture.cpp b/tools/gator/daemon/LocalCapture.cpp
index 3235a34ae9c7..d2a4b799d7ac 100644
--- a/tools/gator/daemon/LocalCapture.cpp
+++ b/tools/gator/daemon/LocalCapture.cpp
@@ -1,18 +1,20 @@
/**
- * 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
* published by the Free Software Foundation.
*/
+#include "LocalCapture.h"
+
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
-#include "LocalCapture.h"
+
#include "SessionData.h"
#include "Logging.h"
#include "OlyUtility.h"
diff --git a/tools/gator/daemon/LocalCapture.h b/tools/gator/daemon/LocalCapture.h
index 8042d6a8dc37..aadeccecf0cc 100644
--- a/tools/gator/daemon/LocalCapture.h
+++ b/tools/gator/daemon/LocalCapture.h
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/tools/gator/daemon/Logging.cpp b/tools/gator/daemon/Logging.cpp
index 5fd45b54f90a..b8d3178950d6 100644
--- a/tools/gator/daemon/Logging.cpp
+++ b/tools/gator/daemon/Logging.cpp
@@ -1,11 +1,13 @@
/**
- * 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
* published by the Free Software Foundation.
*/
+#include "Logging.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -23,8 +25,6 @@
#define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex)
#endif
-#include "Logging.h"
-
// Global thread-safe logging
Logging* logg = NULL;
diff --git a/tools/gator/daemon/Logging.h b/tools/gator/daemon/Logging.h
index 8f960de27bf3..6ae328046989 100644
--- a/tools/gator/daemon/Logging.h
+++ b/tools/gator/daemon/Logging.h
@@ -1,5 +1,5 @@
/**
- * 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
@@ -9,14 +9,7 @@
#ifndef __LOGGING_H__
#define __LOGGING_H__
-#include <stdio.h>
-#include <string.h>
-#include <limits.h>
-#ifdef WIN32
-#include <windows.h>
-#else
#include <pthread.h>
-#endif
#define DRIVER_ERROR "\n Driver issue:\n >> gator.ko must be built against the current kernel version & configuration\n >> gator.ko should be co-located with gatord in the same directory\n >> OR insmod gator.ko prior to launching gatord"
@@ -33,11 +26,7 @@ private:
char mErrBuf[4096]; // Arbitrarily large buffer to hold a string
char mLogBuf[4096]; // Arbitrarily large buffer to hold a string
bool mDebug;
-#ifdef WIN32
- HANDLE mLoggingMutex;
-#else
pthread_mutex_t mLoggingMutex;
-#endif
};
extern Logging* logg;
diff --git a/tools/gator/daemon/Monitor.cpp b/tools/gator/daemon/Monitor.cpp
new file mode 100644
index 000000000000..90d5c47706c7
--- /dev/null
+++ b/tools/gator/daemon/Monitor.cpp
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#include "Monitor.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "Logging.h"
+
+Monitor::Monitor() : mFd(-1) {
+}
+
+Monitor::~Monitor() {
+ if (mFd >= -1) {
+ close(mFd);
+ }
+}
+
+bool Monitor::init() {
+ mFd = epoll_create(16);
+ if (mFd < 0) {
+ logg->logMessage("%s(%s:%i): epoll_create1 failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ return true;
+}
+
+bool Monitor::add(const int fd) {
+ struct epoll_event event;
+ memset(&event, 0, sizeof(event));
+ event.data.fd = fd;
+ event.events = EPOLLIN;
+ if (epoll_ctl(mFd, EPOLL_CTL_ADD, fd, &event) != 0) {
+ logg->logMessage("%s(%s:%i): epoll_ctl failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ return true;
+}
+
+int Monitor::wait(struct epoll_event *const events, int maxevents, int timeout) {
+ int result = epoll_wait(mFd, events, maxevents, timeout);
+ if (result < 0) {
+ // Ignore if the call was interrupted as this will happen when SIGINT is received
+ if (errno == EINTR) {
+ result = 0;
+ } else {
+ logg->logMessage("%s(%s:%i): epoll_wait failed", __FUNCTION__, __FILE__, __LINE__);
+ }
+ }
+
+ return result;
+}
diff --git a/tools/gator/daemon/Monitor.h b/tools/gator/daemon/Monitor.h
new file mode 100644
index 000000000000..6e268b6e1bed
--- /dev/null
+++ b/tools/gator/daemon/Monitor.h
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MONITOR_H
+#define MONITOR_H
+
+#include <sys/epoll.h>
+
+class Monitor {
+public:
+ Monitor();
+ ~Monitor();
+
+ bool init();
+ bool add(const int fd);
+ int wait(struct epoll_event *const events, int maxevents, int timeout);
+
+private:
+
+ int mFd;
+
+ // Intentionally unimplemented
+ Monitor(const Monitor &);
+ Monitor &operator=(const Monitor &);
+};
+
+#endif // MONITOR_H
diff --git a/tools/gator/daemon/OlySocket.cpp b/tools/gator/daemon/OlySocket.cpp
index ab5c3c2c8938..26e4768f3934 100644
--- a/tools/gator/daemon/OlySocket.cpp
+++ b/tools/gator/daemon/OlySocket.cpp
@@ -1,5 +1,5 @@
/**
- * 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
@@ -15,6 +15,7 @@
#else
#include <netinet/in.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <unistd.h>
#include <netdb.h>
#endif
@@ -30,7 +31,7 @@
#define SHUTDOWN_RX_TX SHUT_RDWR
#endif
-OlySocket::OlySocket(int port, bool multiple) {
+OlyServerSocket::OlyServerSocket(int port) {
#ifdef WIN32
WSADATA wsaData;
if (WSAStartup(0x0202, &wsaData) != 0) {
@@ -39,24 +40,82 @@ OlySocket::OlySocket(int port, bool multiple) {
}
#endif
- if (multiple) {
- createServerSocket(port);
- } else {
- createSingleServerConnection(port);
- }
+ createServerSocket(port);
}
-OlySocket::OlySocket(int port, char* host) {
- mFDServer = 0;
+OlySocket::OlySocket(int port, const char* host) {
createClientSocket(host, port);
}
+OlySocket::OlySocket(int socketID) : mSocketID(socketID) {
+}
+
+#ifndef WIN32
+
+OlyServerSocket::OlyServerSocket(const char* path) {
+ // Create socket
+ mFDServer = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (mFDServer < 0) {
+ logg->logError(__FILE__, __LINE__, "Error creating server socket");
+ handleException();
+ }
+
+ unlink(path);
+
+ // Create sockaddr_in structure, ensuring non-populated fields are zero
+ struct sockaddr_un sockaddr;
+ memset((void*)&sockaddr, 0, sizeof(sockaddr));
+ sockaddr.sun_family = AF_UNIX;
+ strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
+ sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
+
+ // Bind the socket to an address
+ if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
+ logg->logError(__FILE__, __LINE__, "Binding of server socket failed.");
+ handleException();
+ }
+
+ // Listen for connections on this socket
+ if (listen(mFDServer, 1) < 0) {
+ logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
+ handleException();
+ }
+}
+
+OlySocket::OlySocket(const char* path) {
+ mSocketID = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (mSocketID < 0) {
+ return;
+ }
+
+ // Create sockaddr_in structure, ensuring non-populated fields are zero
+ struct sockaddr_un sockaddr;
+ memset((void*)&sockaddr, 0, sizeof(sockaddr));
+ sockaddr.sun_family = AF_UNIX;
+ strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
+ sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
+
+ if (connect(mSocketID, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
+ close(mSocketID);
+ mSocketID = -1;
+ return;
+ }
+}
+
+#endif
+
OlySocket::~OlySocket() {
if (mSocketID > 0) {
CLOSE_SOCKET(mSocketID);
}
}
+OlyServerSocket::~OlyServerSocket() {
+ if (mFDServer > 0) {
+ CLOSE_SOCKET(mFDServer);
+ }
+}
+
void OlySocket::shutdownConnection() {
// Shutdown is primarily used to unblock other threads that are blocking on send/receive functions
shutdown(mSocketID, SHUTDOWN_RX_TX);
@@ -70,7 +129,7 @@ void OlySocket::closeSocket() {
}
}
-void OlySocket::closeServerSocket() {
+void OlyServerSocket::closeServerSocket() {
if (CLOSE_SOCKET(mFDServer) != 0) {
logg->logError(__FILE__, __LINE__, "Failed to close server socket.");
handleException();
@@ -78,7 +137,7 @@ void OlySocket::closeServerSocket() {
mFDServer = 0;
}
-void OlySocket::createClientSocket(char* hostname, int portno) {
+void OlySocket::createClientSocket(const char* hostname, int portno) {
#ifdef WIN32
// TODO: Implement for Windows
#else
@@ -119,14 +178,7 @@ void OlySocket::createClientSocket(char* hostname, int portno) {
#endif
}
-void OlySocket::createSingleServerConnection(int port) {
- createServerSocket(port);
-
- mSocketID = acceptConnection();
- closeServerSocket();
-}
-
-void OlySocket::createServerSocket(int port) {
+void OlyServerSocket::createServerSocket(int port) {
int family = AF_INET6;
// Create socket
@@ -169,22 +221,23 @@ void OlySocket::createServerSocket(int port) {
// mSocketID is always set to the most recently accepted connection
// The user of this class should maintain the different socket connections, e.g. by forking the process
-int OlySocket::acceptConnection() {
+int OlyServerSocket::acceptConnection() {
+ int socketID;
if (mFDServer <= 0) {
logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
handleException();
}
// Accept a connection, note that this call blocks until a client connects
- mSocketID = accept(mFDServer, NULL, NULL);
- if (mSocketID < 0) {
+ socketID = accept(mFDServer, NULL, NULL);
+ if (socketID < 0) {
logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
handleException();
}
- return mSocketID;
+ return socketID;
}
-void OlySocket::send(char* buffer, int size) {
+void OlySocket::send(const char* buffer, int size) {
if (size <= 0 || buffer == NULL) {
return;
}
diff --git a/tools/gator/daemon/OlySocket.h b/tools/gator/daemon/OlySocket.h
index 5bab7d1f4cc4..eab786b304bf 100644
--- a/tools/gator/daemon/OlySocket.h
+++ b/tools/gator/daemon/OlySocket.h
@@ -1,5 +1,5 @@
/**
- * 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
@@ -9,27 +9,44 @@
#ifndef __OLY_SOCKET_H__
#define __OLY_SOCKET_H__
-#include <string.h>
-
class OlySocket {
public:
- OlySocket(int port, bool multipleConnections = false);
- OlySocket(int port, char* hostname);
+ OlySocket(int port, const char* hostname);
+ OlySocket(int socketID);
+#ifndef WIN32
+ OlySocket(const char* path);
+#endif
~OlySocket();
- int acceptConnection();
+
void closeSocket();
- void closeServerSocket();
void shutdownConnection();
- void send(char* buffer, int size);
- void sendString(const char* string) {send((char*)string, strlen(string));}
+ void send(const char* buffer, int size);
int receive(char* buffer, int size);
int receiveNBytes(char* buffer, int size);
int receiveString(char* buffer, int size);
- int getSocketID() {return mSocketID;}
+
+ bool isValid() const { return mSocketID >= 0; }
+
+private:
+ int mSocketID;
+
+ void createClientSocket(const char* hostname, int port);
+};
+
+class OlyServerSocket {
+public:
+ OlyServerSocket(int port);
+#ifndef WIN32
+ OlyServerSocket(const char* path);
+#endif
+ ~OlyServerSocket();
+
+ int acceptConnection();
+ void closeServerSocket();
+
private:
- int mSocketID, mFDServer;
- void createClientSocket(char* hostname, int port);
- void createSingleServerConnection(int port);
+ int mFDServer;
+
void createServerSocket(int port);
};
diff --git a/tools/gator/daemon/OlyUtility.cpp b/tools/gator/daemon/OlyUtility.cpp
index 0b22d6ebd027..45340a27d9fa 100644
--- a/tools/gator/daemon/OlyUtility.cpp
+++ b/tools/gator/daemon/OlyUtility.cpp
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/tools/gator/daemon/OlyUtility.h b/tools/gator/daemon/OlyUtility.h
index abab0a510a7c..1d26beb596fa 100644
--- a/tools/gator/daemon/OlyUtility.h
+++ b/tools/gator/daemon/OlyUtility.h
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/tools/gator/daemon/PerfBuffer.cpp b/tools/gator/daemon/PerfBuffer.cpp
new file mode 100644
index 000000000000..5fad583f7bd0
--- /dev/null
+++ b/tools/gator/daemon/PerfBuffer.cpp
@@ -0,0 +1,139 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#include "PerfBuffer.h"
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include "Buffer.h"
+#include "Logging.h"
+#include "Sender.h"
+#include "SessionData.h"
+
+PerfBuffer::PerfBuffer() {
+ for (int cpu = 0; cpu < ARRAY_LENGTH(mBuf); ++cpu) {
+ mBuf[cpu] = MAP_FAILED;
+ mDiscard[cpu] = false;
+ }
+}
+
+PerfBuffer::~PerfBuffer() {
+ for (int cpu = ARRAY_LENGTH(mBuf) - 1; cpu >= 0; --cpu) {
+ if (mBuf[cpu] != MAP_FAILED) {
+ munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
+ }
+ }
+}
+
+bool PerfBuffer::useFd(const int cpu, const int fd, const int groupFd) {
+ if (fd == groupFd) {
+ if (mBuf[cpu] != MAP_FAILED) {
+ logg->logMessage("%s(%s:%i): cpu %i already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__, cpu);
+ return false;
+ }
+
+ // The buffer isn't mapped yet
+ mBuf[cpu] = mmap(NULL, gSessionData->mPageSize + BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (mBuf[cpu] == MAP_FAILED) {
+ logg->logMessage("%s(%s:%i): mmap failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ // Check the version
+ struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
+ if (pemp->compat_version != 0) {
+ logg->logMessage("%s(%s:%i): Incompatible perf_event_mmap_page compat_version", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ } else {
+ if (mBuf[cpu] == MAP_FAILED) {
+ logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, groupFd) < 0) {
+ logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void PerfBuffer::discard(const int cpu) {
+ if (mBuf[cpu] != MAP_FAILED) {
+ mDiscard[cpu] = true;
+ }
+}
+
+bool PerfBuffer::isEmpty() {
+ for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+ if (mBuf[cpu] != MAP_FAILED) {
+ // Take a snapshot of the positions
+ struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
+ const __u64 head = pemp->data_head;
+ const __u64 tail = pemp->data_tail;
+
+ if (head != tail) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool PerfBuffer::send(Sender *const sender) {
+ for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+ if (mBuf[cpu] == MAP_FAILED) {
+ continue;
+ }
+
+ // Take a snapshot of the positions
+ struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
+ const __u64 head = pemp->data_head;
+ const __u64 tail = pemp->data_tail;
+
+ if (head > tail) {
+ const uint8_t *const b = static_cast<uint8_t *>(mBuf[cpu]) + gSessionData->mPageSize;
+ const int offset = gSessionData->mLocalCapture ? 1 : 0;
+ unsigned char header[7];
+ header[0] = RESPONSE_APC_DATA;
+ Buffer::writeLEInt(header + 1, head - tail + sizeof(header) - 5);
+ // Should use real packing functions
+ header[5] = FRAME_PERF;
+ header[6] = cpu;
+
+ // Write header
+ sender->writeData(reinterpret_cast<const char *>(&header) + offset, sizeof(header) - offset, RESPONSE_APC_DATA);
+
+ // Write data
+ if ((head & ~BUF_MASK) == (tail & ~BUF_MASK)) {
+ // Not wrapped
+ sender->writeData(reinterpret_cast<const char *>(b + (tail & BUF_MASK)), head - tail, RESPONSE_APC_DATA);
+ } else {
+ // Wrapped
+ sender->writeData(reinterpret_cast<const char *>(b + (tail & BUF_MASK)), BUF_SIZE - (tail & BUF_MASK), RESPONSE_APC_DATA);
+ sender->writeData(reinterpret_cast<const char *>(b), head & BUF_MASK, RESPONSE_APC_DATA);
+ }
+
+ // Update tail with the data read
+ pemp->data_tail = head;
+ }
+
+ if (mDiscard[cpu]) {
+ munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
+ mBuf[cpu] = MAP_FAILED;
+ mDiscard[cpu] = false;
+ logg->logMessage("%s(%s:%i): Unmaped cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
+ }
+ }
+
+ return true;
+}
diff --git a/tools/gator/daemon/PerfBuffer.h b/tools/gator/daemon/PerfBuffer.h
new file mode 100644
index 000000000000..278a3b9d6db7
--- /dev/null
+++ b/tools/gator/daemon/PerfBuffer.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef PERF_BUFFER
+#define PERF_BUFFER
+
+#include "Config.h"
+
+#define BUF_SIZE (gSessionData->mTotalBufferSize * 1024 * 1024)
+#define BUF_MASK (BUF_SIZE - 1)
+
+class Sender;
+
+class PerfBuffer {
+public:
+ PerfBuffer();
+ ~PerfBuffer();
+
+ bool useFd(const int cpu, const int fd, const int groupFd);
+ void discard(const int cpu);
+ bool isEmpty();
+ bool send(Sender *const sender);
+
+private:
+ void *mBuf[NR_CPUS];
+ // After the buffer is flushed it should be unmaped
+ bool mDiscard[NR_CPUS];
+
+ // Intentionally undefined
+ PerfBuffer(const PerfBuffer &);
+ PerfBuffer &operator=(const PerfBuffer &);
+};
+
+#endif // PERF_BUFFER
diff --git a/tools/gator/daemon/PerfDriver.cpp b/tools/gator/daemon/PerfDriver.cpp
new file mode 100644
index 000000000000..8e25c22f6798
--- /dev/null
+++ b/tools/gator/daemon/PerfDriver.cpp
@@ -0,0 +1,355 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#include "PerfDriver.h"
+
+#include <dirent.h>
+#include <sys/utsname.h>
+#include <time.h>
+
+#include "Buffer.h"
+#include "Config.h"
+#include "ConfigurationXML.h"
+#include "Counter.h"
+#include "DriverSource.h"
+#include "DynBuf.h"
+#include "Logging.h"
+#include "PerfGroup.h"
+#include "SessionData.h"
+
+#define PERF_DEVICES "/sys/bus/event_source/devices"
+
+#define TYPE_DERIVED ~0U
+
+// From gator.h
+struct gator_cpu {
+ const int cpuid;
+ // Human readable name
+ const char core_name[32];
+ // gatorfs event and Perf PMU name
+ const char *const pmnc_name;
+ const int pmnc_counters;
+};
+
+// From gator_main.c
+static const struct gator_cpu gator_cpus[] = {
+ { 0xb36, "ARM1136", "ARM_ARM11", 3 },
+ { 0xb56, "ARM1156", "ARM_ARM11", 3 },
+ { 0xb76, "ARM1176", "ARM_ARM11", 3 },
+ { 0xb02, "ARM11MPCore", "ARM_ARM11MPCore", 3 },
+ { 0xc05, "Cortex-A5", "ARMv7_Cortex_A5", 2 },
+ { 0xc07, "Cortex-A7", "ARMv7_Cortex_A7", 4 },
+ { 0xc08, "Cortex-A8", "ARMv7_Cortex_A8", 4 },
+ { 0xc09, "Cortex-A9", "ARMv7_Cortex_A9", 6 },
+ { 0xc0d, "Cortex-A12", "ARMv7_Cortex_A12", 6 },
+ { 0xc0f, "Cortex-A15", "ARMv7_Cortex_A15", 6 },
+ { 0xc0e, "Cortex-A17", "ARMv7_Cortex_A17", 6 },
+ { 0x00f, "Scorpion", "Scorpion", 4 },
+ { 0x02d, "ScorpionMP", "ScorpionMP", 4 },
+ { 0x049, "KraitSIM", "Krait", 4 },
+ { 0x04d, "Krait", "Krait", 4 },
+ { 0x06f, "Krait S4 Pro", "Krait", 4 },
+ { 0xd03, "Cortex-A53", "ARM_Cortex-A53", 6 },
+ { 0xd07, "Cortex-A57", "ARM_Cortex-A57", 6 },
+ { 0xd0f, "AArch64", "ARM_AArch64", 6 },
+};
+
+static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
+static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_";
+
+class PerfCounter {
+public:
+ PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false) {}
+ ~PerfCounter() {
+ delete [] mName;
+ }
+
+ PerfCounter *getNext() const { return mNext; }
+ const char *getName() const { return mName; }
+ uint32_t getType() const { return mType; }
+ int getCount() const { return mCount; }
+ void setCount(const int count) { mCount = count; }
+ int getKey() const { return mKey; }
+ uint64_t getConfig() const { return mConfig; }
+ void setConfig(const uint64_t config) { mConfig = config; }
+ bool isEnabled() const { return mEnabled; }
+ void setEnabled(const bool enabled) { mEnabled = enabled; }
+
+private:
+ PerfCounter *const mNext;
+ const char *const mName;
+ const uint32_t mType;
+ int mCount;
+ const int mKey;
+ uint64_t mConfig;
+ bool mEnabled;
+};
+
+PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false) {
+}
+
+PerfDriver::~PerfDriver() {
+ while (mCounters != NULL) {
+ PerfCounter *counter = mCounters;
+ mCounters = counter->getNext();
+ delete counter;
+ }
+}
+
+void PerfDriver::addCpuCounters(const char *const counterName, const int type, const int numCounters) {
+ int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
+ char *name = new char[len];
+ snprintf(name, len, "%s_ccnt", counterName);
+ mCounters = new PerfCounter(mCounters, name, type, -1);
+
+ for (int j = 0; j < numCounters; ++j) {
+ len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
+ name = new char[len];
+ snprintf(name, len, "%s_cnt%d", counterName, j);
+ mCounters = new PerfCounter(mCounters, name, type, -1);
+ }
+}
+
+// From include/generated/uapi/linux/version.h
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
+bool PerfDriver::setup() {
+ // Check the kernel version
+ struct utsname utsname;
+ if (uname(&utsname) != 0) {
+ logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ int release[3] = { 0, 0, 0 };
+ int part = 0;
+ char *ch = utsname.release;
+ while (*ch >= '0' && *ch <= '9' && part < ARRAY_LENGTH(release)) {
+ release[part] = 10*release[part] + *ch - '0';
+
+ ++ch;
+ if (*ch == '.') {
+ ++part;
+ ++ch;
+ }
+ }
+
+ if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0)) {
+ logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ // Add supported PMUs
+ bool foundCpu = false;
+ DIR *dir = opendir(PERF_DEVICES);
+ if (dir == NULL) {
+ logg->logMessage("%s(%s:%i): opendif failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ struct dirent *dirent;
+ while ((dirent = readdir(dir)) != NULL) {
+ for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
+ // Do the names match exactly?
+ if (strcmp(dirent->d_name, gator_cpus[i].pmnc_name) != 0 &&
+ // Do these names match but have the old vs new prefix?
+ (strncmp(dirent->d_name, OLD_PMU_PREFIX, sizeof(OLD_PMU_PREFIX) - 1) != 0 ||
+ strncmp(gator_cpus[i].pmnc_name, NEW_PMU_PREFIX, sizeof(NEW_PMU_PREFIX) - 1) != 0 ||
+ strcmp(dirent->d_name + sizeof(OLD_PMU_PREFIX) - 1, gator_cpus[i].pmnc_name + sizeof(NEW_PMU_PREFIX) - 1) != 0)) {
+ continue;
+ }
+
+ int type;
+ char buf[256];
+ snprintf(buf, sizeof(buf), PERF_DEVICES "/%s/type", dirent->d_name);
+ if (DriverSource::readIntDriver(buf, &type) != 0) {
+ continue;
+ }
+
+ foundCpu = true;
+ addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters);
+ }
+ }
+ closedir(dir);
+
+ if (!foundCpu) {
+ // If no cpu was found based on pmu names, try by cpuid
+ for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
+ if (gSessionData->mMaxCpuId != gator_cpus[i].cpuid) {
+ continue;
+ }
+
+ foundCpu = true;
+ addCpuCounters(gator_cpus[i].pmnc_name, PERF_TYPE_RAW, gator_cpus[i].pmnc_counters);
+ }
+ }
+
+ /*
+ if (!foundCpu) {
+ // If all else fails, use the perf architected counters
+ // 9 because that's how many are in events-Perf-Hardware.xml - assume they can all be enabled at once
+ addCpuCounters("Perf_Hardware", PERF_TYPE_HARDWARE, 9);
+ }
+ */
+
+ // Add supported software counters
+ long long id;
+ DynBuf printb;
+
+ id = getTracepointId("irq/softirq_exit", &printb);
+ if (id >= 0) {
+ mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id);
+ }
+
+ id = getTracepointId("irq/irq_handler_exit", &printb);
+ if (id >= 0) {
+ mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id);
+ }
+
+ //Linux_block_rq_wr
+ //Linux_block_rq_rd
+ //Linux_net_rx
+ //Linux_net_tx
+
+ id = getTracepointId(SCHED_SWITCH, &printb);
+ if (id >= 0) {
+ mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id);
+ }
+
+ //Linux_meminfo_memused
+ //Linux_meminfo_memfree
+ //Linux_meminfo_bufferram
+ //Linux_power_cpu_freq
+ //Linux_power_cpu_idle
+
+ mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1);
+
+ //Linux_cpu_wait_io
+
+ mIsSetup = true;
+ return true;
+}
+
+bool PerfDriver::summary(Buffer *const buffer) {
+ struct utsname utsname;
+ if (uname(&utsname) != 0) {
+ logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ char buf[512];
+ snprintf(buf, sizeof(buf), "%s %s %s %s %s GNU/Linux", utsname.sysname, utsname.nodename, utsname.release, utsname.version, utsname.machine);
+
+ struct timespec ts;
+ if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
+ logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ const int64_t timestamp = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
+ logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ const int64_t uptime = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec;
+
+ buffer->summary(timestamp, uptime, 0, buf);
+
+ for (int i = 0; i < gSessionData->mCores; ++i) {
+ int j;
+ for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) {
+ if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) {
+ break;
+ }
+ }
+ if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) {
+ buffer->coreName(i, gSessionData->mCpuIds[i], gator_cpus[j].core_name);
+ } else {
+ snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]);
+ buffer->coreName(i, gSessionData->mCpuIds[i], buf);
+ }
+ }
+ buffer->commit(1);
+
+ return true;
+}
+
+PerfCounter *PerfDriver::findCounter(const Counter &counter) const {
+ for (PerfCounter * perfCounter = mCounters; perfCounter != NULL; perfCounter = perfCounter->getNext()) {
+ if (strcmp(perfCounter->getName(), counter.getType()) == 0) {
+ return perfCounter;
+ }
+ }
+
+ return NULL;
+}
+
+bool PerfDriver::claimCounter(const Counter &counter) const {
+ return findCounter(counter) != NULL;
+}
+
+void PerfDriver::resetCounters() {
+ for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
+ counter->setEnabled(false);
+ }
+}
+
+void PerfDriver::setupCounter(Counter &counter) {
+ PerfCounter *const perfCounter = findCounter(counter);
+ if (perfCounter == NULL) {
+ counter.setEnabled(false);
+ return;
+ }
+
+ // Don't use the config from counters XML if it's not set, ex: software counters
+ if (counter.getEvent() != -1) {
+ perfCounter->setConfig(counter.getEvent());
+ }
+ perfCounter->setCount(counter.getCount());
+ perfCounter->setEnabled(true);
+ counter.setKey(perfCounter->getKey());
+}
+
+int PerfDriver::writeCounters(mxml_node_t *root) const {
+ int count = 0;
+ for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
+ mxml_node_t *node = mxmlNewElement(root, "counter");
+ mxmlElementSetAttr(node, "name", counter->getName());
+ ++count;
+ }
+
+ return count;
+}
+
+bool PerfDriver::enable(PerfGroup *group, Buffer *const buffer) const {
+ for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
+ if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
+ if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), 0, 0)) {
+ logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+long long PerfDriver::getTracepointId(const char *const name, DynBuf *const printb) {
+ if (!printb->printf(EVENTS_PATH "/%s/id", name)) {
+ logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ return -1;
+ }
+
+ int64_t result;
+ if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) {
+ logg->logMessage("%s(%s:%i): DriverSource::readInt64Driver failed", __FUNCTION__, __FILE__, __LINE__);
+ return -1;
+ }
+
+ return result;
+}
diff --git a/tools/gator/daemon/PerfDriver.h b/tools/gator/daemon/PerfDriver.h
new file mode 100644
index 000000000000..3181b74f5570
--- /dev/null
+++ b/tools/gator/daemon/PerfDriver.h
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef PERFDRIVER_H
+#define PERFDRIVER_H
+
+#include "Driver.h"
+
+// If debugfs is not mounted at /sys/kernel/debug, update DEBUGFS_PATH
+#define DEBUGFS_PATH "/sys/kernel/debug"
+#define EVENTS_PATH DEBUGFS_PATH "/tracing/events"
+
+#define SCHED_SWITCH "sched/sched_switch"
+
+class Buffer;
+class DynBuf;
+class PerfCounter;
+class PerfGroup;
+
+class PerfDriver : public Driver {
+public:
+ PerfDriver();
+ ~PerfDriver();
+
+ bool setup();
+ bool summary(Buffer *const buffer);
+ bool isSetup() const { return mIsSetup; }
+
+ bool claimCounter(const Counter &counter) const;
+ void resetCounters();
+ void setupCounter(Counter &counter);
+
+ int writeCounters(mxml_node_t *root) const;
+
+ bool enable(PerfGroup *group, Buffer *const buffer) const;
+
+ static long long getTracepointId(const char *const name, DynBuf *const printb);
+
+private:
+ PerfCounter *findCounter(const Counter &counter) const;
+ void addCpuCounters(const char *const counterName, const int type, const int numCounters);
+
+ PerfCounter *mCounters;
+ bool mIsSetup;
+
+ // Intentionally undefined
+ PerfDriver(const PerfDriver &);
+ PerfDriver &operator=(const PerfDriver &);
+};
+
+#endif // PERFDRIVER_H
diff --git a/tools/gator/daemon/PerfGroup.cpp b/tools/gator/daemon/PerfGroup.cpp
new file mode 100644
index 000000000000..faf5fcaf15e6
--- /dev/null
+++ b/tools/gator/daemon/PerfGroup.cpp
@@ -0,0 +1,206 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#include "PerfGroup.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "Buffer.h"
+#include "Logging.h"
+#include "Monitor.h"
+#include "PerfBuffer.h"
+#include "SessionData.h"
+
+#define DEFAULT_PEA_ARGS(pea, additionalSampleType) \
+ pea.size = sizeof(pea); \
+ /* Emit time, read_format below, group leader id, and raw tracepoint info */ \
+ pea.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER | additionalSampleType; \
+ /* Emit emit value in group format */ \
+ pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP; \
+ /* start out disabled */ \
+ pea.disabled = 1; \
+ /* have a sampling interrupt happen when we cross the wakeup_watermark boundary */ \
+ pea.watermark = 1; \
+ /* Be conservative in flush size as only one buffer set is monitored */ \
+ pea.wakeup_watermark = 3 * BUF_SIZE / 4
+
+static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t pid, const int cpu, const int group_fd, const unsigned long flags) {
+ return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
+}
+
+PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) {
+ memset(&mAttrs, 0, sizeof(mAttrs));
+ memset(&mKeys, -1, sizeof(mKeys));
+ memset(&mFds, -1, sizeof(mFds));
+}
+
+PerfGroup::~PerfGroup() {
+ for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
+ if (mFds[pos] >= 0) {
+ close(mFds[pos]);
+ }
+ }
+}
+
+bool PerfGroup::add(Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) {
+ int i;
+ for (i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+ if (mKeys[i] < 0) {
+ break;
+ }
+ }
+
+ if (i >= ARRAY_LENGTH(mKeys)) {
+ logg->logMessage("%s(%s:%i): Too many counters", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ DEFAULT_PEA_ARGS(mAttrs[i], sampleType);
+ mAttrs[i].type = type;
+ mAttrs[i].config = config;
+ mAttrs[i].sample_period = sample;
+ // always be on the CPU but only a group leader can be pinned
+ mAttrs[i].pinned = (i == 0 ? 1 : 0);
+ mAttrs[i].mmap = (flags & PERF_GROUP_MMAP ? 1 : 0);
+ mAttrs[i].comm = (flags & PERF_GROUP_COMM ? 1 : 0);
+ mAttrs[i].freq = (flags & PERF_GROUP_FREQ ? 1 : 0);
+ mAttrs[i].task = (flags & PERF_GROUP_TASK ? 1 : 0);
+ mAttrs[i].sample_id_all = (flags & PERF_GROUP_SAMPLE_ID_ALL ? 1 : 0);
+
+ mKeys[i] = key;
+
+ buffer->pea(&mAttrs[i], key);
+
+ return true;
+}
+
+bool PerfGroup::prepareCPU(const int cpu) {
+ logg->logMessage("%s(%s:%i): Onlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
+
+ for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+ if (mKeys[i] < 0) {
+ continue;
+ }
+
+ const int offset = i * gSessionData->mCores;
+ if (mFds[cpu + offset] >= 0) {
+ logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ logg->logMessage("%s(%s:%i): perf_event_open cpu: %i type: %lli config: %lli sample: %lli sample_type: %lli", __FUNCTION__, __FILE__, __LINE__, cpu, (long long)mAttrs[i].type, (long long)mAttrs[i].config, (long long)mAttrs[i].sample_period, (long long)mAttrs[i].sample_type);
+ mFds[cpu + offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, i == 0 ? -1 : mFds[cpu], i == 0 ? 0 : PERF_FLAG_FD_OUTPUT);
+ if (mFds[cpu + offset] < 0) {
+ logg->logMessage("%s(%s:%i): failed %s", __FUNCTION__, __FILE__, __LINE__, strerror(errno));
+ continue;
+ }
+
+ if (!mPb->useFd(cpu, mFds[cpu + offset], mFds[cpu])) {
+ logg->logMessage("%s(%s:%i): PerfBuffer::useFd failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor) {
+ __u64 ids[ARRAY_LENGTH(mKeys)];
+ int coreKeys[ARRAY_LENGTH(mKeys)];
+ int idCount = 0;
+
+ for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+ const int fd = mFds[cpu + i * gSessionData->mCores];
+ if (fd < 0) {
+ continue;
+ }
+
+ coreKeys[idCount] = mKeys[i];
+ if (ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0) {
+ logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ ++idCount;
+ }
+
+ if (!monitor->add(mFds[cpu])) {
+ logg->logMessage("%s(%s:%i): Monitor::add failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ buffer->keys(idCount, ids, coreKeys);
+
+ if (start) {
+ for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+ int offset = i * gSessionData->mCores + cpu;
+ if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_ENABLE) < 0) {
+ logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ }
+ }
+
+ return idCount;
+}
+
+bool PerfGroup::offlineCPU(const int cpu) {
+ logg->logMessage("%s(%s:%i): Offlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
+
+ for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+ int offset = i * gSessionData->mCores + cpu;
+ if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_DISABLE) < 0) {
+ logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ }
+
+ // Mark the buffer so that it will be released next time it's read
+ mPb->discard(cpu);
+
+ for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+ if (mKeys[i] < 0) {
+ continue;
+ }
+
+ int offset = i * gSessionData->mCores + cpu;
+ if (mFds[offset] >= 0) {
+ close(mFds[offset]);
+ mFds[offset] = -1;
+ }
+ }
+
+ return true;
+}
+
+bool PerfGroup::start() {
+ for (int pos = 0; pos < ARRAY_LENGTH(mFds); ++pos) {
+ if (mFds[pos] >= 0 && ioctl(mFds[pos], PERF_EVENT_IOC_ENABLE) < 0) {
+ logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+ }
+
+ return true;
+
+ fail:
+ stop();
+
+ return false;
+}
+
+void PerfGroup::stop() {
+ for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
+ if (mFds[pos] >= 0) {
+ ioctl(mFds[pos], PERF_EVENT_IOC_DISABLE);
+ }
+ }
+}
diff --git a/tools/gator/daemon/PerfGroup.h b/tools/gator/daemon/PerfGroup.h
new file mode 100644
index 000000000000..af496d41334c
--- /dev/null
+++ b/tools/gator/daemon/PerfGroup.h
@@ -0,0 +1,55 @@
+ /**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef PERF_GROUP
+#define PERF_GROUP
+
+// Use a snapshot of perf_event.h as it may be more recent than what is on the target and if not newer features won't be supported anyways
+#include "k/perf_event.h"
+
+#include "Config.h"
+
+class Buffer;
+class Monitor;
+class PerfBuffer;
+
+enum PerfGroupFlags {
+ PERF_GROUP_MMAP = 1 << 0,
+ PERF_GROUP_COMM = 1 << 1,
+ PERF_GROUP_FREQ = 1 << 2,
+ PERF_GROUP_TASK = 1 << 3,
+ PERF_GROUP_SAMPLE_ID_ALL = 1 << 4,
+};
+
+class PerfGroup {
+public:
+ PerfGroup(PerfBuffer *const pb);
+ ~PerfGroup();
+
+ bool add(Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags);
+ // Safe to call concurrently
+ bool prepareCPU(const int cpu);
+ // Not safe to call concurrently. Returns the number of events enabled
+ int onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor);
+ bool offlineCPU(int cpu);
+ bool start();
+ void stop();
+
+private:
+ // +1 for the group leader
+ struct perf_event_attr mAttrs[MAX_PERFORMANCE_COUNTERS + 1];
+ int mKeys[MAX_PERFORMANCE_COUNTERS + 1];
+ int mFds[NR_CPUS * (MAX_PERFORMANCE_COUNTERS + 1)];
+ PerfBuffer *const mPb;
+
+ // Intentionally undefined
+ PerfGroup(const PerfGroup &);
+ PerfGroup &operator=(const PerfGroup &);
+};
+
+#endif // PERF_GROUP
diff --git a/tools/gator/daemon/PerfSource.cpp b/tools/gator/daemon/PerfSource.cpp
new file mode 100644
index 000000000000..1f1cb1988f00
--- /dev/null
+++ b/tools/gator/daemon/PerfSource.cpp
@@ -0,0 +1,271 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include "PerfSource.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "Child.h"
+#include "DynBuf.h"
+#include "Logging.h"
+#include "PerfDriver.h"
+#include "Proc.h"
+#include "SessionData.h"
+
+#define MS_PER_US 1000000
+
+extern Child *child;
+
+static bool sendTracepointFormat(Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
+ if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
+ logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ if (!b->read(printb->getBuf())) {
+ logg->logMessage("%s(%s:%i): DynBuf::read failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ buffer->format(b->getLength(), b->getBuf());
+
+ return true;
+}
+
+PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(0, FRAME_PERF_ATTRS, 1024*1024, senderSem), mCountersBuf(), mCountersGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) {
+ long l = sysconf(_SC_PAGE_SIZE);
+ if (l < 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to obtain the page size");
+ handleException();
+ }
+ gSessionData->mPageSize = static_cast<int>(l);
+
+ l = sysconf(_SC_NPROCESSORS_CONF);
+ if (l < 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to obtain the number of cores");
+ handleException();
+ }
+ gSessionData->mCores = static_cast<int>(l);
+}
+
+PerfSource::~PerfSource() {
+}
+
+struct PrepareParallelArgs {
+ PerfGroup *pg;
+ int cpu;
+};
+
+void *prepareParallel(void *arg) {
+ const PrepareParallelArgs *const args = (PrepareParallelArgs *)arg;
+ args->pg->prepareCPU(args->cpu);
+ return NULL;
+}
+
+bool PerfSource::prepare() {
+ DynBuf printb;
+ DynBuf b1;
+ DynBuf b2;
+ DynBuf b3;
+ long long schedSwitchId;
+
+ if (0
+ || !mMonitor.init()
+ || !mUEvent.init()
+ || !mMonitor.add(mUEvent.getFd())
+
+ || (schedSwitchId = PerfDriver::getTracepointId(SCHED_SWITCH, &printb)) < 0
+ || !sendTracepointFormat(&mBuffer, SCHED_SWITCH, &printb, &b1)
+
+ // Only want RAW but not IP on sched_switch and don't want TID on SAMPLE_ID
+ || !mCountersGroup.add(&mBuffer, 100/**/, PERF_TYPE_TRACEPOINT, schedSwitchId, 1, PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL)
+
+ // Only want TID and IP but not RAW on timer
+ || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(&mBuffer, 99/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, 0))
+
+ || !gSessionData->perf.enable(&mCountersGroup, &mBuffer)
+ || 0) {
+ logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.12 or later?", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ if (!gSessionData->perf.summary(&mSummary)) {
+ logg->logMessage("%s(%s:%i): PerfDriver::summary failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ {
+ // Run prepareCPU in parallel as perf_event_open can take more than 1 sec in some cases
+ pthread_t threads[NR_CPUS];
+ PrepareParallelArgs args[NR_CPUS];
+ for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+ args[cpu].pg = &mCountersGroup;
+ args[cpu].cpu = cpu;
+ if (pthread_create(&threads[cpu], NULL, prepareParallel, &args[cpu]) != 0) {
+ logg->logMessage("%s(%s:%i): pthread_create failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ }
+ for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+ if (pthread_join(threads[cpu], NULL) != 0) {
+ logg->logMessage("%s(%s:%i): pthread_join failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ }
+ }
+
+ int numEvents = 0;
+ for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+ numEvents += mCountersGroup.onlineCPU(cpu, false, &mBuffer, &mMonitor);
+ }
+ if (numEvents <= 0) {
+ logg->logMessage("%s(%s:%i): PerfGroup::onlineCPU failed on all cores", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ // Start events before reading proc to avoid race conditions
+ if (!mCountersGroup.start()) {
+ logg->logMessage("%s(%s:%i): PerfGroup::start failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ if (!readProc(&mBuffer, &printb, &b1, &b2, &b3)) {
+ logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ mBuffer.commit(1);
+
+ return true;
+}
+
+static const char CPU_DEVPATH[] = "/devices/system/cpu/cpu";
+
+void PerfSource::run() {
+ int pipefd[2];
+
+ if (pipe(pipefd) != 0) {
+ logg->logError(__FILE__, __LINE__, "pipe failed");
+ handleException();
+ }
+ mInterruptFd = pipefd[1];
+
+ if (!mMonitor.add(pipefd[0])) {
+ logg->logError(__FILE__, __LINE__, "Monitor::add failed");
+ handleException();
+ }
+
+ int timeout = -1;
+ if (gSessionData->mLiveRate > 0) {
+ timeout = gSessionData->mLiveRate/MS_PER_US;
+ }
+
+ sem_post(mStartProfile);
+
+ while (gSessionData->mSessionIsActive) {
+ // +1 for uevents, +1 for pipe
+ struct epoll_event events[NR_CPUS + 2];
+ int ready = mMonitor.wait(events, ARRAY_LENGTH(events), timeout);
+ if (ready < 0) {
+ logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
+ handleException();
+ }
+
+ for (int i = 0; i < ready; ++i) {
+ if (events[i].data.fd == mUEvent.getFd()) {
+ if (!handleUEvent()) {
+ logg->logError(__FILE__, __LINE__, "PerfSource::handleUEvent failed");
+ handleException();
+ }
+ break;
+ }
+ }
+
+ // send a notification that data is ready
+ sem_post(mSenderSem);
+
+ // In one shot mode, stop collection once all the buffers are filled
+ // Assume timeout == 0 in this case
+ if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
+ logg->logMessage("%s(%s:%i): One shot", __FUNCTION__, __FILE__, __LINE__);
+ child->endSession();
+ }
+ }
+
+ mCountersGroup.stop();
+ mBuffer.setDone();
+ mIsDone = true;
+
+ // send a notification that data is ready
+ sem_post(mSenderSem);
+
+ mInterruptFd = -1;
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+bool PerfSource::handleUEvent() {
+ UEventResult result;
+ if (!mUEvent.read(&result)) {
+ logg->logMessage("%s(%s:%i): UEvent::Read failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ if (strcmp(result.mSubsystem, "cpu") == 0) {
+ if (strncmp(result.mDevPath, CPU_DEVPATH, sizeof(CPU_DEVPATH) - 1) != 0) {
+ logg->logMessage("%s(%s:%i): Unexpected cpu DEVPATH format", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ char *endptr;
+ errno = 0;
+ int cpu = strtol(result.mDevPath + sizeof(CPU_DEVPATH) - 1, &endptr, 10);
+ if (errno != 0 || *endptr != '\0') {
+ logg->logMessage("%s(%s:%i): strtol failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ if (strcmp(result.mAction, "online") == 0) {
+ // Only call onlineCPU if prepareCPU succeeded
+ const bool result = mCountersGroup.prepareCPU(cpu) &&
+ mCountersGroup.onlineCPU(cpu, true, &mBuffer, &mMonitor);
+ mBuffer.commit(1);
+ return result;
+ } else if (strcmp(result.mAction, "offline") == 0) {
+ return mCountersGroup.offlineCPU(cpu);
+ }
+ }
+
+ return true;
+}
+
+void PerfSource::interrupt() {
+ if (mInterruptFd >= 0) {
+ int8_t c = 0;
+ // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread
+ if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) {
+ logg->logError(__FILE__, __LINE__, "write failed");
+ handleException();
+ }
+ }
+}
+
+bool PerfSource::isDone () {
+ return mBuffer.isDone() && mIsDone && mCountersBuf.isEmpty();
+}
+
+void PerfSource::write (Sender *sender) {
+ if (!mSummary.isDone()) {
+ mSummary.write(sender);
+ }
+ if (!mBuffer.isDone()) {
+ mBuffer.write(sender);
+ }
+ if (!mCountersBuf.send(sender)) {
+ logg->logError(__FILE__, __LINE__, "PerfBuffer::send failed");
+ handleException();
+ }
+}
diff --git a/tools/gator/daemon/PerfSource.h b/tools/gator/daemon/PerfSource.h
new file mode 100644
index 000000000000..3f471c8de414
--- /dev/null
+++ b/tools/gator/daemon/PerfSource.h
@@ -0,0 +1,54 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef PERFSOURCE_H
+#define PERFSOURCE_H
+
+#include <semaphore.h>
+
+#include "Buffer.h"
+#include "Monitor.h"
+#include "PerfBuffer.h"
+#include "PerfGroup.h"
+#include "Source.h"
+#include "UEvent.h"
+
+class Sender;
+
+class PerfSource : public Source {
+public:
+ PerfSource(sem_t *senderSem, sem_t *startProfile);
+ ~PerfSource();
+
+ bool prepare();
+ void run();
+ void interrupt();
+
+ bool isDone();
+ void write(Sender *sender);
+
+private:
+ bool handleUEvent();
+
+ Buffer mSummary;
+ Buffer mBuffer;
+ PerfBuffer mCountersBuf;
+ PerfGroup mCountersGroup;
+ Monitor mMonitor;
+ UEvent mUEvent;
+ sem_t *const mSenderSem;
+ sem_t *const mStartProfile;
+ int mInterruptFd;
+ bool mIsDone;
+
+ // Intentionally undefined
+ PerfSource(const PerfSource &);
+ PerfSource &operator=(const PerfSource &);
+};
+
+#endif // PERFSOURCE_H
diff --git a/tools/gator/daemon/Proc.cpp b/tools/gator/daemon/Proc.cpp
new file mode 100644
index 000000000000..e0b9e2259cf9
--- /dev/null
+++ b/tools/gator/daemon/Proc.cpp
@@ -0,0 +1,179 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#include "Proc.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "Buffer.h"
+#include "DynBuf.h"
+#include "Logging.h"
+
+struct ProcStat {
+ // From linux-dev/include/linux/sched.h
+#define TASK_COMM_LEN 16
+ // TASK_COMM_LEN may grow, so be ready for it to get larger
+ char comm[2*TASK_COMM_LEN];
+ long numThreads;
+};
+
+static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf *const b) {
+ if (!b->read(pathname)) {
+ logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__);
+ // This is not a fatal error - the thread just doesn't exist any more
+ return true;
+ }
+
+ char *comm = strchr(b->getBuf(), '(');
+ if (comm == NULL) {
+ logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ ++comm;
+ char *const str = strrchr(comm, ')');
+ if (str == NULL) {
+ logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ *str = '\0';
+ strncpy(ps->comm, comm, sizeof(ps->comm) - 1);
+ ps->comm[sizeof(ps->comm) - 1] = '\0';
+
+ const int count = sscanf(str + 2, " %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %ld", &ps->numThreads);
+ if (count != 1) {
+ logg->logMessage("%s(%s:%i): sscanf failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ return true;
+}
+
+static bool readProcTask(Buffer *const buffer, const int pid, const char *const image, DynBuf *const printb, DynBuf *const b) {
+ bool result = false;
+
+ if (!b->printf("/proc/%i/task", pid)) {
+ logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ return result;
+ }
+ DIR *task = opendir(b->getBuf());
+ if (task == NULL) {
+ logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
+ return result;
+ }
+
+ struct dirent *dirent;
+ while ((dirent = readdir(task)) != NULL) {
+ char *endptr;
+ const int tid = strtol(dirent->d_name, &endptr, 10);
+ if (*endptr != '\0') {
+ // Ignore task items that are not integers like ., etc...
+ continue;
+ }
+
+ if (!printb->printf("/proc/%i/task/%i/stat", pid, tid)) {
+ logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+ ProcStat ps;
+ if (!readProcStat(&ps, printb->getBuf(), b)) {
+ logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+
+ buffer->comm(pid, tid, image, ps.comm);
+ }
+
+ result = true;
+
+ fail:
+ closedir(task);
+
+ return result;
+}
+
+bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) {
+ bool result = false;
+
+ DIR *proc = opendir("/proc");
+ if (proc == NULL) {
+ logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
+ return result;
+ }
+
+ struct dirent *dirent;
+ while ((dirent = readdir(proc)) != NULL) {
+ char *endptr;
+ const int pid = strtol(dirent->d_name, &endptr, 10);
+ if (*endptr != '\0') {
+ // Ignore proc items that are not integers like ., cpuinfo, etc...
+ continue;
+ }
+
+ if (!printb->printf("/proc/%i/stat", pid)) {
+ logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+ ProcStat ps;
+ if (!readProcStat(&ps, printb->getBuf(), b1)) {
+ logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+
+ if (!printb->printf("/proc/%i/exe", pid)) {
+ logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+ const int err = b1->readlink(printb->getBuf());
+ const char *image;
+ if (err == 0) {
+ image = strrchr(b1->getBuf(), '/');
+ if (image == NULL) {
+ image = b1->getBuf();
+ } else {
+ ++image;
+ }
+ } else if (err == -ENOENT) {
+ // readlink /proc/[pid]/exe returns ENOENT for kernel threads
+ image = "\0";
+ } else {
+ logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+
+ if (!printb->printf("/proc/%i/maps", pid)) {
+ logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+ if (!b2->read(printb->getBuf())) {
+ logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__);
+ // This is not a fatal error - the process just doesn't exist any more
+ continue;
+ }
+
+ buffer->maps(pid, pid, b2->getBuf());
+ if (ps.numThreads <= 1) {
+ buffer->comm(pid, pid, image, ps.comm);
+ } else {
+ if (!readProcTask(buffer, pid, image, printb, b3)) {
+ logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+ }
+ }
+
+ result = true;
+
+ fail:
+ closedir(proc);
+
+ return result;
+}
diff --git a/tools/gator/daemon/Proc.h b/tools/gator/daemon/Proc.h
new file mode 100644
index 000000000000..057b6109848a
--- /dev/null
+++ b/tools/gator/daemon/Proc.h
@@ -0,0 +1,17 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef PROC_H
+#define PROC_H
+
+class Buffer;
+class DynBuf;
+
+bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3);
+
+#endif // PROC_H
diff --git a/tools/gator/daemon/Sender.cpp b/tools/gator/daemon/Sender.cpp
index 8eb348ff3a06..3a981a6427be 100644
--- a/tools/gator/daemon/Sender.cpp
+++ b/tools/gator/daemon/Sender.cpp
@@ -1,19 +1,18 @@
/**
- * 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
* published by the Free Software Foundation.
*/
-#include <string.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
+#include "Sender.h"
+
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
-#include "Sender.h"
+
+#include "Buffer.h"
#include "Logging.h"
#include "OlySocket.h"
#include "SessionData.h"
@@ -49,9 +48,12 @@ Sender::Sender(OlySocket* socket) {
}
Sender::~Sender() {
- delete mDataSocket;
- mDataSocket = NULL;
- if (mDataFile) {
+ // Just close it as the client socket is on the stack
+ if (mDataSocket != NULL) {
+ mDataSocket->closeSocket();
+ mDataSocket = NULL;
+ }
+ if (mDataFile != NULL) {
fclose(mDataFile);
}
}
@@ -95,10 +97,7 @@ void Sender::writeData(const char* data, int length, int type) {
// type and length already added by the Collector for apc data
unsigned char header[5];
header[0] = type;
- header[1] = (length >> 0) & 0xff;
- header[2] = (length >> 8) & 0xff;
- header[3] = (length >> 16) & 0xff;
- header[4] = (length >> 24) & 0xff;
+ Buffer::writeLEInt(header + 1, length);
mDataSocket->send((char*)&header, sizeof(header));
}
@@ -106,7 +105,7 @@ void Sender::writeData(const char* data, int length, int type) {
const int chunkSize = 100*1000 * alarmDuration / 8;
int pos = 0;
while (true) {
- mDataSocket->send((char*)data + pos, min(length - pos, chunkSize));
+ mDataSocket->send((const char*)data + pos, min(length - pos, chunkSize));
pos += chunkSize;
if (pos >= length) {
break;
diff --git a/tools/gator/daemon/Sender.h b/tools/gator/daemon/Sender.h
index b388f039bad7..4c359dba82f8 100644
--- a/tools/gator/daemon/Sender.h
+++ b/tools/gator/daemon/Sender.h
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/tools/gator/daemon/SessionData.cpp b/tools/gator/daemon/SessionData.cpp
index cf844075401f..c169299af872 100644
--- a/tools/gator/daemon/SessionData.cpp
+++ b/tools/gator/daemon/SessionData.cpp
@@ -1,13 +1,15 @@
/**
- * 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
* published by the Free Software Foundation.
*/
-#include <string.h>
#include "SessionData.h"
+
+#include <string.h>
+
#include "SessionXML.h"
#include "Logging.h"
@@ -38,6 +40,7 @@ void SessionData::initialize() {
mTotalBufferSize = 0;
// sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
mCores = 1;
+ mPageSize = 0;
}
void SessionData::parseSessionXML(char* xmlString) {
@@ -88,7 +91,8 @@ void SessionData::parseSessionXML(char* xmlString) {
void SessionData::readCpuInfo() {
char temp[256]; // arbitrarily large amount
strcpy(mCoreName, "unknown");
- mCpuId = -1;
+ memset(&mCpuIds, -1, sizeof(mCpuIds));
+ mMaxCpuId = -1;
FILE* f = fopen("/proc/cpuinfo", "r");
if (f == NULL) {
@@ -98,15 +102,16 @@ void SessionData::readCpuInfo() {
}
bool foundCoreName = false;
- bool foundCpuId = false;
- while (fgets(temp, sizeof(temp), f) && (!foundCoreName || !foundCpuId)) {
+ int processor = 0;
+ while (fgets(temp, sizeof(temp), f)) {
if (strlen(temp) > 0) {
temp[strlen(temp) - 1] = 0; // Replace the line feed with a null
}
const bool foundHardware = strstr(temp, "Hardware") != 0;
const bool foundCPUPart = strstr(temp, "CPU part") != 0;
- if (foundHardware || foundCPUPart) {
+ const bool foundProcessor = strstr(temp, "processor") != 0;
+ if (foundHardware || foundCPUPart || foundProcessor) {
char* position = strchr(temp, ':');
if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
logg->logMessage("Unknown format of /proc/cpuinfo\n"
@@ -122,11 +127,15 @@ void SessionData::readCpuInfo() {
}
if (foundCPUPart) {
- int cpuId = strtol(position, NULL, 16);
- if (cpuId > mCpuId) {
- mCpuId = cpuId;
+ mCpuIds[processor] = strtol(position, NULL, 0);
+ // If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId
+ if (mCpuIds[processor] > mMaxCpuId) {
+ mMaxCpuId = mCpuIds[processor];
}
- foundCpuId = true;
+ }
+
+ if (foundProcessor) {
+ processor = strtol(position, NULL, 0);
}
}
}
diff --git a/tools/gator/daemon/SessionData.h b/tools/gator/daemon/SessionData.h
index c834251527cf..ea34240e2df7 100644
--- a/tools/gator/daemon/SessionData.h
+++ b/tools/gator/daemon/SessionData.h
@@ -1,5 +1,5 @@
/**
- * 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
@@ -11,12 +11,12 @@
#include <stdint.h>
+#include "Config.h"
#include "Counter.h"
#include "Hwmon.h"
+#include "PerfDriver.h"
-#define MAX_PERFORMANCE_COUNTERS 50
-
-#define PROTOCOL_VERSION 17
+#define PROTOCOL_VERSION 18
#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions
struct ImageLinkList {
@@ -34,6 +34,7 @@ public:
void parseSessionXML(char* xmlString);
Hwmon hwmon;
+ PerfDriver perf;
char mCoreName[MAX_STRING_LEN];
struct ImageLinkList *mImages;
@@ -47,6 +48,7 @@ public:
bool mSessionIsActive;
bool mLocalCapture;
bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled
+ bool mIsEBS;
int mBacktraceDepth;
int mTotalBufferSize; // number of MB to use for the entire collection buffer
@@ -54,7 +56,9 @@ public:
int64_t mLiveRate;
int mDuration;
int mCores;
- int mCpuId;
+ int mPageSize;
+ int mCpuIds[NR_CPUS];
+ int mMaxCpuId;
// PMU Counters
int mCounterOverflow;
diff --git a/tools/gator/daemon/SessionXML.cpp b/tools/gator/daemon/SessionXML.cpp
index 0a0a02779176..55b2f9280709 100644
--- a/tools/gator/daemon/SessionXML.cpp
+++ b/tools/gator/daemon/SessionXML.cpp
@@ -1,15 +1,17 @@
/**
- * 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
* published by the Free Software Foundation.
*/
+#include "SessionXML.h"
+
#include <string.h>
#include <stdlib.h>
#include <limits.h>
-#include "SessionXML.h"
+
#include "Logging.h"
#include "OlyUtility.h"
#include "SessionData.h"
@@ -25,7 +27,7 @@ static const char* ATTR_DURATION = "duration";
static const char* ATTR_PATH = "path";
static const char* ATTR_LIVE_RATE = "live_rate";
-SessionXML::SessionXML(const char* str) {
+SessionXML::SessionXML(const char *str) {
parameters.buffer_mode[0] = 0;
parameters.sample_rate[0] = 0;
parameters.duration = 0;
@@ -33,13 +35,13 @@ SessionXML::SessionXML(const char* str) {
parameters.live_rate = 0;
parameters.images = NULL;
mPath = 0;
- mSessionXML = (char*)str;
+ mSessionXML = (const char *)str;
logg->logMessage(mSessionXML);
}
SessionXML::~SessionXML() {
if (mPath != 0) {
- free(mSessionXML);
+ free((char *)mSessionXML);
}
}
diff --git a/tools/gator/daemon/SessionXML.h b/tools/gator/daemon/SessionXML.h
index 0fb03bd6627c..e146094a4d17 100644
--- a/tools/gator/daemon/SessionXML.h
+++ b/tools/gator/daemon/SessionXML.h
@@ -1,5 +1,5 @@
/**
- * 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
@@ -24,13 +24,13 @@ struct ConfigParameters {
class SessionXML {
public:
- SessionXML(const char* str);
+ SessionXML(const char *str);
~SessionXML();
void parse();
ConfigParameters parameters;
private:
- char* mSessionXML;
- char* mPath;
+ const char *mSessionXML;
+ const char *mPath;
void sessionTag(mxml_node_t *tree, mxml_node_t *node);
void sessionImage(mxml_node_t *node);
diff --git a/tools/gator/daemon/Source.cpp b/tools/gator/daemon/Source.cpp
new file mode 100644
index 000000000000..60cf704e599b
--- /dev/null
+++ b/tools/gator/daemon/Source.cpp
@@ -0,0 +1,33 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include "Source.h"
+
+#include "Logging.h"
+
+Source::Source() : mThreadID() {
+}
+
+Source::~Source() {
+}
+
+void Source::start() {
+ if (pthread_create(&mThreadID, NULL, runStatic, this)) {
+ logg->logError(__FILE__, __LINE__, "Failed to create source thread");
+ handleException();
+ }
+}
+
+void Source::join() {
+ pthread_join(mThreadID, NULL);
+}
+
+void *Source::runStatic(void *arg) {
+ static_cast<Source *>(arg)->run();
+ return NULL;
+}
diff --git a/tools/gator/daemon/Source.h b/tools/gator/daemon/Source.h
new file mode 100644
index 000000000000..56ac3d6e94f3
--- /dev/null
+++ b/tools/gator/daemon/Source.h
@@ -0,0 +1,40 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SOURCE_H
+#define SOURCE_H
+
+#include <pthread.h>
+
+class Sender;
+
+class Source {
+public:
+ Source();
+ virtual ~Source();
+
+ virtual bool prepare() = 0;
+ void start();
+ virtual void run() = 0;
+ virtual void interrupt() = 0;
+ void join();
+
+ virtual bool isDone() = 0;
+ virtual void write(Sender *sender) = 0;
+
+private:
+ static void *runStatic(void *arg);
+
+ pthread_t mThreadID;
+
+ // Intentionally undefined
+ Source(const Source &);
+ Source &operator=(const Source &);
+};
+
+#endif // SOURCE_H
diff --git a/tools/gator/daemon/StreamlineSetup.cpp b/tools/gator/daemon/StreamlineSetup.cpp
index 2faada23f842..caa665e67193 100644
--- a/tools/gator/daemon/StreamlineSetup.cpp
+++ b/tools/gator/daemon/StreamlineSetup.cpp
@@ -1,26 +1,23 @@
/**
- * Copyright (C) ARM Limited 2011-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2011-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
* published by the Free Software Foundation.
*/
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include "Sender.h"
-#include "Logging.h"
-#include "OlyUtility.h"
-#include "SessionData.h"
-#include "CapturedXML.h"
#include "StreamlineSetup.h"
+
+#include "Buffer.h"
+#include "CapturedXML.h"
#include "ConfigurationXML.h"
#include "Driver.h"
#include "EventsXML.h"
+#include "Logging.h"
+#include "OlySocket.h"
+#include "OlyUtility.h"
+#include "Sender.h"
+#include "SessionData.h"
static const char* TAG_SESSION = "session";
static const char* TAG_REQUEST = "request";
@@ -198,12 +195,9 @@ void StreamlineSetup::handleDeliver(char* xml) {
void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
unsigned char header[5];
header[0] = type;
- header[1] = (length >> 0) & 0xff;
- header[2] = (length >> 8) & 0xff;
- header[3] = (length >> 16) & 0xff;
- header[4] = (length >> 24) & 0xff;
+ Buffer::writeLEInt(header + 1, length);
mSocket->send((char*)&header, sizeof(header));
- mSocket->send((char*)data, length);
+ mSocket->send((const char*)data, length);
}
void StreamlineSetup::sendEvents() {
@@ -241,8 +235,14 @@ void StreamlineSetup::sendCounters() {
xml = mxmlNewXML("1.0");
counters = mxmlNewElement(xml, "counters");
+ int count = 0;
for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
- driver->writeCounters(counters);
+ count += driver->writeCounters(counters);
+ }
+
+ if (count == 0) {
+ logg->logError(__FILE__, __LINE__, "No counters found, this could be because /dev/gator/events can not be read or because perf is not working correctly");
+ handleException();
}
char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
diff --git a/tools/gator/daemon/StreamlineSetup.h b/tools/gator/daemon/StreamlineSetup.h
index d6d9a6ea2991..74bb197e35ff 100644
--- a/tools/gator/daemon/StreamlineSetup.h
+++ b/tools/gator/daemon/StreamlineSetup.h
@@ -1,5 +1,5 @@
/**
- * 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
@@ -9,7 +9,10 @@
#ifndef __STREAMLINE_SETUP_H__
#define __STREAMLINE_SETUP_H__
-#include "OlySocket.h"
+#include <stdint.h>
+#include <string.h>
+
+class OlySocket;
// Commands from Streamline
enum {
diff --git a/tools/gator/daemon/UEvent.cpp b/tools/gator/daemon/UEvent.cpp
new file mode 100644
index 000000000000..d977cd080b40
--- /dev/null
+++ b/tools/gator/daemon/UEvent.cpp
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#include "UEvent.h"
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <string.h>
+
+#include <unistd.h>
+
+#include "Logging.h"
+
+static const char EMPTY[] = "";
+static const char ACTION[] = "ACTION=";
+static const char DEVPATH[] = "DEVPATH=";
+static const char SUBSYSTEM[] = "SUBSYSTEM=";
+
+UEvent::UEvent() : mFd(-1) {
+}
+
+UEvent::~UEvent() {
+ if (mFd >= 0) {
+ close(mFd);
+ }
+}
+
+bool UEvent::init() {
+ mFd = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
+ if (mFd < 0) {
+ logg->logMessage("%s(%s:%i): socket failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ struct sockaddr_nl sockaddr;
+ memset(&sockaddr, 0, sizeof(sockaddr));
+ sockaddr.nl_family = AF_NETLINK;
+ sockaddr.nl_groups = 1; // bitmask: (1 << 0) == kernel events, (1 << 1) == udev events
+ sockaddr.nl_pid = 0;
+ if (bind(mFd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0) {
+ logg->logMessage("%s(%s:%i): bind failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ return true;
+}
+
+bool UEvent::read(UEventResult *const result) {
+ ssize_t bytes = recv(mFd, result->mBuf, sizeof(result->mBuf), 0);
+ if (bytes <= 0) {
+ logg->logMessage("%s(%s:%i): recv failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ result->mAction = EMPTY;
+ result->mDevPath = EMPTY;
+ result->mSubsystem = EMPTY;
+
+ for (int pos = 0; pos < bytes; pos += strlen(result->mBuf + pos) + 1) {
+ char *const str = result->mBuf + pos;
+ if (strncmp(str, ACTION, sizeof(ACTION) - 1) == 0) {
+ result->mAction = str + sizeof(ACTION) - 1;
+ } else if (strncmp(str, DEVPATH, sizeof(DEVPATH) - 1) == 0) {
+ result->mDevPath = str + sizeof(DEVPATH) - 1;
+ } else if (strncmp(str, SUBSYSTEM, sizeof(SUBSYSTEM) - 1) == 0) {
+ result->mSubsystem = str + sizeof(SUBSYSTEM) - 1;
+ }
+ }
+
+ return true;
+}
diff --git a/tools/gator/daemon/UEvent.h b/tools/gator/daemon/UEvent.h
new file mode 100644
index 000000000000..2f7ef2c93f5d
--- /dev/null
+++ b/tools/gator/daemon/UEvent.h
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) ARM Limited 2013-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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef UEVENT_H
+#define UEVENT_H
+
+struct UEventResult {
+ const char *mAction;
+ const char *mDevPath;
+ const char *mSubsystem;
+ char mBuf[1<<13];
+};
+
+class UEvent {
+public:
+ UEvent();
+ ~UEvent();
+
+ bool init();
+ bool read(UEventResult *const result);
+ int getFd() const { return mFd; }
+
+private:
+ int mFd;
+
+ // Intentionally undefined
+ UEvent(const UEvent &);
+ UEvent &operator=(const UEvent &);
+};
+
+#endif // UEVENT_H
diff --git a/tools/gator/daemon/UserSpaceSource.cpp b/tools/gator/daemon/UserSpaceSource.cpp
new file mode 100644
index 000000000000..debe69636cff
--- /dev/null
+++ b/tools/gator/daemon/UserSpaceSource.cpp
@@ -0,0 +1,97 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include "UserSpaceSource.h"
+
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include "Child.h"
+#include "DriverSource.h"
+#include "Logging.h"
+#include "SessionData.h"
+
+#define NS_PER_S ((uint64_t)1000000000)
+#define NS_PER_US 1000
+
+extern Child *child;
+
+UserSpaceSource::UserSpaceSource(sem_t *senderSem) : mBuffer(0, FRAME_BLOCK_COUNTER, gSessionData->mTotalBufferSize*1024*1024, senderSem) {
+}
+
+UserSpaceSource::~UserSpaceSource() {
+}
+
+bool UserSpaceSource::prepare() {
+ return true;
+}
+
+void UserSpaceSource::run() {
+ prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
+
+ gSessionData->hwmon.start();
+
+ int64_t monotonic_started = 0;
+ while (monotonic_started <= 0) {
+ usleep(10);
+
+ if (DriverSource::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
+ logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
+ handleException();
+ }
+ }
+
+ uint64_t next_time = 0;
+ while (gSessionData->mSessionIsActive) {
+ struct timespec ts;
+#ifndef CLOCK_MONOTONIC_RAW
+ // Android doesn't have this defined but it was added in Linux 2.6.28
+#define CLOCK_MONOTONIC_RAW 4
+#endif
+ if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
+ logg->logError(__FILE__, __LINE__, "Failed to get uptime");
+ handleException();
+ }
+ const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started;
+ // Sample ten times a second ignoring gSessionData->mSampleRate
+ next_time += NS_PER_S/10;//gSessionData->mSampleRate;
+ if (next_time < curr_time) {
+ logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
+ next_time = curr_time;
+ }
+
+ if (mBuffer.eventHeader(curr_time)) {
+ gSessionData->hwmon.read(&mBuffer);
+ // Only check after writing all counters so that time and corresponding counters appear in the same frame
+ mBuffer.check(curr_time);
+ }
+
+ if (mBuffer.bytesAvailable() <= 0) {
+ logg->logMessage("One shot (counters)");
+ child->endSession();
+ }
+
+ usleep((next_time - curr_time)/NS_PER_US);
+ }
+
+ mBuffer.setDone();
+}
+
+void UserSpaceSource::interrupt() {
+ // Do nothing
+}
+
+bool UserSpaceSource::isDone() {
+ return mBuffer.isDone();
+}
+
+void UserSpaceSource::write(Sender *sender) {
+ if (!mBuffer.isDone()) {
+ mBuffer.write(sender);
+ }
+}
diff --git a/tools/gator/daemon/UserSpaceSource.h b/tools/gator/daemon/UserSpaceSource.h
new file mode 100644
index 000000000000..fb5889d26ffb
--- /dev/null
+++ b/tools/gator/daemon/UserSpaceSource.h
@@ -0,0 +1,38 @@
+/**
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef USERSPACESOURCE_H
+#define USERSPACESOURCE_H
+
+#include <semaphore.h>
+
+#include "Buffer.h"
+#include "Source.h"
+
+// User space counters - currently just hwmon
+class UserSpaceSource : public Source {
+public:
+ UserSpaceSource(sem_t *senderSem);
+ ~UserSpaceSource();
+
+ bool prepare();
+ void run();
+ void interrupt();
+
+ bool isDone();
+ void write(Sender *sender);
+
+private:
+ Buffer mBuffer;
+
+ // Intentionally unimplemented
+ UserSpaceSource(const UserSpaceSource &);
+ UserSpaceSource &operator=(const UserSpaceSource &);
+};
+
+#endif // USERSPACESOURCE_H
diff --git a/tools/gator/daemon/common.mk b/tools/gator/daemon/common.mk
index 031d16906881..d9dc14606b07 100644
--- a/tools/gator/daemon/common.mk
+++ b/tools/gator/daemon/common.mk
@@ -25,7 +25,7 @@ include $(wildcard *.d)
include $(wildcard mxml/*.d)
EventsXML.cpp: events_xml.h
-ConfigurationXML.cpp: configuration_xml.h
+ConfigurationXML.cpp: defaults_xml.h
# Don't regenerate conf-lex.c or conf-parse.c
libsensors/conf-lex.c: ;
@@ -47,4 +47,4 @@ escape: escape.c
gcc $^ -o $@
clean:
- rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h configuration_xml.h
+ rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h defaults_xml.h
diff --git a/tools/gator/daemon/configuration.xml b/tools/gator/daemon/defaults.xml
index b44c00a79e88..5bf096cb2a45 100644
--- a/tools/gator/daemon/configuration.xml
+++ b/tools/gator/daemon/defaults.xml
@@ -6,29 +6,34 @@
<configuration counter="ARM_ARM11MPCore_ccnt" event="0xff"/>
<configuration counter="ARM_ARM11MPCore_cnt0" event="0x08"/>
<configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b"/>
- <configuration counter="ARM_Cortex-A5_ccnt" event="0xff"/>
- <configuration counter="ARM_Cortex-A5_cnt0" event="0x8"/>
- <configuration counter="ARM_Cortex-A5_cnt1" event="0x1"/>
- <configuration counter="ARM_Cortex-A7_ccnt" event="0xff"/>
- <configuration counter="ARM_Cortex-A7_cnt0" event="0x08"/>
- <configuration counter="ARM_Cortex-A7_cnt1" event="0x10"/>
- <configuration counter="ARM_Cortex-A7_cnt2" event="0x16"/>
- <configuration counter="ARM_Cortex-A8_ccnt" event="0xff"/>
- <configuration counter="ARM_Cortex-A8_cnt0" event="0x8"/>
- <configuration counter="ARM_Cortex-A8_cnt1" event="0x44"/>
- <configuration counter="ARM_Cortex-A8_cnt2" event="0x43"/>
- <configuration counter="ARM_Cortex-A8_cnt3" event="0x10"/>
- <configuration counter="ARM_Cortex-A9_ccnt" event="0xff"/>
- <configuration counter="ARM_Cortex-A9_cnt0" event="0x68"/>
- <configuration counter="ARM_Cortex-A9_cnt1" event="0x06"/>
- <configuration counter="ARM_Cortex-A9_cnt2" event="0x07"/>
- <configuration counter="ARM_Cortex-A9_cnt3" event="0x03"/>
- <configuration counter="ARM_Cortex-A9_cnt4" event="0x04"/>
- <configuration counter="ARM_Cortex-A15_ccnt" event="0xff"/>
- <configuration counter="ARM_Cortex-A15_cnt0" event="0x8"/>
- <configuration counter="ARM_Cortex-A15_cnt1" event="0x16"/>
- <configuration counter="ARM_Cortex-A15_cnt2" event="0x10"/>
- <configuration counter="ARM_Cortex-A15_cnt3" event="0x19"/>
+ <configuration counter="ARMv7_Cortex_A5_ccnt" event="0xff"/>
+ <configuration counter="ARMv7_Cortex_A5_cnt0" event="0x8"/>
+ <configuration counter="ARMv7_Cortex_A5_cnt1" event="0x1"/>
+ <configuration counter="ARMv7_Cortex_A7_ccnt" event="0xff"/>
+ <configuration counter="ARMv7_Cortex_A7_cnt0" event="0x08"/>
+ <configuration counter="ARMv7_Cortex_A7_cnt1" event="0x10"/>
+ <configuration counter="ARMv7_Cortex_A7_cnt2" event="0x16"/>
+ <configuration counter="ARMv7_Cortex_A8_ccnt" event="0xff"/>
+ <configuration counter="ARMv7_Cortex_A8_cnt0" event="0x8"/>
+ <configuration counter="ARMv7_Cortex_A8_cnt1" event="0x44"/>
+ <configuration counter="ARMv7_Cortex_A8_cnt2" event="0x43"/>
+ <configuration counter="ARMv7_Cortex_A8_cnt3" event="0x10"/>
+ <configuration counter="ARMv7_Cortex_A9_ccnt" event="0xff"/>
+ <configuration counter="ARMv7_Cortex_A9_cnt0" event="0x68"/>
+ <configuration counter="ARMv7_Cortex_A9_cnt1" event="0x06"/>
+ <configuration counter="ARMv7_Cortex_A9_cnt2" event="0x07"/>
+ <configuration counter="ARMv7_Cortex_A9_cnt3" event="0x03"/>
+ <configuration counter="ARMv7_Cortex_A9_cnt4" event="0x04"/>
+ <configuration counter="ARMv7_Cortex_A12_ccnt" event="0xff"/>
+ <configuration counter="ARMv7_Cortex_A12_cnt0" event="0x08"/>
+ <configuration counter="ARMv7_Cortex_A12_cnt1" event="0x16"/>
+ <configuration counter="ARMv7_Cortex_A12_cnt2" event="0x10"/>
+ <configuration counter="ARMv7_Cortex_A12_cnt3" event="0x19"/>
+ <configuration counter="ARMv7_Cortex_A15_ccnt" event="0xff"/>
+ <configuration counter="ARMv7_Cortex_A15_cnt0" event="0x8"/>
+ <configuration counter="ARMv7_Cortex_A15_cnt1" event="0x16"/>
+ <configuration counter="ARMv7_Cortex_A15_cnt2" event="0x10"/>
+ <configuration counter="ARMv7_Cortex_A15_cnt3" event="0x19"/>
<configuration counter="ARM_Cortex-A53_ccnt" event="0x11"/>
<configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/>
<configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/>
diff --git a/tools/gator/daemon/escape.c b/tools/gator/daemon/escape.c
index 3eec1f8d38d3..c54aa1c3e75d 100644
--- a/tools/gator/daemon/escape.c
+++ b/tools/gator/daemon/escape.c
@@ -1,5 +1,5 @@
/**
- * 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
diff --git a/tools/gator/daemon/events-Cortex-A12.xml b/tools/gator/daemon/events-Cortex-A12.xml
index 20a4772c4587..9c04354ad137 100644
--- a/tools/gator/daemon/events-Cortex-A12.xml
+++ b/tools/gator/daemon/events-Cortex-A12.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex-A12_cnt" count="6"/>
- <category name="Cortex-A12" counter_set="ARM_Cortex-A12_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex-A12_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv7_Cortex_A12_cnt" count="6"/>
+ <category name="Cortex-A12" counter_set="ARMv7_Cortex_A12_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv7_Cortex_A12_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
<event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
diff --git a/tools/gator/daemon/events-Cortex-A15.xml b/tools/gator/daemon/events-Cortex-A15.xml
index faa8b1cbcfb2..f50e55d66195 100644
--- a/tools/gator/daemon/events-Cortex-A15.xml
+++ b/tools/gator/daemon/events-Cortex-A15.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex-A15_cnt" count="6"/>
- <category name="Cortex-A15" counter_set="ARM_Cortex-A15_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex-A15_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv7_Cortex_A15_cnt" count="6"/>
+ <category name="Cortex-A15" counter_set="ARMv7_Cortex_A15_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv7_Cortex_A15_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/tools/gator/daemon/events-Cortex-A5.xml b/tools/gator/daemon/events-Cortex-A5.xml
index a5b15466be52..d67581d77c08 100644
--- a/tools/gator/daemon/events-Cortex-A5.xml
+++ b/tools/gator/daemon/events-Cortex-A5.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex-A5_cnt" count="2"/>
- <category name="Cortex-A5" counter_set="ARM_Cortex-A5_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex-A5_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv7_Cortex_A5_cnt" count="2"/>
+ <category name="Cortex-A5" counter_set="ARMv7_Cortex_A5_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv7_Cortex_A5_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/tools/gator/daemon/events-Cortex-A7.xml b/tools/gator/daemon/events-Cortex-A7.xml
index 54d7264bc08e..6e078b3cffa3 100644
--- a/tools/gator/daemon/events-Cortex-A7.xml
+++ b/tools/gator/daemon/events-Cortex-A7.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex-A7_cnt" count="4"/>
- <category name="Cortex-A7" counter_set="ARM_Cortex-A7_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex-A7_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv7_Cortex_A7_cnt" count="4"/>
+ <category name="Cortex-A7" counter_set="ARMv7_Cortex_A7_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv7_Cortex_A7_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/tools/gator/daemon/events-Cortex-A8.xml b/tools/gator/daemon/events-Cortex-A8.xml
index f2518237983a..a69e25ab2c34 100644
--- a/tools/gator/daemon/events-Cortex-A8.xml
+++ b/tools/gator/daemon/events-Cortex-A8.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex-A8_cnt" count="4"/>
- <category name="Cortex-A8" counter_set="ARM_Cortex-A8_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex-A8_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv7_Cortex_A8_cnt" count="4"/>
+ <category name="Cortex-A8" counter_set="ARMv7_Cortex_A8_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv7_Cortex_A8_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/tools/gator/daemon/events-Cortex-A9.xml b/tools/gator/daemon/events-Cortex-A9.xml
index 75f09c80425e..3e7f8289062e 100644
--- a/tools/gator/daemon/events-Cortex-A9.xml
+++ b/tools/gator/daemon/events-Cortex-A9.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex-A9_cnt" count="6"/>
- <category name="Cortex-A9" counter_set="ARM_Cortex-A9_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex-A9_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv7_Cortex_A9_cnt" count="6"/>
+ <category name="Cortex-A9" counter_set="ARMv7_Cortex_A9_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv7_Cortex_A9_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/tools/gator/daemon/events-Linux.xml b/tools/gator/daemon/events-Linux.xml
index 31a90a1d6335..4d677e15db7e 100644
--- a/tools/gator/daemon/events-Linux.xml
+++ b/tools/gator/daemon/events-Linux.xml
@@ -6,12 +6,12 @@
<event counter="Linux_net_rx" title="Network" name="Receive" units="B" description="Receive network traffic, including effect from Streamline"/>
<event counter="Linux_net_tx" title="Network" name="Transmit" units="B" description="Transmit network traffic, including effect from Streamline"/>
<event counter="Linux_sched_switch" title="Scheduler" name="Switch" per_cpu="yes" description="Context switch events"/>
- <event counter="Linux_meminfo_memused" title="Memory" name="Used" display="maximum" units="B" proc="yes" description="Total used memory size. Note: a process' used memory includes shared memory that may be counted more than once (equivalent to RES from top). Kernel threads are not filterable."/>
- <event counter="Linux_meminfo_memfree" title="Memory" name="Free" display="minimum" units="B" description="Available memory size"/>
- <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" display="maximum" units="B" description="Memory used by OS disk buffers"/>
- <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" display="maximum" units="Hz" series_composition="overlay" average_cores="yes" description="Frequency setting of the CPU"/>
- <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" display="maximum" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/>
- <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" display="average" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on contended resource"/>
- <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" display="average" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on I/O resource"/>
+ <event counter="Linux_meminfo_memused" title="Memory" name="Used" class="absolute" units="B" proc="yes" description="Total used memory size. Note: a process' used memory includes shared memory that may be counted more than once (equivalent to RES from top). Kernel threads are not filterable."/>
+ <event counter="Linux_meminfo_memfree" title="Memory" name="Free" class="absolute" display="minimum" units="B" description="Available memory size"/>
+ <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" class="absolute" units="B" description="Memory used by OS disk buffers"/>
+ <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" class="absolute" units="Hz" series_composition="overlay" average_cores="yes" description="Frequency setting of the CPU"/>
+ <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" class="absolute" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/>
+ <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on contended resource"/>
+ <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on I/O resource"/>
</category>
diff --git a/tools/gator/daemon/events-Mali-4xx.xml b/tools/gator/daemon/events-Mali-4xx.xml
index 8772ce410b95..5a71386830ba 100644
--- a/tools/gator/daemon/events-Mali-4xx.xml
+++ b/tools/gator/daemon/events-Mali-4xx.xml
@@ -207,7 +207,7 @@
<event event="0x0400" option_set="fs" title="ARM Mali-4xx" name="Filmstrip" description="Scaled framebuffer"/>
</category>
<category name="ARM_Mali-4xx_Voltage" per_cpu="no">
- <event counter="ARM_Mali-4xx_Voltage" title="Mali GPU Voltage" name="Voltage" display="average" average_selection="yes" units="mV" description="GPU core voltage."/>
+ <event counter="ARM_Mali-4xx_Voltage" title="Mali GPU Voltage" name="Voltage" class="absolute" display="average" average_selection="yes" units="mV" description="GPU core voltage."/>
</category>
<category name="ARM_Mali-4xx_Frequency" per_cpu="no">
<event counter="ARM_Mali-4xx_Frequency" title="Mali GPU Frequency" name="Frequency" display="average" average_selection="yes" units="MHz" description="GPU core frequency."/>
diff --git a/tools/gator/daemon/events-Mali-T6xx.xml b/tools/gator/daemon/events-Mali-T6xx.xml
index 2465238a8bda..ec9ca006f85f 100644
--- a/tools/gator/daemon/events-Mali-T6xx.xml
+++ b/tools/gator/daemon/events-Mali-T6xx.xml
@@ -4,14 +4,14 @@
</category>
<category name="Mali-T6xx-PMShader" per_cpu="no">
- <event counter="ARM_Mali-T6xx_PM_SHADER_0" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 0" description="Mali PM Shader: PM Shader Core 0."/>
- <event counter="ARM_Mali-T6xx_PM_SHADER_1" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 1" description="Mali PM Shader: PM Shader Core 1."/>
- <event counter="ARM_Mali-T6xx_PM_SHADER_2" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 2" description="Mali PM Shader: PM Shader Core 2."/>
- <event counter="ARM_Mali-T6xx_PM_SHADER_3" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 3" description="Mali PM Shader: PM Shader Core 3."/>
- <event counter="ARM_Mali-T6xx_PM_SHADER_4" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 4" description="Mali PM Shader: PM Shader Core 4."/>
- <event counter="ARM_Mali-T6xx_PM_SHADER_5" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 5" description="Mali PM Shader: PM Shader Core 5."/>
- <event counter="ARM_Mali-T6xx_PM_SHADER_6" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 6" description="Mali PM Shader: PM Shader Core 6."/>
- <event counter="ARM_Mali-T6xx_PM_SHADER_7" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 7" description="Mali PM Shader: PM Shader Core 7."/>
+ <event counter="ARM_Mali-T6xx_PM_SHADER_0" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 0" description="Mali PM Shader: PM Shader Core 0."/>
+ <event counter="ARM_Mali-T6xx_PM_SHADER_1" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 1" description="Mali PM Shader: PM Shader Core 1."/>
+ <event counter="ARM_Mali-T6xx_PM_SHADER_2" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 2" description="Mali PM Shader: PM Shader Core 2."/>
+ <event counter="ARM_Mali-T6xx_PM_SHADER_3" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 3" description="Mali PM Shader: PM Shader Core 3."/>
+ <event counter="ARM_Mali-T6xx_PM_SHADER_4" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 4" description="Mali PM Shader: PM Shader Core 4."/>
+ <event counter="ARM_Mali-T6xx_PM_SHADER_5" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 5" description="Mali PM Shader: PM Shader Core 5."/>
+ <event counter="ARM_Mali-T6xx_PM_SHADER_6" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 6" description="Mali PM Shader: PM Shader Core 6."/>
+ <event counter="ARM_Mali-T6xx_PM_SHADER_7" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 7" description="Mali PM Shader: PM Shader Core 7."/>
</category>
<category name="Mali-T6xx-PMTiler" per_cpu="no">
diff --git a/tools/gator/daemon/events-Perf-Hardware.xml b/tools/gator/daemon/events-Perf-Hardware.xml
new file mode 100644
index 000000000000..423696f82420
--- /dev/null
+++ b/tools/gator/daemon/events-Perf-Hardware.xml
@@ -0,0 +1,12 @@
+ <counter_set name="Perf_Hardware_cnt" count="6"/>
+ <category name="Perf Hardware" counter_set="Perf_Hardware_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="Perf_Hardware_ccnt" event="0" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <event event="1" title="Instruction" name="Executed" description="Instruction executed"/>
+ <event event="2" title="Cache" name="References" description="Cache References"/>
+ <event event="3" title="Cache" name="Misses" description="Cache Misses"/>
+ <event event="4" title="Branch" name="Instructions" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="5" title="Branch" name="Misses" description="Branch mispredicted or not predicted"/>
+ <event event="6" title="Bus" name="Cycles" description="Bus Cycles"/>
+ <event event="7" title="Instruction" name="Stalled Frontend" description="Stalled Frontend Cycles"/>
+ <event event="8" title="Instruction" name="Stalled Backend" description="Stalled Backend Cycles"/>
+ </category>
diff --git a/tools/gator/daemon/k/perf_event.3.12.h b/tools/gator/daemon/k/perf_event.3.12.h
new file mode 100644
index 000000000000..e886c48cadf6
--- /dev/null
+++ b/tools/gator/daemon/k/perf_event.3.12.h
@@ -0,0 +1,792 @@
+/*
+ * Performance events:
+ *
+ * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
+ * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra
+ *
+ * Data type definitions, declarations, prototypes.
+ *
+ * Started by: Thomas Gleixner and Ingo Molnar
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+#ifndef _LINUX_PERF_EVENT_H
+#define _LINUX_PERF_EVENT_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/byteorder.h>
+
+/*
+ * User-space ABI bits:
+ */
+
+/*
+ * attr.type
+ */
+enum perf_type_id {
+ PERF_TYPE_HARDWARE = 0,
+ PERF_TYPE_SOFTWARE = 1,
+ PERF_TYPE_TRACEPOINT = 2,
+ PERF_TYPE_HW_CACHE = 3,
+ PERF_TYPE_RAW = 4,
+ PERF_TYPE_BREAKPOINT = 5,
+
+ PERF_TYPE_MAX, /* non-ABI */
+};
+
+/*
+ * Generalized performance event event_id types, used by the
+ * attr.event_id parameter of the sys_perf_event_open()
+ * syscall:
+ */
+enum perf_hw_id {
+ /*
+ * Common hardware events, generalized by the kernel:
+ */
+ PERF_COUNT_HW_CPU_CYCLES = 0,
+ PERF_COUNT_HW_INSTRUCTIONS = 1,
+ PERF_COUNT_HW_CACHE_REFERENCES = 2,
+ PERF_COUNT_HW_CACHE_MISSES = 3,
+ PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
+ PERF_COUNT_HW_BRANCH_MISSES = 5,
+ PERF_COUNT_HW_BUS_CYCLES = 6,
+ PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
+ PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
+ PERF_COUNT_HW_REF_CPU_CYCLES = 9,
+
+ PERF_COUNT_HW_MAX, /* non-ABI */
+};
+
+/*
+ * Generalized hardware cache events:
+ *
+ * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
+ * { read, write, prefetch } x
+ * { accesses, misses }
+ */
+enum perf_hw_cache_id {
+ PERF_COUNT_HW_CACHE_L1D = 0,
+ PERF_COUNT_HW_CACHE_L1I = 1,
+ PERF_COUNT_HW_CACHE_LL = 2,
+ PERF_COUNT_HW_CACHE_DTLB = 3,
+ PERF_COUNT_HW_CACHE_ITLB = 4,
+ PERF_COUNT_HW_CACHE_BPU = 5,
+ PERF_COUNT_HW_CACHE_NODE = 6,
+
+ PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
+};
+
+enum perf_hw_cache_op_id {
+ PERF_COUNT_HW_CACHE_OP_READ = 0,
+ PERF_COUNT_HW_CACHE_OP_WRITE = 1,
+ PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
+
+ PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
+};
+
+enum perf_hw_cache_op_result_id {
+ PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
+ PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
+
+ PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
+};
+
+/*
+ * Special "software" events provided by the kernel, even if the hardware
+ * does not support performance events. These events measure various
+ * physical and sw events of the kernel (and allow the profiling of them as
+ * well):
+ */
+enum perf_sw_ids {
+ PERF_COUNT_SW_CPU_CLOCK = 0,
+ PERF_COUNT_SW_TASK_CLOCK = 1,
+ PERF_COUNT_SW_PAGE_FAULTS = 2,
+ PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
+ PERF_COUNT_SW_CPU_MIGRATIONS = 4,
+ PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
+ PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
+ PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
+ PERF_COUNT_SW_EMULATION_FAULTS = 8,
+ PERF_COUNT_SW_DUMMY = 9,
+
+ PERF_COUNT_SW_MAX, /* non-ABI */
+};
+
+/*
+ * Bits that can be set in attr.sample_type to request information
+ * in the overflow packets.
+ */
+enum perf_event_sample_format {
+ PERF_SAMPLE_IP = 1U << 0,
+ PERF_SAMPLE_TID = 1U << 1,
+ PERF_SAMPLE_TIME = 1U << 2,
+ PERF_SAMPLE_ADDR = 1U << 3,
+ PERF_SAMPLE_READ = 1U << 4,
+ PERF_SAMPLE_CALLCHAIN = 1U << 5,
+ PERF_SAMPLE_ID = 1U << 6,
+ PERF_SAMPLE_CPU = 1U << 7,
+ PERF_SAMPLE_PERIOD = 1U << 8,
+ PERF_SAMPLE_STREAM_ID = 1U << 9,
+ PERF_SAMPLE_RAW = 1U << 10,
+ PERF_SAMPLE_BRANCH_STACK = 1U << 11,
+ PERF_SAMPLE_REGS_USER = 1U << 12,
+ PERF_SAMPLE_STACK_USER = 1U << 13,
+ PERF_SAMPLE_WEIGHT = 1U << 14,
+ PERF_SAMPLE_DATA_SRC = 1U << 15,
+ PERF_SAMPLE_IDENTIFIER = 1U << 16,
+
+ PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */
+};
+
+/*
+ * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
+ *
+ * If the user does not pass priv level information via branch_sample_type,
+ * the kernel uses the event's priv level. Branch and event priv levels do
+ * not have to match. Branch priv level is checked for permissions.
+ *
+ * The branch types can be combined, however BRANCH_ANY covers all types
+ * of branches and therefore it supersedes all the other types.
+ */
+enum perf_branch_sample_type {
+ PERF_SAMPLE_BRANCH_USER = 1U << 0, /* user branches */
+ PERF_SAMPLE_BRANCH_KERNEL = 1U << 1, /* kernel branches */
+ PERF_SAMPLE_BRANCH_HV = 1U << 2, /* hypervisor branches */
+
+ PERF_SAMPLE_BRANCH_ANY = 1U << 3, /* any branch types */
+ PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 4, /* any call branch */
+ PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 5, /* any return branch */
+ PERF_SAMPLE_BRANCH_IND_CALL = 1U << 6, /* indirect calls */
+ PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */
+ PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */
+ PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */
+
+ PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */
+};
+
+#define PERF_SAMPLE_BRANCH_PLM_ALL \
+ (PERF_SAMPLE_BRANCH_USER|\
+ PERF_SAMPLE_BRANCH_KERNEL|\
+ PERF_SAMPLE_BRANCH_HV)
+
+/*
+ * Values to determine ABI of the registers dump.
+ */
+enum perf_sample_regs_abi {
+ PERF_SAMPLE_REGS_ABI_NONE = 0,
+ PERF_SAMPLE_REGS_ABI_32 = 1,
+ PERF_SAMPLE_REGS_ABI_64 = 2,
+};
+
+/*
+ * The format of the data returned by read() on a perf event fd,
+ * as specified by attr.read_format:
+ *
+ * struct read_format {
+ * { u64 value;
+ * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
+ * { u64 id; } && PERF_FORMAT_ID
+ * } && !PERF_FORMAT_GROUP
+ *
+ * { u64 nr;
+ * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
+ * { u64 value;
+ * { u64 id; } && PERF_FORMAT_ID
+ * } cntr[nr];
+ * } && PERF_FORMAT_GROUP
+ * };
+ */
+enum perf_event_read_format {
+ PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
+ PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
+ PERF_FORMAT_ID = 1U << 2,
+ PERF_FORMAT_GROUP = 1U << 3,
+
+ PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
+};
+
+#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
+#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */
+#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
+#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
+ /* add: sample_stack_user */
+
+/*
+ * Hardware event_id to monitor via a performance monitoring event:
+ */
+struct perf_event_attr {
+
+ /*
+ * Major type: hardware/software/tracepoint/etc.
+ */
+ __u32 type;
+
+ /*
+ * Size of the attr structure, for fwd/bwd compat.
+ */
+ __u32 size;
+
+ /*
+ * Type specific configuration information.
+ */
+ __u64 config;
+
+ union {
+ __u64 sample_period;
+ __u64 sample_freq;
+ };
+
+ __u64 sample_type;
+ __u64 read_format;
+
+ __u64 disabled : 1, /* off by default */
+ inherit : 1, /* children inherit it */
+ pinned : 1, /* must always be on PMU */
+ exclusive : 1, /* only group on PMU */
+ exclude_user : 1, /* don't count user */
+ exclude_kernel : 1, /* ditto kernel */
+ exclude_hv : 1, /* ditto hypervisor */
+ exclude_idle : 1, /* don't count when idle */
+ mmap : 1, /* include mmap data */
+ comm : 1, /* include comm data */
+ freq : 1, /* use freq, not period */
+ inherit_stat : 1, /* per task counts */
+ enable_on_exec : 1, /* next exec enables */
+ task : 1, /* trace fork/exit */
+ watermark : 1, /* wakeup_watermark */
+ /*
+ * precise_ip:
+ *
+ * 0 - SAMPLE_IP can have arbitrary skid
+ * 1 - SAMPLE_IP must have constant skid
+ * 2 - SAMPLE_IP requested to have 0 skid
+ * 3 - SAMPLE_IP must have 0 skid
+ *
+ * See also PERF_RECORD_MISC_EXACT_IP
+ */
+ precise_ip : 2, /* skid constraint */
+ mmap_data : 1, /* non-exec mmap data */
+ sample_id_all : 1, /* sample_type all events */
+
+ exclude_host : 1, /* don't count in host */
+ exclude_guest : 1, /* don't count in guest */
+
+ exclude_callchain_kernel : 1, /* exclude kernel callchains */
+ exclude_callchain_user : 1, /* exclude user callchains */
+ mmap2 : 1, /* include mmap with inode data */
+
+ __reserved_1 : 40;
+
+ union {
+ __u32 wakeup_events; /* wakeup every n events */
+ __u32 wakeup_watermark; /* bytes before wakeup */
+ };
+
+ __u32 bp_type;
+ union {
+ __u64 bp_addr;
+ __u64 config1; /* extension of config */
+ };
+ union {
+ __u64 bp_len;
+ __u64 config2; /* extension of config1 */
+ };
+ __u64 branch_sample_type; /* enum perf_branch_sample_type */
+
+ /*
+ * Defines set of user regs to dump on samples.
+ * See asm/perf_regs.h for details.
+ */
+ __u64 sample_regs_user;
+
+ /*
+ * Defines size of the user stack to dump on samples.
+ */
+ __u32 sample_stack_user;
+
+ /* Align to u64. */
+ __u32 __reserved_2;
+};
+
+#define perf_flags(attr) (*(&(attr)->read_format + 1))
+
+/*
+ * Ioctls that can be done on a perf event fd:
+ */
+#define PERF_EVENT_IOC_ENABLE _IO ('$', 0)
+#define PERF_EVENT_IOC_DISABLE _IO ('$', 1)
+#define PERF_EVENT_IOC_REFRESH _IO ('$', 2)
+#define PERF_EVENT_IOC_RESET _IO ('$', 3)
+#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64)
+#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
+#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
+#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
+
+enum perf_event_ioc_flags {
+ PERF_IOC_FLAG_GROUP = 1U << 0,
+};
+
+/*
+ * Structure of the page that can be mapped via mmap
+ */
+struct perf_event_mmap_page {
+ __u32 version; /* version number of this structure */
+ __u32 compat_version; /* lowest version this is compat with */
+
+ /*
+ * Bits needed to read the hw events in user-space.
+ *
+ * u32 seq, time_mult, time_shift, idx, width;
+ * u64 count, enabled, running;
+ * u64 cyc, time_offset;
+ * s64 pmc = 0;
+ *
+ * do {
+ * seq = pc->lock;
+ * barrier()
+ *
+ * enabled = pc->time_enabled;
+ * running = pc->time_running;
+ *
+ * if (pc->cap_usr_time && enabled != running) {
+ * cyc = rdtsc();
+ * time_offset = pc->time_offset;
+ * time_mult = pc->time_mult;
+ * time_shift = pc->time_shift;
+ * }
+ *
+ * idx = pc->index;
+ * count = pc->offset;
+ * if (pc->cap_usr_rdpmc && idx) {
+ * width = pc->pmc_width;
+ * pmc = rdpmc(idx - 1);
+ * }
+ *
+ * barrier();
+ * } while (pc->lock != seq);
+ *
+ * NOTE: for obvious reason this only works on self-monitoring
+ * processes.
+ */
+ __u32 lock; /* seqlock for synchronization */
+ __u32 index; /* hardware event identifier */
+ __s64 offset; /* add to hardware event value */
+ __u64 time_enabled; /* time event active */
+ __u64 time_running; /* time event on cpu */
+ union {
+ __u64 capabilities;
+ struct {
+ __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
+ cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */
+
+ cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */
+ cap_user_time : 1, /* The time_* fields are used */
+ cap_user_time_zero : 1, /* The time_zero field is used */
+ cap_____res : 59;
+ };
+ };
+
+ /*
+ * If cap_usr_rdpmc this field provides the bit-width of the value
+ * read using the rdpmc() or equivalent instruction. This can be used
+ * to sign extend the result like:
+ *
+ * pmc <<= 64 - width;
+ * pmc >>= 64 - width; // signed shift right
+ * count += pmc;
+ */
+ __u16 pmc_width;
+
+ /*
+ * If cap_usr_time the below fields can be used to compute the time
+ * delta since time_enabled (in ns) using rdtsc or similar.
+ *
+ * u64 quot, rem;
+ * u64 delta;
+ *
+ * quot = (cyc >> time_shift);
+ * rem = cyc & ((1 << time_shift) - 1);
+ * delta = time_offset + quot * time_mult +
+ * ((rem * time_mult) >> time_shift);
+ *
+ * Where time_offset,time_mult,time_shift and cyc are read in the
+ * seqcount loop described above. This delta can then be added to
+ * enabled and possible running (if idx), improving the scaling:
+ *
+ * enabled += delta;
+ * if (idx)
+ * running += delta;
+ *
+ * quot = count / running;
+ * rem = count % running;
+ * count = quot * enabled + (rem * enabled) / running;
+ */
+ __u16 time_shift;
+ __u32 time_mult;
+ __u64 time_offset;
+ /*
+ * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
+ * from sample timestamps.
+ *
+ * time = timestamp - time_zero;
+ * quot = time / time_mult;
+ * rem = time % time_mult;
+ * cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
+ *
+ * And vice versa:
+ *
+ * quot = cyc >> time_shift;
+ * rem = cyc & ((1 << time_shift) - 1);
+ * timestamp = time_zero + quot * time_mult +
+ * ((rem * time_mult) >> time_shift);
+ */
+ __u64 time_zero;
+ __u32 size; /* Header size up to __reserved[] fields. */
+
+ /*
+ * Hole for extension of the self monitor capabilities
+ */
+
+ __u8 __reserved[118*8+4]; /* align to 1k. */
+
+ /*
+ * Control data for the mmap() data buffer.
+ *
+ * User-space reading the @data_head value should issue an smp_rmb(),
+ * after reading this value.
+ *
+ * When the mapping is PROT_WRITE the @data_tail value should be
+ * written by userspace to reflect the last read data, after issueing
+ * an smp_mb() to separate the data read from the ->data_tail store.
+ * In this case the kernel will not over-write unread data.
+ *
+ * See perf_output_put_handle() for the data ordering.
+ */
+ __u64 data_head; /* head in the data section */
+ __u64 data_tail; /* user-space written tail */
+};
+
+#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
+#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
+#define PERF_RECORD_MISC_KERNEL (1 << 0)
+#define PERF_RECORD_MISC_USER (2 << 0)
+#define PERF_RECORD_MISC_HYPERVISOR (3 << 0)
+#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0)
+#define PERF_RECORD_MISC_GUEST_USER (5 << 0)
+
+#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
+/*
+ * Indicates that the content of PERF_SAMPLE_IP points to
+ * the actual instruction that triggered the event. See also
+ * perf_event_attr::precise_ip.
+ */
+#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
+/*
+ * Reserve the last bit to indicate some extended misc field
+ */
+#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15)
+
+struct perf_event_header {
+ __u32 type;
+ __u16 misc;
+ __u16 size;
+};
+
+enum perf_event_type {
+
+ /*
+ * If perf_event_attr.sample_id_all is set then all event types will
+ * have the sample_type selected fields related to where/when
+ * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
+ * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
+ * just after the perf_event_header and the fields already present for
+ * the existing fields, i.e. at the end of the payload. That way a newer
+ * perf.data file will be supported by older perf tools, with these new
+ * optional fields being ignored.
+ *
+ * struct sample_id {
+ * { u32 pid, tid; } && PERF_SAMPLE_TID
+ * { u64 time; } && PERF_SAMPLE_TIME
+ * { u64 id; } && PERF_SAMPLE_ID
+ * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
+ * { u32 cpu, res; } && PERF_SAMPLE_CPU
+ * { u64 id; } && PERF_SAMPLE_IDENTIFIER
+ * } && perf_event_attr::sample_id_all
+ *
+ * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The
+ * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
+ * relative to header.size.
+ */
+
+ /*
+ * The MMAP events record the PROT_EXEC mappings so that we can
+ * correlate userspace IPs to code. They have the following structure:
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * char filename[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_MMAP = 1,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u64 id;
+ * u64 lost;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_LOST = 2,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * char comm[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_COMM = 3,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, ppid;
+ * u32 tid, ptid;
+ * u64 time;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_EXIT = 4,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u64 time;
+ * u64 id;
+ * u64 stream_id;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_THROTTLE = 5,
+ PERF_RECORD_UNTHROTTLE = 6,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, ppid;
+ * u32 tid, ptid;
+ * u64 time;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_FORK = 7,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, tid;
+ *
+ * struct read_format values;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_READ = 8,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ *
+ * #
+ * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
+ * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
+ * # is fixed relative to header.
+ * #
+ *
+ * { u64 id; } && PERF_SAMPLE_IDENTIFIER
+ * { u64 ip; } && PERF_SAMPLE_IP
+ * { u32 pid, tid; } && PERF_SAMPLE_TID
+ * { u64 time; } && PERF_SAMPLE_TIME
+ * { u64 addr; } && PERF_SAMPLE_ADDR
+ * { u64 id; } && PERF_SAMPLE_ID
+ * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
+ * { u32 cpu, res; } && PERF_SAMPLE_CPU
+ * { u64 period; } && PERF_SAMPLE_PERIOD
+ *
+ * { struct read_format values; } && PERF_SAMPLE_READ
+ *
+ * { u64 nr,
+ * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
+ *
+ * #
+ * # The RAW record below is opaque data wrt the ABI
+ * #
+ * # That is, the ABI doesn't make any promises wrt to
+ * # the stability of its content, it may vary depending
+ * # on event, hardware, kernel version and phase of
+ * # the moon.
+ * #
+ * # In other words, PERF_SAMPLE_RAW contents are not an ABI.
+ * #
+ *
+ * { u32 size;
+ * char data[size];}&& PERF_SAMPLE_RAW
+ *
+ * { u64 nr;
+ * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+ *
+ * { u64 abi; # enum perf_sample_regs_abi
+ * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
+ *
+ * { u64 size;
+ * char data[size];
+ * u64 dyn_size; } && PERF_SAMPLE_STACK_USER
+ *
+ * { u64 weight; } && PERF_SAMPLE_WEIGHT
+ * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
+ * };
+ */
+ PERF_RECORD_SAMPLE = 9,
+
+ /*
+ * The MMAP2 records are an augmented version of MMAP, they add
+ * maj, min, ino numbers to be used to uniquely identify each mapping
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * u32 maj;
+ * u32 min;
+ * u64 ino;
+ * u64 ino_generation;
+ * char filename[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_MMAP2 = 10,
+
+ PERF_RECORD_MAX, /* non-ABI */
+};
+
+#define PERF_MAX_STACK_DEPTH 127
+
+enum perf_callchain_context {
+ PERF_CONTEXT_HV = (__u64)-32,
+ PERF_CONTEXT_KERNEL = (__u64)-128,
+ PERF_CONTEXT_USER = (__u64)-512,
+
+ PERF_CONTEXT_GUEST = (__u64)-2048,
+ PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176,
+ PERF_CONTEXT_GUEST_USER = (__u64)-2560,
+
+ PERF_CONTEXT_MAX = (__u64)-4095,
+};
+
+#define PERF_FLAG_FD_NO_GROUP (1U << 0)
+#define PERF_FLAG_FD_OUTPUT (1U << 1)
+#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */
+
+union perf_mem_data_src {
+ __u64 val;
+ struct {
+ __u64 mem_op:5, /* type of opcode */
+ mem_lvl:14, /* memory hierarchy level */
+ mem_snoop:5, /* snoop mode */
+ mem_lock:2, /* lock instr */
+ mem_dtlb:7, /* tlb access */
+ mem_rsvd:31;
+ };
+};
+
+/* type of opcode (load/store/prefetch,code) */
+#define PERF_MEM_OP_NA 0x01 /* not available */
+#define PERF_MEM_OP_LOAD 0x02 /* load instruction */
+#define PERF_MEM_OP_STORE 0x04 /* store instruction */
+#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */
+#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */
+#define PERF_MEM_OP_SHIFT 0
+
+/* memory hierarchy (memory level, hit or miss) */
+#define PERF_MEM_LVL_NA 0x01 /* not available */
+#define PERF_MEM_LVL_HIT 0x02 /* hit level */
+#define PERF_MEM_LVL_MISS 0x04 /* miss level */
+#define PERF_MEM_LVL_L1 0x08 /* L1 */
+#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */
+#define PERF_MEM_LVL_L2 0x20 /* L2 */
+#define PERF_MEM_LVL_L3 0x40 /* L3 */
+#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */
+#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */
+#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */
+#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */
+#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */
+#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */
+#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */
+#define PERF_MEM_LVL_SHIFT 5
+
+/* snoop mode */
+#define PERF_MEM_SNOOP_NA 0x01 /* not available */
+#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */
+#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */
+#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */
+#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */
+#define PERF_MEM_SNOOP_SHIFT 19
+
+/* locked instruction */
+#define PERF_MEM_LOCK_NA 0x01 /* not available */
+#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */
+#define PERF_MEM_LOCK_SHIFT 24
+
+/* TLB access */
+#define PERF_MEM_TLB_NA 0x01 /* not available */
+#define PERF_MEM_TLB_HIT 0x02 /* hit level */
+#define PERF_MEM_TLB_MISS 0x04 /* miss level */
+#define PERF_MEM_TLB_L1 0x08 /* L1 */
+#define PERF_MEM_TLB_L2 0x10 /* L2 */
+#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/
+#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
+#define PERF_MEM_TLB_SHIFT 26
+
+#define PERF_MEM_S(a, s) \
+ (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
+
+/*
+ * single taken branch record layout:
+ *
+ * from: source instruction (may not always be a branch insn)
+ * to: branch target
+ * mispred: branch target was mispredicted
+ * predicted: branch target was predicted
+ *
+ * support for mispred, predicted is optional. In case it
+ * is not supported mispred = predicted = 0.
+ *
+ * in_tx: running in a hardware transaction
+ * abort: aborting a hardware transaction
+ */
+struct perf_branch_entry {
+ __u64 from;
+ __u64 to;
+ __u64 mispred:1, /* target mispredicted */
+ predicted:1,/* target predicted */
+ in_tx:1, /* in transaction */
+ abort:1, /* transaction abort */
+ reserved:60;
+};
+
+#endif /* _LINUX_PERF_EVENT_H */
diff --git a/tools/gator/daemon/k/perf_event.h b/tools/gator/daemon/k/perf_event.h
new file mode 120000
index 000000000000..e5dff8c21ef4
--- /dev/null
+++ b/tools/gator/daemon/k/perf_event.h
@@ -0,0 +1 @@
+perf_event.3.12.h \ No newline at end of file
diff --git a/tools/gator/daemon/main.cpp b/tools/gator/daemon/main.cpp
index bfd36b98766c..1275aef1cb79 100644
--- a/tools/gator/daemon/main.cpp
+++ b/tools/gator/daemon/main.cpp
@@ -1,32 +1,30 @@
/**
- * 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
* published by the Free Software Foundation.
*/
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-#include <sys/prctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
+#include <arpa/inet.h>
#include <fcntl.h>
+#include <pthread.h>
#include <sys/mman.h>
-#include <sys/time.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
#include <sys/resource.h>
-#include <arpa/inet.h>
#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
#include "Child.h"
-#include "SessionData.h"
-#include "OlySocket.h"
+#include "KMod.h"
#include "Logging.h"
+#include "OlySocket.h"
#include "OlyUtility.h"
-#include "KMod.h"
+#include "SessionData.h"
#define DEBUG false
@@ -34,7 +32,7 @@ extern Child* child;
static int shutdownFilesystem();
static pthread_mutex_t numSessions_mutex;
static int numSessions = 0;
-static OlySocket* sock = NULL;
+static OlyServerSocket* sock = NULL;
static bool driverRunningAtStart = false;
static bool driverMountedAtStart = false;
@@ -157,6 +155,7 @@ typedef struct {
static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 };
static void* answerThread(void* pVoid) {
+ prctl(PR_SET_NAME, (unsigned long)&"gatord-discover", 0, 0, 0);
const struct cmdline_t * const cmdline = (struct cmdline_t *)pVoid;
RVIConfigureInfo dstAns;
int req = udpPort(UDP_REQ_PORT);
@@ -231,16 +230,7 @@ static bool init_module (const char * const location) {
return ret;
}
-static int setupFilesystem(char* module) {
- int retval;
-
- // Verify root permissions
- uid_t euid = geteuid();
- if (euid) {
- logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
- handleException();
- }
-
+static bool setupFilesystem(char* module) {
if (module) {
// unmount and rmmod if the module was specified on the commandline, i.e. ensure that the specified module is indeed running
shutdownFilesystem();
@@ -252,7 +242,7 @@ static int setupFilesystem(char* module) {
}
}
- retval = mountGatorFS();
+ const int retval = mountGatorFS();
if (retval == 1) {
logg->logMessage("Driver already running at startup");
driverRunningAtStart = true;
@@ -274,8 +264,8 @@ static int setupFilesystem(char* module) {
}
if (access(location, F_OK) == -1) {
- logg->logError(__FILE__, __LINE__, "Unable to locate gator.ko driver:\n >>> gator.ko should be co-located with gatord in the same directory\n >>> OR insmod gator.ko prior to launching gatord\n >>> OR specify the location of gator.ko on the command line");
- handleException();
+ // The gator kernel is not already loaded and unable to locate gator.ko
+ return false;
}
// Load driver
@@ -296,7 +286,7 @@ static int setupFilesystem(char* module) {
}
}
- return 0;
+ return true;
}
static int shutdownFilesystem() {
@@ -418,8 +408,28 @@ int main(int argc, char** argv) {
// Parse the command line parameters
struct cmdline_t cmdline = parseCommandLine(argc, argv);
+ // Verify root permissions
+ uid_t euid = geteuid();
+ if (euid) {
+ logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
+ handleException();
+ }
+
// Call before setting up the SIGCHLD handler, as system() spawns child processes
- setupFilesystem(cmdline.module);
+ if (!setupFilesystem(cmdline.module)) {
+ logg->logMessage("Unable to setup gatorfs, trying perf");
+ if (!gSessionData->perf.setup()) {
+ logg->logError(__FILE__, __LINE__,
+ "Unable to locate gator.ko driver:\n"
+ " >>> gator.ko should be co-located with gatord in the same directory\n"
+ " >>> OR insmod gator.ko prior to launching gatord\n"
+ " >>> OR specify the location of gator.ko on the command line\n"
+ " >>> OR run Linux 3.12 or later with perf support to collect data via userspace only");
+ handleException();
+ }
+ }
+
+ gSessionData->hwmon.setup();
// Handle child exit codes
signal(SIGCHLD, child_exit);
@@ -439,11 +449,11 @@ int main(int argc, char** argv) {
logg->logError(__FILE__, __LINE__, "Failed to create answer thread");
handleException();
}
- sock = new OlySocket(cmdline.port, true);
+ sock = new OlyServerSocket(cmdline.port);
// Forever loop, can be exited via a signal or exception
while (1) {
logg->logMessage("Waiting on connection...");
- sock->acceptConnection();
+ OlySocket client(sock->acceptConnection());
int pid = fork();
if (pid < 0) {
@@ -452,13 +462,13 @@ int main(int argc, char** argv) {
} else if (pid == 0) {
// Child
sock->closeServerSocket();
- child = new Child(sock, numSessions + 1);
+ child = new Child(&client, numSessions + 1);
child->run();
delete child;
exit(0);
} else {
// Parent
- sock->closeSocket();
+ client.closeSocket();
pthread_mutex_lock(&numSessions_mutex);
numSessions++;