gator: Version 5.18
authorJon Medhurst <tixy@linaro.org>
Thu, 10 Apr 2014 08:02:02 +0000 (09:02 +0100)
committerJon Medhurst <tixy@linaro.org>
Thu, 10 Apr 2014 11:11:17 +0000 (12:11 +0100)
Signed-off-by: Jon Medhurst <tixy@linaro.org>
121 files changed:
drivers/gator/Kconfig [new file with mode: 0644]
drivers/gator/gator.h
drivers/gator/gator_annotate.c
drivers/gator/gator_annotate_kernel.c
drivers/gator/gator_backtrace.c
drivers/gator/gator_buffer.c [new file with mode: 0644]
drivers/gator/gator_buffer_write.c [new file with mode: 0644]
drivers/gator/gator_cookies.c
drivers/gator/gator_events_armv6.c
drivers/gator/gator_events_armv7.c
drivers/gator/gator_events_block.c
drivers/gator/gator_events_ccn-504.c
drivers/gator/gator_events_irq.c
drivers/gator/gator_events_l2c-310.c
drivers/gator/gator_events_mali_4xx.c
drivers/gator/gator_events_mali_4xx.h
drivers/gator/gator_events_mali_common.c
drivers/gator/gator_events_mali_common.h
drivers/gator/gator_events_mali_t6xx.c
drivers/gator/gator_events_mali_t6xx_hw.c
drivers/gator/gator_events_mali_t6xx_hw_test.c
drivers/gator/gator_events_meminfo.c
drivers/gator/gator_events_mmapped.c
drivers/gator/gator_events_net.c
drivers/gator/gator_events_perf_pmu.c
drivers/gator/gator_events_sched.c
drivers/gator/gator_events_scorpion.c
drivers/gator/gator_fs.c
drivers/gator/gator_hrtimer_gator.c
drivers/gator/gator_hrtimer_perf.c [deleted file]
drivers/gator/gator_iks.c
drivers/gator/gator_main.c
drivers/gator/gator_marshaling.c
drivers/gator/gator_pack.c [deleted file]
drivers/gator/gator_trace_gpu.c
drivers/gator/gator_trace_gpu.h
drivers/gator/gator_trace_power.c
drivers/gator/gator_trace_sched.c
drivers/gator/mali/mali_mjollnir_profiling_gator_api.h
drivers/gator/mali/mali_utgard_profiling_gator_api.h
drivers/gator/mali_t6xx.mk
tools/gator/daemon/Android.mk
tools/gator/daemon/Buffer.cpp
tools/gator/daemon/Buffer.h
tools/gator/daemon/CapturedXML.cpp
tools/gator/daemon/CapturedXML.h
tools/gator/daemon/Child.cpp
tools/gator/daemon/Child.h
tools/gator/daemon/Collector.cpp [deleted file]
tools/gator/daemon/Collector.h [deleted file]
tools/gator/daemon/Config.h [new file with mode: 0644]
tools/gator/daemon/ConfigurationXML.cpp
tools/gator/daemon/ConfigurationXML.h
tools/gator/daemon/Counter.h
tools/gator/daemon/Driver.cpp
tools/gator/daemon/Driver.h
tools/gator/daemon/DriverSource.cpp [new file with mode: 0644]
tools/gator/daemon/DriverSource.h [new file with mode: 0644]
tools/gator/daemon/DynBuf.cpp [new file with mode: 0644]
tools/gator/daemon/DynBuf.h [new file with mode: 0644]
tools/gator/daemon/EventsXML.cpp
tools/gator/daemon/EventsXML.h
tools/gator/daemon/ExternalSource.cpp [new file with mode: 0644]
tools/gator/daemon/ExternalSource.h [new file with mode: 0644]
tools/gator/daemon/Fifo.cpp
tools/gator/daemon/Fifo.h
tools/gator/daemon/Hwmon.cpp
tools/gator/daemon/Hwmon.h
tools/gator/daemon/KMod.cpp
tools/gator/daemon/KMod.h
tools/gator/daemon/LocalCapture.cpp
tools/gator/daemon/LocalCapture.h
tools/gator/daemon/Logging.cpp
tools/gator/daemon/Logging.h
tools/gator/daemon/Monitor.cpp [new file with mode: 0644]
tools/gator/daemon/Monitor.h [new file with mode: 0644]
tools/gator/daemon/OlySocket.cpp
tools/gator/daemon/OlySocket.h
tools/gator/daemon/OlyUtility.cpp
tools/gator/daemon/OlyUtility.h
tools/gator/daemon/PerfBuffer.cpp [new file with mode: 0644]
tools/gator/daemon/PerfBuffer.h [new file with mode: 0644]
tools/gator/daemon/PerfDriver.cpp [new file with mode: 0644]
tools/gator/daemon/PerfDriver.h [new file with mode: 0644]
tools/gator/daemon/PerfGroup.cpp [new file with mode: 0644]
tools/gator/daemon/PerfGroup.h [new file with mode: 0644]
tools/gator/daemon/PerfSource.cpp [new file with mode: 0644]
tools/gator/daemon/PerfSource.h [new file with mode: 0644]
tools/gator/daemon/Proc.cpp [new file with mode: 0644]
tools/gator/daemon/Proc.h [new file with mode: 0644]
tools/gator/daemon/Sender.cpp
tools/gator/daemon/Sender.h
tools/gator/daemon/SessionData.cpp
tools/gator/daemon/SessionData.h
tools/gator/daemon/SessionXML.cpp
tools/gator/daemon/SessionXML.h
tools/gator/daemon/Source.cpp [new file with mode: 0644]
tools/gator/daemon/Source.h [new file with mode: 0644]
tools/gator/daemon/StreamlineSetup.cpp
tools/gator/daemon/StreamlineSetup.h
tools/gator/daemon/UEvent.cpp [new file with mode: 0644]
tools/gator/daemon/UEvent.h [new file with mode: 0644]
tools/gator/daemon/UserSpaceSource.cpp [new file with mode: 0644]
tools/gator/daemon/UserSpaceSource.h [new file with mode: 0644]
tools/gator/daemon/common.mk
tools/gator/daemon/configuration.xml [deleted file]
tools/gator/daemon/defaults.xml [new file with mode: 0644]
tools/gator/daemon/escape.c
tools/gator/daemon/events-Cortex-A12.xml
tools/gator/daemon/events-Cortex-A15.xml
tools/gator/daemon/events-Cortex-A5.xml
tools/gator/daemon/events-Cortex-A7.xml
tools/gator/daemon/events-Cortex-A8.xml
tools/gator/daemon/events-Cortex-A9.xml
tools/gator/daemon/events-Linux.xml
tools/gator/daemon/events-Mali-4xx.xml
tools/gator/daemon/events-Mali-T6xx.xml
tools/gator/daemon/events-Perf-Hardware.xml [new file with mode: 0644]
tools/gator/daemon/k/perf_event.3.12.h [new file with mode: 0644]
tools/gator/daemon/k/perf_event.h [new symlink]
tools/gator/daemon/main.cpp

diff --git a/drivers/gator/Kconfig b/drivers/gator/Kconfig
new file mode 100644 (file)
index 0000000..e46ccb9
--- /dev/null
@@ -0,0 +1,39 @@
+config GATOR
+       tristate "Gator module for ARM's Streamline Performance Analyzer"
+       default m if (ARM || ARM64)
+       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
+
+choice
+       prompt "Enable Mali GPU support in Gator"
+       depends on GATOR
+       optional
+       help
+         Enable Mali GPU support in Gator
+
+config GATOR_MALI_4XXMP
+       bool "Mali-400MP or Mali-450MP"
+       select GATOR_WITH_MALI_SUPPORT
+
+config GATOR_MALI_T6XX
+       bool "Mali-T604 or Mali-T658"
+       select GATOR_WITH_MALI_SUPPORT
+
+endchoice
+
+config GATOR_MALI_PATH
+       string "Path to Mali driver"
+       depends on GATOR_WITH_MALI_SUPPORT
+       default "drivers/gpu/arm/mali400mp"
+       help
+         The gator code adds this to its include path so it can get the Mali
+         trace headers with: #include "linux/mali_linux_trace.h"
index d8981ed85a6a101cbfa5aadcfda9af4f99859a54..586cd9e742fb14bc2a6d2e8f808fe5539ec95919 100644 (file)
@@ -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
  ******************************************************************************/
index 5b9399bea230c7cccd982bc81ba49216786175af..7e2c6e5d871510033cb92c971a9a53235023b601 100644 (file)
@@ -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
index a406e4882974ba27571d7dadb12feaf1050103e8..0108068255297285859854a15bc632579365de15 100644 (file)
@@ -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;
index ffacb490194cb60a7161bea3b2f7886f1b732891..9f305cf7242c8c2b3a196a13d7e3ad5e6e1811b7 100644 (file)
@@ -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 (file)
index 0000000..eba22df
--- /dev/null
@@ -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_buffer_write.c b/drivers/gator/gator_buffer_write.c
new file mode 100644 (file)
index 0000000..b621ba9
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * 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 gator_buffer_write_packed_int(int cpu, int buftype, int x)
+{
+       uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype];
+       uint32_t mask = gator_buffer_mask[buftype];
+       char *buffer = per_cpu(gator_buffer, cpu)[buftype];
+       int packedBytes = 0;
+       int more = true;
+       while (more) {
+               // low order 7 bits of x
+               char b = x & 0x7f;
+               x >>= 7;
+
+               if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
+                       more = false;
+               } else {
+                       b |= 0x80;
+               }
+
+               buffer[(write + packedBytes) & mask] = b;
+               packedBytes++;
+       }
+
+       per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask;
+}
+
+static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x)
+{
+       uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype];
+       uint32_t mask = gator_buffer_mask[buftype];
+       char *buffer = per_cpu(gator_buffer, cpu)[buftype];
+       int packedBytes = 0;
+       int more = true;
+       while (more) {
+               // low order 7 bits of x
+               char b = x & 0x7f;
+               x >>= 7;
+
+               if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
+                       more = false;
+               } else {
+                       b |= 0x80;
+               }
+
+               buffer[(write + packedBytes) & mask] = b;
+               packedBytes++;
+       }
+
+       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);
+}
index 91adfdde9be2e0246e3e173eb6ce14744704715d..5c7d842070e0097325cf6b4602dcfb8688e94c50 100644 (file)
@@ -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
 static uint32_t *gator_crc32_table;
 static unsigned int translate_buffer_mask;
 
+struct cookie_args {
+       struct task_struct *task;
+       const char *text;
+};
+
 static DEFINE_PER_CPU(char *, translate_text);
 static DEFINE_PER_CPU(uint32_t, cookie_next_key);
 static DEFINE_PER_CPU(uint64_t *, cookie_keys);
 static DEFINE_PER_CPU(uint32_t *, cookie_values);
 static DEFINE_PER_CPU(int, translate_buffer_read);
 static DEFINE_PER_CPU(int, translate_buffer_write);
-static DEFINE_PER_CPU(void **, translate_buffer);
+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);
 
@@ -109,36 +114,62 @@ static void cookiemap_add(uint64_t key, uint32_t value)
 }
 
 #ifndef CONFIG_PREEMPT_RT_FULL
-static void translate_buffer_write_ptr(int cpu, void *x)
+static void translate_buffer_write_args(int cpu, struct task_struct *task, const char *text)
 {
-       per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_write, cpu)++] = x;
-       per_cpu(translate_buffer_write, cpu) &= translate_buffer_mask;
+       unsigned long flags;
+       int write;
+       int next_write;
+       struct cookie_args *args;
+
+       local_irq_save(flags);
+
+       write = per_cpu(translate_buffer_write, cpu);
+       next_write = (write + 1) & translate_buffer_mask;
+
+       // At least one entry must always remain available as when read == write, the queue is empty not full
+       if (next_write != per_cpu(translate_buffer_read, cpu)) {
+               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;
+       }
+
+       local_irq_restore(flags);
 }
 #endif
 
-static void *translate_buffer_read_ptr(int cpu)
+static void translate_buffer_read_args(int cpu, struct cookie_args *args)
 {
-       void *value = per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_read, cpu)++];
-       per_cpu(translate_buffer_read, cpu) &= translate_buffer_mask;
-       return value;
+       unsigned long flags;
+       int read;
+
+       local_irq_save(flags);
+
+       read = per_cpu(translate_buffer_read, cpu);
+       *args = per_cpu(translate_buffer, cpu)[read];
+       per_cpu(translate_buffer_read, cpu) = (read + 1) & translate_buffer_mask;
+
+       local_irq_restore(flags);
 }
 
 static void wq_cookie_handler(struct work_struct *unused)
 {
-       struct task_struct *task;
-       char *text;
+       struct cookie_args args;
        int cpu = get_physical_cpu(), cookie;
-       unsigned int commit;
 
        mutex_lock(&start_mutex);
 
        if (gator_started != 0) {
-               commit = per_cpu(translate_buffer_write, cpu);
-               while (per_cpu(translate_buffer_read, cpu) != commit) {
-                       task = (struct task_struct *)translate_buffer_read_ptr(cpu);
-                       text = (char *)translate_buffer_read_ptr(cpu);
-                       cookie = get_cookie(cpu, task, text, true);
-                       marshal_link(cookie, task->tgid, task->pid);
+               while (per_cpu(translate_buffer_read, cpu) != per_cpu(translate_buffer_write, cpu)) {
+                       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
                }
        }
 
@@ -169,15 +200,14 @@ static int translate_app_process(const char **text, int cpu, struct task_struct
        //   inconsistent during a context switch between android/linux versions
        if (!from_wq) {
                // Check if already in buffer
-               int ptr = per_cpu(translate_buffer_read, cpu);
-               while (ptr != per_cpu(translate_buffer_write, cpu)) {
-                       if (per_cpu(translate_buffer, cpu)[ptr] == (void *)task)
+               int pos = per_cpu(translate_buffer_read, cpu);
+               while (pos != per_cpu(translate_buffer_write, cpu)) {
+                       if (per_cpu(translate_buffer, cpu)[pos].task == task)
                                goto out;
-                       ptr = (ptr + 2) & translate_buffer_mask;
+                       pos = (pos + 1) & translate_buffer_mask;
                }
 
-               translate_buffer_write_ptr(cpu, (void *)task);
-               translate_buffer_write_ptr(cpu, (void *)*text);
+               translate_buffer_write_args(cpu, task, *text);
 
                // Not safe to call in RT-Preempt full in schedule switch context
                mod_timer(&app_process_wake_up_timer, jiffies + 1);
@@ -340,7 +370,7 @@ static int cookies_initialize(void)
                }
                memset(per_cpu(cookie_values, cpu), 0, size);
 
-               per_cpu(translate_buffer, cpu) = (void **)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL);
+               per_cpu(translate_buffer, cpu) = (struct cookie_args *)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL);
                if (!per_cpu(translate_buffer, cpu)) {
                        err = -ENOMEM;
                        goto cookie_setup_error;
index dd7974090b821d3e9bec339a9487ff8e864e6df6..353645622306048fbcd6f06e6af15da68a1544b0 100644 (file)
@@ -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
index 30881c8fd3fd94443d9e9781ab5c218b33939e09..153119b463e654c1cacc53633cfb412b69da9a43 100644 (file)
@@ -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;
        }
index 691ef2574536e580516c9e7057401f92bee04b6f..b2bc414e462e4df23b86e40abfa04ba55e9e974a 100644 (file)
@@ -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
index b89231967c75c75fc00bdeda5aa4fb1f9ffa9fec..024ffc2856aa0b7312ad84a89f0d680494c27bf4 100644 (file)
@@ -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
index b11879a248f831f130a8beb8eaf976a36ef582b5..facbdd62325eccbc722a82f516ac15652a7ad860 100644 (file)
@@ -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
index ee521af22517a0f9bcf6d597ddc0618298bd248d..553f9707bdbf6161b3b0d850c6e41556d8e7a1e8 100644 (file)
@@ -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
index 6719c1ec73a2e07be50b198c1928b59c9f2e5411..85d47645a9d9e0333ab245ee246da3ce2c0cb901 100644 (file)
@@ -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
index 413ad0ffe7943170359554583ad18694f67501f9..976ca8c4cfa1af78567327951a2ab1de2b094f04 100644 (file)
@@ -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
index 466ca1683c7e99f2baf82fd44de8073fe70ed161..dc58dcf0c6628cded90241571d3b4d31e0905372 100644 (file)
@@ -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
index 509f9b61884a3c6620d1c2520bc12ffc6384644e..41c2a3c13fae69ccc6c6aae407951f6a5872a882 100644 (file)
@@ -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
index 7bf7d6a6dbf9b0a09f08d61935ed297d319f6f28..76f14eee76764cda89ca2a48b26badf235b0538d 100644 (file)
@@ -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
 #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"
 
index e406991398d997fbf1ac32303f0c9742696766a0..dfbc91ffd765524bebb5e4bd06109ec593c82cab 100644 (file)
@@ -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
 #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"
 
index efb32ddf5483049cb79e3fca874f86286579f3d2..ba6553f3540f4bf1ae4641534f3561a2596de99a 100644 (file)
@@ -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
index 451290d9af1759fa5759a985a44df303b98089e4..c633dfdce3069c91ac6c19bb8b2d2ab694945dbb 100644 (file)
@@ -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
index f055e48d317adaa1c1c9c07ceda8f2614ecfca0b..3b248ec24e6e36b0c1013178d3158c5a423062a0 100644 (file)
@@ -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
index 9c8d3a43eaebd408ad7be01f66516ef83ddc7b8f..11c10e3755117ae317abfcebd720ad2d2f9b12f7 100644 (file)
@@ -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
index d472df918ab0f88069101261e35cc777efc125b7..8b2d67a058b36c77d8e3cc30e1e3ca831da6794f 100644 (file)
@@ -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
index 29f4e39e261c4214413dbf799cc8fcd91c4fd2f7..9e39158301820e0b33bd80d204650f59710ff2c0 100644 (file)
@@ -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
index c91db1219d080b62aa9585f8530a451b7c981863..8ca251af0e2672e4216f19b085d4b1f7cf3b3102 100644 (file)
@@ -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
index fe6f83d547e907fbbf5b374d054187b96d260b0e..166cfe7d681de292396163897aa4023d623b81d0 100644 (file)
@@ -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);
 }
index b0c947afe1e1631fcd5f7d5316137f1fb8435ad1..76584554b00fd1c0ae08a85af1ea1f21351488db 100644 (file)
@@ -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 (file)
index 7b95399..0000000
+++ /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
index 24233d775581b284fa76644d93f8bf35ff7f5eb0..e90dfcce93810258999e5aac782937c5b2ac969f 100644 (file)
@@ -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
@@ -147,11 +147,13 @@ static void gator_send_iks_core_names(void)
 {
        int cpu;
        // Send the cpu names
+       preempt_disable();
        for (cpu = 0; cpu < nr_cpu_ids; ++cpu) {
                if (mpidr_cpus[cpu] != NULL) {
                        gator_send_core_name(cpu, mpidr_cpus[cpu]->cpuid, mpidr_cpus[cpu]);
                }
        }
+       preempt_enable();
 }
 
 static int gator_migrate_start(void)
index 9773ae24d6f2d5345ea0bd0946eb5b32418c0d4b..e67f7c5cc61d02553bcf63d476b19e91fd6320f8 100644 (file)
@@ -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>
@@ -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,51 +288,52 @@ 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",
@@ -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;
                }
 
@@ -463,173 +480,6 @@ static bool buffer_commit_ready(int *cpu, int *buftype)
        return false;
 }
 
-/******************************************************************************
- * Buffer management
- ******************************************************************************/
-static int buffer_bytes_available(int cpu, int buftype)
-{
-       int remaining, filled;
-
-       filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype];
-       if (filled < 0) {
-               filled += gator_buffer_size[buftype];
-       }
-
-       remaining = gator_buffer_size[buftype] - filled;
-
-       if (per_cpu(buffer_space_available, cpu)[buftype]) {
-               // Give some extra room; also allows space to insert the overflow error packet
-               remaining -= 200;
-       } else {
-               // Hysteresis, prevents multiple overflow messages
-               remaining -= 2000;
-       }
-
-       return remaining;
-}
-
-static int contiguous_space_available(int cpu, int buftype)
-{
-       int remaining = buffer_bytes_available(cpu, buftype);
-       int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype];
-       if (remaining < contiguous)
-               return remaining;
-       else
-               return contiguous;
-}
-
-static bool buffer_check_space(int cpu, int buftype, int bytes)
-{
-       int remaining = buffer_bytes_available(cpu, buftype);
-
-       if (remaining < bytes) {
-               per_cpu(buffer_space_available, cpu)[buftype] = false;
-       } else {
-               per_cpu(buffer_space_available, cpu)[buftype] = true;
-       }
-
-       return per_cpu(buffer_space_available, cpu)[buftype];
-}
-
-static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len)
-{
-       int i;
-       u32 write = per_cpu(gator_buffer_write, cpu)[buftype];
-       u32 mask = gator_buffer_mask[buftype];
-       char *buffer = per_cpu(gator_buffer, cpu)[buftype];
-
-       for (i = 0; i < len; i++) {
-               buffer[write] = x[i];
-               write = (write + 1) & mask;
-       }
-
-       per_cpu(gator_buffer_write, cpu)[buftype] = write;
-}
-
-static void gator_buffer_write_string(int cpu, int buftype, const char *x)
-{
-       int len = strlen(x);
-       gator_buffer_write_packed_int(cpu, buftype, len);
-       gator_buffer_write_bytes(cpu, buftype, x, len);
-}
-
-static void gator_commit_buffer(int cpu, int buftype, u64 time)
-{
-       int type_length, commit, length, byte;
-
-       if (!per_cpu(gator_buffer, cpu)[buftype])
-               return;
-
-       // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
-       type_length = gator_response_type ? 1 : 0;
-       commit = per_cpu(gator_buffer_commit, cpu)[buftype];
-       length = per_cpu(gator_buffer_write, cpu)[buftype] - commit;
-       if (length < 0) {
-               length += gator_buffer_size[buftype];
-       }
-       length = length - type_length - sizeof(s32);
-
-       if (length <= FRAME_HEADER_SIZE) {
-               // Nothing to write, only the frame header is present
-               return;
-       }
-
-       for (byte = 0; byte < sizeof(s32); byte++) {
-               per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
-       }
-
-       per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
-
-       if (gator_live_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
  ******************************************************************************/
@@ -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;
index af80ff62e712c4e423ebea24af6cc08addd2a80a..fd413ad1331c03984a469bfe301da5ca5c0076ee 100644 (file)
@@ -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_pack.c b/drivers/gator/gator_pack.c
deleted file mode 100644 (file)
index 2c082f2..0000000
+++ /dev/null
@@ -1,58 +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.
- *
- */
-
-static void gator_buffer_write_packed_int(int cpu, int buftype, int x)
-{
-       uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype];
-       uint32_t mask = gator_buffer_mask[buftype];
-       char *buffer = per_cpu(gator_buffer, cpu)[buftype];
-       int packedBytes = 0;
-       int more = true;
-       while (more) {
-               // low order 7 bits of x
-               char b = x & 0x7f;
-               x >>= 7;
-
-               if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
-                       more = false;
-               } else {
-                       b |= 0x80;
-               }
-
-               buffer[(write + packedBytes) & mask] = b;
-               packedBytes++;
-       }
-
-       per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask;
-}
-
-static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x)
-{
-       uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype];
-       uint32_t mask = gator_buffer_mask[buftype];
-       char *buffer = per_cpu(gator_buffer, cpu)[buftype];
-       int packedBytes = 0;
-       int more = true;
-       while (more) {
-               // low order 7 bits of x
-               char b = x & 0x7f;
-               x >>= 7;
-
-               if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
-                       more = false;
-               } else {
-                       b |= 0x80;
-               }
-
-               buffer[(write + packedBytes) & mask] = b;
-               packedBytes++;
-       }
-
-       per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask;
-}
index be135b4aac563bbdabac6266383ca93c88054f27..6332098e595840d9ffe1797b22addf39d006fa60 100644 (file)
@@ -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
 #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) {
index bb0f42d290dabf3da30c6d1163ab83d24b9c805e..5113d459e24cc1109219bef49ddaaa482fc1cd1c 100644 (file)
@@ -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
index 272e05684ee8e7b790a780e6d5feb349d2ef0935..1895bb988c9fcb4559920fe214647dc72e2a8d10 100644 (file)
@@ -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
index 332b3f6ba965d99f6ab2dfc18255821028532ff2..52990e9d48117b868b5391ca2dbd4840514d2f68 100644 (file)
@@ -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++) {
index 347a4fe404bc8bd597d5365d9742aafa4c4c1be9..ff00d90cee78e79c1dff955ccfcff6ecbbc85a10 100644 (file)
@@ -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
index 559647a76d29096980b44e8c752731e836804cee..43c57604288037e4d3f453285b79a1f2e087a25b 100644 (file)
@@ -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
index 1a98c1c6a73fe3320b805ba41e834ad49dee9675..059d47aec910cb98b0caa600c7f7a58b9d193fbd 100644 (file)
@@ -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
index a0429712fa82267f0db9430c4dff2bae61c338c3..045d028fda5f5176d8f2e2ab966732efa2da1a4d 100644 (file)
@@ -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 \
index 090a71553277b6ab74073552c106a627688b2588..93557dabed9f1835910243ab7cff0802ad3d38fe 100644 (file)
@@ -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
 #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;
 }
index b3c8d78cf758af6cffbacd0a8e5e43bee2e4c5b2..50237771860c184d1c03b8c2a2687cadd8aed9d9 100644 (file)
@@ -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 &);
index 30c4c44c5d92dc6cdc9f87cc23d8ed53fafd83e7..cf79b72a1166966a2e1f71d0aff8a26a7befa59a 100644 (file)
@@ -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");
index b0482f593c6f8444fb56f242bd855b035f5a4de7..efc1e52bdba33519fb83f8a0af02a8b835995ff5 100644 (file)
@@ -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
index 9ee2ef8afb9d582225cb0823151758138e9b119c..ca33561ffdca6d21dbacb4af3b8d4d23d252c5fc 100644 (file)
@@ -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;
 }
index 0330e9d780276c1228e95c3eabcae708dedb8390..9e206d7113b8353d3375f08fdff409ed1a1c5570 100644 (file)
@@ -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.cpp b/tools/gator/daemon/Collector.cpp
deleted file mode 100644 (file)
index bf73534..0000000
+++ /dev/null
@@ -1,221 +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.
- */
-
-#define __STDC_FORMAT_MACROS
-
-#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 "Logging.h"
-#include "Sender.h"
-
-// Driver initialization independent of session settings
-Collector::Collector() {
-       mBufferFD = 0;
-
-       checkVersion();
-
-       int enable = -1;
-       if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) {
-               logg->logError(__FILE__, __LINE__, "Driver already enabled, possibly a session is already in progress.");
-               handleException();
-       }
-
-       readIntDriver("/dev/gator/cpu_cores", &gSessionData->mCores);
-       if (gSessionData->mCores == 0) {
-               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() {
-       // Write zero for safety, as a zero should have already been written
-       writeDriver("/dev/gator/enable", "0");
-
-       // Calls event_buffer_release in the driver
-       if (mBufferFD) {
-               close(mBufferFD);
-       }
-}
-
-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();
-       }
-
-       // 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();
-               }
-       }
-}
-
-void Collector::start() {
-       // Set the maximum backtrace depth
-       if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) {
-               logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
-               handleException();
-       }
-
-       // open the buffer which calls userspace_buffer_open() in the driver
-       mBufferFD = open("/dev/gator/buffer", O_RDONLY);
-       if (mBufferFD < 0) {
-               logg->logError(__FILE__, __LINE__, "The gator driver did not set up properly. Please view the linux console or dmesg log for more information on the failure.");
-               handleException();
-       }
-
-       // set the tick rate of the profiling timer
-       if (writeReadDriver("/dev/gator/tick", &gSessionData->mSampleRate) != 0) {
-               logg->logError(__FILE__, __LINE__, "Unable to set the driver tick");
-               handleException();
-       }
-
-       // notify the kernel of the response type
-       int response_type = gSessionData->mLocalCapture ? 0 : RESPONSE_APC_DATA;
-       if (writeDriver("/dev/gator/response_type", response_type)) {
-               logg->logError(__FILE__, __LINE__, "Unable to write the response type");
-               handleException();
-       }
-
-       // Set the live rate
-       if (writeReadDriver("/dev/gator/live_rate", &gSessionData->mLiveRate)) {
-               logg->logError(__FILE__, __LINE__, "Unable to set the driver live rate");
-               handleException();
-       }
-
-       logg->logMessage("Start the driver");
-
-       // This command makes the driver start profiling by calling gator_op_start() in the driver
-       if (writeDriver("/dev/gator/enable", "1") != 0) {
-               logg->logError(__FILE__, __LINE__, "The gator driver did not start properly. Please view the linux console or dmesg log for more information on the failure.");
-               handleException();
-       }
-
-       lseek(mBufferFD, 0, SEEK_SET);
-}
-
-// These commands should cause the read() function in collect() to return
-void Collector::stop() {
-       // This will 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);
-
-       // 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);
-       }
-
-       // 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) {
-               return -1;
-       }
-       if (fscanf(file, "%u", value) != 1) {
-               fclose(file);
-               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) {
-               return -1;
-       }
-       if (fscanf(file, "%" SCNi64, value) != 1) {
-               fclose(file);
-               logg->logMessage("Invalid value in file %s", fullpath);
-               return -1;
-       }
-       fclose(file);
-       return 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);
-}
-
-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);
-}
-
-int Collector::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) {
-               close(fd);
-               logg->logMessage("Opened but could not write to %s", fullpath);
-               return -1;
-       }
-       close(fd);
-       return 0;
-}
-
-int Collector::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) {
-       if (writeDriver(path, *value) || readInt64Driver(path, value)) {
-               return -1;
-       }
-       return 0;
-}
diff --git a/tools/gator/daemon/Collector.h b/tools/gator/daemon/Collector.h
deleted file mode 100644 (file)
index c5e9eac..0000000
+++ /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 (file)
index 0000000..6f5e2aa
--- /dev/null
@@ -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
index 2a5252a5bb04933f29e84411c049f0f1d5b2d5d9..fd479f2452cd0267bbbbbed280335ae524843924 100644 (file)
@@ -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) {
index 5650f487b990a45f16e047bc16c0ca573bc4986f..efa415e508b6fd17c78250160ebcd0621f895668 100644 (file)
@@ -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
index 231a85d6e3b55d5c57597f37ce663206d8b34dc8..689174573e4e5518292a6f06034ab947199f04c2 100644 (file)
@@ -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;
index c262467dc219c18ec8c40a175de5530e7d8ff646..09e04016291232477fc2d4d38ff8a75ec48b0dc9 100644 (file)
@@ -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
index f3a932f852cb089a9cb970a8b5a10fdf6e21da5c..e5ed7b6c1295993bcc454a5b55efbb814b129129 100644 (file)
@@ -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/DriverSource.cpp b/tools/gator/daemon/DriverSource.cpp
new file mode 100644 (file)
index 0000000..f78ec6b
--- /dev/null
@@ -0,0 +1,276 @@
+/**
+ * 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.
+ */
+
+#define __STDC_FORMAT_MACROS
+
+#include "DriverSource.h"
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include "Child.h"
+#include "Fifo.h"
+#include "Logging.h"
+#include "Sender.h"
+#include "SessionData.h"
+
+extern Child *child;
+
+DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) {
+       int driver_version = 0;
+
+       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) {
+               logg->logError(__FILE__, __LINE__, "Driver already enabled, possibly a session is already in progress.");
+               handleException();
+       }
+
+       readIntDriver("/dev/gator/cpu_cores", &gSessionData->mCores);
+       if (gSessionData->mCores == 0) {
+               gSessionData->mCores = 1;
+       }
+
+       if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) {
+               logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size");
+               handleException();
+       }
+}
+
+DriverSource::~DriverSource() {
+       delete mFifo;
+
+       // Write zero for safety, as a zero should have already been written
+       writeDriver("/dev/gator/enable", "0");
+
+       // Calls event_buffer_release in the driver
+       if (mBufferFD) {
+               close(mBufferFD);
+       }
+}
+
+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);
+
+       return true;
+}
+
+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");
+               handleException();
+       }
+
+       // open the buffer which calls userspace_buffer_open() in the driver
+       mBufferFD = open("/dev/gator/buffer", O_RDONLY);
+       if (mBufferFD < 0) {
+               logg->logError(__FILE__, __LINE__, "The gator driver did not set up properly. Please view the linux console or dmesg log for more information on the failure.");
+               handleException();
+       }
+
+       // set the tick rate of the profiling timer
+       if (writeReadDriver("/dev/gator/tick", &gSessionData->mSampleRate) != 0) {
+               logg->logError(__FILE__, __LINE__, "Unable to set the driver tick");
+               handleException();
+       }
+
+       // notify the kernel of the response type
+       int response_type = gSessionData->mLocalCapture ? 0 : RESPONSE_APC_DATA;
+       if (writeDriver("/dev/gator/response_type", response_type)) {
+               logg->logError(__FILE__, __LINE__, "Unable to write the response type");
+               handleException();
+       }
+
+       // Set the live rate
+       if (writeReadDriver("/dev/gator/live_rate", &gSessionData->mLiveRate)) {
+               logg->logError(__FILE__, __LINE__, "Unable to set the driver live rate");
+               handleException();
+       }
+
+       logg->logMessage("Start the driver");
+
+       // This command makes the driver start profiling by calling gator_op_start() in the driver
+       if (writeDriver("/dev/gator/enable", "1") != 0) {
+               logg->logError(__FILE__, __LINE__, "The gator driver did not start properly. Please view the linux console or dmesg log for more information on the failure.");
+               handleException();
+       }
+
+       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");
+}
+
+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");
+       }
+}
+
+bool DriverSource::isDone() {
+       return mLength <= 0;
+}
+
+void DriverSource::write(Sender *sender) {
+       char *data = mFifo->read(&mLength);
+       if (data != NULL) {
+               sender->writeData(data, mLength, RESPONSE_APC_DATA);
+               mFifo->release();
+       }
+}
+
+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;
+       }
+       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;
+       }
+
+       return 0;
+}
+
+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;
+       }
+
+       const ssize_t bytes = read(fd, data, sizeof(data) - 1);
+       close(fd);
+       if (bytes < 0) {
+               return -1;
+       }
+       data[bytes] = '\0';
+
+       char *endptr;
+       errno = 0;
+       *value = strtoll(data, &endptr, 10);
+       if (errno != 0 || *endptr != '\n') {
+               logg->logMessage("Invalid value in file %s", fullpath);
+               return -1;
+       }
+
+       return 0;
+}
+
+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) {
+               close(fd);
+               logg->logMessage("Opened but could not write to %s", fullpath);
+               return -1;
+       }
+       close(fd);
+       return 0;
+}
+
+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 DriverSource::writeReadDriver(const char *path, int64_t *value) {
+       if (writeDriver(path, *value) || readInt64Driver(path, value)) {
+               return -1;
+       }
+       return 0;
+}
diff --git a/tools/gator/daemon/DriverSource.h b/tools/gator/daemon/DriverSource.h
new file mode 100644 (file)
index 0000000..dcf1078
--- /dev/null
@@ -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 (file)
index 0000000..6f92b33
--- /dev/null
@@ -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 (file)
index 0000000..2f4554a
--- /dev/null
@@ -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
index 2a80482e0b8d1f76b013519f225e5585081b17ff..a07a046f335367b7825f639b6d037800c458a54c 100644 (file)
@@ -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
index 8e693efab2021271e15d9add17a8b63d892bcea8..6cd1560f7d4e13d042281c31e1bdfe8288c054ba 100644 (file)
@@ -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 (file)
index 0000000..fe5824b
--- /dev/null
@@ -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 (file)
index 0000000..2052bdf
--- /dev/null
@@ -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
index 250a4d023bf265f72e170fdc24a5678421294cb7..f672e92a6807403c43274ad3705cc16a2dd2aee6 100644 (file)
@@ -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
index d25cd68825614a621eab87089fb877669d9ef7d3..7dd7426132d8c332c026a83879e20b20bfd7d0f5 100644 (file)
@@ -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))
index 1d7c0da9cc83673eb1beba18c72518f7f9e43380..778f30755dfe14a99bbb42f0ecf01051a5cb9851 100644 (file)
@@ -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 {
index 46bb42e898d7dee083cfe2e4f36823446de47470..a22a3609f99f81241e54f3f5a40ef7e0aa1c94cf 100644 (file)
@@ -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();
index 559297fe2274dd99780df1549fab53733d8e7c48..9300002f3fb2a41126b1c97d7f136e9b545aea2d 100644 (file)
@@ -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;
 }
index 797426290dfc752dd46e4a6ebe9379e68c5c6706..fb7fc8a8f9c6200fc31a9fe190d36d3d309370df 100644 (file)
@@ -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
index 3235a34ae9c718f76db3cc426d43cc9e7325b6e4..d2a4b799d7ac721e25f141054bff1d3bb86bba9e 100644 (file)
@@ -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"
index 8042d6a8dc37e11c1633f5fa952d0c1c736b0059..aadeccecf0ccf28b61c57ac79cc9f3efa1283a8d 100644 (file)
@@ -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
index 5fd45b54f90ad8371c9008ca4f4c52b29f899fcb..b8d3178950d6c5a119e69ac03b0faf706608bbaf 100644 (file)
@@ -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;
 
index 8f960de27bf35a9f4f529565a4ffc47ce00d8527..6ae328046989342db0fd4270896d72cbe090fe0e 100644 (file)
@@ -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 (file)
index 0000000..90d5c47
--- /dev/null
@@ -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 (file)
index 0000000..6e268b6
--- /dev/null
@@ -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
index ab5c3c2c89383d5b26ab916c2508134bd34629f7..26e4768f39342440d0c25a81a2bdd8c579d352a6 100644 (file)
@@ -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;
   }
index 5bab7d1f4cc46f4152443cae99254b012629ec51..eab786b304bf3907cfe361623751d8c7018126a9 100644 (file)
@@ -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);
 };
 
index 0b22d6ebd027c1c9148af424e8949acf754e9fda..45340a27d9fa5dd26a51dad284d69281603f353a 100644 (file)
@@ -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
index abab0a510a7c0cc5d1e10018aac64a537e79c834..1d26beb596fae3452939b266640f3d2899362085 100644 (file)
@@ -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 (file)
index 0000000..5fad583
--- /dev/null
@@ -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 (file)
index 0000000..278a3b9
--- /dev/null
@@ -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 (file)
index 0000000..8e25c22
--- /dev/null
@@ -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 (file)
index 0000000..3181b74
--- /dev/null
@@ -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 (file)
index 0000000..faf5fca
--- /dev/null
@@ -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 (file)
index 0000000..af496d4
--- /dev/null
@@ -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 (file)
index 0000000..1f1cb19
--- /dev/null
@@ -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 (file)
index 0000000..3f471c8
--- /dev/null
@@ -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 (file)
index 0000000..e0b9e22
--- /dev/null
@@ -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 (file)
index 0000000..057b610
--- /dev/null
@@ -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
index 8eb348ff3a069bd9319de78e4dbf53e4e2731bfe..3a981a6427be01ebbe0aa525cbb8b65ebed91184 100644 (file)
@@ -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;
index b388f039bad7d33ff89e04fdf6213f55216f23dc..4c359dba82f87b79be729583ea6a5d2ccc8bc1d8 100644 (file)
@@ -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
index cf844075401f919448e9a3e70b3a568fc3c9bb05..c169299af8720d0c16da229a0939264a81c21500 100644 (file)
@@ -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);
                        }
                }
        }
index c834251527cf22334e3a06f2346c20d9f97fbd09..ea34240e2df7c3ec271bf9b6917d7c45ba4037f8 100644 (file)
@@ -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
 
 #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;
index 0a0a02779176aa971d53d340ce15f46ca281b3d9..55b2f92807092ee071a2cfdbd8c36b43f435b590 100644 (file)
@@ -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 charstr) {
+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);
        }
 }
 
index 0fb03bd6627c75bd8344a308666cfc057e55cf7d..e146094a4d1751c260e356075fd36b322b1db849 100644 (file)
@@ -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 charstr);
+       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 (file)
index 0000000..60cf704
--- /dev/null
@@ -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 (file)
index 0000000..56ac3d6
--- /dev/null
@@ -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
index 2faada23f842094e7fc1cfeab7d3868529963abb..caa665e67193a9f88f378c290ce9b74d3aad3f91 100644 (file)
@@ -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);
index d6d9a6ea29919db845ec5c4777c56b28698adda1..74bb197e35ff2a563b10b53397ad5c47d8ac4b1e 100644 (file)
@@ -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 (file)
index 0000000..282e965
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * 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 <linux/netlink.h>
+#include <string.h>
+#include <sys/socket.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 (file)
index 0000000..2f7ef2c
--- /dev/null
@@ -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 (file)
index 0000000..debe696
--- /dev/null
@@ -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 (file)
index 0000000..fb5889d
--- /dev/null
@@ -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
index 031d169068817e3182ec3c3dd5e16487bb7da16f..d9dc14606b0716082cddfc4d5e95dd1d18dd9a39 100644 (file)
@@ -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/configuration.xml
deleted file mode 100644 (file)
index b44c00a..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configurations revision="3">
-  <configuration counter="ARM_ARM11_ccnt" event="0xff"/>
-  <configuration counter="ARM_ARM11_cnt0" event="0x7"/>
-  <configuration counter="ARM_ARM11_cnt1" event="0xb"/>
-  <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="ARM_Cortex-A53_ccnt" event="0x11"/>
-  <configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/>
-  <configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/>
-  <configuration counter="ARM_Cortex-A53_cnt2" event="0x10"/>
-  <configuration counter="ARM_Cortex-A53_cnt3" event="0x19"/>
-  <configuration counter="ARM_Cortex-A57_ccnt" event="0x11"/>
-  <configuration counter="ARM_Cortex-A57_cnt0" event="0x8"/>
-  <configuration counter="ARM_Cortex-A57_cnt1" event="0x16"/>
-  <configuration counter="ARM_Cortex-A57_cnt2" event="0x10"/>
-  <configuration counter="ARM_Cortex-A57_cnt3" event="0x19"/>
-  <configuration counter="Scorpion_ccnt" event="0xff"/>
-  <configuration counter="Scorpion_cnt0" event="0x08"/>
-  <configuration counter="Scorpion_cnt1" event="0x10"/>
-  <configuration counter="ScorpionMP_ccnt" event="0xff"/>
-  <configuration counter="ScorpionMP_cnt0" event="0x08"/>
-  <configuration counter="ScorpionMP_cnt1" event="0x10"/>
-  <configuration counter="Krait_ccnt" event="0xff"/>
-  <configuration counter="Krait_cnt0" event="0x08"/>
-  <configuration counter="Krait_cnt1" event="0x10"/>
-  <configuration counter="Linux_block_rq_wr"/>
-  <configuration counter="Linux_block_rq_rd"/>
-  <configuration counter="Linux_meminfo_memused"/>
-  <configuration counter="Linux_meminfo_memfree"/>
-  <configuration counter="Linux_power_cpu_freq"/>
-  <configuration counter="L2C-310_cnt0" event="0x1"/>
-</configurations>
diff --git a/tools/gator/daemon/defaults.xml b/tools/gator/daemon/defaults.xml
new file mode 100644 (file)
index 0000000..5bf096c
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configurations revision="3">
+  <configuration counter="ARM_ARM11_ccnt" event="0xff"/>
+  <configuration counter="ARM_ARM11_cnt0" event="0x7"/>
+  <configuration counter="ARM_ARM11_cnt1" event="0xb"/>
+  <configuration counter="ARM_ARM11MPCore_ccnt" event="0xff"/>
+  <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08"/>
+  <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b"/>
+  <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"/>
+  <configuration counter="ARM_Cortex-A53_cnt2" event="0x10"/>
+  <configuration counter="ARM_Cortex-A53_cnt3" event="0x19"/>
+  <configuration counter="ARM_Cortex-A57_ccnt" event="0x11"/>
+  <configuration counter="ARM_Cortex-A57_cnt0" event="0x8"/>
+  <configuration counter="ARM_Cortex-A57_cnt1" event="0x16"/>
+  <configuration counter="ARM_Cortex-A57_cnt2" event="0x10"/>
+  <configuration counter="ARM_Cortex-A57_cnt3" event="0x19"/>
+  <configuration counter="Scorpion_ccnt" event="0xff"/>
+  <configuration counter="Scorpion_cnt0" event="0x08"/>
+  <configuration counter="Scorpion_cnt1" event="0x10"/>
+  <configuration counter="ScorpionMP_ccnt" event="0xff"/>
+  <configuration counter="ScorpionMP_cnt0" event="0x08"/>
+  <configuration counter="ScorpionMP_cnt1" event="0x10"/>
+  <configuration counter="Krait_ccnt" event="0xff"/>
+  <configuration counter="Krait_cnt0" event="0x08"/>
+  <configuration counter="Krait_cnt1" event="0x10"/>
+  <configuration counter="Linux_block_rq_wr"/>
+  <configuration counter="Linux_block_rq_rd"/>
+  <configuration counter="Linux_meminfo_memused"/>
+  <configuration counter="Linux_meminfo_memfree"/>
+  <configuration counter="Linux_power_cpu_freq"/>
+  <configuration counter="L2C-310_cnt0" event="0x1"/>
+</configurations>
index 3eec1f8d38d34d2e2c3b5ce290b07c65a0c19d4b..c54aa1c3e75d9be24d0febffefbb8f13e80d13a9 100644 (file)
@@ -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
index 20a4772c45878d0ee5a5222f06c512a52db7564b..9c04354ad137b2fb4f34eaa0e152bc254994a4c7 100644 (file)
@@ -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"/>
index faa8b1cbcfb2c3a0f420297e678791650828079c..f50e55d6619502cd2aca0e9d7ce76473a70e92cd 100644 (file)
@@ -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"/>
index a5b15466be5221eb04abab8b3a5aac1a8d522063..d67581d77c08d3b41ac6a979138e69bdb2d0ceb9 100644 (file)
@@ -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"/>
index 54d7264bc08e49b93bfbf97057cdbffc5c970cb5..6e078b3cffa3d8562ec52bfd4cb5868670efe5c5 100644 (file)
@@ -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"/>
index f2518237983af904a8eeaab18cec9001f8001966..a69e25ab2c3483f6985d924a1ea55265fd682d29 100644 (file)
@@ -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"/>
index 75f09c80425e5f431fd7e8608777ea0a5bf8be4f..3e7f8289062e596f5bca5fa9c6f9ed118bbda606 100644 (file)
@@ -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"/>
index 31a90a1d6335e16a08bf3e37dbe2c836db3f3bfa..4d677e15db7e8546c0db6b4052c77575e5931f7c 100644 (file)
@@ -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>
 
index 8772ce410b95d18530b83703f17252bdc06e1468..5a71386830ba1ff627ca30f3051826c54c79e3e2 100644 (file)
     <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."/>
index 2465238a8bda8eeff71ba566d7932230af15cd77..ec9ca006f85fd6e7f2102537009171cdc578cc53 100644 (file)
@@ -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 (file)
index 0000000..423696f
--- /dev/null
@@ -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 (file)
index 0000000..e886c48
--- /dev/null
@@ -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 (symlink)
index 0000000..e5dff8c
--- /dev/null
@@ -0,0 +1 @@
+perf_event.3.12.h
\ No newline at end of file
index bfd36b98766c63319b76702d0845d75cc2a92c87..1275aef1cb7938ffe804f7168095c7cd47b6e187 100644 (file)
@@ -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++;