gator: Version 5.22
authorDrew Richardson <drew.richardson@arm.com>
Wed, 22 Jul 2015 19:00:00 +0000 (12:00 -0700)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Wed, 14 Dec 2016 04:49:42 +0000 (13:49 +0900)
Signed-off-by: Drew Richardson <drew.richardson@arm.com>
[Ported from https://github.com/ARM-software/gator.git to kernel tree, out of tree files are removed]
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
81 files changed:
drivers/gator/Makefile
drivers/gator/gator.h
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_irq.c
drivers/gator/gator_events_l2c-310.c
drivers/gator/gator_events_mali_4xx.c
drivers/gator/gator_events_mali_common.c
drivers/gator/gator_events_mali_midgard.c
drivers/gator/gator_events_mali_midgard_hw.c
drivers/gator/gator_events_mali_midgard_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_main.c
drivers/gator/gator_marshaling.c
drivers/gator/gator_trace_gpu.c
drivers/gator/gator_trace_sched.c
drivers/gator/mali_midgard.mk
tools/gator/daemon/Android.mk
tools/gator/daemon/AtraceDriver.cpp [new file with mode: 0644]
tools/gator/daemon/AtraceDriver.h [new file with mode: 0644]
tools/gator/daemon/Buffer.cpp
tools/gator/daemon/Buffer.h
tools/gator/daemon/CCNDriver.cpp
tools/gator/daemon/CCNDriver.h
tools/gator/daemon/CapturedXML.cpp
tools/gator/daemon/Child.cpp
tools/gator/daemon/Command.cpp
tools/gator/daemon/Config.h
tools/gator/daemon/ConfigurationXML.cpp
tools/gator/daemon/DiskIODriver.cpp
tools/gator/daemon/DriverSource.cpp
tools/gator/daemon/DriverSource.h
tools/gator/daemon/EventsXML.cpp
tools/gator/daemon/ExternalDriver.cpp [new file with mode: 0644]
tools/gator/daemon/ExternalDriver.h [new file with mode: 0644]
tools/gator/daemon/ExternalSource.cpp
tools/gator/daemon/ExternalSource.h
tools/gator/daemon/FtraceDriver.cpp
tools/gator/daemon/FtraceDriver.h
tools/gator/daemon/FtraceSource.cpp [deleted file]
tools/gator/daemon/FtraceSource.h [deleted file]
tools/gator/daemon/MaliVideoDriver.cpp
tools/gator/daemon/MaliVideoDriver.h
tools/gator/daemon/MemInfoDriver.cpp
tools/gator/daemon/NetDriver.cpp
tools/gator/daemon/PerfDriver.cpp
tools/gator/daemon/PerfDriver.h
tools/gator/daemon/PerfGroup.cpp
tools/gator/daemon/PerfSource.cpp
tools/gator/daemon/Proc.cpp
tools/gator/daemon/Sender.cpp
tools/gator/daemon/SessionData.cpp
tools/gator/daemon/SessionData.h
tools/gator/daemon/Setup.cpp
tools/gator/daemon/StreamlineSetup.cpp
tools/gator/daemon/UserSpaceSource.cpp
tools/gator/daemon/defaults.xml
tools/gator/daemon/events-CCI-400.xml
tools/gator/daemon/events-Cortex-A53.xml
tools/gator/daemon/events-Cortex-A57.xml
tools/gator/daemon/events-Cortex-A72.xml
tools/gator/daemon/events-Mali-4xx.xml
tools/gator/daemon/events-Mali-Midgard_hw.xml
tools/gator/daemon/events-Mali-V500.xml
tools/gator/daemon/events-atrace.xml [new file with mode: 0644]
tools/gator/daemon/events-ftrace.xml
tools/gator/daemon/k/perf_event.3.12.h [deleted file]
tools/gator/daemon/k/perf_event.h [changed from symlink to file mode: 0644]
tools/gator/daemon/main.cpp
tools/gator/daemon/notify/COPYING [new file with mode: 0644]
tools/gator/daemon/notify/Makefile [new file with mode: 0644]
tools/gator/daemon/notify/Notify.java [new file with mode: 0644]

index d14e2a0..4f97237 100644 (file)
@@ -77,7 +77,7 @@ clean-files := gator_src_md5.h
 silent_chk_events.h = :
 $(obj)/gator_src_md5.h: FORCE
        @$($(quiet)chk_events.h)
-       $(Q)cd $(srctree) && cd $(src) ; $(CONFIG_SHELL) -c "echo 'static char *gator_src_md5 = \"'\`ls *.c *.h mali/*.h | grep -Ev '^(gator_src_md5\.c|gator\.mod\.c)$$' | LC_ALL=C sort | xargs cat | md5sum | cut -b 1-32\`'\";'" > $(abspath $@)
+       $(Q)cd $(srctree) && cd $(src) ; $(CONFIG_SHELL) -c "echo 'static char *gator_src_md5 = \"'\`ls *.c *.h mali/*.h | grep -Ev '^(gator_src_md5\.h|gator\.mod\.c)$$' | LC_ALL=C sort | xargs cat | md5sum | cut -b 1-32\`'\";'" > $(abspath $@)
 
 else
 
index 202eb41..50b0180 100644 (file)
@@ -77,8 +77,8 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
 /******************************************************************************
  * Tracepoints
  ******************************************************************************/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
-#      error Kernels prior to 2.6.32 not supported
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
+#      error Kernels prior to 3.4.0 not supported. DS-5 v5.21 and earlier supported 2.6.32 and later.
 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
 #      define GATOR_DEFINE_PROBE(probe_name, proto) \
                static void probe_##probe_name(PARAMS(proto))
@@ -103,10 +103,15 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
                tracepoint_probe_unregister(gator_tracepoint_##probe_name, probe_##probe_name, NULL)
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+#define setup_deferrable_timer_on_stack setup_timer
+#endif
+
 /******************************************************************************
  * Events
  ******************************************************************************/
 struct gator_interface {
+       const char *const name;
        /* Complementary function to init */
        void (*shutdown)(void);
        int (*create_files)(struct super_block *sb, struct dentry *root);
@@ -120,11 +125,12 @@ struct gator_interface {
        /* called in process context but may not be running on core 'cpu' */
        void (*offline_dispatch)(int cpu, bool migrate);
        int (*read)(int **buffer, bool sched_switch);
-       int (*read64)(long long **buffer);
+       int (*read64)(long long **buffer, bool sched_switch);
        int (*read_proc)(long long **buffer, struct task_struct *);
        struct list_head list;
 };
 
+u64 gator_get_time(void);
 int gator_events_install(struct gator_interface *interface);
 int gator_events_get_key(void);
 u32 gator_cpuid(void);
index 9bd4c8b..7636726 100644 (file)
@@ -7,6 +7,29 @@
  *
  */
 
+#include <linux/mount.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+
+struct mount {
+       struct mount *mnt_parent;
+       struct dentry *mnt_mountpoint;
+       struct vfsmount mnt;
+};
+
+static inline struct mount *real_mount(struct vfsmount *mnt)
+{
+       return container_of(mnt, struct mount, mnt);
+}
+
+#define GET_MNT_ROOT(mount) (mount)->mnt.mnt_root
+
+#else
+
+#define GET_MNT_ROOT(mount) (mount)->mnt_root
+
+#endif
+
 /* must be power of 2 */
 #define COOKIEMAP_ENTRIES      1024
 /* must be a power of 2 - 512/4 = 128 entries */
@@ -23,6 +46,7 @@ struct cookie_args {
 };
 
 static DEFINE_PER_CPU(char *, translate_text);
+static DEFINE_PER_CPU(char *, scratch);
 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);
@@ -285,7 +309,7 @@ static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text,
                return cookie;
 
        /* On 64-bit android app_process can be app_process32 or app_process64 */
-       if (strncmp(text, APP_PROCESS, sizeof(APP_PROCESS) - 1) == 0) {
+       if (strstr(text, APP_PROCESS) != NULL) {
                if (!translate_app_process(&text, cpu, task, from_wq))
                        return UNRESOLVED_COOKIE;
        }
@@ -305,6 +329,75 @@ static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text,
        return cookie;
 }
 
+/* Can't call d_path in interrupt context so create something similar */
+static const char *gator_d_path(const struct path *path, char *buf, int buflen)
+{
+       struct dentry *dentry = path->dentry;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+       struct mount *mount = real_mount(path->mnt);
+#else
+       struct vfsmount *mount = path->mnt;
+#endif
+       int pos = buflen - 1;
+       int len;
+
+       buf[pos] = '\0';
+
+       for (;;) {
+               if (dentry == NULL) {
+                       pr_err("gator: dentry is null!\n");
+                       break;
+               }
+               if (dentry->d_name.name[0] == '\0') {
+                       pr_err("gator: path is empty string\n");
+                       break;
+               }
+               if (dentry->d_name.name[0] == '/' && dentry->d_name.name[1] == '\0') {
+                       /* Normal operation */
+                       /* pr_err("gator: path is /\n"); */
+                       break;
+               }
+
+               len = strlen(dentry->d_name.name);
+               if (pos < len) {
+                       pr_err("gator: path is too long\n");
+                       break;
+               }
+               pos -= len;
+               memcpy(buf + pos, dentry->d_name.name, len);
+
+               if (pos == 0) {
+                       pr_err("gator: no room for slash\n");
+                       /* Fall back to name only */
+                       return path->dentry->d_name.name;
+               }
+               --pos;
+               buf[pos] = '/';
+
+               if (dentry->d_parent == GET_MNT_ROOT(mount)) {
+                       /* pr_err("gator: filesystem is complete, moving to next '%s'\n", buf + pos); */
+                       dentry = mount->mnt_mountpoint;
+                       mount = mount->mnt_parent;
+                       continue;
+               }
+               if (dentry == dentry->d_parent) {
+                       pr_err("gator: parent is self\n");
+                       break;
+               }
+               dentry = dentry->d_parent;
+       }
+
+       if (pos < 0) {
+               pr_err("gator: pos is somenow negative\n");
+               /* Fall back to name only */
+               return path->dentry->d_name.name;
+       }
+
+       return buf + pos;
+}
+
+#define d_path gator_d_path
+
 static int get_exec_cookie(int cpu, struct task_struct *task)
 {
        struct mm_struct *mm = task->mm;
@@ -315,7 +408,7 @@ static int get_exec_cookie(int cpu, struct task_struct *task)
                return NO_COOKIE;
 
        if (task && task->mm && task->mm->exe_file) {
-               text = task->mm->exe_file->f_path.dentry->d_name.name;
+               text = d_path(&task->mm->exe_file->f_path, per_cpu(scratch, get_physical_cpu()), PAGE_SIZE);
                return get_cookie(cpu, task, text, false);
        }
 
@@ -337,7 +430,7 @@ static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsig
                        continue;
 
                if (vma->vm_file) {
-                       text = vma->vm_file->f_path.dentry->d_name.name;
+                       text = d_path(&vma->vm_file->f_path, per_cpu(scratch, get_physical_cpu()), PAGE_SIZE);
                        cookie = get_cookie(cpu, task, text, false);
                        *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
                } else {
@@ -394,6 +487,12 @@ static int cookies_initialize(void)
                        err = -ENOMEM;
                        goto cookie_setup_error;
                }
+
+               per_cpu(scratch, cpu) = kmalloc(PAGE_SIZE, GFP_KERNEL);
+               if (!per_cpu(scratch, cpu)) {
+                       err = -ENOMEM;
+                       goto cookie_setup_error;
+               }
        }
 
        /* build CRC32 table */
@@ -414,7 +513,7 @@ static int cookies_initialize(void)
                gator_crc32_table[i] = crc;
        }
 
-       setup_timer(&app_process_wake_up_timer, app_process_wake_up_handler, 0);
+       setup_deferrable_timer_on_stack(&app_process_wake_up_timer, app_process_wake_up_handler, 0);
 
 cookie_setup_error:
        return err;
@@ -438,6 +537,9 @@ static void cookies_release(void)
 
                kfree(per_cpu(translate_text, cpu));
                per_cpu(translate_text, cpu) = NULL;
+
+               kfree(per_cpu(scratch, cpu));
+               per_cpu(scratch, cpu) = NULL;
        }
 
        del_timer_sync(&app_process_wake_up_timer);
index 1783970..62bd6eb 100644 (file)
@@ -198,6 +198,7 @@ static int gator_events_armv6_read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_armv6_interface = {
+       .name = "armv6",
        .create_files = gator_events_armv6_create_files,
        .stop = gator_events_armv6_stop,
        .online = gator_events_armv6_online,
index e1f6a5f..0db857c 100644 (file)
@@ -263,6 +263,7 @@ static int gator_events_armv7_read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_armv7_interface = {
+       .name = "armv7",
        .create_files = gator_events_armv7_create_files,
        .stop = gator_events_armv7_stop,
        .online = gator_events_armv7_online,
index b3467b1..0bb4085 100644 (file)
@@ -142,6 +142,7 @@ static int gator_events_block_read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_block_interface = {
+       .name = "block",
        .create_files = gator_events_block_create_files,
        .start = gator_events_block_start,
        .stop = gator_events_block_stop,
index 81b976a..aa1ebbb 100644 (file)
@@ -144,6 +144,7 @@ static int gator_events_irq_read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_irq_interface = {
+       .name = "irq",
        .create_files = gator_events_irq_create_files,
        .online = gator_events_irq_online,
        .start = gator_events_irq_start,
index 063a060..de3b383 100644 (file)
@@ -121,6 +121,7 @@ static int gator_events_l2c310_read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_l2c310_interface = {
+       .name = "l2c-310",
        .create_files = gator_events_l2c310_create_files,
        .start = gator_events_l2c310_start,
        .stop = gator_events_l2c310_stop,
index 423b4e0..fb3909a 100644 (file)
@@ -66,9 +66,7 @@ static unsigned long counter_event[NUMBER_OF_EVENTS];
 static unsigned long counter_key[NUMBER_OF_EVENTS];
 
 /* The data we have recorded */
-static u32 counter_data[NUMBER_OF_EVENTS];
-/* The address to sample (or 0 if samples are sent to us) */
-static u32 *counter_address[NUMBER_OF_EVENTS];
+static atomic_t counter_data[NUMBER_OF_EVENTS];
 
 /* An array used to return the data we recorded
  * as key,value pairs hence the *2
@@ -116,7 +114,7 @@ static inline int is_hw_counter(unsigned int event_id)
 GATOR_DEFINE_PROBE(mali_hw_counter, TP_PROTO(unsigned int event_id, unsigned int value))
 {
        if (is_hw_counter(event_id))
-               counter_data[event_id] = value;
+               atomic_add(value, &counter_data[event_id]);
 }
 
 GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surface_id, unsigned int *counters))
@@ -126,7 +124,7 @@ GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surfac
        /* Copy over the values for those counters which are enabled. */
        for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++) {
                if (counter_enabled[i])
-                       counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]);
+                       atomic_add(counters[i - FIRST_SW_COUNTER], &counter_data[i]);
        }
 }
 
@@ -375,22 +373,22 @@ static void mali_counter_initialize(void)
        if (mali_get_counters)
                pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", mali_get_counters);
        else
-               pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined\n");
+               pr_debug("gator: mali _mali_profiling_get_counters symbol not defined\n");
 
        mali_get_l2_counters = symbol_get(_mali_profiling_get_l2_counters);
        if (mali_get_l2_counters)
                pr_debug("gator: mali online _mali_profiling_get_l2_counters symbol @ %p\n", mali_get_l2_counters);
        else
-               pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined\n");
+               pr_debug("gator: mali _mali_profiling_get_l2_counters symbol not defined\n");
 
        if (!mali_get_counters && !mali_get_l2_counters) {
-               pr_debug("gator: WARNING: no L2 counters available\n");
+               pr_err("gator: no L2 counters available\n");
                n_l2_cores = 0;
        }
 
        /* Clear counters in the start */
        for (i = 0; i < NUMBER_OF_EVENTS; i++) {
-               counter_data[i] = 0;
+               atomic_set(&counter_data[i], 0);
                prev_set[i] = false;
        }
 }
@@ -477,7 +475,6 @@ static void stop(void)
        for (cnt = 0; cnt < NUMBER_OF_EVENTS; cnt++) {
                counter_enabled[cnt] = 0;
                counter_event[cnt] = 0;
-               counter_address[cnt] = NULL;
        }
 
        mali_counter_deinitialize();
@@ -489,10 +486,12 @@ static void dump_counters(unsigned int from_counter, unsigned int to_counter, un
 
        for (counter_id = from_counter; counter_id <= to_counter; counter_id++) {
                if (counter_enabled[counter_id]) {
-                       counter_dump[(*len)++] = counter_key[counter_id];
-                       counter_dump[(*len)++] = counter_data[counter_id];
+                       unsigned int value;
 
-                       counter_data[counter_id] = 0;
+                       counter_dump[(*len)++] = counter_key[counter_id];
+                       value = atomic_read(&counter_data[counter_id]);
+                       atomic_sub(value, &counter_data[counter_id]);
+                       counter_dump[(*len)++] = value;
                }
        }
 }
@@ -564,17 +563,19 @@ static int read(int **buffer, bool sched_switch)
                 * Add in the voltage and frequency counters if enabled. Note
                 * that, since these are actually passed as events, the counter
                 * value should not be cleared.
+                *
+                * Intentionally use atomic_read as these are absolute counters
                 */
                cnt = COUNTER_FREQUENCY;
                if (counter_enabled[cnt]) {
                        counter_dump[len++] = counter_key[cnt];
-                       counter_dump[len++] = counter_data[cnt];
+                       counter_dump[len++] = atomic_read(&counter_data[cnt]);
                }
 
                cnt = COUNTER_VOLTAGE;
                if (counter_enabled[cnt]) {
                        counter_dump[len++] = counter_key[cnt];
-                       counter_dump[len++] = counter_data[cnt];
+                       counter_dump[len++] = atomic_read(&counter_data[cnt]);
                }
        }
 #endif
@@ -586,6 +587,7 @@ static int read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_mali_interface = {
+       .name = "mali_4xx",
        .create_files = create_files,
        .start = start,
        .stop = stop,
@@ -595,8 +597,9 @@ static struct gator_interface gator_events_mali_interface = {
 extern void gator_events_mali_log_dvfs_event(unsigned int frequency_mhz, unsigned int voltage_mv)
 {
 #ifdef DVFS_REPORTED_BY_DDK
-       counter_data[COUNTER_FREQUENCY] = frequency_mhz;
-       counter_data[COUNTER_VOLTAGE] = voltage_mv;
+       /* Intentionally use atomic_set as these are absolute counters */
+       atomic_set(&counter_data[COUNTER_FREQUENCY], frequency_mhz);
+       atomic_set(&counter_data[COUNTER_VOLTAGE], voltage_mv);
 #endif
 }
 
@@ -612,8 +615,7 @@ int gator_events_mali_init(void)
                counter_enabled[cnt] = 0;
                counter_event[cnt] = 0;
                counter_key[cnt] = gator_events_get_key();
-               counter_address[cnt] = NULL;
-               counter_data[cnt] = 0;
+               atomic_set(&counter_data[cnt], 0);
        }
 
        trace_registered = 0;
index 7741f25..60fece8 100644 (file)
@@ -25,31 +25,31 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even
                dir = gatorfs_mkdir(sb, root, buf);
 
                if (dir == NULL) {
-                       pr_debug("gator: %s: error creating file system for: %s (%s)\n", mali_name, event_name, buf);
+                       pr_err("gator: %s: error creating file system for: %s (%s)\n", mali_name, event_name, buf);
                        return -1;
                }
 
                err = gatorfs_create_ulong(sb, dir, "enabled", &counter->enabled);
                if (err != 0) {
-                       pr_debug("gator: %s: error calling gatorfs_create_ulong for: %s (%s)\n", mali_name, event_name, buf);
+                       pr_err("gator: %s: error calling gatorfs_create_ulong for: %s (%s)\n", mali_name, event_name, buf);
                        return -1;
                }
                err = gatorfs_create_ro_ulong(sb, dir, "key", &counter->key);
                if (err != 0) {
-                       pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
+                       pr_err("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
                        return -1;
                }
                if (counter->cores != -1) {
                        err = gatorfs_create_ro_ulong(sb, dir, "cores", &counter->cores);
                        if (err != 0) {
-                               pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
+                               pr_err("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
                                return -1;
                        }
                }
                if (event != NULL) {
                        err = gatorfs_create_ulong(sb, dir, "event", event);
                        if (err != 0) {
-                               pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
+                               pr_err("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
                                return -1;
                        }
                }
index 3b0963a..5b84975 100644 (file)
@@ -146,6 +146,10 @@ static unsigned int accumulators_data[NUMBER_OF_ACCUMULATORS];
 /* Hold the previous timestamp, used to calculate the sample interval. */
 static struct timespec prev_timestamp;
 
+static unsigned long long previous_shader_bitmask;
+static unsigned long long previous_tiler_bitmask;
+static unsigned long long previous_l2_bitmask;
+
 /**
  * Returns the timespan (in microseconds) between the two specified timestamps.
  *
@@ -209,10 +213,6 @@ GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long
 #define L2_PRESENT_LO           0x120  /* (RO) Level 2 cache present bitmap, low word */
 #define BIT_AT(value, pos) ((value >> pos) & 1)
 
-       static unsigned long long previous_shader_bitmask;
-       static unsigned long long previous_tiler_bitmask;
-       static unsigned long long previous_l2_bitmask;
-
        switch (event_id) {
        case SHADER_PRESENT_LO:
                {
@@ -324,27 +324,27 @@ static int create_files(struct super_block *sb, struct dentry *root)
 static int register_tracepoints(void)
 {
        if (GATOR_REGISTER_TRACE(mali_pm_status)) {
-               pr_debug("gator: Mali-Midgard: mali_pm_status tracepoint failed to activate\n");
+               pr_err("gator: Mali-Midgard: mali_pm_status tracepoint failed to activate\n");
                return 0;
        }
 
        if (GATOR_REGISTER_TRACE(mali_page_fault_insert_pages)) {
-               pr_debug("gator: Mali-Midgard: mali_page_fault_insert_pages tracepoint failed to activate\n");
+               pr_err("gator: Mali-Midgard: mali_page_fault_insert_pages tracepoint failed to activate\n");
                return 0;
        }
 
        if (GATOR_REGISTER_TRACE(mali_mmu_as_in_use)) {
-               pr_debug("gator: Mali-Midgard: mali_mmu_as_in_use tracepoint failed to activate\n");
+               pr_err("gator: Mali-Midgard: mali_mmu_as_in_use tracepoint failed to activate\n");
                return 0;
        }
 
        if (GATOR_REGISTER_TRACE(mali_mmu_as_released)) {
-               pr_debug("gator: Mali-Midgard: mali_mmu_as_released tracepoint failed to activate\n");
+               pr_err("gator: Mali-Midgard: mali_mmu_as_released tracepoint failed to activate\n");
                return 0;
        }
 
        if (GATOR_REGISTER_TRACE(mali_total_alloc_pages_change)) {
-               pr_debug("gator: Mali-Midgard: mali_total_alloc_pages_change tracepoint failed to activate\n");
+               pr_err("gator: Mali-Midgard: mali_total_alloc_pages_change tracepoint failed to activate\n");
                return 0;
        }
 
@@ -363,6 +363,10 @@ static int start(void)
        unsigned int cnt;
        mali_profiling_control_type *mali_control;
 
+       previous_shader_bitmask = 0;
+       previous_tiler_bitmask = 0;
+       previous_l2_bitmask = 0;
+
        /* Clean all data for the next capture */
        for (cnt = 0; cnt < NUMBER_OF_TIMELINE_EVENTS; cnt++) {
                timeline_event_starttime[cnt].tv_sec = timeline_event_starttime[cnt].tv_nsec = 0;
@@ -546,6 +550,7 @@ static int read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_mali_midgard_interface = {
+       .name = "mali_midgard",
        .create_files = create_files,
        .start = start,
        .stop = stop,
index 7e1eee3..db91c42 100644 (file)
@@ -433,7 +433,8 @@ static unsigned int num_hardware_counters_enabled;
 static struct mali_counter *counters;
 
 /* An array used to return the data we recorded as key,value pairs */
-static int *counter_dump;
+static long long *counter_dump;
+static uint64_t last_read_time;
 
 extern struct mali_counter mali_activity[3];
 
@@ -517,31 +518,6 @@ static void clean_symbols(void)
 #endif
 }
 
-/**
- * Determines whether a read should take place
- * @param current_time The current time, obtained from getnstimeofday()
- * @param prev_time_s The number of seconds at the previous read attempt.
- * @param next_read_time_ns The time (in ns) when the next read should be allowed.
- *
- * Note that this function has been separated out here to allow it to be tested.
- */
-static int is_read_scheduled(const struct timespec *current_time, u32 *prev_time_s, s32 *next_read_time_ns)
-{
-       /* If the current ns count rolls over a second, roll the next read time too. */
-       if (current_time->tv_sec != *prev_time_s)
-               *next_read_time_ns = *next_read_time_ns - NSEC_PER_SEC;
-
-       /* Abort the read if the next read time has not arrived. */
-       if (current_time->tv_nsec < *next_read_time_ns)
-               return 0;
-
-       /* Set the next read some fixed time after this one, and update the read timestamp. */
-       *next_read_time_ns = current_time->tv_nsec + READ_INTERVAL_NSEC;
-
-       *prev_time_s = current_time->tv_sec;
-       return 1;
-}
-
 static int start(void)
 {
 #if MALI_DDK_GATOR_API_VERSION != 3
@@ -552,6 +528,8 @@ static int start(void)
 #endif
        int cnt;
 
+       last_read_time = 0;
+
 #if MALI_DDK_GATOR_API_VERSION == 3
        /* Setup HW counters */
        num_hardware_counters_enabled = 0;
@@ -620,14 +598,14 @@ static int start(void)
 
                /* If we already got a context, fail */
                if (kbcontext) {
-                       pr_debug("gator: Mali-Midgard: error context already present\n");
+                       pr_err("gator: Mali-Midgard: error context already present\n");
                        goto out;
                }
 
                /* kbcontext will only be valid after all the Mali symbols are loaded successfully */
                kbcontext = kbase_create_context_symbol(kbdevice);
                if (!kbcontext) {
-                       pr_debug("gator: Mali-Midgard: error creating kbase context\n");
+                       pr_err("gator: Mali-Midgard: error creating kbase context\n");
                        goto out;
                }
 
@@ -650,7 +628,7 @@ static int start(void)
                kernel_dump_buffer = kbase_va_alloc_symbol(kbcontext, 4096, &kernel_dump_buffer_handle);
 #endif
                if (!kernel_dump_buffer) {
-                       pr_debug("gator: Mali-Midgard: error trying to allocate va\n");
+                       pr_err("gator: Mali-Midgard: error trying to allocate va\n");
                        goto destroy_context;
                }
 
@@ -665,7 +643,7 @@ static int start(void)
                /* Use kbase API to enable hardware counters and provide dump buffer */
                err = kbase_instr_hwcnt_enable_symbol(kbcontext, &setup);
                if (err != MALI_ERROR_NONE) {
-                       pr_debug("gator: Mali-Midgard: can't setup hardware counters\n");
+                       pr_err("gator: Mali-Midgard: can't setup hardware counters\n");
                        goto free_buffer;
                }
                pr_debug("gator: Mali-Midgard: hardware counters enabled\n");
@@ -813,68 +791,80 @@ static int read_counter(const int cnt, const int len, const struct mali_counter
        return 2;
 }
 
-static int read(int **buffer, bool sched_switch)
+static int read(long long **buffer, bool sched_switch)
 {
        int cnt;
        int len = 0;
        uint32_t success;
 
-       struct timespec current_time;
-       static u32 prev_time_s;
-       static s32 next_read_time_ns;
+       uint64_t curr_time;
 
        if (!on_primary_core() || sched_switch)
                return 0;
 
-       getnstimeofday(&current_time);
+       /*
+        * Report the HW counters
+        * Only process hardware counters if at least one of the hardware counters is enabled.
+        */
+       if (num_hardware_counters_enabled <= 0)
+               return 0;
+
+       curr_time = gator_get_time();
 
        /*
         * Discard reads unless a respectable time has passed. This
         * reduces the load on the GPU without sacrificing accuracy on
         * the Streamline display.
         */
-       if (!is_read_scheduled(&current_time, &prev_time_s, &next_read_time_ns))
+       if (curr_time - last_read_time < READ_INTERVAL_NSEC)
                return 0;
 
-       /*
-        * Report the HW counters
-        * Only process hardware counters if at least one of the hardware counters is enabled.
-        */
-       if (num_hardware_counters_enabled > 0) {
 #if MALI_DDK_GATOR_API_VERSION == 3
-               if (!handles)
-                       return -1;
+       if (!handles)
+               return -1;
 
-               /* Mali symbols can be called safely since a kbcontext is valid */
-               if (kbase_gator_instr_hwcnt_dump_complete_symbol(handles, &success)) {
+       /* Mali symbols can be called safely since a kbcontext is valid */
+       if (kbase_gator_instr_hwcnt_dump_complete_symbol(handles, &success)) {
 #else
-               if (!kbcontext)
-                       return -1;
+       if (!kbcontext)
+               return -1;
 
-               /* Mali symbols can be called safely since a kbcontext is valid */
-               if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success)) {
+       /* Mali symbols can be called safely since a kbcontext is valid */
+       if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success)) {
 #endif
-                       kbase_device_busy = false;
+               kbase_device_busy = false;
+
+               /*
+                * If last_read_time is zero, then this result is from a previous
+                * capture or in error.
+                */
+               if (success && last_read_time > 0) {
+                       /* Backdate these events to when they were requested */
+                       counter_dump[len++] = 0;
+                       counter_dump[len++] = last_read_time;
 
-                       if (success) {
-                               /* Cycle through hardware counters and accumulate totals */
-                               for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
-                                       const struct mali_counter *counter = &counters[cnt];
+                       /* Cycle through hardware counters and accumulate totals */
+                       for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
+                               const struct mali_counter *counter = &counters[cnt];
 
-                                       if (counter->enabled)
-                                               len += read_counter(cnt, len, counter);
-                               }
+                               if (counter->enabled)
+                                       len += read_counter(cnt, len, counter);
                        }
+
+                       /* Restore the timestamp */
+                       counter_dump[len++] = 0;
+                       counter_dump[len++] = curr_time;
                }
+       }
 
-               if (!kbase_device_busy) {
-                       kbase_device_busy = true;
+       if (!kbase_device_busy) {
+               kbase_device_busy = true;
+               last_read_time = curr_time;
 #if MALI_DDK_GATOR_API_VERSION == 3
-                       kbase_gator_instr_hwcnt_dump_irq_symbol(handles);
+               kbase_gator_instr_hwcnt_dump_irq_symbol(handles);
 #else
-                       kbase_instr_hwcnt_dump_irq_symbol(kbcontext);
+               kbase_instr_hwcnt_dump_irq_symbol(kbcontext);
 #endif
-               }
        }
 
        /* Update the buffer */
@@ -920,7 +910,7 @@ static void shutdown(void)
        hardware_counter_names = NULL;
        if (kbase_gator_hwcnt_term_names_symbol != NULL) {
                kbase_gator_hwcnt_term_names_symbol();
-               pr_err("Released symbols\n");
+               pr_debug("gator: Released symbols\n");
        }
 
        SYMBOL_CLEANUP(kbase_gator_hwcnt_term_names);
@@ -928,11 +918,12 @@ static void shutdown(void)
 }
 
 static struct gator_interface gator_events_mali_midgard_interface = {
+       .name = "mali_midgard_hw",
        .shutdown = shutdown,
        .create_files = create_files,
        .start = start,
        .stop = stop,
-       .read = read
+       .read64 = read
 };
 
 int gator_events_mali_midgard_hw_init(void)
@@ -969,7 +960,7 @@ int gator_events_mali_midgard_hw_init(void)
 #endif
 
        counters = kmalloc(sizeof(*counters)*number_of_hardware_counters, GFP_KERNEL);
-       counter_dump = kmalloc(sizeof(*counter_dump)*number_of_hardware_counters*2, GFP_KERNEL);
+       counter_dump = kmalloc(sizeof(*counter_dump)*number_of_hardware_counters*2 + 4, GFP_KERNEL);
 
        gator_mali_initialise_counters(mali_activity, ARRAY_SIZE(mali_activity));
        gator_mali_initialise_counters(counters, number_of_hardware_counters);
index 87c569c..9fd44bc 100644 (file)
 /**
  * Test functions for mali_t600_hw code.
  */
-
-static int is_read_scheduled(const struct timespec *current_time, u32 *prev_time_s, s32 *next_read_time_ns);
-
-static int test_is_read_scheduled(u32 s, u32 ns, u32 prev_s, s32 next_ns, int expected_result, s32 expected_next_ns)
-{
-       struct timespec current_time;
-       u32 prev_time_s = prev_s;
-       s32 next_read_time_ns = next_ns;
-
-       current_time.tv_sec = s;
-       current_time.tv_nsec = ns;
-
-       if (is_read_scheduled(&current_time, &prev_time_s, &next_read_time_ns) != expected_result) {
-               pr_err("Failed do_read(%u, %u, %u, %d): expected %d\n", s, ns, prev_s, next_ns, expected_result);
-               return 0;
-       }
-
-       if (next_read_time_ns != expected_next_ns) {
-               pr_err("Failed: next_read_ns expected=%d, actual=%d\n", expected_next_ns, next_read_time_ns);
-               return 0;
-       }
-
-       return 1;
-}
-
-static void test_all_is_read_scheduled(void)
-{
-       const int HIGHEST_NS = 999999999;
-       int n_tests_passed = 0;
-
-       pr_err("gator: running tests on %s\n", __FILE__);
-
-       n_tests_passed += test_is_read_scheduled(0, 0, 0, 0, 1, READ_INTERVAL_NSEC);    /* Null time */
-       n_tests_passed += test_is_read_scheduled(100, 1000, 0, 0, 1, READ_INTERVAL_NSEC + 1000);        /* Initial values */
-
-       n_tests_passed += test_is_read_scheduled(100, HIGHEST_NS, 100, HIGHEST_NS + 500, 0, HIGHEST_NS + 500);
-       n_tests_passed += test_is_read_scheduled(101, 0001, 100, HIGHEST_NS + 500, 0, HIGHEST_NS + 500 - NSEC_PER_SEC);
-       n_tests_passed += test_is_read_scheduled(101, 600, 100, HIGHEST_NS + 500 - NSEC_PER_SEC, 1, 600 + READ_INTERVAL_NSEC);
-
-       n_tests_passed += test_is_read_scheduled(101, 600, 100, HIGHEST_NS + 500, 1, 600 + READ_INTERVAL_NSEC);
-
-       pr_err("gator: %d tests passed\n", n_tests_passed);
-}
index 985b312..42a6947 100644 (file)
@@ -80,7 +80,7 @@ static void notify(void)
 
 static unsigned int mem_event;
 static void wq_sched_handler(struct work_struct *wsptr);
-DECLARE_WORK(work, wq_sched_handler);
+static DECLARE_WORK(work, wq_sched_handler);
 static struct timer_list meminfo_wake_up_timer;
 static void meminfo_wake_up_handler(unsigned long unused_data);
 
@@ -187,7 +187,7 @@ static int gator_events_meminfo_start(void)
        if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo")))
                goto kthread_run_exit;
 #else
-       setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
+       setup_deferrable_timer_on_stack(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
 #endif
 
        return 0;
@@ -313,7 +313,7 @@ static void meminfo_wake_up_handler(unsigned long unused_data)
 
 #endif
 
-static int gator_events_meminfo_read(long long **buffer)
+static int gator_events_meminfo_read(long long **buffer, bool sched_switch)
 {
 #if !USE_THREAD
        static unsigned int last_mem_event;
@@ -446,6 +446,7 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
 }
 
 static struct gator_interface gator_events_meminfo_interface = {
+       .name = "meminfo",
        .create_files = gator_events_meminfo_create_files,
        .start = gator_events_meminfo_start,
        .stop = gator_events_meminfo_stop,
index 7b51761..30ca980 100644 (file)
@@ -189,6 +189,7 @@ static int gator_events_mmapped_read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_mmapped_interface = {
+       .name = "mmapped",
        .create_files = gator_events_mmapped_create_files,
        .start = gator_events_mmapped_start,
        .stop = gator_events_mmapped_stop,
index 1e36731..053f719 100644 (file)
@@ -45,7 +45,7 @@ static void get_network_stats(struct work_struct *wsptr)
        tx_total = tx;
 }
 
-DECLARE_WORK(wq_get_stats, get_network_stats);
+static DECLARE_WORK(wq_get_stats, get_network_stats);
 
 static void net_wake_up_handler(unsigned long unused_data)
 {
@@ -98,11 +98,7 @@ static int gator_events_net_start(void)
        get_network_stats(0);
        netPrev[NETRX] = rx_total;
        netPrev[NETTX] = tx_total;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
-       setup_timer(&net_wake_up_timer, net_wake_up_handler, 0);
-#else
        setup_deferrable_timer_on_stack(&net_wake_up_timer, net_wake_up_handler, 0);
-#endif
        return 0;
 }
 
@@ -154,6 +150,7 @@ static int gator_events_net_read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_net_interface = {
+       .name = "net",
        .create_files = gator_events_net_create_files,
        .start = gator_events_net_start,
        .stop = gator_events_net_stop,
index f6b4f18..d49277d 100644 (file)
@@ -153,13 +153,13 @@ static void __online_dispatch(int cpu, bool migrate, struct gator_attr *const at
        event->pevent = perf_event_create_kernel_counter(event->pevent_attr, cpu, 0, handler, 0);
 #endif
        if (IS_ERR(event->pevent)) {
-               pr_debug("gator: unable to online a counter on cpu %d\n", cpu);
+               pr_err("gator: unable to online a counter on cpu %d\n", cpu);
                event->pevent = NULL;
                return;
        }
 
        if (event->pevent->state != PERF_EVENT_STATE_ACTIVE) {
-               pr_debug("gator: inactive counter on cpu %d\n", cpu);
+               pr_err("gator: inactive counter on cpu %d\n", cpu);
                perf_event_release_kernel(event->pevent);
                event->pevent = NULL;
                return;
@@ -369,6 +369,7 @@ static int gator_events_perf_pmu_read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_perf_pmu_interface = {
+       .name = "perf_pmu",
        .create_files = gator_events_perf_pmu_create_files,
        .start = gator_events_perf_pmu_start,
        .stop = gator_events_perf_pmu_stop,
@@ -463,10 +464,10 @@ static void gator_events_perf_pmu_cci_400_init(const int type)
                cci_name = "CCI_400";
                break;
        case 1:
-               cci_name = "CCI_400-r1";
+               cci_name = "CCI_400_r1";
                break;
        default:
-               pr_debug("gator: unrecognized cci-400 revision\n");
+               pr_err("gator: unrecognized cci-400 revision\n");
                return;
        }
 
@@ -536,14 +537,19 @@ int gator_events_perf_pmu_init(void)
                }
 
                if (pe->pmu != NULL && type == pe->pmu->type) {
-                       if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0 || strcmp("CCI_400-r1", pe->pmu->name) == 0) {
+                       pr_notice("gator: perf pmu: %s\n", pe->pmu->name);
+                       if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0 || strcmp("CCI_400_r1", pe->pmu->name) == 0) {
+                               pr_notice("gator: Adding CCI-400 counters with type %i\n", type);
                                gator_events_perf_pmu_cci_400_init(type);
                        } else if (strcmp("CCI_500", pe->pmu->name) == 0) {
+                               pr_notice("gator: Adding CCI-500 counters with type %i\n", type);
                                gator_events_perf_pmu_uncore_init("CCI_500", type, CCI_500, false);
                        } else if (strcmp("ccn", pe->pmu->name) == 0) {
+                               pr_notice("gator: Adding CCN counters with type %i\n", type);
                                gator_events_perf_pmu_uncore_init("ARM_CCN_5XX", type, CCN_5XX, true);
                        } else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) {
                                found_cpu = true;
+                               pr_notice("gator: Adding cpu counters for %s with type %i\n", gator_cpu->pmnc_name, type);
                                gator_events_perf_pmu_cpu_init(gator_cpu, type);
                        }
                        /* Initialize gator_attrs for dynamic PMUs here */
@@ -562,6 +568,7 @@ int gator_events_perf_pmu_init(void)
                                return -1;
                        }
                }
+               pr_notice("gator: Adding cpu counters (based on cpuid) for %s\n", gator_cpu->pmnc_name);
                gator_events_perf_pmu_cpu_init(gator_cpu, PERF_TYPE_RAW);
        }
 
index 463d834..d352415 100644 (file)
@@ -97,6 +97,7 @@ static int gator_events_sched_read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_sched_interface = {
+       .name = "sched",
        .create_files = gator_events_sched_create_files,
        .start = gator_events_sched_start,
        .stop = gator_events_sched_stop,
index b51dcd3..efb5e7a 100644 (file)
@@ -635,6 +635,7 @@ static int gator_events_scorpion_read(int **buffer, bool sched_switch)
 }
 
 static struct gator_interface gator_events_scorpion_interface = {
+       .name = "scorpion",
        .create_files = gator_events_scorpion_create_files,
        .stop = gator_events_scorpion_stop,
        .online = gator_events_scorpion_online,
index d8fb357..205da8b 100644 (file)
@@ -18,7 +18,7 @@
 
 #define gatorfs_MAGIC 0x24051020
 #define TMPBUFSIZE 50
-DEFINE_SPINLOCK(gatorfs_lock);
+static DEFINE_SPINLOCK(gatorfs_lock);
 
 static struct inode *gatorfs_get_inode(struct super_block *sb, int mode)
 {
index 36961f8..8b86ede 100644 (file)
@@ -7,10 +7,10 @@
  *
  */
 
-void (*callback)(void);
-DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
-DEFINE_PER_CPU(ktime_t, hrtimer_expire);
-DEFINE_PER_CPU(int, hrtimer_is_active);
+static void (*callback)(void);
+static DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
+static DEFINE_PER_CPU(ktime_t, hrtimer_expire);
+static DEFINE_PER_CPU(int, hrtimer_is_active);
 static ktime_t profiling_interval;
 static void gator_hrtimer_online(void);
 static void gator_hrtimer_offline(void);
index affa1dc..2d55afe 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 /* This version must match the gator daemon version */
-#define PROTOCOL_VERSION 21
+#define PROTOCOL_VERSION 22
 static unsigned long gator_protocol_version = PROTOCOL_VERSION;
 
 #include <linux/slab.h>
@@ -180,7 +180,6 @@ static DEFINE_PER_CPU(bool, in_scheduler_context);
 /******************************************************************************
  * Prototypes
  ******************************************************************************/
-static u64 gator_get_time(void);
 static void gator_emit_perf_time(u64 time);
 static void gator_op_create_files(struct super_block *sb, struct dentry *root);
 
@@ -378,21 +377,21 @@ static const struct gator_cpu gator_cpus[] = {
        {
                .cpuid = CORTEX_A53,
                .core_name = "Cortex-A53",
-               .pmnc_name = "ARM_Cortex-A53",
+               .pmnc_name = "ARMv8_Cortex_A53",
                .dt_name = "arm,cortex-a53",
                .pmnc_counters = 6,
        },
        {
                .cpuid = CORTEX_A57,
                .core_name = "Cortex-A57",
-               .pmnc_name = "ARM_Cortex-A57",
+               .pmnc_name = "ARMv8_Cortex_A57",
                .dt_name = "arm,cortex-a57",
                .pmnc_counters = 6,
        },
        {
                .cpuid = CORTEX_A72,
                .core_name = "Cortex-A72",
-               .pmnc_name = "ARM_Cortex-A72",
+               .pmnc_name = "ARMv8_Cortex_A72",
                .dt_name = "arm,cortex-a72",
                .pmnc_counters = 6,
        },
@@ -551,6 +550,8 @@ static void gator_timer_offline(void *migrate)
                list_for_each_entry(gi, &gator_events, list) {
                        if (gi->offline) {
                                len = gi->offline(&buffer, migrate);
+                               if (len < 0)
+                                       pr_err("gator: offline failed for %s\n", gi->name);
                                marshal_event(len, buffer);
                        }
                }
@@ -639,6 +640,8 @@ static void gator_timer_online(void *migrate)
                list_for_each_entry(gi, &gator_events, list) {
                        if (gi->online) {
                                len = gi->online(&buffer, migrate);
+                               if (len < 0)
+                                       pr_err("gator: online failed for %s\n", gi->name);
                                marshal_event(len, buffer);
                        }
                }
@@ -699,7 +702,7 @@ static int gator_timer_start(unsigned long sample_rate)
        return 0;
 }
 
-static u64 gator_get_time(void)
+u64 gator_get_time(void)
 {
        struct timespec ts;
        u64 timestamp;
@@ -1366,6 +1369,7 @@ static void gator_op_create_files(struct super_block *sb, struct dentry *root)
        struct dentry *dir;
        struct gator_interface *gi;
        int cpu;
+       int err;
 
        /* reinitialize default values */
        gator_cpu_cores = 0;
@@ -1393,8 +1397,12 @@ static void gator_op_create_files(struct super_block *sb, struct dentry *root)
        /* Linux Events */
        dir = gatorfs_mkdir(sb, root, "events");
        list_for_each_entry(gi, &gator_events, list)
-               if (gi->create_files)
-                       gi->create_files(sb, dir);
+               if (gi->create_files) {
+                       err = gi->create_files(sb, dir);
+                       if (err != 0) {
+                               pr_err("gator: create_files failed for %s\n", gi->name);
+                       }
+               }
 
        /* Sched Events */
        sched_trace_create_files(sb, dir);
@@ -1473,7 +1481,7 @@ static int __init gator_module_init(void)
                return -1;
        }
 
-       setup_timer(&gator_buffer_wake_up_timer, gator_buffer_wake_up, 0);
+       setup_deferrable_timer_on_stack(&gator_buffer_wake_up_timer, gator_buffer_wake_up, 0);
 
        /* Initialize the list of cpuids */
        memset(gator_cpuids, -1, sizeof(gator_cpuids));
index f5b8184..cb75a34 100644 (file)
@@ -27,6 +27,7 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
 {
        unsigned long flags;
        int cpu = 0;
+       char buf[32];
 
        local_irq_save(flags);
        gator_buffer_write_packed_int(cpu, SUMMARY_BUF, MESSAGE_SUMMARY);
@@ -36,6 +37,9 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
        gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, monotonic_delta);
        gator_buffer_write_string(cpu, SUMMARY_BUF, "uname");
        gator_buffer_write_string(cpu, SUMMARY_BUF, uname);
+       gator_buffer_write_string(cpu, SUMMARY_BUF, "PAGESIZE");
+       snprintf(buf, sizeof(buf), "%lu", PAGE_SIZE);
+       gator_buffer_write_string(cpu, SUMMARY_BUF, buf);
 #if GATOR_IKS_SUPPORT
        gator_buffer_write_string(cpu, SUMMARY_BUF, "iks");
        gator_buffer_write_string(cpu, SUMMARY_BUF, "");
index d9b82ee..b35ccd5 100644 (file)
@@ -132,7 +132,7 @@ static void mali_activity_stop(int core, int key)
                gator_marshal_activity_switch(core, key, last_activity, last_pid);
 }
 
-void mali_activity_clear(struct mali_counter mali_activity[], size_t mali_activity_size)
+static void mali_activity_clear(struct mali_counter mali_activity[], size_t mali_activity_size)
 {
        int activity;
        int cores;
index ad7c39e..700dd2e 100644 (file)
@@ -104,13 +104,19 @@ static void collect_counters(u64 time, struct task_struct *task, bool sched_swit
                list_for_each_entry(gi, &gator_events, list) {
                        if (gi->read) {
                                len = gi->read(&buffer, sched_switch);
+                               if (len < 0)
+                                       pr_err("gator: read failed for %s\n", gi->name);
                                marshal_event(len, buffer);
                        } else if (gi->read64) {
-                               len = gi->read64(&buffer64);
+                               len = gi->read64(&buffer64, sched_switch);
+                               if (len < 0)
+                                       pr_err("gator: read64 failed for %s\n", gi->name);
                                marshal_event64(len, buffer64);
                        }
                        if (gi->read_proc && task != NULL) {
                                len = gi->read_proc(&buffer64, task);
+                               if (len < 0)
+                                       pr_err("gator: read_proc failed for %s\n", gi->name);
                                marshal_event64(len, buffer64);
                        }
                }
index b0076c2..bd0ac77 100644 (file)
@@ -36,5 +36,6 @@ EXTRA_CFLAGS += -I$(KBASE_DIR)/ \
                 -I$(DDK_DIR)/include \
                 -I$(KBASE_DIR)/osk/src/linux/include \
                 -I$(KBASE_DIR)/platform_dummy \
-                -I$(KBASE_DIR)/src
+                -I$(KBASE_DIR)/src \
+                -Idrivers/staging/android \
 
index 68f4a83..ae49e68 100644 (file)
@@ -5,6 +5,7 @@ XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h SrcMd5.cpp
 
 LOCAL_SRC_FILES := \
        AnnotateListener.cpp \
+       AtraceDriver.cpp \
        Buffer.cpp \
        CCNDriver.cpp \
        CapturedXML.cpp \
@@ -16,11 +17,11 @@ LOCAL_SRC_FILES := \
        DriverSource.cpp \
        DynBuf.cpp \
        EventsXML.cpp \
+       ExternalDriver.cpp \
        ExternalSource.cpp \
        FSDriver.cpp \
        Fifo.cpp \
        FtraceDriver.cpp \
-       FtraceSource.cpp \
        HwmonDriver.cpp \
        KMod.cpp \
        LocalCapture.cpp \
diff --git a/tools/gator/daemon/AtraceDriver.cpp b/tools/gator/daemon/AtraceDriver.cpp
new file mode 100644 (file)
index 0000000..78fe58a
--- /dev/null
@@ -0,0 +1,136 @@
+/**
+ * Copyright (C) ARM Limited 2014-2015. 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 "AtraceDriver.h"
+
+#include <unistd.h>
+
+/*
+#include <regex.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "DriverSource.h"
+#include "Setup.h"
+*/
+
+#include "Logging.h"
+#include "OlyUtility.h"
+#include "SessionData.h"
+
+class AtraceCounter : public DriverCounter {
+public:
+       AtraceCounter(DriverCounter *next, char *name, int flag);
+       ~AtraceCounter();
+
+       int getFlag() const { return mFlag; }
+
+private:
+       const int mFlag;
+
+       // Intentionally unimplemented
+       AtraceCounter(const AtraceCounter &);
+       AtraceCounter &operator=(const AtraceCounter &);
+};
+
+AtraceCounter::AtraceCounter(DriverCounter *next, char *name, int flag) : DriverCounter(next, name), mFlag(flag) {
+}
+
+AtraceCounter::~AtraceCounter() {
+}
+
+AtraceDriver::AtraceDriver() : mSupported(false), mNotifyPath() {
+}
+
+AtraceDriver::~AtraceDriver() {
+}
+
+void AtraceDriver::readEvents(mxml_node_t *const xml) {
+       if (!gSessionData->mFtraceDriver.isSupported()) {
+               logg->logMessage("Atrace support disabled, ftrace support is required");
+               return;
+       }
+       if (access("/system/bin/setprop", X_OK) != 0) {
+               logg->logMessage("Atrace support disabled, setprop is not found, this is not an Android target");
+               return;
+       }
+
+       if (util->getApplicationFullPath(mNotifyPath, sizeof(mNotifyPath)) != 0) {
+               logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
+       }
+       strncat(mNotifyPath, "notify.dex", sizeof(mNotifyPath) - strlen(mNotifyPath) - 1);
+       if (access(mNotifyPath, W_OK) != 0) {
+               logg->logMessage("Atrace support disabled, unable to locate notify.dex");
+               return;
+       }
+
+       mSupported = true;
+
+       mxml_node_t *node = xml;
+       while (true) {
+               node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
+               if (node == NULL) {
+                       break;
+               }
+               const char *counter = mxmlElementGetAttr(node, "counter");
+               if (counter == NULL) {
+                       continue;
+               }
+
+               if (strncmp(counter, "atrace_", 7) != 0) {
+                       continue;
+               }
+
+               const char *flag = mxmlElementGetAttr(node, "flag");
+               if (flag == NULL) {
+                       logg->logError("The atrace counter %s is missing the required flag attribute", counter);
+                       handleException();
+               }
+               setCounters(new AtraceCounter(getCounters(), strdup(counter), strtol(flag, NULL, 16)));
+       }
+}
+
+void AtraceDriver::setAtrace(const int flags) {
+       logg->logMessage("Setting atrace flags to %i\n", flags);
+       pid_t pid = fork();
+       if (pid < 0) {
+               logg->logError("fork failed");
+               handleException();
+       } else if (pid == 0) {
+               char buf[1<<10];
+               snprintf(buf, sizeof(buf), "setprop debug.atrace.tags.enableflags %i; "
+                        "dalvikvm -cp %s com.android.internal.util.WithFramework Notify", flags, mNotifyPath);
+               execlp("sh", "sh", "-c", buf, NULL);
+               exit(0);
+       }
+}
+
+void AtraceDriver::start() {
+       if (!mSupported) {
+               return;
+       }
+
+       int flags = 0;
+       for (AtraceCounter *counter = static_cast<AtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<AtraceCounter *>(counter->getNext())) {
+               if (!counter->isEnabled()) {
+                       continue;
+               }
+               flags |= counter->getFlag();
+       }
+
+       setAtrace(flags);
+}
+
+void AtraceDriver::stop() {
+       if (!mSupported) {
+               return;
+       }
+
+       setAtrace(0);
+}
diff --git a/tools/gator/daemon/AtraceDriver.h b/tools/gator/daemon/AtraceDriver.h
new file mode 100644 (file)
index 0000000..0a06858
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) ARM Limited 2015. 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 ATRACEDRIVER_H
+#define ATRACEDRIVER_H
+
+#include "mxml/mxml.h"
+
+#include "Driver.h"
+
+class AtraceDriver : public SimpleDriver {
+public:
+       AtraceDriver();
+       ~AtraceDriver();
+
+       void readEvents(mxml_node_t *const xml);
+
+       void start();
+       void stop();
+
+       bool isSupported() const { return mSupported; }
+
+private:
+       void setAtrace(const int flags);
+
+       bool mSupported;
+       char mNotifyPath[256];
+
+       // Intentionally unimplemented
+       AtraceDriver(const AtraceDriver &);
+       AtraceDriver &operator=(const AtraceDriver &);
+};
+
+#endif // ATRACEDRIVER_H
index c4ced9f..26deb2e 100644 (file)
@@ -143,6 +143,16 @@ int Buffer::contiguousSpaceAvailable() const {
        }
 }
 
+bool Buffer::hasUncommittedMessages() const {
+       const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
+       int length = mWritePos - mCommitPos;
+       if (length < 0) {
+               length += mSize;
+       }
+       length = length - typeLength - sizeof(int32_t);
+       return length > FRAME_HEADER_SIZE;
+}
+
 void Buffer::commit(const uint64_t time, const bool force) {
        // 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;
@@ -263,7 +273,7 @@ void Buffer::frame() {
        }
 }
 
-void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
+void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname, const long pageSize) {
        packInt(MESSAGE_SUMMARY);
        writeString(NEWLINE_CANARY);
        packInt64(timestamp);
@@ -271,6 +281,10 @@ void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int
        packInt64(monotonicDelta);
        writeString("uname");
        writeString(uname);
+       writeString("PAGESIZE");
+       char buf[32];
+       snprintf(buf, sizeof(buf), "%li", pageSize);
+       writeString(buf);
        writeString("");
        check(currTime);
 }
index 13c44e1..ea250a9 100644 (file)
@@ -36,11 +36,12 @@ public:
 
        int bytesAvailable() const;
        int contiguousSpaceAvailable() const;
+       bool hasUncommittedMessages() const;
        void commit(const uint64_t time, const bool force = false);
        void check(const uint64_t time);
 
        // Summary messages
-       void summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname);
+       void summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname, const long pageSize);
        void coreName(const uint64_t currTime, const int core, const int cpuid, const char *const name);
 
        // Block Counter messages
index d77513a..24eda03 100644 (file)
@@ -19,6 +19,7 @@
 #include "Config.h"
 #include "DriverSource.h"
 #include "Logging.h"
+#include "SessionData.h"
 
 static const char TAG_CATEGORY[] = "category";
 static const char TAG_COUNTER_SET[] = "counter_set";
@@ -44,6 +45,8 @@ static const char RNI_REGION[] = "RN-I_Region";
 static const char SBAS_REGION[] = "SBAS_Region";
 static const char CCN_5XX[] = "CCN-5xx";
 #define ARM_CCN_5XX "ARM_CCN_5XX_"
+#define CCN_COUNT 8
+static const char ARM_CCN_5XX_CNT[] = ARM_CCN_5XX "cnt";
 
 static const char *const VC_TYPES[] = { "REQ", "RSP", "SNP", "DAT" };
 static const char *const XP_EVENT_NAMES[] = { NULL, "H-bit", "S-bit", "P-Cnt", "TknV" };
@@ -173,12 +176,12 @@ int CCNDriver::writeCounters(mxml_node_t *const) const {
 
 void CCNDriver::writeEvents(mxml_node_t *const root) const {
        mxml_node_t *const counter_set = mxmlNewElement(root, TAG_COUNTER_SET);
-       mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX "cnt");
-       mxmlElementSetAttr(counter_set, ATTR_COUNT, "8");
+       mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX_CNT);
+       mxmlElementSetAttr(counter_set, ATTR_COUNT, STRIFY(CCN_COUNT));
 
        mxml_node_t *const category = mxmlNewElement(root, TAG_CATEGORY);
        mxmlElementSetAttr(category, ATTR_NAME, CCN_5XX);
-       mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX "cnt");
+       mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX_CNT);
 
        mxml_node_t *const clock_event = mxmlNewElement(category, TAG_EVENT);
        mxmlElementSetAttr(clock_event, ATTR_COUNTER, ARM_CCN_5XX "ccnt");
@@ -292,3 +295,35 @@ void CCNDriver::writeEvents(mxml_node_t *const root) const {
                }
        }
 }
+
+void CCNDriver::validateCounters() const {
+       int counts[CCN_COUNT][2] = { { 0 } };
+       const unsigned int mask = getConfig(0xff, 0xff, 0, 0, 0);
+
+       for (int i = 0; i < ARRAY_LENGTH(gSessionData->mCounters); ++i) {
+               const Counter *const counter = &gSessionData->mCounters[i];
+
+               if (!counter->isEnabled()) {
+                       continue;
+               }
+
+               if (strncmp(counter->getType(), ARM_CCN_5XX_CNT, sizeof(ARM_CCN_5XX_CNT) - 1) == 0) {
+                       const int node = counter->getEvent() & mask;
+
+                       for (int j = 0; j < ARRAY_LENGTH(counts); ++j) {
+                               if (counts[j][0] == 0) {
+                                       counts[j][0] = node;
+                               }
+                               if (counts[j][0] == node) {
+                                       ++counts[j][1];
+                                       if (counts[j][1] > 4) {
+                                               if (asprintf(&gSessionData->mCountersError, "More than 4 events are assigned to the same CCN node") <= 0) {
+                                                       logg->logError("asprintf failed");
+                                                       handleException();
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
index 06ac33f..8a155a7 100644 (file)
@@ -24,6 +24,8 @@ public:
        int writeCounters(mxml_node_t *const root) const;
        void writeEvents(mxml_node_t *const) const;
 
+       void validateCounters() const;
+
 private:
        enum NodeType {
                NT_UNKNOWN,
index 1854c77..e87c909 100644 (file)
@@ -32,7 +32,7 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
 
        captured = mxmlNewElement(xml, "captured");
        mxmlElementSetAttr(captured, "version", "1");
-       if (gSessionData->perf.isSetup()) {
+       if (gSessionData->mPerf.isSetup()) {
                mxmlElementSetAttr(captured, "type", "Perf");
        }
        mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION);
index a19e9cf..551ec6b 100644 (file)
@@ -20,7 +20,6 @@
 #include "Driver.h"
 #include "DriverSource.h"
 #include "ExternalSource.h"
-#include "FtraceSource.h"
 #include "LocalCapture.h"
 #include "Logging.h"
 #include "OlySocket.h"
@@ -35,7 +34,6 @@ static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shar
 static Source *primarySource = NULL;
 static Source *externalSource = NULL;
 static Source *userSpaceSource = NULL;
-static Source *ftraceSource = NULL;
 static Sender* sender = NULL;        // Shared by Child.cpp and spawned threads
 Child* child = NULL;                 // shared by Child.cpp and main.cpp
 
@@ -44,7 +42,8 @@ void handleException() {
        if (child && child->numExceptions++ > 0) {
                // it is possible one of the below functions itself can cause an exception, thus allow only one exception
                logg->logMessage("Received multiple exceptions, terminating the child");
-               exit(1);
+               // Something is really wrong, exit immediately
+               _exit(1);
        }
        fprintf(stderr, "%s", logg->getLastError());
 
@@ -67,8 +66,9 @@ void handleException() {
                }
        }
 
-       if (gSessionData->mLocalCapture)
+       if (gSessionData->mLocalCapture) {
                cleanUp();
+       }
 
        exit(1);
 }
@@ -152,7 +152,6 @@ static void *senderThread(void *) {
 
        while (!externalSource->isDone() ||
               (userSpaceSource != NULL && !userSpaceSource->isDone()) ||
-                  (ftraceSource != NULL && !ftraceSource->isDone()) ||
               !primarySource->isDone()) {
                sem_wait(&senderSem);
 
@@ -160,9 +159,6 @@ static void *senderThread(void *) {
                if (userSpaceSource != NULL) {
                        userSpaceSource->write(sender);
                }
-               if (ftraceSource != NULL) {
-                       ftraceSource->write(sender);
-               }
                primarySource->write(sender);
        }
 
@@ -213,9 +209,6 @@ void Child::endSession() {
        if (userSpaceSource != NULL) {
                userSpaceSource->interrupt();
        }
-       if (ftraceSource != NULL) {
-               ftraceSource->interrupt();
-       }
        sem_post(&haltPipeline);
 }
 
@@ -240,7 +233,7 @@ void Child::run() {
        { ConfigurationXML configuration; }
 
        // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
-       if (!gSessionData->perf.isSetup()) {
+       if (!gSessionData->mPerf.isSetup()) {
                primarySource = new DriverSource(&senderSem, &startProfile);
        } else {
                primarySource = new PerfSource(&senderSem, &startProfile);
@@ -279,25 +272,24 @@ void Child::run() {
                free(xmlString);
        }
 
-       if (gSessionData->kmod.isMaliCapture() && (gSessionData->mSampleRate == 0)) {
+       if (gSessionData->mKmod.isMaliCapture() && (gSessionData->mSampleRate == 0)) {
                logg->logError("Mali counters are not supported with Sample Rate: None.");
                handleException();
        }
 
        // Initialize ftrace source before child as it's slow and dependens on nothing else
        // If initialized later, us gator with ftrace has time sync issues
-       if (gSessionData->ftraceDriver.countersEnabled()) {
-               ftraceSource = new FtraceSource(&senderSem);
-               if (!ftraceSource->prepare()) {
-                       logg->logError("Unable to prepare userspace source for capture");
-                       handleException();
-               }
-               ftraceSource->start();
+       // Must be initialized before senderThread is started as senderThread checks externalSource
+       externalSource = new ExternalSource(&senderSem);
+       if (!externalSource->prepare()) {
+               logg->logError("Unable to prepare external source for capture");
+               handleException();
        }
+       externalSource->start();
 
        // Must be after session XML is parsed
        if (!primarySource->prepare()) {
-               if (gSessionData->perf.isSetup()) {
+               if (gSessionData->mPerf.isSetup()) {
                        logg->logError("Unable to communicate with the perf API, please ensure that CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER are enabled. Please refer to README_Streamline.txt for more information.");
                } else {
                        logg->logError("Unable to prepare gator driver for capture");
@@ -308,14 +300,6 @@ void Child::run() {
        // Sender thread shall be halted until it is signaled for one shot mode
        sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
 
-       // Must be initialized before senderThread is started as senderThread checks externalSource
-       externalSource = new ExternalSource(&senderSem);
-       if (!externalSource->prepare()) {
-               logg->logError("Unable to prepare external source for capture");
-               handleException();
-       }
-       externalSource->start();
-
        // Create the duration, stop, and sender threads
        bool thread_creation_success = true;
        if (gSessionData->mDuration > 0 && pthread_create(&durationThreadID, NULL, durationThread, NULL)) {
@@ -327,8 +311,8 @@ void Child::run() {
        }
 
        bool startUSSource = false;
-       for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
-               if (gSessionData->usDrivers[i]->countersEnabled()) {
+       for (int i = 0; i < ARRAY_LENGTH(gSessionData->mUsDrivers); ++i) {
+               if (gSessionData->mUsDrivers[i]->countersEnabled()) {
                        startUSSource = true;
                }
        }
@@ -360,9 +344,6 @@ void Child::run() {
        primarySource->run();
 
        // Wait for the other threads to exit
-       if (ftraceSource != NULL) {
-               ftraceSource->join();
-       }
        if (userSpaceSource != NULL) {
                userSpaceSource->join();
        }
@@ -384,7 +365,6 @@ void Child::run() {
 
        logg->logMessage("Profiling ended.");
 
-       delete ftraceSource;
        delete userSpaceSource;
        delete externalSource;
        delete primarySource;
index 0a6e3b9..22f8be7 100644 (file)
@@ -9,6 +9,7 @@
 #include "Command.h"
 
 #include <fcntl.h>
+#include <grp.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <sys/prctl.h>
 #include "Logging.h"
 #include "SessionData.h"
 
-static int getUid(const char *const name, char *const shPath, const char *const tmpDir) {
+static int getUid(const char *const name, const char *const tmpDir, uid_t *const uid) {
        // Lookups may fail when using a different libc or a statically compiled executable
        char gatorTemp[32];
        snprintf(gatorTemp, sizeof(gatorTemp), "%s/gator_temp", tmpDir);
 
        const int fd = open(gatorTemp, 600, O_CREAT | O_CLOEXEC);
        if (fd < 0) {
-               return -1;
+               return false;
        }
        close(fd);
 
@@ -43,15 +44,7 @@ static int getUid(const char *const name, char *const shPath, const char *const
                handleException();
        }
        if (pid == 0) {
-               char cargv1[] = "-c";
-               char *cargv[] = {
-                       shPath,
-                       cargv1,
-                       cmd,
-                       NULL,
-               };
-
-               execv(cargv[0], cargv);
+               execlp("sh", "sh", "-c", cmd, NULL);
                exit(-1);
        }
        while ((waitpid(pid, NULL, 0) < 0) && (errno == EINTR));
@@ -62,38 +55,42 @@ static int getUid(const char *const name, char *const shPath, const char *const
                result = st.st_uid;
        }
        unlink(gatorTemp);
-       return result;
+       *uid = result;
+       return true;
 }
 
-static int getUid(const char *const name) {
+static bool getUid(const char *const name, uid_t *const uid, gid_t *const gid) {
        // Look up the username
        struct passwd *const user = getpwnam(name);
        if (user != NULL) {
-               return user->pw_uid;
+               *uid = user->pw_uid;
+               *gid = user->pw_gid;
+               return true;
        }
 
+       // Unable to get the user without getpwanm, so create a unique uid by adding a fixed number to the pid
+       *gid = 0x484560f8 + getpid();
 
        // Are we on Linux
-       char cargv0l[] = "/bin/sh";
-       if ((access(cargv0l, X_OK) == 0) && (access("/tmp", W_OK) == 0)) {
-               return getUid(name, cargv0l, "/tmp");
+       if (access("/tmp", W_OK) == 0) {
+               return getUid(name, "/tmp", uid);
        }
 
        // Are we on android
-       char cargv0a[] = "/system/bin/sh";
-       if ((access(cargv0a, X_OK) == 0) && (access("/data", W_OK) == 0)) {
-               return getUid(name, cargv0a, "/data");
+       if (access("/data", W_OK) == 0) {
+               return getUid(name, "/data", uid);
        }
 
-       return -1;
+       return false;
 }
 
 void *commandThread(void *) {
        prctl(PR_SET_NAME, (unsigned long)&"gatord-command", 0, 0, 0);
 
        const char *const name = gSessionData->mCaptureUser == NULL ? "nobody" : gSessionData->mCaptureUser;
-       const int uid = getUid(name);
-       if (uid < 0) {
+       uid_t uid;
+       gid_t gid;
+       if (!getUid(name, &uid, &gid)) {
                logg->logError("Unable to look up the user %s, please double check that the user exists", name);
                handleException();
        }
@@ -113,16 +110,6 @@ void *commandThread(void *) {
                handleException();
        }
        if (pid == 0) {
-               char cargv0l[] = "/bin/sh";
-               char cargv0a[] = "/system/bin/sh";
-               char cargv1[] = "-c";
-               char *cargv[] = {
-                       cargv0l,
-                       cargv1,
-                       gSessionData->mCaptureCommand,
-                       NULL,
-               };
-
                buf[0] = '\0';
                close(pipefd[0]);
 
@@ -132,8 +119,16 @@ void *commandThread(void *) {
                        goto fail_exit;
                }
 
-               if (setuid(uid) != 0) {
-                       snprintf(buf, sizeof(buf), "setuid failed");
+               if (setgroups(1, &gid) != 0) {
+                       snprintf(buf, sizeof(buf), "setgroups failed");
+                       goto fail_exit;
+               }
+               if (setresgid(gid, gid, gid) != 0) {
+                       snprintf(buf, sizeof(buf), "setresgid failed");
+                       goto fail_exit;
+               }
+               if (setresuid(uid, uid, uid) != 0) {
+                       snprintf(buf, sizeof(buf), "setresuid failed");
                        goto fail_exit;
                }
 
@@ -145,9 +140,7 @@ void *commandThread(void *) {
                        }
                }
 
-               execv(cargv[0], cargv);
-               cargv[0] = cargv0a;
-               execv(cargv[0], cargv);
+               execlp("sh", "sh", "-c", gSessionData->mCaptureCommand, NULL);
                snprintf(buf, sizeof(buf), "execv failed");
 
        fail_exit:
index eb31556..3c6752e 100644 (file)
@@ -9,12 +9,19 @@
 #ifndef CONFIG_H
 #define CONFIG_H
 
+#define STRIFY2(ARG) #ARG
+#define STRIFY(ARG) STRIFY2(ARG)
+
 #define ARRAY_LENGTH(A) static_cast<int>(sizeof(A)/sizeof((A)[0]))
 #define ACCESS_ONCE(x) (*(volatile typeof(x)*)&(x))
 
 #define MAX_PERFORMANCE_COUNTERS 50
 #define NR_CPUS 32
 
+// If debugfs is not mounted at /sys/kernel/debug, update TRACING_PATH
+#define TRACING_PATH "/sys/kernel/debug/tracing"
+#define EVENTS_PATH TRACING_PATH "/events"
+
 template<typename T>
 static inline T min(const T a, const T b) {
        return (a < b ? a : b);
index be224a4..b433811 100644 (file)
@@ -68,8 +68,10 @@ int ConfigurationXML::parse(const char* configurationXML) {
        mxml_node_t *tree, *node;
        int ret;
 
-       // clear counter overflow
-       gSessionData->mCounterOverflow = 0;
+       if (gSessionData->mCountersError != NULL) {
+               free(gSessionData->mCountersError);
+               gSessionData->mCountersError = NULL;
+       }
        gSessionData->mIsEBS = false;
        mIndex = 0;
 
@@ -98,6 +100,14 @@ int ConfigurationXML::parse(const char* configurationXML) {
 
        mxmlDelete(tree);
 
+       if (gSessionData->mCountersError == NULL && mIndex > MAX_PERFORMANCE_COUNTERS) {
+               if (asprintf(&gSessionData->mCountersError, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, mIndex) <= 0) {
+                       logg->logError("asprintf failed");
+                       handleException();
+               }
+       }
+       gSessionData->mCcnDriver.validateCounters();
+
        return ret;
 }
 
@@ -149,7 +159,6 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
        // handle all other performance counters
        if (mIndex >= MAX_PERFORMANCE_COUNTERS) {
                mIndex++;
-               gSessionData->mCounterOverflow = mIndex;
                return;
        }
 
index af62bb9..bd18bbd 100644 (file)
@@ -53,7 +53,7 @@ DiskIODriver::~DiskIODriver() {
 
 void DiskIODriver::readEvents(mxml_node_t *const) {
        // Only for use with perf
-       if (!gSessionData->perf.isSetup()) {
+       if (!gSessionData->mPerf.isSetup()) {
                return;
        }
 
index 34920ce..caa956f 100644 (file)
 extern Child *child;
 
 DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL), mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) {
-       int driver_version = 0;
-
        mBuffer = new Buffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem);
-       if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
-               logg->logError("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(
-                               "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(
-                               "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();
-               }
-       }
+       checkVersion();
 
        int enable = -1;
        if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) {
@@ -85,6 +60,35 @@ DriverSource::~DriverSource() {
        }
 }
 
+void DriverSource::checkVersion() {
+       int driverVersion = 0;
+
+       if (readIntDriver("/dev/gator/version", &driverVersion) == -1) {
+               logg->logError("Error reading gator driver version");
+               handleException();
+       }
+
+       // Verify the driver version matches the daemon version
+       if (driverVersion != PROTOCOL_VERSION) {
+               if ((driverVersion > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
+                       // One of the mismatched versions is development version
+                       logg->logError(
+                               "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", driverVersion, PROTOCOL_VERSION);
+                       handleException();
+               } else {
+                       // Release version mismatch
+                       logg->logError(
+                               "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
+                               ">> Please upgrade the driver and daemon to the latest versions.", driverVersion, PROTOCOL_VERSION);
+                       handleException();
+               }
+       }
+}
+
 bool DriverSource::prepare() {
        // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
        logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, mBufferSize);
index 32d983d..971a4d9 100644 (file)
@@ -29,6 +29,7 @@ public:
        bool isDone();
        void write(Sender *sender);
 
+       static void checkVersion();
        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);
index cec08d5..d8044d8 100644 (file)
@@ -50,7 +50,7 @@ mxml_node_t *EventsXML::getTree() {
        // Load the provided or default events xml
        if (gSessionData->mEventsXMLPath) {
                strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
-               fl = fopen(path, "r");
+               fl = fopen_cloexec(path, "r");
                if (fl) {
                        xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
                        fclose(fl);
@@ -63,7 +63,7 @@ mxml_node_t *EventsXML::getTree() {
 
        // Append additional events XML
        if (gSessionData->mEventsXMLAppend) {
-               fl = fopen(gSessionData->mEventsXMLAppend, "r");
+               fl = fopen_cloexec(gSessionData->mEventsXMLAppend, "r");
                if (fl == NULL) {
                        logg->logError("Unable to open additional events XML %s", gSessionData->mEventsXMLAppend);
                        handleException();
diff --git a/tools/gator/daemon/ExternalDriver.cpp b/tools/gator/daemon/ExternalDriver.cpp
new file mode 100644 (file)
index 0000000..c1b7983
--- /dev/null
@@ -0,0 +1,269 @@
+/**
+ * Copyright (C) ARM Limited 2010-2015. 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 "ExternalDriver.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "Buffer.h"
+#include "Logging.h"
+#include "OlySocket.h"
+#include "SessionData.h"
+
+static const char MALI_UTGARD_SETUP[] = "\0mali-utgard-setup";
+static const char SETUP_VERSION[] = "ANNOTATE_SETUP 1\n";
+static const size_t HEADER_SIZE = 1 + sizeof(uint32_t);
+
+#define HEADER_ERROR            0x80
+#define HEADER_ACK              0x81
+#define HEADER_REQUEST_COUNTERS 0x82
+#define HEADER_COUNTERS         0x83
+#define HEADER_ENABLE_COUNTERS  0x84
+#define HEADER_START            0x85
+
+static uint32_t readLEInt(char *const buf)
+{
+       size_t i;
+       uint32_t v;
+
+       v = 0;
+       for (i = 0; i < sizeof(v); ++i)
+               v |= (uint32_t)buf[i] << 8*i;
+
+       return v;
+}
+
+static int readPackedInt(char *const buf, const size_t bufSize, size_t *const pos, uint64_t *const l)
+{
+       uint8_t shift = 0;
+       uint8_t b = ~0;
+
+       *l = 0;
+       while ((b & 0x80) != 0) {
+               if (*pos >= bufSize) {
+                       return -1;
+               }
+               b = buf[*pos];
+               *pos += 1;
+               *l |= (uint64_t)(b & 0x7f) << shift;
+               shift += 7;
+       }
+
+       if (shift < 8*sizeof(*l) && (b & 0x40) != 0) {
+               *l |= -(1 << shift);
+       }
+
+       return 0;
+}
+
+class ExternalCounter : public DriverCounter {
+public:
+       ExternalCounter(DriverCounter *next, const char *name, int cores) : DriverCounter(next, name), mCores(cores), mEvent(-1) {}
+
+       ~ExternalCounter() {
+       }
+
+       int getCores() const { return mCores; }
+       void setEvent(const int event) { mEvent = event; }
+       int getEvent() const { return mEvent; }
+
+private:
+       const int mCores;
+       int mEvent;
+
+       // Intentionally undefined
+       ExternalCounter(const ExternalCounter &);
+       ExternalCounter &operator=(const ExternalCounter &);
+};
+
+ExternalDriver::ExternalDriver() : mUds(-1), mQueried(false), mStarted(false) {
+}
+
+bool ExternalDriver::connect() const {
+       if (mUds < 0) {
+               mUds = OlySocket::connect(MALI_UTGARD_SETUP, sizeof(MALI_UTGARD_SETUP));
+               if (mUds >= 0 && !writeAll(mUds, SETUP_VERSION, sizeof(SETUP_VERSION) - 1)) {
+                       logg->logError("Unable to send setup version");
+                       handleException();
+               }
+       }
+       return mUds >= 0;
+}
+
+void ExternalDriver::disconnect() {
+       if (mUds >= 0) {
+               close(mUds);
+               mUds = -1;
+               mStarted = false;
+       }
+}
+
+void ExternalDriver::query() const {
+       if (mQueried) {
+               return;
+       }
+       // Only try once even if it fails otherwise not all the possible counters may be shown
+       mQueried = true;
+
+       char *const buf = gSessionData->mSharedData->mMaliUtgardCounters;
+       const size_t bufSize = sizeof(gSessionData->mSharedData->mMaliUtgardCounters);
+       size_t size = 0;
+
+       if (!connect()) {
+               size = gSessionData->mSharedData->mMaliUtgardCountersSize;
+               logg->logMessage("Unable to connect, using cached version; size: %zi", size);
+       } else {
+               gSessionData->mSharedData->mMaliUtgardCountersSize = 0;
+
+               buf[0] = HEADER_REQUEST_COUNTERS;
+               size_t pos = HEADER_SIZE;
+               Buffer::writeLEInt((unsigned char *)(buf + 1), pos);
+               if (!writeAll(mUds, buf, pos)) {
+                       logg->logError("Unable to send request counters message");
+                       handleException();
+               }
+
+               if (!readAll(mUds, buf, HEADER_SIZE) || buf[0] != (char)HEADER_COUNTERS) {
+                       logg->logError("Unable to read request counters response header");
+                       handleException();
+               }
+               size = readLEInt(buf + 1);
+               if (size > bufSize || !readAll(mUds, buf, size - HEADER_SIZE)) {
+                       logg->logError("Unable to read request counters response");
+                       handleException();
+               }
+
+               size -= HEADER_SIZE;
+               gSessionData->mSharedData->mMaliUtgardCountersSize = size;
+               logg->logMessage("Requested counters; size: %zi", size);
+       }
+
+       size_t pos = 0;
+       while (pos < size) {
+               size_t begin = pos;
+               char *name = NULL;
+               uint64_t cores = -1;
+               while (pos < size && buf[pos] != '\0') {
+                       ++pos;
+               }
+               if (pos > begin) {
+                       name = strndup(buf + begin, pos - begin);
+               }
+               if (pos < size && buf[pos] == '\0') {
+                       ++pos;
+               }
+               ;
+               if (name != NULL && readPackedInt(buf, bufSize, &pos, &cores) == 0) {
+                       // Cheat so that this can be 'const'
+                       ((ExternalDriver *)(this))->setCounters(new ExternalCounter(getCounters(), name, cores));
+               }
+       }
+
+       if (pos != size) {
+               logg->logError("Unable to parse request counters response");
+               handleException();
+       }
+}
+
+void ExternalDriver::start() {
+       if (!connect()) {
+               return;
+       }
+
+       if (mStarted) {
+               return;
+       }
+       // Only start once
+       mStarted = true;
+
+       char buf[1<<12];
+       int pos;
+
+       buf[0] = HEADER_ENABLE_COUNTERS;
+       pos = HEADER_SIZE;
+       for (ExternalCounter *counter = static_cast<ExternalCounter *>(getCounters()); counter != NULL; counter = static_cast<ExternalCounter *>(counter->getNext())) {
+               if (!counter->isEnabled()) {
+                       continue;
+               }
+               size_t nameLen = strlen(counter->getName());
+               if (pos + nameLen + 1 + 2*Buffer::MAXSIZE_PACK32 > sizeof(buf)) {
+                       logg->logError("Unable to enable counters, message is too large");
+                       handleException();
+               }
+               memcpy(buf + pos, counter->getName(), nameLen + 1);
+               pos += nameLen + 1;
+               Buffer::packInt(buf, sizeof(buf), pos, counter->getEvent());
+               Buffer::packInt(buf, sizeof(buf), pos, counter->getKey());
+       }
+       Buffer::writeLEInt((unsigned char *)(buf + 1), pos);
+       if (!writeAll(mUds, buf, pos)) {
+               logg->logError("Unable to send enable counters message");
+               handleException();
+       }
+
+       size_t size = 0;
+       if (!readAll(mUds, buf, HEADER_SIZE) || buf[0] != (char)HEADER_ACK) {
+               logg->logError("Unable to read enable counters response header");
+               handleException();
+       }
+       size = readLEInt(buf + 1);
+       if (size != HEADER_SIZE) {
+               logg->logError("Unable to parse enable counters response");
+               handleException();
+       }
+
+       buf[0] = HEADER_START;
+       pos = HEADER_SIZE;
+       // ns/sec / samples/sec = ns/sample
+       // For sample rate of none, sample every 100ms
+       Buffer::packInt(buf, sizeof(buf), pos, NS_PER_S / (gSessionData->mSampleRate == 0 ? 10 : gSessionData->mSampleRate));
+       Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mLiveRate);
+       Buffer::writeLEInt((unsigned char *)(buf + 1), pos);
+       if (!writeAll(mUds, buf, pos)) {
+               logg->logError("Unable to send start message");
+               handleException();
+       }
+
+       size = 0;
+       if (!readAll(mUds, buf, HEADER_SIZE) || buf[0] != (char)HEADER_ACK) {
+               logg->logError("Unable to read start response header");
+               handleException();
+       }
+       size = readLEInt(buf + 1);
+       if (size != HEADER_SIZE) {
+               logg->logError("Unable to parse start response");
+               handleException();
+       }
+}
+
+bool ExternalDriver::claimCounter(const Counter &counter) const {
+       query();
+       return super::claimCounter(counter);
+}
+
+void ExternalDriver::setupCounter(Counter &counter) {
+       ExternalCounter *const externalCounter = static_cast<ExternalCounter *>(findCounter(counter));
+       if (externalCounter == NULL) {
+               counter.setEnabled(false);
+               return;
+       }
+       externalCounter->setEnabled(true);
+       counter.setKey(externalCounter->getKey());
+       if (counter.getEvent() != -1) {
+               externalCounter->setEvent(counter.getEvent());
+       }
+       if (externalCounter->getCores() > 0) {
+               counter.setCores(externalCounter->getCores());
+       }
+}
+
+void ExternalDriver::resetCounters() {
+       query();
+       super::resetCounters();
+}
diff --git a/tools/gator/daemon/ExternalDriver.h b/tools/gator/daemon/ExternalDriver.h
new file mode 100644 (file)
index 0000000..d88f9e1
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) ARM Limited 2010-2015. 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 EXTERNALDRIVER_H
+#define EXTERNALDRIVER_H
+
+#include "Driver.h"
+
+class ExternalDriver : public SimpleDriver {
+public:
+       ExternalDriver();
+
+       bool claimCounter(const Counter &counter) const;
+       void resetCounters();
+       void setupCounter(Counter &counter);
+
+       void start();
+
+       void disconnect();
+
+private:
+       typedef SimpleDriver super;
+
+       bool connect() const;
+       void query() const;
+
+       mutable int mUds;
+       mutable bool mQueried;
+       bool mStarted;
+
+       // Intentionally unimplemented
+       ExternalDriver(const ExternalDriver &);
+       ExternalDriver &operator=(const ExternalDriver &);
+};
+
+#endif // EXTERNALDRIVER_H
index 8d71b6d..e87fb9e 100644 (file)
@@ -13,6 +13,7 @@
 #include <unistd.h>
 
 #include "Child.h"
+#include "DriverSource.h"
 #include "Logging.h"
 #include "OlySocket.h"
 #include "SessionData.h"
@@ -26,25 +27,10 @@ static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n";
 static const char MALI_GRAPHICS[] = "\0mali_thirdparty_server";
 static const char MALI_GRAPHICS_STARTUP[] = "\0mali_thirdparty_client";
 static const char MALI_GRAPHICS_V1[] = "MALI_GRAPHICS 1\n";
+static const char MALI_UTGARD_STARTUP[] = "\0mali-utgard-startup";
+static const char FTRACE_V1[] = "FTRACE 1\n";
 
-static bool setNonblock(const int fd) {
-       int flags;
-
-       flags = fcntl(fd, F_GETFL);
-       if (flags < 0) {
-               logg->logMessage("fcntl getfl failed");
-               return false;
-       }
-
-       if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
-               logg->logMessage("fcntl setfl failed");
-               return false;
-       }
-
-       return true;
-}
-
-ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mAnnotate(8083), mAnnotateUds(STREAMLINE_ANNOTATE, sizeof(STREAMLINE_ANNOTATE), true), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) {
+ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mUtgardStartupUds(MALI_UTGARD_STARTUP, sizeof(MALI_UTGARD_STARTUP)), mAnnotate(8083), mAnnotateUds(STREAMLINE_ANNOTATE, sizeof(STREAMLINE_ANNOTATE), true), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1), mFtraceFd(-1) {
        sem_init(&mBufferSem, 0, 0);
 }
 
@@ -91,7 +77,7 @@ bool ExternalSource::connectMali() {
 }
 
 bool ExternalSource::connectMve() {
-       if (!gSessionData->maliVideo.countersEnabled()) {
+       if (!gSessionData->mMaliVideo.countersEnabled()) {
                return true;
        }
 
@@ -100,7 +86,7 @@ bool ExternalSource::connectMve() {
                return false;
        }
 
-       if (!gSessionData->maliVideo.start(mMveUds)) {
+       if (!gSessionData->mMaliVideo.start(mMveUds)) {
                return false;
        }
 
@@ -109,10 +95,27 @@ bool ExternalSource::connectMve() {
        return true;
 }
 
+void ExternalSource::connectFtrace() {
+       if (!gSessionData->mFtraceDriver.isSupported()) {
+               return;
+       }
+
+       gSessionData->mFtraceDriver.prepare();
+
+       mFtraceFd = open(TRACING_PATH "/trace_pipe", O_RDONLY | O_CLOEXEC);
+       if (mFtraceFd < 0) {
+               logg->logError("Unable to open trace_pipe");
+               handleException();
+       }
+
+       configureConnection(mFtraceFd, FTRACE_V1, sizeof(FTRACE_V1));
+}
+
 bool ExternalSource::prepare() {
        if (!mMonitor.init() ||
                        !setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd()) ||
                        !setNonblock(mMaliStartupUds.getFd()) || !mMonitor.add(mMaliStartupUds.getFd()) ||
+                       !setNonblock(mUtgardStartupUds.getFd()) || !mMonitor.add(mUtgardStartupUds.getFd()) ||
                        !setNonblock(mAnnotate.getFd()) || !mMonitor.add(mAnnotate.getFd()) ||
                        !setNonblock(mAnnotateUds.getFd()) || !mMonitor.add(mAnnotateUds.getFd()) ||
                        false) {
@@ -121,6 +124,8 @@ bool ExternalSource::prepare() {
 
        connectMali();
        connectMve();
+       connectFtrace();
+       gSessionData->mExternalDriver.start();
 
        return true;
 }
@@ -147,6 +152,30 @@ void ExternalSource::run() {
                logg->logMessage("Writing to annotate pipe failed");
        }
 
+       if (mFtraceFd >= 0) {
+               gSessionData->mAtraceDriver.start();
+
+               if (DriverSource::writeDriver(TRACING_PATH "/tracing_on", "1") != 0) {
+                       logg->logError("Unable to turn ftrace on");
+                       handleException();
+               }
+       }
+
+       // Wait until monotonicStarted is set before sending data
+       int64_t monotonicStarted = 0;
+       while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
+               usleep(10);
+
+               if (gSessionData->mPerf.isSetup()) {
+                       monotonicStarted = gSessionData->mMonotonicStarted;
+               } else {
+                       if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
+                               logg->logError("Error reading gator driver start time");
+                               handleException();
+                       }
+               }
+       }
+
        while (gSessionData->mSessionIsActive) {
                struct epoll_event events[16];
                // Clear any pending sem posts
@@ -179,6 +208,13 @@ void ExternalSource::run() {
                                        logg->logError("Unable to configure incoming Mali graphics connection");
                                        handleException();
                                }
+                       } else if (fd == mUtgardStartupUds.getFd()) {
+                               // Mali Utgard says it's alive
+                               int client = mUtgardStartupUds.acceptConnection();
+                               // Don't read from this connection, configure utgard and expect them to reconnect with annotations
+                               close(client);
+                               gSessionData->mExternalDriver.disconnect();
+                               gSessionData->mExternalDriver.start();
                        } else if (fd == mAnnotate.getFd()) {
                                int client = mAnnotate.acceptConnection();
                                if (!setNonblock(client) || !mMonitor.add(client)) {
@@ -243,8 +279,14 @@ void ExternalSource::run() {
 
        mBuffer.setDone();
 
+       if (mFtraceFd >= 0) {
+               gSessionData->mFtraceDriver.stop();
+               gSessionData->mAtraceDriver.stop();
+               close(mFtraceFd);
+       }
+
        if (mMveUds >= 0) {
-               gSessionData->maliVideo.stop(mMveUds);
+               gSessionData->mMaliVideo.stop(mMveUds);
        }
 
        mInterruptFd = -1;
index 25ae7cd..69d16af 100644 (file)
@@ -34,17 +34,20 @@ private:
        void configureConnection(const int fd, const char *const handshake, size_t size);
        bool connectMali();
        bool connectMve();
+       void connectFtrace();
 
        sem_t mBufferSem;
        Buffer mBuffer;
        Monitor mMonitor;
        OlyServerSocket mMveStartupUds;
        OlyServerSocket mMaliStartupUds;
+       OlyServerSocket mUtgardStartupUds;
        OlyServerSocket mAnnotate;
        OlyServerSocket mAnnotateUds;
        int mInterruptFd;
        int mMaliUds;
        int mMveUds;
+       int mFtraceFd;
 
        // Intentionally unimplemented
        ExternalSource(const ExternalSource &);
index 98bd0a5..7c57cfc 100644 (file)
 
 #include <regex.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
+#include "Config.h"
 #include "DriverSource.h"
 #include "Logging.h"
+#include "SessionData.h"
 #include "Setup.h"
 
 class FtraceCounter : public DriverCounter {
 public:
-       FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable);
+       FtraceCounter(DriverCounter *next, char *name, const char *enable);
        ~FtraceCounter();
 
        void prepare();
-       int read(const char *const line, int64_t *values);
        void stop();
 
 private:
-       regex_t mReg;
        char *const mEnable;
        int mWasEnabled;
 
@@ -34,18 +37,10 @@ private:
        FtraceCounter &operator=(const FtraceCounter &);
 };
 
-FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable) : DriverCounter(next, name), mEnable(enable == NULL ? NULL : strdup(enable)) {
-       int result = regcomp(&mReg, regex, REG_EXTENDED);
-       if (result != 0) {
-               char buf[128];
-               regerror(result, &mReg, buf, sizeof(buf));
-               logg->logError("Invalid regex '%s': %s", regex, buf);
-               handleException();
-       }
+FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *enable) : DriverCounter(next, name), mEnable(enable == NULL ? NULL : strdup(enable)) {
 }
 
 FtraceCounter::~FtraceCounter() {
-       regfree(&mReg);
        if (mEnable != NULL) {
                free(mEnable);
        }
@@ -57,7 +52,7 @@ void FtraceCounter::prepare() {
        }
 
        char buf[1<<10];
-       snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
+       snprintf(buf, sizeof(buf), EVENTS_PATH "/%s/enable", mEnable);
        if ((DriverSource::readIntDriver(buf, &mWasEnabled) != 0) ||
                        (DriverSource::writeDriver(buf, 1) != 0)) {
                logg->logError("Unable to read or write to %s", buf);
@@ -65,43 +60,17 @@ void FtraceCounter::prepare() {
        }
 }
 
-int FtraceCounter::read(const char *const line, int64_t *values) {
-       regmatch_t match[2];
-       int result = regexec(&mReg, line, 2, match, 0);
-       if (result != 0) {
-               // No match
-               return 0;
-       }
-
-       int64_t value;
-       if (match[1].rm_so < 0) {
-               value = 1;
-       } else {
-               errno = 0;
-               value = strtoll(line + match[1].rm_so, NULL, 0);
-               if (errno != 0) {
-                       logg->logError("Parsing %s failed: %s", getName(), strerror(errno));
-                       handleException();
-               }
-       }
-
-       values[0] = getKey();
-       values[1] = value;
-
-       return 1;
-}
-
 void FtraceCounter::stop() {
        if (mEnable == NULL) {
                return;
        }
 
        char buf[1<<10];
-       snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
+       snprintf(buf, sizeof(buf), EVENTS_PATH "/%s/enable", mEnable);
        DriverSource::writeDriver(buf, mWasEnabled);
 }
 
-FtraceDriver::FtraceDriver() : mValues(NULL) {
+FtraceDriver::FtraceDriver() : mValues(NULL), mSupported(false), mTracingOn(0) {
 }
 
 FtraceDriver::~FtraceDriver() {
@@ -118,10 +87,20 @@ void FtraceDriver::readEvents(mxml_node_t *const xml) {
 
        // The perf clock was added in 3.10
        if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 10, 0)) {
+               mSupported = false;
                logg->logMessage("Unsupported kernel version, to use ftrace please upgrade to Linux 3.10 or later");
                return;
        }
 
+       // Is debugfs or tracefs available?
+       if (access(TRACING_PATH, R_OK) != 0) {
+               mSupported = false;
+               logg->logMessage("Unable to locate the tracing directory, disabling ftrace");
+               return;
+       }
+
+       mSupported = true;
+
        mxml_node_t *node = xml;
        int count = 0;
        while (true) {
@@ -143,20 +122,28 @@ void FtraceDriver::readEvents(mxml_node_t *const xml) {
                        logg->logError("The regex counter %s is missing the required regex attribute", counter);
                        handleException();
                }
-               bool addCounter = true;
+
+               const char *tracepoint = mxmlElementGetAttr(node, "tracepoint");
                const char *enable = mxmlElementGetAttr(node, "enable");
+               if (enable == NULL) {
+                       enable = tracepoint;
+               }
+               if (gSessionData->mPerf.isSetup() && tracepoint != NULL) {
+                       logg->logMessage("Not using ftrace for counter %s", counter);
+                       continue;
+               }
                if (enable != NULL) {
                        char buf[1<<10];
-                       snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", enable);
+                       snprintf(buf, sizeof(buf), EVENTS_PATH "/%s/enable", enable);
                        if (access(buf, W_OK) != 0) {
                                logg->logMessage("Disabling counter %s, %s not found", counter, buf);
-                               addCounter = false;
+                               continue;
                        }
                }
-               if (addCounter) {
-                       setCounters(new FtraceCounter(getCounters(), strdup(counter), regex, enable));
-                       ++count;
-               }
+
+               logg->logMessage("Using ftrace for %s", counter);
+               setCounters(new FtraceCounter(getCounters(), strdup(counter), enable));
+               ++count;
        }
 
        mValues = new int64_t[2*count];
@@ -169,23 +156,37 @@ void FtraceDriver::prepare() {
                }
                counter->prepare();
        }
-}
 
-int FtraceDriver::read(const char *line, int64_t **buf) {
-       int count = 0;
+       if (DriverSource::readIntDriver(TRACING_PATH "/tracing_on", &mTracingOn)) {
+               logg->logError("Unable to read if ftrace is enabled");
+               handleException();
+       }
 
-       for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
-               if (!counter->isEnabled()) {
-                       continue;
+       if (DriverSource::writeDriver(TRACING_PATH "/tracing_on", "0") != 0) {
+               logg->logError("Unable to turn ftrace off before truncating the buffer");
+               handleException();
+       }
+
+       {
+               int fd;
+               fd = open(TRACING_PATH "/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
+               if (fd < 0) {
+                       logg->logError("Unable truncate ftrace buffer: %s", strerror(errno));
+                       handleException();
                }
-               count += counter->read(line, mValues + 2*count);
+               close(fd);
        }
 
-       *buf = mValues;
-       return count;
+       if (DriverSource::writeDriver(TRACING_PATH "/trace_clock", "perf") != 0) {
+               logg->logError("Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
+               handleException();
+       }
 }
 
 void FtraceDriver::stop() {
+       DriverSource::writeDriver(TRACING_PATH "/tracing_on", mTracingOn);
+       DriverSource::writeDriver(TRACING_PATH "/trace_clock", "local");
+
        for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
                if (!counter->isEnabled()) {
                        continue;
index b79dc91..6e592d7 100644 (file)
@@ -19,11 +19,14 @@ public:
        void readEvents(mxml_node_t *const xml);
 
        void prepare();
-       int read(const char *line, int64_t **buf);
        void stop();
 
+       bool isSupported() const { return mSupported; }
+
 private:
        int64_t *mValues;
+       bool mSupported;
+       int mTracingOn;
 
        // Intentionally unimplemented
        FtraceDriver(const FtraceDriver &);
diff --git a/tools/gator/daemon/FtraceSource.cpp b/tools/gator/daemon/FtraceSource.cpp
deleted file mode 100644 (file)
index 14a48b3..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2010-2015. 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 "FtraceSource.h"
-
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#include "Child.h"
-#include "DriverSource.h"
-#include "Logging.h"
-#include "SessionData.h"
-
-extern Child *child;
-
-static void handler(int signum)
-{
-       (void)signum;
-};
-
-FtraceSource::FtraceSource(sem_t *senderSem) : mFtraceFh(NULL), mBuffer(0, FRAME_BLOCK_COUNTER, 128*1024, senderSem), mTid(-1), mTracingOn(0) {
-}
-
-FtraceSource::~FtraceSource() {
-}
-
-bool FtraceSource::prepare() {
-       {
-               struct sigaction act;
-               act.sa_handler = handler;
-               act.sa_flags = (int)SA_RESETHAND;
-               if (sigaction(SIGUSR1, &act, NULL) != 0) {
-                       logg->logError("sigaction failed: %s\n", strerror(errno));
-                       handleException();
-               }
-       }
-
-       gSessionData->ftraceDriver.prepare();
-
-       if (DriverSource::readIntDriver("/sys/kernel/debug/tracing/tracing_on", &mTracingOn)) {
-               logg->logError("Unable to read if ftrace is enabled");
-               handleException();
-       }
-
-       if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "0") != 0) {
-               logg->logError("Unable to turn ftrace off before truncating the buffer");
-               handleException();
-       }
-
-       {
-               int fd;
-               fd = open("/sys/kernel/debug/tracing/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
-               if (fd < 0) {
-                       logg->logError("Unable truncate ftrace buffer: %s", strerror(errno));
-                       handleException();
-               }
-               close(fd);
-       }
-
-       if (DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "perf") != 0) {
-               logg->logError("Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
-               handleException();
-       }
-
-       mFtraceFh = fopen_cloexec("/sys/kernel/debug/tracing/trace_pipe", "rb");
-       if (mFtraceFh == NULL) {
-               logg->logError("Unable to open trace_pipe");
-               handleException();
-       }
-
-       return true;
-}
-
-void FtraceSource::run() {
-       prctl(PR_SET_NAME, (unsigned long)&"gatord-ftrace", 0, 0, 0);
-       mTid = syscall(__NR_gettid);
-
-       if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "1") != 0) {
-               logg->logError("Unable to turn ftrace on");
-               handleException();
-       }
-
-       // Wait until monotonicStarted is set before sending data
-       int64_t monotonicStarted = 0;
-       while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
-               usleep(10);
-
-               if (gSessionData->perf.isSetup()) {
-                       monotonicStarted = gSessionData->mMonotonicStarted;
-               } else {
-                       if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
-                               logg->logError("Error reading gator driver start time");
-                               handleException();
-                       }
-               }
-       }
-
-       while (gSessionData->mSessionIsActive) {
-               char buf[1<<12];
-
-               if (fgets(buf, sizeof(buf), mFtraceFh) == NULL) {
-                       if (errno == EINTR) {
-                               // Interrupted by interrupt - likely user request to terminate
-                               break;
-                       }
-                       logg->logError("Unable read trace data: %s", strerror(errno));
-                       handleException();
-               }
-
-               const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted;
-
-               char *const colon = strstr(buf, ": ");
-               if (colon == NULL) {
-                       if (strstr(buf, " [LOST ") != NULL) {
-                               logg->logError("Ftrace events lost, aborting the capture. It is recommended to discard this report and collect a new capture. If this error occurs often, please reduce the number of ftrace counters selected or the amount of ftrace events generated.");
-                       } else {
-                               logg->logError("Unable to find colon: %s", buf);
-                       }
-                       handleException();
-               }
-               *colon = '\0';
-
-               char *const space = strrchr(buf, ' ');
-               if (space == NULL) {
-                       logg->logError("Unable to find space: %s", buf);
-                       handleException();
-               }
-               *colon = ':';
-
-               int64_t *data = NULL;
-               int count = gSessionData->ftraceDriver.read(colon + 2, &data);
-               if (count > 0) {
-                       errno = 0;
-                       const long long time = strtod(space, NULL) * 1000000000;
-                       if (errno != 0) {
-                               logg->logError("Unable to parse time: %s", strerror(errno));
-                               handleException();
-                       }
-                       mBuffer.event64(-1, time);
-
-                       for (int i = 0; i < count; ++i) {
-                               mBuffer.event64(data[2*i + 0], data[2*i + 1]);
-                       }
-
-                       mBuffer.check(currTime);
-
-                       if (gSessionData->mOneShot && gSessionData->mSessionIsActive && (mBuffer.bytesAvailable() <= 0)) {
-                               logg->logMessage("One shot (ftrace)");
-                               child->endSession();
-                       }
-               }
-
-       }
-
-       mBuffer.setDone();
-
-       DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", mTracingOn);
-       fclose(mFtraceFh);
-       DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "local");
-       gSessionData->ftraceDriver.stop();
-}
-
-void FtraceSource::interrupt() {
-       // Closing the underlying file handle does not result in the read on the ftrace file handle to return, so send a signal to the thread
-       syscall(__NR_tgkill, getpid(), mTid, SIGUSR1);
-}
-
-bool FtraceSource::isDone() {
-       return mBuffer.isDone();
-}
-
-void FtraceSource::write(Sender *sender) {
-       // Don't send ftrace data until the summary packet is sent so that monotonic delta is available
-       if (!gSessionData->mSentSummary) {
-               return;
-       }
-       if (!mBuffer.isDone()) {
-               mBuffer.write(sender);
-       }
-}
diff --git a/tools/gator/daemon/FtraceSource.h b/tools/gator/daemon/FtraceSource.h
deleted file mode 100644 (file)
index bc068d2..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2010-2015. 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 FTRACESOURCE_H
-#define FTRACESOURCE_H
-
-#include <semaphore.h>
-#include <stdio.h>
-
-#include "Buffer.h"
-#include "Source.h"
-
-class FtraceSource : public Source {
-public:
-       FtraceSource(sem_t *senderSem);
-       ~FtraceSource();
-
-       bool prepare();
-       void run();
-       void interrupt();
-
-       bool isDone();
-       void write(Sender *sender);
-
-private:
-       void waitFor(const int bytes);
-
-       FILE *mFtraceFh;
-       Buffer mBuffer;
-       int mTid;
-       int mTracingOn;
-
-       // Intentionally unimplemented
-       FtraceSource(const FtraceSource &);
-       FtraceSource &operator=(const FtraceSource &);
-};
-
-#endif // FTRACESOURCE_H
index 2db332d..209a2d3 100644 (file)
@@ -58,6 +58,7 @@ MaliVideoDriver::~MaliVideoDriver() {
 }
 
 void MaliVideoDriver::readEvents(mxml_node_t *const xml) {
+       // Always create the counters as /dev/mv500 may show up after gatord starts
        mxml_node_t *node = xml;
        while (true) {
                node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
@@ -82,12 +83,22 @@ void MaliVideoDriver::readEvents(mxml_node_t *const xml) {
 
 int MaliVideoDriver::writeCounters(mxml_node_t *root) const {
        if (access("/dev/mv500", F_OK) != 0) {
+               // Don't show the counters in counter configuration
                return 0;
        }
 
        return super::writeCounters(root);
 }
 
+bool MaliVideoDriver::claimCounter(const Counter &counter) const {
+       if (access("/dev/mv500", F_OK) != 0) {
+               // Don't add the counters to captured XML
+               return 0;
+       }
+
+       return super::claimCounter(counter);
+}
+
 void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos) {
        // size
        int numEnabled = 0;
@@ -104,20 +115,6 @@ void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const
        }
 }
 
-static bool writeAll(const int mveUds, const char *const buf, const int pos) {
-       int written = 0;
-       while (written < pos) {
-               size_t bytes = ::write(mveUds, buf + written, pos - written);
-               if (bytes <= 0) {
-                       logg->logMessage("write failed");
-                       return false;
-               }
-               written += bytes;
-       }
-
-       return true;
-}
-
 bool MaliVideoDriver::start(const int mveUds) {
        char buf[256];
        int pos = 0;
@@ -146,7 +143,7 @@ bool MaliVideoDriver::start(const int mveUds) {
        // data_protocol_version
        Buffer::packInt(buf, sizeof(buf), pos, 1);
        // sample_rate - convert samples/second to ms/sample
-       Buffer::packInt(buf, sizeof(buf), pos, 1000/gSessionData->mSampleRate);
+       Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mSampleRate/1000);
        // live_rate - convert ns/flush to ms/flush
        Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mLiveRate/1000000);
 
@@ -183,7 +180,6 @@ void MaliVideoDriver::stop(const int mveUds) {
        buf[pos++] = 'T';
        buf[pos++] = 'O';
        buf[pos++] = 'P';
-       marshalEnable(MVCT_COUNTER, buf, sizeof(buf), pos);
 
        writeAll(mveUds, buf, pos);
 
index 35b0558..fd01b1b 100644 (file)
@@ -30,6 +30,7 @@ public:
        void readEvents(mxml_node_t *const root);
 
        int writeCounters(mxml_node_t *root) const;
+       bool claimCounter(const Counter &counter) const;
 
        bool start(const int mveUds);
        void stop(const int mveUds);
index 6818b97..4c0b051 100644 (file)
@@ -44,7 +44,7 @@ MemInfoDriver::~MemInfoDriver() {
 
 void MemInfoDriver::readEvents(mxml_node_t *const) {
        // Only for use with perf
-       if (!gSessionData->perf.isSetup()) {
+       if (!gSessionData->mPerf.isSetup()) {
                return;
        }
 
index 56b25e0..ab36211 100644 (file)
@@ -52,7 +52,7 @@ NetDriver::~NetDriver() {
 
 void NetDriver::readEvents(mxml_node_t *const) {
        // Only for use with perf
-       if (!gSessionData->perf.isSetup()) {
+       if (!gSessionData->mPerf.isSetup()) {
                return;
        }
 
index 796ee75..e5f8aaa 100644 (file)
@@ -56,9 +56,9 @@ static const struct gator_cpu gator_cpus[] = {
        { 0x51049, "KraitSIM",     "Krait",            4 },
        { 0x5104d, "Krait",        "Krait",            4 },
        { 0x5106f, "Krait S4 Pro", "Krait",            4 },
-       { 0x41d03, "Cortex-A53",   "ARM_Cortex-A53",   6 },
-       { 0x41d07, "Cortex-A57",   "ARM_Cortex-A57",   6 },
-       { 0x41d08, "Cortex-A72",   "ARM_Cortex-A72",   6 },
+       { 0x41d03, "Cortex-A53",   "ARMv8_Cortex_A53", 6 },
+       { 0x41d07, "Cortex-A57",   "ARMv8_Cortex_A57", 6 },
+       { 0x41d08, "Cortex-A72",   "ARMv8_Cortex_A72", 6 },
 };
 
 static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
@@ -75,14 +75,14 @@ struct uncore_counter {
 
 static const struct uncore_counter uncore_counters[] = {
        { "CCI_400",    "CCI_400",     4, true },
-       { "CCI_400-r1", "CCI_400-r1",  4, true },
+       { "CCI_400_r1", "CCI_400_r1",  4, true },
        { "CCI_500",    "CCI_500",     8, false },
        { "ccn",        "ARM_CCN_5XX", 8, true },
 };
 
 class PerfCounter : public DriverCounter {
 public:
-       PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, uint64_t sampleType, uint64_t flags) : DriverCounter(next, name), mType(type), mConfig(config), mSampleType(sampleType), mFlags(flags), mCount(0) {}
+       PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, uint64_t sampleType, uint64_t flags, const int count) : DriverCounter(next, name), mType(type), mConfig(config), mSampleType(sampleType), mFlags(flags), mCount(count) {}
 
        ~PerfCounter() {
        }
@@ -93,13 +93,14 @@ public:
        uint64_t getConfig() const { return mConfig; }
        void setConfig(const uint64_t config) { mConfig = config; }
        uint64_t getSampleType() const { return mSampleType; }
+       void setSampleType(uint64_t sampleType) { mSampleType = sampleType; }
        uint64_t getFlags() const { return mFlags; }
        virtual void read(Buffer *const, const int) {}
 
 private:
        const uint32_t mType;
        uint64_t mConfig;
-       const uint64_t mSampleType;
+       uint64_t mSampleType;
        const uint64_t mFlags;
        int mCount;
 
@@ -110,7 +111,7 @@ private:
 
 class CPUFreqDriver : public PerfCounter {
 public:
-       CPUFreqDriver(DriverCounter *next, uint64_t id) : PerfCounter(next, "Linux_power_cpu_freq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU) {}
+       CPUFreqDriver(DriverCounter *next, uint64_t id) : PerfCounter(next, "Linux_power_cpu_freq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU, 1) {}
 
        void read(Buffer *const buffer, const int cpu) {
                char buf[64];
@@ -135,17 +136,35 @@ PerfDriver::PerfDriver() : mIsSetup(false), mLegacySupport(false) {
 PerfDriver::~PerfDriver() {
 }
 
+class PerfTracepoint {
+public:
+       PerfTracepoint(PerfTracepoint *const next, const DriverCounter *const counter, const char *const tracepoint) : mNext(next), mCounter(counter), mTracepoint(tracepoint) {}
+
+       PerfTracepoint *getNext() const { return mNext; }
+       const DriverCounter *getCounter() const { return mCounter; }
+       const char *getTracepoint() const { return mTracepoint; }
+
+private:
+       PerfTracepoint *const mNext;
+       const DriverCounter *const mCounter;
+       const char *const mTracepoint;
+
+       // Intentionally undefined
+       PerfTracepoint(const PerfTracepoint &);
+       PerfTracepoint &operator=(const PerfTracepoint &);
+};
+
 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);
-       setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+       setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
 
        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);
-               setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+               setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
        }
 }
 
@@ -157,14 +176,60 @@ void PerfDriver::addUncoreCounters(const char *const counterName, const int type
                len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
                name = new char[len];
                snprintf(name, len, "%s_ccnt", counterName);
-               setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0));
+               setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0, 0));
        }
 
        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);
-               setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0));
+               setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0, 0));
+       }
+}
+
+void PerfDriver::readEvents(mxml_node_t *const xml) {
+       mxml_node_t *node = xml;
+       DynBuf printb;
+
+       // Only for use with perf
+       if (!isSetup()) {
+               return;
+       }
+
+       while (true) {
+               node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
+               if (node == NULL) {
+                       break;
+               }
+               const char *counter = mxmlElementGetAttr(node, "counter");
+               if (counter == NULL) {
+                       continue;
+               }
+
+               if (strncmp(counter, "ftrace_", 7) != 0) {
+                       continue;
+               }
+
+               const char *tracepoint = mxmlElementGetAttr(node, "tracepoint");
+               if (tracepoint == NULL) {
+                       const char *regex = mxmlElementGetAttr(node, "regex");
+                       if (regex == NULL) {
+                               logg->logError("The tracepoint counter %s is missing the required tracepoint attribute", counter);
+                               handleException();
+                       } else {
+                               logg->logMessage("Not using perf for counter %s", counter);
+                               continue;
+                       }
+               }
+
+               const char *arg = mxmlElementGetAttr(node, "arg");
+
+               long long id = getTracepointId(tracepoint, &printb);
+               if (id >= 0) {
+                       logg->logMessage("Using perf for %s", counter);
+                       setCounters(new PerfCounter(getCounters(), strdup(counter), PERF_TYPE_TRACEPOINT, id, arg == NULL ? 0 : PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU, 1));
+                       mTracepoints = new PerfTracepoint(mTracepoints, getCounters(), strdup(tracepoint));
+               }
        }
 }
 
@@ -197,6 +262,7 @@ bool PerfDriver::setup() {
 
        struct dirent *dirent;
        while ((dirent = readdir(dir)) != NULL) {
+               logg->logMessage("perf pmu: %s", dirent->d_name);
                for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
                        const struct gator_cpu *const gator_cpu = &gator_cpus[i];
 
@@ -217,7 +283,7 @@ bool PerfDriver::setup() {
                        }
 
                        foundCpu = true;
-                       logg->logMessage("Adding cpu counters for %s", gator_cpu->pmnc_name);
+                       logg->logMessage("Adding cpu counters for %s with type %i", gator_cpu->pmnc_name, type);
                        addCpuCounters(gator_cpu->pmnc_name, type, gator_cpu->pmnc_counters);
                }
 
@@ -233,7 +299,7 @@ bool PerfDriver::setup() {
                                continue;
                        }
 
-                       logg->logMessage("Adding uncore counters for %s", uncore_counters[i].gatorName);
+                       logg->logMessage("Adding uncore counters for %s with type %i", uncore_counters[i].gatorName, type);
                        addUncoreCounters(uncore_counters[i].gatorName, type, uncore_counters[i].count, uncore_counters[i].hasCyclesCounter);
                }
        }
@@ -264,25 +330,25 @@ bool PerfDriver::setup() {
 
        id = getTracepointId("irq/softirq_exit", &printb);
        if (id >= 0) {
-               setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+               setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
        }
 
        id = getTracepointId("irq/irq_handler_exit", &printb);
        if (id >= 0) {
-               setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+               setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
        }
 
        id = getTracepointId(SCHED_SWITCH, &printb);
        if (id >= 0) {
-               setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+               setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
        }
 
        id = getTracepointId(CPU_FREQUENCY, &printb);
-       if (id >= 0) {
+       if (id >= 0 && access("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq", R_OK) == 0) {
                setCounters(new CPUFreqDriver(getCounters(), id));
        }
 
-       setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, 0, 0));
+       setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, 0, 0, 0));
 
        //Linux_cpu_wait_io
 
@@ -300,6 +366,12 @@ bool PerfDriver::summary(Buffer *const buffer) {
        char buf[512];
        snprintf(buf, sizeof(buf), "%s %s %s %s %s GNU/Linux", utsname.sysname, utsname.nodename, utsname.release, utsname.version, utsname.machine);
 
+       long pageSize = sysconf(_SC_PAGESIZE);
+       if (pageSize < 0) {
+               logg->logMessage("sysconf _SC_PAGESIZE failed");
+               return false;
+       }
+
        struct timespec ts;
        if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
                logg->logMessage("clock_gettime failed");
@@ -311,7 +383,7 @@ bool PerfDriver::summary(Buffer *const buffer) {
        gSessionData->mMonotonicStarted = monotonicStarted;
        const uint64_t currTime = 0;//getTime() - gSessionData->mMonotonicStarted;
 
-       buffer->summary(currTime, timestamp, monotonicStarted, monotonicStarted, buf);
+       buffer->summary(currTime, timestamp, monotonicStarted, monotonicStarted, buf, pageSize);
 
        for (int i = 0; i < gSessionData->mCores; ++i) {
                coreName(currTime, buffer, i);
@@ -322,27 +394,28 @@ bool PerfDriver::summary(Buffer *const buffer) {
 }
 
 void PerfDriver::coreName(const uint64_t currTime, Buffer *const buffer, const int cpu) {
+       const SharedData *const sharedData = gSessionData->mSharedData;
        // Don't send information on a cpu we know nothing about
-       if (gSessionData->mCpuIds[cpu] == -1) {
+       if (sharedData->mCpuIds[cpu] == -1) {
                return;
        }
 
        int j;
        for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) {
-               if (gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
+               if (gator_cpus[j].cpuid == sharedData->mCpuIds[cpu]) {
                        break;
                }
        }
-       if (j < ARRAY_LENGTH(gator_cpus) && gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
-               buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], gator_cpus[j].core_name);
+       if (j < ARRAY_LENGTH(gator_cpus) && gator_cpus[j].cpuid == sharedData->mCpuIds[cpu]) {
+               buffer->coreName(currTime, cpu, sharedData->mCpuIds[cpu], gator_cpus[j].core_name);
        } else {
                char buf[32];
-               if (gSessionData->mCpuIds[cpu] == -1) {
+               if (sharedData->mCpuIds[cpu] == -1) {
                        snprintf(buf, sizeof(buf), "Unknown");
                } else {
-                       snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[cpu]);
+                       snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", sharedData->mCpuIds[cpu]);
                }
-               buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], buf);
+               buffer->coreName(currTime, cpu, sharedData->mCpuIds[cpu], buf);
        }
 }
 
@@ -357,27 +430,22 @@ void PerfDriver::setupCounter(Counter &counter) {
        if (counter.getEvent() != -1) {
                perfCounter->setConfig(counter.getEvent());
        }
-       perfCounter->setCount(counter.getCount());
+       if (counter.getCount() > 0) {
+               // EBS
+               perfCounter->setCount(counter.getCount());
+               // Collect samples
+               perfCounter->setSampleType(perfCounter->getSampleType() | PERF_SAMPLE_TID | PERF_SAMPLE_IP);
+       }
        perfCounter->setEnabled(true);
        counter.setKey(perfCounter->getKey());
 }
 
 bool PerfDriver::enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const {
        for (PerfCounter *counter = static_cast<PerfCounter *>(getCounters()); counter != NULL; counter = static_cast<PerfCounter *>(counter->getNext())) {
-               if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
-                       int count = counter->getCount();
-                       uint64_t sampleType = counter->getSampleType();
-                       if (sampleType & PERF_SAMPLE_RAW) {
-                               // If raw is enabled, every sample is needed
-                               count = 1;
-                       }
-                       if (!group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), count,
-                                       // use getCount instead of count as EBS counters need TID and IP but RAW tracepoints don't
-                                       (counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0) | sampleType,
-                                       counter->getFlags())) {
-                               logg->logMessage("PerfGroup::add failed");
-                               return false;
-                       }
+               if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED) &&
+                               !group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), counter->getSampleType(), counter->getFlags())) {
+                       logg->logMessage("PerfGroup::add failed");
+                       return false;
                }
        }
 
@@ -393,6 +461,38 @@ void PerfDriver::read(Buffer *const buffer, const int cpu) {
        }
 }
 
+static bool sendTracepointFormat(const uint64_t currTime, Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
+       if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
+               logg->logMessage("DynBuf::printf failed");
+               return false;
+       }
+       if (!b->read(printb->getBuf())) {
+               logg->logMessage("DynBuf::read failed");
+               return false;
+       }
+       buffer->marshalFormat(currTime, b->getLength(), b->getBuf());
+
+       return true;
+}
+
+bool PerfDriver::sendTracepointFormats(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b) {
+       if (
+               !sendTracepointFormat(currTime, buffer, SCHED_SWITCH, printb, b) ||
+               !sendTracepointFormat(currTime, buffer, CPU_IDLE, printb, b) ||
+               !sendTracepointFormat(currTime, buffer, CPU_FREQUENCY, printb, b) ||
+               false) {
+               return false;
+       }
+
+       for (PerfTracepoint *tracepoint = mTracepoints; tracepoint != NULL; tracepoint = tracepoint->getNext()) {
+               if (tracepoint->getCounter()->isEnabled() && !sendTracepointFormat(currTime, buffer, tracepoint->getTracepoint(), printb, b)) {
+                       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("DynBuf::printf failed");
@@ -401,7 +501,7 @@ long long PerfDriver::getTracepointId(const char *const name, DynBuf *const prin
 
        int64_t result;
        if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) {
-               logg->logMessage("DriverSource::readInt64Driver failed");
+               logg->logMessage("Unable to read tracepoint id for %s", printb->getBuf());
                return -1;
        }
 
index 95b42bf..a38fcde 100644 (file)
 
 #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"
 #define CPU_IDLE "power/cpu_idle"
 #define CPU_FREQUENCY "power/cpu_frequency"
@@ -24,6 +20,7 @@
 class Buffer;
 class DynBuf;
 class PerfGroup;
+class PerfTracepoint;
 
 class PerfDriver : public SimpleDriver {
 public:
@@ -32,6 +29,7 @@ public:
 
        bool getLegacySupport() const { return mLegacySupport; }
 
+       void readEvents(mxml_node_t *const xml);
        bool setup();
        bool summary(Buffer *const buffer);
        void coreName(const uint64_t currTime, Buffer *const buffer, const int cpu);
@@ -41,6 +39,7 @@ public:
 
        bool enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const;
        void read(Buffer *const buffer, const int cpu);
+       bool sendTracepointFormats(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b);
 
        static long long getTracepointId(const char *const name, DynBuf *const printb);
 
@@ -50,6 +49,7 @@ private:
 
        bool mIsSetup;
        bool mLegacySupport;
+       PerfTracepoint *mTracepoints;
 
        // Intentionally undefined
        PerfDriver(const PerfDriver &);
index cfc62e4..9b71531 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/syscall.h>
 #include "SessionData.h"
 
 static const int schedSwitchKey = getEventKey();
-static const int clockKey = getEventKey();
 
 #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 = (gSessionData->perf.getLegacySupport() \
+       pea.sample_type = (gSessionData->mPerf.getLegacySupport() \
                           ? PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_ID \
                           : PERF_SAMPLE_IDENTIFIER ) | PERF_SAMPLE_TIME | additionalSampleType; \
        /* Emit emit value in group format */ \
@@ -132,7 +132,7 @@ bool PerfGroup::createCpuGroup(const uint64_t currTime, Buffer *const buffer) {
                return false;
        }
 
-       if (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && doAdd(currTime, buffer, clockKey, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU) < 0) {
+       if (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && doAdd(currTime, buffer, INT_MAX-PERF_TYPE_HARDWARE, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU) < 0) {
                return false;
        }
 
@@ -152,8 +152,7 @@ bool PerfGroup::add(const uint64_t currTime, Buffer *const buffer, const int key
                } else {
                        // Non-CPU PMUs are sampled every 100ms for Sample Rate: None and EBS, otherwise they would never be sampled
                        const uint64_t timeout = gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS ? 1000000000UL / gSessionData->mSampleRate : 100000000UL;
-                       // PERF_SAMPLE_TID | PERF_SAMPLE_IP aren't helpful on non-CPU or 'uncore' PMUs - which CPU is the right one to sample? But removing it causes problems, remove it later.
-                       mLeaders[effectiveType] = doAdd(currTime, buffer, clockKey, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, timeout, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_LEADER);
+                       mLeaders[effectiveType] = doAdd(currTime, buffer, INT_MAX-effectiveType, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, timeout, PERF_SAMPLE_READ, PERF_GROUP_LEADER);
                        if (mLeaders[effectiveType] < 0) {
                                return false;
                        }
@@ -194,16 +193,12 @@ int PerfGroup::prepareCPU(const int cpu, Monitor *const monitor) {
                                // The core is offline
                                return PG_CPU_OFFLINE;
                        }
-#ifndef USE_STRICTER_CHECK
-                       continue;
-#else
                        if (errno == ENOENT) {
                                // This event doesn't apply to this CPU but should apply to a different one, ex bL
                                continue;
                        }
                        logg->logMessage("perf_event_open failed");
                        return PG_FAILURE;
-#endif
                }
 
                if (!mPb->useFd(cpu, mFds[offset])) {
@@ -236,7 +231,7 @@ static bool readAndSend(const uint64_t currTime, Buffer *const buffer, const int
 int PerfGroup::onlineCPU(const uint64_t currTime, const int cpu, const bool enable, Buffer *const buffer) {
        bool addedEvents = false;
 
-       if (!gSessionData->perf.getLegacySupport()) {
+       if (!gSessionData->mPerf.getLegacySupport()) {
                int idCount = 0;
                int coreKeys[ARRAY_LENGTH(mKeys)];
                __u64 ids[ARRAY_LENGTH(mKeys)];
index 2c45de8..9f34bbd 100644 (file)
@@ -33,20 +33,6 @@ extern Child *child;
 
 static const int cpuIdleKey = getEventKey();
 
-static bool sendTracepointFormat(const uint64_t currTime, Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
-       if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
-               logg->logMessage("DynBuf::printf failed");
-               return false;
-       }
-       if (!b->read(printb->getBuf())) {
-               logg->logMessage("DynBuf::read failed");
-               return false;
-       }
-       buffer->marshalFormat(currTime, b->getLength(), b->getBuf());
-
-       return true;
-}
-
 static void *syncFunc(void *arg)
 {
        struct timespec ts;
@@ -160,17 +146,14 @@ bool PerfSource::prepare() {
                        || !mUEvent.init()
                        || !mMonitor.add(mUEvent.getFd())
 
-                       || !sendTracepointFormat(currTime, mBuffer, SCHED_SWITCH, &printb, &b1)
-
                        || (cpuIdleId = PerfDriver::getTracepointId(CPU_IDLE, &printb)) < 0
-                       || !sendTracepointFormat(currTime, mBuffer, CPU_IDLE, &printb, &b1)
 
-                       || !sendTracepointFormat(currTime, mBuffer, CPU_FREQUENCY, &printb, &b1)
+                       || !gSessionData->mPerf.sendTracepointFormats(currTime, mBuffer, &printb, &b1)
 
                        || !mCountersGroup.createCpuGroup(currTime, mBuffer)
                        || !mCountersGroup.add(currTime, mBuffer, cpuIdleKey, PERF_TYPE_TRACEPOINT, cpuIdleId, 1, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU)
 
-                       || !gSessionData->perf.enable(currTime, &mCountersGroup, mBuffer)
+                       || !gSessionData->mPerf.enable(currTime, &mCountersGroup, mBuffer)
                        || 0) {
                logg->logMessage("perf setup failed, are you running Linux 3.4 or later?");
                return false;
@@ -194,7 +177,7 @@ bool PerfSource::prepare() {
        }
 
        // Send the summary right before the start so that the monotonic delta is close to the start time
-       if (!gSessionData->perf.summary(&mSummary)) {
+       if (!gSessionData->mPerf.summary(&mSummary)) {
                logg->logError("PerfDriver::summary failed");
                handleException();
        }
@@ -283,7 +266,7 @@ void PerfSource::run() {
 
                mBuffer->perfCounterHeader(currTime);
                for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
-                       gSessionData->perf.read(mBuffer, cpu);
+                       gSessionData->mPerf.read(mBuffer, cpu);
                }
                mBuffer->perfCounterFooter(currTime);
 
@@ -396,7 +379,7 @@ bool PerfSource::handleUEvent(const uint64_t currTime) {
                        } else if (err == PG_SUCCESS) {
                                if (mCountersGroup.onlineCPU(currTime, cpu, true, mBuffer) > 0) {
                                        mBuffer->perfCounterHeader(currTime);
-                                       gSessionData->perf.read(mBuffer, cpu);
+                                       gSessionData->mPerf.read(mBuffer, cpu);
                                        mBuffer->perfCounterFooter(currTime);
                                        ret = true;
                                }
@@ -404,7 +387,7 @@ bool PerfSource::handleUEvent(const uint64_t currTime) {
                        mBuffer->commit(currTime);
 
                        gSessionData->readCpuInfo();
-                       gSessionData->perf.coreName(currTime, &mSummary, cpu);
+                       gSessionData->mPerf.coreName(currTime, &mSummary, cpu);
                        mSummary.commit(currTime);
                        return ret;
                } else if (strcmp(result.mAction, "offline") == 0) {
index 4ba59b6..ffe1a78 100644 (file)
@@ -72,12 +72,7 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti
        const int err = b->readlink(printb->getBuf());
        const char *image;
        if (err == 0) {
-               image = strrchr(b->getBuf(), '/');
-               if (image == NULL) {
-                       image = b->getBuf();
-               } else {
-                       ++image;
-               }
+               image = b->getBuf();
        } else if (err == -ENOENT) {
                // readlink /proc/[pid]/exe returns ENOENT for kernel threads
                image = "\0";
@@ -88,7 +83,7 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti
 
        // Android apps are run by app_process but the cmdline is changed to reference the actual app name
        // On 64-bit android app_process can be app_process32 or app_process64
-       if (strncmp(image, APP_PROCESS, sizeof(APP_PROCESS) - 1) != 0) {
+       if (strstr(image, APP_PROCESS) == NULL) {
                return image;
        }
 
index d7ad757..71ddfce 100644 (file)
@@ -44,7 +44,15 @@ Sender::Sender(OlySocket* socket) {
                logg->logMessage("Completed magic sequence");
        }
 
-       pthread_mutex_init(&mSendMutex, NULL);
+       pthread_mutexattr_t attr;
+       if (pthread_mutexattr_init(&attr) != 0 ||
+                       pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0 ||
+                       pthread_mutex_init(&mSendMutex, &attr) != 0 ||
+                       pthread_mutexattr_destroy(&attr) != 0 ||
+                       false) {
+               logg->logError("Unable to setup mutex");
+               handleException();
+       }
 }
 
 Sender::~Sender() {
@@ -78,7 +86,10 @@ void Sender::writeData(const char* data, int length, int type) {
        }
 
        // Multiple threads call writeData()
-       pthread_mutex_lock(&mSendMutex);
+       if (pthread_mutex_lock(&mSendMutex) != 0) {
+               logg->logError("pthread_mutex_lock failed");
+               handleException();
+       }
 
        // Send data over the socket connection
        if (mDataSocket) {
@@ -100,7 +111,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((const char*)data + pos, min(length - pos, chunkSize));
+                       mDataSocket->send(data + pos, min(length - pos, chunkSize));
                        pos += chunkSize;
                        if (pos >= length) {
                                break;
@@ -125,5 +136,8 @@ void Sender::writeData(const char* data, int length, int type) {
                }
        }
 
-       pthread_mutex_unlock(&mSendMutex);
+       if (pthread_mutex_unlock(&mSendMutex) != 0) {
+               logg->logError("pthread_mutex_unlock failed");
+               handleException();
+       }
 }
index 2b661bd..42917c0 100644 (file)
 
 SessionData* gSessionData = NULL;
 
+SharedData::SharedData() : mMaliUtgardCountersSize(0) {
+       memset(mCpuIds, -1, sizeof(mCpuIds));
+}
+
 SessionData::SessionData() {
-       usDrivers[0] = new HwmonDriver();
-       usDrivers[1] = new FSDriver();
-       usDrivers[2] = new MemInfoDriver();
-       usDrivers[3] = new NetDriver();
-       usDrivers[4] = new DiskIODriver();
+       mUsDrivers[0] = new HwmonDriver();
+       mUsDrivers[1] = new FSDriver();
+       mUsDrivers[2] = new MemInfoDriver();
+       mUsDrivers[3] = new NetDriver();
+       mUsDrivers[4] = new DiskIODriver();
        initialize();
 }
 
 SessionData::~SessionData() {
 }
 
+// Needed to use placement new
+inline void *operator new(size_t, void *ptr) { return ptr; }
+
 void SessionData::initialize() {
+       mSharedData = (SharedData *)mmap(NULL, sizeof(*mSharedData), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+       if (mSharedData == MAP_FAILED) {
+               logg->logError("Unable to mmap shared memory for cpuids");
+               handleException();
+       }
+       // Use placement new to construct but not allocate the object
+       new ((char *)mSharedData) SharedData();
+
        mWaitingOnCommand = false;
        mSessionIsActive = false;
        mLocalCapture = false;
        mOneShot = false;
        mSentSummary = false;
        mAllowCommands = false;
-       const size_t cpuIdSize = sizeof(int)*NR_CPUS;
-       // Share mCpuIds across all instances of gatord
-       mCpuIds = (int *)mmap(NULL, cpuIdSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
-       if (mCpuIds == MAP_FAILED) {
-               logg->logError("Unable to mmap shared memory for cpuids");
-               handleException();
-       }
-       memset(mCpuIds, -1, cpuIdSize);
        strcpy(mCoreName, CORE_NAME_UNKNOWN);
        readModel();
        readCpuInfo();
@@ -83,11 +90,11 @@ void SessionData::parseSessionXML(char* xmlString) {
 
        // Set session data values - use prime numbers just below the desired value to reduce the chance of events firing at the same time
        if (strcmp(session.parameters.sample_rate, "high") == 0) {
-               mSampleRate = 9973; // 10000
+               mSampleRate = 10007; // 10000
        } else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
-               mSampleRate = 997; // 1000
+               mSampleRate = 1009; // 1000
        } else if (strcmp(session.parameters.sample_rate, "low") == 0) {
-               mSampleRate = 97; // 100
+               mSampleRate = 101; // 100
        } else if (strcmp(session.parameters.sample_rate, "none") == 0) {
                mSampleRate = 0;
        } else {
@@ -126,7 +133,7 @@ void SessionData::parseSessionXML(char* xmlString) {
 }
 
 void SessionData::readModel() {
-       FILE *fh = fopen("/proc/device-tree/model", "rb");
+       FILE *fh = fopen_cloexec("/proc/device-tree/model", "rb");
        if (fh == NULL) {
                return;
        }
@@ -157,7 +164,7 @@ void SessionData::readCpuInfo() {
        char temp[256]; // arbitrarily large amount
        mMaxCpuId = -1;
 
-       FILE *f = fopen("/proc/cpuinfo", "r");
+       FILE *f = fopen_cloexec("/proc/cpuinfo", "r");
        if (f == NULL) {
                logg->logMessage("Error opening /proc/cpuinfo\n"
                        "The core name in the captured xml file will be 'unknown'.");
@@ -169,17 +176,19 @@ void SessionData::readCpuInfo() {
        while (fgets(temp, sizeof(temp), f)) {
                const size_t len = strlen(temp);
 
+               if (len > 0) {
+                       // Replace the line feed with a null
+                       temp[len - 1] = '\0';
+               }
+
+               logg->logMessage("cpuinfo: %s", temp);
+
                if (len == 1) {
                        // New section, clear the processor. Streamline will not know the cpus if the pre Linux 3.8 format of cpuinfo is encountered but also that no incorrect information will be transmitted.
                        processor = -1;
                        continue;
                }
 
-               if (len > 0) {
-                       // Replace the line feed with a null
-                       temp[len - 1] = '\0';
-               }
-
                const bool foundHardware = !foundCoreName && strstr(temp, "Hardware") != 0;
                const bool foundCPUImplementer = strstr(temp, "CPU implementer") != 0;
                const bool foundCPUPart = strstr(temp, "CPU part") != 0;
@@ -204,7 +213,7 @@ void SessionData::readCpuInfo() {
                                if (processor >= NR_CPUS) {
                                        logg->logMessage("Too many processors, please increase NR_CPUS");
                                } else if (processor >= 0) {
-                                       setImplementer(mCpuIds[processor], implementer);
+                                       setImplementer(mSharedData->mCpuIds[processor], implementer);
                                } else {
                                        setImplementer(mMaxCpuId, implementer);
                                }
@@ -215,7 +224,7 @@ void SessionData::readCpuInfo() {
                                if (processor >= NR_CPUS) {
                                        logg->logMessage("Too many processors, please increase NR_CPUS");
                                } else if (processor >= 0) {
-                                       setPart(mCpuIds[processor], cpuId);
+                                       setPart(mSharedData->mCpuIds[processor], cpuId);
                                } else {
                                        setPart(mMaxCpuId, cpuId);
                                }
@@ -229,8 +238,8 @@ void SessionData::readCpuInfo() {
 
        // 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
        for (int i = 0; i < NR_CPUS; ++i) {
-               if (mCpuIds[i] > mMaxCpuId) {
-                       mMaxCpuId = mCpuIds[i];
+               if (mSharedData->mCpuIds[i] > mMaxCpuId) {
+                       mMaxCpuId = mSharedData->mCpuIds[i];
                }
        }
 
@@ -290,3 +299,48 @@ FILE *fopen_cloexec(const char *path, const char *mode) {
        }
        return fh;
 }
+
+bool setNonblock(const int fd) {
+       int flags;
+
+       flags = fcntl(fd, F_GETFL);
+       if (flags < 0) {
+               logg->logMessage("fcntl getfl failed");
+               return false;
+       }
+
+       if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
+               logg->logMessage("fcntl setfl failed");
+               return false;
+       }
+
+       return true;
+}
+
+bool writeAll(const int fd, const void *const buf, const size_t pos) {
+       size_t written = 0;
+       while (written < pos) {
+               ssize_t bytes = write(fd, (const uint8_t *)buf + written, pos - written);
+               if (bytes <= 0) {
+                       logg->logMessage("write failed");
+                       return false;
+               }
+               written += bytes;
+       }
+
+       return true;
+}
+
+bool readAll(const int fd, void *const buf, const size_t count) {
+       size_t pos = 0;
+       while (pos < count) {
+               ssize_t bytes = read(fd, (uint8_t *)buf + pos, count - pos);
+               if (bytes <= 0) {
+                       logg->logMessage("read failed");
+                       return false;
+               }
+               pos += bytes;
+       }
+
+       return true;
+}
index d0c8900..12432d0 100644 (file)
 
 #include <stdint.h>
 
+#include "AtraceDriver.h"
+#include "CCNDriver.h"
 #include "Config.h"
 #include "Counter.h"
+#include "ExternalDriver.h"
 #include "FtraceDriver.h"
 #include "KMod.h"
 #include "MaliVideoDriver.h"
 #include "PerfDriver.h"
 
-#define PROTOCOL_VERSION 21
+#define PROTOCOL_VERSION 22
 // Differentiates development versions (timestamp) from release versions
 #define PROTOCOL_DEV 1000
 
@@ -31,22 +34,41 @@ struct ImageLinkList {
        struct ImageLinkList *next;
 };
 
+class SharedData {
+public:
+       SharedData();
+
+       int mCpuIds[NR_CPUS];
+       size_t mMaliUtgardCountersSize;
+       char mMaliUtgardCounters[1<<12];
+
+private:
+       // Intentionally unimplemented
+       SharedData(const SharedData &);
+       SharedData &operator=(const SharedData &);
+};
+
 class SessionData {
 public:
        static const size_t MAX_STRING_LEN = 80;
 
        SessionData();
        ~SessionData();
-       void initialize();
        void parseSessionXML(char* xmlString);
        void readModel();
        void readCpuInfo();
 
-       PolledDriver *usDrivers[5];
-       KMod kmod;
-       PerfDriver perf;
-       MaliVideoDriver maliVideo;
-       FtraceDriver ftraceDriver;
+       SharedData *mSharedData;
+
+       PolledDriver *mUsDrivers[5];
+       KMod mKmod;
+       PerfDriver mPerf;
+       MaliVideoDriver mMaliVideo;
+       // Intentionally above FtraceDriver as drivers are initialized in reverse order AtraceDriver references AtraceDriver
+       AtraceDriver mAtraceDriver;
+       FtraceDriver mFtraceDriver;
+       ExternalDriver mExternalDriver;
+       CCNDriver mCcnDriver;
 
        char mCoreName[MAX_STRING_LEN];
        struct ImageLinkList *mImages;
@@ -78,15 +100,16 @@ public:
        int mDuration;
        int mCores;
        int mPageSize;
-       int *mCpuIds;
        int mMaxCpuId;
        int mAnnotateStart;
 
        // PMU Counters
-       int mCounterOverflow;
+       char *mCountersError;
        Counter mCounters[MAX_PERFORMANCE_COUNTERS];
 
 private:
+       void initialize();
+
        // Intentionally unimplemented
        SessionData(const SessionData &);
        SessionData &operator=(const SessionData &);
@@ -99,5 +122,8 @@ uint64_t getTime();
 int getEventKey();
 int pipe_cloexec(int pipefd[2]);
 FILE *fopen_cloexec(const char *path, const char *mode);
+bool setNonblock(const int fd);
+bool writeAll(const int fd, const void *const buf, const size_t pos);
+bool readAll(const int fd, void *const buf, const size_t count);
 
 #endif // SESSION_DATA_H
index 7dd83ce..524a702 100644 (file)
@@ -153,30 +153,34 @@ void update(const char *const gatorPath) {
                handleException();
        }
 
-       if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(2, 6, 32)) {
-               logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
-               handleException();
-       }
-
        if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(3, 4, 0)) {
-               logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device.");
+               logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
                handleException();
        }
 
        if (geteuid() != 0) {
-               printf(GATOR_MSG "trying sudo\n");
-               execlp("sudo", "sudo", gatorPath, "-u", NULL);
-               // Streamline will provide the password if needed
-
-               printf(GATOR_MSG "trying su\n");
                char buf[1<<10];
+               snprintf(buf, sizeof(buf),
+                        "which sudo &&"
+                        "("
+                          "sudo -n %1$s -u ||"
+                          "("
+                            "echo " GATOR_MSG "trying sudo;"
+                            // Streamline will provide the password
+                            "sudo %1$s -u"
+                          ")"
+                        ") || ("
+                          "echo " GATOR_MSG "trying su;"
                /*
                 * Different versions of su handle additional -c command line options differently and expect the
                 * arguments in different ways. Try both ways wrapped in a shell.
                 *
                 * Then invoke another shell after su as it avoids odd failures on some Android systems
                 */
-               snprintf(buf, sizeof(buf), "su -c \"sh -c '%s -u'\" || su -c sh -c '%s -u'", gatorPath, gatorPath);
+                          "su -c \"sh -c '%1$s -u'\" ||"
+                          "su -c sh -c '%1$s -u'"
+                        ")",
+                        gatorPath);
                execlp("sh", "sh", "-c", buf, NULL);
                // Streamline will provide the password if needed
 
@@ -228,6 +232,11 @@ void update(const char *const gatorPath) {
        umount("/dev/gator");
        syscall(__NR_delete_module, "gator", O_NONBLOCK);
 
+       if (access("/sys/module/gator", F_OK) == 0) {
+               logg->logError(GATOR_ERROR "Unable to unload gator.ko, the gator module may be built into the kernel or gator.ko cannot be unloaded. Rebooting the device may resolve the issue.");
+               handleException();
+       }
+
        rename("gatord", "gatord.old");
        rename("gator.ko", "gator.ko.old");
 
@@ -314,8 +323,7 @@ void update(const char *const gatorPath) {
        close(pipefd[1]);
        const ssize_t bytes = read(pipefd[0], buf, sizeof(buf));
        if (bytes > 0) {
-               logg->logError("%s", buf);
-               handleException();
+               printf("%s\n", buf);
        }
        close(pipefd[0]);
 
index e37f271..66d1f4e 100644 (file)
@@ -75,8 +75,8 @@ StreamlineSetup::StreamlineSetup(OlySocket* s) {
                free(data);
        }
 
-       if (gSessionData->mCounterOverflow > 0) {
-               logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
+       if (gSessionData->mCountersError != NULL) {
+               logg->logError("%s", gSessionData->mCountersError);
                handleException();
        }
 }
@@ -197,7 +197,7 @@ void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
        header[0] = type;
        Buffer::writeLEInt(header + 1, length);
        mSocket->send((char*)&header, sizeof(header));
-       mSocket->send((const char*)data, length);
+       mSocket->send(data, length);
 }
 
 void StreamlineSetup::sendEvents() {
@@ -265,8 +265,8 @@ void StreamlineSetup::writeConfiguration(char* xml) {
        // Re-populate gSessionData with the configuration, as it has now changed
        { ConfigurationXML configuration; }
 
-       if (gSessionData->mCounterOverflow > 0) {
-               logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
+       if (gSessionData->mCountersError != NULL) {
+               logg->logError("%s", gSessionData->mCountersError);
                handleException();
        }
 }
index f58f828..1036312 100644 (file)
@@ -34,15 +34,15 @@ bool UserSpaceSource::prepare() {
 void UserSpaceSource::run() {
        prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
 
-       for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
-               gSessionData->usDrivers[i]->start();
+       for (int i = 0; i < ARRAY_LENGTH(gSessionData->mUsDrivers); ++i) {
+               gSessionData->mUsDrivers[i]->start();
        }
 
        int64_t monotonicStarted = 0;
        while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
                usleep(10);
 
-               if (gSessionData->perf.isSetup()) {
+               if (gSessionData->mPerf.isSetup()) {
                        monotonicStarted = gSessionData->mMonotonicStarted;
                } else {
                        if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
@@ -64,8 +64,8 @@ void UserSpaceSource::run() {
                }
 
                if (mBuffer.eventHeader(currTime)) {
-                       for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
-                               gSessionData->usDrivers[i]->read(&mBuffer);
+                       for (int i = 0; i < ARRAY_LENGTH(gSessionData->mUsDrivers); ++i) {
+                               gSessionData->mUsDrivers[i]->read(&mBuffer);
                        }
                        // Only check after writing all counters so that time and corresponding counters appear in the same frame
                        mBuffer.check(currTime);
index 31b127c..9adde32 100644 (file)
   <configuration counter="ARMv7_Cortex_A17_cnt1" event="0x16"/>
   <configuration counter="ARMv7_Cortex_A17_cnt2" event="0x10"/>
   <configuration counter="ARMv7_Cortex_A17_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="ARM_Cortex-A72_ccnt" event="0x11"/>
-  <configuration counter="ARM_Cortex-A72_cnt0" event="0x8"/>
-  <configuration counter="ARM_Cortex-A72_cnt1" event="0x16"/>
-  <configuration counter="ARM_Cortex-A72_cnt2" event="0x10"/>
-  <configuration counter="ARM_Cortex-A72_cnt3" event="0x19"/>
+  <configuration counter="ARMv8_Cortex_A53_ccnt" event="0x11"/>
+  <configuration counter="ARMv8_Cortex_A53_cnt0" event="0x8"/>
+  <configuration counter="ARMv8_Cortex_A53_cnt1" event="0x16"/>
+  <configuration counter="ARMv8_Cortex_A53_cnt2" event="0x10"/>
+  <configuration counter="ARMv8_Cortex_A53_cnt3" event="0x19"/>
+  <configuration counter="ARMv8_Cortex_A57_ccnt" event="0x11"/>
+  <configuration counter="ARMv8_Cortex_A57_cnt0" event="0x8"/>
+  <configuration counter="ARMv8_Cortex_A57_cnt1" event="0x16"/>
+  <configuration counter="ARMv8_Cortex_A57_cnt2" event="0x10"/>
+  <configuration counter="ARMv8_Cortex_A57_cnt3" event="0x19"/>
+  <configuration counter="ARMv8_Cortex_A72_ccnt" event="0x11"/>
+  <configuration counter="ARMv8_Cortex_A72_cnt0" event="0x8"/>
+  <configuration counter="ARMv8_Cortex_A72_cnt1" event="0x16"/>
+  <configuration counter="ARMv8_Cortex_A72_cnt2" event="0x10"/>
+  <configuration counter="ARMv8_Cortex_A72_cnt3" event="0x19"/>
   <configuration counter="Scorpion_ccnt" event="0xff"/>
   <configuration counter="Scorpion_cnt0" event="0x08"/>
   <configuration counter="Scorpion_cnt1" event="0x10"/>
index 40d91e5..0dd72c0 100644 (file)
@@ -41,9 +41,9 @@
     <event event="0x19" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
     <event event="0x1a" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase MIx_W_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
   </category>
-  <counter_set name="CCI_400-r1_cnt" count="4"/>
-  <category name="CCI-400" counter_set="CCI_400-r1_cnt" per_cpu="no">
-    <event counter="CCI_400-r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
+  <counter_set name="CCI_400_r1_cnt" count="4"/>
+  <category name="CCI-400" counter_set="CCI_400_r1_cnt" per_cpu="no">
+    <event counter="CCI_400_r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
     <option_set name="Slave">
       <option event_delta="0x00" name="S0" description="Slave interface 0"/>
       <option event_delta="0x20" name="S1" description="Slave interface 1"/>
index acdfe4e..c15cbd8 100644 (file)
@@ -1,6 +1,6 @@
-  <counter_set name="ARM_Cortex-A53_cnt" count="6"/>
-  <category name="Cortex-A53" counter_set="ARM_Cortex-A53_cnt" per_cpu="yes" supports_event_based_sampling="yes">
-    <event counter="ARM_Cortex-A53_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+  <counter_set name="ARMv8_Cortex_A53_cnt" count="6"/>
+  <category name="Cortex-A53" counter_set="ARMv8_Cortex_A53_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+    <event counter="ARMv8_Cortex_A53_ccnt" event="0x11" 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. The register is 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 1da23e7..d1e97c3 100644 (file)
@@ -1,6 +1,6 @@
-  <counter_set name="ARM_Cortex-A57_cnt" count="6"/>
-  <category name="Cortex-A57" counter_set="ARM_Cortex-A57_cnt" per_cpu="yes" supports_event_based_sampling="yes">
-    <event counter="ARM_Cortex-A57_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+  <counter_set name="ARMv8_Cortex_A57_cnt" count="6"/>
+  <category name="Cortex-A57" counter_set="ARMv8_Cortex_A57_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+    <event counter="ARMv8_Cortex_A57_ccnt" event="0x11" 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 31c9cf3..683d0ae 100644 (file)
@@ -1,6 +1,6 @@
-  <counter_set name="ARM_Cortex_A72_cnt" count="6"/>
-  <category name="Cortex-A72" counter_set="ARM_Cortex_A72_cnt" per_cpu="yes" supports_event_based_sampling="yes">
-    <event counter="ARM_Cortex_A72_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+  <counter_set name="ARMv8_Cortex_A72_cnt" count="6"/>
+  <category name="Cortex-A72" counter_set="ARMv8_Cortex_A72_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+    <event counter="ARMv8_Cortex_A72_ccnt" event="0x11" 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 801dd28..e2f4405 100644 (file)
     <event counter="ARM_Mali-4xx_SW_39" title="Geometry Statistics" name="Strip Lines" description="Number of lines passed to GLES using the mode GL_LINE_STRIP."/>
     <event counter="ARM_Mali-4xx_SW_40" title="Geometry Statistics" name="Loop Lines" description="Number of lines passed to GLES using the mode GL_LINE_LOOP."/>
   </category>
+  <category name="ARM_Mali-4xx_Total_alloc_pages" per_cpu="no">
+    <event counter="ARM_Mali-4xx_Total_alloc_pages" title="Mali GPU Alloc" name="pages" class="absolute" display="average" average_selection="yes" description="Total number of allocated pages"/>
+  </category>
+  <category name="Mali-4xx Session Memory usage" per_cpu="no">
+    <event counter="ARM_Mali-4xx_vertex_index_buffer" title="Mali Memory" name="Vertex and Index buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Vertex and index input"/>
+    <event counter="ARM_Mali-4xx_texture_buffer" title="Mali Memory" name="Texture buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Texture data"/>
+    <event counter="ARM_Mali-4xx_varying_buffer" title="Mali Memory" name="Varying buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Varying buffer"/>
+    <event counter="ARM_Mali-4xx_render_target" title="Mali Memory" name="Render target buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Render target buffer"/>
+    <event counter="ARM_Mali-4xx_plbu_heap" title="Mali Memory" name="Plbu heap" units="B" dclass="absolute" display="average" average_selection="yes" description="The memory to store commands from PLBU when Slave tilelist memory isn't enough"/>
+    <event counter="ARM_Mali-4xx_slave_tilelist" title="Mali Memory" name="Slave tilelist" units="B" dclass="absolute" display="average" average_selection="yes" description="Slave tilelist memory"/>
+  </category>
index e8f0cb0..802db8b 100644 (file)
@@ -44,8 +44,8 @@
 
     <event counter="ARM_Mali-Midgard_FRAG_THREADS" title="Mali Core Threads" name="Fragment threads" description="Number of fragment threads started"/>
     <event counter="ARM_Mali-Midgard_FRAG_DUMMY_THREADS" title="Mali Core Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
-    <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS quads" description="Number of threads doing late ZS test"/>
-    <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS quads" description="Number of threads killed by late ZS test"/>
+    <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
+    <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
     <event counter="ARM_Mali-Midgard_FRAG_THREADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
     <event counter="ARM_Mali-Midgard_FRAG_THREADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
 
index 89bc7f4..bc2d6aa 100644 (file)
@@ -25,6 +25,6 @@
     <event counter="ARM_Mali-V500_evn2" title="MVE-V500 Frames" name="Frame Processed" description="Generated when the MVE has finished processing a frame"/>
     <event counter="ARM_Mali-V500_evn3" title="MVE-V500 Output" name="Output buffer received" description="Generated when an an output buffer is returned to us from the MVE"/>
     <event counter="ARM_Mali-V500_evn4" title="MVE-V500 Input" name="Input buffer received" description="Generated when we an input buffer is returned to us from the MVE"/>
-    <event counter="ARM_Mali-V500_act0" title="MVE-V500 Parsed" name="Activity" class="activity" activity1="activity" activity_color1="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" cores="8" description="Mali-V500 Activity"/>
-    <event counter="ARM_Mali-V500_act1" title="MVE-V500 Piped" name="Activity" class="activity" activity1="activity" activity_color1="0x0000ff00" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" cores="8" description="Mali-V500 Activity"/>
+    <event counter="ARM_Mali-V500_act0" title="MVE-V500 Parsed" name="Activity" class="activity" activity1="activity" activity_color1="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" per_cpu="yes" cores="8" description="Mali-V500 Activity"/>
+    <event counter="ARM_Mali-V500_act1" title="MVE-V500 Piped" name="Activity" class="activity" activity1="activity" activity_color1="0x0000ff00" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" per_cpu="yes" cores="8" description="Mali-V500 Activity"/>
   </category>
diff --git a/tools/gator/daemon/events-atrace.xml b/tools/gator/daemon/events-atrace.xml
new file mode 100644 (file)
index 0000000..432b6af
--- /dev/null
@@ -0,0 +1,19 @@
+  <category name="Atrace">
+    <event counter="atrace_graphics" flag="0x2" title="Atrace" name="Graphics" description="Graphics"/>
+    <event counter="atrace_input" flag="0x4" title="Atrace" name="Input" description="Input"/>
+    <event counter="atrace_view" flag="0x8" title="Atrace" name="View" description="View"/>
+    <event counter="atrace_webview" flag="0x10" title="Atrace" name="Webview" description="Webview"/>
+    <event counter="atrace_window_manager" flag="0x20" title="Atrace" name="Window manager" description="Window manager"/>
+    <event counter="atrace_activity_manager" flag="0x40" title="Atrace" name="Activity manager" description="Activity manager"/>
+    <event counter="atrace_sync_manager" flag="0x80" title="Atrace" name="Sync manager" description="Sync manager"/>
+    <event counter="atrace_audio" flag="0x100" title="Atrace" name="Audio" description="Audio"/>
+    <event counter="atrace_video" flag="0x200" title="Atrace" name="Video" description="Video"/>
+    <event counter="atrace_camera" flag="0x400" title="Atrace" name="Camera" description="Camera"/>
+    <event counter="atrace_hal" flag="0x800" title="Atrace" name="Hal" description="Hal"/>
+    <event counter="atrace_app" flag="0x1000" title="Atrace" name="App" description="App"/>
+    <event counter="atrace_resources" flag="0x2000" title="Atrace" name="Resources" description="Resources"/>
+    <event counter="atrace_dalvik" flag="0x4000" title="Atrace" name="Dalvik" description="Dalvik"/>
+    <event counter="atrace_rs" flag="0x8000" title="Atrace" name="Rs" description="Rs"/>
+    <event counter="atrace_bionic" flag="0x10000" title="Atrace" name="Bionic" description="Bionic"/>
+    <event counter="atrace_power" flag="0x20000" title="Atrace" name="Power" description="Power"/>
+  </category>
index ae5529f..17fad17 100644 (file)
@@ -1,22 +1,24 @@
   <category name="Ftrace">
     <!--
-       Ftrace counters require Linux 3.10 or later. If you do you see ftrace counters in counter configuration, please check your Linux version.
+       ftrace counters require Linux 3.10 or later; if you do not see ftrace counters in counter configuration, please check your Linux version
        'counter' attribute must start with ftrace_ and be unique
        the regex item in () is the value shown or, if the parentheses are missing, the number of regex matches is counted
        'enable' (optional) is the ftrace event to enable associated with the gator event
+       'tracepoint' (optional) same meaning as enable, but will use perf instead of ftrace when using user space gator
+       'arg' (optional) used in conjunction with 'tracepoint' to specify the value to show otherwise the number of tracepoint events is counted
     -->
     <!--
-    <event counter="ftrace_trace_marker_numbers" title="ftrace" name="trace_marker" regex="^tracing_mark_write: ([0-9]+)\s$" class="absolute" description="Numbers written to /sys/kernel/debug/tracing/trace_marker, ex: echo 42 > /sys/kernel/debug/tracing/trace_marker"/>
+    <event counter="ftrace_trace_marker_numbers" title="ftrace" name="trace_marker" regex="^tracing_mark_write: ([0-9]+)$" class="absolute" description="Numbers written to /sys/kernel/debug/tracing/trace_marker, ex: echo 42 > /sys/kernel/debug/tracing/trace_marker"/>
     -->
 
     <!-- ftrace counters -->
-    <event counter="ftrace_kmem_kmalloc" title="Kmem" name="kmalloc" regex="^kmalloc:.* bytes_alloc=([0-9]+) " enable="kmem/kmalloc" class="incident" description="Number of bytes allocated in the kernel using kmalloc"/>
-    <event counter="ftrace_ext4_ext4_da_write" title="Ext4" name="ext4_da_write" regex="^ext4_da_write_end:.* len ([0-9]+) " enable="ext4/ext4_da_write_end" class="incident" description="Number of bytes written to an ext4 filesystem"/>
-    <event counter="ftrace_f2fs_f2fs_write" title="F2FS" name="f2fs_write" regex="^f2fs_write_end:.* len ([0-9]+), " enable="f2fs/f2fs_write_end" class="incident" description="Number of bytes written to an f2fs filesystem"/>
-    <event counter="ftrace_power_clock_set_rate" title="Power" name="clock_set_rate" regex="^clock_set_rate:.* state=([0-9]+) " enable="power/clock_set_rate" class="absolute" description="Clock rate state"/>
+    <event counter="ftrace_kmem_kmalloc" title="Kmem" name="kmalloc" regex="^kmalloc:.* bytes_alloc=([0-9]+) " tracepoint="kmem/kmalloc" arg="bytes_alloc" class="incident" description="Number of bytes allocated in the kernel using kmalloc"/>
+    <event counter="ftrace_ext4_ext4_da_write" title="Ext4" name="ext4_da_write" regex="^ext4_da_write_end:.* len ([0-9]+) " tracepoint="ext4/ext4_da_write_end" arg="len" class="incident" description="Number of bytes written to an ext4 filesystem"/>
+    <event counter="ftrace_f2fs_f2fs_write" title="F2FS" name="f2fs_write" regex="^f2fs_write_end:.* len ([0-9]+), " tracepoint="f2fs/f2fs_write_end" arg="len" class="incident" description="Number of bytes written to an f2fs filesystem"/>
+    <event counter="ftrace_power_clock_set_rate" title="Power" name="clock_set_rate" regex="^clock_set_rate:.* state=([0-9]+) " tracepoint="power/clock_set_rate" arg="state" class="absolute" description="Clock rate state"/>
 
     <!-- counting ftrace counters -->
-    <event counter="ftrace_block_block_rq_complete" title="Block" name="block_rq_complete" regex="^block_rq_complete: " enable="block/block_rq_complete" class="delta" description="Number of block IO operations completed by device driver"/>
-    <event counter="ftrace_block_block_rq_issue" title="Block" name="block_rq_issue" regex="^block_rq_issue: " enable="block/block_rq_issue" class="delta" description="Number of block IO operations issued to device driver"/>
-    <event counter="ftrace_power_cpu_idle" title="Power" name="cpu_idle" regex="^cpu_idle: " enable="power/cpu_idle" class="delta" description="Number of times cpu_idle is entered or exited"/>
+    <event counter="ftrace_block_block_rq_complete" title="Block" name="block_rq_complete" regex="^block_rq_complete: " tracepoint="block/block_rq_complete" class="delta" description="Number of block IO operations completed by device driver"/>
+    <event counter="ftrace_block_block_rq_issue" title="Block" name="block_rq_issue" regex="^block_rq_issue: " tracepoint="block/block_rq_issue" class="delta" description="Number of block IO operations issued to device driver"/>
+    <event counter="ftrace_power_cpu_idle" title="Power" name="cpu_idle" regex="^cpu_idle: " tracepoint="power/cpu_idle" class="delta" description="Number of times cpu_idle is entered or exited"/>
   </category>
diff --git a/tools/gator/daemon/k/perf_event.3.12.h b/tools/gator/daemon/k/perf_event.3.12.h
deleted file mode 100644 (file)
index e886c48..0000000
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * 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 */
deleted file mode 120000 (symlink)
index e5dff8c21ef47d0fcecb9856418e0143c556bb8c..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-perf_event.3.12.h
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..e886c48cadf62e45bedb9887cd3218abc9f4647e
--- /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 */
index c68a892..95e179e 100644 (file)
@@ -20,8 +20,8 @@
 #include <unistd.h>
 
 #include "AnnotateListener.h"
-#include "CCNDriver.h"
 #include "Child.h"
+#include "DriverSource.h"
 #include "EventsXML.h"
 #include "Logging.h"
 #include "Monitor.h"
@@ -297,15 +297,10 @@ static bool setupFilesystem(char* module) {
                }
 
                // Load driver
-               bool success = init_module(location);
-               if (!success) {
-                       logg->logMessage("init_module failed, trying insmod");
-                       snprintf(command, sizeof(command), "insmod %s >/dev/null 2>&1", location);
-                       if (system(command) != 0) {
-                               logg->logMessage("Unable to load gator.ko driver with command: %s", command);
-                               logg->logError("Unable to load (insmod) gator.ko driver:\n  >>> gator.ko must be built against the current kernel version & configuration\n  >>> See dmesg for more details");
-                               handleException();
-                       }
+               if (!init_module(location)) {
+                       logg->logMessage("Unable to load gator.ko driver with command: %s", command);
+                       logg->logError("Unable to load (insmod) gator.ko driver:\n  >>> gator.ko must be built against the current kernel version & configuration\n  >>> See dmesg for more details");
+                       handleException();
                }
 
                if (mountGatorFS() == -1) {
@@ -323,10 +318,7 @@ static int shutdownFilesystem() {
        }
        if (driverRunningAtStart == false) {
                if (syscall(__NR_delete_module, "gator", O_NONBLOCK) != 0) {
-                       logg->logMessage("delete_module failed, trying rmmod");
-                       if (system("rmmod gator >/dev/null 2>&1") != 0) {
-                               return -1;
-                       }
+                       return -1;
                }
        }
 
@@ -496,16 +488,13 @@ int main(int argc, char** argv) {
        //   e.g. it may not be the group leader when launched as 'sudo gatord'
        setsid();
 
-  // Set up global thread-safe logging
+       // Set up global thread-safe logging
        logg = new Logging(hasDebugFlag(argc, argv));
        // Global data class
        gSessionData = new SessionData();
        // Set up global utility class
        util = new OlyUtility();
 
-       // Initialize drivers
-       new CCNDriver();
-
        prctl(PR_SET_NAME, (unsigned long)&"gatord-main", 0, 0, 0);
        pthread_mutex_init(&numSessions_mutex, NULL);
 
@@ -535,9 +524,11 @@ int main(int argc, char** argv) {
        }
 
        // Call before setting up the SIGCHLD handler, as system() spawns child processes
-       if (!setupFilesystem(cmdline.module)) {
+       if (setupFilesystem(cmdline.module)) {
+               DriverSource::checkVersion();
+       } else {
                logg->logMessage("Unable to set up gatorfs, trying perf");
-               if (!gSessionData->perf.setup()) {
+               if (!gSessionData->mPerf.setup()) {
                        logg->logError(
                                       "Unable to locate gator.ko driver:\n"
                                       "  >>> gator.ko should be co-located with gatord in the same directory\n"
diff --git a/tools/gator/daemon/notify/COPYING b/tools/gator/daemon/notify/COPYING
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/tools/gator/daemon/notify/Makefile b/tools/gator/daemon/notify/Makefile
new file mode 100644 (file)
index 0000000..0d8f041
--- /dev/null
@@ -0,0 +1,24 @@
+ifneq ($(SDKDIR),)
+
+# Find the oldest SDK Platform installed >= 16
+SDK_PLATFORM := $(shell ls -d $(SDKDIR)/platforms/android-1[6-9] $(SDKDIR)/platforms/android-[2-9][0-9] | head -1)
+# Find the newest SDK Build-tools
+SDK_BUILD_TOOLS := $(shell ls -d $(SDKDIR)/build-tools/* | tail -1)
+
+all: notify.dex
+
+notify.dex: Notify.java
+       javac -cp $(SDK_PLATFORM)/data/layoutlib.jar -source 1.6 -target 1.6 $^
+       $(SDK_BUILD_TOOLS)/dx --dex --output=$@ $(^:%.java=%.class)
+
+else
+
+all:
+       $(error Please specify SDKDIR as the location to the Android SDK)
+
+endif
+
+.PHONY: clean
+
+clean:
+       rm -f *~ *.class *.dex
diff --git a/tools/gator/daemon/notify/Notify.java b/tools/gator/daemon/notify/Notify.java
new file mode 100644 (file)
index 0000000..9702451
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) ARM Limited 2015. 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.
+ */
+
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+public class Notify {
+       public static void main(String[] args) throws RemoteException {
+               for (String service : ServiceManager.listServices()) {
+                       IBinder b = ServiceManager.checkService(service);
+                       if (b != null) {
+                               Parcel p = null;
+                               try {
+                                       p = Parcel.obtain();
+                                       b.transact(IBinder.SYSPROPS_TRANSACTION, p, null, 0);
+                               } finally {
+                                       if (p != null) {
+                                               p.recycle();
+                                       }
+                               }
+                       }
+               }
+       }
+}