From 34d9769988397a1edf93ad1966c167591ab29e79 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 19 Dec 2013 09:23:06 +0000 Subject: gator: Version 5.17 Signed-off-by: Jon Medhurst --- drivers/gator/Makefile | 61 +++-- drivers/gator/gator.h | 6 +- drivers/gator/gator_annotate_kernel.c | 107 +++++--- drivers/gator/gator_backtrace.c | 10 +- drivers/gator/gator_cookies.c | 36 ++- drivers/gator/gator_events.sh | 19 -- drivers/gator/gator_events_armv6.c | 7 - drivers/gator/gator_events_armv7.c | 7 - drivers/gator/gator_events_block.c | 2 - drivers/gator/gator_events_ccn-504.c | 192 +++++++------ drivers/gator/gator_events_irq.c | 2 - drivers/gator/gator_events_l2c-310.c | 2 - drivers/gator/gator_events_mali_4xx.c | 30 +- drivers/gator/gator_events_mali_common.c | 9 +- drivers/gator/gator_events_mali_common.h | 4 +- drivers/gator/gator_events_mali_t6xx.c | 60 +++- drivers/gator/gator_events_mali_t6xx_hw.c | 46 +++- drivers/gator/gator_events_meminfo.c | 301 +++++++++++++++------ drivers/gator/gator_events_mmaped.c | 229 ---------------- drivers/gator/gator_events_mmapped.c | 209 ++++++++++++++ drivers/gator/gator_events_net.c | 5 +- drivers/gator/gator_events_perf_pmu.c | 83 +++++- drivers/gator/gator_events_sched.c | 2 - drivers/gator/gator_events_scorpion.c | 7 - drivers/gator/gator_main.c | 108 +++++++- drivers/gator/gator_marshaling.c | 19 ++ drivers/gator/gator_trace_gpu.c | 6 +- drivers/gator/gator_trace_sched.c | 20 +- .../gator/mali/mali_mjollnir_profiling_gator_api.h | 15 +- .../gator/mali/mali_utgard_profiling_gator_api.h | 15 +- drivers/gator/mali_t6xx.mk | 11 +- tools/gator/daemon/Buffer.cpp | 11 + tools/gator/daemon/Buffer.h | 5 + tools/gator/daemon/Child.cpp | 13 +- tools/gator/daemon/Child.h | 4 + tools/gator/daemon/ConfigurationXML.h | 4 + tools/gator/daemon/Driver.h | 6 +- tools/gator/daemon/Fifo.h | 4 + tools/gator/daemon/Hwmon.cpp | 4 + tools/gator/daemon/Hwmon.h | 4 + tools/gator/daemon/OlySocket.cpp | 23 +- tools/gator/daemon/Sender.h | 4 + tools/gator/daemon/SessionData.cpp | 12 +- tools/gator/daemon/SessionData.h | 6 +- tools/gator/daemon/SessionXML.h | 4 + tools/gator/daemon/StreamlineSetup.h | 4 + tools/gator/daemon/common.mk | 2 +- tools/gator/daemon/events-CCI-400.xml | 62 ++++- tools/gator/daemon/events-Linux.xml | 10 +- tools/gator/daemon/events-Mali-T6xx.xml | 10 + tools/gator/daemon/events-Mali-T6xx_hw.xml | 5 +- tools/gator/daemon/main.cpp | 25 +- 52 files changed, 1213 insertions(+), 639 deletions(-) delete mode 100755 drivers/gator/gator_events.sh delete mode 100644 drivers/gator/gator_events_mmaped.c create mode 100644 drivers/gator/gator_events_mmapped.c diff --git a/drivers/gator/Makefile b/drivers/gator/Makefile index 0d4ca68701e0..3dc9d059a4b4 100644 --- a/drivers/gator/Makefile +++ b/drivers/gator/Makefile @@ -3,7 +3,8 @@ ifneq ($(KERNELRELEASE),) # Uncomment the following line to enable kernel stack unwinding within gator, or update gator_backtrace.c # EXTRA_CFLAGS += -DGATOR_KERNEL_STACK_UNWINDING -obj-m := gator.o +CONFIG_GATOR ?= m +obj-$(CONFIG_GATOR) := gator.o gator-y := gator_main.o \ gator_events_irq.o \ @@ -11,23 +12,40 @@ gator-y := gator_main.o \ gator_events_net.o \ gator_events_block.o \ gator_events_meminfo.o \ - gator_events_perf_pmu.o - -gator-y += gator_events_mmaped.o + gator_events_perf_pmu.o \ + gator_events_mmapped.o \ +# Convert the old GATOR_WITH_MALI_SUPPORT to the new kernel flags ifneq ($(GATOR_WITH_MALI_SUPPORT),) -ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx) -gator-y += gator_events_mali_t6xx.o \ - gator_events_mali_t6xx_hw.o -include $(M)/mali_t6xx.mk -else -gator-y += gator_events_mali_4xx.o -endif -gator-y += gator_events_mali_common.o -EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT) -ifneq ($(GATOR_MALI_INTERFACE_STYLE),) -EXTRA_CFLAGS += -DGATOR_MALI_INTERFACE_STYLE=$(GATOR_MALI_INTERFACE_STYLE) + CONFIG_GATOR_WITH_MALI_SUPPORT := y + ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx) + CONFIG_GATOR_MALI_4XXMP := n + CONFIG_GATOR_MALI_T6XX := y + else + CONFIG_GATOR_MALI_4XXMP := y + CONFIG_GATOR_MALI_T6XX := n + endif + EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT) + ifneq ($(GATOR_MALI_INTERFACE_STYLE),) + EXTRA_CFLAGS += -DGATOR_MALI_INTERFACE_STYLE=$(GATOR_MALI_INTERFACE_STYLE) + endif endif + +ifeq ($(CONFIG_GATOR_WITH_MALI_SUPPORT),y) + ifeq ($(CONFIG_GATOR_MALI_T6XX),y) + gator-y += gator_events_mali_t6xx.o \ + gator_events_mali_t6xx_hw.o + include $(src)/mali_t6xx.mk + else + gator-y += gator_events_mali_4xx.o + endif + gator-y += gator_events_mali_common.o + + ifneq ($(CONFIG_GATOR_MALI_PATH),) + ccflags-y += -I$(CONFIG_GATOR_MALI_PATH) + endif + ccflags-$(CONFIG_GATOR_MALI_4XXMP) += -DMALI_SUPPORT=MALI_4xx + ccflags-$(CONFIG_GATOR_MALI_T6XX) += -DMALI_SUPPORT=MALI_T6xx endif # GATOR_TEST controls whether to include (=1) or exclude (=0) test code. @@ -42,17 +60,6 @@ gator-$(CONFIG_ARM) += gator_events_armv6.o \ gator-$(CONFIG_ARM64) += gator_events_ccn-504.o -$(obj)/gator_main.o: gator_events.h - -clean-files := gator_events.h - - chk_events.h = : - quiet_chk_events.h = echo ' CHK $@' -silent_chk_events.h = : -gator_events.h: FORCE - @$($(quiet)chk_events.h) - $(Q)cd $(obj) ; $(CONFIG_SHELL) $(obj)/gator_events.sh $@ - else all: @@ -63,7 +70,7 @@ all: $(error) clean: - rm -f *.o .*.cmd gator_events.h modules.order Module.symvers gator.ko gator.mod.c + rm -f *.o .*.cmd modules.order Module.symvers gator.ko gator.mod.c rm -rf .tmp_versions endif diff --git a/drivers/gator/gator.h b/drivers/gator/gator.h index 2e122da767d8..d8981ed85a6a 100644 --- a/drivers/gator/gator.h +++ b/drivers/gator/gator.h @@ -112,14 +112,10 @@ struct gator_interface { void (*offline_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu' int (*read)(int **buffer); int (*read64)(long long **buffer); + int (*read_proc)(long long **buffer, struct task_struct *); struct list_head list; }; -// gator_events_init is used as a search term in gator_events.sh -#define gator_events_init(initfn) \ - static inline int __gator_events_init_test(void) \ - { return initfn(); } - int gator_events_install(struct gator_interface *interface); int gator_events_get_key(void); u32 gator_cpuid(void); diff --git a/drivers/gator/gator_annotate_kernel.c b/drivers/gator/gator_annotate_kernel.c index 4715f64a1865..a406e4882974 100644 --- a/drivers/gator/gator_annotate_kernel.c +++ b/drivers/gator/gator_annotate_kernel.c @@ -29,11 +29,27 @@ static void kannotate_write(const char *ptr, unsigned int size) } } +static void marshal_u16(char *buf, u16 val) { + buf[0] = val & 0xff; + buf[1] = (val >> 8) & 0xff; +} + +static void marshal_u32(char *buf, u32 val) { + buf[0] = val & 0xff; + buf[1] = (val >> 8) & 0xff; + buf[2] = (val >> 16) & 0xff; + buf[3] = (val >> 24) & 0xff; +} + void gator_annotate_channel(int channel, const char *str) { - int str_size = strlen(str) & 0xffff; - long long header = ESCAPE_CODE | (STRING_ANNOTATION << 8) | (channel << 16) | ((long long)str_size << 48); - kannotate_write((char *)&header, sizeof(header)); + const u16 str_size = strlen(str) & 0xffff; + char header[8]; + header[0] = ESCAPE_CODE; + header[1] = STRING_ANNOTATION; + marshal_u32(header + 2, channel); + marshal_u16(header + 6, str_size); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } @@ -48,14 +64,14 @@ EXPORT_SYMBOL(gator_annotate); void gator_annotate_channel_color(int channel, int color, const char *str) { - int str_size = (strlen(str) + 4) & 0xffff; + const u16 str_size = (strlen(str) + 4) & 0xffff; char header[12]; header[0] = ESCAPE_CODE; header[1] = STRING_ANNOTATION; - *(u32 *)(&header[2]) = channel; - *(u16 *)(&header[6]) = str_size; - *(u32 *)(&header[8]) = color; - kannotate_write((char *)&header, sizeof(header)); + marshal_u32(header + 2, channel); + marshal_u16(header + 6, str_size); + marshal_u32(header + 8, color); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size - 4); } @@ -70,8 +86,12 @@ EXPORT_SYMBOL(gator_annotate_color); void gator_annotate_channel_end(int channel) { - long long header = ESCAPE_CODE | (STRING_ANNOTATION << 8) | (channel << 16); - kannotate_write((char *)&header, sizeof(header)); + char header[8]; + header[0] = ESCAPE_CODE; + header[1] = STRING_ANNOTATION; + marshal_u32(header + 2, channel); + marshal_u16(header + 6, 0); + kannotate_write(header, sizeof(header)); } EXPORT_SYMBOL(gator_annotate_channel_end); @@ -85,14 +105,14 @@ EXPORT_SYMBOL(gator_annotate_end); void gator_annotate_name_channel(int channel, int group, const char* str) { - int str_size = strlen(str) & 0xffff; + const u16 str_size = strlen(str) & 0xffff; char header[12]; header[0] = ESCAPE_CODE; header[1] = NAME_CHANNEL_ANNOTATION; - *(u32 *)(&header[2]) = channel; - *(u32 *)(&header[6]) = group; - *(u16 *)(&header[10]) = str_size; - kannotate_write((char *)&header, sizeof(header)); + marshal_u32(header + 2, channel); + marshal_u32(header + 6, group); + marshal_u16(header + 10, str_size); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } @@ -100,9 +120,13 @@ EXPORT_SYMBOL(gator_annotate_name_channel); void gator_annotate_name_group(int group, const char* str) { - int str_size = strlen(str) & 0xffff; - long long header = ESCAPE_CODE | (NAME_GROUP_ANNOTATION << 8) | (group << 16) | ((long long)str_size << 48); - kannotate_write((char *)&header, sizeof(header)); + const u16 str_size = strlen(str) & 0xffff; + char header[8]; + header[0] = ESCAPE_CODE; + header[1] = NAME_GROUP_ANNOTATION; + marshal_u32(header + 2, group); + marshal_u16(header + 6, str_size); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } @@ -110,11 +134,16 @@ EXPORT_SYMBOL(gator_annotate_name_group); void gator_annotate_visual(const char *data, unsigned int length, const char *str) { - int str_size = strlen(str) & 0xffff; - int visual_annotation = ESCAPE_CODE | (VISUAL_ANNOTATION << 8) | (str_size << 16); - kannotate_write((char *)&visual_annotation, sizeof(visual_annotation)); + const u16 str_size = strlen(str) & 0xffff; + char header[4]; + char header_length[4]; + header[0] = ESCAPE_CODE; + header[1] = VISUAL_ANNOTATION; + marshal_u16(header + 2, str_size); + marshal_u32(header_length, length); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); - kannotate_write((char *)&length, sizeof(length)); + kannotate_write(header_length, sizeof(header_length)); kannotate_write(data, length); } @@ -122,17 +151,23 @@ EXPORT_SYMBOL(gator_annotate_visual); void gator_annotate_marker(void) { - int header = ESCAPE_CODE | (MARKER_ANNOTATION << 8); - kannotate_write((char *)&header, sizeof(header)); + char header[4]; + header[0] = ESCAPE_CODE; + header[1] = MARKER_ANNOTATION; + marshal_u16(header + 2, 0); + kannotate_write(header, sizeof(header)); } EXPORT_SYMBOL(gator_annotate_marker); void gator_annotate_marker_str(const char *str) { - int str_size = strlen(str) & 0xffff; - int header = ESCAPE_CODE | (MARKER_ANNOTATION << 8) | (str_size << 16); - kannotate_write((char *)&header, sizeof(header)); + const u16 str_size = strlen(str) & 0xffff; + char header[4]; + header[0] = ESCAPE_CODE; + header[1] = MARKER_ANNOTATION; + marshal_u16(header + 2, str_size); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } @@ -140,17 +175,25 @@ EXPORT_SYMBOL(gator_annotate_marker_str); void gator_annotate_marker_color(int color) { - long long header = (ESCAPE_CODE | (MARKER_ANNOTATION << 8) | 0x00040000 | ((long long)color << 32)); - kannotate_write((char *)&header, sizeof(header)); + char header[8]; + header[0] = ESCAPE_CODE; + header[1] = MARKER_ANNOTATION; + marshal_u16(header + 2, 4); + marshal_u32(header + 4, color); + kannotate_write(header, sizeof(header)); } EXPORT_SYMBOL(gator_annotate_marker_color); void gator_annotate_marker_color_str(int color, const char *str) { - int str_size = (strlen(str) + 4) & 0xffff; - long long header = ESCAPE_CODE | (MARKER_ANNOTATION << 8) | (str_size << 16) | ((long long)color << 32); - kannotate_write((char *)&header, sizeof(header)); + const u16 str_size = (strlen(str) + 4) & 0xffff; + char header[8]; + header[0] = ESCAPE_CODE; + header[1] = MARKER_ANNOTATION; + marshal_u16(header + 2, str_size); + marshal_u32(header + 4, color); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size - 4); } diff --git a/drivers/gator/gator_backtrace.c b/drivers/gator/gator_backtrace.c index 0670d6cea9bd..ffacb490194c 100644 --- a/drivers/gator/gator_backtrace.c +++ b/drivers/gator/gator_backtrace.c @@ -132,13 +132,21 @@ static int report_trace(struct stackframe *frame, void *d) // Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile // #define GATOR_KERNEL_STACK_UNWINDING + +#if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING) +// Disabled by default +MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding."); +bool kernel_stack_unwinding = 0; +module_param(kernel_stack_unwinding, bool, 0644); +#endif + static void kernel_backtrace(int cpu, struct pt_regs *const regs) { #if defined(__arm__) || defined(__aarch64__) #ifdef GATOR_KERNEL_STACK_UNWINDING int depth = gator_backtrace_depth; #else - int depth = 1; + int depth = (kernel_stack_unwinding ? gator_backtrace_depth : 1); #endif struct stackframe frame; if (depth == 0) diff --git a/drivers/gator/gator_cookies.c b/drivers/gator/gator_cookies.c index 5f98a1cc309c..91adfdde9be2 100644 --- a/drivers/gator/gator_cookies.c +++ b/drivers/gator/gator_cookies.c @@ -8,7 +8,8 @@ */ #define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */ -#define TRANSLATE_SIZE 256 +#define TRANSLATE_BUFFER_SIZE 512 // must be a power of 2 - 512/4 = 128 entries +#define TRANSLATE_TEXT_SIZE 256 #define MAX_COLLISIONS 2 static uint32_t *gator_crc32_table; @@ -22,7 +23,7 @@ static DEFINE_PER_CPU(int, translate_buffer_read); static DEFINE_PER_CPU(int, translate_buffer_write); static DEFINE_PER_CPU(void **, translate_buffer); -static inline uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq); +static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq); static void wq_cookie_handler(struct work_struct *unused); DECLARE_WORK(cookie_work, wq_cookie_handler); static struct timer_list app_process_wake_up_timer; @@ -107,11 +108,13 @@ static void cookiemap_add(uint64_t key, uint32_t value) values[0] = value; } +#ifndef CONFIG_PREEMPT_RT_FULL static void translate_buffer_write_ptr(int cpu, void *x) { per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_write, cpu)++] = x; per_cpu(translate_buffer_write, cpu) &= translate_buffer_mask; } +#endif static void *translate_buffer_read_ptr(int cpu) { @@ -124,7 +127,7 @@ static void wq_cookie_handler(struct work_struct *unused) { struct task_struct *task; char *text; - int cpu = get_physical_cpu(); + int cpu = get_physical_cpu(), cookie; unsigned int commit; mutex_lock(&start_mutex); @@ -134,7 +137,8 @@ static void wq_cookie_handler(struct work_struct *unused) while (per_cpu(translate_buffer_read, cpu) != commit) { task = (struct task_struct *)translate_buffer_read_ptr(cpu); text = (char *)translate_buffer_read_ptr(cpu); - get_cookie(cpu, task, text, true); + cookie = get_cookie(cpu, task, text, true); + marshal_link(cookie, task->tgid, task->pid); } } @@ -156,15 +160,16 @@ static int translate_app_process(const char **text, int cpu, struct task_struct struct mm_struct *mm; struct page *page = NULL; struct vm_area_struct *page_vma; - int bytes, offset, retval = 0, ptr; + int bytes, offset, retval = 0; char *buf = per_cpu(translate_text, cpu); +#ifndef CONFIG_PREEMPT_RT_FULL // Push work into a work queue if in atomic context as the kernel functions below might sleep // Rely on the in_interrupt variable rather than in_irq() or in_interrupt() kernel functions, as the value of these functions seems // inconsistent during a context switch between android/linux versions if (!from_wq) { // Check if already in buffer - ptr = per_cpu(translate_buffer_read, cpu); + int ptr = per_cpu(translate_buffer_read, cpu); while (ptr != per_cpu(translate_buffer_write, cpu)) { if (per_cpu(translate_buffer, cpu)[ptr] == (void *)task) goto out; @@ -174,9 +179,11 @@ static int translate_app_process(const char **text, int cpu, struct task_struct translate_buffer_write_ptr(cpu, (void *)task); translate_buffer_write_ptr(cpu, (void *)*text); + // Not safe to call in RT-Preempt full in schedule switch context mod_timer(&app_process_wake_up_timer, jiffies + 1); goto out; } +#endif mm = get_task_mm(task); if (!mm) @@ -186,8 +193,8 @@ static int translate_app_process(const char **text, int cpu, struct task_struct addr = mm->arg_start; len = mm->arg_end - mm->arg_start; - if (len > TRANSLATE_SIZE) - len = TRANSLATE_SIZE; + if (len > TRANSLATE_TEXT_SIZE) + len = TRANSLATE_TEXT_SIZE; down_read(&mm->mmap_sem); while (len) { @@ -225,7 +232,7 @@ out: return retval; } -static inline uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq) +static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq) { unsigned long flags, cookie; uint64_t key; @@ -312,8 +319,7 @@ static int cookies_initialize(void) uint32_t crc, poly; int i, j, cpu, size, err = 0; - int translate_buffer_size = 512; // must be a power of 2 - translate_buffer_mask = translate_buffer_size / sizeof(per_cpu(translate_buffer, 0)[0]) - 1; + translate_buffer_mask = TRANSLATE_BUFFER_SIZE / sizeof(per_cpu(translate_buffer, 0)[0]) - 1; for_each_present_cpu(cpu) { per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu; @@ -334,7 +340,7 @@ static int cookies_initialize(void) } memset(per_cpu(cookie_values, cpu), 0, size); - per_cpu(translate_buffer, cpu) = (void **)kmalloc(translate_buffer_size, GFP_KERNEL); + per_cpu(translate_buffer, cpu) = (void **)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL); if (!per_cpu(translate_buffer, cpu)) { err = -ENOMEM; goto cookie_setup_error; @@ -343,7 +349,7 @@ static int cookies_initialize(void) per_cpu(translate_buffer_write, cpu) = 0; per_cpu(translate_buffer_read, cpu) = 0; - per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_SIZE, GFP_KERNEL); + per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL); if (!per_cpu(translate_text, cpu)) { err = -ENOMEM; goto cookie_setup_error; @@ -353,6 +359,10 @@ static int cookies_initialize(void) // build CRC32 table poly = 0x04c11db7; gator_crc32_table = (uint32_t *)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL); + if (!gator_crc32_table) { + err = -ENOMEM; + goto cookie_setup_error; + } for (i = 0; i < 256; i++) { crc = i; for (j = 8; j > 0; j--) { diff --git a/drivers/gator/gator_events.sh b/drivers/gator/gator_events.sh deleted file mode 100755 index 5467dd6d17d6..000000000000 --- a/drivers/gator/gator_events.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -EVENTS=`grep gator_events_init *.c | sed 's/.\+gator_events_init(\(.\+\)).\+/\1/'` - -( - echo /\* This file is auto generated \*/ - echo - for EVENT in $EVENTS; do - echo __weak int $EVENT\(void\)\; - done - echo - echo static int \(*gator_events_list[]\)\(void\) = { - for EVENT in $EVENTS; do - echo \ $EVENT, - done - echo }\; -) > $1.tmp - -cmp -s $1 $1.tmp && rm $1.tmp || mv $1.tmp $1 diff --git a/drivers/gator/gator_events_armv6.c b/drivers/gator/gator_events_armv6.c index 4f1bca6e2dbe..dd7974090b82 100644 --- a/drivers/gator/gator_events_armv6.c +++ b/drivers/gator/gator_events_armv6.c @@ -234,11 +234,4 @@ int gator_events_armv6_init(void) return gator_events_install(&gator_events_armv6_interface); } -gator_events_init(gator_events_armv6_init); - -#else -int gator_events_armv6_init(void) -{ - return -1; -} #endif diff --git a/drivers/gator/gator_events_armv7.c b/drivers/gator/gator_events_armv7.c index 58f29566eeab..30881c8fd3fd 100644 --- a/drivers/gator/gator_events_armv7.c +++ b/drivers/gator/gator_events_armv7.c @@ -309,11 +309,4 @@ int gator_events_armv7_init(void) return gator_events_install(&gator_events_armv7_interface); } -gator_events_init(gator_events_armv7_init); - -#else -int gator_events_armv7_init(void) -{ - return -1; -} #endif diff --git a/drivers/gator/gator_events_block.c b/drivers/gator/gator_events_block.c index 56c6a6736529..691ef2574536 100644 --- a/drivers/gator/gator_events_block.c +++ b/drivers/gator/gator_events_block.c @@ -151,5 +151,3 @@ int gator_events_block_init(void) return gator_events_install(&gator_events_block_interface); } - -gator_events_init(gator_events_block_init); diff --git a/drivers/gator/gator_events_ccn-504.c b/drivers/gator/gator_events_ccn-504.c index b91a9a149b90..b89231967c75 100644 --- a/drivers/gator/gator_events_ccn-504.c +++ b/drivers/gator/gator_events_ccn-504.c @@ -6,23 +6,16 @@ * published by the Free Software Foundation. */ -/******************************************************************************* - * WARNING: This code is an experimental implementation of the CCN-504 hardware - * counters which has not been tested on the hardware. Commented debug - * statements are present and can be uncommented for diagnostic purposes. - ******************************************************************************/ - #include #include #include "gator.h" -#define PERIPHBASE 0x2E000000 - #define NUM_REGIONS 256 #define REGION_SIZE (64*1024) #define REGION_DEBUG 1 #define REGION_XP 64 +#define NUM_XPS 11 // DT (Debug) region #define PMEVCNTSR0 0x0150 @@ -34,27 +27,86 @@ // XP region #define DT_CONFIG 0x0300 +#define DT_CONTROL 0x0370 // Multiple #define PMU_EVENT_SEL 0x0600 #define OLY_ID 0xFF00 #define CCNT 4 -#define CNTMAX (4 + 1) +#define CNTMAX (CCNT + 1) #define get_pmu_event_id(event) (((event) >> 0) & 0xFF) #define get_node_type(event) (((event) >> 8) & 0xFF) #define get_region(event) (((event) >> 16) & 0xFF) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + +// From kernel/params.c +#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \ + int param_set_##name(const char *val, struct kernel_param *kp) \ + { \ + tmptype l; \ + int ret; \ + \ + if (!val) return -EINVAL; \ + ret = strtolfn(val, 0, &l); \ + if (ret == -EINVAL || ((type)l != l)) \ + return -EINVAL; \ + *((type *)kp->arg) = l; \ + return 0; \ + } \ + int param_get_##name(char *buffer, struct kernel_param *kp) \ + { \ + return sprintf(buffer, format, *((type *)kp->arg)); \ + } + +#else + +// From kernel/params.c +#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \ + int param_set_##name(const char *val, const struct kernel_param *kp) \ + { \ + tmptype l; \ + int ret; \ + \ + ret = strtolfn(val, 0, &l); \ + if (ret < 0 || ((type)l != l)) \ + return ret < 0 ? ret : -EINVAL; \ + *((type *)kp->arg) = l; \ + return 0; \ + } \ + int param_get_##name(char *buffer, const struct kernel_param *kp) \ + { \ + return scnprintf(buffer, PAGE_SIZE, format, \ + *((type *)kp->arg)); \ + } \ + struct kernel_param_ops param_ops_##name = { \ + .set = param_set_##name, \ + .get = param_get_##name, \ + }; \ + EXPORT_SYMBOL(param_set_##name); \ + EXPORT_SYMBOL(param_get_##name); \ + EXPORT_SYMBOL(param_ops_##name) + +#endif + +STANDARD_PARAM_DEF(u64, u64, "%llu", u64, strict_strtoull); + +// From include/linux/moduleparam.h +#define param_check_u64(name, p) __param_check(name, p, u64) + MODULE_PARM_DESC(ccn504_addr, "CCN-504 physical base address"); -static unsigned long ccn504_addr = 0; -module_param(ccn504_addr, ulong, 0444); +static u64 ccn504_addr = 0; +module_param(ccn504_addr, u64, 0444); static void __iomem *gator_events_ccn504_base; +static bool gator_events_ccn504_global_enabled; static unsigned long gator_events_ccn504_enabled[CNTMAX]; static unsigned long gator_events_ccn504_event[CNTMAX]; static unsigned long gator_events_ccn504_key[CNTMAX]; static int gator_events_ccn504_buffer[2*CNTMAX]; +static int gator_events_ccn504_prev[CNTMAX]; static void gator_events_ccn504_create_shutdown(void) { @@ -96,7 +148,6 @@ static void gator_events_ccn504_set_dt_config(int xp_node_id, int event_num, int dt_config = readl(gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG); dt_config |= (value + event_num) << (4*event_num); - //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, dt_config, (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG); writel(dt_config, gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG); } @@ -104,6 +155,20 @@ static int gator_events_ccn504_start(void) { int i; + gator_events_ccn504_global_enabled = 0; + for (i = 0; i < CNTMAX; ++i) { + if (gator_events_ccn504_enabled[i]) { + gator_events_ccn504_global_enabled = 1; + break; + } + } + + if (!gator_events_ccn504_global_enabled) { + return 0; + } + + memset(&gator_events_ccn504_prev, 0x80, sizeof(gator_events_ccn504_prev)); + // Disable INTREQ on overflow // [6] ovfl_intr_en = 0 // perhaps set to 1? @@ -112,9 +177,22 @@ static int gator_events_ccn504_start(void) // [4:1] cntcfg = 0 // Enable PMU features // [0] pmu_en = 1 - //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0x1, REGION_DEBUG*REGION_SIZE + PMCR); writel(0x1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMCR); + // Configure the XPs + for (i = 0; i < NUM_XPS; ++i) { + int dt_control; + + // Pass on all events + writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG); + + // Enable PMU capability + // [0] dt_enable = 1 + dt_control = readl(gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL); + dt_control |= 0x1; + writel(dt_control, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL); + } + // Assume no other pmu_event_sel registers are set // cycle counter does not need to be enabled @@ -134,15 +212,14 @@ static int gator_events_ccn504_start(void) pmu_event_id = get_pmu_event_id(gator_events_ccn504_event[i]); node_type = get_node_type(gator_events_ccn504_event[i]); region = get_region(gator_events_ccn504_event[i]); - //printk(KERN_ERR "%s(%s:%i) pmu_event_id: %x node_type: %x region: %x\n", __FUNCTION__, __FILE__, __LINE__, pmu_event_id, node_type, region); // Verify the node_type oly_id_whole = readl(gator_events_ccn504_base + region*REGION_SIZE + OLY_ID); oly_id = oly_id_whole & 0x1F; node_id = (oly_id_whole >> 8) & 0x7F; if ((oly_id != node_type) || - ((node_type == 0x16) && ((oly_id == 0x14) || (oly_id == 0x15) || (oly_id == 0x16) || (oly_id == 0x18) || (oly_id == 0x19) || (oly_id == 0x1A)))) { - printk(KERN_ERR "%s(%s:%i) oly_id is %x expected %x\n", __FUNCTION__, __FILE__, __LINE__, oly_id, node_type); + ((node_type == 0x16) && ((oly_id != 0x14) && (oly_id != 0x15) && (oly_id != 0x16) && (oly_id != 0x18) && (oly_id != 0x19) && (oly_id != 0x1A)))) { + printk(KERN_ERR "gator: oly_id is 0x%x expected 0x%x\n", oly_id, node_type); return -1; } @@ -160,7 +237,6 @@ static int gator_events_ccn504_start(void) gator_events_ccn504_set_dt_config(node_id/2, i, (node_id & 1) == 0 ? 0x8 : 0xC); break; } - //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, pmu_event_sel, region*REGION_SIZE + PMU_EVENT_SEL); writel(pmu_event_sel, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL); } @@ -171,21 +247,25 @@ static void gator_events_ccn504_stop(void) { int i; + if (!gator_events_ccn504_global_enabled) { + return; + } + // cycle counter does not need to be disabled for (i = 0; i < CCNT; ++i) { - int node_type; int region; - node_type = get_node_type(gator_events_ccn504_event[i]); + if (!gator_events_ccn504_enabled[i]) { + continue; + } + region = get_region(gator_events_ccn504_event[i]); - //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0, region*REGION_SIZE + PMU_EVENT_SEL); writel(0, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL); } // Clear dt_config - for (i = 0; i < 11; ++i) { - //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0, (REGION_XP + i)*REGION_SIZE + DT_CONFIG); + for (i = 0; i < NUM_XPS; ++i) { writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG); } } @@ -194,27 +274,20 @@ static int gator_events_ccn504_read(int **buffer) { int i; int len = 0; + int value; - if (!on_primary_core()) { + if (!on_primary_core() || !gator_events_ccn504_global_enabled) { return 0; } // Verify the pmsr register is zero - //i = 0; - while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0) { - //++i; - } - //printk(KERN_ERR "%s(%s:%i) %i\n", __FUNCTION__, __FILE__, __LINE__, i); + while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0); // Request a PMU snapshot writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_REQ); // Wait for the snapshot - //i = 0; - while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0) { - //++i; - } - //printk(KERN_ERR "%s(%s:%i) %i\n", __FUNCTION__, __FILE__, __LINE__, i); + while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0); // Read the shadow registers for (i = 0; i < CNTMAX; ++i) { @@ -222,8 +295,12 @@ static int gator_events_ccn504_read(int **buffer) continue; } - gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i]; - gator_events_ccn504_buffer[len++] = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i)); + value = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i)); + if (gator_events_ccn504_prev[i] != 0x80808080) { + gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i]; + gator_events_ccn504_buffer[len++] = value - gator_events_ccn504_prev[i]; + } + gator_events_ccn504_prev[i] = value; // Are the counters registers cleared when read? Is that what the cntr_rst bit on the pmcr register does? } @@ -231,18 +308,10 @@ static int gator_events_ccn504_read(int **buffer) // Clear the PMU snapshot status writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_CLR); - return len; -} - -static void __maybe_unused gator_events_ccn504_enumerate(int pos, int size) -{ - int i; - u32 oly_id; + if (buffer) + *buffer = gator_events_ccn504_buffer; - for (i = pos; i < pos + size; ++i) { - oly_id = readl(gator_events_ccn504_base + i*REGION_SIZE + OLY_ID); - printk(KERN_ERR "%s(%s:%i) %i %08x\n", __FUNCTION__, __FILE__, __LINE__, i, oly_id); - } + return len; } static struct gator_interface gator_events_ccn504_interface = { @@ -263,36 +332,9 @@ int gator_events_ccn504_init(void) gator_events_ccn504_base = ioremap(ccn504_addr, NUM_REGIONS*REGION_SIZE); if (gator_events_ccn504_base == NULL) { - printk(KERN_ERR "%s(%s:%i) ioremap returned NULL\n", __FUNCTION__, __FILE__, __LINE__); + printk(KERN_ERR "gator: ioremap returned NULL\n"); return -1; } - //printk(KERN_ERR "%s(%s:%i)\n", __FUNCTION__, __FILE__, __LINE__); - - // Test - can memory be read - { - //gator_events_ccn504_enumerate(0, NUM_REGIONS); - -#if 0 - // DT - gator_events_ccn504_enumerate(1, 1); - // HN-F - gator_events_ccn504_enumerate(32, 8); - // XP - gator_events_ccn504_enumerate(64, 11); - // RN-I - gator_events_ccn504_enumerate(128, 1); - gator_events_ccn504_enumerate(130, 1); - gator_events_ccn504_enumerate(134, 1); - gator_events_ccn504_enumerate(140, 1); - gator_events_ccn504_enumerate(144, 1); - gator_events_ccn504_enumerate(148, 1); - // SBAS - gator_events_ccn504_enumerate(129, 1); - gator_events_ccn504_enumerate(137, 1); - gator_events_ccn504_enumerate(139, 1); - gator_events_ccn504_enumerate(147, 1); -#endif - } for (i = 0; i < CNTMAX; ++i) { gator_events_ccn504_enabled[i] = 0; @@ -302,5 +344,3 @@ int gator_events_ccn504_init(void) return gator_events_install(&gator_events_ccn504_interface); } - -gator_events_init(gator_events_ccn504_init); diff --git a/drivers/gator/gator_events_irq.c b/drivers/gator/gator_events_irq.c index b4df7faefff8..b11879a248f8 100644 --- a/drivers/gator/gator_events_irq.c +++ b/drivers/gator/gator_events_irq.c @@ -163,5 +163,3 @@ int gator_events_irq_init(void) return gator_events_install(&gator_events_irq_interface); } - -gator_events_init(gator_events_irq_init); diff --git a/drivers/gator/gator_events_l2c-310.c b/drivers/gator/gator_events_l2c-310.c index 21aa4a214d97..ee521af22517 100644 --- a/drivers/gator/gator_events_l2c-310.c +++ b/drivers/gator/gator_events_l2c-310.c @@ -206,5 +206,3 @@ int gator_events_l2c310_init(void) return gator_events_install(&gator_events_l2c310_interface); } - -gator_events_init(gator_events_l2c310_init); diff --git a/drivers/gator/gator_events_mali_4xx.c b/drivers/gator/gator_events_mali_4xx.c index dd275f70b700..6719c1ec73a2 100644 --- a/drivers/gator/gator_events_mali_4xx.c +++ b/drivers/gator/gator_events_mali_4xx.c @@ -415,25 +415,12 @@ static void mali_counter_initialize(void) int i; int core_id; - mali_osk_fb_control_set_type *mali_set_fb_event; mali_profiling_control_type *mali_control; init_counters(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores) - 1); init_counters(COUNTER_VP_0_C0, COUNTER_VP_0_C0 + (2 * n_vp_cores) - 1); init_counters(COUNTER_FP_0_C0, COUNTER_FP_0_C0 + (2 * n_fp_cores) - 1); - mali_set_fb_event = symbol_get(_mali_osk_fb_control_set); - - if (mali_set_fb_event) { - pr_debug("gator: mali online _mali_osk_fb_control_set symbol @ %p\n", mali_set_fb_event); - - mali_set_fb_event(0, (counter_enabled[COUNTER_FILMSTRIP] ? 1 : 0)); - - symbol_put(_mali_osk_fb_control_set); - } else { - printk("gator: mali online _mali_osk_fb_control_set symbol not found\n"); - } - /* Generic control interface for Mali DDK. */ mali_control = symbol_get(_mali_profiling_control); if (mali_control) { @@ -491,7 +478,6 @@ static void mali_counter_initialize(void) static void mali_counter_deinitialize(void) { mali_profiling_set_event_type *mali_set_hw_event; - mali_osk_fb_control_set_type *mali_set_fb_event; mali_profiling_control_type *mali_control; mali_set_hw_event = symbol_get(_mali_profiling_set_event); @@ -509,23 +495,11 @@ static void mali_counter_deinitialize(void) printk("gator: mali offline _mali_profiling_set_event symbol not found\n"); } - mali_set_fb_event = symbol_get(_mali_osk_fb_control_set); - - if (mali_set_fb_event) { - pr_debug("gator: mali offline _mali_osk_fb_control_set symbol @ %p\n", mali_set_fb_event); - - mali_set_fb_event(0, 0); - - symbol_put(_mali_osk_fb_control_set); - } else { - printk("gator: mali offline _mali_osk_fb_control_set symbol not found\n"); - } - /* Generic control interface for Mali DDK. */ mali_control = symbol_get(_mali_profiling_control); if (mali_control) { - pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_set_fb_event); + pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control); /* Reset the DDK state - disable counter collection */ mali_control(SW_COUNTER_ENABLE, 0); @@ -747,5 +721,3 @@ int gator_events_mali_init(void) return gator_events_install(&gator_events_mali_interface); } - -gator_events_init(gator_events_mali_init); diff --git a/drivers/gator/gator_events_mali_common.c b/drivers/gator/gator_events_mali_common.c index 5a98b3745fc2..466ca1683c7e 100644 --- a/drivers/gator/gator_events_mali_common.c +++ b/drivers/gator/gator_events_mali_common.c @@ -28,7 +28,7 @@ extern const char *gator_mali_get_mali_name(void) } } -extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter) +extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event) { int err; char buf[255]; @@ -56,6 +56,13 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf); return -1; } + if (event != NULL) { + err = gatorfs_create_ulong(sb, dir, "event", event); + if (err != 0) { + pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf); + return -1; + } + } } return 0; diff --git a/drivers/gator/gator_events_mali_common.h b/drivers/gator/gator_events_mali_common.h index d67ee2d245ad..509f9b61884a 100644 --- a/drivers/gator/gator_events_mali_common.h +++ b/drivers/gator/gator_events_mali_common.h @@ -43,7 +43,6 @@ typedef struct { * Mali-4xx */ typedef int mali_profiling_set_event_type(unsigned int, int); -typedef void mali_osk_fb_control_set_type(unsigned int, unsigned int); typedef void mali_profiling_control_type(unsigned int, unsigned int); typedef void mali_profiling_get_counters_type(unsigned int *, unsigned int *, unsigned int *, unsigned int *); @@ -51,7 +50,6 @@ typedef void mali_profiling_get_counters_type(unsigned int *, unsigned int *, un * Driver entry points for functions called directly by gator. */ extern int _mali_profiling_set_event(unsigned int, int); -extern void _mali_osk_fb_control_set(unsigned int, unsigned int); extern void _mali_profiling_control(unsigned int, unsigned int); extern void _mali_profiling_get_counters(unsigned int *, unsigned int *, unsigned int *, unsigned int *); @@ -75,7 +73,7 @@ extern const char *gator_mali_get_mali_name(void); * * @return 0 if entry point was created, non-zero if not. */ -extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter); +extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event); /** * Initializes the counter array. diff --git a/drivers/gator/gator_events_mali_t6xx.c b/drivers/gator/gator_events_mali_t6xx.c index 2576a99a126a..7bf7d6a6dbf9 100644 --- a/drivers/gator/gator_events_mali_t6xx.c +++ b/drivers/gator/gator_events_mali_t6xx.c @@ -109,12 +109,14 @@ enum { #define NUMBER_OF_SOFTWARE_COUNTERS (sizeof(software_counter_names) / sizeof(software_counter_names[0])) #define FIRST_ACCUMULATOR (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS) #define NUMBER_OF_ACCUMULATORS (sizeof(accumulators_names) / sizeof(accumulators_names[0])) -#define NUMBER_OF_EVENTS (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS) +#define FILMSTRIP (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS) +#define NUMBER_OF_EVENTS (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS + 1) /* * gatorfs variables for counter enable state */ static mali_counter counters[NUMBER_OF_EVENTS]; +static unsigned long filmstrip_event; /* An array used to return the data we recorded * as key,value pairs hence the *2 @@ -285,28 +287,37 @@ static int create_files(struct super_block *sb, struct dentry *root) */ int counter_index = 0; const char *mali_name = gator_mali_get_mali_name(); + mali_profiling_control_type *mali_control; for (event = FIRST_TIMELINE_EVENT; event < FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS; event++) { - if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event]) != 0) { + if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event], NULL) != 0) { return -1; } counter_index++; } counter_index = 0; for (event = FIRST_SOFTWARE_COUNTER; event < FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS; event++) { - if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event]) != 0) { + if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event], NULL) != 0) { return -1; } counter_index++; } counter_index = 0; for (event = FIRST_ACCUMULATOR; event < FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS; event++) { - if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event]) != 0) { + if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event], NULL) != 0) { return -1; } counter_index++; } + mali_control = symbol_get(_mali_profiling_control); + if (mali_control) { + if (gator_mali_create_file_system(mali_name, "Filmstrip_cnt0", sb, root, &counters[FILMSTRIP], &filmstrip_event) != 0) { + return -1; + } + symbol_put(_mali_profiling_control); + } + return 0; } @@ -350,6 +361,7 @@ static int register_tracepoints(void) static int start(void) { unsigned int cnt; + mali_profiling_control_type *mali_control; /* Clean all data for the next capture */ for (cnt = 0; cnt < NUMBER_OF_TIMELINE_EVENTS; cnt++) { @@ -370,6 +382,30 @@ static int start(void) return -1; } + /* Generic control interface for Mali DDK. */ + mali_control = symbol_get(_mali_profiling_control); + if (mali_control) { + /* The event attribute in the XML file keeps the actual frame rate. */ + unsigned int enabled = counters[FILMSTRIP].enabled ? 1 : 0; + unsigned int rate = filmstrip_event & 0xff; + unsigned int resize_factor = (filmstrip_event >> 8) & 0xff; + + pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control); + +#define FBDUMP_CONTROL_ENABLE (1) +#define FBDUMP_CONTROL_RATE (2) +#define FBDUMP_CONTROL_RESIZE_FACTOR (4) + mali_control(FBDUMP_CONTROL_ENABLE, enabled); + mali_control(FBDUMP_CONTROL_RATE, rate); + mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor); + + pr_debug("gator: sent mali_control enabled=%d, rate=%d, resize_factor=%d\n", enabled, rate, resize_factor); + + symbol_put(_mali_profiling_control); + } else { + printk("gator: mali online _mali_profiling_control symbol not found\n"); + } + /* * Set the first timestamp for calculating the sample interval. The first interval could be quite long, * since it will be the time between 'start' and the first 'read'. @@ -382,6 +418,8 @@ static int start(void) static void stop(void) { + mali_profiling_control_type *mali_control; + pr_debug("gator: Mali-T6xx: stop\n"); /* @@ -402,6 +440,18 @@ static void stop(void) GATOR_UNREGISTER_TRACE(mali_total_alloc_pages_change); pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint deactivated\n"); + + /* Generic control interface for Mali DDK. */ + mali_control = symbol_get(_mali_profiling_control); + if (mali_control) { + pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control); + + mali_control(FBDUMP_CONTROL_ENABLE, 0); + + symbol_put(_mali_profiling_control); + } else { + printk("gator: mali offline _mali_profiling_control symbol not found\n"); + } } static int read(int **buffer) @@ -508,5 +558,3 @@ extern int gator_events_mali_t6xx_init(void) return gator_events_install(&gator_events_mali_t6xx_interface); } - -gator_events_init(gator_events_mali_t6xx_init); diff --git a/drivers/gator/gator_events_mali_t6xx_hw.c b/drivers/gator/gator_events_mali_t6xx_hw.c index f557350eb9bc..e406991398d9 100644 --- a/drivers/gator/gator_events_mali_t6xx_hw.c +++ b/drivers/gator/gator_events_mali_t6xx_hw.c @@ -63,6 +63,8 @@ static kbase_instr_hwcnt_disable_type *kbase_instr_hwcnt_disable_symbol; static kbase_va_free_type *kbase_va_free_symbol; static kbase_destroy_context_type *kbase_destroy_context_symbol; +static long shader_present_low = 0; + /** The interval between reads, in ns. * * Earlier we introduced @@ -496,6 +498,7 @@ static int start(void) mali_error err; int cnt; u16 bitmask[] = { 0, 0, 0, 0 }; + unsigned long long shadersPresent = 0; /* Setup HW counters */ num_hardware_counters_enabled = 0; @@ -539,6 +542,11 @@ static int start(void) goto out; } + + /* See if we can get the number of shader cores */ + shadersPresent = kbdevice->shader_present_bitmap; + shader_present_low = (unsigned long)shadersPresent; + /* * The amount of memory needed to store the dump (bytes) * DUMP_SIZE = number of core groups @@ -679,21 +687,41 @@ static int read(int **buffer) kbase_device_busy = false; if (success == MALI_TRUE) { + /* Cycle through hardware counters and accumulate totals */ for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++) { const mali_counter *counter = &counters[cnt]; if (counter->enabled) { const int block = GET_HW_BLOCK(cnt); const int counter_offset = GET_COUNTER_OFFSET(cnt); - const u32 *counter_block = (u32 *) ((uintptr_t)kernel_dump_buffer + vithar_blocks[block]); - const u32 *counter_address = counter_block + counter_offset; - value = *counter_address; + const char* block_base_address = (char*)kernel_dump_buffer + vithar_blocks[block]; + /* If counter belongs to shader block need to take into account all cores */ if (block == SHADER_BLOCK) { - /* (counter_address + 0x000) has already been accounted-for above. */ - value += *(counter_address + 0x100); - value += *(counter_address + 0x200); - value += *(counter_address + 0x300); + int i = 0; + int shader_core_count = 0; + value = 0; + + for (i = 0; i < 4; i++) { + if ((shader_present_low >> i) & 1) { + value += *((u32*) (block_base_address + (0x100 * i)) + counter_offset); + shader_core_count++; + } + } + + for (i = 0; i < 4; i++) { + if((shader_present_low >> (i+4)) & 1) { + value += *((u32*)(block_base_address + (0x100 * i) + 0x800) + counter_offset); + shader_core_count++; + } + } + + /* Need to total by number of cores to produce an average */ + if (shader_core_count != 0) { + value /= shader_core_count; + } + } else { + value = *((u32*)block_base_address + counter_offset); } counter_dump[len++] = counter->key; @@ -727,7 +755,7 @@ static int create_files(struct super_block *sb, struct dentry *root) const char *mali_name = gator_mali_get_mali_name(); for (event = 0; event < NUMBER_OF_HARDWARE_COUNTERS; event++) { - if (gator_mali_create_file_system(mali_name, hardware_counter_names[counter_index], sb, root, &counters[event]) != 0) + if (gator_mali_create_file_system(mali_name, hardware_counter_names[counter_index], sb, root, &counters[event], NULL) != 0) return -1; counter_index++; } @@ -754,5 +782,3 @@ int gator_events_mali_t6xx_hw_init(void) return gator_events_install(&gator_events_mali_t6xx_interface); } - -gator_events_init(gator_events_mali_t6xx_hw_init); diff --git a/drivers/gator/gator_events_meminfo.c b/drivers/gator/gator_events_meminfo.c index c1e360d12895..451290d9af17 100644 --- a/drivers/gator/gator_events_meminfo.c +++ b/drivers/gator/gator_events_meminfo.c @@ -8,27 +8,62 @@ */ #include "gator.h" + +#include +#include +#include +#include #include #include -#include -#define MEMINFO_MEMFREE 0 -#define MEMINFO_MEMUSED 1 -#define MEMINFO_BUFFERRAM 2 -#define MEMINFO_TOTAL 3 +enum { + MEMINFO_MEMFREE, + MEMINFO_MEMUSED, + MEMINFO_BUFFERRAM, + MEMINFO_TOTAL, +}; + +enum { + PROC_SIZE, + PROC_SHARE, + PROC_TEXT, + PROC_DATA, + PROC_COUNT, +}; + +static const char * const meminfo_names[] = { + "Linux_meminfo_memfree", + "Linux_meminfo_memused", + "Linux_meminfo_bufferram", +}; + +static const char * const proc_names[] = { + "Linux_proc_statm_size", + "Linux_proc_statm_share", + "Linux_proc_statm_text", + "Linux_proc_statm_data", +}; -static ulong meminfo_global_enabled; +static bool meminfo_global_enabled; static ulong meminfo_enabled[MEMINFO_TOTAL]; -static ulong meminfo_key[MEMINFO_TOTAL]; -static unsigned long long meminfo_buffer[MEMINFO_TOTAL * 2]; +static ulong meminfo_keys[MEMINFO_TOTAL]; +static long long meminfo_buffer[2 * (MEMINFO_TOTAL + 2)]; static int meminfo_length = 0; -static unsigned int mem_event = 0; static bool new_data_avail; -static void wq_sched_handler(struct work_struct *wsptr); -DECLARE_WORK(work, wq_sched_handler); -static struct timer_list meminfo_wake_up_timer; -static void meminfo_wake_up_handler(unsigned long unused_data); +static bool proc_global_enabled; +static ulong proc_enabled[PROC_COUNT]; +static ulong proc_keys[PROC_COUNT]; +static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]); + +static int gator_meminfo_func(void *data); +static bool gator_meminfo_run; +// Initialize semaphore unlocked to initialize memory values +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) +static DECLARE_MUTEX(gator_meminfo_sem); +#else +static DEFINE_SEMAPHORE(gator_meminfo_sem); +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order)) @@ -36,7 +71,7 @@ GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order)) #endif { - mem_event++; + up(&gator_meminfo_sem); } #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) @@ -45,12 +80,12 @@ GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold)) GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold)) #endif { - mem_event++; + up(&gator_meminfo_sem); } GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype)) { - mem_event++; + up(&gator_meminfo_sem); } static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root) @@ -59,24 +94,21 @@ static int gator_events_meminfo_create_files(struct super_block *sb, struct dent int i; for (i = 0; i < MEMINFO_TOTAL; i++) { - switch (i) { - case MEMINFO_MEMFREE: - dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memfree"); - break; - case MEMINFO_MEMUSED: - dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memused"); - break; - case MEMINFO_BUFFERRAM: - dir = gatorfs_mkdir(sb, root, "Linux_meminfo_bufferram"); - break; - default: + dir = gatorfs_mkdir(sb, root, meminfo_names[i]); + if (!dir) { return -1; } + gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]); + gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_keys[i]); + } + + for (i = 0; i < PROC_COUNT; ++i) { + dir = gatorfs_mkdir(sb, root, proc_names[i]); if (!dir) { return -1; } - gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]); - gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_key[i]); + gatorfs_create_ulong(sb, dir, "enabled", &proc_enabled[i]); + gatorfs_create_ro_ulong(sb, dir, "key", &proc_keys[i]); } return 0; @@ -86,13 +118,26 @@ static int gator_events_meminfo_start(void) { int i; - new_data_avail = true; + new_data_avail = false; + meminfo_global_enabled = 0; for (i = 0; i < MEMINFO_TOTAL; i++) { if (meminfo_enabled[i]) { meminfo_global_enabled = 1; + break; } } + proc_global_enabled = 0; + for (i = 0; i < PROC_COUNT; ++i) { + if (proc_enabled[i]) { + proc_global_enabled = 1; + break; + } + } + if (meminfo_enabled[MEMINFO_MEMUSED]) { + proc_global_enabled = 1; + } + if (meminfo_global_enabled == 0) return 0; @@ -111,9 +156,16 @@ static int gator_events_meminfo_start(void) if (GATOR_REGISTER_TRACE(mm_page_alloc)) goto mm_page_alloc_exit; - setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0); + // Start worker thread + gator_meminfo_run = true; + // Since the mutex starts unlocked, memory values will be initialized + if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo"))) + goto kthread_run_exit; + return 0; +kthread_run_exit: + GATOR_UNREGISTER_TRACE(mm_page_alloc); mm_page_alloc_exit: #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) GATOR_UNREGISTER_TRACE(mm_pagevec_free); @@ -132,8 +184,6 @@ mm_page_free_exit: static void gator_events_meminfo_stop(void) { - int i; - if (meminfo_global_enabled) { #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) GATOR_UNREGISTER_TRACE(mm_page_free_direct); @@ -144,68 +194,75 @@ static void gator_events_meminfo_stop(void) #endif GATOR_UNREGISTER_TRACE(mm_page_alloc); - del_timer_sync(&meminfo_wake_up_timer); - } - - meminfo_global_enabled = 0; - for (i = 0; i < MEMINFO_TOTAL; i++) { - meminfo_enabled[i] = 0; + // Stop worker thread + gator_meminfo_run = false; + up(&gator_meminfo_sem); } } // Must be run in process context as the kernel function si_meminfo() can sleep -static void wq_sched_handler(struct work_struct *wsptr) +static int gator_meminfo_func(void *data) { struct sysinfo info; int i, len; unsigned long long value; - meminfo_length = len = 0; + for (;;) { + if (down_killable(&gator_meminfo_sem)) { + break; + } - si_meminfo(&info); - for (i = 0; i < MEMINFO_TOTAL; i++) { - if (meminfo_enabled[i]) { - switch (i) { - case MEMINFO_MEMFREE: - value = info.freeram * PAGE_SIZE; - break; - case MEMINFO_MEMUSED: - value = (info.totalram - info.freeram) * PAGE_SIZE; - break; - case MEMINFO_BUFFERRAM: - value = info.bufferram * PAGE_SIZE; - break; - default: - value = 0; - break; + // Eat up any pending events + while (!down_trylock(&gator_meminfo_sem)); + + if (!gator_meminfo_run) { + break; + } + + meminfo_length = len = 0; + + si_meminfo(&info); + for (i = 0; i < MEMINFO_TOTAL; i++) { + if (meminfo_enabled[i]) { + switch (i) { + case MEMINFO_MEMFREE: + value = info.freeram * PAGE_SIZE; + break; + case MEMINFO_MEMUSED: + // pid -1 means system wide + meminfo_buffer[len++] = 1; + meminfo_buffer[len++] = -1; + // Emit value + meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED]; + meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE; + // Clear pid + meminfo_buffer[len++] = 1; + meminfo_buffer[len++] = 0; + continue; + case MEMINFO_BUFFERRAM: + value = info.bufferram * PAGE_SIZE; + break; + default: + value = 0; + break; + } + meminfo_buffer[len++] = meminfo_keys[i]; + meminfo_buffer[len++] = value; } - meminfo_buffer[len++] = (unsigned long long)meminfo_key[i]; - meminfo_buffer[len++] = value; } - } - meminfo_length = len; - new_data_avail = true; -} + meminfo_length = len; + new_data_avail = true; + } -static void meminfo_wake_up_handler(unsigned long unused_data) -{ - // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater - schedule_work(&work); + return 0; } static int gator_events_meminfo_read(long long **buffer) { - static unsigned int last_mem_event = 0; - if (!on_primary_core() || !meminfo_global_enabled) return 0; - if (last_mem_event != mem_event) { - last_mem_event = mem_event; - mod_timer(&meminfo_wake_up_timer, jiffies + 1); - } - if (!new_data_avail) return 0; @@ -217,11 +274,97 @@ static int gator_events_meminfo_read(long long **buffer) return meminfo_length; } +static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct *task) +{ + struct mm_struct *mm; + u64 share = 0; + int i; + long long value; + int len = 0; + int cpu = get_physical_cpu(); + long long *buf = per_cpu(proc_buffer, cpu); + + if (!proc_global_enabled) { + return 0; + } + + // Collect the memory stats of the process instead of the thread + if (task->group_leader != NULL) { + task = task->group_leader; + } + + // get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch + mm = task->mm; + if (mm == NULL) { + return 0; + } + + // Derived from task_statm in fs/proc/task_mmu.c + if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) { + share = get_mm_counter(mm, +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) + file_rss +#else + MM_FILEPAGES +#endif + ); + } + + // key of 1 indicates a pid + buf[len++] = 1; + buf[len++] = task->pid; + + for (i = 0; i < PROC_COUNT; ++i) { + if (proc_enabled[i]) { + switch (i) { + case PROC_SIZE: + value = mm->total_vm; + break; + case PROC_SHARE: + value = share; + break; + case PROC_TEXT: + value = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> PAGE_SHIFT; + break; + case PROC_DATA: + value = mm->total_vm - mm->shared_vm; + break; + } + + buf[len++] = proc_keys[i]; + buf[len++] = value * PAGE_SIZE; + } + } + + if (meminfo_enabled[MEMINFO_MEMUSED]) { + value = share + get_mm_counter(mm, +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) + anon_rss +#else + MM_ANONPAGES +#endif + ); + // Send resident for this pid + buf[len++] = meminfo_keys[MEMINFO_MEMUSED]; + buf[len++] = value * PAGE_SIZE; + } + + // Clear pid + buf[len++] = 1; + buf[len++] = 0; + + if (buffer) + *buffer = buf; + + return len; +} + static struct gator_interface gator_events_meminfo_interface = { .create_files = gator_events_meminfo_create_files, .start = gator_events_meminfo_start, .stop = gator_events_meminfo_stop, .read64 = gator_events_meminfo_read, + .read_proc = gator_events_meminfo_read_proc, }; int gator_events_meminfo_init(void) @@ -231,10 +374,14 @@ int gator_events_meminfo_init(void) meminfo_global_enabled = 0; for (i = 0; i < MEMINFO_TOTAL; i++) { meminfo_enabled[i] = 0; - meminfo_key[i] = gator_events_get_key(); + meminfo_keys[i] = gator_events_get_key(); + } + + proc_global_enabled = 0; + for (i = 0; i < PROC_COUNT; ++i) { + proc_enabled[i] = 0; + proc_keys[i] = gator_events_get_key(); } return gator_events_install(&gator_events_meminfo_interface); } - -gator_events_init(gator_events_meminfo_init); diff --git a/drivers/gator/gator_events_mmaped.c b/drivers/gator/gator_events_mmaped.c deleted file mode 100644 index f7670f62a258..000000000000 --- a/drivers/gator/gator_events_mmaped.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Example events provider - * - * Copyright (C) ARM Limited 2010-2013. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Similar entries to those below must be present in the events.xml file. - * To add them to the events.xml, create an events-mmap.xml with the - * following contents and rebuild gatord: - * - * - * - * - * - * - * - */ - -#include -#include -#include - -#include "gator.h" - -#define MMAPED_COUNTERS_NUM 3 - -static struct { - unsigned long enabled; - unsigned long event; - unsigned long key; -} mmaped_counters[MMAPED_COUNTERS_NUM]; - -static int mmaped_buffer[MMAPED_COUNTERS_NUM * 2]; - -#ifdef TODO -static void __iomem *mmaped_base; -#endif - -#ifndef TODO -static s64 prev_time; -#endif - -/* Adds mmaped_cntX directories and enabled, event, and key files to /dev/gator/events */ -static int gator_events_mmaped_create_files(struct super_block *sb, - struct dentry *root) -{ - int i; - - for (i = 0; i < MMAPED_COUNTERS_NUM; i++) { - char buf[16]; - struct dentry *dir; - - snprintf(buf, sizeof(buf), "mmaped_cnt%d", i); - dir = gatorfs_mkdir(sb, root, buf); - if (WARN_ON(!dir)) - return -1; - gatorfs_create_ulong(sb, dir, "enabled", - &mmaped_counters[i].enabled); - gatorfs_create_ulong(sb, dir, "event", - &mmaped_counters[i].event); - gatorfs_create_ro_ulong(sb, dir, "key", - &mmaped_counters[i].key); - } - - return 0; -} - -static int gator_events_mmaped_start(void) -{ -#ifdef TODO - for (i = 0; i < MMAPED_COUNTERS_NUM; i++) - writel(mmaped_counters[i].event, - mmaped_base + COUNTERS_CONFIG_OFFSET[i]); - - writel(ENABLED, COUNTERS_CONTROL_OFFSET); -#endif - -#ifndef TODO - struct timespec ts; - getnstimeofday(&ts); - prev_time = timespec_to_ns(&ts); -#endif - - return 0; -} - -static void gator_events_mmaped_stop(void) -{ -#ifdef TODO - writel(DISABLED, COUNTERS_CONTROL_OFFSET); -#endif -} - -#ifndef TODO -/* This function "simulates" counters, generating values of fancy - * functions like sine or triangle... */ -static int mmaped_simulate(int counter, int delta_in_us) -{ - int result = 0; - - switch (counter) { - case 0: /* sort-of-sine */ - { - static int t = 0; - int x; - - t += delta_in_us; - if (t > 2048000) - t = 0; - - if (t % 1024000 < 512000) - x = 512000 - (t % 512000); - else - x = t % 512000; - - result = 32 * x / 512000; - result = result * result; - - if (t < 1024000) - result = 1922 - result; - } - break; - case 1: /* triangle */ - { - static int v, d = 1; - - v = v + d * delta_in_us; - if (v < 0) { - v = 0; - d = 1; - } else if (v > 1000000) { - v = 1000000; - d = -1; - } - - result = v; - } - break; - case 2: /* PWM signal */ - { - static int dc, x, t = 0; - - t += delta_in_us; - if (t > 1000000) - t = 0; - if (x / 1000000 != (x + delta_in_us) / 1000000) - dc = (dc + 100000) % 1000000; - x += delta_in_us; - - result = t < dc ? 0 : 10; - } - break; - } - - return result; -} -#endif - -static int gator_events_mmaped_read(int **buffer) -{ - int i; - int len = 0; -#ifndef TODO - int delta_in_us; - struct timespec ts; - s64 time; -#endif - - /* System wide counters - read from one core only */ - if (!on_primary_core()) - return 0; - -#ifndef TODO - getnstimeofday(&ts); - time = timespec_to_ns(&ts); - delta_in_us = (int)(time - prev_time) / 1000; - prev_time = time; -#endif - - for (i = 0; i < MMAPED_COUNTERS_NUM; i++) { - if (mmaped_counters[i].enabled) { - mmaped_buffer[len++] = mmaped_counters[i].key; -#ifdef TODO - mmaped_buffer[len++] = - readl(mmaped_base + COUNTERS_VALUE_OFFSET[i]); -#else - mmaped_buffer[len++] = - mmaped_simulate(mmaped_counters[i].event, - delta_in_us); -#endif - } - } - - if (buffer) - *buffer = mmaped_buffer; - - return len; -} - -static struct gator_interface gator_events_mmaped_interface = { - .create_files = gator_events_mmaped_create_files, - .start = gator_events_mmaped_start, - .stop = gator_events_mmaped_stop, - .read = gator_events_mmaped_read, -}; - -/* Must not be static! */ -int __init gator_events_mmaped_init(void) -{ - int i; - -#ifdef TODO - mmaped_base = ioremap(COUNTERS_PHYS_ADDR, SZ_4K); - if (!mmaped_base) - return -ENOMEM; -#endif - - for (i = 0; i < MMAPED_COUNTERS_NUM; i++) { - mmaped_counters[i].enabled = 0; - mmaped_counters[i].key = gator_events_get_key(); - } - - return gator_events_install(&gator_events_mmaped_interface); -} - -gator_events_init(gator_events_mmaped_init); diff --git a/drivers/gator/gator_events_mmapped.c b/drivers/gator/gator_events_mmapped.c new file mode 100644 index 000000000000..f055e48d317a --- /dev/null +++ b/drivers/gator/gator_events_mmapped.c @@ -0,0 +1,209 @@ +/* + * Example events provider + * + * Copyright (C) ARM Limited 2010-2013. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Similar entries to those below must be present in the events.xml file. + * To add them to the events.xml, create an events-mmap.xml with the + * following contents and rebuild gatord: + * + * + * + * + * + * + * + * + * When adding custom events, be sure do the following + * - add any needed .c files to the gator driver Makefile + * - call gator_events_install in the events init function + * - add the init function to GATOR_EVENTS_LIST in gator_main.c + * - add a new events-*.xml file to the gator daemon and rebuild + */ + +#include +#include +#include + +#include "gator.h" + +#define MMAPPED_COUNTERS_NUM 3 + +static int mmapped_global_enabled; + +static struct { + unsigned long enabled; + unsigned long event; + unsigned long key; +} mmapped_counters[MMAPPED_COUNTERS_NUM]; + +static int mmapped_buffer[MMAPPED_COUNTERS_NUM * 2]; + +static s64 prev_time; + +/* Adds mmapped_cntX directories and enabled, event, and key files to /dev/gator/events */ +static int gator_events_mmapped_create_files(struct super_block *sb, + struct dentry *root) +{ + int i; + + for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { + char buf[16]; + struct dentry *dir; + + snprintf(buf, sizeof(buf), "mmapped_cnt%d", i); + dir = gatorfs_mkdir(sb, root, buf); + if (WARN_ON(!dir)) + return -1; + gatorfs_create_ulong(sb, dir, "enabled", + &mmapped_counters[i].enabled); + gatorfs_create_ulong(sb, dir, "event", + &mmapped_counters[i].event); + gatorfs_create_ro_ulong(sb, dir, "key", + &mmapped_counters[i].key); + } + + return 0; +} + +static int gator_events_mmapped_start(void) +{ + int i; + struct timespec ts; + + getnstimeofday(&ts); + prev_time = timespec_to_ns(&ts); + + mmapped_global_enabled = 0; + for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { + if (mmapped_counters[i].enabled) { + mmapped_global_enabled = 1; + break; + } + } + + return 0; +} + +static void gator_events_mmapped_stop(void) +{ +} + +/* This function "simulates" counters, generating values of fancy + * functions like sine or triangle... */ +static int mmapped_simulate(int counter, int delta_in_us) +{ + int result = 0; + + switch (counter) { + case 0: /* sort-of-sine */ + { + static int t = 0; + int x; + + t += delta_in_us; + if (t > 2048000) + t = 0; + + if (t % 1024000 < 512000) + x = 512000 - (t % 512000); + else + x = t % 512000; + + result = 32 * x / 512000; + result = result * result; + + if (t < 1024000) + result = 1922 - result; + } + break; + case 1: /* triangle */ + { + static int v, d = 1; + + v = v + d * delta_in_us; + if (v < 0) { + v = 0; + d = 1; + } else if (v > 1000000) { + v = 1000000; + d = -1; + } + + result = v; + } + break; + case 2: /* PWM signal */ + { + static int dc, x, t = 0; + + t += delta_in_us; + if (t > 1000000) + t = 0; + if (x / 1000000 != (x + delta_in_us) / 1000000) + dc = (dc + 100000) % 1000000; + x += delta_in_us; + + result = t < dc ? 0 : 10; + } + break; + } + + return result; +} + +static int gator_events_mmapped_read(int **buffer) +{ + int i; + int len = 0; + int delta_in_us; + struct timespec ts; + s64 time; + + /* System wide counters - read from one core only */ + if (!on_primary_core() || !mmapped_global_enabled) + return 0; + + getnstimeofday(&ts); + time = timespec_to_ns(&ts); + delta_in_us = (int)(time - prev_time) / 1000; + prev_time = time; + + for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { + if (mmapped_counters[i].enabled) { + mmapped_buffer[len++] = mmapped_counters[i].key; + mmapped_buffer[len++] = + mmapped_simulate(mmapped_counters[i].event, + delta_in_us); + } + } + + if (buffer) + *buffer = mmapped_buffer; + + return len; +} + +static struct gator_interface gator_events_mmapped_interface = { + .create_files = gator_events_mmapped_create_files, + .start = gator_events_mmapped_start, + .stop = gator_events_mmapped_stop, + .read = gator_events_mmapped_read, +}; + +/* Must not be static! */ +int __init gator_events_mmapped_init(void) +{ + int i; + + for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { + mmapped_counters[i].enabled = 0; + mmapped_counters[i].key = gator_events_get_key(); + } + + return gator_events_install(&gator_events_mmapped_interface); +} diff --git a/drivers/gator/gator_events_net.c b/drivers/gator/gator_events_net.c index 80cdee41ae3d..9c8d3a43eaeb 100644 --- a/drivers/gator/gator_events_net.c +++ b/drivers/gator/gator_events_net.c @@ -73,6 +73,8 @@ static void calculate_delta(int *rx, int *tx) static int gator_events_net_create_files(struct super_block *sb, struct dentry *root) { + // Network counters are not currently supported in RT-Preempt full because mod_timer is used +#ifndef CONFIG_PREEMPT_RT_FULL struct dentry *dir; dir = gatorfs_mkdir(sb, root, "Linux_net_rx"); @@ -88,6 +90,7 @@ static int gator_events_net_create_files(struct super_block *sb, struct dentry * } gatorfs_create_ulong(sb, dir, "enabled", &nettx_enabled); gatorfs_create_ro_ulong(sb, dir, "key", &nettx_key); +#endif return 0; } @@ -167,5 +170,3 @@ int gator_events_net_init(void) return gator_events_install(&gator_events_net_interface); } - -gator_events_init(gator_events_net_init); diff --git a/drivers/gator/gator_events_perf_pmu.c b/drivers/gator/gator_events_perf_pmu.c index 53b2d0a5afbf..d472df918ab0 100644 --- a/drivers/gator/gator_events_perf_pmu.c +++ b/drivers/gator/gator_events_perf_pmu.c @@ -6,13 +6,18 @@ * published by the Free Software Foundation. */ -#include -#include #include "gator.h" // gator_events_armvX.c is used for Linux 2.6.x #if GATOR_PERF_PMU_SUPPORT +#include +#ifdef CONFIG_OF +#include +#endif +#include +#include + extern bool event_based_sampling; // Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE @@ -22,6 +27,9 @@ extern bool event_based_sampling; // + 1 for the cci-400 cycles counter #define UCCNT (CCI_400 + 1) +// Default to 0 if unable to probe the revision which was the previous behavior +#define DEFAULT_CCI_REVISION 0 + // A gator_attr is needed for every counter struct gator_attr { // Set once in gator_events_perf_pmu_*_init - the name of the event in the gatorfs @@ -404,17 +412,81 @@ static void __attr_init(struct gator_attr *const attr) attr->key = gator_events_get_key(); } +#ifdef CONFIG_OF + +static const struct of_device_id arm_cci_matches[] = { + {.compatible = "arm,cci-400" }, + {}, +}; + +static int probe_cci_revision(void) +{ + struct device_node *np; + struct resource res; + void __iomem *cci_ctrl_base; + int rev; + int ret = DEFAULT_CCI_REVISION; + + np = of_find_matching_node(NULL, arm_cci_matches); + if (!np) { + return ret; + } + + if (of_address_to_resource(np, 0, &res)) { + goto node_put; + } + + cci_ctrl_base = ioremap(res.start, resource_size(&res)); + + rev = (readl_relaxed(cci_ctrl_base + 0xfe8) >> 4) & 0xf; + + if (rev <= 4) { + ret = 0; + } else if (rev <= 6) { + ret = 1; + } + + iounmap(cci_ctrl_base); + + node_put: + of_node_put(np); + + return ret; +} + +#else + +static int probe_cci_revision(void) +{ + return DEFAULT_CCI_REVISION; +} + +#endif + static void gator_events_perf_pmu_cci_init(const int type) { int cnt; + const char *cci_name; + + switch (probe_cci_revision()) { + case 0: + cci_name = "cci-400"; + break; + case 1: + cci_name = "cci-400-r1"; + break; + default: + pr_debug("gator: unrecognized cci-400 revision\n"); + return; + } - strncpy(uc_attrs[uc_attr_count].name, "cci-400_ccnt", sizeof(uc_attrs[uc_attr_count].name)); + snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", cci_name); uc_attrs[uc_attr_count].type = type; ++uc_attr_count; for (cnt = 0; cnt < CCI_400; ++cnt, ++uc_attr_count) { struct gator_attr *const attr = &uc_attrs[uc_attr_count]; - snprintf(attr->name, sizeof(attr->name), "cci-400_cnt%d", cnt); + snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", cci_name, cnt); attr->type = type; } } @@ -477,7 +549,7 @@ int gator_events_perf_pmu_init(void) } if (pe->pmu != NULL && type == pe->pmu->type) { - if (strcmp("CCI", pe->pmu->name) == 0) { + if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0) { gator_events_perf_pmu_cci_init(type); } else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) { found_cpu = true; @@ -512,5 +584,4 @@ int gator_events_perf_pmu_init(void) return gator_events_install(&gator_events_perf_pmu_interface); } -gator_events_init(gator_events_perf_pmu_init); #endif diff --git a/drivers/gator/gator_events_sched.c b/drivers/gator/gator_events_sched.c index 461a0511143d..29f4e39e261c 100644 --- a/drivers/gator/gator_events_sched.c +++ b/drivers/gator/gator_events_sched.c @@ -111,5 +111,3 @@ int gator_events_sched_init(void) return gator_events_install(&gator_events_sched_interface); } - -gator_events_init(gator_events_sched_init); diff --git a/drivers/gator/gator_events_scorpion.c b/drivers/gator/gator_events_scorpion.c index aaf306a4b4c8..c91db1219d08 100644 --- a/drivers/gator/gator_events_scorpion.c +++ b/drivers/gator/gator_events_scorpion.c @@ -666,11 +666,4 @@ int gator_events_scorpion_init(void) return gator_events_install(&gator_events_scorpion_interface); } -gator_events_init(gator_events_scorpion_init); - -#else -int gator_events_scorpion_init(void) -{ - return -1; -} #endif diff --git a/drivers/gator/gator_main.c b/drivers/gator/gator_main.c index 7dd70d9eccf9..9773ae24d6f2 100644 --- a/drivers/gator/gator_main.c +++ b/drivers/gator/gator_main.c @@ -8,7 +8,8 @@ */ // This version must match the gator daemon version -static unsigned long gator_protocol_version = 16; +#define PROTOCOL_VERSION 17 +static unsigned long gator_protocol_version = PROTOCOL_VERSION; #include #include @@ -22,16 +23,20 @@ static unsigned long gator_protocol_version = 16; #include #include #include +#include #include #include #include "gator.h" -#include "gator_events.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) #error kernels prior to 2.6.32 are not supported #endif +#if defined(MODULE) && !defined(CONFIG_MODULES) +#error Cannot build a module against a kernel that does not support modules. To resolve, either rebuild the kernel to support modules or build gator as part of the kernel. +#endif + #if !defined(CONFIG_GENERIC_TRACER) && !defined(CONFIG_TRACING) #error gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined #endif @@ -44,7 +49,7 @@ static unsigned long gator_protocol_version = 16; #error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined to support PC sampling #endif -#if defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) #error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems #endif @@ -87,6 +92,7 @@ static unsigned long gator_protocol_version = 16; #define MESSAGE_COOKIE 1 #define MESSAGE_THREAD_NAME 2 #define HRTIMER_CORE_NAME 3 +#define MESSAGE_LINK 4 #define MESSAGE_GPU_START 1 #define MESSAGE_GPU_STOP 2 @@ -136,6 +142,7 @@ static u64 gator_live_rate; static unsigned long gator_started; static u64 gator_monotonic_started; +static u64 gator_hibernate_time; static unsigned long gator_buffer_opened; static unsigned long gator_timer_count; static unsigned long gator_response_type; @@ -147,6 +154,8 @@ bool event_based_sampling; static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait); static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait); static struct timer_list gator_buffer_wake_up_timer; +static bool gator_buffer_wake_stop; +static struct task_struct *gator_buffer_wake_thread; static LIST_HEAD(gator_events); static DEFINE_PER_CPU(u64, last_timestamp); @@ -189,6 +198,34 @@ static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer); // The time after which the buffer should be committed for live display static DEFINE_PER_CPU(u64, gator_buffer_commit_time); +// List of all gator events - new events must be added to this list +#define GATOR_EVENTS_LIST \ + GATOR_EVENT(gator_events_armv6_init) \ + GATOR_EVENT(gator_events_armv7_init) \ + GATOR_EVENT(gator_events_block_init) \ + GATOR_EVENT(gator_events_ccn504_init) \ + GATOR_EVENT(gator_events_irq_init) \ + GATOR_EVENT(gator_events_l2c310_init) \ + GATOR_EVENT(gator_events_mali_init) \ + GATOR_EVENT(gator_events_mali_t6xx_hw_init) \ + GATOR_EVENT(gator_events_mali_t6xx_init) \ + GATOR_EVENT(gator_events_meminfo_init) \ + GATOR_EVENT(gator_events_mmapped_init) \ + GATOR_EVENT(gator_events_net_init) \ + GATOR_EVENT(gator_events_perf_pmu_init) \ + GATOR_EVENT(gator_events_sched_init) \ + GATOR_EVENT(gator_events_scorpion_init) \ + +#define GATOR_EVENT(EVENT_INIT) __weak int EVENT_INIT(void); +GATOR_EVENTS_LIST +#undef GATOR_EVENT + +static int (*gator_events_list[])(void) = { +#define GATOR_EVENT(EVENT_INIT) EVENT_INIT, +GATOR_EVENTS_LIST +#undef GATOR_EVENT +}; + /****************************************************************************** * Application Includes ******************************************************************************/ @@ -392,6 +429,21 @@ static void gator_buffer_wake_up(unsigned long data) wake_up(&gator_buffer_wait); } +static int gator_buffer_wake_func(void *data) +{ + while (!gator_buffer_wake_stop) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (gator_buffer_wake_stop) { + break; + } + + gator_buffer_wake_up(0); + } + + return 0; +} + /****************************************************************************** * Commit interface ******************************************************************************/ @@ -517,7 +569,14 @@ static void gator_commit_buffer(int cpu, int buftype, u64 time) marshal_frame(cpu, buftype); // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater - mod_timer(&gator_buffer_wake_up_timer, jiffies + 1); + if (per_cpu(in_scheduler_context, cpu)) { +#ifndef CONFIG_PREEMPT_RT_FULL + // mod_timer can not be used in interrupt context in RT-Preempt full + mod_timer(&gator_buffer_wake_up_timer, jiffies + 1); +#endif + } else { + wake_up_process(gator_buffer_wake_thread); + } } static void buffer_check(int cpu, int buftype, u64 time) @@ -590,8 +649,13 @@ void gator_backtrace_handler(struct pt_regs *const regs) // Collect counters if (!per_cpu(collecting, cpu)) { - collect_counters(time); + collect_counters(time, NULL); } + + // No buffer flushing occurs during sched switch for RT-Preempt full. The block counter frame will be flushed by collect_counters, but the sched buffer needs to be explicitly flushed +#ifdef CONFIG_PREEMPT_RT_FULL + buffer_check(cpu, SCHED_TRACE_BUF, time); +#endif } static int gator_running; @@ -815,6 +879,7 @@ static struct notifier_block __refdata gator_hotcpu_notifier = { static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) { int cpu; + struct timespec ts; switch (event) { case PM_HIBERNATION_PREPARE: @@ -825,9 +890,20 @@ static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void for_each_online_cpu(cpu) { gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false); } + + // Record the wallclock hibernate time + getnstimeofday(&ts); + gator_hibernate_time = timespec_to_ns(&ts) - gator_get_time(); break; case PM_POST_HIBERNATION: case PM_POST_SUSPEND: + // Adjust gator_monotonic_started for the time spent sleeping, as gator_get_time does not account for it + if (gator_hibernate_time > 0) { + getnstimeofday(&ts); + gator_monotonic_started += gator_hibernate_time + gator_get_time() - timespec_to_ns(&ts); + gator_hibernate_time = 0; + } + for_each_online_cpu(cpu) { gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false); } @@ -902,8 +978,10 @@ int gator_events_install(struct gator_interface *interface) int gator_events_get_key(void) { - // key of zero is reserved as a timestamp - static int key = 1; + // key 0 is reserved as a timestamp + // key 1 is reserved as the marker for thread specific counters + // Odd keys are assigned by the driver, even keys by the daemon + static int key = 3; const int ret = key; key += 2; @@ -916,7 +994,7 @@ static int gator_init(void) calc_first_cluster_size(); - // events sources (gator_events.h, generated by gator_events.sh) + // events sources for (i = 0; i < ARRAY_SIZE(gator_events_list); i++) if (gator_events_list[i]) gator_events_list[i](); @@ -941,6 +1019,11 @@ static int gator_start(void) unsigned long cpu, i; struct gator_interface *gi; + gator_buffer_wake_stop = false; + if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) { + goto bwake_failure; + } + if (gator_migrate_start()) goto migrate_failure; @@ -1011,6 +1094,9 @@ cookies_failure: events_failure: gator_migrate_stop(); migrate_failure: + gator_buffer_wake_stop = true; + wake_up_process(gator_buffer_wake_thread); +bwake_failure: return -1; } @@ -1034,6 +1120,9 @@ static void gator_stop(void) gi->stop(); gator_migrate_stop(); + + gator_buffer_wake_stop = true; + wake_up_process(gator_buffer_wake_thread); } /****************************************************************************** @@ -1438,3 +1527,6 @@ module_exit(gator_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("ARM Ltd"); MODULE_DESCRIPTION("Gator system profiler"); +#define STRIFY2(ARG) #ARG +#define STRIFY(ARG) STRIFY2(ARG) +MODULE_VERSION(STRIFY(PROTOCOL_VERSION)); diff --git a/drivers/gator/gator_marshaling.c b/drivers/gator/gator_marshaling.c index 3282de843f71..af80ff62e712 100644 --- a/drivers/gator/gator_marshaling.c +++ b/drivers/gator/gator_marshaling.c @@ -89,6 +89,25 @@ static void marshal_thread_name(int pid, char *name) local_irq_restore(flags); } +static void marshal_link(int cookie, int tgid, int pid) +{ + unsigned long cpu = get_physical_cpu(), flags; + u64 time; + + local_irq_save(flags); + time = gator_get_time(); + if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { + gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_LINK); + gator_buffer_write_packed_int64(cpu, NAME_BUF, time); + gator_buffer_write_packed_int(cpu, NAME_BUF, cookie); + gator_buffer_write_packed_int(cpu, NAME_BUF, tgid); + gator_buffer_write_packed_int(cpu, NAME_BUF, pid); + } + // Check and commit; commit is set to occur once buffer is 3/4 full + buffer_check(cpu, NAME_BUF, time); + local_irq_restore(flags); +} + static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inKernel, u64 time) { int cpu = get_physical_cpu(); diff --git a/drivers/gator/gator_trace_gpu.c b/drivers/gator/gator_trace_gpu.c index 12623c4036ee..be135b4aac56 100644 --- a/drivers/gator/gator_trace_gpu.c +++ b/drivers/gator/gator_trace_gpu.c @@ -85,7 +85,7 @@ static void mali_gpu_stop(int unit, int core) int count; int last_tgid = 0; int last_pid = 0; - int last_job_id = 0; + //int last_job_id = 0; spin_lock(&mali_gpu_jobs_lock); if (mali_gpu_jobs[unit][core].count == 0) { @@ -97,7 +97,7 @@ static void mali_gpu_stop(int unit, int core) if (count) { last_tgid = mali_gpu_jobs[unit][core].last_tgid; last_pid = mali_gpu_jobs[unit][core].last_pid; - last_job_id = mali_gpu_jobs[unit][core].last_job_id; + //last_job_id = mali_gpu_jobs[unit][core].last_job_id; } spin_unlock(&mali_gpu_jobs_lock); @@ -242,7 +242,7 @@ int gator_trace_gpu_start(void) * Absence of gpu trace points is not an error */ - memset(&mali_gpu_jobs, sizeof(mali_gpu_jobs), 0); + memset(&mali_gpu_jobs, 0, sizeof(mali_gpu_jobs)); gpu_trace_registered = mali_timeline_trace_registered = mali_job_slots_trace_registered = 0; #if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx) diff --git a/drivers/gator/gator_trace_sched.c b/drivers/gator/gator_trace_sched.c index e98815e25b9c..332b3f6ba965 100644 --- a/drivers/gator/gator_trace_sched.c +++ b/drivers/gator/gator_trace_sched.c @@ -22,6 +22,7 @@ enum { static DEFINE_PER_CPU(uint64_t *, taskname_keys); static DEFINE_PER_CPU(int, collecting); +static DEFINE_PER_CPU(bool, in_scheduler_context); // this array is never read as the cpu wait charts are derived counters // the files are needed, nonetheless, to show that these counters are available @@ -89,7 +90,7 @@ void emit_pid_name(struct task_struct *task) } } -static void collect_counters(u64 time) +static void collect_counters(u64 time, struct task_struct *task) { int *buffer, len, cpu = get_physical_cpu(); long long *buffer64; @@ -104,17 +105,26 @@ static void collect_counters(u64 time) len = gi->read64(&buffer64); marshal_event64(len, buffer64); } + if (gi->read_proc && task != NULL) { + len = gi->read_proc(&buffer64, task); + marshal_event64(len, buffer64); + } } // Only check after writing all counters so that time and corresponding counters appear in the same frame buffer_check(cpu, BLOCK_COUNTER_BUF, time); // Commit buffers on timeout if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) { - static const int buftypes[] = { COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF }; + static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF }; + unsigned long flags; int i; + + local_irq_save(flags); for (i = 0; i < ARRAY_SIZE(buftypes); ++i) { gator_commit_buffer(cpu, buftypes[i], time); } + local_irq_restore(flags); + // Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full if (on_primary_core() && spin_trylock(&annotate_lock)) { gator_commit_buffer(0, ANNOTATE_BUF, time); @@ -151,6 +161,8 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_ int state; int cpu = get_physical_cpu(); + per_cpu(in_scheduler_context, cpu) = true; + // do as much work as possible before disabling interrupts cookie = get_exec_cookie(cpu, next); emit_pid_name(next); @@ -163,10 +175,12 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_ } per_cpu(collecting, cpu) = 1; - collect_counters(gator_get_time()); + collect_counters(gator_get_time(), prev); per_cpu(collecting, cpu) = 0; marshal_sched_trace_switch(next->tgid, next->pid, cookie, state); + + per_cpu(in_scheduler_context, cpu) = false; } GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p)) diff --git a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h index 3db454371d59..347a4fe404bc 100644 --- a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h +++ b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h @@ -1,11 +1,10 @@ -/* - * This confidential and proprietary software may be used only as - * authorised by a licensing agreement from ARM Limited - * (C) COPYRIGHT 2013 ARM Limited - * ALL RIGHTS RESERVED - * The entire notice above must be reproduced on all authorised - * copies and copies may only be made to the extent permitted - * by a licensing agreement from ARM Limited. +/** + * Copyright (C) ARM Limited 2013. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * */ #ifndef __MALI_MJOLLNIR_PROFILING_GATOR_API_H__ diff --git a/drivers/gator/mali/mali_utgard_profiling_gator_api.h b/drivers/gator/mali/mali_utgard_profiling_gator_api.h index c02a1a43efff..559647a76d29 100644 --- a/drivers/gator/mali/mali_utgard_profiling_gator_api.h +++ b/drivers/gator/mali/mali_utgard_profiling_gator_api.h @@ -1,11 +1,10 @@ -/* - * This confidential and proprietary software may be used only as - * authorised by a licensing agreement from ARM Limited - * (C) COPYRIGHT 2013 ARM Limited - * ALL RIGHTS RESERVED - * The entire notice above must be reproduced on all authorised - * copies and copies may only be made to the extent permitted - * by a licensing agreement from ARM Limited. +/** + * Copyright (C) ARM Limited 2013. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * */ #ifndef __MALI_UTGARD_PROFILING_GATOR_API_H__ diff --git a/drivers/gator/mali_t6xx.mk b/drivers/gator/mali_t6xx.mk index 2cc64113ea2c..1a98c1c6a73f 100644 --- a/drivers/gator/mali_t6xx.mk +++ b/drivers/gator/mali_t6xx.mk @@ -9,16 +9,17 @@ EXTRA_CFLAGS += -DMALI_USE_UMP=1 \ -DMALI_BACKEND_KERNEL=1 \ -DMALI_NO_MALI=0 -KBASE_DIR = $(DDK_DIR)/kernel/drivers/gpu/arm/t6xx/kbase -OSK_DIR = $(DDK_DIR)/kernel/drivers/gpu/arm/t6xx/kbase/osk -UMP_DIR = $(DDK_DIR)/kernel/include/linux +DDK_DIR ?= . +KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase +OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase/osk +UMP_DIR = $(DDK_DIR)/include/linux # Include directories in the DDK -EXTRA_CFLAGS += -I$(DDK_DIR) \ +EXTRA_CFLAGS += -I$(KBASE_DIR)/ \ -I$(KBASE_DIR)/.. \ -I$(OSK_DIR)/.. \ -I$(UMP_DIR)/.. \ - -I$(DDK_DIR)/kernel/include \ + -I$(DDK_DIR)/include \ -I$(KBASE_DIR)/osk/src/linux/include \ -I$(KBASE_DIR)/platform_dummy \ -I$(KBASE_DIR)/src diff --git a/tools/gator/daemon/Buffer.cpp b/tools/gator/daemon/Buffer.cpp index c7abbf3a1820..090a71553277 100644 --- a/tools/gator/daemon/Buffer.cpp +++ b/tools/gator/daemon/Buffer.cpp @@ -193,6 +193,17 @@ bool Buffer::eventHeader (const uint64_t curr_time) { return retval; } +bool Buffer::eventTid (const int tid) { + bool retval = false; + if (checkSpace(2*MAXSIZE_PACK32)) { + packInt(1); // key of 1 indicates a tid + packInt(tid); + retval = true; + } + + return retval; +} + void Buffer::event (const int32_t key, const int32_t value) { if (checkSpace(2 * MAXSIZE_PACK32)) { packInt(key); diff --git a/tools/gator/daemon/Buffer.h b/tools/gator/daemon/Buffer.h index f820cfd851e3..b3c8d78cf758 100644 --- a/tools/gator/daemon/Buffer.h +++ b/tools/gator/daemon/Buffer.h @@ -32,6 +32,7 @@ public: void frame (); bool eventHeader (uint64_t curr_time); + bool eventTid (int tid); void event (int32_t key, int32_t value); void event64 (int64_t key, int64_t value); @@ -56,6 +57,10 @@ private: char *const buf; uint64_t commitTime; sem_t *const readerSem; + + // Intentionally unimplemented + Buffer(const Buffer &); + Buffer &operator=(const Buffer &); }; #endif // BUFFER_H diff --git a/tools/gator/daemon/Child.cpp b/tools/gator/daemon/Child.cpp index c0540762698f..9ee2ef8afb9d 100644 --- a/tools/gator/daemon/Child.cpp +++ b/tools/gator/daemon/Child.cpp @@ -86,7 +86,7 @@ static void child_handler(int signum) { } } -static void* durationThread(void* pVoid) { +static void *durationThread(void *) { prctl(PR_SET_NAME, (unsigned long)&"gatord-duration", 0, 0, 0); sem_wait(&startProfile); if (gSessionData->mSessionIsActive) { @@ -102,7 +102,7 @@ static void* durationThread(void* pVoid) { return 0; } -static void* stopThread(void* pVoid) { +static void *stopThread(void *) { OlySocket* socket = child->socket; prctl(PR_SET_NAME, (unsigned long)&"gatord-stopper", 0, 0, 0); @@ -139,7 +139,7 @@ static void* stopThread(void* pVoid) { return 0; } -void* countersThread(void* pVoid) { +static void *countersThread(void *) { prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0); gSessionData->hwmon.start(); @@ -192,7 +192,7 @@ void* countersThread(void* pVoid) { return NULL; } -static void* senderThread(void* pVoid) { +static void *senderThread(void *) { int length = 1; char* data; char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0}; @@ -340,7 +340,8 @@ void Child::run() { thread_creation_success = false; } - if (gSessionData->hwmon.countersEnabled()) { + bool startcountersThread = gSessionData->hwmon.countersEnabled(); + if (startcountersThread) { if (pthread_create(&countersThreadID, NULL, countersThread, this)) { thread_creation_success = false; } @@ -378,7 +379,7 @@ void Child::run() { } while (bytesCollected > 0); logg->logMessage("Exit collect data loop"); - if (gSessionData->hwmon.countersEnabled()) { + if (startcountersThread) { pthread_join(countersThreadID, NULL); } diff --git a/tools/gator/daemon/Child.h b/tools/gator/daemon/Child.h index e39d18276407..0330e9d78027 100644 --- a/tools/gator/daemon/Child.h +++ b/tools/gator/daemon/Child.h @@ -26,6 +26,10 @@ private: int mNumConnections; void initialization(); + + // Intentionally unimplemented + Child(const Child &); + Child &operator=(const Child &); }; #endif //__CHILD_H__ diff --git a/tools/gator/daemon/ConfigurationXML.h b/tools/gator/daemon/ConfigurationXML.h index eba7dc4bac46..5650f487b990 100644 --- a/tools/gator/daemon/ConfigurationXML.h +++ b/tools/gator/daemon/ConfigurationXML.h @@ -29,6 +29,10 @@ private: int parse(const char* xmlFile); int configurationsTag(mxml_node_t *node); void configurationTag(mxml_node_t *node); + + // Intentionally unimplemented + ConfigurationXML(const ConfigurationXML &); + ConfigurationXML &operator=(const ConfigurationXML &); }; #endif // COUNTERS_H diff --git a/tools/gator/daemon/Driver.h b/tools/gator/daemon/Driver.h index dd1dc27d1cdb..f3a932f852cb 100644 --- a/tools/gator/daemon/Driver.h +++ b/tools/gator/daemon/Driver.h @@ -29,7 +29,7 @@ public: // Emits available counters virtual void writeCounters(mxml_node_t *root) const = 0; // Emits possible dynamically generated events/counters - virtual void writeEvents(mxml_node_t *root) const {} + virtual void writeEvents(mxml_node_t *) const {} Driver *getNext() const { return next; } @@ -39,6 +39,10 @@ protected: private: static Driver *head; Driver *next; + + // Intentionally unimplemented + Driver(const Driver &); + Driver &operator=(const Driver &); }; #endif // DRIVER_H diff --git a/tools/gator/daemon/Fifo.h b/tools/gator/daemon/Fifo.h index ada42b9fb584..d25cd6882561 100644 --- a/tools/gator/daemon/Fifo.h +++ b/tools/gator/daemon/Fifo.h @@ -39,6 +39,10 @@ private: sem_t* mReaderSem; char* mBuffer; bool mEnd; + + // Intentionally unimplemented + Fifo(const Fifo &); + Fifo &operator=(const Fifo &); }; #endif //__FIFO_H__ diff --git a/tools/gator/daemon/Hwmon.cpp b/tools/gator/daemon/Hwmon.cpp index 07925680c1f6..1d7c0da9cc83 100644 --- a/tools/gator/daemon/Hwmon.cpp +++ b/tools/gator/daemon/Hwmon.cpp @@ -63,6 +63,10 @@ private: double previous_value; sensors_subfeature_type input; + + // Intentionally unimplemented + HwmonCounter(const HwmonCounter &); + HwmonCounter &operator=(const HwmonCounter &); }; HwmonCounter::HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(key), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) { diff --git a/tools/gator/daemon/Hwmon.h b/tools/gator/daemon/Hwmon.h index 35981dc3d9ad..46bb42e898d7 100644 --- a/tools/gator/daemon/Hwmon.h +++ b/tools/gator/daemon/Hwmon.h @@ -34,6 +34,10 @@ private: HwmonCounter *findCounter(const Counter &counter) const; HwmonCounter *counters; + + // Intentionally unimplemented + Hwmon(const Hwmon &); + Hwmon &operator=(const Hwmon &); }; #endif // HWMON_H diff --git a/tools/gator/daemon/OlySocket.cpp b/tools/gator/daemon/OlySocket.cpp index 132510df584a..ab5c3c2c8938 100644 --- a/tools/gator/daemon/OlySocket.cpp +++ b/tools/gator/daemon/OlySocket.cpp @@ -11,6 +11,7 @@ #include #ifdef WIN32 #include +#include #else #include #include @@ -126,11 +127,17 @@ void OlySocket::createSingleServerConnection(int port) { } void OlySocket::createServerSocket(int port) { + int family = AF_INET6; + // Create socket - mFDServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + mFDServer = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); if (mFDServer < 0) { - logg->logError(__FILE__, __LINE__, "Error creating server socket"); - handleException(); + family = AF_INET; + mFDServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (mFDServer < 0) { + logg->logError(__FILE__, __LINE__, "Error creating server socket"); + handleException(); + } } // Enable address reuse, another solution would be to create the server socket once and only close it when the object exits @@ -141,11 +148,11 @@ void OlySocket::createServerSocket(int port) { } // Create sockaddr_in structure, ensuring non-populated fields are zero - struct sockaddr_in sockaddr; - memset((void*)&sockaddr, 0, sizeof(struct sockaddr_in)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(port); - sockaddr.sin_addr.s_addr = INADDR_ANY; + struct sockaddr_in6 sockaddr; + memset((void*)&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = family; + sockaddr.sin6_port = htons(port); + sockaddr.sin6_addr = in6addr_any; // Bind the socket to an address if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { diff --git a/tools/gator/daemon/Sender.h b/tools/gator/daemon/Sender.h index 8f23361a5def..b388f039bad7 100644 --- a/tools/gator/daemon/Sender.h +++ b/tools/gator/daemon/Sender.h @@ -33,6 +33,10 @@ private: FILE* mDataFile; char* mDataFileName; pthread_mutex_t mSendMutex; + + // Intentionally unimplemented + Sender(const Sender &); + Sender &operator=(const Sender &); }; #endif //__SENDER_H__ diff --git a/tools/gator/daemon/SessionData.cpp b/tools/gator/daemon/SessionData.cpp index 4068d4e957f0..cf844075401f 100644 --- a/tools/gator/daemon/SessionData.cpp +++ b/tools/gator/daemon/SessionData.cpp @@ -44,13 +44,13 @@ void SessionData::parseSessionXML(char* xmlString) { SessionXML session(xmlString); session.parse(); - // Set session data values + // 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 = 10000; + mSampleRate = 9973; // 10000 } else if (strcmp(session.parameters.sample_rate, "normal") == 0) { - mSampleRate = 1000; + mSampleRate = 997; // 1000 } else if (strcmp(session.parameters.sample_rate, "low") == 0) { - mSampleRate = 100; + mSampleRate = 97; // 100 } else if (strcmp(session.parameters.sample_rate, "none") == 0) { mSampleRate = 0; } else { @@ -139,7 +139,9 @@ void SessionData::readCpuInfo() { } int getEventKey() { - // Start one after the gator.ko's value of 1 + // key 0 is reserved as a timestamp + // key 1 is reserved as the marker for thread specific counters + // Odd keys are assigned by the driver, even keys by the daemon static int key = 2; const int ret = key; diff --git a/tools/gator/daemon/SessionData.h b/tools/gator/daemon/SessionData.h index e72fa5d7c5ed..c834251527cf 100644 --- a/tools/gator/daemon/SessionData.h +++ b/tools/gator/daemon/SessionData.h @@ -16,7 +16,7 @@ #define MAX_PERFORMANCE_COUNTERS 50 -#define PROTOCOL_VERSION 16 +#define PROTOCOL_VERSION 17 #define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions struct ImageLinkList { @@ -62,6 +62,10 @@ public: private: void readCpuInfo(); + + // Intentionally unimplemented + SessionData(const SessionData &); + SessionData &operator=(const SessionData &); }; extern SessionData* gSessionData; diff --git a/tools/gator/daemon/SessionXML.h b/tools/gator/daemon/SessionXML.h index c7e3798d6950..0fb03bd6627c 100644 --- a/tools/gator/daemon/SessionXML.h +++ b/tools/gator/daemon/SessionXML.h @@ -33,6 +33,10 @@ private: char* mPath; void sessionTag(mxml_node_t *tree, mxml_node_t *node); void sessionImage(mxml_node_t *node); + + // Intentionally unimplemented + SessionXML(const SessionXML &); + SessionXML &operator=(const SessionXML &); }; #endif // SESSION_XML_H diff --git a/tools/gator/daemon/StreamlineSetup.h b/tools/gator/daemon/StreamlineSetup.h index 092d956ec99f..d6d9a6ea2991 100644 --- a/tools/gator/daemon/StreamlineSetup.h +++ b/tools/gator/daemon/StreamlineSetup.h @@ -38,6 +38,10 @@ private: void sendDefaults(); void sendCounters(); void writeConfiguration(char* xml); + + // Intentionally unimplemented + StreamlineSetup(const StreamlineSetup &); + StreamlineSetup &operator=(const StreamlineSetup &); }; #endif //__STREAMLINE_SETUP_H__ diff --git a/tools/gator/daemon/common.mk b/tools/gator/daemon/common.mk index ee2415b8825c..031d16906881 100644 --- a/tools/gator/daemon/common.mk +++ b/tools/gator/daemon/common.mk @@ -6,7 +6,7 @@ # -std=c++0x is the planned new c++ standard # -std=c++98 is the 1998 c++ standard CFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors -CXXFLAGS += -fno-rtti +CXXFLAGS += -fno-rtti -Wextra # -Weffc++ ifeq ($(WERROR),1) CFLAGS += -Werror endif diff --git a/tools/gator/daemon/events-CCI-400.xml b/tools/gator/daemon/events-CCI-400.xml index 86db2087e1f5..4fa77117d2d8 100644 --- a/tools/gator/daemon/events-CCI-400.xml +++ b/tools/gator/daemon/events-CCI-400.xml @@ -17,7 +17,7 @@ - + @@ -45,3 +45,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/gator/daemon/events-Linux.xml b/tools/gator/daemon/events-Linux.xml index 4a30ad6ec4e6..31a90a1d6335 100644 --- a/tools/gator/daemon/events-Linux.xml +++ b/tools/gator/daemon/events-Linux.xml @@ -6,11 +6,11 @@ - - - - - + + + + + diff --git a/tools/gator/daemon/events-Mali-T6xx.xml b/tools/gator/daemon/events-Mali-T6xx.xml index 647e3d5b0fcf..2465238a8bda 100644 --- a/tools/gator/daemon/events-Mali-T6xx.xml +++ b/tools/gator/daemon/events-Mali-T6xx.xml @@ -36,3 +36,13 @@ + + + + + + + diff --git a/tools/gator/daemon/events-Mali-T6xx_hw.xml b/tools/gator/daemon/events-Mali-T6xx_hw.xml index 8cfe7c3084d5..03566cbb06ab 100644 --- a/tools/gator/daemon/events-Mali-T6xx_hw.xml +++ b/tools/gator/daemon/events-Mali-T6xx_hw.xml @@ -60,12 +60,15 @@ - + + + + diff --git a/tools/gator/daemon/main.cpp b/tools/gator/daemon/main.cpp index d1b0913aa78f..bfd36b98766c 100644 --- a/tools/gator/daemon/main.cpp +++ b/tools/gator/daemon/main.cpp @@ -93,7 +93,7 @@ static void handler(int signum) { } // Child exit Signal Handler -static void child_exit(int signum) { +static void child_exit(int) { int status; int pid = wait(&status); if (pid != -1) { @@ -106,13 +106,18 @@ static void child_exit(int signum) { static int udpPort(int port) { int s; - struct sockaddr_in sockaddr; + struct sockaddr_in6 sockaddr; int on; + int family = AF_INET6; - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (s == -1) { - logg->logError(__FILE__, __LINE__, "socket failed"); - handleException(); + family = AF_INET; + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) { + logg->logError(__FILE__, __LINE__, "socket failed"); + handleException(); + } } on = 1; @@ -122,9 +127,9 @@ static int udpPort(int port) { } memset((void*)&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(port); - sockaddr.sin_addr.s_addr = INADDR_ANY; + sockaddr.sin6_family = family; + sockaddr.sin6_port = htons(port); + sockaddr.sin6_addr = in6addr_any; if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { logg->logError(__FILE__, __LINE__, "socket failed"); handleException(); @@ -173,7 +178,7 @@ static void* answerThread(void* pVoid) { for (;;) { char buf[128]; - struct sockaddr_in sockaddr; + struct sockaddr_in6 sockaddr; socklen_t addrlen; int read; addrlen = sizeof(sockaddr); @@ -386,7 +391,7 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) { } // Gator data flow: collector -> collector fifo -> sender -int main(int argc, char** argv, char* envp[]) { +int main(int argc, char** argv) { // Ensure proper signal handling by making gatord the process group leader // e.g. it may not be the group leader when launched as 'sudo gatord' setsid(); -- cgit v1.2.3