summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Medhurst2013-04-03 08:14:37 -0500
committerJon Medhurst2013-04-03 08:14:37 -0500
commitda2c4ac36164e6bbc450d3105c00c0b88c55c865 (patch)
tree69eb94f6351d13fd5828c00c2335c7b13c4f1e3b
parent27eed928fcf0adc67fb2b0fd41bb6869d62d941f (diff)
parent91fab6bd992a48167a7e6259bc7e715b0968a28c (diff)
downloadarm-ds5-gator-da2c4ac36164e6bbc450d3105c00c0b88c55c865.tar.gz
arm-ds5-gator-da2c4ac36164e6bbc450d3105c00c0b88c55c865.tar.xz
arm-ds5-gator-da2c4ac36164e6bbc450d3105c00c0b88c55c865.zip
Merge branch 'master' into android
-rw-r--r--README_Streamline.txt250
-rw-r--r--daemon/Android.mk14
-rw-r--r--daemon/Buffer.cpp354
-rw-r--r--daemon/Buffer.h66
-rw-r--r--daemon/CapturedXML.cpp76
-rw-r--r--daemon/CapturedXML.h3
-rw-r--r--daemon/Child.cpp131
-rw-r--r--daemon/Child.h6
-rw-r--r--daemon/Collector.cpp141
-rw-r--r--daemon/Collector.h19
-rw-r--r--daemon/ConfigurationXML.cpp153
-rw-r--r--daemon/ConfigurationXML.h2
-rw-r--r--daemon/Counter.h97
-rw-r--r--daemon/Driver.cpp15
-rw-r--r--daemon/Driver.h44
-rw-r--r--daemon/Fifo.cpp20
-rw-r--r--daemon/Fifo.h8
-rw-r--r--daemon/Hwmon.cpp277
-rw-r--r--daemon/Hwmon.h39
-rw-r--r--daemon/KMod.cpp102
-rw-r--r--daemon/KMod.h27
-rw-r--r--daemon/LocalCapture.cpp12
-rw-r--r--daemon/LocalCapture.h4
-rw-r--r--daemon/Logging.cpp3
-rw-r--r--daemon/Logging.h4
-rw-r--r--daemon/Makefile55
-rw-r--r--daemon/Makefile_aarch6415
-rw-r--r--daemon/OlySocket.cpp2
-rw-r--r--daemon/OlySocket.h2
-rw-r--r--daemon/OlyUtility.cpp2
-rw-r--r--daemon/OlyUtility.h2
-rw-r--r--daemon/Sender.cpp27
-rw-r--r--daemon/Sender.h5
-rw-r--r--daemon/SessionData.cpp122
-rw-r--r--daemon/SessionData.h38
-rw-r--r--daemon/SessionXML.cpp6
-rw-r--r--daemon/SessionXML.h6
-rw-r--r--daemon/StreamlineSetup.cpp81
-rw-r--r--daemon/StreamlineSetup.h3
-rw-r--r--daemon/common.mk50
-rw-r--r--daemon/configuration.xml24
-rw-r--r--daemon/escape.c8
-rw-r--r--daemon/events-ARM11.xml2
-rw-r--r--daemon/events-ARM11MPCore.xml2
-rw-r--r--daemon/events-CCI-400.xml47
-rw-r--r--daemon/events-Cortex-A15.xml12
-rw-r--r--daemon/events-Cortex-A5.xml6
-rw-r--r--daemon/events-Cortex-A53.xml2
-rw-r--r--daemon/events-Cortex-A57.xml2
-rw-r--r--daemon/events-Cortex-A7.xml11
-rw-r--r--daemon/events-Cortex-A8.xml4
-rw-r--r--daemon/events-Cortex-A9.xml2
-rw-r--r--daemon/events-Krait-architected.xml2
-rw-r--r--daemon/events-Mali-400.xml404
-rw-r--r--daemon/events-Mali-T6xx_hw.xml12
-rw-r--r--daemon/events-Scorpion.xml2
-rw-r--r--daemon/events-ScorpionMP.xml2
-rw-r--r--daemon/libsensors/COPYING.LGPL502
-rw-r--r--daemon/libsensors/access.c561
-rw-r--r--daemon/libsensors/access.h33
-rw-r--r--daemon/libsensors/conf-lex.c2881
-rw-r--r--daemon/libsensors/conf-lex.l372
-rw-r--r--daemon/libsensors/conf-parse.c2042
-rw-r--r--daemon/libsensors/conf-parse.h84
-rw-r--r--daemon/libsensors/conf-parse.y347
-rw-r--r--daemon/libsensors/conf.h34
-rw-r--r--daemon/libsensors/data.c278
-rw-r--r--daemon/libsensors/data.h184
-rw-r--r--daemon/libsensors/error.c92
-rw-r--r--daemon/libsensors/error.h74
-rw-r--r--daemon/libsensors/general.c85
-rw-r--r--daemon/libsensors/general.h39
-rw-r--r--daemon/libsensors/init.c341
-rw-r--r--daemon/libsensors/init.h28
-rw-r--r--daemon/libsensors/scanner.h32
-rw-r--r--daemon/libsensors/sensors.h311
-rw-r--r--daemon/libsensors/sysfs.c926
-rw-r--r--daemon/libsensors/sysfs.h43
-rw-r--r--daemon/libsensors/version.h1
-rw-r--r--daemon/main.cpp26
-rw-r--r--driver/Makefile1
-rw-r--r--driver/gator.h43
-rw-r--r--driver/gator_annotate.c23
-rw-r--r--driver/gator_annotate_kernel.c2
-rw-r--r--driver/gator_backtrace.c39
-rw-r--r--driver/gator_cookies.c8
-rwxr-xr-x[-rw-r--r--]driver/gator_events.sh0
-rw-r--r--driver/gator_events_armv6.c6
-rw-r--r--driver/gator_events_armv7.c6
-rw-r--r--driver/gator_events_block.c9
-rw-r--r--driver/gator_events_irq.c48
-rw-r--r--driver/gator_events_l2c-310.c74
-rw-r--r--driver/gator_events_mali_400.c4
-rw-r--r--driver/gator_events_mali_400.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.c4
-rw-r--r--driver/gator_events_mali_t6xx_hw.c4
-rw-r--r--driver/gator_events_mali_t6xx_hw_test.c2
-rw-r--r--driver/gator_events_meminfo.c4
-rw-r--r--driver/gator_events_mmaped.c6
-rw-r--r--driver/gator_events_net.c4
-rw-r--r--driver/gator_events_perf_pmu.c520
-rw-r--r--driver/gator_events_sched.c6
-rw-r--r--driver/gator_events_scorpion.c6
-rw-r--r--driver/gator_fs.c87
-rw-r--r--driver/gator_hrtimer_gator.c35
-rw-r--r--driver/gator_hrtimer_perf.c2
-rw-r--r--driver/gator_iks.c144
-rw-r--r--driver/gator_main.c331
-rw-r--r--driver/gator_marshaling.c119
-rw-r--r--driver/gator_pack.c2
-rw-r--r--driver/gator_trace_gpu.c86
-rw-r--r--driver/gator_trace_gpu.h2
-rw-r--r--driver/gator_trace_power.c43
-rw-r--r--driver/gator_trace_sched.c28
116 files changed, 12450 insertions, 1397 deletions
diff --git a/README_Streamline.txt b/README_Streamline.txt
index 0445e3f..5472c07 100644
--- a/README_Streamline.txt
+++ b/README_Streamline.txt
@@ -1,108 +1,142 @@
1 1
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.
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 and executed on the target. 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. 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. 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 17
18*** Preparing and building the kernel *** 18*** Kernel configuration ***
19 19
20cd into the root source dir of the linux kernel 20menuconfig options (depending on the kernel version, the location of these configuration settings within menuconfig may differ)
21if your target has never been configured, choose the appropriate configuration for your target 21- General Setup
22 make ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- <platform_defconfig> 22 - Kernel Performance Events And Counters
23make ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- menuconfig 23 - [*] Kernel performance events and counters (enables CONFIG_PERF_EVENTS)
24 24 - [*] Profiling Support (enables CONFIG_PROFILING)
25Required Kernel Changes (depending on the kernel version, the location of these configuration settings within menuconfig may be different) 25- Kernel Features
26- General Setup 26 - [*] High Resolution Timer Support (enables CONFIG_HIGH_RES_TIMERS)
27 - [*] Profiling Support 27 - [*] Use local timer interrupts (only required for SMP, enables CONFIG_LOCAL_TIMERS)
28- Kernel hacking 28 - [*] Enable hardware performance counter support for perf events (enables CONFIG_HW_PERF_EVENTS)
29 - [*] Tracers 29- CPU Power Management
30 - [*] Trace process context switches and events 30 - CPU Frequency scaling
31- Kernel Features 31 - [*] CPU Frequency scaling (enables CONFIG_CPU_FREQ)
32 - [*] High Resolution Timer Support 32- Kernel hacking
33 - [*] Use local timer interrupts (only required for SMP) 33 - [*] Mutex debugging: basic checks (optional, enables CONFIG_DEBUG_MUTEXES)
34 34 - [*] Compile the kernel with debug info (optional, enables CONFIG_DEBUG_INFO)
35The "context switches and events" option will not be available if other trace configurations are enabled. Other trace configurations being enabled is sufficient to turn on context switches and events. 35 - [*] Tracers
36 36 - [*] Trace process context switches and events (#)
37Optional Kernel Changes (depending on the kernel version, the location of these configuration settings within menuconfig may be different) 37
38Note: Configurations may not be supported on all targets 38(#) The "Trace process context switches and events" is not the only option that enables tracing (CONFIG_GENERIC_TRACER or CONFIG_TRACING) and may not be visible in menuconfig as an option if other trace configurations are enabled. Other trace configurations being enabled is sufficient to turn on tracing.
39- System Type 39
40 - [*] <SoC name> debugging peripherals (enable core performance counters on supported SoCs) /* kernels before 2.6.35 */ 40The configuration options:
41 41CONFIG_GENERIC_TRACER or CONFIG_TRACING
42make -j5 ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- uImage 42CONFIG_PROFILING
43 43CONFIG_HIGH_RES_TIMERS
44*** Checking the gator requirements *** 44CONFIG_LOCAL_TIMERS (for SMP systems)
45 45CONFIG_PERF_EVENTS and CONFIG_HW_PERF_EVENTS (kernel versions 3.0 and greater)
46(optional) Use the hrtimer_module utility to validate the kernel High Resolution Timer requirement. 46CONFIG_DEBUG_MUTEXES (optional, provides 'mutex' as a reason code when a thread stops running)
47 47CONFIG_DEBUG_INFO (optional, used for analyzing the kernel)
48*** Building the gator module *** 48CONFIG_CPU_FREQ (optional, provides frequency setting of the CPU)
49 49
50To create the gator.ko module, 50These 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
51 cd /path/to/gator/driver-src 51 > zcat /proc/config.gz | grep CONFIG_PROFILING
52 tar xzf gator-driver.tar.gz 52 CONFIG_PROFILING=y
53 cd gator-driver 53
54 make -C <kernel_build_dir> M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules 54*** Checking the gator requirements ***
55for example 55
56 make -C /home/username/kernel_2.6.32/ M=`pwd` ARCH=arm CROSS_COMPILE=/home/username/CodeSourcery/Sourcery_G++_Lite/bin/arm-none-linux-gnueabi- modules 56(optional) Use the hrtimer_module utility to validate the kernel High Resolution Timer requirement.
57If successful, a gator.ko module should be generated 57
58 58*** Building the gator module ***
59*** Building the gator daemon *** 59
60 60To create the gator.ko module,
61cd /path/to/gator/daemon-src 61 cd /path/to/gator/driver-src
62tar -xzf gator-daemon.tar.gz 62 tar xzf gator-driver.tar.gz
63For Linux, 63 cd gator-driver
64 build with 'make' 64 make -C <kernel_build_dir> M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules
65For Android, 65for example when using the linaro-toolchain-binaries
66 mv gator-daemon jni 66 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 install the android ndk, see developer.android.com 67If successful, a gator.ko module should be generated
68 /path/to/ndk/ndk-build 68
69 gatord should now be created and located in libs/armeabi 69*** Building the gator daemon ***
70 70
71*** Running gator *** 71cd /path/to/gator/daemon-src
72 72tar -xzf gator-daemon.tar.gz (may need to issue with 'sudo')
73Load the kernel onto the target and copy gatord and gator.ko into the target's filesystem. 73For Linux targets,
74Ensure gatord has execute permissions 74 cd gator-daemon
75 chmod +x gatord 75 make CROSS_COMPILE=<...> # For ARMv7 targets
76gator.ko must be located in the same directory as gatord on the target. 76 make -f Makefile_aarch64 CROSS_COMPILE=<...> # For ARMv8 targets
77With root privileges, run the daemon 77 gatord should now be created
78 sudo ./gatord & 78For Android targets (install the android ndk, see developer.android.com)
79 79 mv gator-daemon jni
80*** Compiling an application or shared library *** 80 ndk-build
81 81 or execute /path/to/ndk/ndk-build if the ndk is not on your path
82Recommended compiler settings: 82 gatord should now be created and located in libs/armeabi
83 "-g": Debug symbols needed for best analysis results. 83
84 "-fno-inline": Speed improvement when processing the image files and most accurate analysis results. 84*** Running gator ***
85 "-fno-omit-frame-pointer": ARM EABI frame pointers (Code Sourcery cross compiler) allow the call stack to be recorded with each sample taken when in ARM state (i.e. not -mthumb). 85
86 86Load the kernel onto the target and copy gatord and gator.ko into the target's filesystem.
87*** Profiling the kernel (optional) *** 87Ensure gatord has execute permissions
88 88 chmod +x gatord
89make ARCH=arm CROSS_COMPILE=$(CROSS_TOOLS}/bin/arm-none-linux-gnueabi- menuconfig 89gator.ko must be located in the same directory as gatord on the target or the location specified with the -m option or already insmod'ed.
90- Kernel Hacking 90With root privileges, run the daemon
91 - [*] Compile the kernel with debug info 91 sudo ./gatord &
92 92Note: 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.
93make -j5 ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- uImage 93
94Use vmlinux as the image for debug symbols in Streamline. 94*** Customizing the l2c-310 Counter ***
95Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the module as an image. 95
96To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko. 96The l2c-310 counter in gator_events_l2c-310.c contains hard coded offsets where the L2 cache counter registers are located. This offset can also be configured via a module parameter specified when gator.ko is loaded, ex:
97 97 insmod gator.ko l2c310_addr=<offset>
98*** Automatically start gator on boot (optional) *** 98Further, the l2c-310 counter can be disabled by providing an offset of zero, ex:
99 99 insmod gator.ko l2c310_addr=0
100cd /etc/init.d 100
101vi rungator.sh 101*** Compiling an application or shared library ***
102 #!/bin/bash 102
103 /path/to/gatord & 103Recommended compiler settings:
104update-rc.d rungator.sh defaults 104 "-g": Debug symbols needed for best analysis results.
105 105 "-fno-inline": Speed improvement when processing the image files and most accurate analysis results.
106*** GPL License *** 106 "-fno-omit-frame-pointer": ARM EABI frame pointers (Code Sourcery cross compiler) allow recording of the call stack with each sample taken when in ARM state (i.e. not -mthumb).
107 107 "-marm": This option is required if your compiler is configured with --with-mode=thumb, otherwise call stack unwinding will not work.
108For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz. 108
109*** Hardfloat EABI ***
110Binary applications built for the soft or softfp ABI are not compatible on a hardfloat system. All soft/softfp applications need to be rebuilt for hardfloat. To see if your ARM compiler supports hardfloat, run "gcc -v" and look for --with-float=hard.
111To compile for non-hardfloat targets it is necessary to add options '-marm -march=armv4t -mfloat-abi=soft'. It may also be necessary to provide a softfloat filesystem by adding the option --sysroot, ex: '--sysroot=../DS-5Examples/distribution/filesystem/armv5t_mtx'. The gatord makefile will do this when run as 'make SOFTFLOAT=1 SYSROOT=/path/to/sysroot'
112The armv5t_mtx filesystem is provided as part of the "DS-5 Linux Example Distribution" package which can be downloaded from the DS-5 Downloads page.
113Attempting to run an incompatible binary often results in the confusing error message "No such file or directory" when clearly the file exists.
114
115*** Bugs ***
116
117There 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.
118
119# ls /sys/bus/event_source/devices/
120ARMv7_Cortex_A9 breakpoint software tracepoint
121
122To workaround the issue try upgrading to a later kernel or comment out the gator_events_perf_pmu_cpu_init(gator_cpu, type); cal in gator_events_perf_pmu.c
123
124*** Profiling the kernel (optional) ***
125
126CONFIG_DEBUG_INFO must be enabled, see "Kernel configuration" section above.
127Use vmlinux as the image for debug symbols in Streamline.
128Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the driver as an image to Streamline.
129To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko.
130
131*** Automatically start gator on boot (optional) ***
132
133cd /etc/init.d
134vi rungator.sh
135 #!/bin/bash
136 /path/to/gatord &
137update-rc.d rungator.sh defaults
138
139*** GPL License ***
140
141For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz.
142
diff --git a/daemon/Android.mk b/daemon/Android.mk
index b8cc7ff..86483f3 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -3,14 +3,18 @@ include $(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 configuration_xml.h)
5 5
6LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions 6LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -DETCDIR=\"/etc\" -Ilibsensors
7 7
8LOCAL_SRC_FILES := \ 8LOCAL_SRC_FILES := \
9 Buffer.cpp \
9 CapturedXML.cpp \ 10 CapturedXML.cpp \
10 Child.cpp \ 11 Child.cpp \
11 Collector.cpp \ 12 Collector.cpp \
12 ConfigurationXML.cpp \ 13 ConfigurationXML.cpp \
14 Driver.cpp \
13 Fifo.cpp \ 15 Fifo.cpp \
16 Hwmon.cpp \
17 KMod.cpp \
14 LocalCapture.cpp \ 18 LocalCapture.cpp \
15 Logging.cpp \ 19 Logging.cpp \
16 main.cpp \ 20 main.cpp \
@@ -20,6 +24,14 @@ LOCAL_SRC_FILES := \
20 SessionData.cpp \ 24 SessionData.cpp \
21 SessionXML.cpp \ 25 SessionXML.cpp \
22 StreamlineSetup.cpp \ 26 StreamlineSetup.cpp \
27 libsensors/access.c \
28 libsensors/conf-lex.c \
29 libsensors/conf-parse.c \
30 libsensors/data.c \
31 libsensors/error.c \
32 libsensors/general.c \
33 libsensors/init.c \
34 libsensors/sysfs.c \
23 mxml/mxml-attr.c \ 35 mxml/mxml-attr.c \
24 mxml/mxml-entity.c \ 36 mxml/mxml-entity.c \
25 mxml/mxml-file.c \ 37 mxml/mxml-file.c \
diff --git a/daemon/Buffer.cpp b/daemon/Buffer.cpp
new file mode 100644
index 0000000..ee391bc
--- /dev/null
+++ b/daemon/Buffer.cpp
@@ -0,0 +1,354 @@
1/**
2 * Copyright (C) ARM Limited 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#include "Buffer.h"
10
11#include "Logging.h"
12#include "Sender.h"
13#include "SessionData.h"
14
15#define mask (size - 1)
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]),
18#ifdef GATOR_LIVE
19 commitTime(gSessionData->mLiveRate),
20#endif
21 readerSem(readerSem) {
22 if ((size & mask) != 0) {
23 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
24 handleException();
25 }
26 frame();
27}
28
29Buffer::~Buffer () {
30 delete [] buf;
31}
32
33void Buffer::write (Sender * const sender) {
34 if (!commitReady()) {
35 return;
36 }
37
38 // determine the size of two halves
39 int length1 = commitPos - readPos;
40 char * buffer1 = buf + readPos;
41 int length2 = 0;
42 char * buffer2 = buf;
43 if (length1 < 0) {
44 length1 = size - readPos;
45 length2 = commitPos;
46 }
47
48 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
49
50 // start, middle or end
51 if (length1 > 0) {
52 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
53 }
54
55 // possible wrap around
56 if (length2 > 0) {
57 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
58 }
59
60 readPos = commitPos;
61}
62
63bool Buffer::commitReady () const {
64 return commitPos != readPos;
65}
66
67int Buffer::bytesAvailable () const {
68 int filled = writePos - readPos;
69 if (filled < 0) {
70 filled += size;
71 }
72
73 int remaining = size - filled;
74
75 if (available) {
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
86bool Buffer::checkSpace (const int bytes) {
87 const int remaining = bytesAvailable();
88
89 if (remaining < bytes) {
90 available = false;
91 } else {
92 available = true;
93 }
94
95 return available;
96}
97
98void Buffer::commit (const uint64_t time) {
99 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
100 const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
101 int length = writePos - commitPos;
102 if (length < 0) {
103 length += size;
104 }
105 length = length - typeLength - sizeof(int32_t);
106 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
107 buf[(commitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
108 }
109
110 logg->logMessage("Committing data readPos: %i writePos: %i commitPos: %i", readPos, writePos, commitPos);
111 commitPos = writePos;
112
113#ifdef GATOR_LIVE
114 if (gSessionData->mLiveRate > 0) {
115 while (time > commitTime) {
116 commitTime += gSessionData->mLiveRate;
117 }
118 }
119#endif
120
121 if (!done) {
122 frame();
123 }
124
125 // send a notification that data is ready
126 sem_post(readerSem);
127}
128
129void Buffer::check (const uint64_t time) {
130 int filled = writePos - commitPos;
131 if (filled < 0) {
132 filled += size;
133 }
134 if (filled >= ((size * 3) / 4)
135#ifdef GATOR_LIVE
136 || (gSessionData->mLiveRate > 0 && time >= commitTime)
137#endif
138 ) {
139 commit(time);
140 }
141}
142
143void Buffer::packInt (const int32_t x) {
144 const int write0 = (writePos + 0) & mask;
145 const int write1 = (writePos + 1) & mask;
146
147 if ((x & 0xffffff80) == 0) {
148 buf[write0] = x & 0x7f;
149 writePos = write1;
150 } else if ((x & 0xffffc000) == 0) {
151 const int write2 = (writePos + 2) & mask;
152 buf[write0] = x | 0x80;
153 buf[write1] = (x >> 7) & 0x7f;
154 writePos = write2;
155 } else if ((x & 0xffe00000) == 0) {
156 const int write2 = (writePos + 2) & mask;
157 const int write3 = (writePos + 3) & mask;
158 buf[write0] = x | 0x80;
159 buf[write1] = (x >> 7) | 0x80;
160 buf[write2] = (x >> 14) & 0x7f;
161 writePos = write3;
162 } else if ((x & 0xf0000000) == 0) {
163 const int write2 = (writePos + 2) & mask;
164 const int write3 = (writePos + 3) & mask;
165 const int write4 = (writePos + 4) & mask;
166 buf[write0] = x | 0x80;
167 buf[write1] = (x >> 7) | 0x80;
168 buf[write2] = (x >> 14) | 0x80;
169 buf[write3] = (x >> 21) & 0x7f;
170 writePos = write4;
171 } else {
172 const int write2 = (writePos + 2) & mask;
173 const int write3 = (writePos + 3) & mask;
174 const int write4 = (writePos + 4) & mask;
175 const int write5 = (writePos + 5) & mask;
176 buf[write0] = x | 0x80;
177 buf[write1] = (x >> 7) | 0x80;
178 buf[write2] = (x >> 14) | 0x80;
179 buf[write3] = (x >> 21) | 0x80;
180 buf[write4] = (x >> 28) & 0x0f;
181 writePos = write5;
182 }
183}
184
185void Buffer::packInt64 (const int64_t x) {
186 const int write0 = (writePos + 0) & mask;
187 const int write1 = (writePos + 1) & mask;
188
189 if ((x & 0xffffffffffffff80LL) == 0) {
190 buf[write0] = x & 0x7f;
191 writePos = write1;
192 } else if ((x & 0xffffffffffffc000LL) == 0) {
193 const int write2 = (writePos + 2) & mask;
194 buf[write0] = x | 0x80;
195 buf[write1] = (x >> 7) & 0x7f;
196 writePos = write2;
197 } else if ((x & 0xffffffffffe00000LL) == 0) {
198 const int write2 = (writePos + 2) & mask;
199 const int write3 = (writePos + 3) & mask;
200 buf[write0] = x | 0x80;
201 buf[write1] = (x >> 7) | 0x80;
202 buf[write2] = (x >> 14) & 0x7f;
203 writePos = write3;
204 } else if ((x & 0xfffffffff0000000LL) == 0) {
205 const int write2 = (writePos + 2) & mask;
206 const int write3 = (writePos + 3) & mask;
207 const int write4 = (writePos + 4) & mask;
208 buf[write0] = x | 0x80;
209 buf[write1] = (x >> 7) | 0x80;
210 buf[write2] = (x >> 14) | 0x80;
211 buf[write3] = (x >> 21) & 0x7f;
212 writePos = write4;
213 } else if ((x & 0xfffffff800000000LL) == 0) {
214 const int write2 = (writePos + 2) & mask;
215 const int write3 = (writePos + 3) & mask;
216 const int write4 = (writePos + 4) & mask;
217 const int write5 = (writePos + 5) & mask;
218 buf[write0] = x | 0x80;
219 buf[write1] = (x >> 7) | 0x80;
220 buf[write2] = (x >> 14) | 0x80;
221 buf[write3] = (x >> 21) | 0x80;
222 buf[write4] = (x >> 28) & 0x7f;
223 writePos = write5;
224 } else if ((x & 0xfffffc0000000000LL) == 0) {
225 const int write2 = (writePos + 2) & mask;
226 const int write3 = (writePos + 3) & mask;
227 const int write4 = (writePos + 4) & mask;
228 const int write5 = (writePos + 5) & mask;
229 const int write6 = (writePos + 6) & mask;
230 buf[write0] = x | 0x80;
231 buf[write1] = (x >> 7) | 0x80;
232 buf[write2] = (x >> 14) | 0x80;
233 buf[write3] = (x >> 21) | 0x80;
234 buf[write4] = (x >> 28) | 0x80;
235 buf[write5] = (x >> 35) & 0x7f;
236 writePos = write6;
237 } else if ((x & 0xfffe000000000000LL) == 0) {
238 const int write2 = (writePos + 2) & mask;
239 const int write3 = (writePos + 3) & mask;
240 const int write4 = (writePos + 4) & mask;
241 const int write5 = (writePos + 5) & mask;
242 const int write6 = (writePos + 6) & mask;
243 const int write7 = (writePos + 7) & mask;
244 buf[write0] = x | 0x80;
245 buf[write1] = (x >> 7) | 0x80;
246 buf[write2] = (x >> 14) | 0x80;
247 buf[write3] = (x >> 21) | 0x80;
248 buf[write4] = (x >> 28) | 0x80;
249 buf[write5] = (x >> 35) | 0x80;
250 buf[write6] = (x >> 42) & 0x7f;
251 writePos = write7;
252 } else if ((x & 0xff00000000000000LL) == 0) {
253 const int write2 = (writePos + 2) & mask;
254 const int write3 = (writePos + 3) & mask;
255 const int write4 = (writePos + 4) & mask;
256 const int write5 = (writePos + 5) & mask;
257 const int write6 = (writePos + 6) & mask;
258 const int write7 = (writePos + 7) & mask;
259 const int write8 = (writePos + 8) & mask;
260 buf[write0] = x | 0x80;
261 buf[write1] = (x >> 7) | 0x80;
262 buf[write2] = (x >> 14) | 0x80;
263 buf[write3] = (x >> 21) | 0x80;
264 buf[write4] = (x >> 28) | 0x80;
265 buf[write5] = (x >> 35) | 0x80;
266 buf[write6] = (x >> 42) | 0x80;
267 buf[write7] = (x >> 49) & 0x7f;
268 writePos = write8;
269 } else if ((x & 0x8000000000000000LL) == 0) {
270 const int write2 = (writePos + 2) & mask;
271 const int write3 = (writePos + 3) & mask;
272 const int write4 = (writePos + 4) & mask;
273 const int write5 = (writePos + 5) & mask;
274 const int write6 = (writePos + 6) & mask;
275 const int write7 = (writePos + 7) & mask;
276 const int write8 = (writePos + 8) & mask;
277 const int write9 = (writePos + 9) & mask;
278 buf[write0] = x | 0x80;
279 buf[write1] = (x >> 7) | 0x80;
280 buf[write2] = (x >> 14) | 0x80;
281 buf[write3] = (x >> 21) | 0x80;
282 buf[write4] = (x >> 28) | 0x80;
283 buf[write5] = (x >> 35) | 0x80;
284 buf[write6] = (x >> 42) | 0x80;
285 buf[write7] = (x >> 49) | 0x80;
286 buf[write8] = (x >> 56) & 0x7f;
287 writePos = write9;
288 } else {
289 const int write2 = (writePos + 2) & mask;
290 const int write3 = (writePos + 3) & mask;
291 const int write4 = (writePos + 4) & mask;
292 const int write5 = (writePos + 5) & mask;
293 const int write6 = (writePos + 6) & mask;
294 const int write7 = (writePos + 7) & mask;
295 const int write8 = (writePos + 8) & mask;
296 const int write9 = (writePos + 9) & mask;
297 const int write10 = (writePos + 10) & mask;
298 buf[write0] = x | 0x80;
299 buf[write1] = (x >> 7) | 0x80;
300 buf[write2] = (x >> 14) | 0x80;
301 buf[write3] = (x >> 21) | 0x80;
302 buf[write4] = (x >> 28) | 0x80;
303 buf[write5] = (x >> 35) | 0x80;
304 buf[write6] = (x >> 42) | 0x80;
305 buf[write7] = (x >> 49) | 0x80;
306 buf[write8] = (x >> 56) | 0x80;
307 buf[write9] = (x >> 63) & 0x7f;
308 writePos = write10;
309 }
310}
311
312void Buffer::frame () {
313 if (!gSessionData->mLocalCapture) {
314 packInt(RESPONSE_APC_DATA);
315 }
316 // Reserve space for the length
317 writePos += sizeof(int32_t);
318 packInt(buftype);
319 packInt(core);
320}
321
322bool Buffer::eventHeader (const uint64_t curr_time) {
323 bool retval = false;
324 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
325 packInt(0); // key of zero indicates a timestamp
326 packInt64(curr_time);
327 retval = true;
328 }
329
330 return retval;
331}
332
333void Buffer::event (const int32_t key, const int32_t value) {
334 if (checkSpace(2 * MAXSIZE_PACK32)) {
335 packInt(key);
336 packInt(value);
337 }
338}
339
340void Buffer::event64 (const int64_t key, const int64_t value) {
341 if (checkSpace(2 * MAXSIZE_PACK64)) {
342 packInt64(key);
343 packInt64(value);
344 }
345}
346
347void Buffer::setDone () {
348 done = true;
349 commit(0);
350}
351
352bool Buffer::isDone () const {
353 return done && readPos == commitPos && commitPos == writePos;
354}
diff --git a/daemon/Buffer.h b/daemon/Buffer.h
new file mode 100644
index 0000000..c460fb7
--- /dev/null
+++ b/daemon/Buffer.h
@@ -0,0 +1,66 @@
1/**
2 * Copyright (C) ARM Limited 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 BUFFER_H
10#define BUFFER_H
11
12#include <stddef.h>
13#include <stdint.h>
14#include <semaphore.h>
15
16#define GATOR_LIVE
17
18class Sender;
19
20class Buffer {
21public:
22 static const size_t MAXSIZE_PACK32 = 5;
23 static const size_t MAXSIZE_PACK64 = 10;
24
25 Buffer (int32_t core, int32_t buftype, const int size, sem_t *const readerSem);
26 ~Buffer ();
27
28 void write (Sender * sender);
29
30 int bytesAvailable () const;
31 void commit (const uint64_t time);
32 void check (const uint64_t time);
33
34 void frame ();
35
36 bool eventHeader (uint64_t curr_time);
37 void event (int32_t key, int32_t value);
38 void event64 (int64_t key, int64_t value);
39
40 void setDone ();
41 bool isDone () const;
42
43private:
44 bool commitReady () const;
45 bool checkSpace (int bytes);
46
47 void packInt (int32_t x);
48 void packInt64 (int64_t x);
49
50 const int32_t core;
51 const int32_t buftype;
52 const int size;
53 int readPos;
54 int writePos;
55 int commitPos;
56 bool available;
57 bool done;
58 char *const buf;
59#ifdef GATOR_LIVE
60 uint64_t commitTime;
61#endif
62
63 sem_t *const readerSem;
64};
65
66#endif // BUFFER_H
diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp
index cc218d7..8b037cb 100644
--- a/daemon/CapturedXML.cpp
+++ b/daemon/CapturedXML.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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,21 +21,11 @@ CapturedXML::~CapturedXML() {
21} 21}
22 22
23mxml_node_t* CapturedXML::getTree(bool includeTime) { 23mxml_node_t* CapturedXML::getTree(bool includeTime) {
24 bool perfCounters = false;
25 mxml_node_t *xml; 24 mxml_node_t *xml;
26 mxml_node_t *captured; 25 mxml_node_t *captured;
27 mxml_node_t *target; 26 mxml_node_t *target;
28 mxml_node_t *counters;
29 mxml_node_t *counter;
30 int x; 27 int x;
31 28
32 for (x=0; x<MAX_PERFORMANCE_COUNTERS; x++) {
33 if (gSessionData->mPerfCounterEnabled[x]) {
34 perfCounters = true;
35 break;
36 }
37 }
38
39 xml = mxmlNewXML("1.0"); 29 xml = mxmlNewXML("1.0");
40 30
41 captured = mxmlNewElement(xml, "captured"); 31 captured = mxmlNewElement(xml, "captured");
@@ -51,35 +41,40 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
51 mxmlElementSetAttr(target, "name", gSessionData->mCoreName); 41 mxmlElementSetAttr(target, "name", gSessionData->mCoreName);
52 mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate); 42 mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate);
53 mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores); 43 mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores);
54 44 mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mCpuId);
55 if (perfCounters) { 45
56 counters = mxmlNewElement(captured, "counters"); 46 mxml_node_t *counters = NULL;
57 for (x = 0; x < MAX_PERFORMANCE_COUNTERS; x++) { 47 for (x = 0; x < MAX_PERFORMANCE_COUNTERS; x++) {
58 if (gSessionData->mPerfCounterEnabled[x]) { 48 const Counter & counter = gSessionData->mCounters[x];
59 counter = mxmlNewElement(counters, "counter"); 49 if (counter.isEnabled()) {
60 mxmlElementSetAttr(counter, "title", gSessionData->mPerfCounterTitle[x]); 50 if (counters == NULL) {
61 mxmlElementSetAttr(counter, "name", gSessionData->mPerfCounterName[x]); 51 counters = mxmlNewElement(captured, "counters");
62 mxmlElementSetAttrf(counter, "color", "0x%08x", gSessionData->mPerfCounterColor[x]); 52 }
63 mxmlElementSetAttrf(counter, "key", "0x%08x", gSessionData->mPerfCounterKey[x]); 53 mxml_node_t *const node = mxmlNewElement(counters, "counter");
64 mxmlElementSetAttr(counter, "type", gSessionData->mPerfCounterType[x]); 54 mxmlElementSetAttr(node, "title", counter.getTitle());
65 mxmlElementSetAttrf(counter, "event", "0x%08x", gSessionData->mPerfCounterEvent[x]); 55 mxmlElementSetAttr(node, "name", counter.getName());
66 if (gSessionData->mPerfCounterPerCPU[x]) { 56 mxmlElementSetAttrf(node, "key", "0x%08x", counter.getKey());
67 mxmlElementSetAttr(counter, "per_cpu", "yes"); 57 mxmlElementSetAttr(node, "type", counter.getType());
68 } 58 mxmlElementSetAttrf(node, "event", "0x%08x", counter.getEvent());
69 if (gSessionData->mPerfCounterCount[x] > 0) { 59 if (counter.isPerCPU()) {
70 mxmlElementSetAttrf(counter, "count", "%d", gSessionData->mPerfCounterCount[x]); 60 mxmlElementSetAttr(node, "per_cpu", "yes");
71 } 61 }
72 if (strlen(gSessionData->mPerfCounterDisplay[x]) > 0) { 62 if (counter.getCount() > 0) {
73 mxmlElementSetAttr(counter, "display", gSessionData->mPerfCounterDisplay[x]); 63 mxmlElementSetAttrf(node, "count", "%d", counter.getCount());
74 } 64 }
75 if (strlen(gSessionData->mPerfCounterUnits[x]) > 0) { 65 if (strlen(counter.getDisplay()) > 0) {
76 mxmlElementSetAttr(counter, "units", gSessionData->mPerfCounterUnits[x]); 66 mxmlElementSetAttr(node, "display", counter.getDisplay());
77 } 67 }
78 if (gSessionData->mPerfCounterAverageSelection[x]) { 68 if (strlen(counter.getUnits()) > 0) {
79 mxmlElementSetAttr(counter, "average_selection", "yes"); 69 mxmlElementSetAttr(node, "units", counter.getUnits());
80 } 70 }
81 mxmlElementSetAttr(counter, "description", gSessionData->mPerfCounterDescription[x]); 71 if (counter.getModifier() != 1) {
72 mxmlElementSetAttrf(node, "modifier", "%d", counter.getModifier());
73 }
74 if (counter.isAverageSelection()) {
75 mxmlElementSetAttr(node, "average_selection", "yes");
82 } 76 }
77 mxmlElementSetAttr(node, "description", counter.getDescription());
83 } 78 }
84 } 79 }
85 80
@@ -95,7 +90,7 @@ char* CapturedXML::getXML(bool includeTime) {
95} 90}
96 91
97void CapturedXML::write(char* path) { 92void CapturedXML::write(char* path) {
98 char *file = (char*)malloc(PATH_MAX); 93 char file[PATH_MAX];
99 94
100 // Set full path 95 // Set full path
101 snprintf(file, PATH_MAX, "%s/captured.xml", path); 96 snprintf(file, PATH_MAX, "%s/captured.xml", path);
@@ -107,7 +102,6 @@ void CapturedXML::write(char* path) {
107 } 102 }
108 103
109 free(xml); 104 free(xml);
110 free(file);
111} 105}
112 106
113// whitespace callback utility function used with mini-xml 107// whitespace callback utility function used with mini-xml
diff --git a/daemon/CapturedXML.h b/daemon/CapturedXML.h
index 3cac576..b0482f5 100644
--- a/daemon/CapturedXML.h
+++ b/daemon/CapturedXML.h
@@ -1,6 +1,5 @@
1/** 1/**
2 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * Copyright (C) ARM Limited 2010-2012. All rights reserved.
4 * 3 *
5 * 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
6 * 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 b97e0db..c784847 100644
--- a/daemon/Child.cpp
+++ b/daemon/Child.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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#include <stdlib.h> 9#include <stdlib.h>
10#include <string.h> 10#include <string.h>
11#include <signal.h> 11#include <signal.h>
12#include <sys/syscall.h>
13#include <sys/resource.h>
14#include <unistd.h> 12#include <unistd.h>
15#include <sys/prctl.h> 13#include <sys/prctl.h>
16#include "Logging.h" 14#include "Logging.h"
@@ -23,11 +21,18 @@
23#include "OlyUtility.h" 21#include "OlyUtility.h"
24#include "StreamlineSetup.h" 22#include "StreamlineSetup.h"
25#include "ConfigurationXML.h" 23#include "ConfigurationXML.h"
24#include "Driver.h"
25#include "Fifo.h"
26#include "Buffer.h"
26 27
27static sem_t haltPipeline, senderThreadStarted, startProfile; // Shared by Child and spawned threads 28#define NS_PER_S ((uint64_t)1000000000)
29#define NS_PER_US 1000
30
31static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads
28static Fifo* collectorFifo = NULL; // Shared by Child.cpp and spawned threads 32static Fifo* collectorFifo = NULL; // Shared by Child.cpp and spawned threads
33static Buffer* buffer = NULL;
29static Sender* sender = NULL; // Shared by Child.cpp and spawned threads 34static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
30Collector* collector = NULL; 35static Collector* collector = NULL;
31Child* child = NULL; // shared by Child.cpp and main.cpp 36Child* child = NULL; // shared by Child.cpp and main.cpp
32 37
33extern void cleanUp(); 38extern void cleanUp();
@@ -62,7 +67,7 @@ void handleException() {
62} 67}
63 68
64// CTRL C Signal Handler for child process 69// CTRL C Signal Handler for child process
65void child_handler(int signum) { 70static void child_handler(int signum) {
66 static bool beenHere = false; 71 static bool beenHere = false;
67 if (beenHere == true) { 72 if (beenHere == true) {
68 logg->logMessage("Gator is being forced to shut down."); 73 logg->logMessage("Gator is being forced to shut down.");
@@ -78,7 +83,7 @@ void child_handler(int signum) {
78 } 83 }
79} 84}
80 85
81void* durationThread(void* pVoid) { 86static void* durationThread(void* pVoid) {
82 prctl(PR_SET_NAME, (unsigned long)&"gatord-duration", 0, 0, 0); 87 prctl(PR_SET_NAME, (unsigned long)&"gatord-duration", 0, 0, 0);
83 sem_wait(&startProfile); 88 sem_wait(&startProfile);
84 if (gSessionData->mSessionIsActive) { 89 if (gSessionData->mSessionIsActive) {
@@ -94,7 +99,7 @@ void* durationThread(void* pVoid) {
94 return 0; 99 return 0;
95} 100}
96 101
97void* stopThread(void* pVoid) { 102static void* stopThread(void* pVoid) {
98 int length; 103 int length;
99 char type; 104 char type;
100 OlySocket* socket = child->socket; 105 OlySocket* socket = child->socket;
@@ -134,8 +139,61 @@ void* stopThread(void* pVoid) {
134 return 0; 139 return 0;
135} 140}
136 141
137void* senderThread(void* pVoid) { 142void* countersThread(void* pVoid) {
138 int length; 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* pVoid) {
196 int length = 1;
139 char* data; 197 char* data;
140 char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0}; 198 char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0};
141 199
@@ -143,10 +201,17 @@ void* senderThread(void* pVoid) {
143 prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0); 201 prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0);
144 sem_wait(&haltPipeline); 202 sem_wait(&haltPipeline);
145 203
146 do { 204 while (length > 0 || !buffer->isDone()) {
205 sem_wait(&senderSem);
147 data = collectorFifo->read(&length); 206 data = collectorFifo->read(&length);
148 sender->writeData(data, length, RESPONSE_APC_DATA); 207 if (data != NULL) {
149 } while (length > 0); 208 sender->writeData(data, length, RESPONSE_APC_DATA);
209 collectorFifo->release();
210 }
211 if (!buffer->isDone()) {
212 buffer->write(sender);
213 }
214 }
150 215
151 // write end-of-capture sequence 216 // write end-of-capture sequence
152 if (!gSessionData->mLocalCapture) { 217 if (!gSessionData->mLocalCapture) {
@@ -185,6 +250,7 @@ void Child::initialization() {
185 // Initialize semaphores 250 // Initialize semaphores
186 sem_init(&senderThreadStarted, 0, 0); 251 sem_init(&senderThreadStarted, 0, 0);
187 sem_init(&startProfile, 0, 0); 252 sem_init(&startProfile, 0, 0);
253 sem_init(&senderSem, 0, 0);
188} 254}
189 255
190void Child::endSession() { 256void Child::endSession() {
@@ -197,7 +263,7 @@ void Child::run() {
197 char* collectBuffer; 263 char* collectBuffer;
198 int bytesCollected = 0; 264 int bytesCollected = 0;
199 LocalCapture* localCapture = NULL; 265 LocalCapture* localCapture = NULL;
200 pthread_t durationThreadID, stopThreadID, senderThreadID; 266 pthread_t durationThreadID, stopThreadID, senderThreadID, countersThreadID;
201 267
202 prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0); 268 prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0);
203 269
@@ -213,11 +279,24 @@ void Child::run() {
213 } 279 }
214 280
215 // Populate gSessionData with the configuration 281 // Populate gSessionData with the configuration
216 new ConfigurationXML(); 282 { ConfigurationXML configuration; }
217 283
218 // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated 284 // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
219 collector = new Collector(); 285 collector = new Collector();
220 286
287 // Initialize all drivers
288 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
289 driver->resetCounters();
290 }
291
292 // Set up counters using the associated driver's setup function
293 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
294 Counter & counter = gSessionData->mCounters[i];
295 if (counter.isEnabled()) {
296 counter.getDriver()->setupCounter(counter);
297 }
298 }
299
221 // Start up and parse session xml 300 // Start up and parse session xml
222 if (socket) { 301 if (socket) {
223 // Respond to Streamline requests 302 // Respond to Streamline requests
@@ -238,16 +317,16 @@ void Child::run() {
238 free(xmlString); 317 free(xmlString);
239 } 318 }
240 319
241 // Write configuration into the driver
242 collector->setupPerfCounters();
243
244 // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length 320 // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
245 logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, collector->getBufferSize()); 321 logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, collector->getBufferSize());
246 collectorFifo = new Fifo(collector->getBufferSize() + 5, gSessionData->mTotalBufferSize* 1024 * 1024); 322 collectorFifo = new Fifo(collector->getBufferSize() + 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem);
247 323
248 // Get the initial pointer to the collect buffer 324 // Get the initial pointer to the collect buffer
249 collectBuffer = collectorFifo->start(); 325 collectBuffer = collectorFifo->start();
250 326
327 // Create a new Block Counter Buffer
328 buffer = new Buffer(0, 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem);
329
251 // Sender thread shall be halted until it is signaled for one shot mode 330 // Sender thread shall be halted until it is signaled for one shot mode
252 sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2); 331 sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
253 332
@@ -261,6 +340,15 @@ void Child::run() {
261 thread_creation_success = false; 340 thread_creation_success = false;
262 } 341 }
263 342
343 if (gSessionData->hwmon.countersEnabled()) {
344 if (pthread_create(&countersThreadID, NULL, countersThread, this)) {
345 thread_creation_success = false;
346 }
347 } else {
348 // Let senderThread know there is no buffer data to send
349 buffer->setDone();
350 }
351
264 if (!thread_creation_success) { 352 if (!thread_creation_success) {
265 logg->logError(__FILE__, __LINE__, "Failed to create gator threads"); 353 logg->logError(__FILE__, __LINE__, "Failed to create gator threads");
266 handleException(); 354 handleException();
@@ -290,6 +378,10 @@ void Child::run() {
290 } while (bytesCollected > 0); 378 } while (bytesCollected > 0);
291 logg->logMessage("Exit collect data loop"); 379 logg->logMessage("Exit collect data loop");
292 380
381 if (gSessionData->hwmon.countersEnabled()) {
382 pthread_join(countersThreadID, NULL);
383 }
384
293 // Wait for the other threads to exit 385 // Wait for the other threads to exit
294 pthread_join(senderThreadID, NULL); 386 pthread_join(senderThreadID, NULL);
295 387
@@ -308,6 +400,7 @@ void Child::run() {
308 400
309 logg->logMessage("Profiling ended."); 401 logg->logMessage("Profiling ended.");
310 402
403 delete buffer;
311 delete collectorFifo; 404 delete collectorFifo;
312 delete sender; 405 delete sender;
313 delete collector; 406 delete collector;
diff --git a/daemon/Child.h b/daemon/Child.h
index 612ca7c..e39d182 100644
--- a/daemon/Child.h
+++ b/daemon/Child.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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
@@ -10,8 +10,8 @@
10#define __CHILD_H__ 10#define __CHILD_H__
11 11
12#include <pthread.h> 12#include <pthread.h>
13#include "Fifo.h" 13
14#include "OlySocket.h" 14class OlySocket;
15 15
16class Child { 16class Child {
17public: 17public:
diff --git a/daemon/Collector.cpp b/daemon/Collector.cpp
index 2e4af0c..bf73534 100644
--- a/daemon/Collector.cpp
+++ b/daemon/Collector.cpp
@@ -1,18 +1,20 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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#define __STDC_FORMAT_MACROS
10
9#include <fcntl.h> 11#include <fcntl.h>
10#include <malloc.h>
11#include <unistd.h> 12#include <unistd.h>
12#include <string.h> 13#include <string.h>
13#include <stdlib.h> 14#include <stdlib.h>
14#include <errno.h> 15#include <errno.h>
15#include <sys/time.h> 16#include <sys/time.h>
17#include <inttypes.h>
16#include "Collector.h" 18#include "Collector.h"
17#include "SessionData.h" 19#include "SessionData.h"
18#include "Logging.h" 20#include "Logging.h"
@@ -20,8 +22,6 @@
20 22
21// Driver initialization independent of session settings 23// Driver initialization independent of session settings
22Collector::Collector() { 24Collector::Collector() {
23 char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/<file>
24
25 mBufferFD = 0; 25 mBufferFD = 0;
26 26
27 checkVersion(); 27 checkVersion();
@@ -42,18 +42,6 @@ Collector::Collector() {
42 logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size"); 42 logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size");
43 handleException(); 43 handleException();
44 } 44 }
45
46 getCoreName();
47
48 enablePerfCounters();
49
50 // Read unchanging keys from driver which are created at insmod'ing of gator.ko
51 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
52 if (gSessionData->mPerfCounterEnabled[i]) {
53 snprintf(text, sizeof(text), "/dev/gator/events/%s/key", gSessionData->mPerfCounterType[i]);
54 readIntDriver(text, &gSessionData->mPerfCounterKey[i]);
55 }
56 }
57} 45}
58 46
59Collector::~Collector() { 47Collector::~Collector() {
@@ -66,63 +54,6 @@ Collector::~Collector() {
66 } 54 }
67} 55}
68 56
69#include <dirent.h>
70void Collector::enablePerfCounters() {
71 char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/enabled
72
73 // Initialize all perf counters in the driver, i.e. set enabled to zero
74 struct dirent *ent;
75 DIR* dir = opendir("/dev/gator/events");
76 if (dir) {
77 while ((ent = readdir(dir)) != NULL) {
78 // skip hidden files, current dir, and parent dir
79 if (ent->d_name[0] == '.')
80 continue;
81 snprintf(text, sizeof(text), "/dev/gator/events/%s/enabled", ent->d_name);
82 writeDriver(text, 0);
83 }
84 closedir (dir);
85 }
86
87 for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
88 if (!gSessionData->mPerfCounterEnabled[i]) {
89 continue;
90 }
91 snprintf(text, sizeof(text), "/dev/gator/events/%s/enabled", gSessionData->mPerfCounterType[i]);
92 if (writeReadDriver(text, &gSessionData->mPerfCounterEnabled[i])) {
93 // Disable those events that don't exist on this hardware platform even though they exist in configuration.xml
94 gSessionData->mPerfCounterEnabled[i] = 0;
95 continue;
96 }
97 }
98}
99
100void Collector::setupPerfCounters() {
101 char base[sizeof(gSessionData->mPerfCounterType[0]) + 20]; // sufficiently large to hold all /dev/gator/events/<types>
102 char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/<file>
103
104 for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
105 if (!gSessionData->mPerfCounterEnabled[i]) {
106 continue;
107 }
108 snprintf(base, sizeof(base), "/dev/gator/events/%s", gSessionData->mPerfCounterType[i]);
109 snprintf(text, sizeof(text), "%s/event", base);
110 writeDriver(text, gSessionData->mPerfCounterEvent[i]);
111 if (gSessionData->mPerfCounterEBSCapable[i]) {
112 snprintf(text, sizeof(text), "%s/count", base);
113 if (access(text, F_OK) == 0) {
114 if (writeReadDriver(text, &gSessionData->mPerfCounterCount[i]) && gSessionData->mPerfCounterCount[i] > 0) {
115 logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%s with a count of %d\n", gSessionData->mPerfCounterTitle[i], gSessionData->mPerfCounterName[i], gSessionData->mPerfCounterCount[i]);
116 handleException();
117 }
118 } else if (gSessionData->mPerfCounterCount[i] > 0) {
119 logg->logError(__FILE__, __LINE__, "Event Based Sampling is only supported with kernel versions 3.0.0 and higher with CONFIG_PERF_EVENTS=y, and CONFIG_HW_PERF_EVENTS=y\n");
120 handleException();
121 }
122 }
123 }
124}
125
126void Collector::checkVersion() { 57void Collector::checkVersion() {
127 int driver_version = 0; 58 int driver_version = 0;
128 59
@@ -179,6 +110,12 @@ void Collector::start() {
179 handleException(); 110 handleException();
180 } 111 }
181 112
113 // Set the live rate
114 if (writeReadDriver("/dev/gator/live_rate", &gSessionData->mLiveRate)) {
115 logg->logError(__FILE__, __LINE__, "Unable to set the driver live rate");
116 handleException();
117 }
118
182 logg->logMessage("Start the driver"); 119 logg->logMessage("Start the driver");
183 120
184 // This command makes the driver start profiling by calling gator_op_start() in the driver 121 // This command makes the driver start profiling by calling gator_op_start() in the driver
@@ -215,47 +152,26 @@ int Collector::collect(char* buffer) {
215 return bytesRead; 152 return bytesRead;
216} 153}
217 154
218void Collector::getCoreName() { 155int Collector::readIntDriver(const char* fullpath, int* value) {
219 char temp[256]; // arbitrarily large amount 156 FILE* file = fopen(fullpath, "r");
220 strcpy(gSessionData->mCoreName, "unknown"); 157 if (file == NULL) {
221 158 return -1;
222 FILE* f = fopen("/proc/cpuinfo", "r");
223 if (f == NULL) {
224 logg->logMessage("Error opening /proc/cpuinfo\n"
225 "The core name in the captured xml file will be 'unknown'.");
226 return;
227 } 159 }
228 160 if (fscanf(file, "%u", value) != 1) {
229 while (fgets(temp, sizeof(temp), f)) { 161 fclose(file);
230 if (strlen(temp) > 0) { 162 logg->logMessage("Invalid value in file %s", fullpath);
231 temp[strlen(temp) - 1] = 0; // Replace the line feed with a null 163 return -1;
232 }
233
234 if (strstr(temp, "Hardware") != 0) {
235 char* position = strchr(temp, ':');
236 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
237 logg->logMessage("Unknown format of /proc/cpuinfo\n"
238 "The core name in the captured xml file will be 'unknown'.");
239 return;
240 }
241 strncpy(gSessionData->mCoreName, (char*)((long)position + 2), sizeof(gSessionData->mCoreName));
242 gSessionData->mCoreName[sizeof(gSessionData->mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
243 fclose(f);
244 return;
245 }
246 } 164 }
247 165 fclose(file);
248 logg->logMessage("Could not determine core name from /proc/cpuinfo\n" 166 return 0;
249 "The core name in the captured xml file will be 'unknown'.");
250 fclose(f);
251} 167}
252 168
253int Collector::readIntDriver(const char* fullpath, int* value) { 169int Collector::readInt64Driver(const char* fullpath, int64_t* value) {
254 FILE* file = fopen(fullpath, "r"); 170 FILE* file = fopen(fullpath, "r");
255 if (file == NULL) { 171 if (file == NULL) {
256 return -1; 172 return -1;
257 } 173 }
258 if (fscanf(file, "%u", value) != 1) { 174 if (fscanf(file, "%" SCNi64, value) != 1) {
259 fclose(file); 175 fclose(file);
260 logg->logMessage("Invalid value in file %s", fullpath); 176 logg->logMessage("Invalid value in file %s", fullpath);
261 return -1; 177 return -1;
@@ -270,6 +186,12 @@ int Collector::writeDriver(const char* path, int value) {
270 return writeDriver(path, data); 186 return writeDriver(path, data);
271} 187}
272 188
189int Collector::writeDriver(const char* path, int64_t value) {
190 char data[40]; // Sufficiently large to hold any integer
191 snprintf(data, sizeof(data), "%" PRIi64, value);
192 return writeDriver(path, data);
193}
194
273int Collector::writeDriver(const char* fullpath, const char* data) { 195int Collector::writeDriver(const char* fullpath, const char* data) {
274 int fd = open(fullpath, O_WRONLY); 196 int fd = open(fullpath, O_WRONLY);
275 if (fd < 0) { 197 if (fd < 0) {
@@ -290,3 +212,10 @@ int Collector::writeReadDriver(const char* path, int* value) {
290 } 212 }
291 return 0; 213 return 0;
292} 214}
215
216int Collector::writeReadDriver(const char* path, int64_t* value) {
217 if (writeDriver(path, *value) || readInt64Driver(path, value)) {
218 return -1;
219 }
220 return 0;
221}
diff --git a/daemon/Collector.h b/daemon/Collector.h
index 5977a72..c5e9eac 100644
--- a/daemon/Collector.h
+++ b/daemon/Collector.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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
@@ -18,20 +18,21 @@ public:
18 void start(); 18 void start();
19 void stop(); 19 void stop();
20 int collect(char* buffer); 20 int collect(char* buffer);
21 void enablePerfCounters();
22 void setupPerfCounters();
23 int getBufferSize() {return mBufferSize;} 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
24private: 31private:
25 int mBufferSize; 32 int mBufferSize;
26 int mBufferFD; 33 int mBufferFD;
27 34
28 void checkVersion(); 35 void checkVersion();
29 void getCoreName();
30
31 int readIntDriver(const char* path, int* value);
32 int writeDriver(const char* path, int value);
33 int writeDriver(const char* path, const char* data);
34 int writeReadDriver(const char* path, int* value);
35}; 36};
36 37
37#endif //__COLLECTOR_H__ 38#endif //__COLLECTOR_H__
diff --git a/daemon/ConfigurationXML.cpp b/daemon/ConfigurationXML.cpp
index 14c2809..9d51f26 100644
--- a/daemon/ConfigurationXML.cpp
+++ b/daemon/ConfigurationXML.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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
@@ -10,30 +10,31 @@
10#include <stdlib.h> 10#include <stdlib.h>
11#include <dirent.h> 11#include <dirent.h>
12#include "ConfigurationXML.h" 12#include "ConfigurationXML.h"
13#include "Driver.h"
13#include "Logging.h" 14#include "Logging.h"
14#include "OlyUtility.h" 15#include "OlyUtility.h"
15#include "SessionData.h" 16#include "SessionData.h"
16 17
17static const char* ATTR_COUNTER = "counter"; 18static const char* ATTR_COUNTER = "counter";
18static const char* ATTR_REVISION = "revision"; 19static const char* ATTR_REVISION = "revision";
19static const char* ATTR_TITLE = "title"; 20static const char* ATTR_TITLE = "title";
20static const char* ATTR_NAME = "name"; 21static const char* ATTR_NAME = "name";
21static const char* ATTR_EVENT = "event"; 22static const char* ATTR_EVENT = "event";
22static const char* ATTR_COUNT = "count"; 23static const char* ATTR_COUNT = "count";
23static const char* ATTR_PER_CPU = "per_cpu"; 24static const char* ATTR_PER_CPU = "per_cpu";
24static const char* ATTR_DESCRIPTION = "description"; 25static const char* ATTR_DESCRIPTION = "description";
25static const char* ATTR_EBS = "supports_event_based_sampling"; 26static const char* ATTR_EBS = "supports_event_based_sampling";
26static const char* ATTR_DISPLAY = "display"; 27static const char* ATTR_DISPLAY = "display";
27static const char* ATTR_UNITS = "units"; 28static const char* ATTR_UNITS = "units";
28static const char* ATTR_AVERAGE_SELECTION = "average_selection"; 29static const char* ATTR_MODIFIER = "modifier";
30static const char* ATTR_AVERAGE_SELECTION = "average_selection";
29 31
30ConfigurationXML::ConfigurationXML() { 32ConfigurationXML::ConfigurationXML() {
31 const char * configuration_xml; 33 const char * configuration_xml;
32 unsigned int configuration_xml_len; 34 unsigned int configuration_xml_len;
33 getDefaultConfigurationXml(configuration_xml, configuration_xml_len); 35 getDefaultConfigurationXml(configuration_xml, configuration_xml_len);
34 36
35 mIndex = 0; 37 char path[PATH_MAX];
36 char* path = (char*)malloc(PATH_MAX);
37 38
38 if (gSessionData->mConfigurationXMLPath) { 39 if (gSessionData->mConfigurationXMLPath) {
39 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX); 40 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX);
@@ -45,35 +46,34 @@ ConfigurationXML::ConfigurationXML() {
45 } 46 }
46 mConfigurationXML = util->readFromDisk(path); 47 mConfigurationXML = util->readFromDisk(path);
47 48
48 if (mConfigurationXML == NULL) { 49 for (int retryCount = 0; retryCount < 2; ++retryCount) {
49 logg->logMessage("Unable to locate configuration.xml, using default in binary"); 50 if (mConfigurationXML == NULL) {
50 // null-terminate configuration_xml 51 logg->logMessage("Unable to locate configuration.xml, using default in binary");
51 mConfigurationXML = (char*)malloc(configuration_xml_len + 1); 52 // null-terminate configuration_xml
52 memcpy(mConfigurationXML, (const void*)configuration_xml, configuration_xml_len); 53 mConfigurationXML = (char*)malloc(configuration_xml_len + 1);
53 mConfigurationXML[configuration_xml_len] = 0; 54 memcpy(mConfigurationXML, (const void*)configuration_xml, configuration_xml_len);
54 } 55 mConfigurationXML[configuration_xml_len] = 0;
55 56 }
56 // disable all counters prior to parsing the configuration xml
57 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
58 gSessionData->mPerfCounterEnabled[i] = 0;
59 }
60 57
61 // clear counter overflow 58 int ret = parse(mConfigurationXML);
62 gSessionData->mCounterOverflow = false; 59 if (ret == 1) {
60 // remove configuration.xml on disk to use the default
61 if (remove(path) != 0) {
62 logg->logError(__FILE__, __LINE__, "Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk");
63 handleException();
64 }
65 logg->logMessage("Invalid configuration.xml file detected and removed");
63 66
64 int ret = parse(mConfigurationXML); 67 // Free the current configuration and reload
65 if (ret == 1) { 68 free((void*)mConfigurationXML);
66 // remove configuration.xml on disk to use the default 69 mConfigurationXML = NULL;
67 if (remove(path) != 0) { 70 continue;
68 logg->logError(__FILE__, __LINE__, "Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk");
69 handleException();
70 } 71 }
71 logg->logMessage("Invalid configuration.xml file detected and removed"); 72
73 break;
72 } 74 }
73 75
74 validate(); 76 validate();
75
76 free(path);
77} 77}
78 78
79ConfigurationXML::~ConfigurationXML() { 79ConfigurationXML::~ConfigurationXML() {
@@ -86,6 +86,15 @@ int ConfigurationXML::parse(const char* configurationXML) {
86 mxml_node_t *tree, *node; 86 mxml_node_t *tree, *node;
87 int ret; 87 int ret;
88 88
89 // clear counter overflow
90 gSessionData->mCounterOverflow = false;
91 mIndex = 0;
92
93 // disable all counters prior to parsing the configuration xml
94 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
95 gSessionData->mCounters[i].setEnabled(false);
96 }
97
89 tree = mxmlLoadString(NULL, configurationXML, MXML_NO_CALLBACK); 98 tree = mxmlLoadString(NULL, configurationXML, MXML_NO_CALLBACK);
90 99
91 node = mxmlGetFirstChild(tree); 100 node = mxmlGetFirstChild(tree);
@@ -111,18 +120,20 @@ int ConfigurationXML::parse(const char* configurationXML) {
111 120
112void ConfigurationXML::validate(void) { 121void ConfigurationXML::validate(void) {
113 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) { 122 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
114 if (gSessionData->mPerfCounterEnabled[i]) { 123 const Counter & counter = gSessionData->mCounters[i];
115 if (strcmp(gSessionData->mPerfCounterType[i], "") == 0) { 124 if (counter.isEnabled()) {
116 logg->logError(__FILE__, __LINE__, "Invalid required attribute in configuration.xml:\n counter=\"%s\"\n title=\"%s\"\n name=\"%s\"\n event=%d\n", gSessionData->mPerfCounterType[i], gSessionData->mPerfCounterTitle[i], gSessionData->mPerfCounterName[i], gSessionData->mPerfCounterEvent[i]); 125 if (strcmp(counter.getType(), "") == 0) {
126 logg->logError(__FILE__, __LINE__, "Invalid required attribute in configuration.xml:\n counter=\"%s\"\n title=\"%s\"\n name=\"%s\"\n event=%d\n", counter.getType(), counter.getTitle(), counter.getName(), counter.getEvent());
117 handleException(); 127 handleException();
118 } 128 }
119 129
120 // iterate through the remaining enabled performance counters 130 // iterate through the remaining enabled performance counters
121 for (int j = i + 1; j < MAX_PERFORMANCE_COUNTERS; j++) { 131 for (int j = i + 1; j < MAX_PERFORMANCE_COUNTERS; j++) {
122 if (gSessionData->mPerfCounterEnabled[j]) { 132 const Counter & counter2 = gSessionData->mCounters[j];
133 if (counter2.isEnabled()) {
123 // check if the types are the same 134 // check if the types are the same
124 if (strcmp(gSessionData->mPerfCounterType[i], gSessionData->mPerfCounterType[j]) == 0) { 135 if (strcmp(counter.getType(), counter2.getType()) == 0) {
125 logg->logError(__FILE__, __LINE__, "Duplicate performance counter type in configuration.xml: %s", gSessionData->mPerfCounterType[i]); 136 logg->logError(__FILE__, __LINE__, "Duplicate performance counter type in configuration.xml: %s", counter.getType());
126 handleException(); 137 handleException();
127 } 138 }
128 } 139 }
@@ -131,7 +142,7 @@ void ConfigurationXML::validate(void) {
131 } 142 }
132} 143}
133 144
134#define CONFIGURATION_REVISION 1 145#define CONFIGURATION_REVISION 2
135int ConfigurationXML::configurationsTag(mxml_node_t *node) { 146int ConfigurationXML::configurationsTag(mxml_node_t *node) {
136 const char* revision_string; 147 const char* revision_string;
137 148
@@ -156,26 +167,38 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
156 } 167 }
157 168
158 // read attributes 169 // read attributes
159 if (mxmlElementGetAttr(node, ATTR_COUNTER)) strncpy(gSessionData->mPerfCounterType[mIndex], mxmlElementGetAttr(node, ATTR_COUNTER), sizeof(gSessionData->mPerfCounterType[mIndex])); 170 Counter & counter = gSessionData->mCounters[mIndex];
160 if (mxmlElementGetAttr(node, ATTR_TITLE)) strncpy(gSessionData->mPerfCounterTitle[mIndex], mxmlElementGetAttr(node, ATTR_TITLE), sizeof(gSessionData->mPerfCounterTitle[mIndex])); 171 counter.clear();
161 if (mxmlElementGetAttr(node, ATTR_NAME)) strncpy(gSessionData->mPerfCounterName[mIndex], mxmlElementGetAttr(node, ATTR_NAME), sizeof(gSessionData->mPerfCounterName[mIndex])); 172 if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER));
162 if (mxmlElementGetAttr(node, ATTR_DESCRIPTION)) strncpy(gSessionData->mPerfCounterDescription[mIndex], mxmlElementGetAttr(node, ATTR_DESCRIPTION), sizeof(gSessionData->mPerfCounterDescription[mIndex])); 173 if (mxmlElementGetAttr(node, ATTR_TITLE)) counter.setTitle(mxmlElementGetAttr(node, ATTR_TITLE));
163 if (mxmlElementGetAttr(node, ATTR_EVENT)) gSessionData->mPerfCounterEvent[mIndex] = strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16); 174 if (mxmlElementGetAttr(node, ATTR_NAME)) counter.setName(mxmlElementGetAttr(node, ATTR_NAME));
164 if (mxmlElementGetAttr(node, ATTR_COUNT)) gSessionData->mPerfCounterCount[mIndex] = strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10); 175 if (mxmlElementGetAttr(node, ATTR_DESCRIPTION)) counter.setDescription(mxmlElementGetAttr(node, ATTR_DESCRIPTION));
165 if (mxmlElementGetAttr(node, ATTR_PER_CPU)) gSessionData->mPerfCounterPerCPU[mIndex] = util->stringToBool(mxmlElementGetAttr(node, ATTR_PER_CPU), false); 176 if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16));
166 if (mxmlElementGetAttr(node, ATTR_EBS)) gSessionData->mPerfCounterEBSCapable[mIndex] = util->stringToBool(mxmlElementGetAttr(node, ATTR_EBS), false); 177 if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10));
167 if (mxmlElementGetAttr(node, ATTR_DISPLAY)) strncpy(gSessionData->mPerfCounterDisplay[mIndex], mxmlElementGetAttr(node, ATTR_DISPLAY), sizeof(gSessionData->mPerfCounterDisplay[mIndex])); 178 if (mxmlElementGetAttr(node, ATTR_PER_CPU)) counter.setPerCPU(util->stringToBool(mxmlElementGetAttr(node, ATTR_PER_CPU), false));
168 if (mxmlElementGetAttr(node, ATTR_UNITS)) strncpy(gSessionData->mPerfCounterUnits[mIndex], mxmlElementGetAttr(node, ATTR_UNITS), sizeof(gSessionData->mPerfCounterUnits[mIndex])); 179 if (mxmlElementGetAttr(node, ATTR_EBS)) counter.setEBSCapable(util->stringToBool(mxmlElementGetAttr(node, ATTR_EBS), false));
169 if (mxmlElementGetAttr(node, ATTR_AVERAGE_SELECTION)) gSessionData->mPerfCounterAverageSelection[mIndex] = util->stringToBool(mxmlElementGetAttr(node, ATTR_AVERAGE_SELECTION), false); 180 if (mxmlElementGetAttr(node, ATTR_DISPLAY)) counter.setDisplay(mxmlElementGetAttr(node, ATTR_DISPLAY));
170 gSessionData->mPerfCounterEnabled[mIndex] = true; 181 if (mxmlElementGetAttr(node, ATTR_UNITS)) counter.setUnits(mxmlElementGetAttr(node, ATTR_UNITS));
171 182 if (mxmlElementGetAttr(node, ATTR_MODIFIER)) counter.setModifier(strtol(mxmlElementGetAttr(node, ATTR_MODIFIER), NULL, 10));
172 // strncpy does not guarantee a null-terminated string 183 if (mxmlElementGetAttr(node, ATTR_AVERAGE_SELECTION)) counter.setAverageSelection(util->stringToBool(mxmlElementGetAttr(node, ATTR_AVERAGE_SELECTION), false));
173 gSessionData->mPerfCounterType[mIndex][sizeof(gSessionData->mPerfCounterType[mIndex]) - 1] = 0; 184 counter.setEnabled(true);
174 gSessionData->mPerfCounterTitle[mIndex][sizeof(gSessionData->mPerfCounterTitle[mIndex]) - 1] = 0; 185
175 gSessionData->mPerfCounterName[mIndex][sizeof(gSessionData->mPerfCounterName[mIndex]) - 1] = 0; 186 // Associate a driver with each counter
176 gSessionData->mPerfCounterDescription[mIndex][sizeof(gSessionData->mPerfCounterDescription[mIndex]) - 1] = 0; 187 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
177 gSessionData->mPerfCounterDisplay[mIndex][sizeof(gSessionData->mPerfCounterDisplay[mIndex]) - 1] = 0; 188 if (driver->claimCounter(counter)) {
178 gSessionData->mPerfCounterUnits[mIndex][sizeof(gSessionData->mPerfCounterUnits[mIndex]) - 1] = 0; 189 if (counter.getDriver() != NULL) {
190 logg->logError(__FILE__, __LINE__, "More than one driver has claimed %s: %s", counter.getTitle(), counter.getName());
191 handleException();
192 }
193 counter.setDriver(driver);
194 }
195 }
196
197 // If no driver is associated with the counter, disable it
198 if (counter.getDriver() == NULL) {
199 logg->logMessage("No driver has claimed %s (%s: %s)", counter.getType(), counter.getTitle(), counter.getName());
200 counter.setEnabled(false);
201 }
179 202
180 // update counter index 203 // update counter index
181 mIndex++; 204 mIndex++;
diff --git a/daemon/ConfigurationXML.h b/daemon/ConfigurationXML.h
index 66ad587..f709ad1 100644
--- a/daemon/ConfigurationXML.h
+++ b/daemon/ConfigurationXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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
new file mode 100644
index 0000000..041020b
--- /dev/null
+++ b/daemon/Counter.h
@@ -0,0 +1,97 @@
1/**
2 * Copyright (C) ARM Limited 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 COUNTER_H
10#define COUNTER_H
11
12#include <string.h>
13
14class Driver;
15
16class Counter {
17public:
18 static const size_t MAX_STRING_LEN = 80;
19 static const size_t MAX_DESCRIPTION_LEN = 400;
20
21 Counter () {
22 clear();
23 }
24
25 void clear () {
26 mType[0] = '\0';
27 mTitle[0] = '\0';
28 mName[0] = '\0';
29 mDescription[0] = '\0';
30 mDisplay[0] = '\0';
31 mUnits[0] = '\0';
32 mModifier = 1;
33 mEnabled = false;
34 mEvent = 0;
35 mCount = 0;
36 mKey = 0;
37 mPerCPU = false;
38 mEBSCapable = false;
39 mAverageSelection = false;
40 mDriver = NULL;
41 }
42
43 void setType(const char *const type) { strncpy(mType, type, sizeof(mType)); mType[sizeof(mType) - 1] = '\0'; }
44 void setTitle(const char *const title) { strncpy(mTitle, title, sizeof(mTitle)); mTitle[sizeof(mTitle) - 1] = '\0'; }
45 void setName(const char *const name) { strncpy(mName, name, sizeof(mName)); mName[sizeof(mName) - 1] = '\0'; }
46 void setDescription(const char *const description) { strncpy(mDescription, description, sizeof(mDescription)); mDescription[sizeof(mDescription) - 1] = '\0'; }
47 void setDisplay(const char *const display) { strncpy(mDisplay, display, sizeof(mDisplay)); mDisplay[sizeof(mDisplay) - 1] = '\0'; }
48 void setUnits(const char *const units) { strncpy(mUnits, units, sizeof(mUnits)); mUnits[sizeof(mUnits) - 1] = '\0'; }
49 void setModifier(const int modifier) { mModifier = modifier; }
50 void setEnabled(const bool enabled) { mEnabled = enabled; }
51 void setEvent(const int event) { mEvent = event; }
52 void setCount(const int count) { mCount = count; }
53 void setKey(const int key) { mKey = key; }
54 void setPerCPU(const bool perCPU) { mPerCPU = perCPU; }
55 void setEBSCapable(const bool ebsCapable) { mEBSCapable = ebsCapable; }
56 void setAverageSelection(const bool averageSelection) { mAverageSelection = averageSelection; }
57 void setDriver(Driver *const driver) { mDriver = driver; }
58
59 const char *getType() const { return mType;}
60 const char *getTitle() const { return mTitle; }
61 const char *getName() const { return mName; }
62 const char *getDescription() const { return mDescription; }
63 const char *getDisplay() const { return mDisplay; }
64 const char *getUnits() const { return mUnits; }
65 int getModifier() const { return mModifier; }
66 bool isEnabled() const { return mEnabled; }
67 int getEvent() const { return mEvent; }
68 int getCount() const { return mCount; }
69 int getKey() const { return mKey; }
70 bool isPerCPU() const { return mPerCPU; }
71 bool isEBSCapable() const { return mEBSCapable; }
72 bool isAverageSelection() const { return mAverageSelection; }
73 Driver *getDriver() const { return mDriver; }
74
75private:
76 // Intentionally unimplemented
77 Counter(const Counter &);
78 Counter & operator=(const Counter &);
79
80 char mType[MAX_STRING_LEN];
81 char mTitle[MAX_STRING_LEN];
82 char mName[MAX_STRING_LEN];
83 char mDescription[MAX_DESCRIPTION_LEN];
84 char mDisplay[MAX_STRING_LEN];
85 char mUnits[MAX_STRING_LEN];
86 int mModifier;
87 bool mEnabled;
88 int mEvent;
89 int mCount;
90 int mKey;
91 bool mPerCPU;
92 bool mEBSCapable;
93 bool mAverageSelection;
94 Driver *mDriver;
95};
96
97#endif // COUNTER_H
diff --git a/daemon/Driver.cpp b/daemon/Driver.cpp
new file mode 100644
index 0000000..c262467
--- /dev/null
+++ b/daemon/Driver.cpp
@@ -0,0 +1,15 @@
1/**
2 * Copyright (C) ARM Limited 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#include "Driver.h"
10
11Driver *Driver::head = NULL;
12
13Driver::Driver() : next(head) {
14 head = this;
15}
diff --git a/daemon/Driver.h b/daemon/Driver.h
new file mode 100644
index 0000000..dd1dc27
--- /dev/null
+++ b/daemon/Driver.h
@@ -0,0 +1,44 @@
1/**
2 * Copyright (C) ARM Limited 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 DRIVER_H
10#define DRIVER_H
11
12#include "mxml/mxml.h"
13
14class Counter;
15
16class Driver {
17public:
18 static Driver *getHead() { return head; }
19
20 virtual ~Driver() {}
21
22 // Returns true if this driver can manage the counter
23 virtual bool claimCounter(const Counter &counter) const = 0;
24 // Clears and disables all counters
25 virtual void resetCounters() = 0;
26 // Enables and prepares the counter for capture
27 virtual void setupCounter(Counter &counter) = 0;
28
29 // Emits available counters
30 virtual void writeCounters(mxml_node_t *root) const = 0;
31 // Emits possible dynamically generated events/counters
32 virtual void writeEvents(mxml_node_t *root) const {}
33
34 Driver *getNext() const { return next; }
35
36protected:
37 Driver ();
38
39private:
40 static Driver *head;
41 Driver *next;
42};
43
44#endif // DRIVER_H
diff --git a/daemon/Fifo.cpp b/daemon/Fifo.cpp
index 4a27452..f0b0178 100644
--- a/daemon/Fifo.cpp
+++ b/daemon/Fifo.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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,10 +15,11 @@
15// bufferSize is the amount of data to be filled 15// bufferSize is the amount of data to be filled
16// singleBufferSize is the maximum size that may be filled during a single write 16// singleBufferSize is the maximum size that may be filled during a single write
17// (bufferSize + singleBufferSize) will be allocated 17// (bufferSize + singleBufferSize) will be allocated
18Fifo::Fifo(int singleBufferSize, int bufferSize) { 18Fifo::Fifo(int singleBufferSize, int bufferSize, sem_t* readerSem) {
19 mWrite = mRead = mReadCommit = mRaggedEnd = 0; 19 mWrite = mRead = mReadCommit = mRaggedEnd = 0;
20 mWrapThreshold = bufferSize; 20 mWrapThreshold = bufferSize;
21 mSingleBufferSize = singleBufferSize; 21 mSingleBufferSize = singleBufferSize;
22 mReaderSem = readerSem;
22 mBuffer = (char*)valloc(bufferSize + singleBufferSize); 23 mBuffer = (char*)valloc(bufferSize + singleBufferSize);
23 mEnd = false; 24 mEnd = false;
24 25
@@ -27,7 +28,7 @@ Fifo::Fifo(int singleBufferSize, int bufferSize) {
27 handleException(); 28 handleException();
28 } 29 }
29 30
30 if (sem_init(&mWaitForSpaceSem, 0, 0) || sem_init(&mWaitForDataSem, 0, 0)) { 31 if (sem_init(&mWaitForSpaceSem, 0, 0)) {
31 logg->logError(__FILE__, __LINE__, "sem_init() failed"); 32 logg->logError(__FILE__, __LINE__, "sem_init() failed");
32 handleException(); 33 handleException();
33 } 34 }
@@ -36,7 +37,6 @@ Fifo::Fifo(int singleBufferSize, int bufferSize) {
36Fifo::~Fifo() { 37Fifo::~Fifo() {
37 free(mBuffer); 38 free(mBuffer);
38 sem_destroy(&mWaitForSpaceSem); 39 sem_destroy(&mWaitForSpaceSem);
39 sem_destroy(&mWaitForDataSem);
40} 40}
41 41
42int Fifo::numBytesFilled() const { 42int Fifo::numBytesFilled() const {
@@ -87,7 +87,7 @@ char* Fifo::write(int length) {
87 } 87 }
88 88
89 // send a notification that data is ready 89 // send a notification that data is ready
90 sem_post(&mWaitForDataSem); 90 sem_post(mReaderSem);
91 91
92 // wait for space 92 // wait for space
93 while (isFull()) { 93 while (isFull()) {
@@ -97,8 +97,7 @@ char* Fifo::write(int length) {
97 return &mBuffer[mWrite]; 97 return &mBuffer[mWrite];
98} 98}
99 99
100// This function will stall until data is available 100void Fifo::release() {
101char* Fifo::read(int *const length) {
102 // update the read pointer now that the data has been handled 101 // update the read pointer now that the data has been handled
103 mRead = mReadCommit; 102 mRead = mReadCommit;
104 103
@@ -109,10 +108,13 @@ char* Fifo::read(int *const length) {
109 108
110 // send a notification that data is free (space is available) 109 // send a notification that data is free (space is available)
111 sem_post(&mWaitForSpaceSem); 110 sem_post(&mWaitForSpaceSem);
111}
112 112
113// This function will return null if no data is available
114char* Fifo::read(int *const length) {
113 // wait for data 115 // wait for data
114 while (isEmpty() && !mEnd) { 116 if (isEmpty() && !mEnd) {
115 sem_wait(&mWaitForDataSem); 117 return NULL;
116 } 118 }
117 119
118 // obtain the length 120 // obtain the length
diff --git a/daemon/Fifo.h b/daemon/Fifo.h
index e2a5d94..d46e1af 100644
--- a/daemon/Fifo.h
+++ b/daemon/Fifo.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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
@@ -13,7 +13,7 @@
13 13
14class Fifo { 14class Fifo {
15public: 15public:
16 Fifo(int singleBufferSize, int totalBufferSize); 16 Fifo(int singleBufferSize, int totalBufferSize, sem_t* readerSem);
17 ~Fifo(); 17 ~Fifo();
18 int numBytesFilled() const; 18 int numBytesFilled() const;
19 bool isEmpty() const; 19 bool isEmpty() const;
@@ -21,11 +21,13 @@ public:
21 bool willFill(int additional) const; 21 bool willFill(int additional) const;
22 char* start() const; 22 char* start() const;
23 char* write(int length); 23 char* write(int length);
24 void release();
24 char* read(int *const length); 25 char* read(int *const length);
25 26
26private: 27private:
27 int mSingleBufferSize, mWrite, mRead, mReadCommit, mRaggedEnd, mWrapThreshold; 28 int mSingleBufferSize, mWrite, mRead, mReadCommit, mRaggedEnd, mWrapThreshold;
28 sem_t mWaitForSpaceSem, mWaitForDataSem; 29 sem_t mWaitForSpaceSem;
30 sem_t* mReaderSem;
29 char* mBuffer; 31 char* mBuffer;
30 bool mEnd; 32 bool mEnd;
31}; 33};
diff --git a/daemon/Hwmon.cpp b/daemon/Hwmon.cpp
new file mode 100644
index 0000000..9603411
--- /dev/null
+++ b/daemon/Hwmon.cpp
@@ -0,0 +1,277 @@
1/**
2 * Copyright (C) ARM Limited 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#include "Hwmon.h"
10
11#include "libsensors/sensors.h"
12
13#include "Buffer.h"
14#include "Counter.h"
15#include "Logging.h"
16#include "SessionData.h"
17
18class HwmonCounter {
19public:
20 HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature);
21 ~HwmonCounter();
22
23 HwmonCounter *getNext() const { return next; }
24 int getKey() const { return key; }
25 bool isEnabled() const { return enabled; }
26 const char *getName() const { return name; }
27 const char *getLabel() const { return label; }
28 const char *getTitle() const { return title; }
29 const char *getDisplay() const { return display; }
30 const char *getUnit() const { return unit; }
31 int getModifier() const { return modifier; }
32
33 void setEnabled(const bool enabled) { this->enabled = enabled; }
34
35 double read();
36
37private:
38 void init(const sensors_chip_name *chip, const sensors_feature *feature);
39
40 HwmonCounter *const next;
41 const int key;
42 bool enabled;
43
44 const sensors_chip_name *chip;
45 const sensors_feature *feature;
46
47 char *name;
48 char *label;
49 const char *title;
50 const char *display;
51 const char *unit;
52 int modifier;
53 bool monotonic;
54 double previous_value;
55
56 sensors_subfeature_type input;
57};
58
59HwmonCounter::HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(key), enabled(false), chip(chip), feature(feature) {
60
61 int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
62 char *chip_name = new char[len];
63 sensors_snprintf_chip_name(chip_name, len, chip);
64
65 len = snprintf(NULL, 0, "hwmon_%s_%d", chip_name, feature->number) + 1;
66 name = new char[len];
67 len = snprintf(name, len, "hwmon_%s_%d", chip_name, feature->number);
68
69 delete [] chip_name;
70
71 label = sensors_get_label(chip, feature);
72
73 switch (feature->type) {
74 case SENSORS_FEATURE_IN:
75 title = "Voltage";
76 input = SENSORS_SUBFEATURE_IN_INPUT;
77 display = "average";
78 unit = "V";
79 modifier = 1000;
80 monotonic = false;
81 break;
82 case SENSORS_FEATURE_FAN:
83 title = "Fan";
84 input = SENSORS_SUBFEATURE_FAN_INPUT;
85 display = "average";
86 unit = "RPM";
87 modifier = 1;
88 monotonic = false;
89 break;
90 case SENSORS_FEATURE_TEMP:
91 title = "Temperature";
92 input = SENSORS_SUBFEATURE_TEMP_INPUT;
93 display = "maximum";
94 unit = "°C";
95 modifier = 1000;
96 monotonic = false;
97 break;
98 case SENSORS_FEATURE_POWER:
99 title = "Power";
100 input = SENSORS_SUBFEATURE_POWER_INPUT;
101 display = "average";
102 unit = "W";
103 modifier = 1000000;
104 monotonic = false;
105 break;
106 case SENSORS_FEATURE_ENERGY:
107 title = "Energy";
108 input = SENSORS_SUBFEATURE_ENERGY_INPUT;
109 display = "accumulate";
110 unit = "J";
111 modifier = 1000000;
112 monotonic = true;
113 break;
114 case SENSORS_FEATURE_CURR:
115 title = "Current";
116 input = SENSORS_SUBFEATURE_CURR_INPUT;
117 display = "average";
118 unit = "A";
119 modifier = 1000;
120 monotonic = false;
121 break;
122 case SENSORS_FEATURE_HUMIDITY:
123 title = "Humidity";
124 input = SENSORS_SUBFEATURE_HUMIDITY_INPUT;
125 display = "average";
126 unit = "%";
127 modifier = 1000;
128 monotonic = false;
129 break;
130 default:
131 logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", feature->type);
132 handleException();
133 }
134}
135
136HwmonCounter::~HwmonCounter() {
137 free((void *)label);
138 delete [] name;
139}
140
141double HwmonCounter::read() {
142 double value;
143 double result;
144 const sensors_subfeature *subfeature;
145
146 subfeature = sensors_get_subfeature(chip, feature, input);
147 if (!subfeature) {
148 logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label);
149 handleException();
150 }
151
152 if (sensors_get_value(chip, subfeature->number, &value) != 0) {
153 logg->logError(__FILE__, __LINE__, "Can't get input value for hwmon sensor %s", label);
154 handleException();
155 }
156
157 result = (monotonic ? value - previous_value : value);
158 previous_value = value;
159
160 return result;
161}
162
163
164Hwmon::Hwmon() : counters(NULL) {
165 int err = sensors_init(NULL);
166 if (err) {
167 logg->logMessage("Failed to initialize libsensors! (%d)", err);
168 return;
169 }
170 sensors_sysfs_no_scaling = 1;
171
172 int chip_nr = 0;
173 const sensors_chip_name *chip;
174 while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
175 int feature_nr = 0;
176 const sensors_feature *feature;
177 while ((feature = sensors_get_features(chip, &feature_nr))) {
178 counters = new HwmonCounter(counters, getEventKey(), chip, feature);
179 }
180 }
181}
182
183Hwmon::~Hwmon() {
184 while (counters != NULL) {
185 HwmonCounter * counter = counters;
186 counters = counter->getNext();
187 delete counter;
188 }
189 sensors_cleanup();
190}
191
192HwmonCounter *Hwmon::findCounter(const Counter &counter) const {
193 for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) {
194 if (strcmp(hwmonCounter->getName(), counter.getType()) == 0) {
195 return hwmonCounter;
196 }
197 }
198
199 return NULL;
200}
201
202bool Hwmon::claimCounter(const Counter &counter) const {
203 return findCounter(counter) != NULL;
204}
205
206bool Hwmon::countersEnabled() const {
207 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
208 if (counter->isEnabled()) {
209 return true;
210 }
211 }
212 return false;
213}
214
215void Hwmon::resetCounters() {
216 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
217 counter->setEnabled(false);
218 }
219}
220
221void Hwmon::setupCounter(Counter &counter) {
222 HwmonCounter *const hwmonCounter = findCounter(counter);
223 if (hwmonCounter == NULL) {
224 counter.setEnabled(false);
225 return;
226 }
227 hwmonCounter->setEnabled(true);
228 counter.setKey(hwmonCounter->getKey());
229}
230
231void Hwmon::writeCounters(mxml_node_t *root) const {
232 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
233 mxml_node_t *node = mxmlNewElement(root, "counter");
234 mxmlElementSetAttr(node, "name", counter->getName());
235 }
236}
237
238void Hwmon::writeEvents(mxml_node_t *root) const {
239 root = mxmlNewElement(root, "category");
240 mxmlElementSetAttr(root, "name", "hwmon");
241
242 char buf[1024];
243 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
244 mxml_node_t *node = mxmlNewElement(root, "event");
245 mxmlElementSetAttr(node, "counter", counter->getName());
246 mxmlElementSetAttr(node, "title", counter->getTitle());
247 mxmlElementSetAttr(node, "name", counter->getLabel());
248 mxmlElementSetAttr(node, "display", counter->getDisplay());
249 mxmlElementSetAttr(node, "units", counter->getUnit());
250 if (counter->getModifier() != 1) {
251 mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier());
252 }
253 if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
254 mxmlElementSetAttr(node, "average_selection", "yes");
255 }
256 snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName());
257 mxmlElementSetAttr(node, "description", buf);
258 }
259}
260
261void Hwmon::start() {
262 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
263 if (!counter->isEnabled()) {
264 continue;
265 }
266 counter->read();
267 }
268}
269
270void Hwmon::read(Buffer * const buffer) {
271 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
272 if (!counter->isEnabled()) {
273 continue;
274 }
275 buffer->event(counter->getKey(), counter->read());
276 }
277}
diff --git a/daemon/Hwmon.h b/daemon/Hwmon.h
new file mode 100644
index 0000000..35981dc
--- /dev/null
+++ b/daemon/Hwmon.h
@@ -0,0 +1,39 @@
1/**
2 * Copyright (C) ARM Limited 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 HWMON_H
10#define HWMON_H
11
12#include "Driver.h"
13
14class Buffer;
15class HwmonCounter;
16
17class Hwmon : public Driver {
18public:
19 Hwmon();
20 ~Hwmon();
21
22 bool claimCounter(const Counter &counter) const;
23 bool countersEnabled() const;
24 void resetCounters();
25 void setupCounter(Counter &counter);
26
27 void writeCounters(mxml_node_t *root) const;
28 void writeEvents(mxml_node_t *root) const;
29
30 void start();
31 void read(Buffer * buffer);
32
33private:
34 HwmonCounter *findCounter(const Counter &counter) const;
35
36 HwmonCounter *counters;
37};
38
39#endif // HWMON_H
diff --git a/daemon/KMod.cpp b/daemon/KMod.cpp
new file mode 100644
index 0000000..5f12046
--- /dev/null
+++ b/daemon/KMod.cpp
@@ -0,0 +1,102 @@
1/**
2 * Copyright (C) ARM Limited 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#include "KMod.h"
10
11#include <sys/types.h>
12#include <dirent.h>
13#include <unistd.h>
14
15#include "Collector.h"
16#include "Counter.h"
17#include "Logging.h"
18
19// Claim all the counters in /dev/gator/events
20bool KMod::claimCounter(const Counter &counter) const {
21 char text[128];
22 snprintf(text, sizeof(text), "/dev/gator/events/%s", counter.getType());
23 return access(text, F_OK) == 0;
24}
25
26void KMod::resetCounters() {
27 char base[128];
28 char text[128];
29
30 // Initialize all perf counters in the driver, i.e. set enabled to zero
31 struct dirent *ent;
32 DIR* dir = opendir("/dev/gator/events");
33 if (dir) {
34 while ((ent = readdir(dir)) != NULL) {
35 // skip hidden files, current dir, and parent dir
36 if (ent->d_name[0] == '.')
37 continue;
38 snprintf(base, sizeof(base), "/dev/gator/events/%s", ent->d_name);
39 snprintf(text, sizeof(text), "%s/enabled", base);
40 Collector::writeDriver(text, 0);
41 snprintf(text, sizeof(text), "%s/count", base);
42 Collector::writeDriver(text, 0);
43 }
44 closedir(dir);
45 }
46}
47
48void KMod::setupCounter(Counter &counter) {
49 char base[128];
50 char text[128];
51 snprintf(base, sizeof(base), "/dev/gator/events/%s", counter.getType());
52
53 snprintf(text, sizeof(text), "%s/enabled", base);
54 int enabled = true;
55 if (Collector::writeReadDriver(text, &enabled) || !enabled) {
56 counter.setEnabled(false);
57 return;
58 }
59
60 snprintf(text, sizeof(text), "%s/key", base);
61 int key;
62 Collector::readIntDriver(text, &key);
63 counter.setKey(key);
64
65 snprintf(text, sizeof(text), "%s/event", base);
66 Collector::writeDriver(text, counter.getEvent());
67 if (counter.isEBSCapable()) {
68 snprintf(text, sizeof(text), "%s/count", base);
69 if (access(text, F_OK) == 0) {
70 int count = counter.getCount();
71 if (Collector::writeReadDriver(text, &count) && counter.getCount() > 0) {
72 logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%s with a count of %d\n", counter.getTitle(), counter.getName(), counter.getCount());
73 handleException();
74 }
75 counter.setCount(count);
76 } else if (counter.getCount() > 0) {
77 logg->logError(__FILE__, __LINE__, "Event Based Sampling is only supported with kernel versions 3.0.0 and higher with CONFIG_PERF_EVENTS=y, and CONFIG_HW_PERF_EVENTS=y\n");
78 handleException();
79 }
80 }
81}
82
83void KMod::writeCounters(mxml_node_t *root) const {
84 struct dirent *ent;
85 mxml_node_t *counter;
86
87 // counters.xml is simply a file listing of /dev/gator/events
88 DIR* dir = opendir("/dev/gator/events");
89 if (dir == NULL) {
90 logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events");
91 handleException();
92 }
93
94 while ((ent = readdir(dir)) != NULL) {
95 // skip hidden files, current dir, and parent dir
96 if (ent->d_name[0] == '.')
97 continue;
98 counter = mxmlNewElement(root, "counter");
99 mxmlElementSetAttr(counter, "name", ent->d_name);
100 }
101 closedir(dir);
102}
diff --git a/daemon/KMod.h b/daemon/KMod.h
new file mode 100644
index 0000000..7974262
--- /dev/null
+++ b/daemon/KMod.h
@@ -0,0 +1,27 @@
1/**
2 * Copyright (C) ARM Limited 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 KMOD_H
10#define KMOD_H
11
12#include "Driver.h"
13
14// Driver for the gator kernel module
15class KMod : public Driver {
16public:
17 KMod() {}
18 ~KMod() {}
19
20 bool claimCounter(const Counter &counter) const;
21 void resetCounters();
22 void setupCounter(Counter &counter);
23
24 void writeCounters(mxml_node_t *root) const;
25};
26
27#endif // KMOD_H
diff --git a/daemon/LocalCapture.cpp b/daemon/LocalCapture.cpp
index 2dd3aff..baa3dd9 100644
--- a/daemon/LocalCapture.cpp
+++ b/daemon/LocalCapture.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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 @@ void LocalCapture::createAPCDirectory(char* target_path) {
30} 30}
31 31
32void LocalCapture::write(char* string) { 32void LocalCapture::write(char* string) {
33 char* file = (char*)malloc(PATH_MAX); 33 char file[PATH_MAX];
34 34
35 // Set full path 35 // Set full path
36 snprintf(file, PATH_MAX, "%s/session.xml", gSessionData->mAPCDir); 36 snprintf(file, PATH_MAX, "%s/session.xml", gSessionData->mAPCDir);
@@ -40,13 +40,11 @@ void LocalCapture::write(char* string) {
40 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); 40 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
41 handleException(); 41 handleException();
42 } 42 }
43
44 free(file);
45} 43}
46 44
47char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* ending) { 45char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* ending) {
48 char* output; 46 char* output;
49 char* path = (char*)malloc(PATH_MAX); 47 char path[PATH_MAX];
50 48
51 // Ensure the path is an absolute path, i.e. starts with a slash 49 // Ensure the path is an absolute path, i.e. starts with a slash
52 if (initialPath == 0 || strlen(initialPath) == 0) { 50 if (initialPath == 0 || strlen(initialPath) == 0) {
@@ -70,7 +68,6 @@ char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* e
70 68
71 output = strdup(path); 69 output = strdup(path);
72 70
73 free(path);
74 return output; 71 return output;
75} 72}
76 73
@@ -107,7 +104,7 @@ int LocalCapture::removeDirAndAllContents(char* path) {
107} 104}
108 105
109void LocalCapture::copyImages(ImageLinkList* ptr) { 106void LocalCapture::copyImages(ImageLinkList* ptr) {
110 char* dstfilename = (char*)malloc(PATH_MAX); 107 char dstfilename[PATH_MAX];
111 108
112 while (ptr) { 109 while (ptr) {
113 strncpy(dstfilename, gSessionData->mAPCDir, PATH_MAX); 110 strncpy(dstfilename, gSessionData->mAPCDir, PATH_MAX);
@@ -124,5 +121,4 @@ void LocalCapture::copyImages(ImageLinkList* ptr) {
124 121
125 ptr = ptr->next; 122 ptr = ptr->next;
126 } 123 }
127 free(dstfilename);
128} 124}
diff --git a/daemon/LocalCapture.h b/daemon/LocalCapture.h
index 40f7883..8042d6a 100644
--- a/daemon/LocalCapture.h
+++ b/daemon/LocalCapture.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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,7 @@
9#ifndef __LOCAL_CAPTURE_H__ 9#ifndef __LOCAL_CAPTURE_H__
10#define __LOCAL_CAPTURE_H__ 10#define __LOCAL_CAPTURE_H__
11 11
12#include "SessionXML.h" 12struct ImageLinkList;
13 13
14class LocalCapture { 14class LocalCapture {
15public: 15public:
diff --git a/daemon/Logging.cpp b/daemon/Logging.cpp
index 3e6f8a3..5fd45b5 100644
--- a/daemon/Logging.cpp
+++ b/daemon/Logging.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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
@@ -10,7 +10,6 @@
10#include <stdlib.h> 10#include <stdlib.h>
11#include <stdarg.h> 11#include <stdarg.h>
12#include <string.h> 12#include <string.h>
13#include "OlyUtility.h"
14 13
15#ifdef WIN32 14#ifdef WIN32
16#define MUTEX_INIT() mLoggingMutex = CreateMutex(NULL, false, NULL); 15#define MUTEX_INIT() mLoggingMutex = CreateMutex(NULL, false, NULL);
diff --git a/daemon/Logging.h b/daemon/Logging.h
index 37f7dd3..8f960de 100644
--- a/daemon/Logging.h
+++ b/daemon/Logging.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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
@@ -42,6 +42,6 @@ private:
42 42
43extern Logging* logg; 43extern Logging* logg;
44 44
45extern void handleException(); 45extern void handleException() __attribute__ ((noreturn));
46 46
47#endif //__LOGGING_H__ 47#endif //__LOGGING_H__
diff --git a/daemon/Makefile b/daemon/Makefile
index 95d1809..24ee940 100644
--- a/daemon/Makefile
+++ b/daemon/Makefile
@@ -5,54 +5,21 @@
5# Uncomment and define CROSS_COMPILE if it is not already defined 5# Uncomment and define CROSS_COMPILE if it is not already defined
6# CROSS_COMPILE=/path/to/cross-compiler/arm-linux-gnueabihf- 6# CROSS_COMPILE=/path/to/cross-compiler/arm-linux-gnueabihf-
7# NOTE: This toolchain uses the hardfloat abi by default. For non-hardfloat 7# NOTE: This toolchain uses the hardfloat abi by default. For non-hardfloat
8# targets it is necessary to add options 8# targets run 'make SOFTFLOAT=1 SYSROOT=/path/to/sysroot', see
9# '-marm -march=armv4t -mfloat-abi=soft'. 9# README_Streamline.txt for more details
10 10
11CPP = $(CROSS_COMPILE)g++ 11CPP = $(CROSS_COMPILE)g++
12GCC = $(CROSS_COMPILE)gcc 12GCC = $(CROSS_COMPILE)gcc
13 13
14# -g produces debugging information
15# -O3 maximum optimization
16# -O0 no optimization, used for debugging
17# -Wall enables most warnings
18# -Werror treats warnings as errors
19# -std=c++0x is the planned new c++ standard
20# -std=c++98 is the 1998 c++ standard
21# -mthumb-interwork is required for interworking to ARM or Thumb stdlibc 14# -mthumb-interwork is required for interworking to ARM or Thumb stdlibc
22CFLAGS = -O3 -Wall -mthumb-interwork -fno-exceptions 15CFLAGS += -mthumb-interwork
23CXXFLAGS = -fno-rtti
24ifeq ($(WERROR),1)
25 CFLAGS += -Werror
26endif
27# -s strips the binary of debug info
28LDFLAGS = -s
29TARGET = gatord
30C_SRC = $(wildcard mxml/*.c)
31CPP_SRC = $(wildcard *.cpp)
32
33all: $(TARGET)
34
35events.xml: events_header.xml $(wildcard events-*.xml) events_footer.xml
36 cat $^ > $@
37
38StreamlineSetup.cpp: events_xml.h
39ConfigurationXML.cpp: configuration_xml.h
40
41%_xml.h: %.xml escape
42 ./escape $< > $@
43 16
44%.o: %.c *.h 17ifeq ($(SOFTFLOAT),1)
45 $(GCC) -c $(CFLAGS) -o $@ $< 18 CFLAGS += -marm -march=armv4t -mfloat-abi=soft
46 19 LDFLAGS += -marm -march=armv4t -mfloat-abi=soft
47%.o: %.cpp *.h 20endif
48 $(CPP) -c $(CFLAGS) $(CXXFLAGS) -o $@ $< 21ifneq ($(SYSROOT),)
49 22 LDFLAGS += --sysroot=$(SYSROOT)
50$(TARGET): $(CPP_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o) 23endif
51 $(CPP) $(LDFLAGS) -o $@ $^ -lc -lrt -lpthread
52 rm -f events_xml.h configuration_xml.h
53
54escape: escape.c
55 gcc $^ -o $@
56 24
57clean: 25include common.mk
58 rm -f *.o mxml/*.o $(TARGET) escape events.xml events_xml.h configuration_xml.h
diff --git a/daemon/Makefile_aarch64 b/daemon/Makefile_aarch64
new file mode 100644
index 0000000..10b4b4a
--- /dev/null
+++ b/daemon/Makefile_aarch64
@@ -0,0 +1,15 @@
1#
2# Makefile for ARM Streamline - Gator Daemon
3# make -f Makefile_aarch64
4#
5
6# Uncomment and define CROSS_COMPILE if it is not already defined
7# CROSS_COMPILE=/path/to/cross-compiler/arm-linux-gnueabihf-
8# NOTE: This toolchain uses the hardfloat abi by default. For non-hardfloat
9# targets it is necessary to add options
10# '-marm -march=armv4t -mfloat-abi=soft'.
11
12CPP = $(CROSS_COMPILE)g++
13GCC = $(CROSS_COMPILE)gcc
14
15include common.mk
diff --git a/daemon/OlySocket.cpp b/daemon/OlySocket.cpp
index 6128dc0..499f68c 100644
--- a/daemon/OlySocket.cpp
+++ b/daemon/OlySocket.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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/OlySocket.h b/daemon/OlySocket.h
index b306908..5bab7d1 100644
--- a/daemon/OlySocket.h
+++ b/daemon/OlySocket.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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.cpp b/daemon/OlyUtility.cpp
index df4fe22..2f85131 100644
--- a/daemon/OlyUtility.cpp
+++ b/daemon/OlyUtility.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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 424c583..5c68a58 100644
--- a/daemon/OlyUtility.h
+++ b/daemon/OlyUtility.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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/Sender.cpp b/daemon/Sender.cpp
index 54f2207..159503f 100644
--- a/daemon/Sender.cpp
+++ b/daemon/Sender.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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#include <unistd.h> 15#include <unistd.h>
16#include "Sender.h" 16#include "Sender.h"
17#include "Logging.h" 17#include "Logging.h"
18#include "OlySocket.h"
18#include "SessionData.h" 19#include "SessionData.h"
19 20
20Sender::Sender(OlySocket* socket) { 21Sender::Sender(OlySocket* socket) {
@@ -69,6 +70,11 @@ void Sender::createDataFile(char* apcDir) {
69 } 70 }
70} 71}
71 72
73template<typename T>
74inline T min(const T a, const T b) {
75 return (a < b ? a : b);
76}
77
72void Sender::writeData(const char* data, int length, int type) { 78void Sender::writeData(const char* data, int length, int type) {
73 if (length < 0 || (data == NULL && length > 0)) { 79 if (length < 0 || (data == NULL && length > 0)) {
74 return; 80 return;
@@ -80,7 +86,8 @@ void Sender::writeData(const char* data, int length, int type) {
80 // Send data over the socket connection 86 // Send data over the socket connection
81 if (mDataSocket) { 87 if (mDataSocket) {
82 // Start alarm 88 // Start alarm
83 alarm(8); 89 const int alarmDuration = 8;
90 alarm(alarmDuration);
84 91
85 // Send data over the socket, sending the type and size first 92 // Send data over the socket, sending the type and size first
86 logg->logMessage("Sending data with length %d", length); 93 logg->logMessage("Sending data with length %d", length);
@@ -89,7 +96,21 @@ void Sender::writeData(const char* data, int length, int type) {
89 mDataSocket->send((char*)&type, 1); 96 mDataSocket->send((char*)&type, 1);
90 mDataSocket->send((char*)&length, sizeof(length)); 97 mDataSocket->send((char*)&length, sizeof(length));
91 } 98 }
92 mDataSocket->send((char*)data, length); 99
100 // 100Kbits/sec * alarmDuration sec / 8 bits/byte
101 const int chunkSize = 100*1000 * alarmDuration / 8;
102 int pos = 0;
103 while (true) {
104 mDataSocket->send((char*)data + pos, min(length - pos, chunkSize));
105 pos += chunkSize;
106 if (pos >= length) {
107 break;
108 }
109
110 // Reset the alarm
111 alarm(alarmDuration);
112 logg->logMessage("Resetting the alarm");
113 }
93 114
94 // Stop alarm 115 // Stop alarm
95 alarm(0); 116 alarm(0);
diff --git a/daemon/Sender.h b/daemon/Sender.h
index ceab343..8f23361 100644
--- a/daemon/Sender.h
+++ b/daemon/Sender.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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,7 +11,8 @@
11 11
12#include <stdio.h> 12#include <stdio.h>
13#include <pthread.h> 13#include <pthread.h>
14#include "OlySocket.h" 14
15class OlySocket;
15 16
16enum { 17enum {
17 RESPONSE_XML = 1, 18 RESPONSE_XML = 1,
diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp
index 53a3ea6..4068d4e 100644
--- a/daemon/SessionData.cpp
+++ b/daemon/SessionData.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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,39 +25,19 @@ void SessionData::initialize() {
25 mSessionIsActive = false; 25 mSessionIsActive = false;
26 mLocalCapture = false; 26 mLocalCapture = false;
27 mOneShot = false; 27 mOneShot = false;
28 strcpy(mCoreName, "unknown"); 28 readCpuInfo();
29 mConfigurationXMLPath = NULL; 29 mConfigurationXMLPath = NULL;
30 mSessionXMLPath = NULL; 30 mSessionXMLPath = NULL;
31 mEventsXMLPath = NULL; 31 mEventsXMLPath = NULL;
32 mTargetPath = NULL; 32 mTargetPath = NULL;
33 mAPCDir = NULL; 33 mAPCDir = NULL;
34 mSampleRate = 0; 34 mSampleRate = 0;
35 mLiveRate = 0;
35 mDuration = 0; 36 mDuration = 0;
36 mBacktraceDepth = 0; 37 mBacktraceDepth = 0;
37 mTotalBufferSize = 0; 38 mTotalBufferSize = 0;
39 // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
38 mCores = 1; 40 mCores = 1;
39
40 initializeCounters();
41}
42
43void SessionData::initializeCounters() {
44 // PMU Counters
45 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
46 mPerfCounterType[i][0] = 0;
47 mPerfCounterTitle[i][0] = 0;
48 mPerfCounterName[i][0] = 0;
49 mPerfCounterDescription[i][0] = 0;
50 mPerfCounterDisplay[i][0] = 0;
51 mPerfCounterUnits[i][0] = 0;
52 mPerfCounterEnabled[i] = 0;
53 mPerfCounterEvent[i] = 0;
54 mPerfCounterColor[i] = 0;
55 mPerfCounterKey[i] = 0;
56 mPerfCounterCount[i] = 0;
57 mPerfCounterPerCPU[i] = false;
58 mPerfCounterEBSCapable[i] = false;
59 mPerfCounterAverageSelection[i] = false;
60 }
61} 41}
62 42
63void SessionData::parseSessionXML(char* xmlString) { 43void SessionData::parseSessionXML(char* xmlString) {
@@ -66,35 +46,103 @@ void SessionData::parseSessionXML(char* xmlString) {
66 46
67 // Set session data values 47 // Set session data values
68 if (strcmp(session.parameters.sample_rate, "high") == 0) { 48 if (strcmp(session.parameters.sample_rate, "high") == 0) {
69 gSessionData->mSampleRate = 10000; 49 mSampleRate = 10000;
70 } else if (strcmp(session.parameters.sample_rate, "normal") == 0) { 50 } else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
71 gSessionData->mSampleRate = 1000; 51 mSampleRate = 1000;
72 } else if (strcmp(session.parameters.sample_rate, "low") == 0) { 52 } else if (strcmp(session.parameters.sample_rate, "low") == 0) {
73 gSessionData->mSampleRate = 100; 53 mSampleRate = 100;
74 } else if (strcmp(session.parameters.sample_rate, "none") == 0) { 54 } else if (strcmp(session.parameters.sample_rate, "none") == 0) {
75 gSessionData->mSampleRate = 0; 55 mSampleRate = 0;
76 } else { 56 } else {
77 logg->logError(__FILE__, __LINE__, "Invalid sample rate (%s) in session xml.", session.parameters.sample_rate); 57 logg->logError(__FILE__, __LINE__, "Invalid sample rate (%s) in session xml.", session.parameters.sample_rate);
78 handleException(); 58 handleException();
79 } 59 }
80 gSessionData->mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0; 60 mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0;
81 gSessionData->mDuration = session.parameters.duration; 61 mDuration = session.parameters.duration;
82 62
83 // Determine buffer size (in MB) based on buffer mode 63 // Determine buffer size (in MB) based on buffer mode
84 gSessionData->mOneShot = true; 64 mOneShot = true;
85 if (strcmp(session.parameters.buffer_mode, "streaming") == 0) { 65 if (strcmp(session.parameters.buffer_mode, "streaming") == 0) {
86 gSessionData->mOneShot = false; 66 mOneShot = false;
87 gSessionData->mTotalBufferSize = 1; 67 mTotalBufferSize = 1;
88 } else if (strcmp(session.parameters.buffer_mode, "small") == 0) { 68 } else if (strcmp(session.parameters.buffer_mode, "small") == 0) {
89 gSessionData->mTotalBufferSize = 1; 69 mTotalBufferSize = 1;
90 } else if (strcmp(session.parameters.buffer_mode, "normal") == 0) { 70 } else if (strcmp(session.parameters.buffer_mode, "normal") == 0) {
91 gSessionData->mTotalBufferSize = 4; 71 mTotalBufferSize = 4;
92 } else if (strcmp(session.parameters.buffer_mode, "large") == 0) { 72 } else if (strcmp(session.parameters.buffer_mode, "large") == 0) {
93 gSessionData->mTotalBufferSize = 16; 73 mTotalBufferSize = 16;
94 } else { 74 } else {
95 logg->logError(__FILE__, __LINE__, "Invalid value for buffer mode in session xml."); 75 logg->logError(__FILE__, __LINE__, "Invalid value for buffer mode in session xml.");
96 handleException(); 76 handleException();
97 } 77 }
98 78
99 gSessionData->mImages = session.parameters.images; 79 mImages = session.parameters.images;
80 // Convert milli- to nanoseconds
81 mLiveRate = session.parameters.live_rate * (int64_t)1000000;
82 if (mLiveRate > 0 && mLocalCapture) {
83 logg->logMessage("Local capture is not compatable with live, disabling live");
84 mLiveRate = 0;
85 }
86}
87
88void SessionData::readCpuInfo() {
89 char temp[256]; // arbitrarily large amount
90 strcpy(mCoreName, "unknown");
91 mCpuId = -1;
92
93 FILE* f = fopen("/proc/cpuinfo", "r");
94 if (f == NULL) {
95 logg->logMessage("Error opening /proc/cpuinfo\n"
96 "The core name in the captured xml file will be 'unknown'.");
97 return;
98 }
99
100 bool foundCoreName = false;
101 bool foundCpuId = false;
102 while (fgets(temp, sizeof(temp), f) && (!foundCoreName || !foundCpuId)) {
103 if (strlen(temp) > 0) {
104 temp[strlen(temp) - 1] = 0; // Replace the line feed with a null
105 }
106
107 const bool foundHardware = strstr(temp, "Hardware") != 0;
108 const bool foundCPUPart = strstr(temp, "CPU part") != 0;
109 if (foundHardware || foundCPUPart) {
110 char* position = strchr(temp, ':');
111 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
112 logg->logMessage("Unknown format of /proc/cpuinfo\n"
113 "The core name in the captured xml file will be 'unknown'.");
114 return;
115 }
116 position += 2;
117
118 if (foundHardware) {
119 strncpy(mCoreName, position, sizeof(mCoreName));
120 mCoreName[sizeof(mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
121 foundCoreName = true;
122 }
123
124 if (foundCPUPart) {
125 int cpuId = strtol(position, NULL, 16);
126 if (cpuId > mCpuId) {
127 mCpuId = cpuId;
128 }
129 foundCpuId = true;
130 }
131 }
132 }
133
134 if (!foundCoreName) {
135 logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
136 "The core name in the captured xml file will be 'unknown'.");
137 }
138 fclose(f);
139 }
140
141int getEventKey() {
142 // Start one after the gator.ko's value of 1
143 static int key = 2;
144
145 const int ret = key;
146 key += 2;
147 return ret;
100} 148}
diff --git a/daemon/SessionData.h b/daemon/SessionData.h
index e0e0b7a..5b6899b 100644
--- a/daemon/SessionData.h
+++ b/daemon/SessionData.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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,11 +9,14 @@
9#ifndef SESSION_DATA_H 9#ifndef SESSION_DATA_H
10#define SESSION_DATA_H 10#define SESSION_DATA_H
11 11
12#include <stdint.h>
13
14#include "Counter.h"
15#include "Hwmon.h"
16
12#define MAX_PERFORMANCE_COUNTERS 50 17#define MAX_PERFORMANCE_COUNTERS 50
13#define MAX_STRING_LEN 80
14#define MAX_DESCRIPTION_LEN 400
15 18
16#define PROTOCOL_VERSION 12 19#define PROTOCOL_VERSION 13
17#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions 20#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions
18 21
19struct ImageLinkList { 22struct ImageLinkList {
@@ -23,12 +26,15 @@ struct ImageLinkList {
23 26
24class SessionData { 27class SessionData {
25public: 28public:
29 static const size_t MAX_STRING_LEN = 80;
30
26 SessionData(); 31 SessionData();
27 ~SessionData(); 32 ~SessionData();
28 void initialize(); 33 void initialize();
29 void initializeCounters();
30 void parseSessionXML(char* xmlString); 34 void parseSessionXML(char* xmlString);
31 35
36 Hwmon hwmon;
37
32 char mCoreName[MAX_STRING_LEN]; 38 char mCoreName[MAX_STRING_LEN];
33 struct ImageLinkList *mImages; 39 struct ImageLinkList *mImages;
34 char* mConfigurationXMLPath; 40 char* mConfigurationXMLPath;
@@ -45,27 +51,21 @@ public:
45 int mBacktraceDepth; 51 int mBacktraceDepth;
46 int mTotalBufferSize; // number of MB to use for the entire collection buffer 52 int mTotalBufferSize; // number of MB to use for the entire collection buffer
47 int mSampleRate; 53 int mSampleRate;
54 int64_t mLiveRate;
48 int mDuration; 55 int mDuration;
49 int mCores; 56 int mCores;
57 int mCpuId;
50 58
51 // PMU Counters 59 // PMU Counters
52 bool mCounterOverflow; 60 bool mCounterOverflow;
53 char mPerfCounterType[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN]; 61 Counter mCounters[MAX_PERFORMANCE_COUNTERS];
54 char mPerfCounterTitle[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN]; 62
55 char mPerfCounterName[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN]; 63private:
56 char mPerfCounterDescription[MAX_PERFORMANCE_COUNTERS][MAX_DESCRIPTION_LEN]; 64 void readCpuInfo();
57 char mPerfCounterDisplay[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
58 char mPerfCounterUnits[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
59 int mPerfCounterEnabled[MAX_PERFORMANCE_COUNTERS];
60 int mPerfCounterEvent[MAX_PERFORMANCE_COUNTERS];
61 int mPerfCounterColor[MAX_PERFORMANCE_COUNTERS];
62 int mPerfCounterCount[MAX_PERFORMANCE_COUNTERS];
63 int mPerfCounterKey[MAX_PERFORMANCE_COUNTERS];
64 bool mPerfCounterPerCPU[MAX_PERFORMANCE_COUNTERS];
65 bool mPerfCounterEBSCapable[MAX_PERFORMANCE_COUNTERS];
66 bool mPerfCounterAverageSelection[MAX_PERFORMANCE_COUNTERS];
67}; 65};
68 66
69extern SessionData* gSessionData; 67extern SessionData* gSessionData;
70 68
69int getEventKey();
70
71#endif // SESSION_DATA_H 71#endif // SESSION_DATA_H
diff --git a/daemon/SessionXML.cpp b/daemon/SessionXML.cpp
index b2b6c30..0a0a027 100644
--- a/daemon/SessionXML.cpp
+++ b/daemon/SessionXML.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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,6 +12,7 @@
12#include "SessionXML.h" 12#include "SessionXML.h"
13#include "Logging.h" 13#include "Logging.h"
14#include "OlyUtility.h" 14#include "OlyUtility.h"
15#include "SessionData.h"
15 16
16static const char* TAG_SESSION = "session"; 17static const char* TAG_SESSION = "session";
17static const char* TAG_IMAGE = "image"; 18static const char* TAG_IMAGE = "image";
@@ -22,12 +23,14 @@ static const char* ATTR_BUFFER_MODE = "buffer_mode";
22static const char* ATTR_SAMPLE_RATE = "sample_rate"; 23static const char* ATTR_SAMPLE_RATE = "sample_rate";
23static const char* ATTR_DURATION = "duration"; 24static const char* ATTR_DURATION = "duration";
24static const char* ATTR_PATH = "path"; 25static const char* ATTR_PATH = "path";
26static const char* ATTR_LIVE_RATE = "live_rate";
25 27
26SessionXML::SessionXML(const char* str) { 28SessionXML::SessionXML(const char* str) {
27 parameters.buffer_mode[0] = 0; 29 parameters.buffer_mode[0] = 0;
28 parameters.sample_rate[0] = 0; 30 parameters.sample_rate[0] = 0;
29 parameters.duration = 0; 31 parameters.duration = 0;
30 parameters.call_stack_unwinding = false; 32 parameters.call_stack_unwinding = false;
33 parameters.live_rate = 0;
31 parameters.images = NULL; 34 parameters.images = NULL;
32 mPath = 0; 35 mPath = 0;
33 mSessionXML = (char*)str; 36 mSessionXML = (char*)str;
@@ -78,6 +81,7 @@ void SessionXML::sessionTag(mxml_node_t *tree, mxml_node_t *node) {
78 // integers/bools 81 // integers/bools
79 parameters.call_stack_unwinding = util->stringToBool(mxmlElementGetAttr(node, ATTR_CALL_STACK_UNWINDING), false); 82 parameters.call_stack_unwinding = util->stringToBool(mxmlElementGetAttr(node, ATTR_CALL_STACK_UNWINDING), false);
80 if (mxmlElementGetAttr(node, ATTR_DURATION)) parameters.duration = strtol(mxmlElementGetAttr(node, ATTR_DURATION), NULL, 10); 83 if (mxmlElementGetAttr(node, ATTR_DURATION)) parameters.duration = strtol(mxmlElementGetAttr(node, ATTR_DURATION), NULL, 10);
84 if (mxmlElementGetAttr(node, ATTR_LIVE_RATE)) parameters.live_rate = strtol(mxmlElementGetAttr(node, ATTR_LIVE_RATE), NULL, 10);
81 85
82 // parse subtags 86 // parse subtags
83 node = mxmlGetFirstChild(node); 87 node = mxmlGetFirstChild(node);
diff --git a/daemon/SessionXML.h b/daemon/SessionXML.h
index f7a5641..c7e3798 100644
--- a/daemon/SessionXML.h
+++ b/daemon/SessionXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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
@@ -10,13 +10,15 @@
10#define SESSION_XML_H 10#define SESSION_XML_H
11 11
12#include "mxml/mxml.h" 12#include "mxml/mxml.h"
13#include "SessionData.h" 13
14struct ImageLinkList;
14 15
15struct ConfigParameters { 16struct ConfigParameters {
16 char buffer_mode[64]; // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size 17 char buffer_mode[64]; // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size
17 char sample_rate[64]; // capture mode, "high", "normal", or "low" 18 char sample_rate[64]; // capture mode, "high", "normal", or "low"
18 int duration; // length of profile in seconds 19 int duration; // length of profile in seconds
19 bool call_stack_unwinding; // whether stack unwinding is performed 20 bool call_stack_unwinding; // whether stack unwinding is performed
21 int live_rate;
20 struct ImageLinkList *images; // linked list of image strings 22 struct ImageLinkList *images; // linked list of image strings
21}; 23};
22 24
diff --git a/daemon/StreamlineSetup.cpp b/daemon/StreamlineSetup.cpp
index d13cf1d..88c07a6 100644
--- a/daemon/StreamlineSetup.cpp
+++ b/daemon/StreamlineSetup.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2013. 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#include <string.h> 9#include <string.h>
10#include <stdlib.h> 10#include <stdlib.h>
11#include <unistd.h> 11#include <unistd.h>
12#include <dirent.h>
13#include <sys/types.h>
14#include <arpa/inet.h> 12#include <arpa/inet.h>
15#include <sys/socket.h> 13#include <sys/socket.h>
16#include <netinet/in.h> 14#include <netinet/in.h>
@@ -21,6 +19,7 @@
21#include "CapturedXML.h" 19#include "CapturedXML.h"
22#include "StreamlineSetup.h" 20#include "StreamlineSetup.h"
23#include "ConfigurationXML.h" 21#include "ConfigurationXML.h"
22#include "Driver.h"
24 23
25static const char* TAG_SESSION = "session"; 24static const char* TAG_SESSION = "session";
26static const char* TAG_REQUEST = "request"; 25static const char* TAG_REQUEST = "request";
@@ -30,7 +29,6 @@ static const char* ATTR_TYPE = "type";
30static const char* VALUE_EVENTS = "events"; 29static const char* VALUE_EVENTS = "events";
31static const char* VALUE_CONFIGURATION = "configuration"; 30static const char* VALUE_CONFIGURATION = "configuration";
32static const char* VALUE_COUNTERS = "counters"; 31static const char* VALUE_COUNTERS = "counters";
33static const char* VALUE_SESSION = "session";
34static const char* VALUE_CAPTURED = "captured"; 32static const char* VALUE_CAPTURED = "captured";
35static const char* VALUE_DEFAULTS = "defaults"; 33static const char* VALUE_DEFAULTS = "defaults";
36 34
@@ -40,7 +38,6 @@ StreamlineSetup::StreamlineSetup(OlySocket* s) {
40 int type; 38 int type;
41 39
42 mSocket = s; 40 mSocket = s;
43 mSessionXML = NULL;
44 41
45 // Receive commands from Streamline (master) 42 // Receive commands from Streamline (master)
46 while (!ready) { 43 while (!ready) {
@@ -87,9 +84,6 @@ StreamlineSetup::StreamlineSetup(OlySocket* s) {
87} 84}
88 85
89StreamlineSetup::~StreamlineSetup() { 86StreamlineSetup::~StreamlineSetup() {
90 if (mSessionXML) {
91 free(mSessionXML);
92 }
93} 87}
94 88
95char* StreamlineSetup::readCommand(int* command) { 89char* StreamlineSetup::readCommand(int* command) {
@@ -162,9 +156,6 @@ void StreamlineSetup::handleRequest(char* xml) {
162 } else if (attr && strcmp(attr, VALUE_COUNTERS) == 0) { 156 } else if (attr && strcmp(attr, VALUE_COUNTERS) == 0) {
163 sendCounters(); 157 sendCounters();
164 logg->logMessage("Sent counters xml response"); 158 logg->logMessage("Sent counters xml response");
165 } else if (attr && strcmp(attr, VALUE_SESSION) == 0) {
166 sendData(mSessionXML, strlen(mSessionXML), RESPONSE_XML);
167 logg->logMessage("Sent session xml response");
168 } else if (attr && strcmp(attr, VALUE_CAPTURED) == 0) { 159 } else if (attr && strcmp(attr, VALUE_CAPTURED) == 0) {
169 CapturedXML capturedXML; 160 CapturedXML capturedXML;
170 char* capturedText = capturedXML.getXML(false); 161 char* capturedText = capturedXML.getXML(false);
@@ -191,13 +182,6 @@ void StreamlineSetup::handleDeliver(char* xml) {
191 if (mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND_FIRST)) { 182 if (mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND_FIRST)) {
192 // Session XML 183 // Session XML
193 gSessionData->parseSessionXML(xml); 184 gSessionData->parseSessionXML(xml);
194
195 // Save xml
196 mSessionXML = strdup(xml);
197 if (mSessionXML == NULL) {
198 logg->logError(__FILE__, __LINE__, "malloc failed for size %d", strlen(xml) + 1);
199 handleException();
200 }
201 sendData(NULL, 0, RESPONSE_ACK); 185 sendData(NULL, 0, RESPONSE_ACK);
202 logg->logMessage("Received session xml"); 186 logg->logMessage("Received session xml");
203 } else if (mxmlFindElement(tree, tree, TAG_CONFIGURATIONS, NULL, NULL, MXML_DESCEND_FIRST)) { 187 } else if (mxmlFindElement(tree, tree, TAG_CONFIGURATIONS, NULL, NULL, MXML_DESCEND_FIRST)) {
@@ -222,28 +206,43 @@ void StreamlineSetup::sendData(const char* data, int length, int type) {
222 206
223void StreamlineSetup::sendEvents() { 207void StreamlineSetup::sendEvents() {
224#include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len 208#include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
225 char* path = (char*)malloc(PATH_MAX);; 209 char path[PATH_MAX];
226 char* buffer; 210 mxml_node_t *xml;
227 unsigned int size = 0; 211 FILE *fl;
228 212
213 // Avoid unused variable warning
214 (void)events_xml_len;
215
216 // Load the provided or default events xml
229 if (gSessionData->mEventsXMLPath) { 217 if (gSessionData->mEventsXMLPath) {
230 strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX); 218 strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
231 } else { 219 } else {
232 util->getApplicationFullPath(path, PATH_MAX); 220 util->getApplicationFullPath(path, PATH_MAX);
233 strncat(path, "events.xml", PATH_MAX - strlen(path) - 1); 221 strncat(path, "events.xml", PATH_MAX - strlen(path) - 1);
234 } 222 }
235 buffer = util->readFromDisk(path, &size); 223 fl = fopen(path, "r");
236 if (buffer == NULL) { 224 if (fl) {
225 xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
226 fclose(fl);
227 } else {
237 logg->logMessage("Unable to locate events.xml, using default"); 228 logg->logMessage("Unable to locate events.xml, using default");
238 buffer = (char*)events_xml; 229 xml = mxmlLoadString(NULL, (char *)events_xml, MXML_NO_CALLBACK);
239 size = events_xml_len;
240 } 230 }
241 231
242 sendData(buffer, size, RESPONSE_XML); 232 // Add dynamic events from the drivers
243 if (buffer != (char*)events_xml) { 233 mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
244 free(buffer); 234 if (!events) {
235 logg->logMessage("Unable to find <events> node in the events.xml");
236 handleException();
237 }
238 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
239 driver->writeEvents(events);
245 } 240 }
246 free(path); 241
242 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
243 sendString(string, RESPONSE_XML);
244 free(string);
245 mxmlDelete(xml);
247} 246}
248 247
249void StreamlineSetup::sendConfiguration() { 248void StreamlineSetup::sendConfiguration() {
@@ -268,30 +267,15 @@ void StreamlineSetup::sendDefaults() {
268 sendData(xml, size, RESPONSE_XML); 267 sendData(xml, size, RESPONSE_XML);
269} 268}
270 269
271#include <dirent.h>
272void StreamlineSetup::sendCounters() { 270void StreamlineSetup::sendCounters() {
273 struct dirent *ent;
274 mxml_node_t *xml; 271 mxml_node_t *xml;
275 mxml_node_t *counters; 272 mxml_node_t *counters;
276 mxml_node_t *counter;
277
278 // counters.xml is simply a file listing of /dev/gator/events
279 DIR* dir = opendir("/dev/gator/events");
280 if (dir == NULL) {
281 logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events");
282 handleException();
283 }
284 273
285 xml = mxmlNewXML("1.0"); 274 xml = mxmlNewXML("1.0");
286 counters = mxmlNewElement(xml, "counters"); 275 counters = mxmlNewElement(xml, "counters");
287 while ((ent = readdir(dir)) != NULL) { 276 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
288 // skip hidden files, current dir, and parent dir 277 driver->writeCounters(counters);
289 if (ent->d_name[0] == '.')
290 continue;
291 counter = mxmlNewElement(counters, "counter");
292 mxmlElementSetAttr(counter, "name", ent->d_name);
293 } 278 }
294 closedir (dir);
295 279
296 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB); 280 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
297 sendString(string, RESPONSE_XML); 281 sendString(string, RESPONSE_XML);
@@ -301,7 +285,7 @@ void StreamlineSetup::sendCounters() {
301} 285}
302 286
303void StreamlineSetup::writeConfiguration(char* xml) { 287void StreamlineSetup::writeConfiguration(char* xml) {
304 char* path = (char*)malloc(PATH_MAX); 288 char path[PATH_MAX];
305 289
306 if (gSessionData->mConfigurationXMLPath) { 290 if (gSessionData->mConfigurationXMLPath) {
307 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX); 291 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX);
@@ -316,8 +300,7 @@ void StreamlineSetup::writeConfiguration(char* xml) {
316 } 300 }
317 301
318 // Re-populate gSessionData with the configuration, as it has now changed 302 // Re-populate gSessionData with the configuration, as it has now changed
319 new ConfigurationXML(); 303 { ConfigurationXML configuration; }
320 free(path);
321 304
322 if (gSessionData->mCounterOverflow) { 305 if (gSessionData->mCounterOverflow) {
323 logg->logError(__FILE__, __LINE__, "Exceeded maximum number of %d performance counters", MAX_PERFORMANCE_COUNTERS); 306 logg->logError(__FILE__, __LINE__, "Exceeded maximum number of %d performance counters", MAX_PERFORMANCE_COUNTERS);
diff --git a/daemon/StreamlineSetup.h b/daemon/StreamlineSetup.h
index 8086fe2..841735d 100644
--- a/daemon/StreamlineSetup.h
+++ b/daemon/StreamlineSetup.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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
@@ -28,7 +28,6 @@ public:
28private: 28private:
29 int mNumConnections; 29 int mNumConnections;
30 OlySocket* mSocket; 30 OlySocket* mSocket;
31 char* mSessionXML;
32 31
33 char* readCommand(int*); 32 char* readCommand(int*);
34 void handleRequest(char* xml); 33 void handleRequest(char* xml);
diff --git a/daemon/common.mk b/daemon/common.mk
new file mode 100644
index 0000000..112b990
--- /dev/null
+++ b/daemon/common.mk
@@ -0,0 +1,50 @@
1# -g produces debugging information
2# -O3 maximum optimization
3# -O0 no optimization, used for debugging
4# -Wall enables most warnings
5# -Werror treats warnings as errors
6# -std=c++0x is the planned new c++ standard
7# -std=c++98 is the 1998 c++ standard
8CFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors
9CXXFLAGS += -fno-rtti
10ifeq ($(WERROR),1)
11 CFLAGS += -Werror
12endif
13# -s strips the binary of debug info
14LDFLAGS += -s
15TARGET = gatord
16C_SRC = $(wildcard mxml/*.c) $(wildcard libsensors/*.c)
17CPP_SRC = $(wildcard *.cpp)
18
19all: $(TARGET)
20
21events.xml: events_header.xml $(wildcard events-*.xml) events_footer.xml
22 cat $^ > $@
23
24include $(wildcard *.d)
25include $(wildcard mxml/*.d)
26
27StreamlineSetup.cpp: events_xml.h
28ConfigurationXML.cpp: configuration_xml.h
29
30# Don't regenerate conf-lex.c or conf-parse.c
31libsensors/conf-lex.c: ;
32libsensors/conf-parse.c: ;
33
34%_xml.h: %.xml escape
35 ./escape $< > $@
36
37%.o: %.c
38 $(GCC) -c $(CFLAGS) -o $@ $<
39
40%.o: %.cpp
41 $(CPP) -c $(CFLAGS) $(CXXFLAGS) -o $@ $<
42
43$(TARGET): $(CPP_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o)
44 $(CPP) $(LDFLAGS) -o $@ $^ -lrt -pthread
45
46escape: escape.c
47 gcc $^ -o $@
48
49clean:
50 rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h configuration_xml.h
diff --git a/daemon/configuration.xml b/daemon/configuration.xml
index fbdef31..62ccd08 100644
--- a/daemon/configuration.xml
+++ b/daemon/configuration.xml
@@ -1,41 +1,41 @@
1<?xml version="1.0" encoding='UTF-8'?> 1<?xml version="1.0" encoding='UTF-8'?>
2<configurations revision="1"> 2<configurations revision="2">
3 <configuration counter="ARM_ARM11_ccnt" title="Clock" name="Cycles" per_cpu="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <configuration counter="ARM_ARM11_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <configuration counter="ARM_ARM11_cnt0" event="0x7" title="Instruction" name="Executed" per_cpu="yes" description="Instructions executed"/> 4 <configuration counter="ARM_ARM11_cnt0" event="0x7" title="Instruction" name="Executed" per_cpu="yes" description="Instructions executed"/>
5 <configuration counter="ARM_ARM11_cnt1" event="0xb" title="Cache" name="Data miss" per_cpu="yes" description="Data cache miss, not including Cache Operations"/> 5 <configuration counter="ARM_ARM11_cnt1" event="0xb" title="Cache" name="Data miss" per_cpu="yes" description="Data cache miss, not including Cache Operations"/>
6 <configuration counter="ARM_ARM11MPCore_ccnt" title="Clock" name="Cycles" per_cpu="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 6 <configuration counter="ARM_ARM11MPCore_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
7 <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08" title="Core" name="Instructions" per_cpu="yes" description="Instructions executed"/> 7 <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08" title="Core" name="Instructions" per_cpu="yes" description="Instructions executed"/>
8 <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b" title="Cache" name="Data read miss" per_cpu="yes" description="Data cache miss, not including Cache Operations"/> 8 <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b" title="Cache" name="Data read miss" per_cpu="yes" description="Data cache miss, not including Cache Operations"/>
9 <configuration counter="ARM_Cortex-A5_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 9 <configuration counter="ARM_Cortex-A5_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
10 <configuration counter="ARM_Cortex-A5_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 10 <configuration counter="ARM_Cortex-A5_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
11 <configuration counter="ARM_Cortex-A5_cnt1" event="0x1" title="Cache" name="Instruction refill" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 11 <configuration counter="ARM_Cortex-A5_cnt1" event="0x1" title="Cache" name="Instruction refill" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
12 <configuration counter="ARM_Cortex-A7_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 12 <configuration counter="ARM_Cortex-A7_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
13 <configuration counter="ARM_Cortex-A7_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 13 <configuration counter="ARM_Cortex-A7_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
14 <configuration counter="ARM_Cortex-A7_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 14 <configuration counter="ARM_Cortex-A7_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
15 <configuration counter="ARM_Cortex-A7_cnt2" event="0x16" title="Cache" name="L2 data access" per_cpu="yes" supports_event_based_sampling="yes" description="Level 2 data cache access"/> 15 <configuration counter="ARM_Cortex-A7_cnt2" event="0x16" title="Cache" name="L2 data access" per_cpu="yes" supports_event_based_sampling="yes" description="Level 2 data cache access"/>
16 <configuration counter="ARM_Cortex-A8_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 16 <configuration counter="ARM_Cortex-A8_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
17 <configuration counter="ARM_Cortex-A8_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 17 <configuration counter="ARM_Cortex-A8_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
18 <configuration counter="ARM_Cortex-A8_cnt1" event="0x44" title="Cache" name="L2 miss" per_cpu="yes" supports_event_based_sampling="yes" description="Any cacheable miss in the L2 cache"/> 18 <configuration counter="ARM_Cortex-A8_cnt1" event="0x44" title="Cache" name="L2 miss" per_cpu="yes" supports_event_based_sampling="yes" description="Any cacheable miss in the L2 cache"/>
19 <configuration counter="ARM_Cortex-A8_cnt2" event="0x43" title="Cache" name="L1 miss" per_cpu="yes" supports_event_based_sampling="yes" description="Any accesses to the L2 cache"/> 19 <configuration counter="ARM_Cortex-A8_cnt2" event="0x43" title="Cache" name="L1 miss" per_cpu="yes" supports_event_based_sampling="yes" description="Any accesses to the L2 cache"/>
20 <configuration counter="ARM_Cortex-A8_cnt3" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 20 <configuration counter="ARM_Cortex-A8_cnt3" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
21 <configuration counter="ARM_Cortex-A9_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 21 <configuration counter="ARM_Cortex-A9_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
22 <configuration counter="ARM_Cortex-A9_cnt0" event="0x68" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and even more approximate of the total number of instructions architecturally executed"/> 22 <configuration counter="ARM_Cortex-A9_cnt0" event="0x68" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and even more approximate of the total number of instructions architecturally executed"/>
23 <configuration counter="ARM_Cortex-A9_cnt1" event="0x06" title="Instruction" name="Memory read" per_cpu="yes" supports_event_based_sampling="yes" description="Memory-reading instruction architecturally executed"/> 23 <configuration counter="ARM_Cortex-A9_cnt1" event="0x06" title="Instruction" name="Memory read" per_cpu="yes" supports_event_based_sampling="yes" description="Memory-reading instruction architecturally executed"/>
24 <configuration counter="ARM_Cortex-A9_cnt2" event="0x07" title="Instruction" name="Memory write" per_cpu="yes" supports_event_based_sampling="yes" description="Memory-writing instruction architecturally executed"/> 24 <configuration counter="ARM_Cortex-A9_cnt2" event="0x07" title="Instruction" name="Memory write" per_cpu="yes" supports_event_based_sampling="yes" description="Memory-writing instruction architecturally executed"/>
25 <configuration counter="ARM_Cortex-A9_cnt3" event="0x03" title="Cache" name="Data refill" per_cpu="yes" supports_event_based_sampling="yes" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/> 25 <configuration counter="ARM_Cortex-A9_cnt3" event="0x03" title="Cache" name="Data refill" per_cpu="yes" supports_event_based_sampling="yes" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
26 <configuration counter="ARM_Cortex-A9_cnt4" event="0x04" title="Cache" name="Data access" per_cpu="yes" supports_event_based_sampling="yes" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/> 26 <configuration counter="ARM_Cortex-A9_cnt4" event="0x04" title="Cache" name="Data access" per_cpu="yes" supports_event_based_sampling="yes" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
27 <configuration counter="ARM_Cortex-A15_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 27 <configuration counter="ARM_Cortex-A15_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
28 <configuration counter="ARM_Cortex-A15_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 28 <configuration counter="ARM_Cortex-A15_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
29 <configuration counter="ARM_Cortex-A15_cnt1" event="0x16" title="Cache" name="L2 data access" per_cpu="yes" supports_event_based_sampling="yes" description="Level 2 data cache access"/> 29 <configuration counter="ARM_Cortex-A15_cnt1" event="0x16" title="Cache" name="L2 data access" per_cpu="yes" supports_event_based_sampling="yes" description="Level 2 data cache access"/>
30 <configuration counter="ARM_Cortex-A15_cnt2" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 30 <configuration counter="ARM_Cortex-A15_cnt2" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
31 <configuration counter="ARM_Cortex-A15_cnt3" event="0x19" title="Bus" name="Access" per_cpu="yes" supports_event_based_sampling="yes" description=""/> 31 <configuration counter="ARM_Cortex-A15_cnt3" event="0x19" title="Bus" name="Access" per_cpu="yes" supports_event_based_sampling="yes" description="Bus - Access"/>
32 <configuration counter="Scorpion_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 32 <configuration counter="Scorpion_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
33 <configuration counter="Scorpion_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 33 <configuration counter="Scorpion_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
34 <configuration counter="Scorpion_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 34 <configuration counter="Scorpion_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
35 <configuration counter="ScorpionMP_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 35 <configuration counter="ScorpionMP_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
36 <configuration counter="ScorpionMP_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 36 <configuration counter="ScorpionMP_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
37 <configuration counter="ScorpionMP_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 37 <configuration counter="ScorpionMP_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
38 <configuration counter="Krait_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 38 <configuration counter="Krait_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
39 <configuration counter="Krait_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 39 <configuration counter="Krait_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
40 <configuration counter="Krait_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 40 <configuration counter="Krait_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
41 <configuration counter="Linux_block_rq_wr" title="Disk IO" name="Write" units="B" description="Disk IO Bytes Written"/> 41 <configuration counter="Linux_block_rq_wr" title="Disk IO" name="Write" units="B" description="Disk IO Bytes Written"/>
diff --git a/daemon/escape.c b/daemon/escape.c
index c0f47f1..a154515 100644
--- a/daemon/escape.c
+++ b/daemon/escape.c
@@ -1,11 +1,17 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. 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/*
10 * The Makefile in the daemon folder builds and executes 'escape'
11 * 'escape' creates configuration_xml.h from configuration.xml and events_xml.h from events-*.xml
12 * these genereated xml files are then #included and built as part of the gatord binary
13 */
14
9#include <errno.h> 15#include <errno.h>
10#include <stdio.h> 16#include <stdio.h>
11#include <stdlib.h> 17#include <stdlib.h>
diff --git a/daemon/events-ARM11.xml b/daemon/events-ARM11.xml
index 0a5ee66..9f31313 100644
--- a/daemon/events-ARM11.xml
+++ b/daemon/events-ARM11.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_ARM11_cnt" count="3"/> 1 <counter_set name="ARM_ARM11_cnt" count="3"/>
2 <category name="ARM11" counter_set="ARM_ARM11_cnt" per_cpu="yes"> 2 <category name="ARM11" counter_set="ARM_ARM11_cnt" per_cpu="yes">
3 <event counter="ARM_ARM11_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ARM_ARM11_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/> 4 <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/>
5 <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/> 5 <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/>
6 <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/> 6 <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/>
diff --git a/daemon/events-ARM11MPCore.xml b/daemon/events-ARM11MPCore.xml
index 1a9ca3f..68ca9a5 100644
--- a/daemon/events-ARM11MPCore.xml
+++ b/daemon/events-ARM11MPCore.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_ARM11MPCore_cnt" count="3"/> 1 <counter_set name="ARM_ARM11MPCore_cnt" count="3"/>
2 <category name="ARM11MPCore" counter_set="ARM_ARM11MPCore_cnt" per_cpu="yes"> 2 <category name="ARM11MPCore" counter_set="ARM_ARM11MPCore_cnt" per_cpu="yes">
3 <event counter="ARM_ARM11MPCore_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ARM_ARM11MPCore_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/> 4 <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/>
5 <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/> 5 <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/>
6 <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/> 6 <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/>
diff --git a/daemon/events-CCI-400.xml b/daemon/events-CCI-400.xml
new file mode 100644
index 0000000..2be0df3
--- /dev/null
+++ b/daemon/events-CCI-400.xml
@@ -0,0 +1,47 @@
1 <counter_set name="cci-400_cnt" count="4"/>
2 <category name="CCI-400" counter_set="cci-400_cnt" per_cpu="no" supports_event_based_sampling="yes">
3 <event counter="cci-400_ccnt" event="0xff" title="CCI-400" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4
5 <option_set name="Slave">
6 <option event_delta="0x00" name="S0" description="Slave interface 0"/>
7 <option event_delta="0x20" name="S1" description="Slave interface 1"/>
8 <option event_delta="0x40" name="S2" description="Slave interface 2"/>
9 <option event_delta="0x60" name="S3" description="Slave interface 3"/>
10 <option event_delta="0x80" name="S4" description="Slave interface 4"/>
11 </option_set>
12
13 <event event="0x00" option_set="Slave" title="CCI-400" name="Read: any" description="Read request handshake: any"/>
14 <event event="0x01" option_set="Slave" title="CCI-400" name="Read: transaction" description="Read request handshake: device transaction"/>
15 <event event="0x02" option_set="Slave" title="CCI-400" name="Read: normal" description="Read request handshake: normal, non-shareable or system-shareable, but not barrier or cache maintenance operation"/>
16 <event event="0x03" option_set="Slave" title="CCI-400" name="Read: shareable" description="Read request handshake: inner- or outer-shareable, but not barrier, DVM message or cache maintenance operation"/>
17 <event event="0x04" option_set="Slave" title="CCI-400" name="Read: cache" description="Read request handshake: cache maintenance operation, CleanInvalid, CleanShared, MakeInvalid"/>
18 <event event="0x05" option_set="Slave" title="CCI-400" name="Read: memory barrier" description="Read request handshake: memory barrier"/>
19 <event event="0x06" option_set="Slave" title="CCI-400" name="Read: sync barrier" description="Read request handshake: synchronization barrier"/>
20 <event event="0x07" option_set="Slave" title="CCI-400" name="Read: DVM message, no sync" description="Read request handshake: DVM message, no synchronization"/>
21 <event event="0x08" option_set="Slave" title="CCI-400" name="Read: DVM message, sync" description="Read request handshake: DVM message, synchronization"/>
22 <event event="0x09" option_set="Slave" title="CCI-400" name="Read: stall" description="Read request stall cycle because the transaction tracker is full. Increase SIx_R_MAX to avoid this stall"/>
23 <event event="0x0a" option_set="Slave" title="CCI-400" name="Read data last handshake" description="Read data last handshake: data returned from the snoop instead of from downstream"/>
24 <event event="0x0b" option_set="Slave" title="CCI-400" name="Read data stall cycle" description="Read data stall cycle: RVALIDS is HIGH, RREADYS is LOW"/>
25 <event event="0x0c" option_set="Slave" title="CCI-400" name="Write: any" description="Write request handshake: any"/>
26 <event event="0x0d" option_set="Slave" title="CCI-400" name="Write: transaction" description="Write request handshake: device transaction"/>
27 <event event="0x0e" option_set="Slave" title="CCI-400" name="Write: normal" description="Write request handshake: normal, non-shareable, or system-shareable, but not barrier"/>
28 <event event="0x0f" option_set="Slave" title="CCI-400" name="Write: shareable" description="Write request handshake: inner- or outer-shareable, WriteBack or WriteClean"/>
29 <event event="0x10" option_set="Slave" title="CCI-400" name="Write: WriteUnique" description="Write request handshake: WriteUnique"/>
30 <event event="0x11" option_set="Slave" title="CCI-400" name="Write: WriteLineUnique" description="Write request handshake: WriteLineUnique"/>
31 <event event="0x12" option_set="Slave" title="CCI-400" name="Write: Evict" description="Write request handshake: Evict"/>
32 <event event="0x13" option_set="Slave" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase SIx_W_MAX to avoid this stall"/>
33
34 <option_set name="Master">
35 <option event_delta="0xa0" name="M0" description="Master interface 0"/>
36 <option event_delta="0xc0" name="M1" description="Master interface 1"/>
37 <option event_delta="0xe0" name="M2" description="Master interface 2"/>
38 </option_set>
39
40 <event event="0x14" option_set="Master" title="CCI-400" name="Retry fetch" description="RETRY of speculative fetch transaction"/>
41 <event event="0x15" option_set="Master" title="CCI-400" name="Read stall: address hazard" description="Read request stall cycle because of an address hazard"/>
42 <event event="0x16" option_set="Master" title="CCI-400" name="Read stall: ID hazard" description="Read request stall cycle because of an ID hazard"/>
43 <event event="0x17" option_set="Master" title="CCI-400" name="Read stall: tracker full" description="Read request stall cycle because the transaction tracker is full. Increase MIx_R_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
44 <event event="0x18" option_set="Master" title="CCI-400" name="Read stall: barrier hazard" description="Read request stall cycle because of a barrier hazard"/>
45 <event event="0x19" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
46 <event event="0x1a" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase MIx_W_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
47 </category>
diff --git a/daemon/events-Cortex-A15.xml b/daemon/events-Cortex-A15.xml
index e0bd201..e3de814 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="ARM_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="ARM_Cortex-A15_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A15_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ARM_Cortex-A15_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="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"/>
@@ -19,13 +19,13 @@
19 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/> 19 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
20 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/> 20 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
21 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/> 21 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
22 <event event="0x19" title="Bus" name="Access" description=""/> 22 <event event="0x19" title="Bus" name="Access" description="Bus - Access"/>
23 <event event="0x1a" title="Memory" name="Error" description="Local memory error"/> 23 <event event="0x1a" title="Memory" name="Error" description="Local memory error"/>
24 <event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/> 24 <event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/>
25 <event event="0x1c" title="Memory" name="Translation table" description="Write to translation table base architecturally executed"/> 25 <event event="0x1c" title="Memory" name="Translation table" description="Wr