diff options
author | Pawel Moll <pawel.moll@arm.com> | 2011-03-14 15:22:44 +0000 |
---|---|---|
committer | Pawel Moll <pawel.moll@arm.com> | 2011-03-14 15:22:44 +0000 |
commit | 438a1e1cbf4b99b4f6ff1ecf07f9b7cfcc20d517 (patch) | |
tree | 844b0b30da7b0653eb5a0d0408b45c86f1e494ea | |
parent | 4b1652908140265b28795a529b73ebb41d690c15 (diff) |
gator: ARM DS-5.4 Streamline gator driverDS-5.4
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | README_Streamline.txt | 36 | ||||
-rw-r--r-- | gator.h | 34 | ||||
-rw-r--r-- | gator_annotate.c | 2 | ||||
-rw-r--r-- | gator_backtrace.c | 2 | ||||
-rw-r--r-- | gator_cookies.c | 16 | ||||
-rw-r--r-- | gator_events.c | 5 | ||||
-rw-r--r-- | gator_events_armv6.c | 41 | ||||
-rw-r--r-- | gator_events_armv7.c | 32 | ||||
-rw-r--r-- | gator_events_block.c | 12 | ||||
-rw-r--r-- | gator_events_irq.c | 20 | ||||
-rw-r--r-- | gator_events_meminfo.c | 10 | ||||
-rw-r--r-- | gator_events_net.c | 176 | ||||
-rw-r--r-- | gator_events_sched.c | 11 | ||||
-rw-r--r-- | gator_main.c | 377 | ||||
-rw-r--r-- | gator_trace_sched.c | 14 |
16 files changed, 489 insertions, 302 deletions
@@ -7,6 +7,7 @@ gator-objs := gator_main.o \ gator_events_armv7.o \ gator_events_irq.o \ gator_events_sched.o \ + gator_events_net.o \ gator_events_block.o \ gator_events_meminfo.o @@ -20,6 +21,6 @@ all: $(error) clean: - rm -f *.o .*.cmd */*.o */.*.cmd modules.order Module.symvers gator.ko gator.mod.c + rm -f *.o modules.order Module.symvers gator.ko gator.mod.c endif diff --git a/README_Streamline.txt b/README_Streamline.txt index 4c52b7d..4688474 100644 --- a/README_Streamline.txt +++ b/README_Streamline.txt @@ -76,42 +76,6 @@ vi rungator.sh /path/to/gatord & update-rc.d rungator.sh defaults -*** Driver Sources *** - -Gator Sources - backtrace.c - cpu_buffer.c - cpu_fifo.c - cpu_fifo.h - gator_annotate.c - gator_events_irq.c - gator_init.c - gator_interrupt.c - gator_pmnc_armv7.c - gator_pmnc_none.c - gator_schedtrace.c - gator_setup.c - gator_timer.c - gator_traceprobe.h - -Oprofile Sources // function names updated to avoid Oprofile collisions - buffer_sync.c - buffer_sync.h - cpu_buffer.h - event_buffer.c - event_buffer.h - oprof.h - oprofile.h - oprofile_files.c - oprofile_stats.c - oprofile_stats.h - timer_int.c - -Modified Oprofile Sources - buffer_sync.c // modify sample contract to allow bad 'mm' or cookie - oprofilefs.c // gatorfs and magic number - oprof.c // updated module name and author - *** GPL License *** For license information, please see the file LICENSE. @@ -6,6 +6,13 @@ * published by the Free Software Foundation. */ +#ifndef GATOR_H_ +#define GATOR_H_ + +#include <linux/version.h> +#include <linux/fs.h> +#include <linux/mm.h> + /****************************************************************************** * Filesystem ******************************************************************************/ @@ -22,6 +29,27 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root, char const *name, unsigned long *val); /****************************************************************************** + * Tracepoints + ******************************************************************************/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) +# error Kernels prior to 2.6.32 not supported +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) +# define GATOR_DEFINE_PROBE(probe_name, proto) \ + static void probe_##probe_name(PARAMS(proto)) +# define GATOR_REGISTER_TRACE(probe_name) \ + register_trace_##probe_name(probe_##probe_name) +# define GATOR_UNREGISTER_TRACE(probe_name) \ + unregister_trace_##probe_name(probe_##probe_name) +#else +# define GATOR_DEFINE_PROBE(probe_name, proto) \ + static void probe_##probe_name(void *data, PARAMS(proto)) +# define GATOR_REGISTER_TRACE(probe_name) \ + register_trace_##probe_name(probe_##probe_name, NULL) +# define GATOR_UNREGISTER_TRACE(probe_name) \ + unregister_trace_##probe_name(probe_##probe_name, NULL) +#endif + +/****************************************************************************** * Events ******************************************************************************/ struct __gator_interface { @@ -29,6 +57,8 @@ struct __gator_interface { int (*init)(int *key); int (*start)(void); void (*stop)(void); + void (*online)(void); + void (*offline)(void); int (*read)(int **buffer); struct __gator_interface *next; }; @@ -36,3 +66,7 @@ struct __gator_interface { typedef struct __gator_interface gator_interface; int gator_event_install(int (*event_install)(gator_interface *)); + +extern unsigned long gator_net_traffic; + +#endif // GATOR_H_ diff --git a/gator_annotate.c b/gator_annotate.c index 1844157..56656f0 100644 --- a/gator_annotate.c +++ b/gator_annotate.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/gator_backtrace.c b/gator_backtrace.c index c4ddf41..628a18f 100644 --- a/gator_backtrace.c +++ b/gator_backtrace.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/gator_cookies.c b/gator_cookies.c index d267a57..4e39667 100644 --- a/gator_cookies.c +++ b/gator_cookies.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,8 +11,6 @@ #define MAX_COLLISIONS 2 static DEFINE_PER_CPU(uint32_t, cookie_next_key); -static DEFINE_PER_CPU(uint32_t, cookie_prev_text); -static DEFINE_PER_CPU(uint32_t, cookie_prev_value); static DEFINE_PER_CPU(uint64_t *, cookie_keys); static DEFINE_PER_CPU(uint32_t *, cookie_values); @@ -105,10 +103,6 @@ static inline uint32_t get_cookie(int cpu, int tgid, struct vm_area_struct *vma) } text = (char*)path->dentry->d_name.name; - if (per_cpu (cookie_prev_text, cpu) == (uint32_t)text) { - return per_cpu(cookie_prev_value, cpu); - } - key = gator_chksum_crc32(text); key = (key << 32) | (uint32_t)text; @@ -125,8 +119,6 @@ static inline uint32_t get_cookie(int cpu, int tgid, struct vm_area_struct *vma) gator_buffer_write_string(cpu, text); output: - per_cpu(cookie_prev_text, cpu) = (uint32_t)text; - per_cpu(cookie_prev_value, cpu) = cookie; return cookie; } @@ -187,10 +179,8 @@ static void cookies_initialize(void) int cpu, size; int i, j; - for_each_possible_cpu(cpu) { + for_each_present_cpu(cpu) { per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu; - per_cpu(cookie_prev_text, cpu) = 0; - per_cpu(cookie_prev_value, cpu) = 0; size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t); per_cpu(cookie_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL); @@ -221,7 +211,7 @@ static void cookies_release(void) { int cpu; - for_each_possible_cpu(cpu) { + for_each_present_cpu(cpu) { kfree(per_cpu(cookie_keys, cpu)); per_cpu(cookie_keys, cpu) = NULL; diff --git a/gator_events.c b/gator_events.c index 1a5d0a0..d837257 100644 --- a/gator_events.c +++ b/gator_events.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. 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 @@ -18,6 +18,7 @@ extern int gator_events_irq_install(gator_interface *gi); extern int gator_events_sched_install(gator_interface *gi); extern int gator_events_block_install(gator_interface *gi); extern int gator_events_meminfo_install(gator_interface *gi); +extern int gator_events_net_install(gator_interface *gi); static int gator_events_install(void) { @@ -33,5 +34,7 @@ static int gator_events_install(void) return -1; if (gator_event_install(gator_events_meminfo_install)) return -1; + if (gator_event_install(gator_events_net_install)) + return -1; return 0; } diff --git a/gator_events_armv6.c b/gator_events_armv6.c index a916d83..c571e44 100644 --- a/gator_events_armv6.c +++ b/gator_events_armv6.c @@ -1,17 +1,11 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. 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 <linux/types.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/fs.h> - #include "gator.h" #if defined(__arm__) @@ -119,15 +113,13 @@ static int gator_events_armv6_init(int *key) return 0; } -static void __gator_events_armv6_start(void* unused) +static void gator_events_armv6_online(void) { unsigned int cnt; u32 pmnc; if (armv6_pmnc_read() & PMCR_E) { - pr_err("gator: CPU%u PMNC still enabled when setup new event counter.\n", smp_processor_id()); - pmnc_count = 0; - return; + armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E); } /* initialize PMNC, reset overflow, D bit, C bit and P bit. */ @@ -162,31 +154,24 @@ static void __gator_events_armv6_start(void* unused) armv6_pmnc_write(pmnc | PMCR_E); } -static int gator_events_armv6_start(void) -{ - if (!pmnc_count) - return 0; - return on_each_cpu(__gator_events_armv6_start, NULL, 1); -} - -static void __gator_events_armv6_stop(void* unused) +static void gator_events_armv6_offline(void) { unsigned int cnt; armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E); - for (cnt = PMN0; cnt <= CCNT; cnt++) { armv6_pmnc_reset_counter(cnt); - pmnc_enabled[cnt] = 0; - pmnc_event[cnt] = 0; } } static void gator_events_armv6_stop(void) { - if (!pmnc_count) - return; - on_each_cpu(__gator_events_armv6_stop, NULL, 1); + unsigned int cnt; + + for (cnt = PMN0; cnt <= CCNT; cnt++) { + pmnc_enabled[cnt] = 0; + pmnc_event[cnt] = 0; + } } static int gator_events_armv6_read(int **buffer) @@ -194,9 +179,6 @@ static int gator_events_armv6_read(int **buffer) int cnt, len = 0; int cpu = raw_smp_processor_id(); - if (!pmnc_count) - return 0; - for (cnt = PMN0; cnt <= CCNT; cnt++) { if (pmnc_enabled[cnt]) { u32 value = 0; @@ -242,8 +224,9 @@ int gator_events_armv6_install(gator_interface *gi) { gi->create_files = gator_events_armv6_create_files; gi->init = gator_events_armv6_init; - gi->start = gator_events_armv6_start; gi->stop = gator_events_armv6_stop; + gi->online = gator_events_armv6_online; + gi->offline = gator_events_armv6_offline; gi->read = gator_events_armv6_read; #endif return 0; diff --git a/gator_events_armv7.c b/gator_events_armv7.c index ca37bef..5a3268f 100644 --- a/gator_events_armv7.c +++ b/gator_events_armv7.c @@ -1,15 +1,10 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. 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 <linux/types.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/fs.h> #include "gator.h" @@ -284,14 +279,12 @@ static int gator_events_armv7_init(int *key) return 0; } -static void __gator_events_armv7_start(void* unused) +static void gator_events_armv7_online(void) { unsigned int cnt; if (armv7_pmnc_read() & PMNC_E) { - pr_err("gator: CPU%u PMNC still enabled when setup new event counter\n", raw_smp_processor_id()); - pmnc_count = 0; - return; + armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); } /* Initialize & Reset PMNC: C bit and P bit */ @@ -339,17 +332,14 @@ static void __gator_events_armv7_start(void* unused) armv7_pmnc_write(armv7_pmnc_read() | PMNC_E); } -static int gator_events_armv7_start(void) +static void gator_events_armv7_offline(void) { - if (!pmnc_count) - return 0; - return on_each_cpu(__gator_events_armv7_start, NULL, 1); + armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); } -static void __gator_events_armv7_stop(void* unused) +static void gator_events_armv7_stop(void) { unsigned int cnt; - armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); for (cnt = CCNT; cnt < CNTMAX; cnt++) { pmnc_enabled[cnt] = 0; @@ -357,13 +347,6 @@ static void __gator_events_armv7_stop(void* unused) } } -static void gator_events_armv7_stop(void) -{ - if (!pmnc_count) - return; - on_each_cpu(__gator_events_armv7_stop, NULL, 1); -} - static int gator_events_armv7_read(int **buffer) { int cnt, len = 0; @@ -419,8 +402,9 @@ int gator_events_armv7_install(gator_interface *gi) { gi->create_files = gator_events_armv7_create_files; gi->init = gator_events_armv7_init; - gi->start = gator_events_armv7_start; gi->stop = gator_events_armv7_stop; + gi->online = gator_events_armv7_online; + gi->offline = gator_events_armv7_offline; gi->read = gator_events_armv7_read; #endif return 0; diff --git a/gator_events_block.c b/gator_events_block.c index c2d1e7e..f32d8ef 100644 --- a/gator_events_block.c +++ b/gator_events_block.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -7,14 +7,8 @@ * */ -#include <linux/version.h> -#include <linux/blkdev.h> -#include <trace/events/block.h> -#include <linux/slab.h> -#include <linux/fs.h> - #include "gator.h" -#include "gator_trace.h" +#include <trace/events/block.h> #define BLOCK_RQ_WR 0 #define BLOCK_RQ_RD 1 @@ -102,7 +96,7 @@ static int gator_events_block_start(void) { int cpu; - for_each_possible_cpu(cpu) + for_each_present_cpu(cpu) per_cpu(new_data_avail, cpu) = true; // register tracepoints diff --git a/gator_events_irq.c b/gator_events_irq.c index f34cc18..7bbbd4b 100644 --- a/gator_events_irq.c +++ b/gator_events_irq.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -7,15 +7,8 @@ * */ -#include <linux/slab.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/dcookies.h> -#include <linux/version.h> -#include <trace/events/irq.h> - #include "gator.h" -#include "gator_trace.h" +#include <trace/events/irq.h> #define HARDIRQ 0 #define SOFTIRQ 1 @@ -41,8 +34,11 @@ GATOR_DEFINE_PROBE(irq_handler_exit, TP_PROTO(int irq, local_irq_restore(flags); } -GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(struct softirq_action *h, - struct softirq_action *vec)) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) +GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(struct softirq_action *h, struct softirq_action *vec)) +#else +GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr)) +#endif { unsigned long flags; @@ -93,7 +89,7 @@ static int gator_events_irq_start(void) { int cpu, i; - for_each_possible_cpu(cpu) { + for_each_present_cpu(cpu) { for (i = 0; i < TOTALIRQ; i++) per_cpu(irqPrev, cpu)[i] = 0; } diff --git a/gator_events_meminfo.c b/gator_events_meminfo.c index 52345c8..1b576f8 100644 --- a/gator_events_meminfo.c +++ b/gator_events_meminfo.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -7,16 +7,10 @@ * */ +#include "gator.h" #include <linux/workqueue.h> -#include <linux/version.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/fs.h> #include <trace/events/kmem.h> -#include "gator.h" -#include "gator_trace.h" - #define MEMINFO_MEMFREE 0 #define MEMINFO_MEMUSED 1 #define MEMINFO_BUFFERRAM 2 diff --git a/gator_events_net.c b/gator_events_net.c new file mode 100644 index 0000000..3ca5911 --- /dev/null +++ b/gator_events_net.c @@ -0,0 +1,176 @@ +/** + * Copyright (C) ARM Limited 2010-2011. 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 "gator.h" +#include <linux/netdevice.h> + +#define NETRX 0 +#define NETTX 1 +#define NETDRV 2 +#define TOTALNET (NETDRV+1) + +static ulong netdrv_enabled; +static ulong netrx_enabled; +static ulong nettx_enabled; +static ulong netdrv_key; +static ulong netrx_key; +static ulong nettx_key; +static int rx_total, tx_total; +static ulong netPrev[TOTALNET]; +static int netGet[TOTALNET * 2]; + +static void get_network_stats(struct work_struct *wsptr) { + int rx = 0, tx = 0; + struct net_device *dev; + + for_each_netdev(&init_net, dev) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + const struct net_device_stats *stats = dev_get_stats(dev); +#else + struct rtnl_link_stats64 temp; + const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); +#endif + rx += stats->rx_bytes; + tx += stats->tx_bytes; + } + rx_total = rx; + tx_total = tx; +} +DECLARE_WORK(wq_get_stats, get_network_stats); + +static void calculate_delta(int *drv, int *rx, int *tx) +{ + int drv_calc, rx_calc, tx_calc; + + drv_calc = gator_net_traffic - netPrev[NETDRV]; + if (drv_calc > 0) { + netPrev[NETDRV] += drv_calc; + netPrev[NETTX] += drv_calc; + // remove tcp/ip header overhead + // approximation based on empirical measurement + netPrev[NETRX] += drv_calc / 42; + netPrev[NETTX] += drv_calc / 18; + } + + rx_calc = (int)(rx_total - netPrev[NETRX]); + if (rx_calc < 0) + rx_calc = 0; + netPrev[NETRX] += rx_calc; + + tx_calc = (int)(tx_total - netPrev[NETTX]); + if (tx_calc < 0) + tx_calc = 0; + netPrev[NETTX] += tx_calc; + + *drv = drv_calc; + *rx = rx_calc; + *tx = tx_calc; +} + +static int gator_events_net_create_files(struct super_block *sb, struct dentry *root) +{ + struct dentry *dir; + + dir = gatorfs_mkdir(sb, root, "Linux_net_drv"); + if (!dir) { + return -1; + } + gatorfs_create_ulong(sb, dir, "enabled", &netdrv_enabled); + gatorfs_create_ro_ulong(sb, dir, "key", &netdrv_key); + + dir = gatorfs_mkdir(sb, root, "Linux_net_rx"); + if (!dir) { + return -1; + } + gatorfs_create_ulong(sb, dir, "enabled", &netrx_enabled); + gatorfs_create_ro_ulong(sb, dir, "key", &netrx_key); + + dir = gatorfs_mkdir(sb, root, "Linux_net_tx"); + if (!dir) { + return -1; + } + gatorfs_create_ulong(sb, dir, "enabled", &nettx_enabled); + gatorfs_create_ro_ulong(sb, dir, "key", &nettx_key); + + return 0; +} + +static int gator_events_net_init(int *key) +{ + netdrv_key = *key; + *key = *key + 1; + netrx_key = *key; + *key = *key + 1; + nettx_key = *key; + *key = *key + 1; + + netdrv_enabled = 0; + netrx_enabled = 0; + nettx_enabled = 0; + + return 0; +} + +static int gator_events_net_start(void) +{ + get_network_stats(NULL); + netPrev[NETDRV] = 0; + netPrev[NETRX] = rx_total; + netPrev[NETTX] = tx_total; + return 0; +} + +static void gator_events_net_stop(void) +{ + netdrv_enabled = 0; + netrx_enabled = 0; + nettx_enabled = 0; +} + +static int gator_events_net_read(int **buffer) +{ + int len, drv_delta, rx_delta, tx_delta; + + if (raw_smp_processor_id() != 0) + return 0; + + schedule_work(&wq_get_stats); + calculate_delta(&drv_delta, &rx_delta, &tx_delta); + + len = 0; + if (netdrv_enabled) { + netGet[len++] = netdrv_key; + netGet[len++] = drv_delta; + } + + if (netrx_enabled) { + netGet[len++] = netrx_key; + netGet[len++] = rx_delta; + } + + if (nettx_enabled) { + netGet[len++] = nettx_key; + netGet[len++] = tx_delta; + } + + if (buffer) + *buffer = netGet; + + return len; +} + +int gator_events_net_install(gator_interface *gi) { + gi->create_files = gator_events_net_create_files; + gi->init = gator_events_net_init; + gi->start = gator_events_net_start; + gi->stop = gator_events_net_stop; + gi->read = gator_events_net_read; + gator_net_traffic++; + return 0; +} diff --git a/gator_events_sched.c b/gator_events_sched.c index 57b710a..138b7e4 100644 --- a/gator_events_sched.c +++ b/gator_events_sched.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -7,15 +7,8 @@ * */ -#include <linux/version.h> -#include <linux/slab.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/dcookies.h> -#include <trace/events/sched.h> - #include "gator.h" -#include "gator_trace.h" +#include <trace/events/sched.h> #define SCHED_SWITCH 0 #define SCHED_TOTAL (SCHED_SWITCH+1) diff --git a/gator_main.c b/gator_main.c index 6748448..60b09cb 100644 --- a/gator_main.c +++ b/gator_main.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -7,20 +7,13 @@ * */ -static unsigned long gator_protocol_version = 2; +static unsigned long gator_protocol_version = 3; -#include <linux/version.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/fs.h> +#include "gator.h" +#include <linux/slab.h> +#include <linux/cpu.h> #include <linux/sched.h> -#include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/smp.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/dcookies.h> #include <linux/vmalloc.h> #include <asm/uaccess.h> @@ -42,12 +35,11 @@ static unsigned long gator_protocol_version = 2; #error kernels prior to 2.6.32 are not supported #endif -#include "gator.h" - /****************************************************************************** * DEFINES ******************************************************************************/ -#define BUFFER_SIZE_DEFAULT 131072 +#define BUFFER_SIZE_DEFAULT 262144 +#define SYNC_FREQ_DEFAULT 1000 #define NO_COOKIE 0UL #define INVALID_COOKIE ~0UL @@ -61,6 +53,7 @@ static unsigned long gator_protocol_version = 2; #define PROTOCOL_SCHEDULER_TRACE 11 #define PROTOCOL_COUNTERS 13 #define PROTOCOL_ANNOTATE 15 +#define PROTOCOL_CPU_SYNC 17 #if defined(__arm__) #define PC_REG regs->ARM_pc @@ -71,19 +64,30 @@ static unsigned long gator_protocol_version = 2; /****************************************************************************** * PER CPU ******************************************************************************/ +static unsigned long gator_cpu_cores; static unsigned long gator_buffer_size; static unsigned long gator_backtrace_depth; static unsigned long gator_started; static unsigned long gator_buffer_opened; static unsigned long gator_timer_count; -static unsigned long gator_dump; +static unsigned long gator_sync_freq; +static int gator_master_tick; static DEFINE_MUTEX(start_mutex); static DEFINE_MUTEX(gator_buffer_mutex); + +unsigned long gator_net_traffic; + +#define COMMIT_SIZE 128 +#define COMMIT_MASK (COMMIT_SIZE-1) +static DEFINE_SPINLOCK(gator_commit_lock); +static int *gator_commit; +static int gator_commit_read; +static int gator_commit_write; + static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait); -/* atomic_t because wait_event checks it outside of gator_buffer_mutex */ -static DEFINE_PER_CPU(atomic_t, gator_buffer_ready); -static DEFINE_PER_CPU(int, gator_tick); +static DEFINE_PER_CPU(int, gator_cpu_sync); +static DEFINE_PER_CPU(int, gator_cpu_tick); static DEFINE_PER_CPU(int, gator_first_time); /****************************************************************************** @@ -115,6 +119,32 @@ u32 gator_cpuid(void) return (val >> 4) & 0xfff; } #endif + +/****************************************************************************** + * Commit interface + ******************************************************************************/ +static int buffer_commit_ready(void) +{ + return (gator_commit_read != gator_commit_write); +} + +static void buffer_commit_read(int *cpu, int *readval, int *writeval) +{ + int read = gator_commit_read; + *cpu = gator_commit[read+0]; + *readval = gator_commit[read+1]; + *writeval = gator_commit[read+2]; + gator_commit_read = (read + 4) & COMMIT_MASK; +} + +static void buffer_commit_write(int cpu, int readval, int writeval) { + int write = gator_commit_write; + gator_commit[write+0] = cpu; + gator_commit[write+1] = readval; + gator_commit[write+2] = writeval; + gator_commit_write = (write + 4) & COMMIT_MASK; +} + /****************************************************************************** * Buffer management ******************************************************************************/ @@ -123,7 +153,6 @@ static uint32_t use_buffer_mask; static DEFINE_PER_CPU(int, use_buffer_seq); static DEFINE_PER_CPU(int, use_buffer_read); static DEFINE_PER_CPU(int, use_buffer_write); -static DEFINE_PER_CPU(int, use_buffer_commit); static DEFINE_PER_CPU(char *, use_buffer); static void gator_buffer_write_packed_int(int cpu, unsigned int x) @@ -193,38 +222,46 @@ static void gator_buffer_header(int cpu) gator_buffer_write_packed_int(cpu, PROTOCOL_FRAME); gator_buffer_write_packed_int(cpu, cpu); gator_buffer_write_packed_int(cpu, per_cpu(use_buffer_seq, cpu)); + per_cpu(use_buffer_seq, cpu)++; } static void gator_buffer_commit(int cpu) { - per_cpu(use_buffer_commit, cpu) = per_cpu(use_buffer_write, cpu); - - per_cpu(use_buffer_seq, cpu)++; + buffer_commit_write(cpu, per_cpu(use_buffer_read, cpu), per_cpu(use_buffer_write, cpu)); + per_cpu(use_buffer_read, cpu) = per_cpu(use_buffer_write, cpu); gator_buffer_header(cpu); - - atomic_set(&per_cpu(gator_buffer_ready, cpu), 1); wake_up(&gator_buffer_wait); } -static void gator_buffer_check(int cpu) +static void gator_buffer_check(int cpu, int tick) { - int commit = 0; - int available = per_cpu(use_buffer_write, cpu) - per_cpu(use_buffer_read, cpu); - if (available < 0) { - available += use_buffer_size; - } - - if (!cpu && gator_dump) { - gator_dump = 0; - commit = 1; - } else if (available >= ((use_buffer_size * 3) / 4)) { - commit = 1; - } else if (cpu && (per_cpu(use_buffer_seq, cpu) < per_cpu(use_buffer_seq, 0))) { - commit = 1; - } - - if (commit) { + if (gator_sync_freq && !(tick % gator_sync_freq)) { + int c, sync; + spin_lock(&gator_commit_lock); + // synchronize, if all online cpus have the same tick waypoint + sync = per_cpu(gator_cpu_sync, cpu) = per_cpu(gator_cpu_tick, cpu); + for_each_online_cpu(c) { + if (sync != per_cpu(gator_cpu_sync, c)) { + sync = 0; + break; + } + } + if (sync) { + gator_buffer_write_packed_int(cpu, PROTOCOL_CPU_SYNC); + } + // commit the buffer gator_buffer_commit(cpu); + spin_unlock(&gator_commit_lock); + } else { + int available = per_cpu(use_buffer_write, cpu) - per_cpu(use_buffer_read, cpu); + if (available < 0) { + available += use_buffer_size; + } + if (available >= ((use_buffer_size * 3) / 4)) { + spin_lock(&gator_commit_lock); + gator_buffer_commit(cpu); + spin_unlock(&gator_commit_lock); + } } } @@ -305,11 +342,11 @@ static void gator_write_annotate(int cpu, int len, int *buffer) ******************************************************************************/ static gator_interface *gi = NULL; -static void gator_timer_interrupt(unsigned int ticks) +static void gator_timer_interrupt(void) { struct pt_regs * const regs = get_irq_regs(); int cpu = raw_smp_processor_id(); - int *buffer, len; + int *buffer, len, tick; gator_interface *i; // check full backtrace has enough space, otherwise may @@ -322,7 +359,6 @@ static void gator_timer_interrupt(unsigned int ticks) i->read(NULL); } } - per_cpu(gator_tick, cpu) += ticks; return; } @@ -354,52 +390,95 @@ static void gator_timer_interrupt(unsigned int ticks) gator_add_sample(cpu, regs); // Timer Tick - gator_write_packet(cpu, PROTOCOL_END_TICK, 1, &per_cpu(gator_tick, cpu)); - per_cpu(gator_tick, cpu) += ticks; + tick = per_cpu(gator_cpu_tick, cpu); + if (tick == gator_master_tick) { + tick++; + per_cpu(gator_cpu_tick, cpu) = gator_master_tick = tick; + } else { + per_cpu(gator_cpu_tick, cpu) = tick = gator_master_tick; + } + gator_write_packet(cpu, PROTOCOL_END_TICK, 1, &tick); - // Check and commit - gator_buffer_check(cpu); + // Check and commit; generally, commit is set to occur once per second + gator_buffer_check(cpu, tick); } /****************************************************************************** * hrtimer ******************************************************************************/ DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer); -extern void gator_timer_stop(void); +DEFINE_PER_CPU(int, hrtimer_is_active); static int hrtimer_running; static ktime_t profiling_interval; -static atomic_t num_active_timers; static enum hrtimer_restart gator_hrtimer_notify(struct hrtimer *hrtimer) { - unsigned int ticks = (unsigned int)hrtimer_forward_now(hrtimer, profiling_interval); - gator_timer_interrupt(ticks); + hrtimer_forward_now(hrtimer, profiling_interval); + gator_timer_interrupt(); return HRTIMER_RESTART; } -int gator_timer_init(void) +static int gator_timer_init(void) { return 0; } -static void __gator_timer_start(void *unused) +static void __gator_timer_offline(void *unused) { int cpu = smp_processor_id(); + if (per_cpu(hrtimer_is_active, cpu)) { + gator_interface *i; + struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); + hrtimer_cancel(hrtimer); + per_cpu(hrtimer_is_active, cpu) = 0; + gator_buffer_commit(cpu); - struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); - hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hrtimer->function = gator_hrtimer_notify; - hrtimer_start(hrtimer, profiling_interval, HRTIMER_MODE_REL_PINNED); - atomic_inc(&num_active_timers); + // offline any events + for (i = gi; i != NULL; i = i->next) { + if (i->offline) { + i->offline(); + } + } + } +} - per_cpu(gator_first_time, cpu) = 1; - per_cpu(gator_tick, cpu) = 0; +static void gator_timer_offline(void) +{ + if (hrtimer_running) { + hrtimer_running = 0; + + on_each_cpu(__gator_timer_offline, NULL, 1); + + // output a final sync point + gator_buffer_write_packed_int(0, PROTOCOL_CPU_SYNC); + gator_buffer_commit(0); + } } -int gator_timer_start(unsigned long setup) +static void __gator_timer_online(void *unused) { - atomic_set(&num_active_timers, 0); + int cpu = smp_processor_id(); + if (!per_cpu(hrtimer_is_active, cpu)) { + gator_interface *i; + struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); + hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer->function = gator_hrtimer_notify; + hrtimer_start(hrtimer, profiling_interval, HRTIMER_MODE_REL_PINNED); + per_cpu(gator_cpu_tick, cpu) = 0; + per_cpu(gator_first_time, cpu) = 1; + per_cpu(hrtimer_is_active, cpu) = 1; + + // online any events + for (i = gi; i != NULL; i = i->next) { + if (i->online) { + i->online(); + } + } + } +} +int gator_timer_online(unsigned long setup) +{ if (!setup) { pr_err("gator: cannot start due to a system tick value of zero"); return -1; @@ -414,37 +493,12 @@ int gator_timer_start(unsigned long setup) profiling_interval = ns_to_ktime(1000000000UL / setup); // timer interrupt - on_each_cpu(__gator_timer_start, NULL, 1); - - if (atomic_read(&num_active_timers) != num_present_cpus()) { - pr_err("gator: %d timer(s) started yet %d cpu(s) detected, please bring all cpus online manually and restart\n", atomic_read(&num_active_timers), nr_cpu_ids); - gator_timer_stop(); - return -1; - } + gator_master_tick = 0; + on_each_cpu(__gator_timer_online, NULL, 1); return 0; } -void __gator_timer_stop(void *unused) -{ - struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, smp_processor_id()); - hrtimer_cancel(hrtimer); - atomic_dec(&num_active_timers); -} - -void gator_timer_stop(void) -{ - if (hrtimer_running) { - int previously_running = atomic_read(&num_active_timers); - hrtimer_running = 0; - on_each_cpu(__gator_timer_stop, NULL, 1); - if (atomic_read(&num_active_timers) != 0) { - pr_err("gator: %d timers stopped yet %d were running, it is advised to quit and restart gatord", previously_running - atomic_read(&num_active_timers), previously_running); - atomic_set(&num_active_timers, 0); - } - } -} - static uint64_t gator_get_time(void) { struct timespec ts; @@ -457,6 +511,42 @@ static uint64_t gator_get_time(void) } /****************************************************************************** + * cpu online notifier + ******************************************************************************/ +static int __cpuinit gator_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + long cpu = (long)hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + smp_call_function_single(cpu, __gator_timer_online, NULL, 1); + break; + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + smp_call_function_single(cpu, __gator_timer_offline, NULL, 1); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block __refdata gator_cpu_notifier = { + .notifier_call = gator_cpu_notify, +}; + +static int gator_notifier_start(void) +{ + return register_hotcpu_notifier(&gator_cpu_notifier); +} + +static void gator_notifier_stop(void) +{ + unregister_hotcpu_notifier(&gator_cpu_notifier); +} + +/****************************************************************************** * Main ******************************************************************************/ int gator_event_install(int (*event_install)(gator_interface *)) @@ -470,6 +560,8 @@ int gator_event_install(int (*event_install)(gator_interface *)) ni->init = NULL; ni->start = NULL; ni->stop = NULL; + ni->online = NULL; + ni->offline = NULL; ni->read = NULL; ni->next = NULL; @@ -538,11 +630,15 @@ static int gator_start(void) goto annotate_failure; if (gator_trace_sched_start()) goto sched_failure; - if (gator_timer_start(gator_timer_count)) + if (gator_timer_online(gator_timer_count)) goto timer_failure; + if (gator_notifier_start()) + goto notifier_failure; return 0; +notifier_failure: + gator_timer_offline(); timer_failure: gator_trace_sched_stop(); sched_failure: @@ -560,17 +656,19 @@ static void gator_stop(void) { gator_interface *i; - // stop all interrupt callback reads before tearing down other interfaces - gator_timer_stop(); - gator_annotate_stop(); - gator_trace_sched_stop(); - // stop all events for (i = gi; i != NULL; i = i->next) { if (i->stop) { i->stop(); } } + + gator_annotate_stop(); + gator_trace_sched_stop(); + + // stop all interrupt callback reads before tearing down other interfaces + gator_timer_offline(); + gator_notifier_stop(); } static void gator_exit(void) @@ -604,18 +702,28 @@ static int gator_op_setup(void) goto setup_error; } - for_each_possible_cpu(cpu) { + gator_net_traffic = 0; + + gator_commit_read = gator_commit_write = 0; + gator_commit = vmalloc(COMMIT_SIZE * sizeof(int)); + if (!gator_commit) { + err = -ENOMEM; + goto setup_error; + } + + for_each_present_cpu(cpu) { per_cpu(use_buffer, cpu) = vmalloc(use_buffer_size); if (!per_cpu(use_buffer, cpu)) { err = -ENOMEM; goto setup_error; } - atomic_set(&per_cpu(gator_buffer_ready, cpu), 0); + per_cpu(gator_cpu_sync, cpu) = 0; + per_cpu(gator_cpu_tick, cpu) = 0; + per_cpu(use_buffer_seq, cpu) = 0; per_cpu(use_buffer_read, cpu) = 0; per_cpu(use_buffer_write, cpu) = 0; - per_cpu(use_buffer_commit, cpu) = 0; gator_buffer_header(cpu); } @@ -646,8 +754,6 @@ static int gator_op_start(void) /* echo 0>/dev/gator/enable */ static void gator_op_stop(void) { - int cpu; - mutex_lock(&start_mutex); if (gator_started) { @@ -655,11 +761,6 @@ static void gator_op_stop(void) mutex_lock(&gator_buffer_mutex); - /* wake up the daemon to read what remains */ - for_each_possible_cpu(cpu) { - gator_buffer_commit(cpu); - atomic_set(&per_cpu(gator_buffer_ready, cpu), 1); - } gator_started = 0; cookies_release(); wake_up(&gator_buffer_wait); @@ -676,14 +777,16 @@ static void gator_shutdown(void) mutex_lock(&start_mutex); - for_each_possible_cpu(cpu) { + vfree(gator_commit); + gator_commit = NULL; + + for_each_present_cpu(cpu) { mutex_lock(&gator_buffer_mutex); vfree(per_cpu(use_buffer, cpu)); per_cpu(use_buffer, cpu) = NULL; per_cpu(use_buffer_seq, cpu) = 0; per_cpu(use_buffer_read, cpu) = 0; per_cpu(use_buffer_write, cpu) = 0; - per_cpu(use_buffer_commit, cpu) = 0; mutex_unlock(&gator_buffer_mutex); } @@ -748,15 +851,6 @@ static int event_buffer_open(struct inode *inode, struct file *file) if (test_and_set_bit_lock(0, &gator_buffer_opened)) return -EBUSY; - /* Register as a user of dcookies - * to ensure they persist for the lifetime of - * the open event file - */ - err = -EINVAL; - file->private_data = dcookie_register(); - if (!file->private_data) - goto out; - if ((err = gator_op_setup())) goto fail; @@ -767,35 +861,18 @@ static int event_buffer_open(struct inode *inode, struct file *file) return 0; fail: - dcookie_unregister(file->private_data); -out: __clear_bit_unlock(0, &gator_buffer_opened); return err; } static int event_buffer_release(struct inode *inode, struct file *file) { - int cpu; gator_op_stop(); gator_shutdown(); - dcookie_unregister(file->private_data); - for_each_possible_cpu(cpu) { - atomic_set(&per_cpu(gator_buffer_ready, cpu), 0); - } __clear_bit_unlock(0, &gator_buffer_opened); return 0; } -static int event_buffer_ready(void) -{ - int cpu; - for_each_possible_cpu(cpu) { - if (atomic_read(&per_cpu(gator_buffer_ready, cpu))) - return cpu; - } - return -1; -} - static ssize_t event_buffer_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { @@ -808,18 +885,17 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf, if (count != use_buffer_size || *offset) return -EINVAL; - wait_event_interruptible(gator_buffer_wait, event_buffer_ready() >= 0 || !gator_started); - cpu = event_buffer_ready(); + // sleep until the condition is true or a signal is received + // the condition is checked each time gator_buffer_wait is woken up + wait_event_interruptible(gator_buffer_wait, buffer_commit_ready() || !gator_started); if (signal_pending(current)) return -EINTR; - if (cpu < 0) + if (!buffer_commit_ready()) return 0; - /* should not happen */ - if (!atomic_read(&per_cpu(gator_buffer_ready, cpu))) - return -EAGAIN; + buffer_commit_read(&cpu, &read, &commit); mutex_lock(&gator_buffer_mutex); @@ -832,8 +908,6 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf, } /* determine the size of two halves */ - commit = per_cpu(use_buffer_commit, cpu); - read = per_cpu(use_buffer_read, cpu); length1 = commit - read; length2 = 0; buffer1 = &(per_cpu(use_buffer, cpu)[read]); @@ -857,16 +931,15 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf, } } - /* update position */ retval = length1 + length2; - per_cpu(use_buffer_read, cpu) = (read + retval) & use_buffer_mask; - - atomic_set(&per_cpu(gator_buffer_ready, cpu), 0); /* kick just in case we've lost an SMP event */ wake_up(&gator_buffer_wait); out: + // do not adjust network stats if in non-streaming buffer mode + if (gator_sync_freq) + gator_net_traffic += retval; mutex_unlock(&gator_buffer_mutex); return retval; } @@ -922,17 +995,24 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root) { struct dentry *dir; gator_interface *i; + int cpu; /* reinitialize default values */ + gator_cpu_cores = 0; + for_each_present_cpu(cpu) { + gator_cpu_cores++; + } gator_buffer_size = BUFFER_SIZE_DEFAULT; + gator_sync_freq = SYNC_FREQ_DEFAULT; gatorfs_create_file(sb, root, "enable", &enable_fops); gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops); gatorfs_create_file(sb, root, "backtrace_depth", &depth_fops); gatorfs_create_file(sb, root, "cpu_type", &cpu_type_fops); + gatorfs_create_ulong(sb, root, "cpu_cores", &gator_cpu_cores); gatorfs_create_ulong(sb, root, "buffer_size", &gator_buffer_size); gatorfs_create_ulong(sb, root, "tick", &gator_timer_count); - gatorfs_create_ulong(sb, root, "dump", &gator_dump); + gatorfs_create_ulong(sb, root, "sync_freq", &gator_sync_freq); gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version); // Annotate interface @@ -975,6 +1055,7 @@ static void __exit gator_module_exit(void) #ifdef GATOR_DEBUG pr_err("gator_module_exit"); #endif + tracepoint_synchronize_unregister(); gatorfs_unregister(); if (gator_initialized) { gator_initialized = 0; diff --git a/gator_trace_sched.c b/gator_trace_sched.c index 1328d88..19d8d89 100644 --- a/gator_trace_sched.c +++ b/gator_trace_sched.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010. All rights reserved. + * Copyright (C) ARM Limited 2010-2011. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -7,14 +7,8 @@ * */ -#include <linux/slab.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/version.h> -#include <linux/hardirq.h> #include <trace/events/sched.h> - -#include "gator_trace.h" +#include "gator.h" #define SCHED_TIMER_EVENT 0 #define SCHED_WAIT_TASK 1 @@ -147,7 +141,7 @@ int gator_trace_sched_start(void) { int cpu; - for_each_possible_cpu(cpu) { + for_each_present_cpu(cpu) { per_cpu(theSchedSel, cpu) = 0; per_cpu(theSchedPos, cpu) = 0; per_cpu(theSchedErr, cpu) = 0; @@ -217,7 +211,7 @@ void gator_trace_sched_stop(void) GATOR_UNREGISTER_TRACE(sched_process_fork); pr_debug("gator: unregistered tracepoints\n"); - for_each_possible_cpu(cpu) { + for_each_present_cpu(cpu) { kfree(per_cpu(theSchedBuf, cpu)[0]); kfree(per_cpu(theSchedBuf, cpu)[1]); per_cpu(theSchedBuf, cpu)[0] = NULL; |