summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xREADME_Streamline.txt56
-rw-r--r--daemon/Android.mk15
-rw-r--r--daemon/Buffer.cpp259
-rw-r--r--daemon/Buffer.h99
-rw-r--r--daemon/CapturedXML.cpp11
-rw-r--r--daemon/CapturedXML.h2
-rw-r--r--daemon/Child.cpp174
-rw-r--r--daemon/Child.h4
-rw-r--r--daemon/Collector.h38
-rw-r--r--daemon/Config.h17
-rw-r--r--daemon/ConfigurationXML.cpp16
-rw-r--r--daemon/ConfigurationXML.h2
-rw-r--r--daemon/Counter.h4
-rw-r--r--daemon/Driver.cpp2
-rw-r--r--daemon/Driver.h4
-rw-r--r--daemon/DriverSource.cpp (renamed from daemon/Collector.cpp)225
-rw-r--r--daemon/DriverSource.h52
-rw-r--r--daemon/DynBuf.cpp139
-rw-r--r--daemon/DynBuf.h52
-rw-r--r--daemon/EventsXML.cpp4
-rw-r--r--daemon/EventsXML.h2
-rw-r--r--daemon/ExternalSource.cpp56
-rw-r--r--daemon/ExternalSource.h40
-rw-r--r--daemon/Fifo.cpp2
-rw-r--r--daemon/Fifo.h4
-rw-r--r--daemon/Hwmon.cpp40
-rw-r--r--daemon/Hwmon.h6
-rw-r--r--daemon/KMod.cpp25
-rw-r--r--daemon/KMod.h4
-rw-r--r--daemon/LocalCapture.cpp6
-rw-r--r--daemon/LocalCapture.h2
-rw-r--r--daemon/Logging.cpp6
-rw-r--r--daemon/Logging.h13
-rw-r--r--daemon/Monitor.cpp61
-rw-r--r--daemon/Monitor.h32
-rw-r--r--daemon/OlySocket.cpp101
-rw-r--r--daemon/OlySocket.h43
-rw-r--r--daemon/OlyUtility.cpp2
-rw-r--r--daemon/OlyUtility.h2
-rw-r--r--daemon/PerfBuffer.cpp139
-rw-r--r--daemon/PerfBuffer.h39
-rw-r--r--daemon/PerfDriver.cpp355
-rw-r--r--daemon/PerfDriver.h56
-rw-r--r--daemon/PerfGroup.cpp206
-rw-r--r--daemon/PerfGroup.h55
-rw-r--r--daemon/PerfSource.cpp271
-rw-r--r--daemon/PerfSource.h54
-rw-r--r--daemon/Proc.cpp179
-rw-r--r--daemon/Proc.h17
-rw-r--r--daemon/Sender.cpp29
-rw-r--r--daemon/Sender.h2
-rw-r--r--daemon/SessionData.cpp29
-rw-r--r--daemon/SessionData.h14
-rw-r--r--daemon/SessionXML.cpp12
-rw-r--r--daemon/SessionXML.h8
-rw-r--r--daemon/Source.cpp33
-rw-r--r--daemon/Source.h40
-rw-r--r--daemon/StreamlineSetup.cpp36
-rw-r--r--daemon/StreamlineSetup.h7
-rw-r--r--daemon/UEvent.cpp75
-rw-r--r--daemon/UEvent.h36
-rw-r--r--daemon/UserSpaceSource.cpp97
-rw-r--r--daemon/UserSpaceSource.h38
-rw-r--r--daemon/common.mk4
-rw-r--r--daemon/defaults.xml (renamed from daemon/configuration.xml)51
-rw-r--r--daemon/escape.c2
-rw-r--r--daemon/events-Cortex-A12.xml6
-rw-r--r--daemon/events-Cortex-A15.xml6
-rw-r--r--daemon/events-Cortex-A5.xml6
-rw-r--r--daemon/events-Cortex-A7.xml6
-rw-r--r--daemon/events-Cortex-A8.xml6
-rw-r--r--daemon/events-Cortex-A9.xml6
-rw-r--r--daemon/events-Linux.xml14
-rw-r--r--daemon/events-Mali-4xx.xml2
-rw-r--r--daemon/events-Mali-T6xx.xml16
-rw-r--r--daemon/events-Perf-Hardware.xml12
-rw-r--r--daemon/k/perf_event.3.12.h792
l---------daemon/k/perf_event.h1
-rw-r--r--daemon/main.cpp80
-rw-r--r--driver/Kconfig39
-rw-r--r--driver/gator.h13
-rw-r--r--driver/gator_annotate.c2
-rw-r--r--driver/gator_annotate_kernel.c8
-rw-r--r--driver/gator_backtrace.c48
-rw-r--r--driver/gator_buffer.c168
-rw-r--r--driver/gator_buffer_write.c (renamed from driver/gator_pack.c)24
-rw-r--r--driver/gator_cookies.c8
-rw-r--r--driver/gator_events_armv6.c2
-rw-r--r--driver/gator_events_armv7.c18
-rw-r--r--driver/gator_events_block.c2
-rw-r--r--driver/gator_events_ccn-504.c2
-rw-r--r--driver/gator_events_irq.c2
-rw-r--r--driver/gator_events_l2c-310.c2
-rw-r--r--driver/gator_events_mali_4xx.c2
-rw-r--r--driver/gator_events_mali_4xx.h2
-rw-r--r--driver/gator_events_mali_common.c2
-rw-r--r--driver/gator_events_mali_common.h2
-rw-r--r--driver/gator_events_mali_t6xx.c8
-rw-r--r--driver/gator_events_mali_t6xx_hw.c10
-rw-r--r--driver/gator_events_mali_t6xx_hw_test.c2
-rw-r--r--driver/gator_events_meminfo.c28
-rw-r--r--driver/gator_events_mmapped.c2
-rw-r--r--driver/gator_events_net.c2
-rw-r--r--driver/gator_events_perf_pmu.c2
-rw-r--r--driver/gator_events_sched.c2
-rw-r--r--driver/gator_events_scorpion.c2
-rw-r--r--driver/gator_fs.c47
-rw-r--r--driver/gator_hrtimer_gator.c8
-rw-r--r--driver/gator_hrtimer_perf.c113
-rw-r--r--driver/gator_iks.c2
-rw-r--r--driver/gator_main.c290
-rw-r--r--driver/gator_marshaling.c97
-rw-r--r--driver/gator_trace_gpu.c13
-rw-r--r--driver/gator_trace_gpu.h2
-rw-r--r--driver/gator_trace_power.c6
-rw-r--r--driver/gator_trace_sched.c20
-rw-r--r--driver/mali/mali_mjollnir_profiling_gator_api.h2
-rw-r--r--driver/mali/mali_utgard_profiling_gator_api.h2
-rw-r--r--driver/mali_t6xx.mk9
119 files changed, 4350 insertions, 1124 deletions
diff --git a/README_Streamline.txt b/README_Streamline.txt
index 744c33f..df3f923 100755
--- a/README_Streamline.txt
+++ b/README_Streamline.txt
@@ -2,18 +2,19 @@
2*** Purpose *** 2*** Purpose ***
3 3
4Instructions on setting up ARM Streamline on the target. 4Instructions on setting up ARM Streamline on the target.
5The gator driver and gator daemon are required to run on the ARM linux target in order for ARM Streamline to operate. 5The gator driver and gator daemon are required to run on the ARM Linux target in order for ARM Streamline to operate. A new early access feature allows the gator daemon can run without the gator driver by using userspace APIs with reduced functionality when using Linux 3.12 or later.
6The driver should be built as a module and the daemon must run with root permissions on the target. 6The driver should be built as a module and the daemon must run with root permissions on the target.
7 7
8*** Introduction *** 8*** Introduction ***
9 9
10A linux development environment with cross compiling tools is most likely required, depending on what is already created and provided. 10A Linux development environment with cross compiling tools is most likely required, depending on what is already created and provided.
11-For users, the ideal environment is to be given a BSP with gatord and gator.ko already running on a properly configured kernel. In such a scenario, a development environment is not needed, root permission may or may not be needed (gatord must be executed with root permissions but can be automatically started, see below), and the user can run Streamline and profile the system without any setup. 11-For users, the ideal environment is to be given a BSP with gatord and gator.ko already running on a properly configured kernel. In such a scenario, a development environment is not needed, root permission may or may not be needed (gatord must be executed with root permissions but can be automatically started, see below), and the user can run Streamline and profile the system without any setup.
12-The ideal development environment has the kernel source code available to be rebuilt, usually by cross-compiling on a host machine. This environment allows the greatest flexibility in configuring the kernel and building the gator driver module. 12-The ideal development environment has the kernel source code available to be rebuilt, usually by cross-compiling on a host machine. This environment allows the greatest flexibility in configuring the kernel and building the gator driver module.
13-However, it is possible that a user/developer has a kernel but does not have the source code. In this scenario it may or may not be possible to obtain a valid profile. 13-However, it is possible that a user/developer has a kernel but does not have the source code. In this scenario it may or may not be possible to obtain a valid profile.
14 -First, check if the kernel has the proper configuration options (see below). Profiling cannot occur using a kernel that is not configured properly, a new kernel must be created. See if /proc/config.gz exists on the target. 14 -First, check if the kernel has the proper configuration options (see below). Profiling cannot occur using a kernel that is not configured properly, a new kernel must be created. See if /proc/config.gz exists on the target.
15 -Second, given a properly configured kernel, check if the filesystem contains the kernel source/headers, which can be used to re-create the gator driver. These files may be located in different areas, but common locations are /lib/modules/ and /usr/src. 15 -Second, given a properly configured kernel, check if the filesystem contains the kernel source/headers, which can be used to re-create the gator driver. These files may be located in different areas, but common locations are /lib/modules/ and /usr/src.
16 -If the kernel is not properly configured or sources/headers are not available, the developer is on their own and kernel creation is beyond the scope of this document. Note: It is possible for a module to work when compiled against a similar kernel source code, though this is not guaranteed to work due to differences in kernel structures, exported symbols and incompatible configuration parameters. 16 -If the kernel is not properly configured or sources/headers are not available, the developer is on their own and kernel creation is beyond the scope of this document. Note: It is possible for a module to work when compiled against a similar kernel source code, though this is not guaranteed to work due to differences in kernel structures, exported symbols and incompatible configuration parameters.
17 -If the target is running Linux 3.12 or later the kernel driver is not required and userspace APIs will be used instead.
17 18
18*** Kernel configuration *** 19*** Kernel configuration ***
19 20
@@ -24,7 +25,7 @@ menuconfig options (depending on the kernel version, the location of these confi
24 - [*] Profiling Support (enables CONFIG_PROFILING) 25 - [*] Profiling Support (enables CONFIG_PROFILING)
25- Kernel Features 26- Kernel Features
26 - [*] High Resolution Timer Support (enables CONFIG_HIGH_RES_TIMERS) 27 - [*] High Resolution Timer Support (enables CONFIG_HIGH_RES_TIMERS)
27 - [*] Use local timer interrupts (only required for SMP, enables CONFIG_LOCAL_TIMERS) 28 - [*] Use local timer interrupts (only required for SMP and for version before Linux 3.12, enables CONFIG_LOCAL_TIMERS)
28 - [*] Enable hardware performance counter support for perf events (enables CONFIG_HW_PERF_EVENTS) 29 - [*] Enable hardware performance counter support for perf events (enables CONFIG_HW_PERF_EVENTS)
29- CPU Power Management 30- CPU Power Management
30 - CPU Frequency scaling 31 - CPU Frequency scaling
@@ -46,8 +47,10 @@ CONFIG_DEBUG_INFO (optional, used for analyzing the kernel)
46CONFIG_CPU_FREQ (optional, provides frequency setting of the CPU) 47CONFIG_CPU_FREQ (optional, provides frequency setting of the CPU)
47 48
48These may be verified on a running system using /proc/config.gz (if this file exists) by running 'zcat /proc/config.gz | grep <option>'. For example, confirming that CONFIG_PROFILING is enabled 49These may be verified on a running system using /proc/config.gz (if this file exists) by running 'zcat /proc/config.gz | grep <option>'. For example, confirming that CONFIG_PROFILING is enabled
49 > zcat /proc/config.gz | grep CONFIG_PROFILING 50 > zcat /proc/config.gz | grep CONFIG_PROFILING
50 CONFIG_PROFILING=y 51 CONFIG_PROFILING=y
52
53If a device tree is used it must include the pmu bindings, see Documentation/devicetree/bindings/arm/pmu.txt for details.
51 54
52*** Checking the gator requirements *** 55*** Checking the gator requirements ***
53 56
@@ -64,6 +67,17 @@ for example when using the linaro-toolchain-binaries
64 make -C /home/username/kernel_2.6.32/ M=`pwd` ARCH=arm CROSS_COMPILE=/home/username/gcc-linaro-arm-linux-gnueabihf-4.7-2013.01-20130125_linux/bin/arm-linux-gnueabihf- modules 67 make -C /home/username/kernel_2.6.32/ M=`pwd` ARCH=arm CROSS_COMPILE=/home/username/gcc-linaro-arm-linux-gnueabihf-4.7-2013.01-20130125_linux/bin/arm-linux-gnueabihf- modules
65If successful, a gator.ko module should be generated 68If successful, a gator.ko module should be generated
66 69
70It is also possible to integrate the gator.ko module into the kernel build system
71 cd /path/to/kernel/build/dir
72 cd drivers
73 mkdir gator
74 cp -r /path/to/gator/driver-src/* gator
75Edit Makefile in the kernel drivers folder and add this to the end
76 obj-$(CONFIG_GATOR) += gator/
77Edit Kconfig in the kernel drivers folder and add this before the last endmenu
78 source "drivers/gator/Kconfig"
79You can now select gator when using menuconfig while configuring the kernel and rebuild as directed
80
67*** Building the gator daemon *** 81*** Building the gator daemon ***
68 82
69cd /path/to/gator/daemon-src 83cd /path/to/gator/daemon-src
@@ -78,6 +92,9 @@ For Android targets (install the android ndk, see developer.android.com)
78 ndk-build 92 ndk-build
79 or execute /path/to/ndk/ndk-build if the ndk is not on your path 93 or execute /path/to/ndk/ndk-build if the ndk is not on your path
80 gatord should now be created and located in libs/armeabi 94 gatord should now be created and located in libs/armeabi
95 If you get an error like the following, upgrade to a more recent version of the android ndk
96 jni/PerfGroup.cpp: In function 'int sys_perf_event_open(perf_event_attr*, pid_t, int, int, long unsigned int)':
97 jni/PerfGroup.cpp:36:17: error: '__NR_perf_event_open' was not declared in this scope
81 98
82*** Running gator *** 99*** Running gator ***
83 100
@@ -88,6 +105,7 @@ gator.ko must be located in the same directory as gatord on the target or the lo
88With root privileges, run the daemon 105With root privileges, run the daemon
89 sudo ./gatord & 106 sudo ./gatord &
90Note: gatord requires libstdc++.so.6 which is usually supplied by the Linux distribution on the target. A copy of libstdc++.so.6 is available in the DS-5 Linux example distribution. 107Note: gatord requires libstdc++.so.6 which is usually supplied by the Linux distribution on the target. A copy of libstdc++.so.6 is available in the DS-5 Linux example distribution.
108If gator.ko is not loaded and is not in the same directory as gatord when using Linux 3.12 or later, gatord can run without gator.ko by using userspace APIs. Not all features are supported by userspace gator. If /dev/gator/version does not exist after starting gatord it is running userspace gator.
91 109
92*** Customizing the l2c-310 Counter *** 110*** Customizing the l2c-310 Counter ***
93 111
@@ -96,6 +114,10 @@ The l2c-310 counter in gator_events_l2c-310.c contains hard coded offsets where
96Further, the l2c-310 counter can be disabled by providing an offset of zero, ex: 114Further, the l2c-310 counter can be disabled by providing an offset of zero, ex:
97 insmod gator.ko l2c310_addr=0 115 insmod gator.ko l2c310_addr=0
98 116
117*** CCN-504 ***
118
119CCN-504 is disabled by default. To enable CCN-504, insmod gator module with the ccn504_addr=<addr> parameter where addr is the base address of the CCN-504 configuration register space (PERIPHBASE), ex: insmod gator.ko ccn504_addr=0x2E000000.
120
99*** Compiling an application or shared library *** 121*** Compiling an application or shared library ***
100 122
101Recommended compiler settings: 123Recommended compiler settings:
@@ -113,18 +135,31 @@ Attempting to run an incompatible binary often results in the confusing error me
113*** Bugs *** 135*** Bugs ***
114 136
115There is a bug in some Linux kernels where perf misidentifies the CPU type. To see if you are affected by this, run ls /sys/bus/event_source/devices/ and verify the listed processor type matches what is expected. For example, an A9 should show the following. 137There is a bug in some Linux kernels where perf misidentifies the CPU type. To see if you are affected by this, run ls /sys/bus/event_source/devices/ and verify the listed processor type matches what is expected. For example, an A9 should show the following.
116 138 # ls /sys/bus/event_source/devices/
117# ls /sys/bus/event_source/devices/ 139 ARMv7_Cortex_A9 breakpoint software tracepoint
118ARMv7_Cortex_A9 breakpoint software tracepoint
119
120To work around the issue try upgrading to a later kernel or comment out the gator_events_perf_pmu_cpu_init(gator_cpu, type); call in gator_events_perf_pmu.c 140To work around the issue try upgrading to a later kernel or comment out the gator_events_perf_pmu_cpu_init(gator_cpu, type); call in gator_events_perf_pmu.c
121 141
142There is a bug in some Linux kernels where an Oops may occurs when using userspace gator and a core is offlined. The fix was merged into mainline in 3.14-rc5, see http://git.kernel.org/tip/e3703f8cdfcf39c25c4338c3ad8e68891cca3731, and as been backported to older kernels.
143
144If you see this error when using SELinux, ex: Android 4.4 or later
145 # ./gatord
146 Unable to load (insmod) gator.ko driver:
147 >>> gator.ko must be built against the current kernel version & configuration
148 >>> See dmesg for more details
149 # dmesg
150 ...
151 <7>[ 6745.475110] SELinux: initialized (dev gatorfs, type gatorfs), not configured for labeling
152 <5>[ 6745.477434] type=1400 audit(1393005053.336:10): avc: denied { mount } for pid=1996 comm="gatord-main" name="/" dev="gatorfs" ino=8733 scontext=u:r:shell:s0 tcontext=u:object_r:unlabeled:s0 tclass=filesystem
153disable SELinux so that gatorfs can be mounted by running
154 # setenforce 0
155Once gator is started, SELinux can be reenabled
156
122*** Profiling the kernel (optional) *** 157*** Profiling the kernel (optional) ***
123 158
124CONFIG_DEBUG_INFO must be enabled, see "Kernel configuration" section above. 159CONFIG_DEBUG_INFO must be enabled, see "Kernel configuration" section above.
125Use vmlinux as the image for debug symbols in Streamline. 160Use vmlinux as the image for debug symbols in Streamline.
126Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the driver as an image to Streamline. 161Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the driver as an image to Streamline.
127To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko. 162To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko or run "echo 1 > /sys/module/gator/parameters/kernel_stack_unwinding" as root on the target after gatord is started.
128 163
129*** Automatically start gator on boot (optional) *** 164*** Automatically start gator on boot (optional) ***
130 165
@@ -137,4 +172,3 @@ update-rc.d rungator.sh defaults
137*** GPL License *** 172*** GPL License ***
138 173
139For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz. 174For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz.
140
diff --git a/daemon/Android.mk b/daemon/Android.mk
index a042971..045d028 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -1,7 +1,7 @@
1LOCAL_PATH := $(call my-dir) 1LOCAL_PATH := $(call my-dir)
2include $(CLEAR_VARS) 2include $(CLEAR_VARS)
3 3
4XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h configuration_xml.h) 4XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h)
5 5
6LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -DETCDIR=\"/etc\" -Ilibsensors 6LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -DETCDIR=\"/etc\" -Ilibsensors
7 7
@@ -9,22 +9,33 @@ LOCAL_SRC_FILES := \
9 Buffer.cpp \ 9 Buffer.cpp \
10 CapturedXML.cpp \ 10 CapturedXML.cpp \
11 Child.cpp \ 11 Child.cpp \
12 Collector.cpp \
13 ConfigurationXML.cpp \ 12 ConfigurationXML.cpp \
14 Driver.cpp \ 13 Driver.cpp \
14 DriverSource.cpp \
15 DynBuf.cpp \
15 EventsXML.cpp \ 16 EventsXML.cpp \
17 ExternalSource.cpp \
16 Fifo.cpp \ 18 Fifo.cpp \
17 Hwmon.cpp \ 19 Hwmon.cpp \
18 KMod.cpp \ 20 KMod.cpp \
19 LocalCapture.cpp \ 21 LocalCapture.cpp \
20 Logging.cpp \ 22 Logging.cpp \
21 main.cpp \ 23 main.cpp \
24 Monitor.cpp \
22 OlySocket.cpp \ 25 OlySocket.cpp \
23 OlyUtility.cpp \ 26 OlyUtility.cpp \
27 PerfBuffer.cpp \
28 PerfDriver.cpp \
29 PerfGroup.cpp \
30 PerfSource.cpp \
31 Proc.cpp \
24 Sender.cpp \ 32 Sender.cpp \
25 SessionData.cpp \ 33 SessionData.cpp \
26 SessionXML.cpp \ 34 SessionXML.cpp \
35 Source.cpp \
27 StreamlineSetup.cpp \ 36 StreamlineSetup.cpp \
37 UEvent.cpp \
38 UserSpaceSource.cpp \
28 libsensors/access.c \ 39 libsensors/access.c \
29 libsensors/conf-lex.c \ 40 libsensors/conf-lex.c \
30 libsensors/conf-parse.c \ 41 libsensors/conf-parse.c \
diff --git a/daemon/Buffer.cpp b/daemon/Buffer.cpp
index 090a715..93557da 100644
--- a/daemon/Buffer.cpp
+++ b/daemon/Buffer.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -12,33 +12,60 @@
12#include "Sender.h" 12#include "Sender.h"
13#include "SessionData.h" 13#include "SessionData.h"
14 14
15#define mask (size - 1) 15#define mask (mSize - 1)
16 16
17Buffer::Buffer (const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : core(core), buftype(buftype), size(size), readPos(0), writePos(0), commitPos(0), available(true), done(false), buf(new char[size]), commitTime(gSessionData->mLiveRate), readerSem(readerSem) { 17enum {
18 if ((size & mask) != 0) { 18 CODE_PEA = 1,
19 CODE_KEYS = 2,
20 CODE_FORMAT = 3,
21 CODE_MAPS = 4,
22 CODE_COMM = 5,
23};
24
25// Summary Frame Messages
26enum {
27 MESSAGE_SUMMARY = 1,
28 MESSAGE_CORE_NAME = 3,
29};
30
31// From gator_marshaling.c
32#define NEWLINE_CANARY \
33 /* Unix */ \
34 "1\n" \
35 /* Windows */ \
36 "2\r\n" \
37 /* Mac OS */ \
38 "3\r" \
39 /* RISC OS */ \
40 "4\n\r" \
41 /* Add another character so the length isn't 0x0a bytes */ \
42 "5"
43
44Buffer::Buffer(const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : mCore(core), mBufType(buftype), mSize(size), mReadPos(0), mWritePos(0), mCommitPos(0), mAvailable(true), mIsDone(false), mBuf(new char[mSize]), mCommitTime(gSessionData->mLiveRate), mReaderSem(readerSem) {
45 if ((mSize & mask) != 0) {
19 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2"); 46 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
20 handleException(); 47 handleException();
21 } 48 }
22 frame(); 49 frame();
23} 50}
24 51
25Buffer::~Buffer () { 52Buffer::~Buffer() {
26 delete [] buf; 53 delete [] mBuf;
27} 54}
28 55
29void Buffer::write (Sender * const sender) { 56void Buffer::write(Sender *const sender) {
30 if (!commitReady()) { 57 if (!commitReady()) {
31 return; 58 return;
32 } 59 }
33 60
34 // determine the size of two halves 61 // determine the size of two halves
35 int length1 = commitPos - readPos; 62 int length1 = mCommitPos - mReadPos;
36 char * buffer1 = buf + readPos; 63 char *buffer1 = mBuf + mReadPos;
37 int length2 = 0; 64 int length2 = 0;
38 char * buffer2 = buf; 65 char *buffer2 = mBuf;
39 if (length1 < 0) { 66 if (length1 < 0) {
40 length1 = size - readPos; 67 length1 = mSize - mReadPos;
41 length2 = commitPos; 68 length2 = mCommitPos;
42 } 69 }
43 70
44 logg->logMessage("Sending data length1: %i length2: %i", length1, length2); 71 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
@@ -53,22 +80,22 @@ void Buffer::write (Sender * const sender) {
53 sender->writeData(buffer2, length2, RESPONSE_APC_DATA); 80 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
54 } 81 }
55 82
56 readPos = commitPos; 83 mReadPos = mCommitPos;
57} 84}
58 85
59bool Buffer::commitReady () const { 86bool Buffer::commitReady() const {
60 return commitPos != readPos; 87 return mCommitPos != mReadPos;
61} 88}
62 89
63int Buffer::bytesAvailable () const { 90int Buffer::bytesAvailable() const {
64 int filled = writePos - readPos; 91 int filled = mWritePos - mReadPos;
65 if (filled < 0) { 92 if (filled < 0) {
66 filled += size; 93 filled += mSize;
67 } 94 }
68 95
69 int remaining = size - filled; 96 int remaining = mSize - filled;
70 97
71 if (available) { 98 if (mAvailable) {
72 // Give some extra room; also allows space to insert the overflow error packet 99 // Give some extra room; also allows space to insert the overflow error packet
73 remaining -= 200; 100 remaining -= 200;
74 } else { 101 } else {
@@ -79,58 +106,68 @@ int Buffer::bytesAvailable () const {
79 return remaining; 106 return remaining;
80} 107}
81 108
82bool Buffer::checkSpace (const int bytes) { 109bool Buffer::checkSpace(const int bytes) {
83 const int remaining = bytesAvailable(); 110 const int remaining = bytesAvailable();
84 111
85 if (remaining < bytes) { 112 if (remaining < bytes) {
86 available = false; 113 mAvailable = false;
87 } else { 114 } else {
88 available = true; 115 mAvailable = true;
89 } 116 }
90 117
91 return available; 118 return mAvailable;
119}
120
121int Buffer::contiguousSpaceAvailable() const {
122 int remaining = bytesAvailable();
123 int contiguous = mSize - mWritePos;
124 if (remaining < contiguous) {
125 return remaining;
126 } else {
127 return contiguous;
128 }
92} 129}
93 130
94void Buffer::commit (const uint64_t time) { 131void Buffer::commit(const uint64_t time) {
95 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload 132 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
96 const int typeLength = gSessionData->mLocalCapture ? 0 : 1; 133 const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
97 int length = writePos - commitPos; 134 int length = mWritePos - mCommitPos;
98 if (length < 0) { 135 if (length < 0) {
99 length += size; 136 length += mSize;
100 } 137 }
101 length = length - typeLength - sizeof(int32_t); 138 length = length - typeLength - sizeof(int32_t);
102 for (size_t byte = 0; byte < sizeof(int32_t); byte++) { 139 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
103 buf[(commitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF; 140 mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
104 } 141 }
105 142
106 logg->logMessage("Committing data readPos: %i writePos: %i commitPos: %i", readPos, writePos, commitPos); 143 logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
107 commitPos = writePos; 144 mCommitPos = mWritePos;
108 145
109 if (gSessionData->mLiveRate > 0) { 146 if (gSessionData->mLiveRate > 0) {
110 while (time > commitTime) { 147 while (time > mCommitTime) {
111 commitTime += gSessionData->mLiveRate; 148 mCommitTime += gSessionData->mLiveRate;
112 } 149 }
113 } 150 }
114 151
115 if (!done) { 152 if (!mIsDone) {
116 frame(); 153 frame();
117 } 154 }
118 155
119 // send a notification that data is ready 156 // send a notification that data is ready
120 sem_post(readerSem); 157 sem_post(mReaderSem);
121} 158}
122 159
123void Buffer::check (const uint64_t time) { 160void Buffer::check(const uint64_t time) {
124 int filled = writePos - commitPos; 161 int filled = mWritePos - mCommitPos;
125 if (filled < 0) { 162 if (filled < 0) {
126 filled += size; 163 filled += mSize;
127 } 164 }
128 if (filled >= ((size * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= commitTime)) { 165 if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
129 commit(time); 166 commit(time);
130 } 167 }
131} 168}
132 169
133void Buffer::packInt (int32_t x) { 170void Buffer::packInt(int32_t x) {
134 int packedBytes = 0; 171 int packedBytes = 0;
135 int more = true; 172 int more = true;
136 while (more) { 173 while (more) {
@@ -144,14 +181,14 @@ void Buffer::packInt (int32_t x) {
144 b |= 0x80; 181 b |= 0x80;
145 } 182 }
146 183
147 buf[(writePos + packedBytes) & mask] = b; 184 mBuf[(mWritePos + packedBytes) & mask] = b;
148 packedBytes++; 185 packedBytes++;
149 } 186 }
150 187
151 writePos = (writePos + packedBytes) & mask; 188 mWritePos = (mWritePos + packedBytes) & mask;
152} 189}
153 190
154void Buffer::packInt64 (int64_t x) { 191void Buffer::packInt64(int64_t x) {
155 int packedBytes = 0; 192 int packedBytes = 0;
156 int more = true; 193 int more = true;
157 while (more) { 194 while (more) {
@@ -165,24 +202,61 @@ void Buffer::packInt64 (int64_t x) {
165 b |= 0x80; 202 b |= 0x80;
166 } 203 }
167 204
168 buf[(writePos + packedBytes) & mask] = b; 205 mBuf[(mWritePos + packedBytes) & mask] = b;
169 packedBytes++; 206 packedBytes++;
170 } 207 }
171 208
172 writePos = (writePos + packedBytes) & mask; 209 mWritePos = (mWritePos + packedBytes) & mask;
210}
211
212void Buffer::writeBytes(const void *const data, size_t count) {
213 size_t i;
214 for (i = 0; i < count; ++i) {
215 mBuf[(mWritePos + i) & mask] = static_cast<const char *>(data)[i];
216 }
217
218 mWritePos = (mWritePos + i) & mask;
173} 219}
174 220
175void Buffer::frame () { 221void Buffer::writeString(const char *const str) {
222 const int len = strlen(str);
223 packInt(len);
224 writeBytes(str, len);
225}
226
227void Buffer::frame() {
176 if (!gSessionData->mLocalCapture) { 228 if (!gSessionData->mLocalCapture) {
177 packInt(RESPONSE_APC_DATA); 229 packInt(RESPONSE_APC_DATA);
178 } 230 }
179 // Reserve space for the length 231 // Reserve space for the length
180 writePos += sizeof(int32_t); 232 mWritePos += sizeof(int32_t);
181 packInt(buftype); 233 packInt(mBufType);
182 packInt(core); 234 packInt(mCore);
183} 235}
184 236
185bool Buffer::eventHeader (const uint64_t curr_time) { 237void Buffer::summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
238 packInt(MESSAGE_SUMMARY);
239 writeString(NEWLINE_CANARY);
240 packInt64(timestamp);
241 packInt64(uptime);
242 packInt64(monotonicDelta);
243 writeString("uname");
244 writeString(uname);
245 writeString("");
246 check(1);
247}
248
249void Buffer::coreName(const int core, const int cpuid, const char *const name) {
250 if (checkSpace(3 * MAXSIZE_PACK32 + 0x100)) {
251 packInt(MESSAGE_CORE_NAME);
252 packInt(core);
253 packInt(cpuid);
254 writeString(name);
255 }
256 check(1);
257}
258
259bool Buffer::eventHeader(const uint64_t curr_time) {
186 bool retval = false; 260 bool retval = false;
187 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) { 261 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
188 packInt(0); // key of zero indicates a timestamp 262 packInt(0); // key of zero indicates a timestamp
@@ -193,9 +267,9 @@ bool Buffer::eventHeader (const uint64_t curr_time) {
193 return retval; 267 return retval;
194} 268}
195 269
196bool Buffer::eventTid (const int tid) { 270bool Buffer::eventTid(const int tid) {
197 bool retval = false; 271 bool retval = false;
198 if (checkSpace(2*MAXSIZE_PACK32)) { 272 if (checkSpace(2 * MAXSIZE_PACK32)) {
199 packInt(1); // key of 1 indicates a tid 273 packInt(1); // key of 1 indicates a tid
200 packInt(tid); 274 packInt(tid);
201 retval = true; 275 retval = true;
@@ -204,25 +278,94 @@ bool Buffer::eventTid (const int tid) {
204 return retval; 278 return retval;
205} 279}
206 280
207void Buffer::event (const int32_t key, const int32_t value) { 281void Buffer::event(const int32_t key, const int32_t value) {
208 if (checkSpace(2 * MAXSIZE_PACK32)) { 282 if (checkSpace(2 * MAXSIZE_PACK32)) {
209 packInt(key); 283 packInt(key);
210 packInt(value); 284 packInt(value);
211 } 285 }
212} 286}
213 287
214void Buffer::event64 (const int64_t key, const int64_t value) { 288void Buffer::event64(const int64_t key, const int64_t value) {
215 if (checkSpace(2 * MAXSIZE_PACK64)) { 289 if (checkSpace(2 * MAXSIZE_PACK64)) {
216 packInt64(key); 290 packInt64(key);
217 packInt64(value); 291 packInt64(value);
218 } 292 }
219} 293}
220 294
221void Buffer::setDone () { 295void Buffer::pea(const struct perf_event_attr *const pea, int key) {
222 done = true; 296 if (checkSpace(2 * MAXSIZE_PACK32 + pea->size)) {
297 packInt(CODE_PEA);
298 writeBytes(pea, pea->size);
299 packInt(key);
300 } else {
301 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
302 handleException();
303 }
304 // Don't know the real perf time so use 1 as it will work for now
305 check(1);
306}
307
308void Buffer::keys(const int count, const __u64 *const ids, const int *const keys) {
309 if (checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) {
310 packInt(CODE_KEYS);
311 packInt(count);
312 for (int i = 0; i < count; ++i) {
313 packInt64(ids[i]);
314 packInt(keys[i]);
315 }
316 } else {
317 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
318 handleException();
319 }
320 check(1);
321}
322
323void Buffer::format(const int length, const char *const format) {
324 if (checkSpace(MAXSIZE_PACK32 + length + 1)) {
325 packInt(CODE_FORMAT);
326 writeBytes(format, length + 1);
327 } else {
328 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
329 handleException();
330 }
331 check(1);
332}
333
334void Buffer::maps(const int pid, const int tid, const char *const maps) {
335 const int mapsLen = strlen(maps) + 1;
336 if (checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) {
337 packInt(CODE_MAPS);
338 packInt(pid);
339 packInt(tid);
340 writeBytes(maps, mapsLen);
341 } else {
342 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
343 handleException();
344 }
345 check(1);
346}
347
348void Buffer::comm(const int pid, const int tid, const char *const image, const char *const comm) {
349 const int imageLen = strlen(image) + 1;
350 const int commLen = strlen(comm) + 1;
351 if (checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) {
352 packInt(CODE_COMM);
353 packInt(pid);
354 packInt(tid);
355 writeBytes(image, imageLen);
356 writeBytes(comm, commLen);
357 } else {
358 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
359 handleException();
360 }
361 check(1);
362}
363
364void Buffer::setDone() {
365 mIsDone = true;
223 commit(0); 366 commit(0);
224} 367}
225 368
226bool Buffer::isDone () const { 369bool Buffer::isDone() const {
227 return done && readPos == commitPos && commitPos == writePos; 370 return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;
228} 371}
diff --git a/daemon/Buffer.h b/daemon/Buffer.h
index b3c8d78..5023777 100644
--- a/daemon/Buffer.h
+++ b/daemon/Buffer.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,54 +9,89 @@
9#ifndef BUFFER_H 9#ifndef BUFFER_H
10#define BUFFER_H 10#define BUFFER_H
11 11
12#include <stddef.h>
13#include <stdint.h> 12#include <stdint.h>
14#include <semaphore.h> 13#include <semaphore.h>
15 14
15#include "k/perf_event.h"
16
16class Sender; 17class Sender;
17 18
19enum {
20 FRAME_SUMMARY = 1,
21 FRAME_BLOCK_COUNTER = 5,
22 FRAME_EXTERNAL = 10,
23 FRAME_PERF_ATTRS = 11,
24 FRAME_PERF = 12,
25};
26
18class Buffer { 27class Buffer {
19public: 28public:
20 static const size_t MAXSIZE_PACK32 = 5; 29 static const size_t MAXSIZE_PACK32 = 5;
21 static const size_t MAXSIZE_PACK64 = 10; 30 static const size_t MAXSIZE_PACK64 = 10;
22 31
23 Buffer (int32_t core, int32_t buftype, const int size, sem_t *const readerSem); 32 Buffer(int32_t core, int32_t buftype, const int size, sem_t *const readerSem);
24 ~Buffer (); 33 ~Buffer();
34
35 void write(Sender *sender);
36
37 int bytesAvailable() const;
38 int contiguousSpaceAvailable() const;
39 void commit(const uint64_t time);
40 void check(const uint64_t time);
25 41
26 void write (Sender * sender); 42 void frame();
27 43
28 int bytesAvailable () const; 44 // Summary messages
29 void commit (const uint64_t time); 45 void summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname);
30 void check (const uint64_t time); 46 void coreName(const int core, const int cpuid, const char *const name);
31 47
32 void frame (); 48 // Block Counter messages
49 bool eventHeader(uint64_t curr_time);
50 bool eventTid(int tid);
51 void event(int32_t key, int32_t value);
52 void event64(int64_t key, int64_t value);
33 53
34 bool eventHeader (uint64_t curr_time); 54 // Perf Attrs messages
35 bool eventTid (int tid); 55 void pea(const struct perf_event_attr *const pea, int key);
36 void event (int32_t key, int32_t value); 56 void keys(const int count, const __u64 *const ids, const int *const keys);
37 void event64 (int64_t key, int64_t value); 57 void format(const int length, const char *const format);
58 void maps(const int pid, const int tid, const char *const maps);
59 void comm(const int pid, const int tid, const char *const image, const char *const comm);
38 60
39 void setDone (); 61 void setDone();
40 bool isDone () const; 62 bool isDone() const;
63
64 // Prefer a new member to using these functions if possible
65 char *getWritePos() { return mBuf + mWritePos; }
66 void advanceWrite(int bytes) { mWritePos = (mWritePos + bytes) & /*mask*/(mSize - 1); }
67
68 static void writeLEInt(unsigned char *buf, int v) {
69 buf[0] = (v >> 0) & 0xFF;
70 buf[1] = (v >> 8) & 0xFF;
71 buf[2] = (v >> 16) & 0xFF;
72 buf[3] = (v >> 24) & 0xFF;
73 }
41 74
42private: 75private:
43 bool commitReady () const; 76 bool commitReady() const;
44 bool checkSpace (int bytes); 77 bool checkSpace(int bytes);
45 78
46 void packInt (int32_t x); 79 void packInt(int32_t x);
47 void packInt64 (int64_t x); 80 void packInt64(int64_t x);
48 81 void writeBytes(const void *const data, size_t count);
49 const int32_t core; 82 void writeString(const char *const str);
50 const int32_t buftype; 83
51 const int size; 84 const int32_t mCore;
52 int readPos; 85 const int32_t mBufType;
53 int writePos; 86 const int mSize;
54 int commitPos; 87 int mReadPos;
55 bool available; 88 int mWritePos;
56 bool done; 89 int mCommitPos;
57 char *const buf; 90 bool mAvailable;
58 uint64_t commitTime; 91 bool mIsDone;
59 sem_t *const readerSem; 92 char *const mBuf;
93 uint64_t mCommitTime;
94 sem_t *const mReaderSem;
60 95
61 // Intentionally unimplemented 96 // Intentionally unimplemented
62 Buffer(const Buffer &); 97 Buffer(const Buffer &);
diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp
index 30c4c44..cf79b72 100644
--- a/daemon/CapturedXML.cpp
+++ b/daemon/CapturedXML.cpp
@@ -1,16 +1,18 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "CapturedXML.h"
10
9#include <stdlib.h> 11#include <stdlib.h>
10#include <string.h> 12#include <string.h>
11#include <dirent.h> 13#include <dirent.h>
14
12#include "SessionData.h" 15#include "SessionData.h"
13#include "CapturedXML.h"
14#include "Logging.h" 16#include "Logging.h"
15#include "OlyUtility.h" 17#include "OlyUtility.h"
16 18
@@ -30,6 +32,9 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
30 32
31 captured = mxmlNewElement(xml, "captured"); 33 captured = mxmlNewElement(xml, "captured");
32 mxmlElementSetAttr(captured, "version", "1"); 34 mxmlElementSetAttr(captured, "version", "1");
35 if (gSessionData->perf.isSetup()) {
36 mxmlElementSetAttr(captured, "type", "Perf");
37 }
33 mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION); 38 mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION);
34 if (includeTime) { // Send the following only after the capture is complete 39 if (includeTime) { // Send the following only after the capture is complete
35 if (time(NULL) > 1267000000) { // If the time is reasonable (after Feb 23, 2010) 40 if (time(NULL) > 1267000000) { // If the time is reasonable (after Feb 23, 2010)
@@ -41,7 +46,7 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
41 mxmlElementSetAttr(target, "name", gSessionData->mCoreName); 46 mxmlElementSetAttr(target, "name", gSessionData->mCoreName);
42 mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate); 47 mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate);
43 mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores); 48 mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores);
44 mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mCpuId); 49 mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mMaxCpuId);
45 50
46 if (!gSessionData->mOneShot && (gSessionData->mSampleRate > 0)) { 51 if (!gSessionData->mOneShot && (gSessionData->mSampleRate > 0)) {
47 mxmlElementSetAttr(target, "supports_live", "yes"); 52 mxmlElementSetAttr(target, "supports_live", "yes");
diff --git a/daemon/CapturedXML.h b/daemon/CapturedXML.h
index b0482f5..efc1e52 100644
--- a/daemon/CapturedXML.h
+++ b/daemon/CapturedXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Child.cpp b/daemon/Child.cpp
index 9ee2ef8..ca33561 100644
--- a/daemon/Child.cpp
+++ b/daemon/Child.cpp
@@ -1,38 +1,39 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "Child.h"
10
9#include <stdlib.h> 11#include <stdlib.h>
10#include <string.h> 12#include <string.h>
11#include <signal.h> 13#include <signal.h>
12#include <unistd.h> 14#include <unistd.h>
13#include <sys/prctl.h> 15#include <sys/prctl.h>
16
14#include "Logging.h" 17#include "Logging.h"
15#include "CapturedXML.h" 18#include "CapturedXML.h"
16#include "SessionData.h" 19#include "SessionData.h"
17#include "Child.h"
18#include "LocalCapture.h" 20#include "LocalCapture.h"
19#include "Collector.h"
20#include "Sender.h" 21#include "Sender.h"
21#include "OlyUtility.h" 22#include "OlyUtility.h"
23#include "OlySocket.h"
22#include "StreamlineSetup.h" 24#include "StreamlineSetup.h"
23#include "ConfigurationXML.h" 25#include "ConfigurationXML.h"
24#include "Driver.h" 26#include "Driver.h"
25#include "Fifo.h" 27#include "PerfSource.h"
26#include "Buffer.h" 28#include "DriverSource.h"
27 29#include "UserSpaceSource.h"
28#define NS_PER_S ((uint64_t)1000000000) 30#include "ExternalSource.h"
29#define NS_PER_US 1000
30 31
31static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads 32static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads
32static Fifo* collectorFifo = NULL; // Shared by Child.cpp and spawned threads 33static Source *primarySource = NULL;
33static Buffer* buffer = NULL; 34static Source *userSpaceSource = NULL;
35static Source *externalSource = NULL;
34static Sender* sender = NULL; // Shared by Child.cpp and spawned threads 36static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
35static Collector* collector = NULL;
36Child* child = NULL; // shared by Child.cpp and main.cpp 37Child* child = NULL; // shared by Child.cpp and main.cpp
37 38
38extern void cleanUp(); 39extern void cleanUp();
@@ -78,7 +79,7 @@ static void child_handler(int signum) {
78 } 79 }
79 beenHere = true; 80 beenHere = true;
80 logg->logMessage("Gator is shutting down."); 81 logg->logMessage("Gator is shutting down.");
81 if (signum == SIGALRM || !collector) { 82 if (signum == SIGALRM || !primarySource) {
82 exit(1); 83 exit(1);
83 } else { 84 } else {
84 child->endSession(); 85 child->endSession();
@@ -139,77 +140,22 @@ static void *stopThread(void *) {
139 return 0; 140 return 0;
140} 141}
141 142
142static void *countersThread(void *) {
143 prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
144
145 gSessionData->hwmon.start();
146
147 int64_t monotonic_started = 0;
148 while (monotonic_started <= 0) {
149 usleep(10);
150
151 if (Collector::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
152 logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
153 handleException();
154 }
155 }
156
157 uint64_t next_time = 0;
158 while (gSessionData->mSessionIsActive) {
159 struct timespec ts;
160#ifndef CLOCK_MONOTONIC_RAW
161 // Android doesn't have this defined but it was added in Linux 2.6.28
162#define CLOCK_MONOTONIC_RAW 4
163#endif
164 if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
165 logg->logError(__FILE__, __LINE__, "Failed to get uptime");
166 handleException();
167 }
168 const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started;
169 // Sample ten times a second ignoring gSessionData->mSampleRate
170 next_time += NS_PER_S/10;//gSessionData->mSampleRate;
171 if (next_time < curr_time) {
172 logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
173 next_time = curr_time;
174 }
175
176 if (buffer->eventHeader(curr_time)) {
177 gSessionData->hwmon.read(buffer);
178 // Only check after writing all counters so that time and corresponding counters appear in the same frame
179 buffer->check(curr_time);
180 }
181
182 if (buffer->bytesAvailable() <= 0) {
183 logg->logMessage("One shot (counters)");
184 child->endSession();
185 }
186
187 usleep((next_time - curr_time)/NS_PER_US);
188 }
189
190 buffer->setDone();
191
192 return NULL;
193}
194
195static void *senderThread(void *) { 143static void *senderThread(void *) {
196 int length = 1;
197 char* data;
198 char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0}; 144 char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0};
199 145
200 sem_post(&senderThreadStarted); 146 sem_post(&senderThreadStarted);
201 prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0); 147 prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0);
202 sem_wait(&haltPipeline); 148 sem_wait(&haltPipeline);
203 149
204 while (length > 0 || !buffer->isDone()) { 150 while (!primarySource->isDone() || (userSpaceSource != NULL && !userSpaceSource->isDone()) || (externalSource != NULL && !externalSource->isDone())) {
205 sem_wait(&senderSem); 151 sem_wait(&senderSem);
206 data = collectorFifo->read(&length); 152
207 if (data != NULL) { 153 primarySource->write(sender);
208 sender->writeData(data, length, RESPONSE_APC_DATA); 154 if (userSpaceSource != NULL) {
209 collectorFifo->release(); 155 userSpaceSource->write(sender);
210 } 156 }
211 if (!buffer->isDone()) { 157 if (externalSource != NULL) {
212 buffer->write(sender); 158 externalSource->write(sender);
213 } 159 }
214 } 160 }
215 161
@@ -255,15 +201,13 @@ void Child::initialization() {
255 201
256void Child::endSession() { 202void Child::endSession() {
257 gSessionData->mSessionIsActive = false; 203 gSessionData->mSessionIsActive = false;
258 collector->stop(); 204 primarySource->interrupt();
259 sem_post(&haltPipeline); 205 sem_post(&haltPipeline);
260} 206}
261 207
262void Child::run() { 208void Child::run() {
263 char* collectBuffer;
264 int bytesCollected = 0;
265 LocalCapture* localCapture = NULL; 209 LocalCapture* localCapture = NULL;
266 pthread_t durationThreadID, stopThreadID, senderThreadID, countersThreadID; 210 pthread_t durationThreadID, stopThreadID, senderThreadID;
267 211
268 prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0); 212 prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0);
269 213
@@ -282,7 +226,11 @@ void Child::run() {
282 { ConfigurationXML configuration; } 226 { ConfigurationXML configuration; }
283 227
284 // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated 228 // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
285 collector = new Collector(); 229 if (!gSessionData->perf.isSetup()) {
230 primarySource = new DriverSource(&senderSem, &startProfile);
231 } else {
232 primarySource = new PerfSource(&senderSem, &startProfile);
233 }
286 234
287 // Initialize all drivers 235 // Initialize all drivers
288 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) { 236 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
@@ -317,15 +265,11 @@ void Child::run() {
317 free(xmlString); 265 free(xmlString);
318 } 266 }
319 267
320 // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length 268 // Must be after session XML is parsed
321 logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, collector->getBufferSize()); 269 if (!primarySource->prepare()) {
322 collectorFifo = new Fifo(collector->getBufferSize() + 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem); 270 logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
323 271 handleException();
324 // Get the initial pointer to the collect buffer 272 }
325 collectBuffer = collectorFifo->start();
326
327 // Create a new Block Counter Buffer
328 buffer = new Buffer(0, 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem);
329 273
330 // Sender thread shall be halted until it is signaled for one shot mode 274 // Sender thread shall be halted until it is signaled for one shot mode
331 sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2); 275 sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
@@ -340,14 +284,21 @@ void Child::run() {
340 thread_creation_success = false; 284 thread_creation_success = false;
341 } 285 }
342 286
343 bool startcountersThread = gSessionData->hwmon.countersEnabled(); 287 if (gSessionData->hwmon.countersEnabled()) {
344 if (startcountersThread) { 288 userSpaceSource = new UserSpaceSource(&senderSem);
345 if (pthread_create(&countersThreadID, NULL, countersThread, this)) { 289 if (!userSpaceSource->prepare()) {
346 thread_creation_success = false; 290 logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
291 handleException();
347 } 292 }
348 } else { 293 userSpaceSource->start();
349 // Let senderThread know there is no buffer data to send 294 }
350 buffer->setDone(); 295 if (access("/tmp/gator", F_OK) == 0) {
296 externalSource = new ExternalSource(&senderSem);
297 if (!externalSource->prepare()) {
298 logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
299 handleException();
300 }
301 externalSource->start();
351 } 302 }
352 303
353 if (!thread_creation_success) { 304 if (!thread_creation_success) {
@@ -359,28 +310,13 @@ void Child::run() {
359 sem_wait(&senderThreadStarted); 310 sem_wait(&senderThreadStarted);
360 311
361 // Start profiling 312 // Start profiling
362 logg->logMessage("********** Profiling started **********"); 313 primarySource->run();
363 collector->start();
364 sem_post(&startProfile);
365
366 // Collect Data
367 do {
368 // This command will stall until data is received from the driver
369 bytesCollected = collector->collect(collectBuffer);
370
371 // In one shot mode, stop collection once all the buffers are filled
372 if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
373 if (bytesCollected == -1 || collectorFifo->willFill(bytesCollected)) {
374 logg->logMessage("One shot");
375 endSession();
376 }
377 }
378 collectBuffer = collectorFifo->write(bytesCollected);
379 } while (bytesCollected > 0);
380 logg->logMessage("Exit collect data loop");
381 314
382 if (startcountersThread) { 315 if (externalSource != NULL) {
383 pthread_join(countersThreadID, NULL); 316 externalSource->join();
317 }
318 if (userSpaceSource != NULL) {
319 userSpaceSource->join();
384 } 320 }
385 321
386 // Wait for the other threads to exit 322 // Wait for the other threads to exit
@@ -401,9 +337,9 @@ void Child::run() {
401 337
402 logg->logMessage("Profiling ended."); 338 logg->logMessage("Profiling ended.");
403 339
404 delete buffer; 340 delete externalSource;
405 delete collectorFifo; 341 delete userSpaceSource;
342 delete primarySource;
406 delete sender; 343 delete sender;
407 delete collector;
408 delete localCapture; 344 delete localCapture;
409} 345}
diff --git a/daemon/Child.h b/daemon/Child.h
index 0330e9d..9e206d7 100644
--- a/daemon/Child.h
+++ b/daemon/Child.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,8 +9,6 @@
9#ifndef __CHILD_H__ 9#ifndef __CHILD_H__
10#define __CHILD_H__ 10#define __CHILD_H__
11 11
12#include <pthread.h>
13
14class OlySocket; 12class OlySocket;
15 13
16class Child { 14class Child {
diff --git a/daemon/Collector.h b/daemon/Collector.h
deleted file mode 100644
index c5e9eac..0000000
--- a/daemon/Collector.h
+++ /dev/null
@@ -1,38 +0,0 @@
1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __COLLECTOR_H__
10#define __COLLECTOR_H__
11
12#include <stdio.h>
13
14class Collector {
15public:
16 Collector();
17 ~Collector();
18 void start();
19 void stop();
20 int collect(char* buffer);
21 int getBufferSize() {return mBufferSize;}
22
23 static int readIntDriver(const char* path, int* value);
24 static int readInt64Driver(const char* path, int64_t* value);
25 static int writeDriver(const char* path, int value);
26 static int writeDriver(const char* path, int64_t value);
27 static int writeDriver(const char* path, const char* data);
28 static int writeReadDriver(const char* path, int* value);
29 static int writeReadDriver(const char* path, int64_t* value);
30
31private:
32 int mBufferSize;
33 int mBufferFD;
34
35 void checkVersion();
36};
37
38#endif //__COLLECTOR_H__
diff --git a/daemon/Config.h b/daemon/Config.h
new file mode 100644
index 0000000..6f5e2aa
--- /dev/null
+++ b/daemon/Config.h
@@ -0,0 +1,17 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef CONFIG_H
10#define CONFIG_H
11
12#define ARRAY_LENGTH(A) static_cast<int>(sizeof(A)/sizeof((A)[0]))
13
14#define MAX_PERFORMANCE_COUNTERS 50
15#define NR_CPUS 16
16
17#endif // CONFIG_H
diff --git a/daemon/ConfigurationXML.cpp b/daemon/ConfigurationXML.cpp
index 2a5252a..fd479f2 100644
--- a/daemon/ConfigurationXML.cpp
+++ b/daemon/ConfigurationXML.cpp
@@ -1,15 +1,17 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "ConfigurationXML.h"
10
9#include <string.h> 11#include <string.h>
10#include <stdlib.h> 12#include <stdlib.h>
11#include <dirent.h> 13#include <dirent.h>
12#include "ConfigurationXML.h" 14
13#include "Driver.h" 15#include "Driver.h"
14#include "Logging.h" 16#include "Logging.h"
15#include "OlyUtility.h" 17#include "OlyUtility.h"
@@ -67,6 +69,7 @@ int ConfigurationXML::parse(const char* configurationXML) {
67 69
68 // clear counter overflow 70 // clear counter overflow
69 gSessionData->mCounterOverflow = 0; 71 gSessionData->mCounterOverflow = 0;
72 gSessionData->mIsEBS = false;
70 mIndex = 0; 73 mIndex = 0;
71 74
72 // disable all counters prior to parsing the configuration xml 75 // disable all counters prior to parsing the configuration xml
@@ -155,6 +158,9 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
155 if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER)); 158 if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER));
156 if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16)); 159 if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16));
157 if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10)); 160 if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10));
161 if (counter.getCount() > 0) {
162 gSessionData->mIsEBS = true;
163 }
158 counter.setEnabled(true); 164 counter.setEnabled(true);
159 165
160 // Associate a driver with each counter 166 // Associate a driver with each counter
@@ -181,9 +187,9 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
181} 187}
182 188
183void ConfigurationXML::getDefaultConfigurationXml(const char * & xml, unsigned int & len) { 189void ConfigurationXML::getDefaultConfigurationXml(const char * & xml, unsigned int & len) {
184#include "configuration_xml.h" // defines and initializes char configuration_xml[] and int configuration_xml_len 190#include "defaults_xml.h" // defines and initializes char defaults_xml[] and int defaults_xml_len
185 xml = (const char *)configuration_xml; 191 xml = (const char *)defaults_xml;
186 len = configuration_xml_len; 192 len = defaults_xml_len;
187} 193}
188 194
189void ConfigurationXML::getPath(char* path) { 195void ConfigurationXML::getPath(char* path) {
diff --git a/daemon/ConfigurationXML.h b/daemon/ConfigurationXML.h
index 5650f48..efa415e 100644
--- a/daemon/ConfigurationXML.h
+++ b/daemon/ConfigurationXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Counter.h b/daemon/Counter.h
index 231a85d..6891745 100644
--- a/daemon/Counter.h
+++ b/daemon/Counter.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -25,7 +25,7 @@ public:
25 void clear () { 25 void clear () {
26 mType[0] = '\0'; 26 mType[0] = '\0';
27 mEnabled = false; 27 mEnabled = false;
28 mEvent = 0; 28 mEvent = -1;
29 mCount = 0; 29 mCount = 0;
30 mKey = 0; 30 mKey = 0;
31 mDriver = NULL; 31 mDriver = NULL;
diff --git a/daemon/Driver.cpp b/daemon/Driver.cpp
index c262467..09e0401 100644
--- a/daemon/Driver.cpp
+++ b/daemon/Driver.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Driver.h b/daemon/Driver.h
index f3a932f..e5ed7b6 100644
--- a/daemon/Driver.h
+++ b/daemon/Driver.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -27,7 +27,7 @@ public:
27 virtual void setupCounter(Counter &counter) = 0; 27 virtual void setupCounter(Counter &counter) = 0;
28 28
29 // Emits available counters 29 // Emits available counters
30 virtual void writeCounters(mxml_node_t *root) const = 0; 30 virtual int writeCounters(mxml_node_t *root) const = 0;
31 // Emits possible dynamically generated events/counters 31 // Emits possible dynamically generated events/counters
32 virtual void writeEvents(mxml_node_t *) const {} 32 virtual void writeEvents(mxml_node_t *) const {}
33 33
diff --git a/daemon/Collector.cpp b/daemon/DriverSource.cpp
index bf73534..f78ec6b 100644
--- a/daemon/Collector.cpp
+++ b/daemon/DriverSource.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -8,23 +8,47 @@
8 8
9#define __STDC_FORMAT_MACROS 9#define __STDC_FORMAT_MACROS
10 10
11#include "DriverSource.h"
12
11#include <fcntl.h> 13#include <fcntl.h>
12#include <unistd.h>
13#include <string.h>
14#include <stdlib.h>
15#include <errno.h>
16#include <sys/time.h>
17#include <inttypes.h> 14#include <inttypes.h>
18#include "Collector.h" 15#include <unistd.h>
19#include "SessionData.h" 16
17#include "Child.h"
18#include "Fifo.h"
20#include "Logging.h" 19#include "Logging.h"
21#include "Sender.h" 20#include "Sender.h"
21#include "SessionData.h"
22
23extern Child *child;
22 24
23// Driver initialization independent of session settings 25DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) {
24Collector::Collector() { 26 int driver_version = 0;
25 mBufferFD = 0;
26 27
27 checkVersion(); 28 if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
29 logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
30 handleException();
31 }
32
33 // Verify the driver version matches the daemon version
34 if (driver_version != PROTOCOL_VERSION) {
35 if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
36 // One of the mismatched versions is development version
37 logg->logError(__FILE__, __LINE__,
38 "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
39 ">> The following must be synchronized from engineering repository:\n"
40 ">> * gator driver\n"
41 ">> * gator daemon\n"
42 ">> * Streamline", driver_version, PROTOCOL_VERSION);
43 handleException();
44 } else {
45 // Release version mismatch
46 logg->logError(__FILE__, __LINE__,
47 "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
48 ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
49 handleException();
50 }
51 }
28 52
29 int enable = -1; 53 int enable = -1;
30 if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) { 54 if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) {
@@ -37,14 +61,15 @@ Collector::Collector() {
37 gSessionData->mCores = 1; 61 gSessionData->mCores = 1;
38 } 62 }
39 63
40 mBufferSize = 0;
41 if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) { 64 if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) {
42 logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size"); 65 logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size");
43 handleException(); 66 handleException();
44 } 67 }
45} 68}
46 69
47Collector::~Collector() { 70DriverSource::~DriverSource() {
71 delete mFifo;
72
48 // Write zero for safety, as a zero should have already been written 73 // Write zero for safety, as a zero should have already been written
49 writeDriver("/dev/gator/enable", "0"); 74 writeDriver("/dev/gator/enable", "0");
50 75
@@ -54,36 +79,21 @@ Collector::~Collector() {
54 } 79 }
55} 80}
56 81
57void Collector::checkVersion() { 82bool DriverSource::prepare() {
58 int driver_version = 0; 83 // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
59 84 logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, mBufferSize);
60 if (readIntDriver("/dev/gator/version", &driver_version) == -1) { 85 mFifo = new Fifo(mBufferSize + 5, gSessionData->mTotalBufferSize*1024*1024, mSenderSem);
61 logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
62 handleException();
63 }
64 86
65 // Verify the driver version matches the daemon version 87 return true;
66 if (driver_version != PROTOCOL_VERSION) {
67 if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
68 // One of the mismatched versions is development version
69 logg->logError(__FILE__, __LINE__,
70 "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
71 ">> The following must be synchronized from engineering repository:\n"
72 ">> * gator driver\n"
73 ">> * gator daemon\n"
74 ">> * Streamline", driver_version, PROTOCOL_VERSION);
75 handleException();
76 } else {
77 // Release version mismatch
78 logg->logError(__FILE__, __LINE__,
79 "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
80 ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
81 handleException();
82 }
83 }
84} 88}
85 89
86void Collector::start() { 90void DriverSource::run() {
91 // Get the initial pointer to the collect buffer
92 char *collectBuffer = mFifo->start();
93 int bytesCollected = 0;
94
95 logg->logMessage("********** Profiling started **********");
96
87 // Set the maximum backtrace depth 97 // Set the maximum backtrace depth
88 if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) { 98 if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) {
89 logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth"); 99 logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
@@ -125,79 +135,112 @@ void Collector::start() {
125 } 135 }
126 136
127 lseek(mBufferFD, 0, SEEK_SET); 137 lseek(mBufferFD, 0, SEEK_SET);
138
139 sem_post(mStartProfile);
140
141 // Collect Data
142 do {
143 // This command will stall until data is received from the driver
144 // Calls event_buffer_read in the driver
145 errno = 0;
146 bytesCollected = read(mBufferFD, collectBuffer, mBufferSize);
147
148 // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
149 if (bytesCollected == -1 && errno == EINTR) {
150 bytesCollected = read(mBufferFD, collectBuffer, mBufferSize);
151 }
152
153 // return the total bytes written
154 logg->logMessage("Driver read of %d bytes", bytesCollected);
155
156 // In one shot mode, stop collection once all the buffers are filled
157 if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
158 if (bytesCollected == -1 || mFifo->willFill(bytesCollected)) {
159 logg->logMessage("One shot");
160 child->endSession();
161 }
162 }
163 collectBuffer = mFifo->write(bytesCollected);
164 } while (bytesCollected > 0);
165
166 logg->logMessage("Exit collect data loop");
128} 167}
129 168
130// These commands should cause the read() function in collect() to return 169void DriverSource::interrupt() {
131void Collector::stop() { 170 // This command should cause the read() function in collect() to return and stop the driver from profiling
132 // This will stop the driver from profiling
133 if (writeDriver("/dev/gator/enable", "0") != 0) { 171 if (writeDriver("/dev/gator/enable", "0") != 0) {
134 logg->logMessage("Stopping kernel failed"); 172 logg->logMessage("Stopping kernel failed");
135 } 173 }
136} 174}
137 175
138int Collector::collect(char* buffer) { 176bool DriverSource::isDone() {
139 // Calls event_buffer_read in the driver 177 return mLength <= 0;
140 int bytesRead; 178}
141
142 errno = 0;
143 bytesRead = read(mBufferFD, buffer, mBufferSize);
144 179
145 // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data 180void DriverSource::write(Sender *sender) {
146 if (bytesRead == -1 && errno == EINTR) { 181 char *data = mFifo->read(&mLength);
147 bytesRead = read(mBufferFD, buffer, mBufferSize); 182 if (data != NULL) {
183 sender->writeData(data, mLength, RESPONSE_APC_DATA);
184 mFifo->release();
148 } 185 }
149
150 // return the total bytes written
151 logg->logMessage("Driver read of %d bytes", bytesRead);
152 return bytesRead;
153} 186}
154 187
155int Collector::readIntDriver(const char* fullpath, int* value) { 188int DriverSource::readIntDriver(const char *fullpath, int *value) {
156 FILE* file = fopen(fullpath, "r"); 189 char data[40]; // Sufficiently large to hold any integer
157 if (file == NULL) { 190 const int fd = open(fullpath, O_RDONLY);
191 if (fd < 0) {
192 return -1;
193 }
194
195 const ssize_t bytes = read(fd, data, sizeof(data) - 1);
196 close(fd);
197 if (bytes < 0) {
158 return -1; 198 return -1;
159 } 199 }
160 if (fscanf(file, "%u", value) != 1) { 200 data[bytes] = '\0';
161 fclose(file); 201
202 char *endptr;
203 errno = 0;
204 *value = strtol(data, &endptr, 10);
205 if (errno != 0 || *endptr != '\n') {
162 logg->logMessage("Invalid value in file %s", fullpath); 206 logg->logMessage("Invalid value in file %s", fullpath);
163 return -1; 207 return -1;
164 } 208 }
165 fclose(file); 209
166 return 0; 210 return 0;
167} 211}
168 212
169int Collector::readInt64Driver(const char* fullpath, int64_t* value) { 213int DriverSource::readInt64Driver(const char *fullpath, int64_t *value) {
170 FILE* file = fopen(fullpath, "r"); 214 char data[40]; // Sufficiently large to hold any integer
171 if (file == NULL) { 215 const int fd = open(fullpath, O_RDONLY);
216 if (fd < 0) {
172 return -1; 217 return -1;
173 } 218 }
174 if (fscanf(file, "%" SCNi64, value) != 1) { 219
175 fclose(file); 220 const ssize_t bytes = read(fd, data, sizeof(data) - 1);
176 logg->logMessage("Invalid value in file %s", fullpath); 221 close(fd);
222 if (bytes < 0) {
177 return -1; 223 return -1;
178 } 224 }
179 fclose(file); 225 data[bytes] = '\0';
180 return 0;
181}
182 226
183int Collector::writeDriver(const char* path, int value) { 227 char *endptr;
184 char data[40]; // Sufficiently large to hold any integer 228 errno = 0;
185 snprintf(data, sizeof(data), "%d", value); 229 *value = strtoll(data, &endptr, 10);
186 return writeDriver(path, data); 230 if (errno != 0 || *endptr != '\n') {
187} 231 logg->logMessage("Invalid value in file %s", fullpath);
232 return -1;
233 }
188 234
189int Collector::writeDriver(const char* path, int64_t value) { 235 return 0;
190 char data[40]; // Sufficiently large to hold any integer
191 snprintf(data, sizeof(data), "%" PRIi64, value);
192 return writeDriver(path, data);
193} 236}
194 237
195int Collector::writeDriver(const char* fullpath, const char* data) { 238int DriverSource::writeDriver(const char *fullpath, const char *data) {
196 int fd = open(fullpath, O_WRONLY); 239 int fd = open(fullpath, O_WRONLY);
197 if (fd < 0) { 240 if (fd < 0) {
198 return -1; 241 return -1;
199 } 242 }
200 if (write(fd, data, strlen(data)) < 0) { 243 if (::write(fd, data, strlen(data)) < 0) {
201 close(fd); 244 close(fd);
202 logg->logMessage("Opened but could not write to %s", fullpath); 245 logg->logMessage("Opened but could not write to %s", fullpath);
203 return -1; 246 return -1;
@@ -206,14 +249,26 @@ int Collector::writeDriver(const char* fullpath, const char* data) {
206 return 0; 249 return 0;
207} 250}
208 251
209int Collector::writeReadDriver(const char* path, int* value) { 252int DriverSource::writeDriver(const char *path, int value) {
253 char data[40]; // Sufficiently large to hold any integer
254 snprintf(data, sizeof(data), "%d", value);
255 return writeDriver(path, data);
256}
257
258int DriverSource::writeDriver(const char *path, int64_t value) {
259 char data[40]; // Sufficiently large to hold any integer
260 snprintf(data, sizeof(data), "%" PRIi64, value);
261 return writeDriver(path, data);
262}
263
264int DriverSource::writeReadDriver(const char *path, int *value) {
210 if (writeDriver(path, *value) || readIntDriver(path, value)) { 265 if (writeDriver(path, *value) || readIntDriver(path, value)) {
211 return -1; 266 return -1;
212 } 267 }
213 return 0; 268 return 0;
214} 269}
215 270
216int Collector::writeReadDriver(const char* path, int64_t* value) { 271int DriverSource::writeReadDriver(const char *path, int64_t *value) {
217 if (writeDriver(path, *value) || readInt64Driver(path, value)) { 272 if (writeDriver(path, *value) || readInt64Driver(path, value)) {
218 return -1; 273 return -1;
219 } 274 }
diff --git a/daemon/DriverSource.h b/daemon/DriverSource.h
new file mode 100644
index 0000000..dcf1078
--- /dev/null
+++ b/daemon/DriverSource.h
@@ -0,0 +1,52 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef DRIVERSOURCE_H
10#define DRIVERSOURCE_H
11
12#include <semaphore.h>
13#include <stdint.h>
14
15#include "Source.h"
16
17class Fifo;
18
19class DriverSource : public Source {
20public:
21 DriverSource(sem_t *senderSem, sem_t *startProfile);
22 ~DriverSource();
23
24 bool prepare();
25 void run();
26 void interrupt();
27
28 bool isDone();
29 void write(Sender *sender);
30
31 static int readIntDriver(const char *fullpath, int *value);
32 static int readInt64Driver(const char *fullpath, int64_t *value);
33 static int writeDriver(const char *fullpath, const char *data);
34 static int writeDriver(const char *path, int value);
35 static int writeDriver(const char *path, int64_t value);
36 static int writeReadDriver(const char *path, int *value);
37 static int writeReadDriver(const char *path, int64_t *value);
38
39private:
40 Fifo *mFifo;
41 sem_t *const mSenderSem;
42 sem_t *const mStartProfile;
43 int mBufferSize;
44 int mBufferFD;
45 int mLength;
46
47 // Intentionally unimplemented
48 DriverSource(const DriverSource &);
49 DriverSource &operator=(const DriverSource &);
50};
51
52#endif // DRIVERSOURCE_H
diff --git a/daemon/DynBuf.cpp b/daemon/DynBuf.cpp
new file mode 100644
index 0000000..6f92b33
--- /dev/null
+++ b/daemon/DynBuf.cpp
@@ -0,0 +1,139 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "DynBuf.h"
10
11#include <errno.h>
12#include <fcntl.h>
13#include <stdarg.h>
14#include <stdio.h>
15#include <unistd.h>
16
17#include "Logging.h"
18
19// Pick an aggressive size as buffer is primarily used for disk IO
20#define MIN_BUFFER_FREE (1 << 12)
21
22int DynBuf::resize(const size_t minCapacity) {
23 size_t scaledCapacity = 2 * capacity;
24 if (scaledCapacity < minCapacity) {
25 scaledCapacity = minCapacity;
26 }
27 if (scaledCapacity < 2 * MIN_BUFFER_FREE) {
28 scaledCapacity = 2 * MIN_BUFFER_FREE;
29 }
30 capacity = scaledCapacity;
31
32 buf = static_cast<char *>(realloc(buf, capacity));
33 if (buf == NULL) {
34 return -errno;
35 }
36
37 return 0;
38}
39
40bool DynBuf::read(const char *const path) {
41 int result = false;
42
43 const int fd = open(path, O_RDONLY);
44 if (fd < 0) {
45 logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
46 return false;
47 }
48
49 length = 0;
50
51 for (;;) {
52 const size_t minCapacity = length + MIN_BUFFER_FREE + 1;
53 if (capacity < minCapacity) {
54 if (resize(minCapacity) != 0) {
55 logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
56 goto fail;
57 }
58 }
59
60 const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1);
61 if (bytes < 0) {
62 logg->logMessage("%s(%s:%i): read failed", __FUNCTION__, __FILE__, __LINE__);
63 goto fail;
64 } else if (bytes == 0) {
65 break;
66 }
67 length += bytes;
68 }
69
70 buf[length] = '\0';
71 result = true;
72
73 fail:
74 close(fd);
75
76 return result;
77}
78
79int DynBuf::readlink(const char *const path) {
80 ssize_t bytes = MIN_BUFFER_FREE;
81
82 for (;;) {
83 if (static_cast<size_t>(bytes) >= capacity) {
84 const int err = resize(2 * bytes);
85 if (err != 0) {
86 return err;
87 }
88 }
89 bytes = ::readlink(path, buf, capacity);
90 if (bytes < 0) {
91 return -errno;
92 } else if (static_cast<size_t>(bytes) < capacity) {
93 break;
94 }
95 }
96
97 length = bytes;
98 buf[bytes] = '\0';
99
100 return 0;
101}
102
103bool DynBuf::printf(const char *format, ...) {
104 va_list ap;
105
106 if (capacity <= 0) {
107 if (resize(2 * MIN_BUFFER_FREE) != 0) {
108 logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
109 return false;
110 }
111 }
112
113 va_start(ap, format);
114 int bytes = vsnprintf(buf, capacity, format, ap);
115 va_end(ap);
116 if (bytes < 0) {
117 logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
118 return false;
119 }
120
121 if (static_cast<size_t>(bytes) > capacity) {
122 if (resize(bytes + 1) != 0) {
123 logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
124 return false;
125 }
126
127 va_start(ap, format);
128 bytes = vsnprintf(buf, capacity, format, ap);
129 va_end(ap);
130 if (bytes < 0) {
131 logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
132 return false;
133 }
134 }
135
136 length = bytes;
137
138 return true;
139}
diff --git a/daemon/DynBuf.h b/daemon/DynBuf.h
new file mode 100644
index 0000000..2f4554a
--- /dev/null
+++ b/daemon/DynBuf.h
@@ -0,0 +1,52 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef DYNBUF_H
10#define DYNBUF_H
11
12#include <stdlib.h>
13
14class DynBuf {
15public:
16 DynBuf() : capacity(0), length(0), buf(NULL) {}
17 ~DynBuf() {
18 reset();
19 }
20
21 inline void reset() {
22 capacity = 0;
23 length = 0;
24 if (buf != NULL) {
25 free(buf);
26 buf = NULL;
27 }
28 }
29
30 bool read(const char *const path);
31 // On error instead of printing the error and returning false, this returns -errno
32 int readlink(const char *const path);
33 __attribute__ ((format(printf, 2, 3)))
34 bool printf(const char *format, ...);
35
36 size_t getLength() const { return length; }
37 const char *getBuf() const { return buf; }
38 char *getBuf() { return buf; }
39
40private:
41 int resize(const size_t minCapacity);
42
43 size_t capacity;
44 size_t length;
45 char *buf;
46
47 // Intentionally undefined
48 DynBuf(const DynBuf &);
49 DynBuf &operator=(const DynBuf &);
50};
51
52#endif // DYNBUF_H
diff --git a/daemon/EventsXML.cpp b/daemon/EventsXML.cpp
index 2a80482..a07a046 100644
--- a/daemon/EventsXML.cpp
+++ b/daemon/EventsXML.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -35,7 +35,7 @@ char* EventsXML::getXML() {
35 fclose(fl); 35 fclose(fl);
36 } else { 36 } else {
37 logg->logMessage("Unable to locate events.xml, using default"); 37 logg->logMessage("Unable to locate events.xml, using default");
38 xml = mxmlLoadString(NULL, (char *)events_xml, MXML_NO_CALLBACK); 38 xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK);
39 } 39 }
40 40
41 // Add dynamic events from the drivers 41 // Add dynamic events from the drivers
diff --git a/daemon/EventsXML.h b/daemon/EventsXML.h
index 8e693ef..6cd1560 100644
--- a/daemon/EventsXML.h
+++ b/daemon/EventsXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/ExternalSource.cpp b/daemon/ExternalSource.cpp
new file mode 100644
index 0000000..fe5824b
--- /dev/null
+++ b/daemon/ExternalSource.cpp
@@ -0,0 +1,56 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "ExternalSource.h"
10
11#include <sys/prctl.h>
12
13#include "Logging.h"
14#include "OlySocket.h"
15#include "SessionData.h"
16
17ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 1024, senderSem), mSock("/tmp/gator") {
18}
19
20ExternalSource::~ExternalSource() {
21}
22
23bool ExternalSource::prepare() {
24 return true;
25}
26
27void ExternalSource::run() {
28 prctl(PR_SET_NAME, (unsigned long)&"gatord-uds", 0, 0, 0);
29
30 while (gSessionData->mSessionIsActive) {
31 // Will be aborted when the socket is closed at the end of the capture
32 int length = mSock.receive(mBuffer.getWritePos(), mBuffer.contiguousSpaceAvailable());
33 if (length <= 0) {
34 break;
35 }
36
37 mBuffer.advanceWrite(length);
38 mBuffer.check(0);
39 }
40
41 mBuffer.setDone();
42}
43
44void ExternalSource::interrupt() {
45 // Do nothing
46}
47
48bool ExternalSource::isDone() {
49 return mBuffer.isDone();
50}
51
52void ExternalSource::write(Sender *sender) {
53 if (!mBuffer.isDone()) {
54 mBuffer.write(sender);
55 }
56}
diff --git a/daemon/ExternalSource.h b/daemon/ExternalSource.h
new file mode 100644
index 0000000..2052bdf
--- /dev/null
+++ b/daemon/ExternalSource.h
@@ -0,0 +1,40 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef EXTERNALSOURCE_H
10#define EXTERNALSOURCE_H
11
12#include <semaphore.h>
13
14#include "Buffer.h"
15#include "OlySocket.h"
16#include "Source.h"
17
18// Unix domain socket counters from external sources like graphics drivers
19class ExternalSource : public Source {
20public:
21 ExternalSource(sem_t *senderSem);
22 ~ExternalSource();
23
24 bool prepare();
25 void run();
26 void interrupt();
27
28 bool isDone();
29 void write(Sender *sender);
30
31private:
32 Buffer mBuffer;
33 OlySocket mSock;
34
35 // Intentionally unimplemented
36 ExternalSource(const ExternalSource &);
37 ExternalSource &operator=(const ExternalSource &);
38};
39
40#endif // EXTERNALSOURCE_H
diff --git a/daemon/Fifo.cpp b/daemon/Fifo.cpp
index 250a4d0..f672e92 100644
--- a/daemon/Fifo.cpp
+++ b/daemon/Fifo.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Fifo.h b/daemon/Fifo.h
index d25cd68..7dd7426 100644
--- a/daemon/Fifo.h
+++ b/daemon/Fifo.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -12,7 +12,7 @@
12#ifdef WIN32 12#ifdef WIN32
13#include <windows.h> 13#include <windows.h>
14#define sem_t HANDLE 14#define sem_t HANDLE
15#define sem_init(sem, pshared, value) ((*(sem) = CreateSemaphore(NULL, value, INFINITE, NULL)) == NULL) 15#define sem_init(sem, pshared, value) ((*(sem) = CreateSemaphore(NULL, value, LONG_MAX, NULL)) == NULL)
16#define sem_wait(sem) WaitForSingleObject(*(sem), INFINITE) 16#define sem_wait(sem) WaitForSingleObject(*(sem), INFINITE)
17#define sem_post(sem) ReleaseSemaphore(*(sem), 1, NULL) 17#define sem_post(sem) ReleaseSemaphore(*(sem), 1, NULL)
18#define sem_destroy(sem) CloseHandle(*(sem)) 18#define sem_destroy(sem) CloseHandle(*(sem))
diff --git a/daemon/Hwmon.cpp b/daemon/Hwmon.cpp
index 1d7c0da..778f307 100644
--- a/daemon/Hwmon.cpp
+++ b/daemon/Hwmon.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,7 @@
17 17
18class HwmonCounter { 18class HwmonCounter {
19public: 19public:
20 HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature); 20 HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature);
21 ~HwmonCounter(); 21 ~HwmonCounter();
22 22
23 HwmonCounter *getNext() const { return next; } 23 HwmonCounter *getNext() const { return next; }
@@ -69,7 +69,7 @@ private:
69 HwmonCounter &operator=(const HwmonCounter &); 69 HwmonCounter &operator=(const HwmonCounter &);
70}; 70};
71 71
72HwmonCounter::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) { 72HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(getEventKey()), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) {
73 73
74 int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1; 74 int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
75 char *chip_name = new char[len]; 75 char *chip_name = new char[len];
@@ -205,6 +205,23 @@ bool HwmonCounter::canRead() {
205} 205}
206 206
207Hwmon::Hwmon() : counters(NULL) { 207Hwmon::Hwmon() : counters(NULL) {
208}
209
210Hwmon::~Hwmon() {
211 while (counters != NULL) {
212 HwmonCounter * counter = counters;
213 counters = counter->getNext();
214 delete counter;
215 }
216 sensors_cleanup();
217}
218
219void Hwmon::setup() {
220 // hwmon does not currently work with perf
221 if (gSessionData->perf.isSetup()) {
222 return;
223 }
224
208 int err = sensors_init(NULL); 225 int err = sensors_init(NULL);
209 if (err) { 226 if (err) {
210 logg->logMessage("Failed to initialize libsensors! (%d)", err); 227 logg->logMessage("Failed to initialize libsensors! (%d)", err);
@@ -218,20 +235,11 @@ Hwmon::Hwmon() : counters(NULL) {
218 int feature_nr = 0; 235 int feature_nr = 0;
219 const sensors_feature *feature; 236 const sensors_feature *feature;
220 while ((feature = sensors_get_features(chip, &feature_nr))) { 237 while ((feature = sensors_get_features(chip, &feature_nr))) {
221 counters = new HwmonCounter(counters, getEventKey(), chip, feature); 238 counters = new HwmonCounter(counters, chip, feature);
222 } 239 }
223 } 240 }
224} 241}
225 242
226Hwmon::~Hwmon() {
227 while (counters != NULL) {
228 HwmonCounter * counter = counters;
229 counters = counter->getNext();
230 delete counter;
231 }
232 sensors_cleanup();
233}
234
235HwmonCounter *Hwmon::findCounter(const Counter &counter) const { 243HwmonCounter *Hwmon::findCounter(const Counter &counter) const {
236 for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) { 244 for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) {
237 if (hwmonCounter->canRead() && strcmp(hwmonCounter->getName(), counter.getType()) == 0) { 245 if (hwmonCounter->canRead() && strcmp(hwmonCounter->getName(), counter.getType()) == 0) {
@@ -271,14 +279,18 @@ void Hwmon::setupCounter(Counter &counter) {
271 counter.setKey(hwmonCounter->getKey()); 279 counter.setKey(hwmonCounter->getKey());
272} 280}
273 281
274void Hwmon::writeCounters(mxml_node_t *root) const { 282int Hwmon::writeCounters(mxml_node_t *root) const {
283 int count = 0;
275 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) { 284 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
276 if (!counter->canRead()) { 285 if (!counter->canRead()) {
277 continue; 286 continue;
278 } 287 }
279 mxml_node_t *node = mxmlNewElement(root, "counter"); 288 mxml_node_t *node = mxmlNewElement(root, "counter");
280 mxmlElementSetAttr(node, "name", counter->getName()); 289 mxmlElementSetAttr(node, "name", counter->getName());
290 ++count;
281 } 291 }
292
293 return count;
282} 294}
283 295
284void Hwmon::writeEvents(mxml_node_t *root) const { 296void Hwmon::writeEvents(mxml_node_t *root) const {
diff --git a/daemon/Hwmon.h b/daemon/Hwmon.h
index 46bb42e..a22a360 100644
--- a/daemon/Hwmon.h
+++ b/daemon/Hwmon.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -19,12 +19,14 @@ public:
19 Hwmon(); 19 Hwmon();
20 ~Hwmon(); 20 ~Hwmon();
21 21
22 void setup();
23
22 bool claimCounter(const Counter &counter) const; 24 bool claimCounter(const Counter &counter) const;
23 bool countersEnabled() const; 25 bool countersEnabled() const;
24 void resetCounters(); 26 void resetCounters();
25 void setupCounter(Counter &counter); 27 void setupCounter(Counter &counter);
26 28
27 void writeCounters(mxml_node_t *root) const; 29 int writeCounters(mxml_node_t *root) const;
28 void writeEvents(mxml_node_t *root) const; 30 void writeEvents(mxml_node_t *root) const;
29 31
30 void start(); 32 void start();
diff --git a/daemon/KMod.cpp b/daemon/KMod.cpp
index 559297f..9300002 100644
--- a/daemon/KMod.cpp
+++ b/daemon/KMod.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,9 @@
12#include <dirent.h> 12#include <dirent.h>
13#include <unistd.h> 13#include <unistd.h>
14 14
15#include "Collector.h"
16#include "ConfigurationXML.h" 15#include "ConfigurationXML.h"
17#include "Counter.h" 16#include "Counter.h"
17#include "DriverSource.h"
18#include "Logging.h" 18#include "Logging.h"
19 19
20// Claim all the counters in /dev/gator/events 20// Claim all the counters in /dev/gator/events
@@ -38,9 +38,9 @@ void KMod::resetCounters() {
38 continue; 38 continue;
39 snprintf(base, sizeof(base), "/dev/gator/events/%s", ent->d_name); 39 snprintf(base, sizeof(base), "/dev/gator/events/%s", ent->d_name);
40 snprintf(text, sizeof(text), "%s/enabled", base); 40 snprintf(text, sizeof(text), "%s/enabled", base);
41 Collector::writeDriver(text, 0); 41 DriverSource::writeDriver(text, 0);
42 snprintf(text, sizeof(text), "%s/count", base); 42 snprintf(text, sizeof(text), "%s/count", base);
43 Collector::writeDriver(text, 0); 43 DriverSource::writeDriver(text, 0);
44 } 44 }
45 closedir(dir); 45 closedir(dir);
46 } 46 }
@@ -53,22 +53,22 @@ void KMod::setupCounter(Counter &counter) {
53 53
54 snprintf(text, sizeof(text), "%s/enabled", base); 54 snprintf(text, sizeof(text), "%s/enabled", base);
55 int enabled = true; 55 int enabled = true;
56 if (Collector::writeReadDriver(text, &enabled) || !enabled) { 56 if (DriverSource::writeReadDriver(text, &enabled) || !enabled) {
57 counter.setEnabled(false); 57 counter.setEnabled(false);
58 return; 58 return;
59 } 59 }
60 60
61 snprintf(text, sizeof(text), "%s/key", base); 61 snprintf(text, sizeof(text), "%s/key", base);
62 int key = 0; 62 int key = 0;
63 Collector::readIntDriver(text, &key); 63 DriverSource::readIntDriver(text, &key);
64 counter.setKey(key); 64 counter.setKey(key);
65 65
66 snprintf(text, sizeof(text), "%s/event", base); 66 snprintf(text, sizeof(text), "%s/event", base);
67 Collector::writeDriver(text, counter.getEvent()); 67 DriverSource::writeDriver(text, counter.getEvent());
68 snprintf(text, sizeof(text), "%s/count", base); 68 snprintf(text, sizeof(text), "%s/count", base);
69 if (access(text, F_OK) == 0) { 69 if (access(text, F_OK) == 0) {
70 int count = counter.getCount(); 70 int count = counter.getCount();
71 if (Collector::writeReadDriver(text, &count) && counter.getCount() > 0) { 71 if (DriverSource::writeReadDriver(text, &count) && counter.getCount() > 0) {
72 logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount()); 72 logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount());
73 handleException(); 73 handleException();
74 } 74 }
@@ -80,23 +80,26 @@ void KMod::setupCounter(Counter &counter) {
80 } 80 }
81} 81}
82 82
83void KMod::writeCounters(mxml_node_t *root) const { 83int KMod::writeCounters(mxml_node_t *root) const {
84 struct dirent *ent; 84 struct dirent *ent;
85 mxml_node_t *counter; 85 mxml_node_t *counter;
86 86
87 // counters.xml is simply a file listing of /dev/gator/events 87 // counters.xml is simply a file listing of /dev/gator/events
88 DIR* dir = opendir("/dev/gator/events"); 88 DIR* dir = opendir("/dev/gator/events");
89 if (dir == NULL) { 89 if (dir == NULL) {
90 logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events"); 90 return 0;
91 handleException();
92 } 91 }
93 92
93 int count = 0;
94 while ((ent = readdir(dir)) != NULL) { 94 while ((ent = readdir(dir)) != NULL) {
95 // skip hidden files, current dir, and parent dir 95 // skip hidden files, current dir, and parent dir
96 if (ent->d_name[0] == '.') 96 if (ent->d_name[0] == '.')
97 continue; 97 continue;
98 counter = mxmlNewElement(root, "counter"); 98 counter = mxmlNewElement(root, "counter");
99 mxmlElementSetAttr(counter, "name", ent->d_name); 99 mxmlElementSetAttr(counter, "name", ent->d_name);
100 ++count;
100 } 101 }
101 closedir(dir); 102 closedir(dir);
103
104 return count;
102} 105}
diff --git a/daemon/KMod.h b/daemon/KMod.h
index 7974262..fb7fc8a 100644
--- a/daemon/KMod.h
+++ b/daemon/KMod.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -21,7 +21,7 @@ public:
21 void resetCounters(); 21 void resetCounters();
22 void setupCounter(Counter &counter); 22 void setupCounter(Counter &counter);
23 23
24 void writeCounters(mxml_node_t *root) const; 24 int writeCounters(mxml_node_t *root) const;
25}; 25};
26 26
27#endif // KMOD_H 27#endif // KMOD_H
diff --git a/daemon/LocalCapture.cpp b/daemon/LocalCapture.cpp
index 3235a34..d2a4b79 100644
--- a/daemon/LocalCapture.cpp
+++ b/daemon/LocalCapture.cpp
@@ -1,18 +1,20 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "LocalCapture.h"
10
9#include <sys/stat.h> 11#include <sys/stat.h>
10#include <sys/types.h> 12#include <sys/types.h>
11#include <dirent.h> 13#include <dirent.h>
12#include <string.h> 14#include <string.h>
13#include <stdlib.h> 15#include <stdlib.h>
14#include <unistd.h> 16#include <unistd.h>
15#include "LocalCapture.h" 17
16#include "SessionData.h" 18#include "SessionData.h"
17#include "Logging.h" 19#include "Logging.h"
18#include "OlyUtility.h" 20#include "OlyUtility.h"
diff --git a/daemon/LocalCapture.h b/daemon/LocalCapture.h
index 8042d6a..aadecce 100644
--- a/daemon/LocalCapture.h
+++ b/daemon/LocalCapture.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Logging.cpp b/daemon/Logging.cpp
index 5fd45b5..b8d3178 100644
--- a/daemon/Logging.cpp
+++ b/daemon/Logging.cpp
@@ -1,11 +1,13 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "Logging.h"
10
9#include <stdio.h> 11#include <stdio.h>
10#include <stdlib.h> 12#include <stdlib.h>
11#include <stdarg.h> 13#include <stdarg.h>
@@ -23,8 +25,6 @@
23#define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex) 25#define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex)
24#endif 26#endif
25 27
26#include "Logging.h"
27
28// Global thread-safe logging 28// Global thread-safe logging
29Logging* logg = NULL; 29Logging* logg = NULL;
30 30
diff --git a/daemon/Logging.h b/daemon/Logging.h
index 8f960de..6ae3280 100644
--- a/daemon/Logging.h
+++ b/daemon/Logging.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,14 +9,7 @@
9#ifndef __LOGGING_H__ 9#ifndef __LOGGING_H__
10#define __LOGGING_H__ 10#define __LOGGING_H__
11 11
12#include <stdio.h>
13#include <string.h>
14#include <limits.h>
15#ifdef WIN32
16#include <windows.h>
17#else
18#include <pthread.h> 12#include <pthread.h>
19#endif
20 13
21#define DRIVER_ERROR "\n Driver issue:\n >> gator.ko must be built against the current kernel version & configuration\n >> gator.ko should be co-located with gatord in the same directory\n >> OR insmod gator.ko prior to launching gatord" 14#define DRIVER_ERROR "\n Driver issue:\n >> gator.ko must be built against the current kernel version & configuration\n >> gator.ko should be co-located with gatord in the same directory\n >> OR insmod gator.ko prior to launching gatord"
22 15
@@ -33,11 +26,7 @@ private:
33 char mErrBuf[4096]; // Arbitrarily large buffer to hold a string 26 char mErrBuf[4096]; // Arbitrarily large buffer to hold a string
34 char mLogBuf[4096]; // Arbitrarily large buffer to hold a string 27 char mLogBuf[4096]; // Arbitrarily large buffer to hold a string
35 bool mDebug; 28 bool mDebug;
36#ifdef WIN32
37 HANDLE mLoggingMutex;
38#else
39 pthread_mutex_t mLoggingMutex; 29 pthread_mutex_t mLoggingMutex;
40#endif
41}; 30};
42 31
43extern Logging* logg; 32extern Logging* logg;
diff --git a/daemon/Monitor.cpp b/daemon/Monitor.cpp
new file mode 100644
index 0000000..90d5c47
--- /dev/null
+++ b/daemon/Monitor.cpp
@@ -0,0 +1,61 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Monitor.h"
10
11#include <errno.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "Logging.h"
16
17Monitor::Monitor() : mFd(-1) {
18}
19
20Monitor::~Monitor() {
21 if (mFd >= -1) {
22 close(mFd);
23 }
24}
25
26bool Monitor::init() {
27 mFd = epoll_create(16);
28 if (mFd < 0) {
29 logg->logMessage("%s(%s:%i): epoll_create1 failed", __FUNCTION__, __FILE__, __LINE__);
30 return false;
31 }
32
33 return true;
34}
35
36bool Monitor::add(const int fd) {
37 struct epoll_event event;
38 memset(&event, 0, sizeof(event));
39 event.data.fd = fd;
40 event.events = EPOLLIN;
41 if (epoll_ctl(mFd, EPOLL_CTL_ADD, fd, &event) != 0) {
42 logg->logMessage("%s(%s:%i): epoll_ctl failed", __FUNCTION__, __FILE__, __LINE__);
43 return false;
44 }
45
46 return true;
47}
48
49int Monitor::wait(struct epoll_event *const events, int maxevents, int timeout) {
50 int result = epoll_wait(mFd, events, maxevents, timeout);
51 if (result < 0) {
52 // Ignore if the call was interrupted as this will happen when SIGINT is received
53 if (errno == EINTR) {
54 result = 0;
55 } else {
56 logg->logMessage("%s(%s:%i): epoll_wait failed", __FUNCTION__, __FILE__, __LINE__);
57 }
58 }
59
60 return result;
61}
diff --git a/daemon/Monitor.h b/daemon/Monitor.h
new file mode 100644
index 0000000..6e268b6
--- /dev/null
+++ b/daemon/Monitor.h
@@ -0,0 +1,32 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef MONITOR_H
10#define MONITOR_H
11
12#include <sys/epoll.h>
13
14class Monitor {
15public:
16 Monitor();
17 ~Monitor();
18
19 bool init();
20 bool add(const int fd);
21 int wait(struct epoll_event *const events, int maxevents, int timeout);
22
23private:
24
25 int mFd;
26
27 // Intentionally unimplemented
28 Monitor(const Monitor &);
29 Monitor &operator=(const Monitor &);
30};
31
32#endif // MONITOR_H
diff --git a/daemon/OlySocket.cpp b/daemon/OlySocket.cpp
index ab5c3c2..26e4768 100644
--- a/daemon/OlySocket.cpp
+++ b/daemon/OlySocket.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,7 @@
15#else 15#else
16#include <netinet/in.h> 16#include <netinet/in.h>
17#include <sys/socket.h> 17#include <sys/socket.h>
18#include <sys/un.h>
18#include <unistd.h> 19#include <unistd.h>
19#include <netdb.h> 20#include <netdb.h>
20#endif 21#endif
@@ -30,7 +31,7 @@
30#define SHUTDOWN_RX_TX SHUT_RDWR 31#define SHUTDOWN_RX_TX SHUT_RDWR
31#endif 32#endif
32 33
33OlySocket::OlySocket(int port, bool multiple) { 34OlyServerSocket::OlyServerSocket(int port) {
34#ifdef WIN32 35#ifdef WIN32
35 WSADATA wsaData; 36 WSADATA wsaData;
36 if (WSAStartup(0x0202, &wsaData) != 0) { 37 if (WSAStartup(0x0202, &wsaData) != 0) {
@@ -39,24 +40,82 @@ OlySocket::OlySocket(int port, bool multiple) {
39 } 40 }
40#endif 41#endif
41 42
42 if (multiple) { 43 createServerSocket(port);
43 createServerSocket(port);
44 } else {
45 createSingleServerConnection(port);
46 }
47} 44}
48 45
49OlySocket::OlySocket(int port, char* host) { 46OlySocket::OlySocket(int port, const char* host) {
50 mFDServer = 0;
51 createClientSocket(host, port); 47 createClientSocket(host, port);
52} 48}
53 49
50OlySocket::OlySocket(int socketID) : mSocketID(socketID) {
51}
52
53#ifndef WIN32
54
55OlyServerSocket::OlyServerSocket(const char* path) {
56 // Create socket
57 mFDServer = socket(PF_UNIX, SOCK_STREAM, 0);
58 if (mFDServer < 0) {
59 logg->logError(__FILE__, __LINE__, "Error creating server socket");
60 handleException();
61 }
62
63 unlink(path);
64
65 // Create sockaddr_in structure, ensuring non-populated fields are zero
66 struct sockaddr_un sockaddr;
67 memset((void*)&sockaddr, 0, sizeof(sockaddr));
68 sockaddr.sun_family = AF_UNIX;
69 strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
70 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
71
72 // Bind the socket to an address
73 if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
74 logg->logError(__FILE__, __LINE__, "Binding of server socket failed.");
75 handleException();
76 }
77
78 // Listen for connections on this socket
79 if (listen(mFDServer, 1) < 0) {
80 logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
81 handleException();
82 }
83}
84
85OlySocket::OlySocket(const char* path) {
86 mSocketID = socket(PF_UNIX, SOCK_STREAM, 0);
87 if (mSocketID < 0) {
88 return;
89 }
90
91 // Create sockaddr_in structure, ensuring non-populated fields are zero
92 struct sockaddr_un sockaddr;
93 memset((void*)&sockaddr, 0, sizeof(sockaddr));
94 sockaddr.sun_family = AF_UNIX;
95 strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
96 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
97
98 if (connect(mSocketID, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
99 close(mSocketID);
100 mSocketID = -1;
101 return;
102 }
103}
104
105#endif
106
54OlySocket::~OlySocket() { 107OlySocket::~OlySocket() {
55 if (mSocketID > 0) { 108 if (mSocketID > 0) {
56 CLOSE_SOCKET(mSocketID); 109 CLOSE_SOCKET(mSocketID);
57 } 110 }
58} 111}
59 112
113OlyServerSocket::~OlyServerSocket() {
114 if (mFDServer > 0) {
115 CLOSE_SOCKET(mFDServer);
116 }
117}
118
60void OlySocket::shutdownConnection() { 119void OlySocket::shutdownConnection() {
61 // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions 120 // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions
62 shutdown(mSocketID, SHUTDOWN_RX_TX); 121 shutdown(mSocketID, SHUTDOWN_RX_TX);
@@ -70,7 +129,7 @@ void OlySocket::closeSocket() {
70 } 129 }
71} 130}
72 131
73void OlySocket::closeServerSocket() { 132void OlyServerSocket::closeServerSocket() {
74 if (CLOSE_SOCKET(mFDServer) != 0) { 133 if (CLOSE_SOCKET(mFDServer) != 0) {
75 logg->logError(__FILE__, __LINE__, "Failed to close server socket."); 134 logg->logError(__FILE__, __LINE__, "Failed to close server socket.");
76 handleException(); 135 handleException();
@@ -78,7 +137,7 @@ void OlySocket::closeServerSocket() {
78 mFDServer = 0; 137 mFDServer = 0;
79} 138}
80 139
81void OlySocket::createClientSocket(char* hostname, int portno) { 140void OlySocket::createClientSocket(const char* hostname, int portno) {
82#ifdef WIN32 141#ifdef WIN32
83 // TODO: Implement for Windows 142 // TODO: Implement for Windows
84#else 143#else
@@ -119,14 +178,7 @@ void OlySocket::createClientSocket(char* hostname, int portno) {
119#endif 178#endif
120} 179}
121 180
122void OlySocket::createSingleServerConnection(int port) { 181void OlyServerSocket::createServerSocket(int port) {
123 createServerSocket(port);
124
125 mSocketID = acceptConnection();
126 closeServerSocket();
127}
128
129void OlySocket::createServerSocket(int port) {
130 int family = AF_INET6; 182 int family = AF_INET6;
131 183
132 // Create socket 184 // Create socket
@@ -169,22 +221,23 @@ void OlySocket::createServerSocket(int port) {
169 221
170// mSocketID is always set to the most recently accepted connection 222// mSocketID is always set to the most recently accepted connection
171// The user of this class should maintain the different socket connections, e.g. by forking the process 223// The user of this class should maintain the different socket connections, e.g. by forking the process
172int OlySocket::acceptConnection() { 224int OlyServerSocket::acceptConnection() {
225 int socketID;
173 if (mFDServer <= 0) { 226 if (mFDServer <= 0) {
174 logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket"); 227 logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
175 handleException(); 228 handleException();
176 } 229 }
177 230
178 // Accept a connection, note that this call blocks until a client connects 231 // Accept a connection, note that this call blocks until a client connects
179 mSocketID = accept(mFDServer, NULL, NULL); 232 socketID = accept(mFDServer, NULL, NULL);
180 if (mSocketID < 0) { 233 if (socketID < 0) {
181 logg->logError(__FILE__, __LINE__, "Socket acceptance failed"); 234 logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
182 handleException(); 235 handleException();
183 } 236 }
184 return mSocketID; 237 return socketID;
185} 238}
186 239
187void OlySocket::send(char* buffer, int size) { 240void OlySocket::send(const char* buffer, int size) {
188 if (size <= 0 || buffer == NULL) { 241 if (size <= 0 || buffer == NULL) {
189 return; 242 return;
190 } 243 }
diff --git a/daemon/OlySocket.h b/daemon/OlySocket.h
index 5bab7d1..eab786b 100644
--- a/daemon/OlySocket.h
+++ b/daemon/OlySocket.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,27 +9,44 @@
9#ifndef __OLY_SOCKET_H__ 9#ifndef __OLY_SOCKET_H__
10#define __OLY_SOCKET_H__ 10#define __OLY_SOCKET_H__
11 11
12#include <string.h>
13
14class OlySocket { 12class OlySocket {
15public: 13public:
16 OlySocket(int port, bool multipleConnections = false); 14 OlySocket(int port, const char* hostname);
17 OlySocket(int port, char* hostname); 15 OlySocket(int socketID);
16#ifndef WIN32
17 OlySocket(const char* path);
18#endif
18 ~OlySocket(); 19 ~OlySocket();
19 int acceptConnection(); 20
20 void closeSocket(); 21 void closeSocket();
21 void closeServerSocket();
22 void shutdownConnection(); 22 void shutdownConnection();
23 void send(char* buffer, int size); 23 void send(const char* buffer, int size);
24 void sendString(const char* string) {send((char*)string, strlen(string));}
25 int receive(char* buffer, int size); 24 int receive(char* buffer, int size);
26 int receiveNBytes(char* buffer, int size); 25 int receiveNBytes(char* buffer, int size);
27 int receiveString(char* buffer, int size); 26 int receiveString(char* buffer, int size);
28 int getSocketID() {return mSocketID;} 27
28 bool isValid() const { return mSocketID >= 0; }
29
30private:
31 int mSocketID;
32
33 void createClientSocket(const char* hostname, int port);
34};
35
36class OlyServerSocket {
37public:
38 OlyServerSocket(int port);
39#ifndef WIN32
40 OlyServerSocket(const char* path);
41#endif
42 ~OlyServerSocket();
43
44 int acceptConnection();
45 void closeServerSocket();
46
29private: 47private:
30 int mSocketID, mFDServer; 48 int mFDServer;
31 void createClientSocket(char* hostname, int port); 49
32 void createSingleServerConnection(int port);
33 void createServerSocket(int port); 50 void createServerSocket(int port);
34}; 51};
35 52
diff --git a/daemon/OlyUtility.cpp b/daemon/OlyUtility.cpp
index 0b22d6e..45340a2 100644
--- a/daemon/OlyUtility.cpp
+++ b/daemon/OlyUtility.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/OlyUtility.h b/daemon/OlyUtility.h
index abab0a5..1d26beb 100644
--- a/daemon/OlyUtility.h
+++ b/daemon/OlyUtility.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/PerfBuffer.cpp b/daemon/PerfBuffer.cpp
new file mode 100644
index 0000000..5fad583
--- /dev/null
+++ b/daemon/PerfBuffer.cpp
@@ -0,0 +1,139 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfBuffer.h"
10
11#include <sys/ioctl.h>
12#include <sys/mman.h>
13
14#include "Buffer.h"
15#include "Logging.h"
16#include "Sender.h"
17#include "SessionData.h"
18
19PerfBuffer::PerfBuffer() {
20 for (int cpu = 0; cpu < ARRAY_LENGTH(mBuf); ++cpu) {
21 mBuf[cpu] = MAP_FAILED;
22 mDiscard[cpu] = false;
23 }
24}
25
26PerfBuffer::~PerfBuffer() {
27 for (int cpu = ARRAY_LENGTH(mBuf) - 1; cpu >= 0; --cpu) {
28 if (mBuf[cpu] != MAP_FAILED) {
29 munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
30 }
31 }
32}
33
34bool PerfBuffer::useFd(const int cpu, const int fd, const int groupFd) {
35 if (fd == groupFd) {
36 if (mBuf[cpu] != MAP_FAILED) {
37 logg->logMessage("%s(%s:%i): cpu %i already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__, cpu);
38 return false;
39 }
40
41 // The buffer isn't mapped yet
42 mBuf[cpu] = mmap(NULL, gSessionData->mPageSize + BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
43 if (mBuf[cpu] == MAP_FAILED) {
44 logg->logMessage("%s(%s:%i): mmap failed", __FUNCTION__, __FILE__, __LINE__);
45 return false;
46 }
47
48 // Check the version
49 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
50 if (pemp->compat_version != 0) {
51 logg->logMessage("%s(%s:%i): Incompatible perf_event_mmap_page compat_version", __FUNCTION__, __FILE__, __LINE__);
52 return false;
53 }
54 } else {
55 if (mBuf[cpu] == MAP_FAILED) {
56 logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
57 return false;
58 }
59
60 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, groupFd) < 0) {
61 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
62 return false;
63 }
64 }
65
66 return true;
67}
68
69void PerfBuffer::discard(const int cpu) {
70 if (mBuf[cpu] != MAP_FAILED) {
71 mDiscard[cpu] = true;
72 }
73}
74
75bool PerfBuffer::isEmpty() {
76 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
77 if (mBuf[cpu] != MAP_FAILED) {
78 // Take a snapshot of the positions
79 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
80 const __u64 head = pemp->data_head;
81 const __u64 tail = pemp->data_tail;
82
83 if (head != tail) {
84 return false;
85 }
86 }
87 }
88
89 return true;
90}
91
92bool PerfBuffer::send(Sender *const sender) {
93 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
94 if (mBuf[cpu] == MAP_FAILED) {
95 continue;
96 }
97
98 // Take a snapshot of the positions
99 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
100 const __u64 head = pemp->data_head;
101 const __u64 tail = pemp->data_tail;
102
103 if (head > tail) {
104 const uint8_t *const b = static_cast<uint8_t *>(mBuf[cpu]) + gSessionData->mPageSize;
105 const int offset = gSessionData->mLocalCapture ? 1 : 0;
106 unsigned char header[7];
107 header[0] = RESPONSE_APC_DATA;
108 Buffer::writeLEInt(header + 1, head - tail + sizeof(header) - 5);
109 // Should use real packing functions
110 header[5] = FRAME_PERF;
111 header[6] = cpu;
112
113 // Write header
114 sender->writeData(reinterpret_cast<const char *>(&header) + offset, sizeof(header) - offset, RESPONSE_APC_DATA);
115
116 // Write data
117 if ((head & ~BUF_MASK) == (tail & ~BUF_MASK)) {
118 // Not wrapped
119 sender->writeData(reinterpret_cast<const char *>(b + (tail & BUF_MASK)), head - tail, RESPONSE_APC_DATA);
120 } else {
121 // Wrapped
122 sender->writeData(reinterpret_cast<const char *>(b + (tail & BUF_MASK)), BUF_SIZE - (tail & BUF_MASK), RESPONSE_APC_DATA);
123 sender->writeData(reinterpret_cast<const char *>(b), head & BUF_MASK, RESPONSE_APC_DATA);
124 }
125
126 // Update tail with the data read
127 pemp->data_tail = head;
128 }
129
130 if (mDiscard[cpu]) {
131 munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
132 mBuf[cpu] = MAP_FAILED;
133 mDiscard[cpu] = false;
134 logg->logMessage("%s(%s:%i): Unmaped cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
135 }
136 }
137
138 return true;
139}
diff --git a/daemon/PerfBuffer.h b/daemon/PerfBuffer.h
new file mode 100644
index 0000000..278a3b9
--- /dev/null
+++ b/daemon/PerfBuffer.h
@@ -0,0 +1,39 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERF_BUFFER
10#define PERF_BUFFER
11
12#include "Config.h"
13
14#define BUF_SIZE (gSessionData->mTotalBufferSize * 1024 * 1024)
15#define BUF_MASK (BUF_SIZE - 1)
16
17class Sender;
18
19class PerfBuffer {
20public:
21 PerfBuffer();
22 ~PerfBuffer();
23
24 bool useFd(const int cpu, const int fd, const int groupFd);
25 void discard(const int cpu);
26 bool isEmpty();
27 bool send(Sender *const sender);
28
29private:
30 void *mBuf[NR_CPUS];
31 // After the buffer is flushed it should be unmaped
32 bool mDiscard[NR_CPUS];
33
34 // Intentionally undefined
35 PerfBuffer(const PerfBuffer &);
36 PerfBuffer &operator=(const PerfBuffer &);
37};
38
39#endif // PERF_BUFFER
diff --git a/daemon/PerfDriver.cpp b/daemon/PerfDriver.cpp
new file mode 100644
index 0000000..8e25c22
--- /dev/null
+++ b/daemon/PerfDriver.cpp
@@ -0,0 +1,355 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfDriver.h"
10
11#include <dirent.h>
12#include <sys/utsname.h>
13#include <time.h>
14
15#include "Buffer.h"
16#include "Config.h"
17#include "ConfigurationXML.h"
18#include "Counter.h"
19#include "DriverSource.h"
20#include "DynBuf.h"
21#include "Logging.h"
22#include "PerfGroup.h"
23#include "SessionData.h"
24
25#define PERF_DEVICES "/sys/bus/event_source/devices"
26
27#define TYPE_DERIVED ~0U
28
29// From gator.h
30struct gator_cpu {
31 const int cpuid;
32 // Human readable name
33 const char core_name[32];
34 // gatorfs event and Perf PMU name
35 const char *const pmnc_name;
36 const int pmnc_counters;
37};
38
39// From gator_main.c
40static const struct gator_cpu gator_cpus[] = {
41 { 0xb36, "ARM1136", "ARM_ARM11", 3 },
42 { 0xb56, "ARM1156", "ARM_ARM11", 3 },
43 { 0xb76, "ARM1176", "ARM_ARM11", 3 },
44 { 0xb02, "ARM11MPCore", "ARM_ARM11MPCore", 3 },
45 { 0xc05, "Cortex-A5", "ARMv7_Cortex_A5", 2 },
46 { 0xc07, "Cortex-A7", "ARMv7_Cortex_A7", 4 },
47 { 0xc08, "Cortex-A8", "ARMv7_Cortex_A8", 4 },
48 { 0xc09, "Cortex-A9", "ARMv7_Cortex_A9", 6 },
49 { 0xc0d, "Cortex-A12", "ARMv7_Cortex_A12", 6 },
50 { 0xc0f, "Cortex-A15", "ARMv7_Cortex_A15", 6 },
51 { 0xc0e, "Cortex-A17", "ARMv7_Cortex_A17", 6 },
52 { 0x00f, "Scorpion", "Scorpion", 4 },
53 { 0x02d, "ScorpionMP", "ScorpionMP", 4 },
54 { 0x049, "KraitSIM", "Krait", 4 },
55 { 0x04d, "Krait", "Krait", 4 },
56 { 0x06f, "Krait S4 Pro", "Krait", 4 },
57 { 0xd03, "Cortex-A53", "ARM_Cortex-A53", 6 },
58 { 0xd07, "Cortex-A57", "ARM_Cortex-A57", 6 },
59 { 0xd0f, "AArch64", "ARM_AArch64", 6 },
60};
61
62static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
63static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_";
64
65class PerfCounter {
66public:
67 PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false) {}
68 ~PerfCounter() {
69 delete [] mName;
70 }
71
72 PerfCounter *getNext() const { return mNext; }
73 const char *getName() const { return mName; }
74 uint32_t getType() const { return mType; }
75 int getCount() const { return mCount; }
76 void setCount(const int count) { mCount = count; }
77 int getKey() const { return mKey; }
78 uint64_t getConfig() const { return mConfig; }
79 void setConfig(const uint64_t config) { mConfig = config; }
80 bool isEnabled() const { return mEnabled; }
81 void setEnabled(const bool enabled) { mEnabled = enabled; }
82
83private:
84 PerfCounter *const mNext;
85 const char *const mName;
86 const uint32_t mType;
87 int mCount;
88 const int mKey;
89 uint64_t mConfig;
90 bool mEnabled;
91};
92
93PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false) {
94}
95
96PerfDriver::~PerfDriver() {
97 while (mCounters != NULL) {
98 PerfCounter *counter = mCounters;
99 mCounters = counter->getNext();
100 delete counter;
101 }
102}
103
104void PerfDriver::addCpuCounters(const char *const counterName, const int type, const int numCounters) {
105 int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
106 char *name = new char[len];
107 snprintf(name, len, "%s_ccnt", counterName);
108 mCounters = new PerfCounter(mCounters, name, type, -1);
109
110 for (int j = 0; j < numCounters; ++j) {
111 len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
112 name = new char[len];
113 snprintf(name, len, "%s_cnt%d", counterName, j);
114 mCounters = new PerfCounter(mCounters, name, type, -1);
115 }
116}
117
118// From include/generated/uapi/linux/version.h
119#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
120
121bool PerfDriver::setup() {
122 // Check the kernel version
123 struct utsname utsname;
124 if (uname(&utsname) != 0) {
125 logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
126 return false;
127 }
128
129 int release[3] = { 0, 0, 0 };
130 int part = 0;
131 char *ch = utsname.release;
132 while (*ch >= '0' && *ch <= '9' && part < ARRAY_LENGTH(release)) {
133 release[part] = 10*release[part] + *ch - '0';
134
135 ++ch;
136 if (*ch == '.') {
137 ++part;
138 ++ch;
139 }
140 }
141
142 if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0)) {
143 logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__);
144 return false;
145 }
146
147 // Add supported PMUs
148 bool foundCpu = false;
149 DIR *dir = opendir(PERF_DEVICES);
150 if (dir == NULL) {
151 logg->logMessage("%s(%s:%i): opendif failed", __FUNCTION__, __FILE__, __LINE__);
152 return false;
153 }
154
155 struct dirent *dirent;
156 while ((dirent = readdir(dir)) != NULL) {
157 for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
158 // Do the names match exactly?
159 if (strcmp(dirent->d_name, gator_cpus[i].pmnc_name) != 0 &&
160 // Do these names match but have the old vs new prefix?
161 (strncmp(dirent->d_name, OLD_PMU_PREFIX, sizeof(OLD_PMU_PREFIX) - 1) != 0 ||
162 strncmp(gator_cpus[i].pmnc_name, NEW_PMU_PREFIX, sizeof(NEW_PMU_PREFIX) - 1) != 0 ||
163 strcmp(dirent->d_name + sizeof(OLD_PMU_PREFIX) - 1, gator_cpus[i].pmnc_name + sizeof(NEW_PMU_PREFIX) - 1) != 0)) {
164 continue;
165 }
166
167 int type;
168 char buf[256];
169 snprintf(buf, sizeof(buf), PERF_DEVICES "/%s/type", dirent->d_name);
170 if (DriverSource::readIntDriver(buf, &type) != 0) {
171 continue;
172 }
173
174 foundCpu = true;
175 addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters);
176 }
177 }
178 closedir(dir);
179
180 if (!foundCpu) {
181 // If no cpu was found based on pmu names, try by cpuid
182 for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
183 if (gSessionData->mMaxCpuId != gator_cpus[i].cpuid) {
184 continue;
185 }
186
187 foundCpu = true;
188 addCpuCounters(gator_cpus[i].pmnc_name, PERF_TYPE_RAW, gator_cpus[i].pmnc_counters);
189 }
190 }
191
192 /*
193 if (!foundCpu) {
194 // If all else fails, use the perf architected counters
195 // 9 because that's how many are in events-Perf-Hardware.xml - assume they can all be enabled at once
196 addCpuCounters("Perf_Hardware", PERF_TYPE_HARDWARE, 9);
197 }
198 */
199
200 // Add supported software counters
201 long long id;
202 DynBuf printb;
203
204 id = getTracepointId("irq/softirq_exit", &printb);
205 if (id >= 0) {
206 mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id);
207 }
208
209 id = getTracepointId("irq/irq_handler_exit", &printb);
210 if (id >= 0) {
211 mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id);
212 }
213
214 //Linux_block_rq_wr
215 //Linux_block_rq_rd
216 //Linux_net_rx
217 //Linux_net_tx
218
219 id = getTracepointId(SCHED_SWITCH, &printb);
220 if (id >= 0) {
221 mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id);
222 }
223
224 //Linux_meminfo_memused
225 //Linux_meminfo_memfree
226 //Linux_meminfo_bufferram
227 //Linux_power_cpu_freq
228 //Linux_power_cpu_idle
229
230 mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1);
231
232 //Linux_cpu_wait_io
233
234 mIsSetup = true;
235 return true;
236}
237
238bool PerfDriver::summary(Buffer *const buffer) {
239 struct utsname utsname;
240 if (uname(&utsname) != 0) {
241 logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
242 return false;
243 }
244
245 char buf[512];
246 snprintf(buf, sizeof(buf), "%s %s %s %s %s GNU/Linux", utsname.sysname, utsname.nodename, utsname.release, utsname.version, utsname.machine);
247
248 struct timespec ts;
249 if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
250 logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__);
251 return false;
252 }
253 const int64_t timestamp = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec;
254
255 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
256 logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__);
257 return false;
258 }
259 const int64_t uptime = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec;
260
261 buffer->summary(timestamp, uptime, 0, buf);
262
263 for (int i = 0; i < gSessionData->mCores; ++i) {
264 int j;
265 for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) {
266 if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) {
267 break;
268 }
269 }
270 if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) {
271 buffer->coreName(i, gSessionData->mCpuIds[i], gator_cpus[j].core_name);
272 } else {
273 snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]);
274 buffer->coreName(i, gSessionData->mCpuIds[i], buf);
275 }
276 }
277 buffer->commit(1);
278
279 return true;
280}
281
282PerfCounter *PerfDriver::findCounter(const Counter &counter) const {
283 for (PerfCounter * perfCounter = mCounters; perfCounter != NULL; perfCounter = perfCounter->getNext()) {
284 if (strcmp(perfCounter->getName(), counter.getType()) == 0) {
285 return perfCounter;
286 }
287 }
288
289 return NULL;
290}
291
292bool PerfDriver::claimCounter(const Counter &counter) const {
293 return findCounter(counter) != NULL;
294}
295
296void PerfDriver::resetCounters() {
297 for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
298 counter->setEnabled(false);
299 }
300}
301
302void PerfDriver::setupCounter(Counter &counter) {
303 PerfCounter *const perfCounter = findCounter(counter);
304 if (perfCounter == NULL) {
305 counter.setEnabled(false);
306 return;
307 }
308
309 // Don't use the config from counters XML if it's not set, ex: software counters
310 if (counter.getEvent() != -1) {
311 perfCounter->setConfig(counter.getEvent());
312 }
313 perfCounter->setCount(counter.getCount());
314 perfCounter->setEnabled(true);
315 counter.setKey(perfCounter->getKey());
316}
317
318int PerfDriver::writeCounters(mxml_node_t *root) const {
319 int count = 0;
320 for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
321 mxml_node_t *node = mxmlNewElement(root, "counter");
322 mxmlElementSetAttr(node, "name", counter->getName());
323 ++count;
324 }
325
326 return count;
327}
328
329bool PerfDriver::enable(PerfGroup *group, Buffer *const buffer) const {
330 for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
331 if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
332 if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), 0, 0)) {
333 logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__);
334 return false;
335 }
336 }
337 }
338
339 return true;
340}
341
342long long PerfDriver::getTracepointId(const char *const name, DynBuf *const printb) {
343 if (!printb->printf(EVENTS_PATH "/%s/id", name)) {
344 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
345 return -1;
346 }
347
348 int64_t result;
349 if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) {
350 logg->logMessage("%s(%s:%i): DriverSource::readInt64Driver failed", __FUNCTION__, __FILE__, __LINE__);
351 return -1;
352 }
353
354 return result;
355}
diff --git a/daemon/PerfDriver.h b/daemon/PerfDriver.h
new file mode 100644
index 0000000..3181b74
--- /dev/null
+++ b/daemon/PerfDriver.h
@@ -0,0 +1,56 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERFDRIVER_H
10#define PERFDRIVER_H
11
12#include "Driver.h"
13
14// If debugfs is not mounted at /sys/kernel/debug, update DEBUGFS_PATH
15#define DEBUGFS_PATH "/sys/kernel/debug"
16#define EVENTS_PATH DEBUGFS_PATH "/tracing/events"
17
18#define SCHED_SWITCH "sched/sched_switch"
19
20class Buffer;
21class DynBuf;
22class PerfCounter;
23class PerfGroup;
24
25class PerfDriver : public Driver {
26public:
27 PerfDriver();
28 ~PerfDriver();
29
30 bool setup();
31 bool summary(Buffer *const buffer);
32 bool isSetup() const { return mIsSetup; }
33
34 bool claimCounter(const Counter &counter) const;
35 void resetCounters();
36 void setupCounter(Counter &counter);
37
38 int writeCounters(mxml_node_t *root) const;
39
40 bool enable(PerfGroup *group, Buffer *const buffer) const;
41
42 static long long getTracepointId(const char *const name, DynBuf *const printb);
43
44private:
45 PerfCounter *findCounter(const Counter &counter) const;
46 void addCpuCounters(const char *const counterName, const int type, const int numCounters);
47
48 PerfCounter *mCounters;
49 bool mIsSetup;
50
51 // Intentionally undefined
52 PerfDriver(const PerfDriver &);
53 PerfDriver &operator=(const PerfDriver &);
54};
55
56#endif // PERFDRIVER_H
diff --git a/daemon/PerfGroup.cpp b/daemon/PerfGroup.cpp
new file mode 100644
index 0000000..faf5fca
--- /dev/null
+++ b/daemon/PerfGroup.cpp
@@ -0,0 +1,206 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfGroup.h"
10
11#include <errno.h>
12#include <string.h>
13#include <sys/ioctl.h>
14#include <sys/syscall.h>
15#include <unistd.h>
16
17#include "Buffer.h"
18#include "Logging.h"
19#include "Monitor.h"
20#include "PerfBuffer.h"
21#include "SessionData.h"
22
23#define DEFAULT_PEA_ARGS(pea, additionalSampleType) \
24 pea.size = sizeof(pea); \
25 /* Emit time, read_format below, group leader id, and raw tracepoint info */ \
26 pea.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER | additionalSampleType; \
27 /* Emit emit value in group format */ \
28 pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP; \
29 /* start out disabled */ \
30 pea.disabled = 1; \
31 /* have a sampling interrupt happen when we cross the wakeup_watermark boundary */ \
32 pea.watermark = 1; \
33 /* Be conservative in flush size as only one buffer set is monitored */ \
34 pea.wakeup_watermark = 3 * BUF_SIZE / 4
35
36static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t pid, const int cpu, const int group_fd, const unsigned long flags) {
37 return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
38}
39
40PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) {
41 memset(&mAttrs, 0, sizeof(mAttrs));
42 memset(&mKeys, -1, sizeof(mKeys));
43 memset(&mFds, -1, sizeof(mFds));
44}
45
46PerfGroup::~PerfGroup() {
47 for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
48 if (mFds[pos] >= 0) {
49 close(mFds[pos]);
50 }
51 }
52}
53
54bool PerfGroup::add(Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) {
55 int i;
56 for (i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
57 if (mKeys[i] < 0) {
58 break;
59 }
60 }
61
62 if (i >= ARRAY_LENGTH(mKeys)) {
63 logg->logMessage("%s(%s:%i): Too many counters", __FUNCTION__, __FILE__, __LINE__);
64 return false;
65 }
66
67 DEFAULT_PEA_ARGS(mAttrs[i], sampleType);
68 mAttrs[i].type = type;
69 mAttrs[i].config = config;
70 mAttrs[i].sample_period = sample;
71 // always be on the CPU but only a group leader can be pinned
72 mAttrs[i].pinned = (i == 0 ? 1 : 0);
73 mAttrs[i].mmap = (flags & PERF_GROUP_MMAP ? 1 : 0);
74 mAttrs[i].comm = (flags & PERF_GROUP_COMM ? 1 : 0);
75 mAttrs[i].freq = (flags & PERF_GROUP_FREQ ? 1 : 0);
76 mAttrs[i].task = (flags & PERF_GROUP_TASK ? 1 : 0);
77 mAttrs[i].sample_id_all = (flags & PERF_GROUP_SAMPLE_ID_ALL ? 1 : 0);
78
79 mKeys[i] = key;
80
81 buffer->pea(&mAttrs[i], key);
82
83 return true;
84}
85
86bool PerfGroup::prepareCPU(const int cpu) {
87 logg->logMessage("%s(%s:%i): Onlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
88
89 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
90 if (mKeys[i] < 0) {
91 continue;
92 }
93
94 const int offset = i * gSessionData->mCores;
95 if (mFds[cpu + offset] >= 0) {
96 logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
97 return false;
98 }
99
100 logg->logMessage("%s(%s:%i): perf_event_open cpu: %i type: %lli config: %lli sample: %lli sample_type: %lli", __FUNCTION__, __FILE__, __LINE__, cpu, (long long)mAttrs[i].type, (long long)mAttrs[i].config, (long long)mAttrs[i].sample_period, (long long)mAttrs[i].sample_type);
101 mFds[cpu + offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, i == 0 ? -1 : mFds[cpu], i == 0 ? 0 : PERF_FLAG_FD_OUTPUT);
102 if (mFds[cpu + offset] < 0) {
103 logg->logMessage("%s(%s:%i): failed %s", __FUNCTION__, __FILE__, __LINE__, strerror(errno));
104 continue;
105 }
106
107 if (!mPb->useFd(cpu, mFds[cpu + offset], mFds[cpu])) {
108 logg->logMessage("%s(%s:%i): PerfBuffer::useFd failed", __FUNCTION__, __FILE__, __LINE__);
109 return false;
110 }
111 }
112
113 return true;
114}
115
116int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor) {
117 __u64 ids[ARRAY_LENGTH(mKeys)];
118 int coreKeys[ARRAY_LENGTH(mKeys)];
119 int idCount = 0;
120
121 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
122 const int fd = mFds[cpu + i * gSessionData->mCores];
123 if (fd < 0) {
124 continue;
125 }
126
127 coreKeys[idCount] = mKeys[i];
128 if (ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0) {
129 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
130 return false;
131 }
132 ++idCount;
133 }
134
135 if (!monitor->add(mFds[cpu])) {
136 logg->logMessage("%s(%s:%i): Monitor::add failed", __FUNCTION__, __FILE__, __LINE__);
137 return false;
138 }
139
140 buffer->keys(idCount, ids, coreKeys);
141
142 if (start) {
143 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
144 int offset = i * gSessionData->mCores + cpu;
145 if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_ENABLE) < 0) {
146 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
147 return false;
148 }
149 }
150 }
151
152 return idCount;
153}
154
155bool PerfGroup::offlineCPU(const int cpu) {
156 logg->logMessage("%s(%s:%i): Offlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
157
158 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
159 int offset = i * gSessionData->mCores + cpu;
160 if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_DISABLE) < 0) {
161 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
162 return false;
163 }
164 }
165
166 // Mark the buffer so that it will be released next time it's read
167 mPb->discard(cpu);
168
169 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
170 if (mKeys[i] < 0) {
171 continue;
172 }
173
174 int offset = i * gSessionData->mCores + cpu;
175 if (mFds[offset] >= 0) {
176 close(mFds[offset]);
177 mFds[offset] = -1;
178 }
179 }
180
181 return true;
182}
183
184bool PerfGroup::start() {
185 for (int pos = 0; pos < ARRAY_LENGTH(mFds); ++pos) {
186 if (mFds[pos] >= 0 && ioctl(mFds[pos], PERF_EVENT_IOC_ENABLE) < 0) {
187 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
188 goto fail;
189 }
190 }
191
192 return true;
193
194 fail:
195 stop();
196
197 return false;
198}
199
200void PerfGroup::stop() {
201 for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
202 if (mFds[pos] >= 0) {
203 ioctl(mFds[pos], PERF_EVENT_IOC_DISABLE);
204 }
205 }
206}
diff --git a/daemon/PerfGroup.h b/daemon/PerfGroup.h
new file mode 100644
index 0000000..af496d4
--- /dev/null
+++ b/daemon/PerfGroup.h
@@ -0,0 +1,55 @@
1 /**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERF_GROUP
10#define PERF_GROUP
11
12// Use a snapshot of perf_event.h as it may be more recent than what is on the target and if not newer features won't be supported anyways
13#include "k/perf_event.h"
14
15#include "Config.h"
16
17class Buffer;
18class Monitor;
19class PerfBuffer;
20
21enum PerfGroupFlags {
22 PERF_GROUP_MMAP = 1 << 0,
23 PERF_GROUP_COMM = 1 << 1,
24 PERF_GROUP_FREQ = 1 << 2,
25 PERF_GROUP_TASK = 1 << 3,
26 PERF_GROUP_SAMPLE_ID_ALL = 1 << 4,
27};
28
29class PerfGroup {
30public:
31 PerfGroup(PerfBuffer *const pb);
32 ~PerfGroup();
33
34 bool add(Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags);
35 // Safe to call concurrently
36 bool prepareCPU(const int cpu);
37 // Not safe to call concurrently. Returns the number of events enabled
38 int onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor);
39 bool offlineCPU(int cpu);
40 bool start();
41 void stop();
42
43private:
44 // +1 for the group leader
45 struct perf_event_attr mAttrs[MAX_PERFORMANCE_COUNTERS + 1];
46 int mKeys[MAX_PERFORMANCE_COUNTERS + 1];
47 int mFds[NR_CPUS * (MAX_PERFORMANCE_COUNTERS + 1)];
48 PerfBuffer *const mPb;
49
50 // Intentionally undefined
51 PerfGroup(const PerfGroup &);
52 PerfGroup &operator=(const PerfGroup &);
53};
54
55#endif // PERF_GROUP
diff --git a/daemon/PerfSource.cpp b/daemon/PerfSource.cpp
new file mode 100644
index 0000000..1f1cb19
--- /dev/null
+++ b/daemon/PerfSource.cpp
@@ -0,0 +1,271 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfSource.h"
10
11#include <errno.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "Child.h"
16#include "DynBuf.h"
17#include "Logging.h"
18#include "PerfDriver.h"
19#include "Proc.h"
20#include "SessionData.h"
21
22#define MS_PER_US 1000000
23
24extern Child *child;
25
26static bool sendTracepointFormat(Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
27 if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
28 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
29 return false;
30 }
31 if (!b->read(printb->getBuf())) {
32 logg->logMessage("%s(%s:%i): DynBuf::read failed", __FUNCTION__, __FILE__, __LINE__);
33 return false;
34 }
35 buffer->format(b->getLength(), b->getBuf());
36
37 return true;
38}
39
40PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(0, FRAME_PERF_ATTRS, 1024*1024, senderSem), mCountersBuf(), mCountersGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) {
41 long l = sysconf(_SC_PAGE_SIZE);
42 if (l < 0) {
43 logg->logError(__FILE__, __LINE__, "Unable to obtain the page size");
44 handleException();
45 }
46 gSessionData->mPageSize = static_cast<int>(l);
47
48 l = sysconf(_SC_NPROCESSORS_CONF);
49 if (l < 0) {
50 logg->logError(__FILE__, __LINE__, "Unable to obtain the number of cores");
51 handleException();
52 }
53 gSessionData->mCores = static_cast<int>(l);
54}
55
56PerfSource::~PerfSource() {
57}
58
59struct PrepareParallelArgs {
60 PerfGroup *pg;
61 int cpu;
62};
63
64void *prepareParallel(void *arg) {
65 const PrepareParallelArgs *const args = (PrepareParallelArgs *)arg;
66 args->pg->prepareCPU(args->cpu);
67 return NULL;
68}
69
70bool PerfSource::prepare() {
71 DynBuf printb;
72 DynBuf b1;
73 DynBuf b2;
74 DynBuf b3;
75 long long schedSwitchId;
76
77 if (0
78 || !mMonitor.init()
79 || !mUEvent.init()
80 || !mMonitor.add(mUEvent.getFd())
81
82 || (schedSwitchId = PerfDriver::getTracepointId(SCHED_SWITCH, &printb)) < 0
83 || !sendTracepointFormat(&mBuffer, SCHED_SWITCH, &printb, &b1)
84
85 // Only want RAW but not IP on sched_switch and don't want TID on SAMPLE_ID
86 || !mCountersGroup.add(&mBuffer, 100/**/, PERF_TYPE_TRACEPOINT, schedSwitchId, 1, PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL)
87
88 // Only want TID and IP but not RAW on timer
89 || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(&mBuffer, 99/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, 0))
90
91 || !gSessionData->perf.enable(&mCountersGroup, &mBuffer)
92 || 0) {
93 logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.12 or later?", __FUNCTION__, __FILE__, __LINE__);
94 return false;
95 }
96
97 if (!gSessionData->perf.summary(&mSummary)) {
98 logg->logMessage("%s(%s:%i): PerfDriver::summary failed", __FUNCTION__, __FILE__, __LINE__);
99 return false;
100 }
101
102 {
103 // Run prepareCPU in parallel as perf_event_open can take more than 1 sec in some cases
104 pthread_t threads[NR_CPUS];
105 PrepareParallelArgs args[NR_CPUS];
106 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
107 args[cpu].pg = &mCountersGroup;
108 args[cpu].cpu = cpu;
109 if (pthread_create(&threads[cpu], NULL, prepareParallel, &args[cpu]) != 0) {
110 logg->logMessage("%s(%s:%i): pthread_create failed", __FUNCTION__, __FILE__, __LINE__);
111 return false;
112 }
113 }
114 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
115 if (pthread_join(threads[cpu], NULL) != 0) {
116 logg->logMessage("%s(%s:%i): pthread_join failed", __FUNCTION__, __FILE__, __LINE__);
117 return false;
118 }
119 }
120 }
121
122 int numEvents = 0;
123 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
124 numEvents += mCountersGroup.onlineCPU(cpu, false, &mBuffer, &mMonitor);
125 }
126 if (numEvents <= 0) {
127 logg->logMessage("%s(%s:%i): PerfGroup::onlineCPU failed on all cores", __FUNCTION__, __FILE__, __LINE__);
128 return false;
129 }
130
131 // Start events before reading proc to avoid race conditions
132 if (!mCountersGroup.start()) {
133 logg->logMessage("%s(%s:%i): PerfGroup::start failed", __FUNCTION__, __FILE__, __LINE__);
134 return false;
135 }
136
137 if (!readProc(&mBuffer, &printb, &b1, &b2, &b3)) {
138 logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__);
139 return false;
140 }
141
142 mBuffer.commit(1);
143
144 return true;
145}
146
147static const char CPU_DEVPATH[] = "/devices/system/cpu/cpu";
148
149void PerfSource::run() {
150 int pipefd[2];
151
152 if (pipe(pipefd) != 0) {
153 logg->logError(__FILE__, __LINE__, "pipe failed");
154 handleException();
155 }
156 mInterruptFd = pipefd[1];
157
158 if (!mMonitor.add(pipefd[0])) {
159 logg->logError(__FILE__, __LINE__, "Monitor::add failed");
160 handleException();
161 }
162
163 int timeout = -1;
164 if (gSessionData->mLiveRate > 0) {
165 timeout = gSessionData->mLiveRate/MS_PER_US;
166 }
167
168 sem_post(mStartProfile);
169
170 while (gSessionData->mSessionIsActive) {
171 // +1 for uevents, +1 for pipe
172 struct epoll_event events[NR_CPUS + 2];
173 int ready = mMonitor.wait(events, ARRAY_LENGTH(events), timeout);
174 if (ready < 0) {
175 logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
176 handleException();
177 }
178
179 for (int i = 0; i < ready; ++i) {
180 if (events[i].data.fd == mUEvent.getFd()) {
181 if (!handleUEvent()) {
182 logg->logError(__FILE__, __LINE__, "PerfSource::handleUEvent failed");
183 handleException();
184 }
185 break;
186 }
187 }
188
189 // send a notification that data is ready
190 sem_post(mSenderSem);
191
192 // In one shot mode, stop collection once all the buffers are filled
193 // Assume timeout == 0 in this case
194 if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
195 logg->logMessage("%s(%s:%i): One shot", __FUNCTION__, __FILE__, __LINE__);
196 child->endSession();
197 }
198 }
199
200 mCountersGroup.stop();
201 mBuffer.setDone();
202 mIsDone = true;
203
204 // send a notification that data is ready
205 sem_post(mSenderSem);
206
207 mInterruptFd = -1;
208 close(pipefd[0]);
209 close(pipefd[1]);
210}
211
212bool PerfSource::handleUEvent() {
213 UEventResult result;
214 if (!mUEvent.read(&result)) {
215 logg->logMessage("%s(%s:%i): UEvent::Read failed", __FUNCTION__, __FILE__, __LINE__);
216 return false;
217 }
218
219 if (strcmp(result.mSubsystem, "cpu") == 0) {
220 if (strncmp(result.mDevPath, CPU_DEVPATH, sizeof(CPU_DEVPATH) - 1) != 0) {
221 logg->logMessage("%s(%s:%i): Unexpected cpu DEVPATH format", __FUNCTION__, __FILE__, __LINE__);
222 return false;
223 }
224 char *endptr;
225 errno = 0;
226 int cpu = strtol(result.mDevPath + sizeof(CPU_DEVPATH) - 1, &endptr, 10);
227 if (errno != 0 || *endptr != '\0') {
228 logg->logMessage("%s(%s:%i): strtol failed", __FUNCTION__, __FILE__, __LINE__);
229 return false;
230 }
231 if (strcmp(result.mAction, "online") == 0) {
232 // Only call onlineCPU if prepareCPU succeeded
233 const bool result = mCountersGroup.prepareCPU(cpu) &&
234 mCountersGroup.onlineCPU(cpu, true, &mBuffer, &mMonitor);
235 mBuffer.commit(1);
236 return result;
237 } else if (strcmp(result.mAction, "offline") == 0) {
238 return mCountersGroup.offlineCPU(cpu);
239 }
240 }
241
242 return true;
243}
244
245void PerfSource::interrupt() {
246 if (mInterruptFd >= 0) {
247 int8_t c = 0;
248 // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread
249 if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) {
250 logg->logError(__FILE__, __LINE__, "write failed");
251 handleException();
252 }
253 }
254}
255
256bool PerfSource::isDone () {
257 return mBuffer.isDone() && mIsDone && mCountersBuf.isEmpty();
258}
259
260void PerfSource::write (Sender *sender) {
261 if (!mSummary.isDone()) {
262 mSummary.write(sender);
263 }
264 if (!mBuffer.isDone()) {
265 mBuffer.write(sender);
266 }
267 if (!mCountersBuf.send(sender)) {
268 logg->logError(__FILE__, __LINE__, "PerfBuffer::send failed");
269 handleException();
270 }
271}
diff --git a/daemon/PerfSource.h b/daemon/PerfSource.h
new file mode 100644
index 0000000..3f471c8
--- /dev/null
+++ b/daemon/PerfSource.h
@@ -0,0 +1,54 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERFSOURCE_H
10#define PERFSOURCE_H
11
12#include <semaphore.h>
13
14#include "Buffer.h"
15#include "Monitor.h"
16#include "PerfBuffer.h"
17#include "PerfGroup.h"
18#include "Source.h"
19#include "UEvent.h"
20
21class Sender;
22
23class PerfSource : public Source {
24public:
25 PerfSource(sem_t *senderSem, sem_t *startProfile);
26 ~PerfSource();
27
28 bool prepare();
29 void run();
30 void interrupt();
31
32 bool isDone();
33 void write(Sender *sender);
34
35private:
36 bool handleUEvent();
37
38 Buffer mSummary;
39 Buffer mBuffer;
40 PerfBuffer mCountersBuf;
41 PerfGroup mCountersGroup;
42 Monitor mMonitor;
43 UEvent mUEvent;
44 sem_t *const mSenderSem;
45 sem_t *const mStartProfile;
46 int mInterruptFd;
47 bool mIsDone;
48
49 // Intentionally undefined
50 PerfSource(const PerfSource &);
51 PerfSource &operator=(const PerfSource &);
52};
53
54#endif // PERFSOURCE_H
diff --git a/daemon/Proc.cpp b/daemon/Proc.cpp
new file mode 100644
index 0000000..e0b9e22
--- /dev/null
+++ b/daemon/Proc.cpp
@@ -0,0 +1,179 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Proc.h"
10
11#include <dirent.h>
12#include <errno.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include "Buffer.h"
18#include "DynBuf.h"
19#include "Logging.h"
20
21struct ProcStat {
22 // From linux-dev/include/linux/sched.h
23#define TASK_COMM_LEN 16
24 // TASK_COMM_LEN may grow, so be ready for it to get larger
25 char comm[2*TASK_COMM_LEN];
26 long numThreads;
27};
28
29static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf *const b) {
30 if (!b->read(pathname)) {
31 logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__);
32 // This is not a fatal error - the thread just doesn't exist any more
33 return true;
34 }
35
36 char *comm = strchr(b->getBuf(), '(');
37 if (comm == NULL) {
38 logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
39 return false;
40 }
41 ++comm;
42 char *const str = strrchr(comm, ')');
43 if (str == NULL) {
44 logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
45 return false;
46 }
47 *str = '\0';
48 strncpy(ps->comm, comm, sizeof(ps->comm) - 1);
49 ps->comm[sizeof(ps->comm) - 1] = '\0';
50
51 const int count = sscanf(str + 2, " %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %ld", &ps->numThreads);
52 if (count != 1) {
53 logg->logMessage("%s(%s:%i): sscanf failed", __FUNCTION__, __FILE__, __LINE__);
54 return false;
55 }
56
57 return true;
58}
59
60static bool readProcTask(Buffer *const buffer, const int pid, const char *const image, DynBuf *const printb, DynBuf *const b) {
61 bool result = false;
62
63 if (!b->printf("/proc/%i/task", pid)) {
64 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
65 return result;
66 }
67 DIR *task = opendir(b->getBuf());
68 if (task == NULL) {
69 logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
70 return result;
71 }
72
73 struct dirent *dirent;
74 while ((dirent = readdir(task)) != NULL) {
75 char *endptr;
76 const int tid = strtol(dirent->d_name, &endptr, 10);
77 if (*endptr != '\0') {
78 // Ignore task items that are not integers like ., etc...
79 continue;
80 }
81
82 if (!printb->printf("/proc/%i/task/%i/stat", pid, tid)) {
83 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
84 goto fail;
85 }
86 ProcStat ps;
87 if (!readProcStat(&ps, printb->getBuf(), b)) {
88 logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
89 goto fail;
90 }
91
92 buffer->comm(pid, tid, image, ps.comm);
93 }
94
95 result = true;
96
97 fail:
98 closedir(task);
99
100 return result;
101}
102
103bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) {
104 bool result = false;
105
106 DIR *proc = opendir("/proc");
107 if (proc == NULL) {
108 logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
109 return result;
110 }
111
112 struct dirent *dirent;
113 while ((dirent = readdir(proc)) != NULL) {
114 char *endptr;
115 const int pid = strtol(dirent->d_name, &endptr, 10);
116 if (*endptr != '\0') {
117 // Ignore proc items that are not integers like ., cpuinfo, etc...
118 continue;
119 }
120
121 if (!printb->printf("/proc/%i/stat", pid)) {
122 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
123 goto fail;
124 }
125 ProcStat ps;
126 if (!readProcStat(&ps, printb->getBuf(), b1)) {
127 logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
128 goto fail;
129 }
130
131 if (!printb->printf("/proc/%i/exe", pid)) {
132 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
133 goto fail;
134 }
135 const int err = b1->readlink(printb->getBuf());
136 const char *image;
137 if (err == 0) {
138 image = strrchr(b1->getBuf(), '/');
139 if (image == NULL) {
140 image = b1->getBuf();
141 } else {
142 ++image;
143 }
144 } else if (err == -ENOENT) {
145 // readlink /proc/[pid]/exe returns ENOENT for kernel threads
146 image = "\0";
147 } else {
148 logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__);
149 goto fail;
150 }
151
152 if (!printb->printf("/proc/%i/maps", pid)) {
153 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
154 goto fail;
155 }
156 if (!b2->read(printb->getBuf())) {
157 logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__);
158 // This is not a fatal error - the process just doesn't exist any more
159 continue;
160 }
161
162 buffer->maps(pid, pid, b2->getBuf());
163 if (ps.numThreads <= 1) {
164 buffer->comm(pid, pid, image, ps.comm);
165 } else {
166 if (!readProcTask(buffer, pid, image, printb, b3)) {
167 logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__);
168 goto fail;
169 }
170 }
171 }
172
173 result = true;
174
175 fail:
176 closedir(proc);
177
178 return result;
179}
diff --git a/daemon/Proc.h b/daemon/Proc.h
new file mode 100644
index 0000000..057b610
--- /dev/null
+++ b/daemon/Proc.h
@@ -0,0 +1,17 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PROC_H
10#define PROC_H
11
12class Buffer;
13class DynBuf;
14
15bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3);
16
17#endif // PROC_H
diff --git a/daemon/Sender.cpp b/daemon/Sender.cpp
index 8eb348f..3a981a6 100644
--- a/daemon/Sender.cpp
+++ b/daemon/Sender.cpp
@@ -1,19 +1,18 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <string.h> 9#include "Sender.h"
10#include <sys/socket.h> 10
11#include <netinet/in.h>
12#include <sys/types.h>
13#include <arpa/inet.h>
14#include <stdlib.h> 11#include <stdlib.h>
12#include <string.h>
15#include <unistd.h> 13#include <unistd.h>
16#include "Sender.h" 14
15#include "Buffer.h"
17#include "Logging.h" 16#include "Logging.h"
18#include "OlySocket.h" 17#include "OlySocket.h"
19#include "SessionData.h" 18#include "SessionData.h"
@@ -49,9 +48,12 @@ Sender::Sender(OlySocket* socket) {
49} 48}
50 49
51Sender::~Sender() { 50Sender::~Sender() {
52 delete mDataSocket; 51 // Just close it as the client socket is on the stack
53 mDataSocket = NULL; 52 if (mDataSocket != NULL) {
54 if (mDataFile) { 53 mDataSocket->closeSocket();
54 mDataSocket = NULL;
55 }
56 if (mDataFile != NULL) {
55 fclose(mDataFile); 57 fclose(mDataFile);
56 } 58 }
57} 59}
@@ -95,10 +97,7 @@ void Sender::writeData(const char* data, int length, int type) {
95 // type and length already added by the Collector for apc data 97 // type and length already added by the Collector for apc data
96 unsigned char header[5]; 98 unsigned char header[5];
97 header[0] = type; 99 header[0] = type;
98 header[1] = (length >> 0) & 0xff; 100 Buffer::writeLEInt(header + 1, length);
99 header[2] = (length >> 8) & 0xff;
100 header[3] = (length >> 16) & 0xff;
101 header[4] = (length >> 24) & 0xff;
102 mDataSocket->send((char*)&header, sizeof(header)); 101 mDataSocket->send((char*)&header, sizeof(header));
103 } 102 }
104 103
@@ -106,7 +105,7 @@ void Sender::writeData(const char* data, int length, int type) {
106 const int chunkSize = 100*1000 * alarmDuration / 8; 105 const int chunkSize = 100*1000 * alarmDuration / 8;
107 int pos = 0; 106 int pos = 0;
108 while (true) { 107 while (true) {
109 mDataSocket->send((char*)data + pos, min(length - pos, chunkSize)); 108 mDataSocket->send((const char*)data + pos, min(length - pos, chunkSize));
110 pos += chunkSize; 109 pos += chunkSize;
111 if (pos >= length) { 110 if (pos >= length) {
112 break; 111 break;
diff --git a/daemon/Sender.h b/daemon/Sender.h
index b388f03..4c359db 100644
--- a/daemon/Sender.h
+++ b/daemon/Sender.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp
index cf84407..c169299 100644
--- a/daemon/SessionData.cpp
+++ b/daemon/SessionData.cpp
@@ -1,13 +1,15 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <string.h>
10#include "SessionData.h" 9#include "SessionData.h"
10
11#include <string.h>
12
11#include "SessionXML.h" 13#include "SessionXML.h"
12#include "Logging.h" 14#include "Logging.h"
13 15
@@ -38,6 +40,7 @@ void SessionData::initialize() {
38 mTotalBufferSize = 0; 40 mTotalBufferSize = 0;
39 // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module 41 // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
40 mCores = 1; 42 mCores = 1;
43 mPageSize = 0;
41} 44}
42 45
43void SessionData::parseSessionXML(char* xmlString) { 46void SessionData::parseSessionXML(char* xmlString) {
@@ -88,7 +91,8 @@ void SessionData::parseSessionXML(char* xmlString) {
88void SessionData::readCpuInfo() { 91void SessionData::readCpuInfo() {
89 char temp[256]; // arbitrarily large amount 92 char temp[256]; // arbitrarily large amount
90 strcpy(mCoreName, "unknown"); 93 strcpy(mCoreName, "unknown");
91 mCpuId = -1; 94 memset(&mCpuIds, -1, sizeof(mCpuIds));
95 mMaxCpuId = -1;
92 96
93 FILE* f = fopen("/proc/cpuinfo", "r"); 97 FILE* f = fopen("/proc/cpuinfo", "r");
94 if (f == NULL) { 98 if (f == NULL) {
@@ -98,15 +102,16 @@ void SessionData::readCpuInfo() {
98 } 102 }
99 103
100 bool foundCoreName = false; 104 bool foundCoreName = false;
101 bool foundCpuId = false; 105 int processor = 0;
102 while (fgets(temp, sizeof(temp), f) && (!foundCoreName || !foundCpuId)) { 106 while (fgets(temp, sizeof(temp), f)) {
103 if (strlen(temp) > 0) { 107 if (strlen(temp) > 0) {
104 temp[strlen(temp) - 1] = 0; // Replace the line feed with a null 108 temp[strlen(temp) - 1] = 0; // Replace the line feed with a null
105 } 109 }
106 110
107 const bool foundHardware = strstr(temp, "Hardware") != 0; 111 const bool foundHardware = strstr(temp, "Hardware") != 0;
108 const bool foundCPUPart = strstr(temp, "CPU part") != 0; 112 const bool foundCPUPart = strstr(temp, "CPU part") != 0;
109 if (foundHardware || foundCPUPart) { 113 const bool foundProcessor = strstr(temp, "processor") != 0;
114 if (foundHardware || foundCPUPart || foundProcessor) {
110 char* position = strchr(temp, ':'); 115 char* position = strchr(temp, ':');
111 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) { 116 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
112 logg->logMessage("Unknown format of /proc/cpuinfo\n" 117 logg->logMessage("Unknown format of /proc/cpuinfo\n"
@@ -122,11 +127,15 @@ void SessionData::readCpuInfo() {
122 } 127 }
123 128
124 if (foundCPUPart) { 129 if (foundCPUPart) {
125 int cpuId = strtol(position, NULL, 16); 130 mCpuIds[processor] = strtol(position, NULL, 0);
126 if (cpuId > mCpuId) { 131 // If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId
127 mCpuId = cpuId; 132 if (mCpuIds[processor] > mMaxCpuId) {
133 mMaxCpuId = mCpuIds[processor];
128 } 134 }
129 foundCpuId = true; 135 }
136
137 if (foundProcessor) {
138 processor = strtol(position, NULL, 0);
130 } 139 }
131 } 140 }
132 } 141 }
diff --git a/daemon/SessionData.h b/daemon/SessionData.h
index c834251..ea34240 100644
--- a/daemon/SessionData.h
+++ b/daemon/SessionData.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -11,12 +11,12 @@
11 11
12#include <stdint.h> 12#include <stdint.h>
13 13
14#include "Config.h"
14#include "Counter.h" 15#include "Counter.h"
15#include "Hwmon.h" 16#include "Hwmon.h"
17#include "PerfDriver.h"
16 18
17#define MAX_PERFORMANCE_COUNTERS 50 19#define PROTOCOL_VERSION 18
18
19#define PROTOCOL_VERSION 17
20#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions 20#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions
21 21
22struct ImageLinkList { 22struct ImageLinkList {
@@ -34,6 +34,7 @@ public:
34 void parseSessionXML(char* xmlString); 34 void parseSessionXML(char* xmlString);
35 35
36 Hwmon hwmon; 36 Hwmon hwmon;
37 PerfDriver perf;
37 38
38 char mCoreName[MAX_STRING_LEN]; 39 char mCoreName[MAX_STRING_LEN];
39 struct ImageLinkList *mImages; 40 struct ImageLinkList *mImages;
@@ -47,6 +48,7 @@ public:
47 bool mSessionIsActive; 48 bool mSessionIsActive;
48 bool mLocalCapture; 49 bool mLocalCapture;
49 bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled 50 bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled
51 bool mIsEBS;
50 52
51 int mBacktraceDepth; 53 int mBacktraceDepth;
52 int mTotalBufferSize; // number of MB to use for the entire collection buffer 54 int mTotalBufferSize; // number of MB to use for the entire collection buffer
@@ -54,7 +56,9 @@ public:
54 int64_t mLiveRate; 56 int64_t mLiveRate;
55 int mDuration; 57 int mDuration;
56 int mCores; 58 int mCores;
57 int mCpuId; 59 int mPageSize;
60 int mCpuIds[NR_CPUS];
61 int mMaxCpuId;
58 62
59 // PMU Counters 63 // PMU Counters
60 int mCounterOverflow; 64 int mCounterOverflow;
diff --git a/daemon/SessionXML.cpp b/daemon/SessionXML.cpp
index 0a0a027..55b2f92 100644
--- a/daemon/SessionXML.cpp
+++ b/daemon/SessionXML.cpp
@@ -1,15 +1,17 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "SessionXML.h"
10
9#include <string.h> 11#include <string.h>
10#include <stdlib.h> 12#include <stdlib.h>
11#include <limits.h> 13#include <limits.h>
12#include "SessionXML.h" 14
13#include "Logging.h" 15#include "Logging.h"
14#include "OlyUtility.h" 16#include "OlyUtility.h"
15#include "SessionData.h" 17#include "SessionData.h"
@@ -25,7 +27,7 @@ static const char* ATTR_DURATION = "duration";
25static const char* ATTR_PATH = "path"; 27static const char* ATTR_PATH = "path";
26static const char* ATTR_LIVE_RATE = "live_rate"; 28static const char* ATTR_LIVE_RATE = "live_rate";
27 29
28SessionXML::SessionXML(const char* str) { 30SessionXML::SessionXML(const char *str) {
29 parameters.buffer_mode[0] = 0; 31 parameters.buffer_mode[0] = 0;
30 parameters.sample_rate[0] = 0; 32 parameters.sample_rate[0] = 0;
31 parameters.duration = 0; 33 parameters.duration = 0;
@@ -33,13 +35,13 @@ SessionXML::SessionXML(const char* str) {
33 parameters.live_rate = 0; 35 parameters.live_rate = 0;
34 parameters.images = NULL; 36 parameters.images = NULL;
35 mPath = 0; 37 mPath = 0;
36 mSessionXML = (char*)str; 38 mSessionXML = (const char *)str;
37 logg->logMessage(mSessionXML); 39 logg->logMessage(mSessionXML);
38} 40}
39 41
40SessionXML::~SessionXML() { 42SessionXML::~SessionXML() {
41 if (mPath != 0) { 43 if (mPath != 0) {
42 free(mSessionXML); 44 free((char *)mSessionXML);
43 } 45 }
44} 46}
45 47
diff --git a/daemon/SessionXML.h b/daemon/SessionXML.h
index 0fb03bd..e146094 100644
--- a/daemon/SessionXML.h
+++ b/daemon/SessionXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -24,13 +24,13 @@ struct ConfigParameters {
24 24
25class SessionXML { 25class SessionXML {
26public: 26public:
27 SessionXML(const char* str); 27 SessionXML(const char *str);
28 ~SessionXML(); 28 ~SessionXML();
29 void parse(); 29 void parse();
30 ConfigParameters parameters; 30 ConfigParameters parameters;
31private: 31private:
32 char* mSessionXML; 32 const char *mSessionXML;
33 char* mPath; 33 const char *mPath;
34 void sessionTag(mxml_node_t *tree, mxml_node_t *node); 34 void sessionTag(mxml_node_t *tree, mxml_node_t *node);
35 void sessionImage(mxml_node_t *node); 35 void sessionImage(mxml_node_t *node);
36 36
diff --git a/daemon/Source.cpp b/daemon/Source.cpp
new file mode 100644
index 0000000..60cf704
--- /dev/null
+++ b/daemon/Source.cpp
@@ -0,0 +1,33 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Source.h"
10
11#include "Logging.h"
12
13Source::Source() : mThreadID() {
14}
15
16Source::~Source() {
17}
18
19void Source::start() {
20 if (pthread_create(&mThreadID, NULL, runStatic, this)) {
21 logg->logError(__FILE__, __LINE__, "Failed to create source thread");
22 handleException();
23 }
24}
25
26void Source::join() {
27 pthread_join(mThreadID, NULL);
28}
29
30void *Source::runStatic(void *arg) {
31 static_cast<Source *>(arg)->run();
32 return NULL;
33}
diff --git a/daemon/Source.h b/daemon/Source.h
new file mode 100644
index 0000000..56ac3d6
--- /dev/null
+++ b/daemon/Source.h
@@ -0,0 +1,40 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef SOURCE_H
10#define SOURCE_H
11
12#include <pthread.h>
13
14class Sender;
15
16class Source {
17public:
18 Source();
19 virtual ~Source();
20
21 virtual bool prepare() = 0;
22 void start();
23 virtual void run() = 0;
24 virtual void interrupt() = 0;
25 void join();
26
27 virtual bool isDone() = 0;
28 virtual void write(Sender *sender) = 0;
29
30private:
31 static void *runStatic(void *arg);
32
33 pthread_t mThreadID;
34
35 // Intentionally undefined
36 Source(const Source &);
37 Source &operator=(const Source &);
38};
39
40#endif // SOURCE_H
diff --git a/daemon/StreamlineSetup.cpp b/daemon/StreamlineSetup.cpp
index 2faada2..caa665e 100644
--- a/daemon/StreamlineSetup.cpp
+++ b/daemon/StreamlineSetup.cpp
@@ -1,26 +1,23 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <string.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <arpa/inet.h>
13#include <sys/socket.h>
14#include <netinet/in.h>
15#include "Sender.h"
16#include "Logging.h"
17#include "OlyUtility.h"
18#include "SessionData.h"
19#include "CapturedXML.h"
20#include "StreamlineSetup.h" 9#include "StreamlineSetup.h"
10
11#include "Buffer.h"
12#include "CapturedXML.h"
21#include "ConfigurationXML.h" 13#include "ConfigurationXML.h"
22#include "Driver.h" 14#include "Driver.h"
23#include "EventsXML.h" 15#include "EventsXML.h"
16#include "Logging.h"
17#include "OlySocket.h"
18#include "OlyUtility.h"
19#include "Sender.h"
20#include "SessionData.h"
24 21
25static const char* TAG_SESSION = "session"; 22static const char* TAG_SESSION = "session";
26static const char* TAG_REQUEST = "request"; 23static const char* TAG_REQUEST = "request";
@@ -198,12 +195,9 @@ void StreamlineSetup::handleDeliver(char* xml) {
198void StreamlineSetup::sendData(const char* data, uint32_t length, char type) { 195void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
199 unsigned char header[5]; 196 unsigned char header[5];
200 header[0] = type; 197 header[0] = type;
201 header[1] = (length >> 0) & 0xff; 198 Buffer::writeLEInt(header + 1, length);
202 header[2] = (length >> 8) & 0xff;
203 header[3] = (length >> 16) & 0xff;
204 header[4] = (length >> 24) & 0xff;
205 mSocket->send((char*)&header, sizeof(header)); 199 mSocket->send((char*)&header, sizeof(header));
206 mSocket->send((char*)data, length); 200 mSocket->send((const char*)data, length);
207} 201}
208 202
209void StreamlineSetup::sendEvents() { 203void StreamlineSetup::sendEvents() {
@@ -241,8 +235,14 @@ void StreamlineSetup::sendCounters() {
241 235
242 xml = mxmlNewXML("1.0"); 236 xml = mxmlNewXML("1.0");
243 counters = mxmlNewElement(xml, "counters"); 237 counters = mxmlNewElement(xml, "counters");
238 int count = 0;
244 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) { 239 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
245 driver->writeCounters(counters); 240 count += driver->writeCounters(counters);
241 }
242
243 if (count == 0) {
244 logg->logError(__FILE__, __LINE__, "No counters found, this could be because /dev/gator/events can not be read or because perf is not working correctly");
245 handleException();
246 } 246 }
247 247
248 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB); 248 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
diff --git a/daemon/StreamlineSetup.h b/daemon/StreamlineSetup.h
index d6d9a6e..74bb197 100644
--- a/daemon/StreamlineSetup.h
+++ b/daemon/StreamlineSetup.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,7 +9,10 @@
9#ifndef __STREAMLINE_SETUP_H__ 9#ifndef __STREAMLINE_SETUP_H__
10#define __STREAMLINE_SETUP_H__ 10#define __STREAMLINE_SETUP_H__
11 11
12#include "OlySocket.h" 12#include <stdint.h>
13#include <string.h>
14
15class OlySocket;
13 16
14// Commands from Streamline 17// Commands from Streamline
15enum { 18enum {
diff --git a/daemon/UEvent.cpp b/daemon/UEvent.cpp
new file mode 100644
index 0000000..282e965
--- /dev/null
+++ b/daemon/UEvent.cpp
@@ -0,0 +1,75 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "UEvent.h"
10
11#include <linux/netlink.h>
12#include <string.h>
13#include <sys/socket.h>
14#include <unistd.h>
15
16#include "Logging.h"
17
18static const char EMPTY[] = "";
19static const char ACTION[] = "ACTION=";
20static const char DEVPATH[] = "DEVPATH=";
21static const char SUBSYSTEM[] = "SUBSYSTEM=";
22
23UEvent::UEvent() : mFd(-1) {
24}
25
26UEvent::~UEvent() {
27 if (mFd >= 0) {
28 close(mFd);
29 }
30}
31
32bool UEvent::init() {
33 mFd = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
34 if (mFd < 0) {
35 logg->logMessage("%s(%s:%i): socket failed", __FUNCTION__, __FILE__, __LINE__);
36 return false;
37 }
38
39 struct sockaddr_nl sockaddr;
40 memset(&sockaddr, 0, sizeof(sockaddr));
41 sockaddr.nl_family = AF_NETLINK;
42 sockaddr.nl_groups = 1; // bitmask: (1 << 0) == kernel events, (1 << 1) == udev events
43 sockaddr.nl_pid = 0;
44 if (bind(mFd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0) {
45 logg->logMessage("%s(%s:%i): bind failed", __FUNCTION__, __FILE__, __LINE__);
46 return false;
47 }
48
49 return true;
50}
51
52bool UEvent::read(UEventResult *const result) {
53 ssize_t bytes = recv(mFd, result->mBuf, sizeof(result->mBuf), 0);
54 if (bytes <= 0) {
55 logg->logMessage("%s(%s:%i): recv failed", __FUNCTION__, __FILE__, __LINE__);
56 return false;
57 }
58
59 result->mAction = EMPTY;
60 result->mDevPath = EMPTY;
61 result->mSubsystem = EMPTY;
62
63 for (int pos = 0; pos < bytes; pos += strlen(result->mBuf + pos) + 1) {
64 char *const str = result->mBuf + pos;
65 if (strncmp(str, ACTION, sizeof(ACTION) - 1) == 0) {
66 result->mAction = str + sizeof(ACTION) - 1;
67 } else if (strncmp(str, DEVPATH, sizeof(DEVPATH) - 1) == 0) {
68 result->mDevPath = str + sizeof(DEVPATH) - 1;
69 } else if (strncmp(str, SUBSYSTEM, sizeof(SUBSYSTEM) - 1) == 0) {
70 result->mSubsystem = str + sizeof(SUBSYSTEM) - 1;
71 }
72 }
73
74 return true;
75}
diff --git a/daemon/UEvent.h b/daemon/UEvent.h
new file mode 100644
index 0000000..2f7ef2c
--- /dev/null
+++ b/daemon/UEvent.h
@@ -0,0 +1,36 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef UEVENT_H
10#define UEVENT_H
11
12struct UEventResult {
13 const char *mAction;
14 const char *mDevPath;
15 const char *mSubsystem;
16 char mBuf[1<<13];
17};
18
19class UEvent {
20public:
21 UEvent();
22 ~UEvent();
23
24 bool init();
25 bool read(UEventResult *const result);
26 int getFd() const { return mFd; }
27
28private:
29 int mFd;
30
31 // Intentionally undefined
32 UEvent(const UEvent &);
33 UEvent &operator=(const UEvent &);
34};
35
36#endif // UEVENT_H
diff --git a/daemon/UserSpaceSource.cpp b/daemon/UserSpaceSource.cpp
new file mode 100644
index 0000000..debe696
--- /dev/null
+++ b/daemon/UserSpaceSource.cpp
@@ -0,0 +1,97 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "UserSpaceSource.h"
10
11#include <sys/prctl.h>
12#include <unistd.h>
13
14#include "Child.h"
15#include "DriverSource.h"
16#include "Logging.h"
17#include "SessionData.h"
18
19#define NS_PER_S ((uint64_t)1000000000)
20#define NS_PER_US 1000
21
22extern Child *child;
23
24UserSpaceSource::UserSpaceSource(sem_t *senderSem) : mBuffer(0, FRAME_BLOCK_COUNTER, gSessionData->mTotalBufferSize*1024*1024, senderSem) {
25}
26
27UserSpaceSource::~UserSpaceSource() {
28}
29
30bool UserSpaceSource::prepare() {
31 return true;
32}
33
34void UserSpaceSource::run() {
35 prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
36
37 gSessionData->hwmon.start();
38
39 int64_t monotonic_started = 0;
40 while (monotonic_started <= 0) {
41 usleep(10);
42
43 if (DriverSource::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
44 logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
45 handleException();
46 }
47 }
48
49 uint64_t next_time = 0;
50 while (gSessionData->mSessionIsActive) {
51 struct timespec ts;
52#ifndef CLOCK_MONOTONIC_RAW
53 // Android doesn't have this defined but it was added in Linux 2.6.28
54#define CLOCK_MONOTONIC_RAW 4
55#endif
56 if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
57 logg->logError(__FILE__, __LINE__, "Failed to get uptime");
58 handleException();
59 }
60 const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started;
61 // Sample ten times a second ignoring gSessionData->mSampleRate
62 next_time += NS_PER_S/10;//gSessionData->mSampleRate;
63 if (next_time < curr_time) {
64 logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
65 next_time = curr_time;
66 }
67
68 if (mBuffer.eventHeader(curr_time)) {
69 gSessionData->hwmon.read(&mBuffer);
70 // Only check after writing all counters so that time and corresponding counters appear in the same frame
71 mBuffer.check(curr_time);
72 }
73
74 if (mBuffer.bytesAvailable() <= 0) {
75 logg->logMessage("One shot (counters)");
76 child->endSession();
77 }
78
79 usleep((next_time - curr_time)/NS_PER_US);
80 }
81
82 mBuffer.setDone();
83}
84
85void UserSpaceSource::interrupt() {
86 // Do nothing
87}
88
89bool UserSpaceSource::isDone() {
90 return mBuffer.isDone();
91}
92
93void UserSpaceSource::write(Sender *sender) {
94 if (!mBuffer.isDone()) {
95 mBuffer.write(sender);
96 }
97}
diff --git a/daemon/UserSpaceSource.h b/daemon/UserSpaceSource.h
new file mode 100644
index 0000000..fb5889d
--- /dev/null
+++ b/daemon/UserSpaceSource.h
@@ -0,0 +1,38 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef USERSPACESOURCE_H
10#define USERSPACESOURCE_H
11
12#include <semaphore.h>
13
14#include "Buffer.h"
15#include "Source.h"
16
17// User space counters - currently just hwmon
18class UserSpaceSource : public Source {
19public:
20 UserSpaceSource(sem_t *senderSem);
21 ~UserSpaceSource();
22
23 bool prepare();
24 void run();
25 void interrupt();
26
27 bool isDone();
28 void write(Sender *sender);
29
30private:
31 Buffer mBuffer;
32
33 // Intentionally unimplemented
34 UserSpaceSource(const UserSpaceSource &);
35 UserSpaceSource &operator=(const UserSpaceSource &);
36};
37
38#endif // USERSPACESOURCE_H
diff --git a/daemon/common.mk b/daemon/common.mk
index 031d169..d9dc146 100644
--- a/daemon/common.mk
+++ b/daemon/common.mk
@@ -25,7 +25,7 @@ include $(wildcard *.d)
25include $(wildcard mxml/*.d) 25include $(wildcard mxml/*.d)
26 26
27EventsXML.cpp: events_xml.h 27EventsXML.cpp: events_xml.h
28ConfigurationXML.cpp: configuration_xml.h 28ConfigurationXML.cpp: defaults_xml.h
29 29
30# Don't regenerate conf-lex.c or conf-parse.c 30# Don't regenerate conf-lex.c or conf-parse.c
31libsensors/conf-lex.c: ; 31libsensors/conf-lex.c: ;
@@ -47,4 +47,4 @@ escape: escape.c
47 gcc $^ -o $@ 47 gcc $^ -o $@
48 48
49clean: 49clean:
50 rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h configuration_xml.h 50 rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h defaults_xml.h
diff --git a/daemon/configuration.xml b/daemon/defaults.xml
index b44c00a..5bf096c 100644
--- a/daemon/configuration.xml
+++ b/daemon/defaults.xml
@@ -6,29 +6,34 @@
6 <configuration counter="ARM_ARM11MPCore_ccnt" event="0xff"/> 6 <configuration counter="ARM_ARM11MPCore_ccnt" event="0xff"/>
7 <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08"/> 7 <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08"/>
8 <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b"/> 8 <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b"/>
9 <configuration counter="ARM_Cortex-A5_ccnt" event="0xff"/> 9 <configuration counter="ARMv7_Cortex_A5_ccnt" event="0xff"/>
10 <configuration counter="ARM_Cortex-A5_cnt0" event="0x8"/> 10 <configuration counter="ARMv7_Cortex_A5_cnt0" event="0x8"/>
11 <configuration counter="ARM_Cortex-A5_cnt1" event="0x1"/> 11 <configuration counter="ARMv7_Cortex_A5_cnt1" event="0x1"/>
12 <configuration counter="ARM_Cortex-A7_ccnt" event="0xff"/> 12 <configuration counter="ARMv7_Cortex_A7_ccnt" event="0xff"/>
13 <configuration counter="ARM_Cortex-A7_cnt0" event="0x08"/> 13 <configuration counter="ARMv7_Cortex_A7_cnt0" event="0x08"/>
14 <configuration counter="ARM_Cortex-A7_cnt1" event="0x10"/> 14 <configuration counter="ARMv7_Cortex_A7_cnt1" event="0x10"/>
15 <configuration counter="ARM_Cortex-A7_cnt2" event="0x16"/> 15 <configuration counter="ARMv7_Cortex_A7_cnt2" event="0x16"/>
16 <configuration counter="ARM_Cortex-A8_ccnt" event="0xff"/> 16 <configuration counter="ARMv7_Cortex_A8_ccnt" event="0xff"/>
17 <configuration counter="ARM_Cortex-A8_cnt0" event="0x8"/> 17 <configuration counter="ARMv7_Cortex_A8_cnt0" event="0x8"/>
18 <configuration counter="ARM_Cortex-A8_cnt1" event="0x44"/> 18 <configuration counter="ARMv7_Cortex_A8_cnt1" event="0x44"/>
19 <configuration counter="ARM_Cortex-A8_cnt2" event="0x43"/> 19 <configuration counter="ARMv7_Cortex_A8_cnt2" event="0x43"/>
20 <configuration counter="ARM_Cortex-A8_cnt3" event="0x10"/> 20 <configuration counter="ARMv7_Cortex_A8_cnt3" event="0x10"/>
21 <configuration counter="ARM_Cortex-A9_ccnt" event="0xff"/> 21 <configuration counter="ARMv7_Cortex_A9_ccnt" event="0xff"/>
22 <configuration counter="ARM_Cortex-A9_cnt0" event="0x68"/> 22 <configuration counter="ARMv7_Cortex_A9_cnt0" event="0x68"/>
23 <configuration counter="ARM_Cortex-A9_cnt1" event="0x06"/> 23 <configuration counter="ARMv7_Cortex_A9_cnt1" event="0x06"/>
24 <configuration counter="ARM_Cortex-A9_cnt2" event="0x07"/> 24 <configuration counter="ARMv7_Cortex_A9_cnt2" event="0x07"/>
25 <configuration counter="ARM_Cortex-A9_cnt3" event="0x03"/> 25 <configuration counter="ARMv7_Cortex_A9_cnt3" event="0x03"/>
26 <configuration counter="ARM_Cortex-A9_cnt4" event="0x04"/> 26 <configuration counter="ARMv7_Cortex_A9_cnt4" event="0x04"/>
27 <configuration counter="ARM_Cortex-A15_ccnt" event="0xff"/> 27 <configuration counter="ARMv7_Cortex_A12_ccnt" event="0xff"/>
28 <configuration counter="ARM_Cortex-A15_cnt0" event="0x8"/> 28 <configuration counter="ARMv7_Cortex_A12_cnt0" event="0x08"/>
29 <configuration counter="ARM_Cortex-A15_cnt1" event="0x16"/> 29 <configuration counter="ARMv7_Cortex_A12_cnt1" event="0x16"/>
30 <configuration counter="ARM_Cortex-A15_cnt2" event="0x10"/> 30 <configuration counter="ARMv7_Cortex_A12_cnt2" event="0x10"/>
31 <configuration counter="ARM_Cortex-A15_cnt3" event="0x19"/> 31 <configuration counter="ARMv7_Cortex_A12_cnt3" event="0x19"/>
32 <configuration counter="ARMv7_Cortex_A15_ccnt" event="0xff"/>
33 <configuration counter="ARMv7_Cortex_A15_cnt0" event="0x8"/>
34 <configuration counter="ARMv7_Cortex_A15_cnt1" event="0x16"/>
35 <configuration counter="ARMv7_Cortex_A15_cnt2" event="0x10"/>
36 <configuration counter="ARMv7_Cortex_A15_cnt3" event="0x19"/>
32 <configuration counter="ARM_Cortex-A53_ccnt" event="0x11"/> 37 <configuration counter="ARM_Cortex-A53_ccnt" event="0x11"/>
33 <configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/> 38 <configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/>
34 <configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/> 39 <configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/>
diff --git a/daemon/escape.c b/daemon/escape.c
index 3eec1f8..c54aa1c 100644
--- a/daemon/escape.c
+++ b/daemon/escape.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/events-Cortex-A12.xml b/daemon/events-Cortex-A12.xml
index 20a4772..9c04354 100644
--- a/daemon/events-Cortex-A12.xml
+++ b/daemon/events-Cortex-A12.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A12_cnt" count="6"/> 1 <counter_set name="ARMv7_Cortex_A12_cnt" count="6"/>
2 <category name="Cortex-A12" counter_set="ARM_Cortex-A12_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A12" counter_set="ARMv7_Cortex_A12_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A12_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A12_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 4 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
5 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 5 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
6 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/> 6 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
diff --git a/daemon/events-Cortex-A15.xml b/daemon/events-Cortex-A15.xml
index faa8b1c..f50e55d 100644
--- a/daemon/events-Cortex-A15.xml
+++ b/daemon/events-Cortex-A15.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A15_cnt" count="6"/> 1 <counter_set name="ARMv7_Cortex_A15_cnt" count="6"/>
2 <category name="Cortex-A15" counter_set="ARM_Cortex-A15_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A15" counter_set="ARMv7_Cortex_A15_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A15_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A15_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/> 4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A5.xml b/daemon/events-Cortex-A5.xml
index a5b1546..d67581d 100644
--- a/daemon/events-Cortex-A5.xml
+++ b/daemon/events-Cortex-A5.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A5_cnt" count="2"/> 1 <counter_set name="ARMv7_Cortex_A5_cnt" count="2"/>
2 <category name="Cortex-A5" counter_set="ARM_Cortex-A5_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A5" counter_set="ARMv7_Cortex_A5_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A5_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A5_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A7.xml b/daemon/events-Cortex-A7.xml
index 54d7264..6e078b3 100644
--- a/daemon/events-Cortex-A7.xml
+++ b/daemon/events-Cortex-A7.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A7_cnt" count="4"/> 1 <counter_set name="ARMv7_Cortex_A7_cnt" count="4"/>
2 <category name="Cortex-A7" counter_set="ARM_Cortex-A7_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A7" counter_set="ARMv7_Cortex_A7_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A7_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A7_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/> 4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A8.xml b/daemon/events-Cortex-A8.xml
index f251823..a69e25a 100644
--- a/daemon/events-Cortex-A8.xml
+++ b/daemon/events-Cortex-A8.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A8_cnt" count="4"/> 1 <counter_set name="ARMv7_Cortex_A8_cnt" count="4"/>
2 <category name="Cortex-A8" counter_set="ARM_Cortex-A8_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A8" counter_set="ARMv7_Cortex_A8_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A8_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A8_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A9.xml b/daemon/events-Cortex-A9.xml
index 75f09c8..3e7f828 100644
--- a/daemon/events-Cortex-A9.xml
+++ b/daemon/events-Cortex-A9.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A9_cnt" count="6"/> 1 <counter_set name="ARMv7_Cortex_A9_cnt" count="6"/>
2 <category name="Cortex-A9" counter_set="ARM_Cortex-A9_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A9" counter_set="ARMv7_Cortex_A9_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A9_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A9_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Linux.xml b/daemon/events-Linux.xml
index 31a90a1..4d677e1 100644
--- a/daemon/events-Linux.xml
+++ b/daemon/events-Linux.xml
@@ -6,12 +6,12 @@
6 <event counter="Linux_net_rx" title="Network" name="Receive" units="B" description="Receive network traffic, including effect from Streamline"/> 6 <event counter="Linux_net_rx" title="Network" name="Receive" units="B" description="Receive network traffic, including effect from Streamline"/>
7 <event counter="Linux_net_tx" title="Network" name="Transmit" units="B" description="Transmit network traffic, including effect from Streamline"/> 7 <event counter="Linux_net_tx" title="Network" name="Transmit" units="B" description="Transmit network traffic, including effect from Streamline"/>
8 <event counter="Linux_sched_switch" title="Scheduler" name="Switch" per_cpu="yes" description="Context switch events"/> 8 <event counter="Linux_sched_switch" title="Scheduler" name="Switch" per_cpu="yes" description="Context switch events"/>
9 <event counter="Linux_meminfo_memused" title="Memory" name="Used" display="maximum" units="B" proc="yes" description="Total used memory size. Note: a process' used memory includes shared memory that may be counted more than once (equivalent to RES from top). Kernel threads are not filterable."/> 9 <event counter="Linux_meminfo_memused" title="Memory" name="Used" class="absolute" units="B" proc="yes" description="Total used memory size. Note: a process' used memory includes shared memory that may be counted more than once (equivalent to RES from top). Kernel threads are not filterable."/>
10 <event counter="Linux_meminfo_memfree" title="Memory" name="Free" display="minimum" units="B" description="Available memory size"/> 10 <event counter="Linux_meminfo_memfree" title="Memory" name="Free" class="absolute" display="minimum" units="B" description="Available memory size"/>
11 <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" display="maximum" units="B" description="Memory used by OS disk buffers"/> 11 <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" class="absolute" units="B" description="Memory used by OS disk buffers"/>
12 <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" display="maximum" units="Hz" series_composition="overlay" average_cores="yes" description="Frequency setting of the CPU"/> 12 <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" class="absolute" units="Hz" series_composition="overlay" average_cores="yes" description="Frequency setting of the CPU"/>
13 <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" display="maximum" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/> 13 <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" class="absolute" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/>
14 <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" display="average" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on contended resource"/> 14 <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on contended resource"/>
15 <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" display="average" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on I/O resource"/> 15 <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on I/O resource"/>
16 </category> 16 </category>
17 17
diff --git a/daemon/events-Mali-4xx.xml b/daemon/events-Mali-4xx.xml
index 8772ce4..5a71386 100644
--- a/daemon/events-Mali-4xx.xml
+++ b/daemon/events-Mali-4xx.xml
@@ -207,7 +207,7 @@
207 <event event="0x0400" option_set="fs" title="ARM Mali-4xx" name="Filmstrip" description="Scaled framebuffer"/> 207 <event event="0x0400" option_set="fs" title="ARM Mali-4xx" name="Filmstrip" description="Scaled framebuffer"/>
208 </category> 208 </category>
209 <category name="ARM_Mali-4xx_Voltage" per_cpu="no"> 209 <category name="ARM_Mali-4xx_Voltage" per_cpu="no">
210 <event counter="ARM_Mali-4xx_Voltage" title="Mali GPU Voltage" name="Voltage" display="average" average_selection="yes" units="mV" description="GPU core voltage."/> 210 <event counter="ARM_Mali-4xx_Voltage" title="Mali GPU Voltage" name="Voltage" class="absolute" display="average" average_selection="yes" units="mV" description="GPU core voltage."/>
211 </category> 211 </category>
212 <category name="ARM_Mali-4xx_Frequency" per_cpu="no"> 212 <category name="ARM_Mali-4xx_Frequency" per_cpu="no">
213 <event counter="ARM_Mali-4xx_Frequency" title="Mali GPU Frequency" name="Frequency" display="average" average_selection="yes" units="MHz" description="GPU core frequency."/> 213 <event counter="ARM_Mali-4xx_Frequency" title="Mali GPU Frequency" name="Frequency" display="average" average_selection="yes" units="MHz" description="GPU core frequency."/>
diff --git a/daemon/events-Mali-T6xx.xml b/daemon/events-Mali-T6xx.xml
index 2465238..ec9ca00 100644
--- a/daemon/events-Mali-T6xx.xml
+++ b/daemon/events-Mali-T6xx.xml
@@ -4,14 +4,14 @@
4 </category> 4 </category>
5 5
6 <category name="Mali-T6xx-PMShader" per_cpu="no"> 6 <category name="Mali-T6xx-PMShader" per_cpu="no">
7 <event counter="ARM_Mali-T6xx_PM_SHADER_0" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 0" description="Mali PM Shader: PM Shader Core 0."/> 7 <event counter="ARM_Mali-T6xx_PM_SHADER_0" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 0" description="Mali PM Shader: PM Shader Core 0."/>
8 <event counter="ARM_Mali-T6xx_PM_SHADER_1" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 1" description="Mali PM Shader: PM Shader Core 1."/> 8 <event counter="ARM_Mali-T6xx_PM_SHADER_1" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 1" description="Mali PM Shader: PM Shader Core 1."/>
9 <event counter="ARM_Mali-T6xx_PM_SHADER_2" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 2" description="Mali PM Shader: PM Shader Core 2."/> 9 <event counter="ARM_Mali-T6xx_PM_SHADER_2" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 2" description="Mali PM Shader: PM Shader Core 2."/>
10 <event counter="ARM_Mali-T6xx_PM_SHADER_3" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 3" description="Mali PM Shader: PM Shader Core 3."/> 10 <event counter="ARM_Mali-T6xx_PM_SHADER_3" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 3" description="Mali PM Shader: PM Shader Core 3."/>
11 <event counter="ARM_Mali-T6xx_PM_SHADER_4" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 4" description="Mali PM Shader: PM Shader Core 4."/> 11 <event counter="ARM_Mali-T6xx_PM_SHADER_4" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 4" description="Mali PM Shader: PM Shader Core 4."/>
12 <event counter="ARM_Mali-T6xx_PM_SHADER_5" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 5" description="Mali PM Shader: PM Shader Core 5."/> 12 <event counter="ARM_Mali-T6xx_PM_SHADER_5" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 5" description="Mali PM Shader: PM Shader Core 5."/>
13 <event counter="ARM_Mali-T6xx_PM_SHADER_6" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 6" description="Mali PM Shader: PM Shader Core 6."/> 13 <event counter="ARM_Mali-T6xx_PM_SHADER_6" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 6" description="Mali PM Shader: PM Shader Core 6."/>
14 <event counter="ARM_Mali-T6xx_PM_SHADER_7" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 7" description="Mali PM Shader: PM Shader Core 7."/> 14 <event counter="ARM_Mali-T6xx_PM_SHADER_7" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 7" description="Mali PM Shader: PM Shader Core 7."/>
15 </category> 15 </category>
16 16
17 <category name="Mali-T6xx-PMTiler" per_cpu="no"> 17 <category name="Mali-T6xx-PMTiler" per_cpu="no">
diff --git a/daemon/events-Perf-Hardware.xml b/daemon/events-Perf-Hardware.xml
new file mode 100644
index 0000000..423696f
--- /dev/null
+++ b/daemon/events-Perf-Hardware.xml
@@ -0,0 +1,12 @@
1 <counter_set name="Perf_Hardware_cnt" count="6"/>
2 <category name="Perf Hardware" counter_set="Perf_Hardware_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="Perf_Hardware_ccnt" event="0" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="1" title="Instruction" name="Executed" description="Instruction executed"/>
5 <event event="2" title="Cache" name="References" description="Cache References"/>
6 <event event="3" title="Cache" name="Misses" description="Cache Misses"/>
7 <event event="4" title="Branch" name="Instructions" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
8 <event event="5" title="Branch" name="Misses" description="Branch mispredicted or not predicted"/>
9 <event event="6" title="Bus" name="Cycles" description="Bus Cycles"/>
10 <event event="7" title="Instruction" name="Stalled Frontend" description="Stalled Frontend Cycles"/>
11 <event event="8" title="Instruction" name="Stalled Backend" description="Stalled Backend Cycles"/>
12 </category>
diff --git a/daemon/k/perf_event.3.12.h b/daemon/k/perf_event.3.12.h
new file mode 100644
index 0000000..e886c48
--- /dev/null
+++ b/daemon/k/perf_event.3.12.h
@@ -0,0 +1,792 @@
1/*
2 * Performance events:
3 *
4 * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
5 * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
6 * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra
7 *
8 * Data type definitions, declarations, prototypes.
9 *
10 * Started by: Thomas Gleixner and Ingo Molnar
11 *
12 * For licencing details see kernel-base/COPYING
13 */
14#ifndef _LINUX_PERF_EVENT_H
15#define _LINUX_PERF_EVENT_H
16
17#include <linux/types.h>
18#include <linux/ioctl.h>
19#include <asm/byteorder.h>
20
21/*
22 * User-space ABI bits:
23 */
24
25/*
26 * attr.type
27 */
28enum perf_type_id {
29 PERF_TYPE_HARDWARE = 0,
30 PERF_TYPE_SOFTWARE = 1,
31 PERF_TYPE_TRACEPOINT = 2,
32 PERF_TYPE_HW_CACHE = 3,
33 PERF_TYPE_RAW = 4,
34 PERF_TYPE_BREAKPOINT = 5,
35
36 PERF_TYPE_MAX, /* non-ABI */
37};
38
39/*
40 * Generalized performance event event_id types, used by the
41 * attr.event_id parameter of the sys_perf_event_open()
42 * syscall:
43 */
44enum perf_hw_id {
45 /*
46 * Common hardware events, generalized by the kernel:
47 */
48 PERF_COUNT_HW_CPU_CYCLES = 0,
49 PERF_COUNT_HW_INSTRUCTIONS = 1,
50 PERF_COUNT_HW_CACHE_REFERENCES = 2,
51 PERF_COUNT_HW_CACHE_MISSES = 3,
52 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
53 PERF_COUNT_HW_BRANCH_MISSES = 5,
54 PERF_COUNT_HW_BUS_CYCLES = 6,
55 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
56 PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
57 PERF_COUNT_HW_REF_CPU_CYCLES = 9,
58
59 PERF_COUNT_HW_MAX, /* non-ABI */
60};
61
62/*
63 * Generalized hardware cache events:
64 *
65 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
66 * { read, write, prefetch } x
67 * { accesses, misses }
68 */
69enum perf_hw_cache_id {
70 PERF_COUNT_HW_CACHE_L1D = 0,
71 PERF_COUNT_HW_CACHE_L1I = 1,
72 PERF_COUNT_HW_CACHE_LL = 2,
73 PERF_COUNT_HW_CACHE_DTLB = 3,
74 PERF_COUNT_HW_CACHE_ITLB = 4,
75 PERF_COUNT_HW_CACHE_BPU = 5,
76 PERF_COUNT_HW_CACHE_NODE = 6,
77
78 PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
79};
80
81enum perf_hw_cache_op_id {
82 PERF_COUNT_HW_CACHE_OP_READ = 0,
83 PERF_COUNT_HW_CACHE_OP_WRITE = 1,
84 PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
85
86 PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
87};
88
89enum perf_hw_cache_op_result_id {
90 PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
91 PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
92
93 PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
94};
95
96/*
97 * Special "software" events provided by the kernel, even if the hardware
98 * does not support performance events. These events measure various
99 * physical and sw events of the kernel (and allow the profiling of them as
100 * well):
101 */
102enum perf_sw_ids {
103 PERF_COUNT_SW_CPU_CLOCK = 0,
104 PERF_COUNT_SW_TASK_CLOCK = 1,
105 PERF_COUNT_SW_PAGE_FAULTS = 2,
106 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
107 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
108 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
109 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
110 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
111 PERF_COUNT_SW_EMULATION_FAULTS = 8,
112 PERF_COUNT_SW_DUMMY = 9,
113
114 PERF_COUNT_SW_MAX, /* non-ABI */
115};
116
117/*
118 * Bits that can be set in attr.sample_type to request information
119 * in the overflow packets.
120 */
121enum perf_event_sample_format {
122 PERF_SAMPLE_IP = 1U << 0,
123 PERF_SAMPLE_TID = 1U << 1,
124 PERF_SAMPLE_TIME = 1U << 2,
125 PERF_SAMPLE_ADDR = 1U << 3,
126 PERF_SAMPLE_READ = 1U << 4,
127 PERF_SAMPLE_CALLCHAIN = 1U << 5,
128 PERF_SAMPLE_ID = 1U << 6,
129 PERF_SAMPLE_CPU = 1U << 7,
130 PERF_SAMPLE_PERIOD = 1U << 8,
131 PERF_SAMPLE_STREAM_ID = 1U << 9,
132 PERF_SAMPLE_RAW = 1U << 10,
133 PERF_SAMPLE_BRANCH_STACK = 1U << 11,
134 PERF_SAMPLE_REGS_USER = 1U << 12,
135 PERF_SAMPLE_STACK_USER = 1U << 13,
136 PERF_SAMPLE_WEIGHT = 1U << 14,
137 PERF_SAMPLE_DATA_SRC = 1U << 15,
138 PERF_SAMPLE_IDENTIFIER = 1U << 16,
139
140 PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */
141};
142
143/*
144 * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
145 *
146 * If the user does not pass priv level information via branch_sample_type,
147 * the kernel uses the event's priv level. Branch and event priv levels do
148 * not have to match. Branch priv level is checked for permissions.
149 *
150 * The branch types can be combined, however BRANCH_ANY covers all types
151 * of branches and therefore it supersedes all the other types.
152 */
153enum perf_branch_sample_type {
154 PERF_SAMPLE_BRANCH_USER = 1U << 0, /* user branches */
155 PERF_SAMPLE_BRANCH_KERNEL = 1U << 1, /* kernel branches */
156 PERF_SAMPLE_BRANCH_HV = 1U << 2, /* hypervisor branches */
157
158 PERF_SAMPLE_BRANCH_ANY = 1U << 3, /* any branch types */
159 PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 4, /* any call branch */
160 PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 5, /* any return branch */
161 PERF_SAMPLE_BRANCH_IND_CALL = 1U << 6, /* indirect calls */
162 PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */
163 PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */
164 PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */
165
166 PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */
167};
168
169#define PERF_SAMPLE_BRANCH_PLM_ALL \
170 (PERF_SAMPLE_BRANCH_USER|\
171 PERF_SAMPLE_BRANCH_KERNEL|\
172 PERF_SAMPLE_BRANCH_HV)
173
174/*
175 * Values to determine ABI of the registers dump.
176 */
177enum perf_sample_regs_abi {
178 PERF_SAMPLE_REGS_ABI_NONE = 0,
179 PERF_SAMPLE_REGS_ABI_32 = 1,
180 PERF_SAMPLE_REGS_ABI_64 = 2,
181};
182
183/*
184 * The format of the data returned by read() on a perf event fd,
185 * as specified by attr.read_format:
186 *
187 * struct read_format {
188 * { u64 value;
189 * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
190 * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
191 * { u64 id; } && PERF_FORMAT_ID
192 * } && !PERF_FORMAT_GROUP
193 *
194 * { u64 nr;
195 * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
196 * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
197 * { u64 value;
198 * { u64 id; } && PERF_FORMAT_ID
199 * } cntr[nr];
200 * } && PERF_FORMAT_GROUP
201 * };
202 */
203enum perf_event_read_format {
204 PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
205 PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
206 PERF_FORMAT_ID = 1U << 2,
207 PERF_FORMAT_GROUP = 1U << 3,
208
209 PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
210};
211
212#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
213#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */
214#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
215#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
216 /* add: sample_stack_user */
217
218/*
219 * Hardware event_id to monitor via a performance monitoring event:
220 */
221struct perf_event_attr {
222
223 /*
224 * Major type: hardware/software/tracepoint/etc.
225 */
226 __u32 type;
227
228 /*
229 * Size of the attr structure, for fwd/bwd compat.
230 */
231 __u32 size;
232
233 /*
234 * Type specific configuration information.
235 */
236 __u64 config;
237
238 union {
239 __u64 sample_period;
240 __u64 sample_freq;
241 };
242
243 __u64 sample_type;
244 __u64 read_format;
245
246 __u64 disabled : 1, /* off by default */
247 inherit : 1, /* children inherit it */
248 pinned : 1, /* must always be on PMU */
249 exclusive : 1, /* only group on PMU */
250 exclude_user : 1, /* don't count user */
251 exclude_kernel : 1, /* ditto kernel */
252 exclude_hv : 1, /* ditto hypervisor */
253 exclude_idle : 1, /* don't count when idle */
254 mmap : 1, /* include mmap data */
255 comm : 1, /* include comm data */
256 freq : 1, /* use freq, not period */
257 inherit_stat : 1, /* per task counts */
258 enable_on_exec : 1, /* next exec enables */
259 task : 1, /* trace fork/exit */
260 watermark : 1, /* wakeup_watermark */
261 /*
262 * precise_ip:
263 *
264 * 0 - SAMPLE_IP can have arbitrary skid
265 * 1 - SAMPLE_IP must have constant skid
266 * 2 - SAMPLE_IP requested to have 0 skid
267 * 3 - SAMPLE_IP must have 0 skid
268 *
269 * See also PERF_RECORD_MISC_EXACT_IP
270 */
271 precise_ip : 2, /* skid constraint */
272 mmap_data : 1, /* non-exec mmap data */
273 sample_id_all : 1, /* sample_type all events */
274
275 exclude_host : 1, /* don't count in host */
276 exclude_guest : 1, /* don't count in guest */
277
278 exclude_callchain_kernel : 1, /* exclude kernel callchains */
279 exclude_callchain_user : 1, /* exclude user callchains */
280 mmap2 : 1, /* include mmap with inode data */
281
282 __reserved_1 : 40;
283
284 union {
285 __u32 wakeup_events; /* wakeup every n events */
286 __u32 wakeup_watermark; /* bytes before wakeup */
287 };
288
289 __u32 bp_type;
290 union {
291 __u64 bp_addr;
292 __u64 config1; /* extension of config */
293 };
294 union {
295 __u64 bp_len;
296 __u64 config2; /* extension of config1 */
297 };
298 __u64 branch_sample_type; /* enum perf_branch_sample_type */
299
300 /*
301 * Defines set of user regs to dump on samples.
302 * See asm/perf_regs.h for details.
303 */
304 __u64 sample_regs_user;
305
306 /*
307 * Defines size of the user stack to dump on samples.
308 */
309 __u32 sample_stack_user;
310
311 /* Align to u64. */
312 __u32 __reserved_2;
313};
314
315#define perf_flags(attr) (*(&(attr)->read_format + 1))
316
317/*
318 * Ioctls that can be done on a perf event fd:
319 */
320#define PERF_EVENT_IOC_ENABLE _IO ('$', 0)
321#define PERF_EVENT_IOC_DISABLE _IO ('$', 1)
322#define PERF_EVENT_IOC_REFRESH _IO ('$', 2)
323#define PERF_EVENT_IOC_RESET _IO ('$', 3)
324#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64)
325#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
326#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
327#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
328
329enum perf_event_ioc_flags {
330 PERF_IOC_FLAG_GROUP = 1U << 0,
331};
332
333/*
334 * Structure of the page that can be mapped via mmap
335 */
336struct perf_event_mmap_page {
337 __u32 version; /* version number of this structure */
338 __u32 compat_version; /* lowest version this is compat with */
339
340 /*
341 * Bits needed to read the hw events in user-space.
342 *
343 * u32 seq, time_mult, time_shift, idx, width;
344 * u64 count, enabled, running;
345 * u64 cyc, time_offset;
346 * s64 pmc = 0;
347 *
348 * do {
349 * seq = pc->lock;
350 * barrier()
351 *
352 * enabled = pc->time_enabled;
353 * running = pc->time_running;
354 *
355 * if (pc->cap_usr_time && enabled != running) {
356 * cyc = rdtsc();
357 * time_offset = pc->time_offset;
358 * time_mult = pc->time_mult;
359 * time_shift = pc->time_shift;
360 * }
361 *
362 * idx = pc->index;
363 * count = pc->offset;
364 * if (pc->cap_usr_rdpmc && idx) {
365 * width = pc->pmc_width;
366 * pmc = rdpmc(idx - 1);
367 * }
368 *
369 * barrier();
370 * } while (pc->lock != seq);
371 *
372 * NOTE: for obvious reason this only works on self-monitoring
373 * processes.
374 */
375 __u32 lock; /* seqlock for synchronization */
376 __u32 index; /* hardware event identifier */
377 __s64 offset; /* add to hardware event value */
378 __u64 time_enabled; /* time event active */
379 __u64 time_running; /* time event on cpu */
380 union {
381 __u64 capabilities;
382 struct {
383 __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
384 cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */
385
386 cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */
387 cap_user_time : 1, /* The time_* fields are used */
388 cap_user_time_zero : 1, /* The time_zero field is used */
389 cap_____res : 59;
390 };
391 };
392
393 /*
394 * If cap_usr_rdpmc this field provides the bit-width of the value
395 * read using the rdpmc() or equivalent instruction. This can be used
396 * to sign extend the result like:
397 *
398 * pmc <<= 64 - width;
399 * pmc >>= 64 - width; // signed shift right
400 * count += pmc;
401 */
402 __u16 pmc_width;
403
404 /*
405 * If cap_usr_time the below fields can be used to compute the time
406 * delta since time_enabled (in ns) using rdtsc or similar.
407 *
408 * u64 quot, rem;
409 * u64 delta;
410 *
411 * quot = (cyc >> time_shift);
412 * rem = cyc & ((1 << time_shift) - 1);
413 * delta = time_offset + quot * time_mult +
414 * ((rem * time_mult) >> time_shift);
415 *
416 * Where time_offset,time_mult,time_shift and cyc are read in the
417 * seqcount loop described above. This delta can then be added to
418 * enabled and possible running (if idx), improving the scaling:
419 *
420 * enabled += delta;
421 * if (idx)
422 * running += delta;
423 *
424 * quot = count / running;
425 * rem = count % running;
426 * count = quot * enabled + (rem * enabled) / running;
427 */
428 __u16 time_shift;
429 __u32 time_mult;
430 __u64 time_offset;
431 /*
432 * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
433 * from sample timestamps.
434 *
435 * time = timestamp - time_zero;
436 * quot = time / time_mult;
437 * rem = time % time_mult;
438 * cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
439 *
440 * And vice versa:
441 *
442 * quot = cyc >> time_shift;
443 * rem = cyc & ((1 << time_shift) - 1);
444 * timestamp = time_zero + quot * time_mult +
445 * ((rem * time_mult) >> time_shift);
446 */
447 __u64 time_zero;
448 __u32 size; /* Header size up to __reserved[] fields. */
449
450 /*
451 * Hole for extension of the self monitor capabilities
452 */
453
454 __u8 __reserved[118*8+4]; /* align to 1k. */
455
456 /*
457 * Control data for the mmap() data buffer.
458 *
459 * User-space reading the @data_head value should issue an smp_rmb(),
460 * after reading this value.
461 *
462 * When the mapping is PROT_WRITE the @data_tail value should be
463 * written by userspace to reflect the last read data, after issueing
464 * an smp_mb() to separate the data read from the ->data_tail store.
465 * In this case the kernel will not over-write unread data.
466 *
467 * See perf_output_put_handle() for the data ordering.
468 */
469 __u64 data_head; /* head in the data section */
470 __u64 data_tail; /* user-space written tail */
471};
472
473#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
474#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
475#define PERF_RECORD_MISC_KERNEL (1 << 0)
476#define PERF_RECORD_MISC_USER (2 << 0)
477#define PERF_RECORD_MISC_HYPERVISOR (3 << 0)
478#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0)
479#define PERF_RECORD_MISC_GUEST_USER (5 << 0)
480
481#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
482/*
483 * Indicates that the content of PERF_SAMPLE_IP points to
484 * the actual instruction that triggered the event. See also
485 * perf_event_attr::precise_ip.
486 */
487#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
488/*
489 * Reserve the last bit to indicate some extended misc field
490 */
491#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15)
492
493struct perf_event_header {
494 __u32 type;
495 __u16 misc;
496 __u16 size;
497};
498
499enum perf_event_type {
500
501 /*
502 * If perf_event_attr.sample_id_all is set then all event types will
503 * have the sample_type selected fields related to where/when
504 * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
505 * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
506 * just after the perf_event_header and the fields already present for
507 * the existing fields, i.e. at the end of the payload. That way a newer
508 * perf.data file will be supported by older perf tools, with these new
509 * optional fields being ignored.
510 *
511 * struct sample_id {
512 * { u32 pid, tid; } && PERF_SAMPLE_TID
513 * { u64 time; } && PERF_SAMPLE_TIME
514 * { u64 id; } && PERF_SAMPLE_ID
515 * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
516 * { u32 cpu, res; } && PERF_SAMPLE_CPU
517 * { u64 id; } && PERF_SAMPLE_IDENTIFIER
518 * } && perf_event_attr::sample_id_all
519 *
520 * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The
521 * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
522 * relative to header.size.
523 */
524
525 /*
526 * The MMAP events record the PROT_EXEC mappings so that we can
527 * correlate userspace IPs to code. They have the following structure:
528 *
529 * struct {
530 * struct perf_event_header header;
531 *
532 * u32 pid, tid;
533 * u64 addr;
534 * u64 len;
535 * u64 pgoff;
536 * char filename[];
537 * struct sample_id sample_id;
538 * };
539 */
540 PERF_RECORD_MMAP = 1,
541
542 /*
543 * struct {
544 * struct perf_event_header header;
545 * u64 id;
546 * u64 lost;
547 * struct sample_id sample_id;
548 * };
549 */
550 PERF_RECORD_LOST = 2,
551
552 /*
553 * struct {
554 * struct perf_event_header header;
555 *
556 * u32 pid, tid;
557 * char comm[];
558 * struct sample_id sample_id;
559 * };
560 */
561 PERF_RECORD_COMM = 3,
562
563 /*
564 * struct {
565 * struct perf_event_header header;
566 * u32 pid, ppid;
567 * u32 tid, ptid;
568 * u64 time;
569 * struct sample_id sample_id;
570 * };
571 */
572 PERF_RECORD_EXIT = 4,
573
574 /*
575 * struct {
576 * struct perf_event_header header;
577 * u64 time;
578 * u64 id;
579 * u64 stream_id;
580 * struct sample_id sample_id;
581 * };
582 */
583 PERF_RECORD_THROTTLE = 5,
584 PERF_RECORD_UNTHROTTLE = 6,
585
586 /*
587 * struct {
588 * struct perf_event_header header;
589 * u32 pid, ppid;
590 * u32 tid, ptid;
591 * u64 time;
592 * struct sample_id sample_id;
593 * };
594 */
595 PERF_RECORD_FORK = 7,
596
597 /*
598 * struct {
599 * struct perf_event_header header;
600 * u32 pid, tid;
601 *
602 * struct read_format values;
603 * struct sample_id sample_id;
604 * };
605 */
606 PERF_RECORD_READ = 8,
607
608 /*
609 * struct {
610 * struct perf_event_header header;
611 *
612 * #
613 * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
614 * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
615 * # is fixed relative to header.
616 * #
617 *
618 * { u64 id; } && PERF_SAMPLE_IDENTIFIER
619 * { u64 ip; } && PERF_SAMPLE_IP
620 * { u32 pid, tid; } && PERF_SAMPLE_TID
621 * { u64 time; } && PERF_SAMPLE_TIME
622 * { u64 addr; } && PERF_SAMPLE_ADDR
623 * { u64 id; } && PERF_SAMPLE_ID
624 * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
625 * { u32 cpu, res; } && PERF_SAMPLE_CPU
626 * { u64 period; } && PERF_SAMPLE_PERIOD
627 *
628 * { struct read_format values; } && PERF_SAMPLE_READ
629 *
630 * { u64 nr,
631 * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
632 *
633 * #
634 * # The RAW record below is opaque data wrt the ABI
635 * #
636 * # That is, the ABI doesn't make any promises wrt to
637 * # the stability of its content, it may vary depending
638 * # on event, hardware, kernel version and phase of
639 * # the moon.
640 * #
641 * # In other words, PERF_SAMPLE_RAW contents are not an ABI.
642 * #
643 *
644 * { u32 size;
645 * char data[size];}&& PERF_SAMPLE_RAW
646 *
647 * { u64 nr;
648 * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
649 *
650 * { u64 abi; # enum perf_sample_regs_abi
651 * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
652 *
653 * { u64 size;
654 * char data[size];
655 * u64 dyn_size; } && PERF_SAMPLE_STACK_USER
656 *
657 * { u64 weight; } && PERF_SAMPLE_WEIGHT
658 * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
659 * };
660 */
661 PERF_RECORD_SAMPLE = 9,
662
663 /*
664 * The MMAP2 records are an augmented version of MMAP, they add
665 * maj, min, ino numbers to be used to uniquely identify each mapping
666 *
667 * struct {
668 * struct perf_event_header header;
669 *
670 * u32 pid, tid;
671 * u64 addr;
672 * u64 len;
673 * u64 pgoff;
674 * u32 maj;
675 * u32 min;
676 * u64 ino;
677 * u64 ino_generation;
678 * char filename[];
679 * struct sample_id sample_id;
680 * };
681 */
682 PERF_RECORD_MMAP2 = 10,
683
684 PERF_RECORD_MAX, /* non-ABI */
685};
686
687#define PERF_MAX_STACK_DEPTH 127
688
689enum perf_callchain_context {
690 PERF_CONTEXT_HV = (__u64)-32,
691 PERF_CONTEXT_KERNEL = (__u64)-128,
692 PERF_CONTEXT_USER = (__u64)-512,
693
694 PERF_CONTEXT_GUEST = (__u64)-2048,
695 PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176,
696 PERF_CONTEXT_GUEST_USER = (__u64)-2560,
697
698 PERF_CONTEXT_MAX = (__u64)-4095,
699};
700
701#define PERF_FLAG_FD_NO_GROUP (1U << 0)
702#define PERF_FLAG_FD_OUTPUT (1U << 1)
703#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */
704
705union perf_mem_data_src {
706 __u64 val;
707 struct {
708 __u64 mem_op:5, /* type of opcode */
709 mem_lvl:14, /* memory hierarchy level */
710 mem_snoop:5, /* snoop mode */
711 mem_lock:2, /* lock instr */
712 mem_dtlb:7, /* tlb access */
713 mem_rsvd:31;
714 };
715};
716
717/* type of opcode (load/store/prefetch,code) */
718#define PERF_MEM_OP_NA 0x01 /* not available */
719#define PERF_MEM_OP_LOAD 0x02 /* load instruction */
720#define PERF_MEM_OP_STORE 0x04 /* store instruction */
721#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */
722#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */
723#define PERF_MEM_OP_SHIFT 0
724
725/* memory hierarchy (memory level, hit or miss) */
726#define PERF_MEM_LVL_NA 0x01 /* not available */
727#define PERF_MEM_LVL_HIT 0x02 /* hit level */
728#define PERF_MEM_LVL_MISS 0x04 /* miss level */
729#define PERF_MEM_LVL_L1 0x08 /* L1 */
730#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */
731#define PERF_MEM_LVL_L2 0x20 /* L2 */
732#define PERF_MEM_LVL_L3 0x40 /* L3 */
733#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */
734#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */
735#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */
736#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */
737#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */
738#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */
739#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */
740#define PERF_MEM_LVL_SHIFT 5
741
742/* snoop mode */
743#define PERF_MEM_SNOOP_NA 0x01 /* not available */
744#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */
745#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */
746#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */
747#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */
748#define PERF_MEM_SNOOP_SHIFT 19
749
750/* locked instruction */
751#define PERF_MEM_LOCK_NA 0x01 /* not available */
752#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */
753#define PERF_MEM_LOCK_SHIFT 24
754
755/* TLB access */
756#define PERF_MEM_TLB_NA 0x01 /* not available */
757#define PERF_MEM_TLB_HIT 0x02 /* hit level */
758#define PERF_MEM_TLB_MISS 0x04 /* miss level */
759#define PERF_MEM_TLB_L1 0x08 /* L1 */
760#define PERF_MEM_TLB_L2 0x10 /* L2 */
761#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/
762#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
763#define PERF_MEM_TLB_SHIFT 26
764
765#define PERF_MEM_S(a, s) \
766 (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
767
768/*
769 * single taken branch record layout:
770 *
771 * from: source instruction (may not always be a branch insn)
772 * to: branch target
773 * mispred: branch target was mispredicted
774 * predicted: branch target was predicted
775 *
776 * support for mispred, predicted is optional. In case it
777 * is not supported mispred = predicted = 0.
778 *
779 * in_tx: running in a hardware transaction
780 * abort: aborting a hardware transaction
781 */
782struct perf_branch_entry {
783 __u64 from;
784 __u64 to;
785 __u64 mispred:1, /* target mispredicted */
786 predicted:1,/* target predicted */
787 in_tx:1, /* in transaction */
788 abort:1, /* transaction abort */
789 reserved:60;
790};
791
792#endif /* _LINUX_PERF_EVENT_H */
diff --git a/daemon/k/perf_event.h b/daemon/k/perf_event.h
new file mode 120000
index 0000000..e5dff8c
--- /dev/null
+++ b/daemon/k/perf_event.h
@@ -0,0 +1 @@
perf_event.3.12.h \ No newline at end of file
diff --git a/daemon/main.cpp b/daemon/main.cpp
index bfd36b9..1275aef 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -1,32 +1,30 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <stdlib.h> 9#include <arpa/inet.h>
10#include <signal.h>
11#include <sys/wait.h>
12#include <unistd.h>
13#include <sys/syscall.h>
14#include <sys/prctl.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <sys/mount.h>
18#include <fcntl.h> 10#include <fcntl.h>
11#include <pthread.h>
19#include <sys/mman.h> 12#include <sys/mman.h>
20#include <sys/time.h> 13#include <sys/mount.h>
14#include <sys/prctl.h>
21#include <sys/resource.h> 15#include <sys/resource.h>
22#include <arpa/inet.h>
23#include <sys/socket.h> 16#include <sys/socket.h>
17#include <sys/stat.h>
18#include <sys/syscall.h>
19#include <sys/wait.h>
20#include <unistd.h>
21
24#include "Child.h" 22#include "Child.h"
25#include "SessionData.h" 23#include "KMod.h"
26#include "OlySocket.h"
27#include "Logging.h" 24#include "Logging.h"
25#include "OlySocket.h"
28#include "OlyUtility.h" 26#include "OlyUtility.h"
29#include "KMod.h" 27#include "SessionData.h"
30 28
31#define DEBUG false 29#define DEBUG false
32 30
@@ -34,7 +32,7 @@ extern Child* child;
34static int shutdownFilesystem(); 32static int shutdownFilesystem();
35static pthread_mutex_t numSessions_mutex; 33static pthread_mutex_t numSessions_mutex;
36static int numSessions = 0; 34static int numSessions = 0;
37static OlySocket* sock = NULL; 35static OlyServerSocket* sock = NULL;
38static bool driverRunningAtStart = false; 36static bool driverRunningAtStart = false;
39static bool driverMountedAtStart = false; 37static bool driverMountedAtStart = false;
40 38
@@ -157,6 +155,7 @@ typedef struct {
157static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 }; 155static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 };
158 156
159static void* answerThread(void* pVoid) { 157static void* answerThread(void* pVoid) {
158 prctl(PR_SET_NAME, (unsigned long)&"gatord-discover", 0, 0, 0);
160 const struct cmdline_t * const cmdline = (struct cmdline_t *)pVoid; 159 const struct cmdline_t * const cmdline = (struct cmdline_t *)pVoid;
161 RVIConfigureInfo dstAns; 160 RVIConfigureInfo dstAns;
162 int req = udpPort(UDP_REQ_PORT); 161 int req = udpPort(UDP_REQ_PORT);
@@ -231,16 +230,7 @@ static bool init_module (const char * const location) {
231 return ret; 230 return ret;
232} 231}
233 232
234static int setupFilesystem(char* module) { 233static bool setupFilesystem(char* module) {
235 int retval;
236
237 // Verify root permissions
238 uid_t euid = geteuid();
239 if (euid) {
240 logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
241 handleException();
242 }
243
244 if (module) { 234 if (module) {
245 // unmount and rmmod if the module was specified on the commandline, i.e. ensure that the specified module is indeed running 235 // unmount and rmmod if the module was specified on the commandline, i.e. ensure that the specified module is indeed running
246 shutdownFilesystem(); 236 shutdownFilesystem();
@@ -252,7 +242,7 @@ static int setupFilesystem(char* module) {
252 } 242 }
253 } 243 }
254 244
255 retval = mountGatorFS(); 245 const int retval = mountGatorFS();
256 if (retval == 1) { 246 if (retval == 1) {
257 logg->logMessage("Driver already running at startup"); 247 logg->logMessage("Driver already running at startup");
258 driverRunningAtStart = true; 248 driverRunningAtStart = true;
@@ -274,8 +264,8 @@ static int setupFilesystem(char* module) {
274 } 264 }
275 265
276 if (access(location, F_OK) == -1) { 266 if (access(location, F_OK) == -1) {
277 logg->logError(__FILE__, __LINE__, "Unable to locate gator.ko driver:\n >>> gator.ko should be co-located with gatord in the same directory\n >>> OR insmod gator.ko prior to launching gatord\n >>> OR specify the location of gator.ko on the command line"); 267 // The gator kernel is not already loaded and unable to locate gator.ko
278 handleException(); 268 return false;
279 } 269 }
280 270
281 // Load driver 271 // Load driver
@@ -296,7 +286,7 @@ static int setupFilesystem(char* module) {
296 } 286 }
297 } 287 }
298 288
299 return 0; 289 return true;
300} 290}
301 291
302static int shutdownFilesystem() { 292static int shutdownFilesystem() {
@@ -418,8 +408,28 @@ int main(int argc, char** argv) {
418 // Parse the command line parameters 408 // Parse the command line parameters
419 struct cmdline_t cmdline = parseCommandLine(argc, argv); 409 struct cmdline_t cmdline = parseCommandLine(argc, argv);
420 410
411 // Verify root permissions
412 uid_t euid = geteuid();
413 if (euid) {
414 logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
415 handleException();
416 }
417
421 // Call before setting up the SIGCHLD handler, as system() spawns child processes 418 // Call before setting up the SIGCHLD handler, as system() spawns child processes
422 setupFilesystem(cmdline.module); 419 if (!setupFilesystem(cmdline.module)) {
420 logg->logMessage("Unable to setup gatorfs, trying perf");
421 if (!gSessionData->perf.setup()) {
422 logg->logError(__FILE__, __LINE__,
423 "Unable to locate gator.ko driver:\n"
424 " >>> gator.ko should be co-located with gatord in the same directory\n"
425 " >>> OR insmod gator.ko prior to launching gatord\n"
426 " >>> OR specify the location of gator.ko on the command line\n"
427 " >>> OR run Linux 3.12 or later with perf support to collect data via userspace only");
428 handleException();
429 }
430 }
431
432 gSessionData->hwmon.setup();
423 433
424 // Handle child exit codes 434 // Handle child exit codes
425 signal(SIGCHLD, child_exit); 435 signal(SIGCHLD, child_exit);
@@ -439,11 +449,11 @@ int main(int argc, char** argv) {
439 logg->logError(__FILE__, __LINE__, "Failed to create answer thread"); 449 logg->logError(__FILE__, __LINE__, "Failed to create answer thread");
440 handleException(); 450 handleException();
441 } 451 }
442 sock = new OlySocket(cmdline.port, true); 452 sock = new OlyServerSocket(cmdline.port);
443 // Forever loop, can be exited via a signal or exception 453 // Forever loop, can be exited via a signal or exception
444 while (1) { 454 while (1) {
445 logg->logMessage("Waiting on connection..."); 455 logg->logMessage("Waiting on connection...");
446 sock->acceptConnection(); 456 OlySocket client(sock->acceptConnection());
447 457
448 int pid = fork(); 458 int pid = fork();
449 if (pid < 0) { 459 if (pid < 0) {
@@ -452,13 +462,13 @@ int main(int argc, char** argv) {
452 } else if (pid == 0) { 462 } else if (pid == 0) {
453 // Child 463 // Child
454 sock->closeServerSocket(); 464 sock->closeServerSocket();
455 child = new Child(sock, numSessions + 1); 465 child = new Child(&client, numSessions + 1);
456 child->run(); 466 child->run();
457 delete child; 467 delete child;
458 exit(0); 468 exit(0);
459 } else { 469 } else {
460 // Parent 470 // Parent
461 sock->closeSocket(); 471 client.closeSocket();
462 472
463 pthread_mutex_lock(&numSessions_mutex); 473 pthread_mutex_lock(&numSessions_mutex);
464 numSessions++; 474 numSessions++;
diff --git a/driver/Kconfig b/driver/Kconfig
new file mode 100644
index 0000000..e46ccb9
--- /dev/null
+++ b/driver/Kconfig
@@ -0,0 +1,39 @@
1config GATOR
2 tristate "Gator module for ARM's Streamline Performance Analyzer"
3 default m if (ARM || ARM64)
4 depends on PROFILING
5 depends on HIGH_RES_TIMERS
6 depends on LOCAL_TIMERS || !(ARM && SMP)
7 depends on PERF_EVENTS
8 depends on HW_PERF_EVENTS || !(ARM || ARM64)
9 select TRACING
10 help
11 Gator module for ARM's Streamline Performance Analyzer
12
13config GATOR_WITH_MALI_SUPPORT
14 bool
15
16choice
17 prompt "Enable Mali GPU support in Gator"
18 depends on GATOR
19 optional
20 help
21 Enable Mali GPU support in Gator
22
23config GATOR_MALI_4XXMP
24 bool "Mali-400MP or Mali-450MP"
25 select GATOR_WITH_MALI_SUPPORT
26
27config GATOR_MALI_T6XX
28 bool "Mali-T604 or Mali-T658"
29 select GATOR_WITH_MALI_SUPPORT
30
31endchoice
32
33config GATOR_MALI_PATH
34 string "Path to Mali driver"
35 depends on GATOR_WITH_MALI_SUPPORT
36 default "drivers/gpu/arm/mali400mp"
37 help
38 The gator code adds this to its include path so it can get the Mali
39 trace headers with: #include "linux/mali_linux_trace.h"
diff --git a/driver/gator.h b/driver/gator.h
index d8981ed..586cd9e 100644
--- a/driver/gator.h
+++ b/driver/gator.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -31,6 +31,7 @@
31#define CORTEX_A9 0xc09 31#define CORTEX_A9 0xc09
32#define CORTEX_A12 0xc0d 32#define CORTEX_A12 0xc0d
33#define CORTEX_A15 0xc0f 33#define CORTEX_A15 0xc0f
34#define CORTEX_A17 0xc0e
34#define SCORPION 0x00f 35#define SCORPION 0x00f
35#define SCORPIONMP 0x02d 36#define SCORPIONMP 0x02d
36#define KRAITSIM 0x049 37#define KRAITSIM 0x049
@@ -47,9 +48,7 @@ struct gator_cpu {
47 const int cpuid; 48 const int cpuid;
48 // Human readable name 49 // Human readable name
49 const char core_name[MAXSIZE_CORE_NAME]; 50 const char core_name[MAXSIZE_CORE_NAME];
50 // Perf PMU name 51 // gatorfs event and Perf PMU name
51 const char * const pmu_name;
52 // gatorfs event name
53 const char * const pmnc_name; 52 const char * const pmnc_name;
54 // compatible from Documentation/devicetree/bindings/arm/cpus.txt 53 // compatible from Documentation/devicetree/bindings/arm/cpus.txt
55 const char * const dt_name; 54 const char * const dt_name;
@@ -62,10 +61,6 @@ const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name);
62/****************************************************************************** 61/******************************************************************************
63 * Filesystem 62 * Filesystem
64 ******************************************************************************/ 63 ******************************************************************************/
65int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
66 char const *name,
67 const struct file_operations *fops, int perm);
68
69struct dentry *gatorfs_mkdir(struct super_block *sb, struct dentry *root, 64struct dentry *gatorfs_mkdir(struct super_block *sb, struct dentry *root,
70 char const *name); 65 char const *name);
71 66
@@ -75,8 +70,6 @@ int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
75int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root, 70int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
76 char const *name, unsigned long *val); 71 char const *name, unsigned long *val);
77 72
78void gator_op_create_files(struct super_block *sb, struct dentry *root);
79
80/****************************************************************************** 73/******************************************************************************
81 * Tracepoints 74 * Tracepoints
82 ******************************************************************************/ 75 ******************************************************************************/
diff --git a/driver/gator_annotate.c b/driver/gator_annotate.c
index 5b9399b..7e2c6e5 100644
--- a/driver/gator_annotate.c
+++ b/driver/gator_annotate.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_annotate_kernel.c b/driver/gator_annotate_kernel.c
index a406e48..0108068 100644
--- a/driver/gator_annotate_kernel.c
+++ b/driver/gator_annotate_kernel.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -29,12 +29,14 @@ static void kannotate_write(const char *ptr, unsigned int size)
29 } 29 }
30} 30}
31 31
32static void marshal_u16(char *buf, u16 val) { 32static void marshal_u16(char *buf, u16 val)
33{
33 buf[0] = val & 0xff; 34 buf[0] = val & 0xff;
34 buf[1] = (val >> 8) & 0xff; 35 buf[1] = (val >> 8) & 0xff;
35} 36}
36 37
37static void marshal_u32(char *buf, u32 val) { 38static void marshal_u32(char *buf, u32 val)
39{
38 buf[0] = val & 0xff; 40 buf[0] = val & 0xff;
39 buf[1] = (val >> 8) & 0xff; 41 buf[1] = (val >> 8) & 0xff;
40 buf[2] = (val >> 16) & 0xff; 42 buf[2] = (val >> 16) & 0xff;
diff --git a/driver/gator_backtrace.c b/driver/gator_backtrace.c
index ffacb49..9f305cf 100644
--- a/driver/gator_backtrace.c
+++ b/driver/gator_backtrace.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -30,6 +30,18 @@ struct stack_frame_eabi {
30 }; 30 };
31}; 31};
32 32
33static void gator_add_trace(int cpu, unsigned long address)
34{
35 off_t offset = 0;
36 unsigned long cookie = get_address_cookie(cpu, current, address & ~1, &offset);
37
38 if (cookie == NO_COOKIE || cookie == UNRESOLVED_COOKIE) {
39 offset = address;
40 }
41
42 marshal_backtrace(offset & ~1, cookie, 0);
43}
44
33static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth) 45static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth)
34{ 46{
35#if defined(__arm__) || defined(__aarch64__) 47#if defined(__arm__) || defined(__aarch64__)
@@ -122,7 +134,7 @@ static int report_trace(struct stackframe *frame, void *d)
122 addr = addr - (unsigned long)mod->module_core; 134 addr = addr - (unsigned long)mod->module_core;
123 } 135 }
124#endif 136#endif
125 marshal_backtrace(addr & ~1, cookie); 137 marshal_backtrace(addr & ~1, cookie, 1);
126 (*depth)--; 138 (*depth)--;
127 } 139 }
128 140
@@ -136,7 +148,7 @@ static int report_trace(struct stackframe *frame, void *d)
136#if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING) 148#if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING)
137// Disabled by default 149// Disabled by default
138MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding."); 150MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding.");
139bool kernel_stack_unwinding = 0; 151static bool kernel_stack_unwinding = 0;
140module_param(kernel_stack_unwinding, bool, 0644); 152module_param(kernel_stack_unwinding, bool, 0644);
141#endif 153#endif
142 154
@@ -163,6 +175,34 @@ static void kernel_backtrace(int cpu, struct pt_regs *const regs)
163#endif 175#endif
164 walk_stackframe(&frame, report_trace, &depth); 176 walk_stackframe(&frame, report_trace, &depth);
165#else 177#else
166 marshal_backtrace(PC_REG & ~1, NO_COOKIE); 178 marshal_backtrace(PC_REG & ~1, NO_COOKIE, 1);
167#endif 179#endif
168} 180}
181
182static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time)
183{
184 bool in_kernel;
185 unsigned long exec_cookie;
186
187 if (!regs)
188 return;
189
190 in_kernel = !user_mode(regs);
191 exec_cookie = get_exec_cookie(cpu, current);
192
193 if (!marshal_backtrace_header(exec_cookie, current->tgid, current->pid, time))
194 return;
195
196 if (in_kernel) {
197 kernel_backtrace(cpu, regs);
198 } else {
199 // Cookie+PC
200 gator_add_trace(cpu, PC_REG);
201
202 // Backtrace
203 if (gator_backtrace_depth)
204 arm_backtrace_eabi(cpu, regs, gator_backtrace_depth);
205 }
206
207 marshal_backtrace_footer(time);
208}
diff --git a/driver/gator_buffer.c b/driver/gator_buffer.c
new file mode 100644
index 0000000..eba22df
--- /dev/null
+++ b/driver/gator_buffer.c
@@ -0,0 +1,168 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10static void marshal_frame(int cpu, int buftype)
11{
12 int frame;
13
14 if (!per_cpu(gator_buffer, cpu)[buftype]) {
15 return;
16 }
17
18 switch (buftype) {
19 case SUMMARY_BUF:
20 frame = FRAME_SUMMARY;
21 break;
22 case BACKTRACE_BUF:
23 frame = FRAME_BACKTRACE;
24 break;
25 case NAME_BUF:
26 frame = FRAME_NAME;
27 break;
28 case COUNTER_BUF:
29 frame = FRAME_COUNTER;
30 break;
31 case BLOCK_COUNTER_BUF:
32 frame = FRAME_BLOCK_COUNTER;
33 break;
34 case ANNOTATE_BUF:
35 frame = FRAME_ANNOTATE;
36 break;
37 case SCHED_TRACE_BUF:
38 frame = FRAME_SCHED_TRACE;
39 break;
40 case GPU_TRACE_BUF:
41 frame = FRAME_GPU_TRACE;
42 break;
43 case IDLE_BUF:
44 frame = FRAME_IDLE;
45 break;
46 default:
47 frame = -1;
48 break;
49 }
50
51 // add response type
52 if (gator_response_type > 0) {
53 gator_buffer_write_packed_int(cpu, buftype, gator_response_type);
54 }
55
56 // leave space for 4-byte unpacked length
57 per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype];
58
59 // add frame type and core number
60 gator_buffer_write_packed_int(cpu, buftype, frame);
61 gator_buffer_write_packed_int(cpu, buftype, cpu);
62}
63
64static int buffer_bytes_available(int cpu, int buftype)
65{
66 int remaining, filled;
67
68 filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype];
69 if (filled < 0) {
70 filled += gator_buffer_size[buftype];
71 }
72
73 remaining = gator_buffer_size[buftype] - filled;
74
75 if (per_cpu(buffer_space_available, cpu)[buftype]) {
76 // Give some extra room; also allows space to insert the overflow error packet
77 remaining -= 200;
78 } else {
79 // Hysteresis, prevents multiple overflow messages
80 remaining -= 2000;
81 }
82
83 return remaining;
84}
85
86static bool buffer_check_space(int cpu, int buftype, int bytes)
87{
88 int remaining = buffer_bytes_available(cpu, buftype);
89
90 if (remaining < bytes) {
91 per_cpu(buffer_space_available, cpu)[buftype] = false;
92 } else {
93 per_cpu(buffer_space_available, cpu)[buftype] = true;
94 }
95
96 return per_cpu(buffer_space_available, cpu)[buftype];
97}
98
99static int contiguous_space_available(int cpu, int buftype)
100{
101 int remaining = buffer_bytes_available(cpu, buftype);
102 int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype];
103 if (remaining < contiguous)
104 return remaining;
105 else
106 return contiguous;
107}
108
109static void gator_commit_buffer(int cpu, int buftype, u64 time)
110{
111 int type_length, commit, length, byte;
112 unsigned long flags;
113
114 if (!per_cpu(gator_buffer, cpu)[buftype])
115 return;
116
117 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
118 local_irq_save(flags);
119 type_length = gator_response_type ? 1 : 0;
120 commit = per_cpu(gator_buffer_commit, cpu)[buftype];
121 length = per_cpu(gator_buffer_write, cpu)[buftype] - commit;
122 if (length < 0) {
123 length += gator_buffer_size[buftype];
124 }
125 length = length - type_length - sizeof(s32);
126
127 if (length <= FRAME_HEADER_SIZE) {
128 // Nothing to write, only the frame header is present
129 local_irq_restore(flags);
130 return;
131 }
132
133 for (byte = 0; byte < sizeof(s32); byte++) {
134 per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
135 }
136
137 per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
138
139 if (gator_live_rate > 0) {
140 while (time > per_cpu(gator_buffer_commit_time, cpu)) {
141 per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
142 }
143 }
144
145 marshal_frame(cpu, buftype);
146 local_irq_restore(flags);
147
148 // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
149 if (per_cpu(in_scheduler_context, cpu)) {
150#ifndef CONFIG_PREEMPT_RT_FULL
151 // mod_timer can not be used in interrupt context in RT-Preempt full
152 mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
153#endif
154 } else {
155 up(&gator_buffer_wake_sem);
156 }
157}
158
159static void buffer_check(int cpu, int buftype, u64 time)
160{
161 int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype];
162 if (filled < 0) {
163 filled += gator_buffer_size[buftype];
164 }
165 if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
166 gator_commit_buffer(cpu, buftype, time);
167 }
168}
diff --git a/driver/gator_pack.c b/driver/gator_buffer_write.c
index 2c082f2..b621ba9 100644
--- a/driver/gator_pack.c
+++ b/driver/gator_buffer_write.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -56,3 +56,25 @@ static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x)
56 56
57 per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask; 57 per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask;
58} 58}
59
60static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len)
61{
62 int i;
63 u32 write = per_cpu(gator_buffer_write, cpu)[buftype];
64 u32 mask = gator_buffer_mask[buftype];
65 char *buffer = per_cpu(gator_buffer, cpu)[buftype];
66
67 for (i = 0; i < len; i++) {
68 buffer[write] = x[i];
69 write = (write + 1) & mask;
70 }
71
72 per_cpu(gator_buffer_write, cpu)[buftype] = write;
73}
74
75static void gator_buffer_write_string(int cpu, int buftype, const char *x)
76{
77 int len = strlen(x);
78 gator_buffer_write_packed_int(cpu, buftype, len);
79 gator_buffer_write_bytes(cpu, buftype, x, len);
80}
diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c
index eb9b946..5c7d842 100644
--- a/driver/gator_cookies.c
+++ b/driver/gator_cookies.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -30,7 +30,7 @@ static DEFINE_PER_CPU(struct cookie_args *, translate_buffer);
30 30
31static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq); 31static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq);
32static void wq_cookie_handler(struct work_struct *unused); 32static void wq_cookie_handler(struct work_struct *unused);
33DECLARE_WORK(cookie_work, wq_cookie_handler); 33static DECLARE_WORK(cookie_work, wq_cookie_handler);
34static struct timer_list app_process_wake_up_timer; 34static struct timer_list app_process_wake_up_timer;
35static void app_process_wake_up_handler(unsigned long unused_data); 35static void app_process_wake_up_handler(unsigned long unused_data);
36 36
@@ -131,7 +131,9 @@ static void translate_buffer_write_args(int cpu, struct task_struct *task, const
131 args = &per_cpu(translate_buffer, cpu)[write]; 131 args = &per_cpu(translate_buffer, cpu)[write];
132 args->task = task; 132 args->task = task;
133 args->text = text; 133 args->text = text;
134#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
134 get_task_struct(task); 135 get_task_struct(task);
136#endif
135 per_cpu(translate_buffer_write, cpu) = next_write; 137 per_cpu(translate_buffer_write, cpu) = next_write;
136 } 138 }
137 139
@@ -165,7 +167,9 @@ static void wq_cookie_handler(struct work_struct *unused)
165 translate_buffer_read_args(cpu, &args); 167 translate_buffer_read_args(cpu, &args);
166 cookie = get_cookie(cpu, args.task, args.text, true); 168 cookie = get_cookie(cpu, args.task, args.text, true);
167 marshal_link(cookie, args.task->tgid, args.task->pid); 169 marshal_link(cookie, args.task->tgid, args.task->pid);
170#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
168 put_task_struct(args.task); 171 put_task_struct(args.task);
172#endif
169 } 173 }
170 } 174 }
171 175
diff --git a/driver/gator_events_armv6.c b/driver/gator_events_armv6.c
index dd79740..3536456 100644
--- a/driver/gator_events_armv6.c
+++ b/driver/gator_events_armv6.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c
index 30881c8..153119b 100644
--- a/driver/gator_events_armv7.c
+++ b/driver/gator_events_armv7.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -141,9 +141,9 @@ static int gator_events_armv7_create_files(struct super_block *sb, struct dentry
141 for (i = 0; i < pmnc_counters; i++) { 141 for (i = 0; i < pmnc_counters; i++) {
142 char buf[40]; 142 char buf[40];
143 if (i == 0) { 143 if (i == 0) {
144 snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name); 144 snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
145 } else { 145 } else {
146 snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i - 1); 146 snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1);
147 } 147 }
148 dir = gatorfs_mkdir(sb, root, buf); 148 dir = gatorfs_mkdir(sb, root, buf);
149 if (!dir) { 149 if (!dir) {
@@ -275,25 +275,27 @@ int gator_events_armv7_init(void)
275 275
276 switch (gator_cpuid()) { 276 switch (gator_cpuid()) {
277 case CORTEX_A5: 277 case CORTEX_A5:
278 pmnc_name = "Cortex-A5"; 278 pmnc_name = "ARMv7_Cortex_A5";
279 pmnc_counters = 2; 279 pmnc_counters = 2;
280 break; 280 break;
281 case CORTEX_A7: 281 case CORTEX_A7:
282 pmnc_name = "Cortex-A7"; 282 pmnc_name = "ARMv7_Cortex_A7";
283 pmnc_counters = 4; 283 pmnc_counters = 4;
284 break; 284 break;
285 case CORTEX_A8: 285 case CORTEX_A8:
286 pmnc_name = "Cortex-A8"; 286 pmnc_name = "ARMv7_Cortex_A8";
287 pmnc_counters = 4; 287 pmnc_counters = 4;
288 break; 288 break;
289 case CORTEX_A9: 289 case CORTEX_A9:
290 pmnc_name = "Cortex-A9"; 290 pmnc_name = "ARMv7_Cortex_A9";
291 pmnc_counters = 6; 291 pmnc_counters = 6;
292 break; 292 break;
293 // ARM Cortex A12 is not supported by version of Linux before 3.0
293 case CORTEX_A15: 294 case CORTEX_A15:
294 pmnc_name = "Cortex-A15"; 295 pmnc_name = "ARMv7_Cortex_A15";
295 pmnc_counters = 6; 296 pmnc_counters = 6;
296 break; 297 break;
298 // ARM Cortex A17 is not supported by version of Linux before 3.0
297 default: 299 default:
298 return -1; 300 return -1;
299 } 301 }
diff --git a/driver/gator_events_block.c b/driver/gator_events_block.c
index 691ef25..b2bc414 100644
--- a/driver/gator_events_block.c
+++ b/driver/gator_events_block.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_ccn-504.c b/driver/gator_events_ccn-504.c
index b892319..024ffc2 100644
--- a/driver/gator_events_ccn-504.c
+++ b/driver/gator_events_ccn-504.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_irq.c b/driver/gator_events_irq.c
index b11879a..facbdd6 100644
--- a/driver/gator_events_irq.c
+++ b/driver/gator_events_irq.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_l2c-310.c b/driver/gator_events_l2c-310.c
index ee521af..553f970 100644
--- a/driver/gator_events_l2c-310.c
+++ b/driver/gator_events_l2c-310.c
@@ -1,7 +1,7 @@
1/** 1/**
2 * l2c310 (L2 Cache Controller) event counters for gator 2 * l2c310 (L2 Cache Controller) event counters for gator
3 * 3 *
4 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 4 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_mali_4xx.c b/driver/gator_events_mali_4xx.c
index 6719c1e..85d4764 100644
--- a/driver/gator_events_mali_4xx.c
+++ b/driver/gator_events_mali_4xx.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_mali_4xx.h b/driver/gator_events_mali_4xx.h
index 413ad0f..976ca8c 100644
--- a/driver/gator_events_mali_4xx.h
+++ b/driver/gator_events_mali_4xx.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_mali_common.c b/driver/gator_events_mali_common.c
index 466ca16..dc58dcf 100644
--- a/driver/gator_events_mali_common.c
+++ b/driver/gator_events_mali_common.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_mali_common.h b/driver/gator_events_mali_common.h
index 509f9b6..41c2a3c 100644
--- a/driver/gator_events_mali_common.h
+++ b/driver/gator_events_mali_common.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_mali_t6xx.c b/driver/gator_events_mali_t6xx.c
index 7bf7d6a..76f14ee 100644
--- a/driver/gator_events_mali_t6xx.c
+++ b/driver/gator_events_mali_t6xx.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -15,7 +15,13 @@
15#include <linux/slab.h> 15#include <linux/slab.h>
16#include <asm/io.h> 16#include <asm/io.h>
17 17
18#ifdef MALI_DIR_MIDGARD
19/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
20#include "mali_linux_trace.h"
21#else
22/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
18#include "linux/mali_linux_trace.h" 23#include "linux/mali_linux_trace.h"
24#endif
19 25
20#include "gator_events_mali_common.h" 26#include "gator_events_mali_common.h"
21 27
diff --git a/driver/gator_events_mali_t6xx_hw.c b/driver/gator_events_mali_t6xx_hw.c
index e406991..dfbc91f 100644
--- a/driver/gator_events_mali_t6xx_hw.c
+++ b/driver/gator_events_mali_t6xx_hw.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -16,9 +16,17 @@
16#include <asm/io.h> 16#include <asm/io.h>
17 17
18/* Mali T6xx DDK includes */ 18/* Mali T6xx DDK includes */
19#ifdef MALI_DIR_MIDGARD
20/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
21#include "mali_linux_trace.h"
22#include "mali_kbase.h"
23#include "mali_kbase_mem_linux.h"
24#else
25/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
19#include "linux/mali_linux_trace.h" 26#include "linux/mali_linux_trace.h"
20#include "kbase/src/common/mali_kbase.h" 27#include "kbase/src/common/mali_kbase.h"
21#include "kbase/src/linux/mali_kbase_mem_linux.h" 28#include "kbase/src/linux/mali_kbase_mem_linux.h"
29#endif
22 30
23#include "gator_events_mali_common.h" 31#include "gator_events_mali_common.h"
24 32
diff --git a/driver/gator_events_mali_t6xx_hw_test.c b/driver/gator_events_mali_t6xx_hw_test.c
index efb32dd..ba6553f 100644
--- a/driver/gator_events_mali_t6xx_hw_test.c
+++ b/driver/gator_events_mali_t6xx_hw_test.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_meminfo.c b/driver/gator_events_meminfo.c
index 451290d..c633dfd 100644
--- a/driver/gator_events_meminfo.c
+++ b/driver/gator_events_meminfo.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -274,6 +274,28 @@ static int gator_events_meminfo_read(long long **buffer)
274 return meminfo_length; 274 return meminfo_length;
275} 275}
276 276
277#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
278
279static inline unsigned long gator_get_mm_counter(struct mm_struct *mm, int member)
280{
281#ifdef SPLIT_RSS_COUNTING
282 long val = atomic_long_read(&mm->rss_stat.count[member]);
283 if (val < 0)
284 val = 0;
285 return (unsigned long)val;
286#else
287#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
288 return mm->rss_stat.count[member];
289#else
290 return atomic_long_read(&mm->rss_stat.count[member]);
291#endif
292#endif
293}
294
295#define get_mm_counter(mm, member) gator_get_mm_counter(mm, member)
296
297#endif
298
277static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct *task) 299static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct *task)
278{ 300{
279 struct mm_struct *mm; 301 struct mm_struct *mm;
@@ -302,7 +324,7 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
302 // Derived from task_statm in fs/proc/task_mmu.c 324 // Derived from task_statm in fs/proc/task_mmu.c
303 if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) { 325 if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) {
304 share = get_mm_counter(mm, 326 share = get_mm_counter(mm,
305#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) 327#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
306 file_rss 328 file_rss
307#else 329#else
308 MM_FILEPAGES 330 MM_FILEPAGES
@@ -338,7 +360,7 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
338 360
339 if (meminfo_enabled[MEMINFO_MEMUSED]) { 361 if (meminfo_enabled[MEMINFO_MEMUSED]) {
340 value = share + get_mm_counter(mm, 362 value = share + get_mm_counter(mm,
341#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) 363#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
342 anon_rss 364 anon_rss
343#else 365#else
344 MM_ANONPAGES 366 MM_ANONPAGES
diff --git a/driver/gator_events_mmapped.c b/driver/gator_events_mmapped.c
index f055e48..3b248ec 100644
--- a/driver/gator_events_mmapped.c
+++ b/driver/gator_events_mmapped.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Example events provider 2 * Example events provider
3 * 3 *
4 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 4 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_net.c b/driver/gator_events_net.c
index 9c8d3a4..11c10e3 100644
--- a/driver/gator_events_net.c
+++ b/driver/gator_events_net.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_perf_pmu.c b/driver/gator_events_perf_pmu.c
index d472df9..8b2d67a 100644
--- a/driver/gator_events_perf_pmu.c
+++ b/driver/gator_events_perf_pmu.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_sched.c b/driver/gator_events_sched.c
index 29f4e39..9e39158 100644
--- a/driver/gator_events_sched.c
+++ b/driver/gator_events_sched.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_scorpion.c b/driver/gator_events_scorpion.c
index c91db12..8ca251a 100644
--- a/driver/gator_events_scorpion.c
+++ b/driver/gator_events_scorpion.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_fs.c b/driver/gator_fs.c
index fe6f83d..166cfe7 100644
--- a/driver/gator_fs.c
+++ b/driver/gator_fs.c
@@ -39,12 +39,7 @@ static const struct super_operations s_ops = {
39 .drop_inode = generic_delete_inode, 39 .drop_inode = generic_delete_inode,
40}; 40};
41 41
42ssize_t gatorfs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset) 42static ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
43{
44 return simple_read_from_buffer(buf, count, offset, str, strlen(str));
45}
46
47ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
48{ 43{
49 char tmpbuf[TMPBUFSIZE]; 44 char tmpbuf[TMPBUFSIZE];
50 size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val); 45 size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
@@ -53,7 +48,7 @@ ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count,
53 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen); 48 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
54} 49}
55 50
56ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff_t *offset) 51static ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff_t *offset)
57{ 52{
58 char tmpbuf[TMPBUFSIZE]; 53 char tmpbuf[TMPBUFSIZE];
59 size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%llu\n", val); 54 size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%llu\n", val);
@@ -62,7 +57,7 @@ ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff_t *off
62 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen); 57 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
63} 58}
64 59
65int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count) 60static int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
66{ 61{
67 char tmpbuf[TMPBUFSIZE]; 62 char tmpbuf[TMPBUFSIZE];
68 unsigned long flags; 63 unsigned long flags;
@@ -84,7 +79,7 @@ int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t c
84 return 0; 79 return 0;
85} 80}
86 81
87int gatorfs_u64_from_user(u64 *val, char const __user *buf, size_t count) 82static int gatorfs_u64_from_user(u64 *val, char const __user *buf, size_t count)
88{ 83{
89 char tmpbuf[TMPBUFSIZE]; 84 char tmpbuf[TMPBUFSIZE];
90 unsigned long flags; 85 unsigned long flags;
@@ -211,8 +206,8 @@ int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
211 return 0; 206 return 0;
212} 207}
213 208
214int gatorfs_create_u64(struct super_block *sb, struct dentry *root, 209static int gatorfs_create_u64(struct super_block *sb, struct dentry *root,
215 char const *name, u64 *val) 210 char const *name, u64 *val)
216{ 211{
217 struct dentry *d = __gatorfs_create_file(sb, root, name, 212 struct dentry *d = __gatorfs_create_file(sb, root, name,
218 &u64_fops, 0644); 213 &u64_fops, 0644);
@@ -235,8 +230,8 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
235 return 0; 230 return 0;
236} 231}
237 232
238int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root, 233static int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root,
239 char const *name, u64 * val) 234 char const *name, u64 * val)
240{ 235{
241 struct dentry *d = 236 struct dentry *d =
242 __gatorfs_create_file(sb, root, name, &u64_ro_fops, 0444); 237 __gatorfs_create_file(sb, root, name, &u64_ro_fops, 0444);
@@ -258,29 +253,17 @@ static const struct file_operations atomic_ro_fops = {
258 .open = default_open, 253 .open = default_open,
259}; 254};
260 255
261int gatorfs_create_ro_atomic(struct super_block *sb, struct dentry *root, 256static int gatorfs_create_file(struct super_block *sb, struct dentry *root,
262 char const *name, atomic_t *val) 257 char const *name, const struct file_operations *fops)
263{
264 struct dentry *d = __gatorfs_create_file(sb, root, name,
265 &atomic_ro_fops, 0444);
266 if (!d)
267 return -EFAULT;
268
269 d->d_inode->i_private = val;
270 return 0;
271}
272
273int gatorfs_create_file(struct super_block *sb, struct dentry *root,
274 char const *name, const struct file_operations *fops)
275{ 258{
276 if (!__gatorfs_create_file(sb, root, name, fops, 0644)) 259 if (!__gatorfs_create_file(sb, root, name, fops, 0644))
277 return -EFAULT; 260 return -EFAULT;
278 return 0; 261 return 0;
279} 262}
280 263
281int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root, 264static int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
282 char const *name, 265 char const *name,
283 const struct file_operations *fops, int perm) 266 const struct file_operations *fops, int perm)
284{ 267{
285 if (!__gatorfs_create_file(sb, root, name, fops, perm)) 268 if (!__gatorfs_create_file(sb, root, name, fops, perm))
286 return -EFAULT; 269 return -EFAULT;
@@ -371,12 +354,12 @@ static struct file_system_type gatorfs_type = {
371 .kill_sb = kill_litter_super, 354 .kill_sb = kill_litter_super,
372}; 355};
373 356
374int __init gatorfs_register(void) 357static int __init gatorfs_register(void)
375{ 358{
376 return register_filesystem(&gatorfs_type); 359 return register_filesystem(&gatorfs_type);
377} 360}
378 361
379void gatorfs_unregister(void) 362static void gatorfs_unregister(void)
380{ 363{
381 unregister_filesystem(&gatorfs_type); 364 unregister_filesystem(&gatorfs_type);
382} 365}
diff --git a/driver/gator_hrtimer_gator.c b/driver/gator_hrtimer_gator.c
index b0c947a..7658455 100644
--- a/driver/gator_hrtimer_gator.c
+++ b/driver/gator_hrtimer_gator.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -7,10 +7,6 @@
7 * 7 *
8 */ 8 */
9 9
10// gator_hrtimer_perf.c is used if perf is supported
11// update, gator_hrtimer_gator.c always used until issues resolved with perf hrtimers
12#if 1
13
14void (*callback)(void); 10void (*callback)(void);
15DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer); 11DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
16DEFINE_PER_CPU(ktime_t, hrtimer_expire); 12DEFINE_PER_CPU(ktime_t, hrtimer_expire);
@@ -82,5 +78,3 @@ static void gator_hrtimer_shutdown(void)
82{ 78{
83 /* empty */ 79 /* empty */
84} 80}
85
86#endif
diff --git a/driver/gator_hrtimer_perf.c b/driver/gator_hrtimer_perf.c
deleted file mode 100644
index 7b95399..0000000
--- a/driver/gator_hrtimer_perf.c
+++ /dev/null
@@ -1,113 +0,0 @@
1/**
2 * Copyright (C) ARM Limited 2011-2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10// gator_hrtimer_gator.c is used if perf is not supported
11// update, gator_hrtimer_gator.c always used until issues resolved with perf hrtimers
12#if 0
13
14// Note: perf Cortex support added in 2.6.35 and PERF_COUNT_SW_CPU_CLOCK/hrtimer broken on 2.6.35 and 2.6.36
15// not relevant as this code is not active until 3.0.0, but wanted to document the issue
16
17void (*callback)(void);
18static int profiling_interval;
19static DEFINE_PER_CPU(struct perf_event *, perf_hrtimer);
20static DEFINE_PER_CPU(struct perf_event_attr *, perf_hrtimer_attr);
21
22static void gator_hrtimer_shutdown(void);
23
24#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
25static void hrtimer_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
26#else
27static void hrtimer_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
28#endif
29{
30 (*callback)();
31}
32
33static int gator_online_single_hrtimer(int cpu)
34{
35 if (per_cpu(perf_hrtimer, cpu) != 0 || per_cpu(perf_hrtimer_attr, cpu) == 0)
36 return 0;
37
38#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
39 per_cpu(perf_hrtimer, cpu) = perf_event_create_kernel_counter(per_cpu(perf_hrtimer_attr, cpu), cpu, 0, hrtimer_overflow_handler);
40#else
41 per_cpu(perf_hrtimer, cpu) = perf_event_create_kernel_counter(per_cpu(perf_hrtimer_attr, cpu), cpu, 0, hrtimer_overflow_handler, 0);
42#endif
43 if (IS_ERR(per_cpu(perf_hrtimer, cpu))) {
44 per_cpu(perf_hrtimer, cpu) = NULL;
45 return -1;
46 }
47
48 if (per_cpu(perf_hrtimer, cpu)->state != PERF_EVENT_STATE_ACTIVE) {
49 perf_event_release_kernel(per_cpu(perf_hrtimer, cpu));
50 per_cpu(perf_hrtimer, cpu) = NULL;
51 return -1;
52 }
53
54 return 0;
55}
56
57static void gator_hrtimer_online(int cpu)
58{
59 if (gator_online_single_hrtimer(cpu) < 0) {
60 pr_debug("gator: unable to online the hrtimer on cpu%d\n", cpu);
61 }
62}
63
64static void gator_hrtimer_offline(int cpu)
65{
66 if (per_cpu(perf_hrtimer, cpu)) {
67 perf_event_release_kernel(per_cpu(perf_hrtimer, cpu));
68 per_cpu(perf_hrtimer, cpu) = NULL;
69 }
70}
71
72static int gator_hrtimer_init(int interval, void (*func)(void))
73{
74 u32 size = sizeof(struct perf_event_attr);
75 int cpu;
76
77 callback = func;
78
79 // calculate profiling interval
80 profiling_interval = 1000000000 / interval;
81
82 for_each_present_cpu(cpu) {
83 per_cpu(perf_hrtimer, cpu) = 0;
84 per_cpu(perf_hrtimer_attr, cpu) = kmalloc(size, GFP_KERNEL);
85 if (per_cpu(perf_hrtimer_attr, cpu) == 0) {
86 gator_hrtimer_shutdown();
87 return -1;
88 }
89
90 memset(per_cpu(perf_hrtimer_attr, cpu), 0, size);
91 per_cpu(perf_hrtimer_attr, cpu)->type = PERF_TYPE_SOFTWARE;
92 per_cpu(perf_hrtimer_attr, cpu)->size = size;
93 per_cpu(perf_hrtimer_attr, cpu)->config = PERF_COUNT_SW_CPU_CLOCK;
94 per_cpu(perf_hrtimer_attr, cpu)->sample_period = profiling_interval;
95 per_cpu(perf_hrtimer_attr, cpu)->pinned = 1;
96 }
97
98 return 0;
99}
100
101static void gator_hrtimer_shutdown(void)
102{
103 int cpu;
104
105 for_each_present_cpu(cpu) {
106 if (per_cpu(perf_hrtimer_attr, cpu)) {
107 kfree(per_cpu(perf_hrtimer_attr, cpu));
108 per_cpu(perf_hrtimer_attr, cpu) = NULL;
109 }
110 }
111}
112
113#endif
diff --git a/driver/gator_iks.c b/driver/gator_iks.c
index 0a90bdd..e90dfcc 100644
--- a/driver/gator_iks.c
+++ b/driver/gator_iks.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_main.c b/driver/gator_main.c
index 19f51c7..e67f7c5 100644
--- a/driver/gator_main.c
+++ b/driver/gator_main.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -8,7 +8,7 @@
8 */ 8 */
9 9
10// This version must match the gator daemon version 10// This version must match the gator daemon version
11#define PROTOCOL_VERSION 17 11#define PROTOCOL_VERSION 18
12static unsigned long gator_protocol_version = PROTOCOL_VERSION; 12static unsigned long gator_protocol_version = PROTOCOL_VERSION;
13 13
14#include <linux/slab.h> 14#include <linux/slab.h>
@@ -55,9 +55,9 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION;
55 55
56#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT)) 56#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT))
57#ifndef CONFIG_PERF_EVENTS 57#ifndef CONFIG_PERF_EVENTS
58#warning gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters 58#error gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
59#elif !defined CONFIG_HW_PERF_EVENTS 59#elif !defined CONFIG_HW_PERF_EVENTS
60#warning gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters 60#error gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
61#endif 61#endif
62#endif 62#endif
63 63
@@ -89,20 +89,27 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION;
89 89
90#define MESSAGE_END_BACKTRACE 1 90#define MESSAGE_END_BACKTRACE 1
91 91
92// Name Frame Messages
92#define MESSAGE_COOKIE 1 93#define MESSAGE_COOKIE 1
93#define MESSAGE_THREAD_NAME 2 94#define MESSAGE_THREAD_NAME 2
94#define HRTIMER_CORE_NAME 3
95#define MESSAGE_LINK 4 95#define MESSAGE_LINK 4
96 96
97// GPU Trace Frame Messages
97#define MESSAGE_GPU_START 1 98#define MESSAGE_GPU_START 1
98#define MESSAGE_GPU_STOP 2 99#define MESSAGE_GPU_STOP 2
99 100
101// Scheduler Trace Frame Messages
100#define MESSAGE_SCHED_SWITCH 1 102#define MESSAGE_SCHED_SWITCH 1
101#define MESSAGE_SCHED_EXIT 2 103#define MESSAGE_SCHED_EXIT 2
102#define MESSAGE_SCHED_START 3 104#define MESSAGE_SCHED_START 3
103 105
106// Idle Frame Messages
104#define MESSAGE_IDLE_ENTER 1 107#define MESSAGE_IDLE_ENTER 1
105#define MESSAGE_IDLE_EXIT 2 108#define MESSAGE_IDLE_EXIT 2
109
110// Summary Frame Messages
111#define MESSAGE_SUMMARY 1
112#define MESSAGE_CORE_NAME 3
106 113
107#define MAXSIZE_PACK32 5 114#define MAXSIZE_PACK32 5
108#define MAXSIZE_PACK64 10 115#define MAXSIZE_PACK64 10
@@ -154,7 +161,13 @@ bool event_based_sampling;
154static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait); 161static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
155static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait); 162static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait);
156static struct timer_list gator_buffer_wake_up_timer; 163static struct timer_list gator_buffer_wake_up_timer;
157static bool gator_buffer_wake_stop; 164static bool gator_buffer_wake_run;
165// Initialize semaphore unlocked to initialize memory values
166#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
167static DECLARE_MUTEX(gator_buffer_wake_sem);
168#else
169static DEFINE_SEMAPHORE(gator_buffer_wake_sem);
170#endif
158static struct task_struct *gator_buffer_wake_thread; 171static struct task_struct *gator_buffer_wake_thread;
159static LIST_HEAD(gator_events); 172static LIST_HEAD(gator_events);
160 173
@@ -164,21 +177,19 @@ static bool printed_monotonic_warning;
164 177
165static bool sent_core_name[NR_CPUS]; 178static bool sent_core_name[NR_CPUS];
166 179
180static DEFINE_PER_CPU(bool, in_scheduler_context);
181
167/****************************************************************************** 182/******************************************************************************
168 * Prototypes 183 * Prototypes
169 ******************************************************************************/ 184 ******************************************************************************/
170static void buffer_check(int cpu, int buftype, u64 time);
171static void gator_commit_buffer(int cpu, int buftype, u64 time);
172static int buffer_bytes_available(int cpu, int buftype);
173static bool buffer_check_space(int cpu, int buftype, int bytes);
174static int contiguous_space_available(int cpu, int bufytpe);
175static void gator_buffer_write_packed_int(int cpu, int buftype, int x);
176static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x);
177static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len);
178static void gator_buffer_write_string(int cpu, int buftype, const char *x);
179static void gator_add_trace(int cpu, unsigned long address);
180static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time);
181static u64 gator_get_time(void); 185static u64 gator_get_time(void);
186static void gator_op_create_files(struct super_block *sb, struct dentry *root);
187
188// gator_buffer is protected by being per_cpu and by having IRQs disabled when writing to it.
189// Most marshal_* calls take care of this except for marshal_cookie*, marshal_backtrace* and marshal_frame where the caller is responsible for doing so.
190// No synchronization is needed with the backtrace buffer as it is per cpu and is only used from the hrtimer.
191// The annotate_lock must be held when using the annotation buffer as it is not per cpu.
192// collect_counters which is the sole writer to the block counter frame is additionally protected by the per cpu collecting flag
182 193
183// Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup. 194// Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup.
184static uint32_t gator_buffer_size[NUM_GATOR_BUFS]; 195static uint32_t gator_buffer_size[NUM_GATOR_BUFS];
@@ -229,8 +240,10 @@ GATOR_EVENTS_LIST
229/****************************************************************************** 240/******************************************************************************
230 * Application Includes 241 * Application Includes
231 ******************************************************************************/ 242 ******************************************************************************/
243#include "gator_fs.c"
244#include "gator_buffer_write.c"
245#include "gator_buffer.c"
232#include "gator_marshaling.c" 246#include "gator_marshaling.c"
233#include "gator_hrtimer_perf.c"
234#include "gator_hrtimer_gator.c" 247#include "gator_hrtimer_gator.c"
235#include "gator_cookies.c" 248#include "gator_cookies.c"
236#include "gator_annotate.c" 249#include "gator_annotate.c"
@@ -238,14 +251,12 @@ GATOR_EVENTS_LIST
238#include "gator_trace_power.c" 251#include "gator_trace_power.c"
239#include "gator_trace_gpu.c" 252#include "gator_trace_gpu.c"
240#include "gator_backtrace.c" 253#include "gator_backtrace.c"
241#include "gator_fs.c"
242#include "gator_pack.c"
243 254
244/****************************************************************************** 255/******************************************************************************
245 * Misc 256 * Misc
246 ******************************************************************************/ 257 ******************************************************************************/
247 258
248const struct gator_cpu gator_cpus[] = { 259static const struct gator_cpu gator_cpus[] = {
249 { 260 {
250 .cpuid = ARM1136, 261 .cpuid = ARM1136,
251 .core_name = "ARM1136", 262 .core_name = "ARM1136",
@@ -277,52 +288,53 @@ const struct gator_cpu gator_cpus[] = {
277 { 288 {
278 .cpuid = CORTEX_A5, 289 .cpuid = CORTEX_A5,
279 .core_name = "Cortex-A5", 290 .core_name = "Cortex-A5",
280 .pmu_name = "ARMv7_Cortex_A5", 291 .pmnc_name = "ARMv7_Cortex_A5",
281 .pmnc_name = "ARM_Cortex-A5",
282 .dt_name = "arm,cortex-a5", 292 .dt_name = "arm,cortex-a5",
283 .pmnc_counters = 2, 293 .pmnc_counters = 2,
284 }, 294 },
285 { 295 {
286 .cpuid = CORTEX_A7, 296 .cpuid = CORTEX_A7,
287 .core_name = "Cortex-A7", 297 .core_name = "Cortex-A7",
288 .pmu_name = "ARMv7_Cortex_A7", 298 .pmnc_name = "ARMv7_Cortex_A7",
289 .pmnc_name = "ARM_Cortex-A7",
290 .dt_name = "arm,cortex-a7", 299 .dt_name = "arm,cortex-a7",
291 .pmnc_counters = 4, 300 .pmnc_counters = 4,
292 }, 301 },
293 { 302 {
294 .cpuid = CORTEX_A8, 303 .cpuid = CORTEX_A8,
295 .core_name = "Cortex-A8", 304 .core_name = "Cortex-A8",
296 .pmu_name = "ARMv7_Cortex_A8", 305 .pmnc_name = "ARMv7_Cortex_A8",
297 .pmnc_name = "ARM_Cortex-A8",
298 .dt_name = "arm,cortex-a8", 306 .dt_name = "arm,cortex-a8",
299 .pmnc_counters = 4, 307 .pmnc_counters = 4,
300 }, 308 },
301 { 309 {
302 .cpuid = CORTEX_A9, 310 .cpuid = CORTEX_A9,
303 .core_name = "Cortex-A9", 311 .core_name = "Cortex-A9",
304 .pmu_name = "ARMv7_Cortex_A9", 312 .pmnc_name = "ARMv7_Cortex_A9",
305 .pmnc_name = "ARM_Cortex-A9",
306 .dt_name = "arm,cortex-a9", 313 .dt_name = "arm,cortex-a9",
307 .pmnc_counters = 6, 314 .pmnc_counters = 6,
308 }, 315 },
309 { 316 {
310 .cpuid = CORTEX_A12, 317 .cpuid = CORTEX_A12,
311 .core_name = "Cortex-A12", 318 .core_name = "Cortex-A12",
312 .pmu_name = "ARMv7_Cortex_A12", 319 .pmnc_name = "ARMv7_Cortex_A12",
313 .pmnc_name = "ARM_Cortex-A12",
314 .dt_name = "arm,cortex-a12", 320 .dt_name = "arm,cortex-a12",
315 .pmnc_counters = 6, 321 .pmnc_counters = 6,
316 }, 322 },
317 { 323 {
318 .cpuid = CORTEX_A15, 324 .cpuid = CORTEX_A15,
319 .core_name = "Cortex-A15", 325 .core_name = "Cortex-A15",
320 .pmu_name = "ARMv7_Cortex_A15", 326 .pmnc_name = "ARMv7_Cortex_A15",
321 .pmnc_name = "ARM_Cortex-A15",
322 .dt_name = "arm,cortex-a15", 327 .dt_name = "arm,cortex-a15",
323 .pmnc_counters = 6, 328 .pmnc_counters = 6,
324 }, 329 },
325 { 330 {
331 .cpuid = CORTEX_A17,
332 .core_name = "Cortex-A17",
333 .pmnc_name = "ARMv7_Cortex_A17",
334 .dt_name = "arm,cortex-a17",
335 .pmnc_counters = 6,
336 },
337 {
326 .cpuid = SCORPION, 338 .cpuid = SCORPION,
327 .core_name = "Scorpion", 339 .core_name = "Scorpion",
328 .pmnc_name = "Scorpion", 340 .pmnc_name = "Scorpion",
@@ -401,7 +413,7 @@ const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name)
401 413
402 for (i = 0; gator_cpus[i].cpuid != 0; ++i) { 414 for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
403 const struct gator_cpu *const gator_cpu = &gator_cpus[i]; 415 const struct gator_cpu *const gator_cpu = &gator_cpus[i];
404 if (gator_cpu->pmu_name != NULL && strcmp(gator_cpu->pmu_name, name) == 0) { 416 if (gator_cpu->pmnc_name != NULL && strcmp(gator_cpu->pmnc_name, name) == 0) {
405 return gator_cpu; 417 return gator_cpu;
406 } 418 }
407 } 419 }
@@ -431,10 +443,15 @@ static void gator_buffer_wake_up(unsigned long data)
431 443
432static int gator_buffer_wake_func(void *data) 444static int gator_buffer_wake_func(void *data)
433{ 445{
434 while (!gator_buffer_wake_stop) { 446 for (;;) {
435 set_current_state(TASK_INTERRUPTIBLE); 447 if (down_killable(&gator_buffer_wake_sem)) {
436 schedule(); 448 break;
437 if (gator_buffer_wake_stop) { 449 }
450
451 // Eat up any pending events
452 while (!down_trylock(&gator_buffer_wake_sem));
453
454 if (!gator_buffer_wake_run) {
438 break; 455 break;
439 } 456 }
440 457
@@ -464,173 +481,6 @@ static bool buffer_commit_ready(int *cpu, int *buftype)
464} 481}
465 482
466/****************************************************************************** 483/******************************************************************************
467 * Buffer management
468 ******************************************************************************/
469static int buffer_bytes_available(int cpu, int buftype)
470{
471 int remaining, filled;
472
473 filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype];
474 if (filled < 0) {
475 filled += gator_buffer_size[buftype];
476 }
477
478 remaining = gator_buffer_size[buftype] - filled;
479
480 if (per_cpu(buffer_space_available, cpu)[buftype]) {
481 // Give some extra room; also allows space to insert the overflow error packet
482 remaining -= 200;
483 } else {
484 // Hysteresis, prevents multiple overflow messages
485 remaining -= 2000;
486 }
487
488 return remaining;
489}
490
491static int contiguous_space_available(int cpu, int buftype)
492{
493 int remaining = buffer_bytes_available(cpu, buftype);
494 int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype];
495 if (remaining < contiguous)
496 return remaining;
497 else
498 return contiguous;
499}
500
501static bool buffer_check_space(int cpu, int buftype, int bytes)
502{
503 int remaining = buffer_bytes_available(cpu, buftype);
504
505 if (remaining < bytes) {
506 per_cpu(buffer_space_available, cpu)[buftype] = false;
507 } else {
508 per_cpu(buffer_space_available, cpu)[buftype] = true;
509 }
510
511 return per_cpu(buffer_space_available, cpu)[buftype];
512}
513
514static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len)
515{
516 int i;
517 u32 write = per_cpu(gator_buffer_write, cpu)[buftype];
518 u32 mask = gator_buffer_mask[buftype];
519 char *buffer = per_cpu(gator_buffer, cpu)[buftype];
520
521 for (i = 0; i < len; i++) {
522 buffer[write] = x[i];
523 write = (write + 1) & mask;
524 }
525
526 per_cpu(gator_buffer_write, cpu)[buftype] = write;
527}
528
529static void gator_buffer_write_string(int cpu, int buftype, const char *x)
530{
531 int len = strlen(x);
532 gator_buffer_write_packed_int(cpu, buftype, len);
533 gator_buffer_write_bytes(cpu, buftype, x, len);
534}
535
536static void gator_commit_buffer(int cpu, int buftype, u64 time)
537{
538 int type_length, commit, length, byte;
539
540 if (!per_cpu(gator_buffer, cpu)[buftype])
541 return;
542
543 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
544 type_length = gator_response_type ? 1 : 0;
545 commit = per_cpu(gator_buffer_commit, cpu)[buftype];
546 length = per_cpu(gator_buffer_write, cpu)[buftype] - commit;
547 if (length < 0) {
548 length += gator_buffer_size[buftype];
549 }
550 length = length - type_length - sizeof(s32);
551
552 if (length <= FRAME_HEADER_SIZE) {
553 // Nothing to write, only the frame header is present
554 return;
555 }
556
557 for (byte = 0; byte < sizeof(s32); byte++) {
558 per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
559 }
560
561 per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
562
563 if (gator_live_rate > 0) {
564 while (time > per_cpu(gator_buffer_commit_time, cpu)) {
565 per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
566 }
567 }
568
569 marshal_frame(cpu, buftype);
570
571 // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
572 if (per_cpu(in_scheduler_context, cpu)) {
573#ifndef CONFIG_PREEMPT_RT_FULL
574 // mod_timer can not be used in interrupt context in RT-Preempt full
575 mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
576#endif
577 } else {
578 wake_up_process(gator_buffer_wake_thread);
579 }
580}
581
582static void buffer_check(int cpu, int buftype, u64 time)
583{
584 int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype];
585 if (filled < 0) {
586 filled += gator_buffer_size[buftype];
587 }
588 if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
589 gator_commit_buffer(cpu, buftype, time);
590 }
591}
592
593static void gator_add_trace(int cpu, unsigned long address)
594{
595 off_t offset = 0;
596 unsigned long cookie = get_address_cookie(cpu, current, address & ~1, &offset);
597
598 if (cookie == NO_COOKIE || cookie == UNRESOLVED_COOKIE) {
599 offset = address;
600 }
601
602 marshal_backtrace(offset & ~1, cookie);
603}
604
605static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time)
606{
607 bool inKernel;
608 unsigned long exec_cookie;
609
610 if (!regs)
611 return;
612
613 inKernel = !user_mode(regs);
614 exec_cookie = get_exec_cookie(cpu, current);
615
616 if (!marshal_backtrace_header(exec_cookie, current->tgid, current->pid, inKernel, time))
617 return;
618
619 if (inKernel) {
620 kernel_backtrace(cpu, regs);
621 } else {
622 // Cookie+PC
623 gator_add_trace(cpu, PC_REG);
624
625 // Backtrace
626 if (gator_backtrace_depth)
627 arm_backtrace_eabi(cpu, regs, gator_backtrace_depth);
628 }
629
630 marshal_backtrace_footer(time);
631}
632
633/******************************************************************************
634 * hrtimer interrupt processing 484 * hrtimer interrupt processing
635 ******************************************************************************/ 485 ******************************************************************************/
636static void gator_timer_interrupt(void) 486static void gator_timer_interrupt(void)
@@ -721,7 +571,8 @@ static void gator_timer_stop(void)
721} 571}
722 572
723#if defined(__arm__) || defined(__aarch64__) 573#if defined(__arm__) || defined(__aarch64__)
724static void gator_send_core_name(int cpu, const u32 cpuid, const struct gator_cpu *const gator_cpu) { 574static void gator_send_core_name(int cpu, const u32 cpuid, const struct gator_cpu *const gator_cpu)
575{
725 const char *core_name = NULL; 576 const char *core_name = NULL;
726 char core_name_buf[32]; 577 char core_name_buf[32];
727 578
@@ -788,7 +639,7 @@ static void gator_timer_online_dispatch(int cpu, bool migrate)
788 639
789#include "gator_iks.c" 640#include "gator_iks.c"
790 641
791int gator_timer_start(unsigned long sample_rate) 642static int gator_timer_start(unsigned long sample_rate)
792{ 643{
793 int cpu; 644 int cpu;
794 645
@@ -944,7 +795,6 @@ static void gator_summary(void)
944 struct timespec ts; 795 struct timespec ts;
945 char uname_buf[512]; 796 char uname_buf[512];
946 void (*m2b)(struct timespec *ts); 797 void (*m2b)(struct timespec *ts);
947 unsigned long flags;
948 798
949 snprintf(uname_buf, sizeof(uname_buf), "%s %s %s %s %s GNU/Linux", utsname()->sysname, utsname()->nodename, utsname()->release, utsname()->version, utsname()->machine); 799 snprintf(uname_buf, sizeof(uname_buf), "%s %s %s %s %s GNU/Linux", utsname()->sysname, utsname()->nodename, utsname()->release, utsname()->version, utsname()->machine);
950 800
@@ -959,14 +809,14 @@ static void gator_summary(void)
959 } 809 }
960 uptime = timespec_to_ns(&ts); 810 uptime = timespec_to_ns(&ts);
961 811
962 // Disable interrupts as gator_get_time calls smp_processor_id to verify time is monotonic 812 // Disable preemption as gator_get_time calls smp_processor_id to verify time is monotonic
963 local_irq_save(flags); 813 preempt_disable();
964 // Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started 814 // Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started
965 gator_monotonic_started = 0; 815 gator_monotonic_started = 0;
966 gator_monotonic_started = gator_get_time(); 816 gator_monotonic_started = gator_get_time();
967 local_irq_restore(flags);
968 817
969 marshal_summary(timestamp, uptime, gator_monotonic_started, uname_buf); 818 marshal_summary(timestamp, uptime, gator_monotonic_started, uname_buf);
819 preempt_enable();
970} 820}
971 821
972int gator_events_install(struct gator_interface *interface) 822int gator_events_install(struct gator_interface *interface)
@@ -1019,7 +869,7 @@ static int gator_start(void)
1019 unsigned long cpu, i; 869 unsigned long cpu, i;
1020 struct gator_interface *gi; 870 struct gator_interface *gi;
1021 871
1022 gator_buffer_wake_stop = false; 872 gator_buffer_wake_run = true;
1023 if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) { 873 if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) {
1024 goto bwake_failure; 874 goto bwake_failure;
1025 } 875 }
@@ -1094,8 +944,9 @@ cookies_failure:
1094events_failure: 944events_failure:
1095 gator_migrate_stop(); 945 gator_migrate_stop();
1096migrate_failure: 946migrate_failure:
1097 gator_buffer_wake_stop = true; 947 gator_buffer_wake_run = false;
1098 wake_up_process(gator_buffer_wake_thread); 948 up(&gator_buffer_wake_sem);
949 gator_buffer_wake_thread = NULL;
1099bwake_failure: 950bwake_failure:
1100 951
1101 return -1; 952 return -1;
@@ -1121,8 +972,9 @@ static void gator_stop(void)
1121 972
1122 gator_migrate_stop(); 973 gator_migrate_stop();
1123 974
1124 gator_buffer_wake_stop = true; 975 gator_buffer_wake_run = false;
1125 wake_up_process(gator_buffer_wake_thread); 976 up(&gator_buffer_wake_sem);
977 gator_buffer_wake_thread = NULL;
1126} 978}
1127 979
1128/****************************************************************************** 980/******************************************************************************
@@ -1417,7 +1269,7 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t
1417 return written > 0 ? written : -EFAULT; 1269 return written > 0 ? written : -EFAULT;
1418} 1270}
1419 1271
1420const struct file_operations gator_event_buffer_fops = { 1272static const struct file_operations gator_event_buffer_fops = {
1421 .open = userspace_buffer_open, 1273 .open = userspace_buffer_open,
1422 .release = userspace_buffer_release, 1274 .release = userspace_buffer_release,
1423 .read = userspace_buffer_read, 1275 .read = userspace_buffer_read,
@@ -1452,7 +1304,7 @@ static const struct file_operations depth_fops = {
1452 .write = depth_write 1304 .write = depth_write
1453}; 1305};
1454 1306
1455void gator_op_create_files(struct super_block *sb, struct dentry *root) 1307static void gator_op_create_files(struct super_block *sb, struct dentry *root)
1456{ 1308{
1457 struct dentry *dir; 1309 struct dentry *dir;
1458 struct gator_interface *gi; 1310 struct gator_interface *gi;
diff --git a/driver/gator_marshaling.c b/driver/gator_marshaling.c
index af80ff6..fd413ad 100644
--- a/driver/gator_marshaling.c
+++ b/driver/gator_marshaling.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -29,6 +29,7 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
29 int cpu = 0; 29 int cpu = 0;
30 30
31 local_irq_save(flags); 31 local_irq_save(flags);
32 gator_buffer_write_packed_int(cpu, SUMMARY_BUF, MESSAGE_SUMMARY);
32 gator_buffer_write_string(cpu, SUMMARY_BUF, NEWLINE_CANARY); 33 gator_buffer_write_string(cpu, SUMMARY_BUF, NEWLINE_CANARY);
33 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, timestamp); 34 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, timestamp);
34 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, uptime); 35 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, uptime);
@@ -52,8 +53,8 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
52#endif 53#endif
53 gator_buffer_write_string(cpu, SUMMARY_BUF, ""); 54 gator_buffer_write_string(cpu, SUMMARY_BUF, "");
54 // Commit the buffer now so it can be one of the first frames read by Streamline 55 // Commit the buffer now so it can be one of the first frames read by Streamline
55 gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
56 local_irq_restore(flags); 56 local_irq_restore(flags);
57 gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
57} 58}
58 59
59static bool marshal_cookie_header(const char *text) 60static bool marshal_cookie_header(const char *text)
@@ -85,8 +86,8 @@ static void marshal_thread_name(int pid, char *name)
85 gator_buffer_write_packed_int(cpu, NAME_BUF, pid); 86 gator_buffer_write_packed_int(cpu, NAME_BUF, pid);
86 gator_buffer_write_string(cpu, NAME_BUF, name); 87 gator_buffer_write_string(cpu, NAME_BUF, name);
87 } 88 }
88 buffer_check(cpu, NAME_BUF, time);
89 local_irq_restore(flags); 89 local_irq_restore(flags);
90 buffer_check(cpu, NAME_BUF, time);
90} 91}
91 92
92static void marshal_link(int cookie, int tgid, int pid) 93static void marshal_link(int cookie, int tgid, int pid)
@@ -103,12 +104,12 @@ static void marshal_link(int cookie, int tgid, int pid)
103 gator_buffer_write_packed_int(cpu, NAME_BUF, tgid); 104 gator_buffer_write_packed_int(cpu, NAME_BUF, tgid);
104 gator_buffer_write_packed_int(cpu, NAME_BUF, pid); 105 gator_buffer_write_packed_int(cpu, NAME_BUF, pid);
105 } 106 }
107 local_irq_restore(flags);
106 // Check and commit; commit is set to occur once buffer is 3/4 full 108 // Check and commit; commit is set to occur once buffer is 3/4 full
107 buffer_check(cpu, NAME_BUF, time); 109 buffer_check(cpu, NAME_BUF, time);
108 local_irq_restore(flags);
109} 110}
110 111
111static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inKernel, u64 time) 112static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, u64 time)
112{ 113{
113 int cpu = get_physical_cpu(); 114 int cpu = get_physical_cpu();
114 if (!buffer_check_space(cpu, BACKTRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32 + gator_backtrace_depth * 2 * MAXSIZE_PACK32)) { 115 if (!buffer_check_space(cpu, BACKTRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32 + gator_backtrace_depth * 2 * MAXSIZE_PACK32)) {
@@ -122,14 +123,16 @@ static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inK
122 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, exec_cookie); 123 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, exec_cookie);
123 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, tgid); 124 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, tgid);
124 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, pid); 125 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, pid);
125 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, inKernel);
126 126
127 return true; 127 return true;
128} 128}
129 129
130static void marshal_backtrace(unsigned long address, int cookie) 130static void marshal_backtrace(unsigned long address, int cookie, int in_kernel)
131{ 131{
132 int cpu = get_physical_cpu(); 132 int cpu = get_physical_cpu();
133 if (cookie == 0 && !in_kernel) {
134 cookie = UNRESOLVED_COOKIE;
135 }
133 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie); 136 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie);
134 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, address); 137 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, address);
135} 138}
@@ -224,9 +227,9 @@ static void marshal_event_single(int core, int key, int value)
224 gator_buffer_write_packed_int(cpu, COUNTER_BUF, key); 227 gator_buffer_write_packed_int(cpu, COUNTER_BUF, key);
225 gator_buffer_write_packed_int(cpu, COUNTER_BUF, value); 228 gator_buffer_write_packed_int(cpu, COUNTER_BUF, value);
226 } 229 }
230 local_irq_restore(flags);
227 // Check and commit; commit is set to occur once buffer is 3/4 full 231 // Check and commit; commit is set to occur once buffer is 3/4 full
228 buffer_check(cpu, COUNTER_BUF, time); 232 buffer_check(cpu, COUNTER_BUF, time);
229 local_irq_restore(flags);
230} 233}
231#endif 234#endif
232 235
@@ -248,9 +251,9 @@ static void marshal_sched_gpu_start(int unit, int core, int tgid, int pid)
248 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, tgid); 251 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, tgid);
249 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, pid); 252 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, pid);
250 } 253 }
254 local_irq_restore(flags);
251 // Check and commit; commit is set to occur once buffer is 3/4 full 255 // Check and commit; commit is set to occur once buffer is 3/4 full
252 buffer_check(cpu, GPU_TRACE_BUF, time); 256 buffer_check(cpu, GPU_TRACE_BUF, time);
253 local_irq_restore(flags);
254} 257}
255 258
256static void marshal_sched_gpu_stop(int unit, int core) 259static void marshal_sched_gpu_stop(int unit, int core)
@@ -269,9 +272,9 @@ static void marshal_sched_gpu_stop(int unit, int core)
269 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit); 272 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit);
270 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core); 273 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core);
271 } 274 }
275 local_irq_restore(flags);
272 // Check and commit; commit is set to occur once buffer is 3/4 full 276 // Check and commit; commit is set to occur once buffer is 3/4 full
273 buffer_check(cpu, GPU_TRACE_BUF, time); 277 buffer_check(cpu, GPU_TRACE_BUF, time);
274 local_irq_restore(flags);
275} 278}
276 279
277static void marshal_sched_trace_start(int tgid, int pid, int cookie) 280static void marshal_sched_trace_start(int tgid, int pid, int cookie)
@@ -291,9 +294,9 @@ static void marshal_sched_trace_start(int tgid, int pid, int cookie)
291 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid); 294 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid);
292 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie); 295 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie);
293 } 296 }
297 local_irq_restore(flags);
294 // Check and commit; commit is set to occur once buffer is 3/4 full 298 // Check and commit; commit is set to occur once buffer is 3/4 full
295 buffer_check(cpu, SCHED_TRACE_BUF, time); 299 buffer_check(cpu, SCHED_TRACE_BUF, time);
296 local_irq_restore(flags);
297} 300}
298 301
299static void marshal_sched_trace_switch(int tgid, int pid, int cookie, int state) 302static void marshal_sched_trace_switch(int tgid, int pid, int cookie, int state)
@@ -314,9 +317,9 @@ static void marshal_sched_trace_switch(int tgid, int pid, int cookie, int state)
314 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie); 317 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie);
315 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, state); 318 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, state);
316 } 319 }
320 local_irq_restore(flags);
317 // Check and commit; commit is set to occur once buffer is 3/4 full 321 // Check and commit; commit is set to occur once buffer is 3/4 full
318 buffer_check(cpu, SCHED_TRACE_BUF, time); 322 buffer_check(cpu, SCHED_TRACE_BUF, time);
319 local_irq_restore(flags);
320} 323}
321 324
322static void marshal_sched_trace_exit(int tgid, int pid) 325static void marshal_sched_trace_exit(int tgid, int pid)
@@ -334,9 +337,9 @@ static void marshal_sched_trace_exit(int tgid, int pid)
334 gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time); 337 gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time);
335 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid); 338 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid);
336 } 339 }
340 local_irq_restore(flags);
337 // Check and commit; commit is set to occur once buffer is 3/4 full 341 // Check and commit; commit is set to occur once buffer is 3/4 full
338 buffer_check(cpu, SCHED_TRACE_BUF, time); 342 buffer_check(cpu, SCHED_TRACE_BUF, time);
339 local_irq_restore(flags);
340} 343}
341 344
342#if GATOR_CPU_FREQ_SUPPORT 345#if GATOR_CPU_FREQ_SUPPORT
@@ -353,80 +356,26 @@ static void marshal_idle(int core, int state)
353 gator_buffer_write_packed_int64(cpu, IDLE_BUF, time); 356 gator_buffer_write_packed_int64(cpu, IDLE_BUF, time);
354 gator_buffer_write_packed_int(cpu, IDLE_BUF, core); 357 gator_buffer_write_packed_int(cpu, IDLE_BUF, core);
355 } 358 }
359 local_irq_restore(flags);
356 // Check and commit; commit is set to occur once buffer is 3/4 full 360 // Check and commit; commit is set to occur once buffer is 3/4 full
357 buffer_check(cpu, IDLE_BUF, time); 361 buffer_check(cpu, IDLE_BUF, time);
358 local_irq_restore(flags);
359} 362}
360#endif 363#endif
361 364
362static void marshal_frame(int cpu, int buftype)
363{
364 int frame;
365
366 if (!per_cpu(gator_buffer, cpu)[buftype]) {
367 return;
368 }
369
370 switch (buftype) {
371 case SUMMARY_BUF:
372 frame = FRAME_SUMMARY;
373 break;
374 case BACKTRACE_BUF:
375 frame = FRAME_BACKTRACE;
376 break;
377 case NAME_BUF:
378 frame = FRAME_NAME;
379 break;
380 case COUNTER_BUF:
381 frame = FRAME_COUNTER;
382 break;
383 case BLOCK_COUNTER_BUF:
384 frame = FRAME_BLOCK_COUNTER;
385 break;
386 case ANNOTATE_BUF:
387 frame = FRAME_ANNOTATE;
388 break;
389 case SCHED_TRACE_BUF:
390 frame = FRAME_SCHED_TRACE;
391 break;
392 case GPU_TRACE_BUF:
393 frame = FRAME_GPU_TRACE;
394 break;
395 case IDLE_BUF:
396 frame = FRAME_IDLE;
397 break;
398 default:
399 frame = -1;
400 break;
401 }
402
403 // add response type
404 if (gator_response_type > 0) {
405 gator_buffer_write_packed_int(cpu, buftype, gator_response_type);
406 }
407
408 // leave space for 4-byte unpacked length
409 per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype];
410
411 // add frame type and core number
412 gator_buffer_write_packed_int(cpu, buftype, frame);
413 gator_buffer_write_packed_int(cpu, buftype, cpu);
414}
415
416#if defined(__arm__) || defined(__aarch64__) 365#if defined(__arm__) || defined(__aarch64__)
417static void marshal_core_name(const int core, const int cpuid, const char *name) 366static void marshal_core_name(const int core, const int cpuid, const char *name)
418{ 367{
419 int cpu = get_physical_cpu(); 368 int cpu = get_physical_cpu();
420 unsigned long flags; 369 unsigned long flags;
421 local_irq_save(flags); 370 local_irq_save(flags);
422 if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK32 + MAXSIZE_CORE_NAME)) { 371 if (buffer_check_space(cpu, SUMMARY_BUF, MAXSIZE_PACK32 + MAXSIZE_CORE_NAME)) {
423 gator_buffer_write_packed_int(cpu, NAME_BUF, HRTIMER_CORE_NAME); 372 gator_buffer_write_packed_int(cpu, SUMMARY_BUF, MESSAGE_CORE_NAME);
424 gator_buffer_write_packed_int(cpu, NAME_BUF, core); 373 gator_buffer_write_packed_int(cpu, SUMMARY_BUF, core);
425 gator_buffer_write_packed_int(cpu, NAME_BUF, cpuid); 374 gator_buffer_write_packed_int(cpu, SUMMARY_BUF, cpuid);
426 gator_buffer_write_string(cpu, NAME_BUF, name); 375 gator_buffer_write_string(cpu, SUMMARY_BUF, name);
427 } 376 }
428 // Commit core names now so that they can show up in live 377 // Commit core names now so that they can show up in live
429 gator_commit_buffer(cpu, NAME_BUF, gator_get_time());
430 local_irq_restore(flags); 378 local_irq_restore(flags);
379 gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
431} 380}
432#endif 381#endif
diff --git a/driver/gator_trace_gpu.c b/driver/gator_trace_gpu.c
index be135b4..6332098 100644
--- a/driver/gator_trace_gpu.c
+++ b/driver/gator_trace_gpu.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -14,8 +14,15 @@
14#include <linux/math64.h> 14#include <linux/math64.h>
15 15
16#ifdef MALI_SUPPORT 16#ifdef MALI_SUPPORT
17#ifdef MALI_DIR_MIDGARD
18/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
19#include "mali_linux_trace.h"
20#else
21/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
17#include "linux/mali_linux_trace.h" 22#include "linux/mali_linux_trace.h"
18#endif 23#endif
24#endif
25
19#include "gator_trace_gpu.h" 26#include "gator_trace_gpu.h"
20 27
21/* 28/*
@@ -235,7 +242,7 @@ GATOR_DEFINE_PROBE(gpu_activity_stop, TP_PROTO(int gpu_unit, int gpu_core))
235 mali_gpu_stop(gpu_unit, gpu_core); 242 mali_gpu_stop(gpu_unit, gpu_core);
236} 243}
237 244
238int gator_trace_gpu_start(void) 245static int gator_trace_gpu_start(void)
239{ 246{
240 /* 247 /*
241 * Returns nonzero for installation failed 248 * Returns nonzero for installation failed
@@ -271,7 +278,7 @@ int gator_trace_gpu_start(void)
271 return 0; 278 return 0;
272} 279}
273 280
274void gator_trace_gpu_stop(void) 281static void gator_trace_gpu_stop(void)
275{ 282{
276#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx) 283#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
277 if (mali_timeline_trace_registered) { 284 if (mali_timeline_trace_registered) {
diff --git a/driver/gator_trace_gpu.h b/driver/gator_trace_gpu.h
index bb0f42d..5113d45 100644
--- a/driver/gator_trace_gpu.h
+++ b/driver/gator_trace_gpu.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_trace_power.c b/driver/gator_trace_power.c
index 272e056..1895bb9 100644
--- a/driver/gator_trace_power.c
+++ b/driver/gator_trace_power.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -166,7 +166,7 @@ static void gator_trace_power_stop(void)
166 } 166 }
167} 167}
168 168
169void gator_trace_power_init(void) 169static void gator_trace_power_init(void)
170{ 170{
171 int i; 171 int i;
172 for (i = 0; i < POWER_TOTAL; i++) { 172 for (i = 0; i < POWER_TOTAL; i++) {
@@ -197,7 +197,7 @@ static void gator_trace_power_stop(void)
197{ 197{
198} 198}
199 199
200void gator_trace_power_init(void) 200static void gator_trace_power_init(void)
201{ 201{
202} 202}
203#endif 203#endif
diff --git a/driver/gator_trace_sched.c b/driver/gator_trace_sched.c
index 332b3f6..52990e9 100644
--- a/driver/gator_trace_sched.c
+++ b/driver/gator_trace_sched.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -22,7 +22,6 @@ enum {
22 22
23static DEFINE_PER_CPU(uint64_t *, taskname_keys); 23static DEFINE_PER_CPU(uint64_t *, taskname_keys);
24static DEFINE_PER_CPU(int, collecting); 24static DEFINE_PER_CPU(int, collecting);
25static DEFINE_PER_CPU(bool, in_scheduler_context);
26 25
27// this array is never read as the cpu wait charts are derived counters 26// this array is never read as the cpu wait charts are derived counters
28// the files are needed, nonetheless, to show that these counters are available 27// the files are needed, nonetheless, to show that these counters are available
@@ -52,7 +51,7 @@ static int sched_trace_create_files(struct super_block *sb, struct dentry *root)
52 return 0; 51 return 0;
53} 52}
54 53
55void emit_pid_name(struct task_struct *task) 54static void emit_pid_name(struct task_struct *task)
56{ 55{
57 bool found = false; 56 bool found = false;
58 char taskcomm[TASK_COMM_LEN + 3]; 57 char taskcomm[TASK_COMM_LEN + 3];
@@ -116,20 +115,21 @@ static void collect_counters(u64 time, struct task_struct *task)
116 // Commit buffers on timeout 115 // Commit buffers on timeout
117 if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) { 116 if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) {
118 static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF }; 117 static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF };
119 unsigned long flags;
120 int i; 118 int i;
121 119
122 local_irq_save(flags);
123 for (i = 0; i < ARRAY_SIZE(buftypes); ++i) { 120 for (i = 0; i < ARRAY_SIZE(buftypes); ++i) {
124 gator_commit_buffer(cpu, buftypes[i], time); 121 gator_commit_buffer(cpu, buftypes[i], time);
125 } 122 }
126 local_irq_restore(flags);
127 123
124 // spinlocks are noops on uniprocessor machines and mutexes do not work in sched_switch context in
125 // RT-Preempt full, so disable proactive flushing of the annotate frame on uniprocessor machines.
126#ifdef CONFIG_SMP
128 // Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full 127 // Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full
129 if (on_primary_core() && spin_trylock(&annotate_lock)) { 128 if (on_primary_core() && spin_trylock(&annotate_lock)) {
130 gator_commit_buffer(0, ANNOTATE_BUF, time); 129 gator_commit_buffer(0, ANNOTATE_BUF, time);
131 spin_unlock(&annotate_lock); 130 spin_unlock(&annotate_lock);
132 } 131 }
132#endif
133 } 133 }
134 } 134 }
135} 135}
@@ -222,7 +222,7 @@ fail_sched_process_fork:
222 return -1; 222 return -1;
223} 223}
224 224
225int gator_trace_sched_start(void) 225static int gator_trace_sched_start(void)
226{ 226{
227 int cpu, size; 227 int cpu, size;
228 228
@@ -237,7 +237,7 @@ int gator_trace_sched_start(void)
237 return register_scheduler_tracepoints(); 237 return register_scheduler_tracepoints();
238} 238}
239 239
240void gator_trace_sched_offline(void) 240static void gator_trace_sched_offline(void)
241{ 241{
242 trace_sched_insert_idle(); 242 trace_sched_insert_idle();
243} 243}
@@ -250,7 +250,7 @@ static void unregister_scheduler_tracepoints(void)
250 pr_debug("gator: unregistered tracepoints\n"); 250 pr_debug("gator: unregistered tracepoints\n");
251} 251}
252 252
253void gator_trace_sched_stop(void) 253static void gator_trace_sched_stop(void)
254{ 254{
255 int cpu; 255 int cpu;
256 unregister_scheduler_tracepoints(); 256 unregister_scheduler_tracepoints();
@@ -260,7 +260,7 @@ void gator_trace_sched_stop(void)
260 } 260 }
261} 261}
262 262
263void gator_trace_sched_init(void) 263static void gator_trace_sched_init(void)
264{ 264{
265 int i; 265 int i;
266 for (i = 0; i < CPU_WAIT_TOTAL; i++) { 266 for (i = 0; i < CPU_WAIT_TOTAL; i++) {
diff --git a/driver/mali/mali_mjollnir_profiling_gator_api.h b/driver/mali/mali_mjollnir_profiling_gator_api.h
index 347a4fe..ff00d90 100644
--- a/driver/mali/mali_mjollnir_profiling_gator_api.h
+++ b/driver/mali/mali_mjollnir_profiling_gator_api.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/mali/mali_utgard_profiling_gator_api.h b/driver/mali/mali_utgard_profiling_gator_api.h
index 559647a..43c5760 100644
--- a/driver/mali/mali_utgard_profiling_gator_api.h
+++ b/driver/mali/mali_utgard_profiling_gator_api.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/mali_t6xx.mk b/driver/mali_t6xx.mk
index 1a98c1c..059d47a 100644
--- a/driver/mali_t6xx.mk
+++ b/driver/mali_t6xx.mk
@@ -10,8 +10,17 @@ EXTRA_CFLAGS += -DMALI_USE_UMP=1 \
10 -DMALI_NO_MALI=0 10 -DMALI_NO_MALI=0
11 11
12DDK_DIR ?= . 12DDK_DIR ?= .
13ifneq ($(wildcard $(DDK_DIR)/drivers/gpu/arm/t6xx),)
13KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase 14KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase
14OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase/osk 15OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase/osk
16endif
17
18ifneq ($(wildcard $(DDK_DIR)/drivers/gpu/arm/midgard),)
19KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/midgard
20OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/midgard/osk
21EXTRA_CFLAGS += -DMALI_DIR_MIDGARD=1
22endif
23
15UMP_DIR = $(DDK_DIR)/include/linux 24UMP_DIR = $(DDK_DIR)/include/linux
16 25
17# Include directories in the DDK 26# Include directories in the DDK