aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrew Richardson <drew.richardson@arm.com>2015-07-22 12:00:00 -0700
committerDrew Richardson <drew.richardson@arm.com>2015-07-24 07:41:39 -0700
commit7ca6004c0b05138c49b9b21e0045487f55a60ab6 (patch)
tree74cdc2c608e28891189b58e68992b3a8acf140e0
parentc2fdcde9f26fff5eebbcc2ab34adb9d4202e0d55 (diff)
gator: Version 5.22HEAD5.22master
Signed-off-by: Drew Richardson <drew.richardson@arm.com>
-rwxr-xr-xREADME.md298
-rw-r--r--README_Streamline.txt250
-rw-r--r--daemon/Android.mk3
-rw-r--r--daemon/AtraceDriver.cpp136
-rw-r--r--daemon/AtraceDriver.h39
-rw-r--r--daemon/Buffer.cpp16
-rw-r--r--daemon/Buffer.h3
-rw-r--r--daemon/CCNDriver.cpp41
-rw-r--r--daemon/CCNDriver.h2
-rw-r--r--daemon/CapturedXML.cpp2
-rw-r--r--daemon/Child.cpp50
-rw-r--r--daemon/Command.cpp69
-rw-r--r--daemon/Config.h7
-rw-r--r--daemon/ConfigurationXML.cpp15
-rw-r--r--daemon/DiskIODriver.cpp2
-rw-r--r--daemon/DriverSource.cpp56
-rw-r--r--daemon/DriverSource.h1
-rw-r--r--daemon/EventsXML.cpp4
-rw-r--r--daemon/ExternalDriver.cpp269
-rw-r--r--daemon/ExternalDriver.h41
-rw-r--r--daemon/ExternalSource.cpp84
-rw-r--r--daemon/ExternalSource.h3
-rw-r--r--daemon/FtraceDriver.cpp115
-rw-r--r--daemon/FtraceDriver.h5
-rw-r--r--daemon/FtraceSource.cpp188
-rw-r--r--daemon/FtraceSource.h43
-rw-r--r--daemon/MaliVideoDriver.cpp28
-rw-r--r--daemon/MaliVideoDriver.h1
-rw-r--r--daemon/MemInfoDriver.cpp2
-rw-r--r--daemon/NetDriver.cpp2
-rw-r--r--daemon/PerfDriver.cpp184
-rw-r--r--daemon/PerfDriver.h8
-rw-r--r--daemon/PerfGroup.cpp15
-rw-r--r--daemon/PerfSource.cpp29
-rw-r--r--daemon/Proc.cpp9
-rw-r--r--daemon/Sender.cpp22
-rw-r--r--daemon/SessionData.cpp108
-rw-r--r--daemon/SessionData.h44
-rw-r--r--daemon/Setup.cpp36
-rw-r--r--daemon/StreamlineSetup.cpp10
-rw-r--r--daemon/UserSpaceSource.cpp10
-rw-r--r--daemon/defaults.xml30
-rw-r--r--daemon/events-CCI-400.xml6
-rw-r--r--daemon/events-Cortex-A53.xml6
-rw-r--r--daemon/events-Cortex-A57.xml6
-rw-r--r--daemon/events-Cortex-A72.xml6
-rw-r--r--daemon/events-Mali-4xx.xml11
-rw-r--r--daemon/events-Mali-Midgard_hw.xml4
-rw-r--r--daemon/events-Mali-T82x_hw.xml216
-rw-r--r--daemon/events-Mali-V500.xml4
-rw-r--r--daemon/events-atrace.xml19
-rw-r--r--daemon/events-ftrace.xml20
-rw-r--r--daemon/k/perf_event.3.12.h792
-rw-r--r--[l---------]daemon/k/perf_event.h793
-rw-r--r--daemon/main.cpp31
-rw-r--r--daemon/notify/COPYING339
-rw-r--r--daemon/notify/Makefile24
-rw-r--r--daemon/notify/Notify.java31
-rw-r--r--driver/Makefile2
-rw-r--r--driver/gator.h12
-rw-r--r--driver/gator_cookies.c110
-rw-r--r--driver/gator_events_armv6.c1
-rw-r--r--driver/gator_events_armv7.c1
-rw-r--r--driver/gator_events_block.c1
-rw-r--r--driver/gator_events_irq.c1
-rw-r--r--driver/gator_events_l2c-310.c1
-rw-r--r--driver/gator_events_mali_4xx.c40
-rw-r--r--driver/gator_events_mali_common.c10
-rw-r--r--driver/gator_events_mali_midgard.c23
-rw-r--r--driver/gator_events_mali_midgard_hw.c121
-rw-r--r--driver/gator_events_mali_midgard_hw_test.c43
-rw-r--r--driver/gator_events_meminfo.c7
-rw-r--r--driver/gator_events_mmapped.c1
-rw-r--r--driver/gator_events_net.c7
-rw-r--r--driver/gator_events_perf_pmu.c17
-rw-r--r--driver/gator_events_sched.c1
-rw-r--r--driver/gator_events_scorpion.c1
-rw-r--r--driver/gator_fs.c2
-rw-r--r--driver/gator_hrtimer_gator.c8
-rw-r--r--driver/gator_main.c26
-rw-r--r--driver/gator_marshaling.c4
-rw-r--r--driver/gator_trace_gpu.c2
-rw-r--r--driver/gator_trace_sched.c8
-rw-r--r--driver/mali_midgard.mk3
84 files changed, 3061 insertions, 1980 deletions
diff --git a/README.md b/README.md
new file mode 100755
index 0000000..8e55b1e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,298 @@
+
+## Purpose
+
+Instructions on setting up ARM Streamline on the target.
+
+A target agent (gator) is required to run on the ARM Linux target in order for ARM Streamline to operate. Gator may run in kernel space or user space mode, though user space gator requires Linux 3.4 or later and contains reduced functionality. Furthermore, user space gator is a beta release, see the bugs section in this readme for a list of known issues.
+
+The driver should be built as a module and the daemon must run with root permissions on the target.
+
+## Introduction
+
+A Linux development environment with cross compiling tools is most likely required, depending on what is already created and provided.
+- 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.
+- 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.
+- 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.
+ - 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.
+ - 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/`.
+ - 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.
+ - If the target is running Linux 3.4 or later the kernel driver is not required and userspace APIs will be used instead.
+
+## Kernel configuration
+
+menuconfig options (depending on the kernel version, the location of these configuration settings within menuconfig may differ)
+- General Setup
+ - Kernel Performance Events And Counters
+ - [*] Kernel performance events and counters (enables CONFIG_PERF_EVENTS)
+ - [*] Profiling Support (enables CONFIG_PROFILING)
+- [*] Enable loadable module support (enables CONFIG_MODULES, needed unless the gator driver is built into the kernel)
+ - [*] Module unloading (enables MODULE_UNLOAD)
+- Kernel Features
+ - [*] High Resolution Timer Support (enables CONFIG_HIGH_RES_TIMERS)
+ - [*] Use local timer interrupts (only required for SMP and for version before Linux 3.12, enables CONFIG_LOCAL_TIMERS)
+ - [*] Enable hardware performance counter support for perf events (enables CONFIG_HW_PERF_EVENTS)
+- CPU Power Management
+ - CPU Frequency scaling
+ - [*] CPU Frequency scaling (enables CONFIG_CPU_FREQ)
+- Device Drivers
+ - Graphics support
+ - ARM GPU Configuration
+ - Mali Midgard series support
+ - [*] Streamline Debug support (enables CONFIG_MALI_GATOR_SUPPORT needed as part of Mali Midgard support)
+- Kernel hacking
+ - [*] Compile the kernel with debug info (optional, enables CONFIG_DEBUG_INFO)
+ - [*] Tracers
+ - [*] Trace process context switches and events (#)
+
+(#) The "Trace process context switches and events" is not the only option that enables tracing (CONFIG_GENERIC_TRACER or CONFIG_TRACING as well as CONFIG_CONTEXT_SWITCH_TRACER) 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.
+
+The configuration options:
+- CONFIG_MODULES and MODULE_UNLOAD (not needed if the gator driver is built into the kernel)
+- CONFIG_GENERIC_TRACER or CONFIG_TRACING
+- CONFIG_CONTEXT_SWITCH_TRACER
+- CONFIG_PROFILING
+- CONFIG_HIGH_RES_TIMERS
+- CONFIG_LOCAL_TIMERS (for SMP systems and kernel versions before 3.12)
+- CONFIG_PERF_EVENTS and CONFIG_HW_PERF_EVENTS (kernel versions 3.0 and greater)
+- CONFIG_DEBUG_INFO (optional, used for analyzing the kernel)
+- CONFIG_CPU_FREQ (optional, provides frequency setting of the CPU)
+- CONFIG_MALI_GATOR_SUPPORT (needed as part of Mali Midgard support)
+
+These 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
+```
+> zcat /proc/config.gz | grep CONFIG_PROFILING
+CONFIG_PROFILING=y
+```
+
+If a device tree is used it must include the pmu bindings, see Documentation/devicetree/bindings/arm/pmu.txt for details.
+
+## Checking the gator requirements
+
+(optional) Use the hrtimer_module utility to validate the kernel High Resolution Timer requirement.
+
+## Building the gator module
+
+To create the gator.ko module,
+```
+tar xzf /path/to/DS-5/arm/gator/driver-src/gator-driver.tar.gz
+cd gator-driver
+make -C <kernel_build_dir> M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules
+```
+whenever possible, use the same toolchain the kernel was built with when building gator.ko
+
+for example when using the linaro-toolchain-binaries
+```
+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
+```
+If successful, a gator.ko module should be generated
+
+It is also possible to integrate the gator.ko module into the kernel build system
+```
+cd /path/to/kernel/build/dir
+cd drivers
+mkdir gator
+cp -r /path/to/gator/driver-src/* gator
+```
+Edit Makefile in the kernel drivers folder and add this to the end
+```
+obj-$(CONFIG_GATOR) += gator/
+```
+Edit Kconfig in the kernel drivers folder and add this before the last endmenu
+```
+source "drivers/gator/Kconfig"
+```
+You can now select gator when using menuconfig while configuring the kernel and rebuild as directed
+
+## Use the prebuilt gator daemon
+
+A prebuilt gator daemon is provided at `/path/to/DS-5/arm/gator/gatord`. This gator daemon should work in most cases so building the gator daemon is only required if the prebuilt gator daemon doesn't work.
+
+To improve portablility gatord is statically compiled against musl libc from http://www.musl-libc.org/download.html instead of glibc. The gator daemon will work correctly with either glibc or musl.
+
+## Building the gator daemon
+
+```
+tar -xzf /path/to/DS-5/arm/gator/daemon-src/gator-daemon.tar.gz
+```
+For Linux targets,
+```
+cd gator-daemon
+make CROSS_COMPILE=<...> # For ARMv7 targets
+make -f Makefile_aarch64 CROSS_COMPILE=<...> # For ARMv8 targets
+```
+gatord should now be created.
+
+For Android targets (install the Android NDK appropriate for your target (ndk32 for 32-bit targets and ndk64 for 64-bit targets), see developer.android.com)
+```
+mv gator-daemon jni
+ndk-build
+```
+or execute `/path/to/ndk/ndk-build` if the ndk is not on your path.
+
+gatord should now be created and located in libs/armeabi.
+
+If you get an error like the following, upgrade to a more recent version of the android ndk
+```
+jni/PerfGroup.cpp: In function 'int sys_perf_event_open(perf_event_attr*, pid_t, int, int, long unsigned int)':
+jni/PerfGroup.cpp:36:17: error: '__NR_perf_event_open' was not declared in this scope
+```
+To build gatord for aarch64 edit `jni/Application.mk` and replace `armeabi-v7a` with `arm64-v8a`. To build for ARM11 `jni/Application.mk` and replace `armeabi-v7a` with `armeabi`.
+
+## Running gator
+
+- Load the kernel onto the target and copy gatord and gator.ko into the target's filesystem.
+- Ensure gatord has execute permissions `chmod +x gatord`
+- gator.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.
+- With root privileges, run the daemon `sudo ./gatord &`
+- If gator.ko is not loaded and is not in the same directory as gatord when using Linux 3.4 or later, gatord can run without gator.ko by using userspace APIs. Not all features are supported by userspace gator. If `/dev/gator/version` does not exist after starting gatord it is running userspace gator.
+
+## Customizing the l2c-310 Counter
+
+The 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:
+`insmod gator.ko l2c310_addr=<offset>`
+Further, the l2c-310 counter can be disabled by providing an offset of zero, ex:
+`insmod gator.ko l2c310_addr=0`
+
+## Perf PMU support
+
+To check the perf PMUs support by your kernel, run
+`ls /sys/bus/event_source/devices/`
+If you see something like `ARMv7_Cortex_A##` this indicates A## support. If you see `CCI_400` this indicates CCI-400 support. If you see `ccn`, it indicates CCN support.
+
+## CCN
+
+CCN requires a perf driver to work. The necessary perf driver has been merged into Linux 3.17 but can be backported to previous versions (see https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/diff/?id=a33b0daab73a0e08cc04459dd44b0121a8e8f81b and later bugfixes)
+
+## Compiling an application or shared library
+
+Recommended compiler settings:
+- `-g`: Debug information, such as line numbers, needed for best analysis results.
+- `-fno-inline`: Speed improvement when processing the image files and most accurate analysis results.
+- `-fno-omit-frame-pointer`: ARM EABI frame pointers allow recording of the call stack with each sample taken when in ARM state (i.e. not `-mthumb`).
+- `-marm`: This option is required for ARMv7 and earlier if your compiler is configured with `--with-mode=thumb`, otherwise call stack unwinding will not work.
+
+For Android ART, passing `--no-strip-symbols` to dex2oat will result in function names but not line numbers to be included in the dex files. This can be done by running `setprop dalvik.vm.dex2oat-flags --no-strip-symbols` on the device and then regenerating the dex files.
+
+## Hardfloat EABI
+
+Binary 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`.
+
+To 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`
+
+The 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.
+
+Attempting to run an incompatible binary often results in the confusing error message `No such file or directory` when clearly the file exists.
+
+## Mali GPU
+
+Streamline supports Mali-400, 450, T6xx, T7xx, and T8xx series GPUs with hardware activity charts, hardware & software counters and an optional Filmstrip showing periodic framebuffer snapshots. Support is chosen at build time and only one type of GPU (and version of driver) is supported at once. For best results build gator in-tree at `.../drivers/gator` and use the menuconfig options. Details of what the menuconfig options mean or how to build out of tree, if you choose, is described below.
+
+Mali-4xx:
+ GATOR_WITH_MALI_SUPPORT=MALI_4xx # Set by CONFIG_GATOR_MALI_4XXMP
+ CONFIG_GATOR_MALI_PATH=".../path/to/Mali_DDK_kernel_files/src/devicedrv/mali" # gator source needs to #include "linux/mali_linux_trace.h"
+ GATOR_MALI_INTERFACE_STYLE=<3|4> # 3=Mali-400 DDK >= r3p0-04rel0 and < r3p2-01rel3
+ # 4=Mali-400 DDK >= r3p2-01rel3
+ # (default of 4 set in gator-driver/gator_events_mali_4xx.c)
+ ___To add the corresponding support to Mali___
+ Userspace needs MALI_TIMELINE_PROFILING_ENABLED=1 MALI_FRAMEBUFFER_DUMP_ENABLED=1 MALI_SW_COUNTERS_ENABLED=1
+ Kernel driver needs USING_PROFILING=1 # Sets CONFIG_MALI400_PROFILING=y
+ See the DDK integration guide for more details (the above are the default in later driver versions)
+
+Mali-T6xx/T7xx/T8xx (Midgard):
+ GATOR_WITH_MALI_SUPPORT=MALI_MIDGARD # Set by CONFIG_GATOR_MALI_MIDGARD
+ DDK_DIR=".../path/to/Mali_DDK_kernel_files" # gator source needs access to headers under .../kernel/drivers/gpu/arm/...
+ # (default of . suitable for in-tree builds)
+ ___To add the corresponding support to Mali___
+ Userspace (scons) needs gator=1
+ Kernel driver needs CONFIG_MALI_GATOR_SUPPORT=y
+ See the DDK integration guide for more details
+
+## Polling /dev, /sys and /proc files
+
+Gator supports reading arbitrary `/dev`, `/sys` and `/proc` files 10 times a second. It will either interpret the file contents as a number or use a POSIX extended regex to extract the number, see `events-Filesystem.xml` for examples.
+
+## Bugs
+
+User space gator is in beta release with known issues. Please note that based on the kernel version and target configuration, the data presented may be incorrect and unexpected behavior can occur including crashing the target kernel. If you experience any of these issues, please use kernel space gator.
+
+There is a bug in some Linux kernels where an Oops may occur when a core is offlined (user space gator only). The fix was merged into mainline in 3.14-rc5, see http://git.kernel.org/tip/e3703f8cdfcf39c25c4338c3ad8e68891cca3731, and has been backported to older kernels (3.4.83, 3.10.33, 3.12.14 and 3.13.6).
+
+`CPU PMU: CPUx reading wrong counter -1` in dmesg (user space gator only). To work around, update to the latest Linux kernel or use kernel space gator.
+
+Scheduler switch resolutions are on exact millisecond boundaries (user space gator only). To work around, update to the latest Linux kernel or use kernel space gator.
+
+There 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.
+```
+# ls /sys/bus/event_source/devices/
+ARMv7_Cortex_A9 breakpoint software tracepoint
+```
+To work around the issue try upgrading to a later kernel or comment out the `gator_events_perf_pmu_cpu_init(gator_cpu, type);` call in `gator_events_perf_pmu.c`
+
+If you see one of these errors when using SELinux, ex: Android 4.4 or later
+`Unable to mount the gator filesystem needed for profiling` or `Unable to load (insmod) gator.ko driver`
+with the following dmesg output,
+```
+<7>[ 6745.475110] SELinux: initialized (dev gatorfs, type gatorfs), not configured for labeling
+<5>[ 6745.477434] type=1400 audit(1393005053.336:10): avc: denied { mount } for pid=1996 comm="gatord-main" name="/" dev="gatorfs" ino=8733 scontext=u:r:shell:s0 tcontext=u:object_r:unlabeled:s0 tclass=filesystem
+```
+disable SELinux so that gatorfs can be mounted by running
+`# setenforce 0`
+Once gator is started, SELinux can be reenabled
+
+On some versions of Android, the Mali Filmstrip may not work and produces a dmesg output similar to
+```
+<4>[ 585.367411] type=1400 audit(1421862808.850:48): avc: denied { search } for pid=3681 comm="mali-renderer" name="/" dev="gatorfs" ino=22378 scontext=u:r:untrusted_app:s0 tcontext=u:object_r:unlabeled:s0 tclass=dir
+```
+To work around this issue, use `streamline_annotate.h` and `streamline_annotate.c` from DS-5 v5.20 or later, or disable SELinux by running
+`# setenforce 0`
+
+On some versions of Android, annotations may not work unless SELinux is disabled by running
+`# setenforce 0`
+
+Some targets do not correctly emit uevents when cores go on/offline. This will cause CPU Activity with user space gator to be either 0% or 100% on a given core and the Heat Map may show a large number of unresolved processes. To work around this issue, use kernel space gator. To test for this run
+`# ./gatord -d | grep uevent`
+When cores go on/offline with user space gator something similar to the following should be emitted
+```
+INFO: read(UEvent.cpp:61): uevent: offline@/devices/system/cpu/cpu1
+INFO: read(UEvent.cpp:61): uevent: online@/devices/system/cpu/cpu1
+```
+The cores that are on/offline can be checked by running
+`# cat /sys/devices/system/cpu/cpu*/online`
+This issue affects a given target if the on/offline cores shown by the cat command change but no cpu uevent is emitted.
+
+On some older versions of Android, the following issue may occur when starting gatord when using ndk-build
+```
+# ./gatord
+[1] + Stopped (signal) ./gatord
+#
+[1] Segmentation fault ./gatord
+#
+```
+Starting with Android-L only position independent executables (pie) are supported, but some older versions of Android do not support them. To avoid this issue, modify Android.mk and remove the references to pie.
+
+## Profiling the kernel (optional)
+
+CONFIG_DEBUG_INFO must be enabled, see "Kernel configuration" section above.
+
+Use vmlinux as the image for debug symbols in Streamline.
+
+Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the driver as an image to Streamline.
+
+To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko or run `echo 1 > /sys/module/gator/parameters/kernel_stack_unwinding` as root on the target after gatord is started.
+
+## Automatically start gator on boot (optional)
+
+```
+cd /etc/init.d
+cat << EOF > rungator.sh
+#!/bin/bash
+/path/to/gatord &
+EOF
+update-rc.d rungator.sh defaults
+```
+
+## GPL License
+
+For license information, please see the file COPYING after unzipping `driver-src/gator-driver.tar.gz`.
+
+The prebuilt gatord uses musl from http://www.musl-libc.org/download.html for musl license information see the COPYRIGHT file in the musl tar file.
diff --git a/README_Streamline.txt b/README_Streamline.txt
deleted file mode 100644
index 4ab6800..0000000
--- a/README_Streamline.txt
+++ /dev/null
@@ -1,250 +0,0 @@
-
-*** Purpose ***
-
-Instructions on setting up ARM Streamline on the target.
-A target agent (gator) is required to run on the ARM Linux target in order for ARM Streamline to operate. Gator may run in kernel space or user space mode, though user space gator requires Linux 3.4 or later and contains reduced functionality. Furthermore, user space gator is a beta release, see the bugs section in this readme for a list of known issues.
-The driver should be built as a module and the daemon must run with root permissions on the target.
-
-*** Introduction ***
-
-A Linux development environment with cross compiling tools is most likely required, depending on what is already created and provided.
--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.
--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.
--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.
- -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.
- -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.
- -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.
- -If the target is running Linux 3.4 or later the kernel driver is not required and userspace APIs will be used instead.
-
-*** Kernel configuration ***
-
-menuconfig options (depending on the kernel version, the location of these configuration settings within menuconfig may differ)
-- General Setup
- - Kernel Performance Events And Counters
- - [*] Kernel performance events and counters (enables CONFIG_PERF_EVENTS)
- - [*] Profiling Support (enables CONFIG_PROFILING)
-- [*] Enable loadable module support (enables CONFIG_MODULES, needed unless the gator driver is built into the kernel)
- - [*] Module unloading (enables MODULE_UNLOAD)
-- Kernel Features
- - [*] High Resolution Timer Support (enables CONFIG_HIGH_RES_TIMERS)
- - [*] Use local timer interrupts (only required for SMP and for version before Linux 3.12, enables CONFIG_LOCAL_TIMERS)
- - [*] Enable hardware performance counter support for perf events (enables CONFIG_HW_PERF_EVENTS)
-- CPU Power Management
- - CPU Frequency scaling
- - [*] CPU Frequency scaling (enables CONFIG_CPU_FREQ)
-- Device Drivers
- - Graphics support
- - ARM GPU Configuration
- - Mali Midgard series support
- - [*] Streamline Debug support (enables CONFIG_MALI_GATOR_SUPPORT needed as part of Mali Midgard support)
-- Kernel hacking
- - [*] Compile the kernel with debug info (optional, enables CONFIG_DEBUG_INFO)
- - [*] Tracers
- - [*] Trace process context switches and events (#)
-
-(#) The "Trace process context switches and events" is not the only option that enables tracing (CONFIG_GENERIC_TRACER or CONFIG_TRACING as well as CONFIG_CONTEXT_SWITCH_TRACER) 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.
-
-The configuration options:
-CONFIG_MODULES and MODULE_UNLOAD (not needed if the gator driver is built into the kernel)
-CONFIG_GENERIC_TRACER or CONFIG_TRACING
-CONFIG_CONTEXT_SWITCH_TRACER
-CONFIG_PROFILING
-CONFIG_HIGH_RES_TIMERS
-CONFIG_LOCAL_TIMERS (for SMP systems and kernel versions before 3.12)
-CONFIG_PERF_EVENTS and CONFIG_HW_PERF_EVENTS (kernel versions 3.0 and greater)
-CONFIG_DEBUG_INFO (optional, used for analyzing the kernel)
-CONFIG_CPU_FREQ (optional, provides frequency setting of the CPU)
-CONFIG_MALI_GATOR_SUPPORT (needed as part of Mali Midgard support)
-
-These 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
- > zcat /proc/config.gz | grep CONFIG_PROFILING
- CONFIG_PROFILING=y
-
-If a device tree is used it must include the pmu bindings, see Documentation/devicetree/bindings/arm/pmu.txt for details.
-
-*** Checking the gator requirements ***
-
-(optional) Use the hrtimer_module utility to validate the kernel High Resolution Timer requirement.
-
-*** Building the gator module ***
-
-To create the gator.ko module,
- tar xzf /path/to/DS-5/arm/gator/driver-src/gator-driver.tar.gz
- cd gator-driver
- make -C <kernel_build_dir> M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules
-whenever possible, use the same toolchain the kernel was built with when building gator.ko
-for example when using the linaro-toolchain-binaries
- 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
-If successful, a gator.ko module should be generated
-
-It is also possible to integrate the gator.ko module into the kernel build system
- cd /path/to/kernel/build/dir
- cd drivers
- mkdir gator
- cp -r /path/to/gator/driver-src/* gator
-Edit Makefile in the kernel drivers folder and add this to the end
- obj-$(CONFIG_GATOR) += gator/
-Edit Kconfig in the kernel drivers folder and add this before the last endmenu
- source "drivers/gator/Kconfig"
-You can now select gator when using menuconfig while configuring the kernel and rebuild as directed
-
-*** Use the prebuilt gator daemon ***
-
-A prebuilt gator daemon is provided at /path/to/DS-5/arm/gator/gatord. This gator daemon should work in most cases so building the gator daemon is only required if the prebuilt gator daemon doesn't work.
-To improve portablility gatord is statically compiled against musl libc from http://www.musl-libc.org/releases/musl-1.0.2.tar.gz instead of glibc. The gator daemon will work correctly with either glibc or musl.
-
-*** Building the gator daemon ***
-
-tar -xzf /path/to/DS-5/arm/gator/daemon-src/gator-daemon.tar.gz
-For Linux targets,
- cd gator-daemon
- make CROSS_COMPILE=<...> # For ARMv7 targets
- make -f Makefile_aarch64 CROSS_COMPILE=<...> # For ARMv8 targets
- gatord should now be created
-For Android targets (install the Android NDK appropriate for your target (ndk32 for 32-bit targets and ndk64 for 64-bit targets), see developer.android.com)
- mv gator-daemon jni
- ndk-build
- or execute /path/to/ndk/ndk-build if the ndk is not on your path
- gatord should now be created and located in libs/armeabi
- If you get an error like the following, upgrade to a more recent version of the android ndk
- jni/PerfGroup.cpp: In function 'int sys_perf_event_open(perf_event_attr*, pid_t, int, int, long unsigned int)':
- jni/PerfGroup.cpp:36:17: error: '__NR_perf_event_open' was not declared in this scope
- To build gatord for aarch64 edit jni/Application.mk and replace armeabi-v7a with arm64-v8a. To build for ARM11 jni/Application.mk and replace armeabi-v7a with armeabi.
-
-*** Running gator ***
-
-Load the kernel onto the target and copy gatord and gator.ko into the target's filesystem.
-Ensure gatord has execute permissions
- chmod +x gatord
-gator.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.
-With root privileges, run the daemon
- sudo ./gatord &
-Note: 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.
-If gator.ko is not loaded and is not in the same directory as gatord when using Linux 3.4 or later, gatord can run without gator.ko by using userspace APIs. Not all features are supported by userspace gator. If /dev/gator/version does not exist after starting gatord it is running userspace gator.
-
-*** Customizing the l2c-310 Counter ***
-
-The 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:
- insmod gator.ko l2c310_addr=<offset>
-Further, the l2c-310 counter can be disabled by providing an offset of zero, ex:
- insmod gator.ko l2c310_addr=0
-
-*** Perf PMU support ***
-
-To check the perf PMUs support by your kernel, run
- ls /sys/bus/event_source/devices/
-If you see something like ARMv7_Cortex_A## this indicates A## support. If you see CCI_400 this indicates CCI-400 support. If you see ccn, it indicates CCN support.
-
-*** CCN ***
-
-CCN requires a perf driver to work. The necessary perf driver has been merged into Linux 3.17 but can be backported to previous versions (see https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/diff/?id=a33b0daab73a0e08cc04459dd44b0121a8e8f81b and later bugfixes)
-
-*** Compiling an application or shared library ***
-
-Recommended compiler settings:
- "-g": Debug information, such as line numbers, needed for best analysis results.
- "-fno-inline": Speed improvement when processing the image files and most accurate analysis results.
- "-fno-omit-frame-pointer": ARM EABI frame pointers allow recording of the call stack with each sample taken when in ARM state (i.e. not -mthumb).
- "-marm": This option is required for ARMv7 and earlier if your compiler is configured with --with-mode=thumb, otherwise call stack unwinding will not work.
-
-*** Hardfloat EABI ***
-Binary 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.
-To 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'
-The 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.
-Attempting to run an incompatible binary often results in the confusing error message "No such file or directory" when clearly the file exists.
-
-*** Mali GPU ***
-
-Streamline supports Mali-400, 450, T6xx, T7xx, and T8xx series GPUs with hardware activity charts, hardware & software counters and an optional Filmstrip showing periodic framebuffer snapshots. Support is chosen at build time and only one type of GPU (and version of driver) is supported at once. For best results build gator in-tree at .../drivers/gator and use the menuconfig options. Details of what these mean or how to build out of tree below.
-
-Mali-4xx:
- GATOR_WITH_MALI_SUPPORT=MALI_4xx # Set by CONFIG_GATOR_MALI_4XXMP
- CONFIG_GATOR_MALI_PATH=".../path/to/Mali_DDK_kernel_files/src/devicedrv/mali" # gator source needs to #include "linux/mali_linux_trace.h"
- GATOR_MALI_INTERFACE_STYLE=<3|4> # 3=Mali-400 DDK >= r3p0-04rel0 and < r3p2-01rel3
- # 4=Mali-400 DDK >= r3p2-01rel3
- # (default of 4 set in gator-driver/gator_events_mali_4xx.c)
- ___To add the corresponding support to Mali___
- Userspace needs MALI_TIMELINE_PROFILING_ENABLED=1 MALI_FRAMEBUFFER_DUMP_ENABLED=1 MALI_SW_COUNTERS_ENABLED=1
- Kernel driver needs USING_PROFILING=1 # Sets CONFIG_MALI400_PROFILING=y
- See the DDK integration guide for more details (the above are the default in later driver versions)
-
-Mali-T6xx/T7xx/T8xx (Midgard):
- GATOR_WITH_MALI_SUPPORT=MALI_MIDGARD # Set by CONFIG_GATOR_MALI_MIDGARD
- DDK_DIR=".../path/to/Mali_DDK_kernel_files" # gator source needs access to headers under .../kernel/drivers/gpu/arm/...
- # (default of . suitable for in-tree builds)
- ___To add the corresponding support to Mali___
- Userspace (scons) needs gator=1
- Kernel driver needs CONFIG_MALI_GATOR_SUPPORT=y
- See the DDK integration guide for more details
-
-*** Polling /dev, /sys and /proc files ***
-Gator supports reading arbitrary /dev, /sys and /proc files 10 times a second. It will either interpret the file contents as a number or use a POSIX extended regex to extract the number, see events-Filesystem.xml for examples.
-
-*** Bugs ***
-
-User space gator is in beta release with known issues. Please note that based on the kernel version and target configuration, the data presented may be incorrect and unexpected behavior can occur including crashing the target kernel. If you experience any of these issues, please use kernel space gator.
-
-There is a bug in some Linux kernels where an Oops may occur when a core is offlined (user space gator only). The fix was merged into mainline in 3.14-rc5, see http://git.kernel.org/tip/e3703f8cdfcf39c25c4338c3ad8e68891cca3731, and has been backported to older kernels (3.4.83, 3.10.33, 3.12.14 and 3.13.6).
-
-"CPU PMU: CPUx reading wrong counter -1" in dmesg (user space gator only). To work around, update to the latest Linux kernel or use kernel space gator.
-
-Scheduler switch resolutions are on exact millisecond boundaries (user space gator only). To work around, update to the latest Linux kernel or use kernel space gator.
-
-There 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.
- # ls /sys/bus/event_source/devices/
- ARMv7_Cortex_A9 breakpoint software tracepoint
-To work around the issue try upgrading to a later kernel or comment out the gator_events_perf_pmu_cpu_init(gator_cpu, type); call in gator_events_perf_pmu.c
-
-If you see one of these errors when using SELinux, ex: Android 4.4 or later
- "Unable to mount the gator filesystem needed for profiling" or "Unable to load (insmod) gator.ko driver"
-with the following dmesg output,
- <7>[ 6745.475110] SELinux: initialized (dev gatorfs, type gatorfs), not configured for labeling
- <5>[ 6745.477434] type=1400 audit(1393005053.336:10): avc: denied { mount } for pid=1996 comm="gatord-main" name="/" dev="gatorfs" ino=8733 scontext=u:r:shell:s0 tcontext=u:object_r:unlabeled:s0 tclass=filesystem
-disable SELinux so that gatorfs can be mounted by running
- # setenforce 0
-Once gator is started, SELinux can be reenabled
-
-On some versions of Android, the Mali Filmstrip may not work and produces a dmesg output similar to
- <4>[ 585.367411] type=1400 audit(1421862808.850:48): avc: denied { search } for pid=3681 comm="mali-renderer" name="/" dev="gatorfs" ino=22378 scontext=u:r:untrusted_app:s0 tcontext=u:object_r:unlabeled:s0 tclass=dir
-To work around this issue, use streamline_annotate.h and streamline_annotate.c from DS-5 v5.20 or later, or disable SELinux by running
- # setenforce 0
-
-On some versions of Android, annotations may not work unless SELinux is disabled by running
- # setenforce 0
-
-Some targets do not correctly emit uevents when cores go on/offline. This will cause CPU Activity with user space gator to be either 0% or 100% on a given core and the Heat Map may show a large number of unresolved processes. To work around this issue, user kernel space gator. To test for this run
- # ./gatord -d | grep uevent
-When cores go on/offline with user space gator something similar to the following should be emitted
- INFO: read(UEvent.cpp:61): uevent: offline@/devices/system/cpu/cpu1
- INFO: read(UEvent.cpp:61): uevent: online@/devices/system/cpu/cpu1
-The core which are on/offline can be checked by running
- # cat /sys/devices/system/cpu/cpu*/online
-This issues affects a given target if the on/offline cores shown by the cat command change but no cpu uevent is emitted.
-
-On some older versions of Android, the following issue may occur when starting gatord when using ndk-build
- # ./gatord
- [1] + Stopped (signal) ./gatord
- #
- [1] Segmentation fault ./gatord
- #
-Starting with Android-L only position independent executables (pie) are supported, but some older versions of Android do not support them. To avoid this issue, modify Android.mk and remove the references to pie.
-
-*** Profiling the kernel (optional) ***
-
-CONFIG_DEBUG_INFO must be enabled, see "Kernel configuration" section above.
-Use vmlinux as the image for debug symbols in Streamline.
-Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the driver as an image to Streamline.
-To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko or run "echo 1 > /sys/module/gator/parameters/kernel_stack_unwinding" as root on the target after gatord is started.
-
-*** Automatically start gator on boot (optional) ***
-
-cd /etc/init.d
-vi rungator.sh
- #!/bin/bash
- /path/to/gatord &
-update-rc.d rungator.sh defaults
-
-*** GPL License ***
-
-For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz.
-The prebuilt gatord uses musl from http://www.musl-libc.org/releases/musl-1.0.2.tar.gz for musl license information see the COPYRIGHT file in the musl tar file.
diff --git a/daemon/Android.mk b/daemon/Android.mk
index 68f4a83..ae49e68 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -5,6 +5,7 @@ XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h SrcMd5.cpp
LOCAL_SRC_FILES := \
AnnotateListener.cpp \
+ AtraceDriver.cpp \
Buffer.cpp \
CCNDriver.cpp \
CapturedXML.cpp \
@@ -16,11 +17,11 @@ LOCAL_SRC_FILES := \
DriverSource.cpp \
DynBuf.cpp \
EventsXML.cpp \
+ ExternalDriver.cpp \
ExternalSource.cpp \
FSDriver.cpp \
Fifo.cpp \
FtraceDriver.cpp \
- FtraceSource.cpp \
HwmonDriver.cpp \
KMod.cpp \
LocalCapture.cpp \
diff --git a/daemon/AtraceDriver.cpp b/daemon/AtraceDriver.cpp
new file mode 100644
index 0000000..78fe58a
--- /dev/null
+++ b/daemon/AtraceDriver.cpp
@@ -0,0 +1,136 @@
+/**
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "AtraceDriver.h"
+
+#include <unistd.h>
+
+/*
+#include <regex.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "DriverSource.h"
+#include "Setup.h"
+*/
+
+#include "Logging.h"
+#include "OlyUtility.h"
+#include "SessionData.h"
+
+class AtraceCounter : public DriverCounter {
+public:
+ AtraceCounter(DriverCounter *next, char *name, int flag);
+ ~AtraceCounter();
+
+ int getFlag() const { return mFlag; }
+
+private:
+ const int mFlag;
+
+ // Intentionally unimplemented
+ AtraceCounter(const AtraceCounter &);
+ AtraceCounter &operator=(const AtraceCounter &);
+};
+
+AtraceCounter::AtraceCounter(DriverCounter *next, char *name, int flag) : DriverCounter(next, name), mFlag(flag) {
+}
+
+AtraceCounter::~AtraceCounter() {
+}
+
+AtraceDriver::AtraceDriver() : mSupported(false), mNotifyPath() {
+}
+
+AtraceDriver::~AtraceDriver() {
+}
+
+void AtraceDriver::readEvents(mxml_node_t *const xml) {
+ if (!gSessionData->mFtraceDriver.isSupported()) {
+ logg->logMessage("Atrace support disabled, ftrace support is required");
+ return;
+ }
+ if (access("/system/bin/setprop", X_OK) != 0) {
+ logg->logMessage("Atrace support disabled, setprop is not found, this is not an Android target");
+ return;
+ }
+
+ if (util->getApplicationFullPath(mNotifyPath, sizeof(mNotifyPath)) != 0) {
+ logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
+ }
+ strncat(mNotifyPath, "notify.dex", sizeof(mNotifyPath) - strlen(mNotifyPath) - 1);
+ if (access(mNotifyPath, W_OK) != 0) {
+ logg->logMessage("Atrace support disabled, unable to locate notify.dex");
+ return;
+ }
+
+ mSupported = true;
+
+ mxml_node_t *node = xml;
+ while (true) {
+ node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
+ if (node == NULL) {
+ break;
+ }
+ const char *counter = mxmlElementGetAttr(node, "counter");
+ if (counter == NULL) {
+ continue;
+ }
+
+ if (strncmp(counter, "atrace_", 7) != 0) {
+ continue;
+ }
+
+ const char *flag = mxmlElementGetAttr(node, "flag");
+ if (flag == NULL) {
+ logg->logError("The atrace counter %s is missing the required flag attribute", counter);
+ handleException();
+ }
+ setCounters(new AtraceCounter(getCounters(), strdup(counter), strtol(flag, NULL, 16)));
+ }
+}
+
+void AtraceDriver::setAtrace(const int flags) {
+ logg->logMessage("Setting atrace flags to %i\n", flags);
+ pid_t pid = fork();
+ if (pid < 0) {
+ logg->logError("fork failed");
+ handleException();
+ } else if (pid == 0) {
+ char buf[1<<10];
+ snprintf(buf, sizeof(buf), "setprop debug.atrace.tags.enableflags %i; "
+ "dalvikvm -cp %s com.android.internal.util.WithFramework Notify", flags, mNotifyPath);
+ execlp("sh", "sh", "-c", buf, NULL);
+ exit(0);
+ }
+}
+
+void AtraceDriver::start() {
+ if (!mSupported) {
+ return;
+ }
+
+ int flags = 0;
+ for (AtraceCounter *counter = static_cast<AtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<AtraceCounter *>(counter->getNext())) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ flags |= counter->getFlag();
+ }
+
+ setAtrace(flags);
+}
+
+void AtraceDriver::stop() {
+ if (!mSupported) {
+ return;
+ }
+
+ setAtrace(0);
+}
diff --git a/daemon/AtraceDriver.h b/daemon/AtraceDriver.h
new file mode 100644
index 0000000..0a06858
--- /dev/null
+++ b/daemon/AtraceDriver.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) ARM Limited 2015. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ATRACEDRIVER_H
+#define ATRACEDRIVER_H
+
+#include "mxml/mxml.h"
+
+#include "Driver.h"
+
+class AtraceDriver : public SimpleDriver {
+public:
+ AtraceDriver();
+ ~AtraceDriver();
+
+ void readEvents(mxml_node_t *const xml);
+
+ void start();
+ void stop();
+
+ bool isSupported() const { return mSupported; }
+
+private:
+ void setAtrace(const int flags);
+
+ bool mSupported;
+ char mNotifyPath[256];
+
+ // Intentionally unimplemented
+ AtraceDriver(const AtraceDriver &);
+ AtraceDriver &operator=(const AtraceDriver &);
+};
+
+#endif // ATRACEDRIVER_H
diff --git a/daemon/Buffer.cpp b/daemon/Buffer.cpp
index c4ced9f..26deb2e 100644
--- a/daemon/Buffer.cpp
+++ b/daemon/Buffer.cpp
@@ -143,6 +143,16 @@ int Buffer::contiguousSpaceAvailable() const {
}
}
+bool Buffer::hasUncommittedMessages() const {
+ const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
+ int length = mWritePos - mCommitPos;
+ if (length < 0) {
+ length += mSize;
+ }
+ length = length - typeLength - sizeof(int32_t);
+ return length > FRAME_HEADER_SIZE;
+}
+
void Buffer::commit(const uint64_t time, const bool force) {
// post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
@@ -263,7 +273,7 @@ void Buffer::frame() {
}
}
-void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
+void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname, const long pageSize) {
packInt(MESSAGE_SUMMARY);
writeString(NEWLINE_CANARY);
packInt64(timestamp);
@@ -271,6 +281,10 @@ void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int
packInt64(monotonicDelta);
writeString("uname");
writeString(uname);
+ writeString("PAGESIZE");
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%li", pageSize);
+ writeString(buf);
writeString("");
check(currTime);
}
diff --git a/daemon/Buffer.h b/daemon/Buffer.h
index 13c44e1..ea250a9 100644
--- a/daemon/Buffer.h
+++ b/daemon/Buffer.h
@@ -36,11 +36,12 @@ public:
int bytesAvailable() const;
int contiguousSpaceAvailable() const;
+ bool hasUncommittedMessages() const;
void commit(const uint64_t time, const bool force = false);
void check(const uint64_t time);
// Summary messages
- void summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname);
+ void summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname, const long pageSize);
void coreName(const uint64_t currTime, const int core, const int cpuid, const char *const name);
// Block Counter messages
diff --git a/daemon/CCNDriver.cpp b/daemon/CCNDriver.cpp
index d77513a..24eda03 100644
--- a/daemon/CCNDriver.cpp
+++ b/daemon/CCNDriver.cpp
@@ -19,6 +19,7 @@
#include "Config.h"
#include "DriverSource.h"
#include "Logging.h"
+#include "SessionData.h"
static const char TAG_CATEGORY[] = "category";
static const char TAG_COUNTER_SET[] = "counter_set";
@@ -44,6 +45,8 @@ static const char RNI_REGION[] = "RN-I_Region";
static const char SBAS_REGION[] = "SBAS_Region";
static const char CCN_5XX[] = "CCN-5xx";
#define ARM_CCN_5XX "ARM_CCN_5XX_"
+#define CCN_COUNT 8
+static const char ARM_CCN_5XX_CNT[] = ARM_CCN_5XX "cnt";
static const char *const VC_TYPES[] = { "REQ", "RSP", "SNP", "DAT" };
static const char *const XP_EVENT_NAMES[] = { NULL, "H-bit", "S-bit", "P-Cnt", "TknV" };
@@ -173,12 +176,12 @@ int CCNDriver::writeCounters(mxml_node_t *const) const {
void CCNDriver::writeEvents(mxml_node_t *const root) const {
mxml_node_t *const counter_set = mxmlNewElement(root, TAG_COUNTER_SET);
- mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX "cnt");
- mxmlElementSetAttr(counter_set, ATTR_COUNT, "8");
+ mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX_CNT);
+ mxmlElementSetAttr(counter_set, ATTR_COUNT, STRIFY(CCN_COUNT));
mxml_node_t *const category = mxmlNewElement(root, TAG_CATEGORY);
mxmlElementSetAttr(category, ATTR_NAME, CCN_5XX);
- mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX "cnt");
+ mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX_CNT);
mxml_node_t *const clock_event = mxmlNewElement(category, TAG_EVENT);
mxmlElementSetAttr(clock_event, ATTR_COUNTER, ARM_CCN_5XX "ccnt");
@@ -292,3 +295,35 @@ void CCNDriver::writeEvents(mxml_node_t *const root) const {
}
}
}
+
+void CCNDriver::validateCounters() const {
+ int counts[CCN_COUNT][2] = { { 0 } };
+ const unsigned int mask = getConfig(0xff, 0xff, 0, 0, 0);
+
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->mCounters); ++i) {
+ const Counter *const counter = &gSessionData->mCounters[i];
+
+ if (!counter->isEnabled()) {
+ continue;
+ }
+
+ if (strncmp(counter->getType(), ARM_CCN_5XX_CNT, sizeof(ARM_CCN_5XX_CNT) - 1) == 0) {
+ const int node = counter->getEvent() & mask;
+
+ for (int j = 0; j < ARRAY_LENGTH(counts); ++j) {
+ if (counts[j][0] == 0) {
+ counts[j][0] = node;
+ }
+ if (counts[j][0] == node) {
+ ++counts[j][1];
+ if (counts[j][1] > 4) {
+ if (asprintf(&gSessionData->mCountersError, "More than 4 events are assigned to the same CCN node") <= 0) {
+ logg->logError("asprintf failed");
+ handleException();
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/daemon/CCNDriver.h b/daemon/CCNDriver.h
index 06ac33f..8a155a7 100644
--- a/daemon/CCNDriver.h
+++ b/daemon/CCNDriver.h
@@ -24,6 +24,8 @@ public:
int writeCounters(mxml_node_t *const root) const;
void writeEvents(mxml_node_t *const) const;
+ void validateCounters() const;
+
private:
enum NodeType {
NT_UNKNOWN,
diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp
index 1854c77..e87c909 100644
--- a/daemon/CapturedXML.cpp
+++ b/daemon/CapturedXML.cpp
@@ -32,7 +32,7 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
captured = mxmlNewElement(xml, "captured");
mxmlElementSetAttr(captured, "version", "1");
- if (gSessionData->perf.isSetup()) {
+ if (gSessionData->mPerf.isSetup()) {
mxmlElementSetAttr(captured, "type", "Perf");
}
mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION);
diff --git a/daemon/Child.cpp b/daemon/Child.cpp
index a19e9cf..551ec6b 100644
--- a/daemon/Child.cpp
+++ b/daemon/Child.cpp
@@ -20,7 +20,6 @@
#include "Driver.h"
#include "DriverSource.h"
#include "ExternalSource.h"
-#include "FtraceSource.h"
#include "LocalCapture.h"
#include "Logging.h"
#include "OlySocket.h"
@@ -35,7 +34,6 @@ static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shar
static Source *primarySource = NULL;
static Source *externalSource = NULL;
static Source *userSpaceSource = NULL;
-static Source *ftraceSource = NULL;
static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
Child* child = NULL; // shared by Child.cpp and main.cpp
@@ -44,7 +42,8 @@ void handleException() {
if (child && child->numExceptions++ > 0) {
// it is possible one of the below functions itself can cause an exception, thus allow only one exception
logg->logMessage("Received multiple exceptions, terminating the child");
- exit(1);
+ // Something is really wrong, exit immediately
+ _exit(1);
}
fprintf(stderr, "%s", logg->getLastError());
@@ -67,8 +66,9 @@ void handleException() {
}
}
- if (gSessionData->mLocalCapture)
+ if (gSessionData->mLocalCapture) {
cleanUp();
+ }
exit(1);
}
@@ -152,7 +152,6 @@ static void *senderThread(void *) {
while (!externalSource->isDone() ||
(userSpaceSource != NULL && !userSpaceSource->isDone()) ||
- (ftraceSource != NULL && !ftraceSource->isDone()) ||
!primarySource->isDone()) {
sem_wait(&senderSem);
@@ -160,9 +159,6 @@ static void *senderThread(void *) {
if (userSpaceSource != NULL) {
userSpaceSource->write(sender);
}
- if (ftraceSource != NULL) {
- ftraceSource->write(sender);
- }
primarySource->write(sender);
}
@@ -213,9 +209,6 @@ void Child::endSession() {
if (userSpaceSource != NULL) {
userSpaceSource->interrupt();
}
- if (ftraceSource != NULL) {
- ftraceSource->interrupt();
- }
sem_post(&haltPipeline);
}
@@ -240,7 +233,7 @@ void Child::run() {
{ ConfigurationXML configuration; }
// Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
- if (!gSessionData->perf.isSetup()) {
+ if (!gSessionData->mPerf.isSetup()) {
primarySource = new DriverSource(&senderSem, &startProfile);
} else {
primarySource = new PerfSource(&senderSem, &startProfile);
@@ -279,25 +272,24 @@ void Child::run() {
free(xmlString);
}
- if (gSessionData->kmod.isMaliCapture() && (gSessionData->mSampleRate == 0)) {
+ if (gSessionData->mKmod.isMaliCapture() && (gSessionData->mSampleRate == 0)) {
logg->logError("Mali counters are not supported with Sample Rate: None.");
handleException();
}
// Initialize ftrace source before child as it's slow and dependens on nothing else
// If initialized later, us gator with ftrace has time sync issues
- if (gSessionData->ftraceDriver.countersEnabled()) {
- ftraceSource = new FtraceSource(&senderSem);
- if (!ftraceSource->prepare()) {
- logg->logError("Unable to prepare userspace source for capture");
- handleException();
- }
- ftraceSource->start();
+ // Must be initialized before senderThread is started as senderThread checks externalSource
+ externalSource = new ExternalSource(&senderSem);
+ if (!externalSource->prepare()) {
+ logg->logError("Unable to prepare external source for capture");
+ handleException();
}
+ externalSource->start();
// Must be after session XML is parsed
if (!primarySource->prepare()) {
- if (gSessionData->perf.isSetup()) {
+ if (gSessionData->mPerf.isSetup()) {
logg->logError("Unable to communicate with the perf API, please ensure that CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER are enabled. Please refer to README_Streamline.txt for more information.");
} else {
logg->logError("Unable to prepare gator driver for capture");
@@ -308,14 +300,6 @@ void Child::run() {
// Sender thread shall be halted until it is signaled for one shot mode
sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
- // Must be initialized before senderThread is started as senderThread checks externalSource
- externalSource = new ExternalSource(&senderSem);
- if (!externalSource->prepare()) {
- logg->logError("Unable to prepare external source for capture");
- handleException();
- }
- externalSource->start();
-
// Create the duration, stop, and sender threads
bool thread_creation_success = true;
if (gSessionData->mDuration > 0 && pthread_create(&durationThreadID, NULL, durationThread, NULL)) {
@@ -327,8 +311,8 @@ void Child::run() {
}
bool startUSSource = false;
- for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
- if (gSessionData->usDrivers[i]->countersEnabled()) {
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->mUsDrivers); ++i) {
+ if (gSessionData->mUsDrivers[i]->countersEnabled()) {
startUSSource = true;
}
}
@@ -360,9 +344,6 @@ void Child::run() {
primarySource->run();
// Wait for the other threads to exit
- if (ftraceSource != NULL) {
- ftraceSource->join();
- }
if (userSpaceSource != NULL) {
userSpaceSource->join();
}
@@ -384,7 +365,6 @@ void Child::run() {
logg->logMessage("Profiling ended.");
- delete ftraceSource;
delete userSpaceSource;
delete externalSource;
delete primarySource;
diff --git a/daemon/Command.cpp b/daemon/Command.cpp
index 0a6e3b9..22f8be7 100644
--- a/daemon/Command.cpp
+++ b/daemon/Command.cpp
@@ -9,6 +9,7 @@
#include "Command.h"
#include <fcntl.h>
+#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <sys/prctl.h>
@@ -23,14 +24,14 @@
#include "Logging.h"
#include "SessionData.h"
-static int getUid(const char *const name, char *const shPath, const char *const tmpDir) {
+static int getUid(const char *const name, const char *const tmpDir, uid_t *const uid) {
// Lookups may fail when using a different libc or a statically compiled executable
char gatorTemp[32];
snprintf(gatorTemp, sizeof(gatorTemp), "%s/gator_temp", tmpDir);
const int fd = open(gatorTemp, 600, O_CREAT | O_CLOEXEC);
if (fd < 0) {
- return -1;
+ return false;
}
close(fd);
@@ -43,15 +44,7 @@ static int getUid(const char *const name, char *const shPath, const char *const
handleException();
}
if (pid == 0) {
- char cargv1[] = "-c";
- char *cargv[] = {
- shPath,
- cargv1,
- cmd,
- NULL,
- };
-
- execv(cargv[0], cargv);
+ execlp("sh", "sh", "-c", cmd, NULL);
exit(-1);
}
while ((waitpid(pid, NULL, 0) < 0) && (errno == EINTR));
@@ -62,38 +55,42 @@ static int getUid(const char *const name, char *const shPath, const char *const
result = st.st_uid;
}
unlink(gatorTemp);
- return result;
+ *uid = result;
+ return true;
}
-static int getUid(const char *const name) {
+static bool getUid(const char *const name, uid_t *const uid, gid_t *const gid) {
// Look up the username
struct passwd *const user = getpwnam(name);
if (user != NULL) {
- return user->pw_uid;
+ *uid = user->pw_uid;
+ *gid = user->pw_gid;
+ return true;
}
+ // Unable to get the user without getpwanm, so create a unique uid by adding a fixed number to the pid
+ *gid = 0x484560f8 + getpid();
// Are we on Linux
- char cargv0l[] = "/bin/sh";
- if ((access(cargv0l, X_OK) == 0) && (access("/tmp", W_OK) == 0)) {
- return getUid(name, cargv0l, "/tmp");
+ if (access("/tmp", W_OK) == 0) {
+ return getUid(name, "/tmp", uid);
}
// Are we on android
- char cargv0a[] = "/system/bin/sh";
- if ((access(cargv0a, X_OK) == 0) && (access("/data", W_OK) == 0)) {
- return getUid(name, cargv0a, "/data");
+ if (access("/data", W_OK) == 0) {
+ return getUid(name, "/data", uid);
}
- return -1;
+ return false;
}
void *commandThread(void *) {
prctl(PR_SET_NAME, (unsigned long)&"gatord-command", 0, 0, 0);
const char *const name = gSessionData->mCaptureUser == NULL ? "nobody" : gSessionData->mCaptureUser;
- const int uid = getUid(name);
- if (uid < 0) {
+ uid_t uid;
+ gid_t gid;
+ if (!getUid(name, &uid, &gid)) {
logg->logError("Unable to look up the user %s, please double check that the user exists", name);
handleException();
}
@@ -113,16 +110,6 @@ void *commandThread(void *) {
handleException();
}
if (pid == 0) {
- char cargv0l[] = "/bin/sh";
- char cargv0a[] = "/system/bin/sh";
- char cargv1[] = "-c";
- char *cargv[] = {
- cargv0l,
- cargv1,
- gSessionData->mCaptureCommand,
- NULL,
- };
-
buf[0] = '\0';
close(pipefd[0]);
@@ -132,8 +119,16 @@ void *commandThread(void *) {
goto fail_exit;
}
- if (setuid(uid) != 0) {
- snprintf(buf, sizeof(buf), "setuid failed");
+ if (setgroups(1, &gid) != 0) {
+ snprintf(buf, sizeof(buf), "setgroups failed");
+ goto fail_exit;
+ }
+ if (setresgid(gid, gid, gid) != 0) {
+ snprintf(buf, sizeof(buf), "setresgid failed");
+ goto fail_exit;
+ }
+ if (setresuid(uid, uid, uid) != 0) {
+ snprintf(buf, sizeof(buf), "setresuid failed");
goto fail_exit;
}
@@ -145,9 +140,7 @@ void *commandThread(void *) {
}
}
- execv(cargv[0], cargv);
- cargv[0] = cargv0a;
- execv(cargv[0], cargv);
+ execlp("sh", "sh", "-c", gSessionData->mCaptureCommand, NULL);
snprintf(buf, sizeof(buf), "execv failed");
fail_exit:
diff --git a/daemon/Config.h b/daemon/Config.h
index eb31556..3c6752e 100644
--- a/daemon/Config.h
+++ b/daemon/Config.h
@@ -9,12 +9,19 @@
#ifndef CONFIG_H
#define CONFIG_H
+#define STRIFY2(ARG) #ARG
+#define STRIFY(ARG) STRIFY2(ARG)
+
#define ARRAY_LENGTH(A) static_cast<int>(sizeof(A)/sizeof((A)[0]))
#define ACCESS_ONCE(x) (*(volatile typeof(x)*)&(x))
#define MAX_PERFORMANCE_COUNTERS 50
#define NR_CPUS 32
+// If debugfs is not mounted at /sys/kernel/debug, update TRACING_PATH
+#define TRACING_PATH "/sys/kernel/debug/tracing"
+#define EVENTS_PATH TRACING_PATH "/events"
+
template<typename T>
static inline T min(const T a, const T b) {
return (a < b ? a : b);
diff --git a/daemon/ConfigurationXML.cpp b/daemon/ConfigurationXML.cpp
index be224a4..b433811 100644
--- a/daemon/ConfigurationXML.cpp
+++ b/daemon/ConfigurationXML.cpp
@@ -68,8 +68,10 @@ int ConfigurationXML::parse(const char* configurationXML) {
mxml_node_t *tree, *node;
int ret;
- // clear counter overflow
- gSessionData->mCounterOverflow = 0;
+ if (gSessionData->mCountersError != NULL) {
+ free(gSessionData->mCountersError);
+ gSessionData->mCountersError = NULL;
+ }
gSessionData->mIsEBS = false;
mIndex = 0;
@@ -98,6 +100,14 @@ int ConfigurationXML::parse(const char* configurationXML) {
mxmlDelete(tree);
+ if (gSessionData->mCountersError == NULL && mIndex > MAX_PERFORMANCE_COUNTERS) {
+ if (asprintf(&gSessionData->mCountersError, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, mIndex) <= 0) {
+ logg->logError("asprintf failed");
+ handleException();
+ }
+ }
+ gSessionData->mCcnDriver.validateCounters();
+
return ret;
}
@@ -149,7 +159,6 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
// handle all other performance counters
if (mIndex >= MAX_PERFORMANCE_COUNTERS) {
mIndex++;
- gSessionData->mCounterOverflow = mIndex;
return;
}
diff --git a/daemon/DiskIODriver.cpp b/daemon/DiskIODriver.cpp
index af62bb9..bd18bbd 100644
--- a/daemon/DiskIODriver.cpp
+++ b/daemon/DiskIODriver.cpp
@@ -53,7 +53,7 @@ DiskIODriver::~DiskIODriver() {
void DiskIODriver::readEvents(mxml_node_t *const) {
// Only for use with perf
- if (!gSessionData->perf.isSetup()) {
+ if (!gSessionData->mPerf.isSetup()) {
return;
}
diff --git a/daemon/DriverSource.cpp b/daemon/DriverSource.cpp
index 34920ce..caa956f 100644
--- a/daemon/DriverSource.cpp
+++ b/daemon/DriverSource.cpp
@@ -28,33 +28,8 @@
extern Child *child;
DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL), mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) {
- int driver_version = 0;
-
mBuffer = new Buffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem);
- if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
- logg->logError("Error reading gator driver version");
- handleException();
- }
-
- // Verify the driver version matches the daemon version
- if (driver_version != PROTOCOL_VERSION) {
- if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
- // One of the mismatched versions is development version
- logg->logError(
- "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
- ">> The following must be synchronized from engineering repository:\n"
- ">> * gator driver\n"
- ">> * gator daemon\n"
- ">> * Streamline", driver_version, PROTOCOL_VERSION);
- handleException();
- } else {
- // Release version mismatch
- logg->logError(
- "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
- ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
- handleException();
- }
- }
+ checkVersion();
int enable = -1;
if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) {
@@ -85,6 +60,35 @@ DriverSource::~DriverSource() {
}
}
+void DriverSource::checkVersion() {
+ int driverVersion = 0;
+
+ if (readIntDriver("/dev/gator/version", &driverVersion) == -1) {
+ logg->logError("Error reading gator driver version");
+ handleException();
+ }
+
+ // Verify the driver version matches the daemon version
+ if (driverVersion != PROTOCOL_VERSION) {
+ if ((driverVersion > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
+ // One of the mismatched versions is development version
+ logg->logError(
+ "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
+ ">> The following must be synchronized from engineering repository:\n"
+ ">> * gator driver\n"
+ ">> * gator daemon\n"
+ ">> * Streamline", driverVersion, PROTOCOL_VERSION);
+ handleException();
+ } else {
+ // Release version mismatch
+ logg->logError(
+ "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
+ ">> Please upgrade the driver and daemon to the latest versions.", driverVersion, PROTOCOL_VERSION);
+ handleException();
+ }
+ }
+}
+
bool DriverSource::prepare() {
// Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, mBufferSize);
diff --git a/daemon/DriverSource.h b/daemon/DriverSource.h
index 32d983d..971a4d9 100644
--- a/daemon/DriverSource.h
+++ b/daemon/DriverSource.h
@@ -29,6 +29,7 @@ public:
bool isDone();
void write(Sender *sender);
+ static void checkVersion();
static int readIntDriver(const char *fullpath, int *value);
static int readInt64Driver(const char *fullpath, int64_t *value);
static int writeDriver(const char *fullpath, const char *data);
diff --git a/daemon/EventsXML.cpp b/daemon/EventsXML.cpp
index cec08d5..d8044d8 100644
--- a/daemon/EventsXML.cpp
+++ b/daemon/EventsXML.cpp
@@ -50,7 +50,7 @@ mxml_node_t *EventsXML::getTree() {
// Load the provided or default events xml
if (gSessionData->mEventsXMLPath) {
strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
- fl = fopen(path, "r");
+ fl = fopen_cloexec(path, "r");
if (fl) {
xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
fclose(fl);
@@ -63,7 +63,7 @@ mxml_node_t *EventsXML::getTree() {
// Append additional events XML
if (gSessionData->mEventsXMLAppend) {
- fl = fopen(gSessionData->mEventsXMLAppend, "r");
+ fl = fopen_cloexec(gSessionData->mEventsXMLAppend, "r");
if (fl == NULL) {
logg->logError("Unable to open additional events XML %s", gSessionData->mEventsXMLAppend);
handleException();
diff --git a/daemon/ExternalDriver.cpp b/daemon/ExternalDriver.cpp
new file mode 100644
index 0000000..c1b7983
--- /dev/null
+++ b/daemon/ExternalDriver.cpp
@@ -0,0 +1,269 @@
+/**
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "ExternalDriver.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "Buffer.h"
+#include "Logging.h"
+#include "OlySocket.h"
+#include "SessionData.h"
+
+static const char MALI_UTGARD_SETUP[] = "\0mali-utgard-setup";
+static const char SETUP_VERSION[] = "ANNOTATE_SETUP 1\n";
+static const size_t HEADER_SIZE = 1 + sizeof(uint32_t);
+
+#define HEADER_ERROR 0x80
+#define HEADER_ACK 0x81
+#define HEADER_REQUEST_COUNTERS 0x82
+#define HEADER_COUNTERS 0x83
+#define HEADER_ENABLE_COUNTERS 0x84
+#define HEADER_START 0x85
+
+static uint32_t readLEInt(char *const buf)
+{
+ size_t i;
+ uint32_t v;
+
+ v = 0;
+ for (i = 0; i < sizeof(v); ++i)
+ v |= (uint32_t)buf[i] << 8*i;
+
+ return v;
+}
+
+static int readPackedInt(char *const buf, const size_t bufSize, size_t *const pos, uint64_t *const l)
+{
+ uint8_t shift = 0;
+ uint8_t b = ~0;
+
+ *l = 0;
+ while ((b & 0x80) != 0) {
+ if (*pos >= bufSize) {
+ return -1;
+ }
+ b = buf[*pos];
+ *pos += 1;
+ *l |= (uint64_t)(b & 0x7f) << shift;
+ shift += 7;
+ }
+
+ if (shift < 8*sizeof(*l) && (b & 0x40) != 0) {
+ *l |= -(1 << shift);
+ }
+
+ return 0;
+}
+
+class ExternalCounter : public DriverCounter {
+public:
+ ExternalCounter(DriverCounter *next, const char *name, int cores) : DriverCounter(next, name), mCores(cores), mEvent(-1) {}
+
+ ~ExternalCounter() {
+ }
+
+ int getCores() const { return mCores; }
+ void setEvent(const int event) { mEvent = event; }
+ int getEvent() const { return mEvent; }
+
+private:
+ const int mCores;
+ int mEvent;
+
+ // Intentionally undefined
+ ExternalCounter(const ExternalCounter &);
+ ExternalCounter &operator=(const ExternalCounter &);
+};
+
+ExternalDriver::ExternalDriver() : mUds(-1), mQueried(false), mStarted(false) {
+}
+
+bool ExternalDriver::connect() const {
+ if (mUds < 0) {
+ mUds = OlySocket::connect(MALI_UTGARD_SETUP, sizeof(MALI_UTGARD_SETUP));
+ if (mUds >= 0 && !writeAll(mUds, SETUP_VERSION, sizeof(SETUP_VERSION) - 1)) {
+ logg->logError("Unable to send setup version");
+ handleException();
+ }
+ }
+ return mUds >= 0;
+}
+
+void ExternalDriver::disconnect() {
+ if (mUds >= 0) {
+ close(mUds);
+ mUds = -1;
+ mStarted = false;
+ }
+}
+
+void ExternalDriver::query() const {
+ if (mQueried) {
+ return;
+ }
+ // Only try once even if it fails otherwise not all the possible counters may be shown
+ mQueried = true;
+
+ char *const buf = gSessionData->mSharedData->mMaliUtgardCounters;
+ const size_t bufSize = sizeof(gSessionData->mSharedData->mMaliUtgardCounters);
+ size_t size = 0;
+
+ if (!connect()) {
+ size = gSessionData->mSharedData->mMaliUtgardCountersSize;
+ logg->logMessage("Unable to connect, using cached version; size: %zi", size);
+ } else {
+ gSessionData->mSharedData->mMaliUtgardCountersSize = 0;
+
+ buf[0] = HEADER_REQUEST_COUNTERS;
+ size_t pos = HEADER_SIZE;
+ Buffer::writeLEInt((unsigned char *)(buf + 1), pos);
+ if (!writeAll(mUds, buf, pos)) {
+ logg->logError("Unable to send request counters message");
+ handleException();
+ }
+
+ if (!readAll(mUds, buf, HEADER_SIZE) || buf[0] != (char)HEADER_COUNTERS) {
+ logg->logError("Unable to read request counters response header");
+ handleException();
+ }
+ size = readLEInt(buf + 1);
+ if (size > bufSize || !readAll(mUds, buf, size - HEADER_SIZE)) {
+ logg->logError("Unable to read request counters response");
+ handleException();
+ }
+
+ size -= HEADER_SIZE;
+ gSessionData->mSharedData->mMaliUtgardCountersSize = size;
+ logg->logMessage("Requested counters; size: %zi", size);
+ }
+
+ size_t pos = 0;
+ while (pos < size) {
+ size_t begin = pos;
+ char *name = NULL;
+ uint64_t cores = -1;
+ while (pos < size && buf[pos] != '\0') {
+ ++pos;
+ }
+ if (pos > begin) {
+ name = strndup(buf + begin, pos - begin);
+ }
+ if (pos < size && buf[pos] == '\0') {
+ ++pos;
+ }
+ ;
+ if (name != NULL && readPackedInt(buf, bufSize, &pos, &cores) == 0) {
+ // Cheat so that this can be 'const'
+ ((ExternalDriver *)(this))->setCounters(new ExternalCounter(getCounters(), name, cores));
+ }
+ }
+
+ if (pos != size) {
+ logg->logError("Unable to parse request counters response");
+ handleException();
+ }
+}
+
+void ExternalDriver::start() {
+ if (!connect()) {
+ return;
+ }
+
+ if (mStarted) {
+ return;
+ }
+ // Only start once
+ mStarted = true;
+
+ char buf[1<<12];
+ int pos;
+
+ buf[0] = HEADER_ENABLE_COUNTERS;
+ pos = HEADER_SIZE;
+ for (ExternalCounter *counter = static_cast<ExternalCounter *>(getCounters()); counter != NULL; counter = static_cast<ExternalCounter *>(counter->getNext())) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ size_t nameLen = strlen(counter->getName());
+ if (pos + nameLen + 1 + 2*Buffer::MAXSIZE_PACK32 > sizeof(buf)) {
+ logg->logError("Unable to enable counters, message is too large");
+ handleException();
+ }
+ memcpy(buf + pos, counter->getName(), nameLen + 1);
+ pos += nameLen + 1;
+ Buffer::packInt(buf, sizeof(buf), pos, counter->getEvent());
+ Buffer::packInt(buf, sizeof(buf), pos, counter->getKey());
+ }
+ Buffer::writeLEInt((unsigned char *)(buf + 1), pos);
+ if (!writeAll(mUds, buf, pos)) {
+ logg->logError("Unable to send enable counters message");
+ handleException();
+ }
+
+ size_t size = 0;
+ if (!readAll(mUds, buf, HEADER_SIZE) || buf[0] != (char)HEADER_ACK) {
+ logg->logError("Unable to read enable counters response header");
+ handleException();
+ }
+ size = readLEInt(buf + 1);
+ if (size != HEADER_SIZE) {
+ logg->logError("Unable to parse enable counters response");
+ handleException();
+ }
+
+ buf[0] = HEADER_START;
+ pos = HEADER_SIZE;
+ // ns/sec / samples/sec = ns/sample
+ // For sample rate of none, sample every 100ms
+ Buffer::packInt(buf, sizeof(buf), pos, NS_PER_S / (gSessionData->mSampleRate == 0 ? 10 : gSessionData->mSampleRate));
+ Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mLiveRate);
+ Buffer::writeLEInt((unsigned char *)(buf + 1), pos);
+ if (!writeAll(mUds, buf, pos)) {
+ logg->logError("Unable to send start message");
+ handleException();
+ }
+
+ size = 0;
+ if (!readAll(mUds, buf, HEADER_SIZE) || buf[0] != (char)HEADER_ACK) {
+ logg->logError("Unable to read start response header");
+ handleException();
+ }
+ size = readLEInt(buf + 1);
+ if (size != HEADER_SIZE) {
+ logg->logError("Unable to parse start response");
+ handleException();
+ }
+}
+
+bool ExternalDriver::claimCounter(const Counter &counter) const {
+ query();
+ return super::claimCounter(counter);
+}
+
+void ExternalDriver::setupCounter(Counter &counter) {
+ ExternalCounter *const externalCounter = static_cast<ExternalCounter *>(findCounter(counter));
+ if (externalCounter == NULL) {
+ counter.setEnabled(false);
+ return;
+ }
+ externalCounter->setEnabled(true);
+ counter.setKey(externalCounter->getKey());
+ if (counter.getEvent() != -1) {
+ externalCounter->setEvent(counter.getEvent());
+ }
+ if (externalCounter->getCores() > 0) {
+ counter.setCores(externalCounter->getCores());
+ }
+}
+
+void ExternalDriver::resetCounters() {
+ query();
+ super::resetCounters();
+}
diff --git a/daemon/ExternalDriver.h b/daemon/ExternalDriver.h
new file mode 100644
index 0000000..d88f9e1
--- /dev/null
+++ b/daemon/ExternalDriver.h
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef EXTERNALDRIVER_H
+#define EXTERNALDRIVER_H
+
+#include "Driver.h"
+
+class ExternalDriver : public SimpleDriver {
+public:
+ ExternalDriver();
+
+ bool claimCounter(const Counter &counter) const;
+ void resetCounters();
+ void setupCounter(Counter &counter);
+
+ void start();
+
+ void disconnect();
+
+private:
+ typedef SimpleDriver super;
+
+ bool connect() const;
+ void query() const;
+
+ mutable int mUds;
+ mutable bool mQueried;
+ bool mStarted;
+
+ // Intentionally unimplemented
+ ExternalDriver(const ExternalDriver &);
+ ExternalDriver &operator=(const ExternalDriver &);
+};
+
+#endif // EXTERNALDRIVER_H
diff --git a/daemon/ExternalSource.cpp b/daemon/ExternalSource.cpp
index 8d71b6d..e87fb9e 100644
--- a/daemon/ExternalSource.cpp
+++ b/daemon/ExternalSource.cpp
@@ -13,6 +13,7 @@
#include <unistd.h>
#include "Child.h"
+#include "DriverSource.h"
#include "Logging.h"
#include "OlySocket.h"
#include "SessionData.h"
@@ -26,25 +27,10 @@ static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n";
static const char MALI_GRAPHICS[] = "\0mali_thirdparty_server";
static const char MALI_GRAPHICS_STARTUP[] = "\0mali_thirdparty_client";
static const char MALI_GRAPHICS_V1[] = "MALI_GRAPHICS 1\n";
+static const char MALI_UTGARD_STARTUP[] = "\0mali-utgard-startup";
+static const char FTRACE_V1[] = "FTRACE 1\n";
-static bool setNonblock(const int fd) {
- int flags;
-
- flags = fcntl(fd, F_GETFL);
- if (flags < 0) {
- logg->logMessage("fcntl getfl failed");
- return false;
- }
-
- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
- logg->logMessage("fcntl setfl failed");
- return false;
- }
-
- return true;
-}
-
-ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mAnnotate(8083), mAnnotateUds(STREAMLINE_ANNOTATE, sizeof(STREAMLINE_ANNOTATE), true), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) {
+ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mUtgardStartupUds(MALI_UTGARD_STARTUP, sizeof(MALI_UTGARD_STARTUP)), mAnnotate(8083), mAnnotateUds(STREAMLINE_ANNOTATE, sizeof(STREAMLINE_ANNOTATE), true), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1), mFtraceFd(-1) {
sem_init(&mBufferSem, 0, 0);
}
@@ -91,7 +77,7 @@ bool ExternalSource::connectMali() {
}
bool ExternalSource::connectMve() {
- if (!gSessionData->maliVideo.countersEnabled()) {
+ if (!gSessionData->mMaliVideo.countersEnabled()) {
return true;
}
@@ -100,7 +86,7 @@ bool ExternalSource::connectMve() {
return false;
}
- if (!gSessionData->maliVideo.start(mMveUds)) {
+ if (!gSessionData->mMaliVideo.start(mMveUds)) {
return false;
}
@@ -109,10 +95,27 @@ bool ExternalSource::connectMve() {
return true;
}
+void ExternalSource::connectFtrace() {
+ if (!gSessionData->mFtraceDriver.isSupported()) {
+ return;
+ }
+
+ gSessionData->mFtraceDriver.prepare();
+
+ mFtraceFd = open(TRACING_PATH "/trace_pipe", O_RDONLY | O_CLOEXEC);
+ if (mFtraceFd < 0) {
+ logg->logError("Unable to open trace_pipe");
+ handleException();
+ }
+
+ configureConnection(mFtraceFd, FTRACE_V1, sizeof(FTRACE_V1));
+}
+
bool ExternalSource::prepare() {
if (!mMonitor.init() ||
!setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd()) ||
!setNonblock(mMaliStartupUds.getFd()) || !mMonitor.add(mMaliStartupUds.getFd()) ||
+ !setNonblock(mUtgardStartupUds.getFd()) || !mMonitor.add(mUtgardStartupUds.getFd()) ||
!setNonblock(mAnnotate.getFd()) || !mMonitor.add(mAnnotate.getFd()) ||
!setNonblock(mAnnotateUds.getFd()) || !mMonitor.add(mAnnotateUds.getFd()) ||
false) {
@@ -121,6 +124,8 @@ bool ExternalSource::prepare() {
connectMali();
connectMve();
+ connectFtrace();
+ gSessionData->mExternalDriver.start();
return true;
}
@@ -147,6 +152,30 @@ void ExternalSource::run() {
logg->logMessage("Writing to annotate pipe failed");
}
+ if (mFtraceFd >= 0) {
+ gSessionData->mAtraceDriver.start();
+
+ if (DriverSource::writeDriver(TRACING_PATH "/tracing_on", "1") != 0) {
+ logg->logError("Unable to turn ftrace on");
+ handleException();
+ }
+ }
+
+ // Wait until monotonicStarted is set before sending data
+ int64_t monotonicStarted = 0;
+ while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
+ usleep(10);
+
+ if (gSessionData->mPerf.isSetup()) {
+ monotonicStarted = gSessionData->mMonotonicStarted;
+ } else {
+ if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
+ logg->logError("Error reading gator driver start time");
+ handleException();
+ }
+ }
+ }
+
while (gSessionData->mSessionIsActive) {
struct epoll_event events[16];
// Clear any pending sem posts
@@ -179,6 +208,13 @@ void ExternalSource::run() {
logg->logError("Unable to configure incoming Mali graphics connection");
handleException();
}
+ } else if (fd == mUtgardStartupUds.getFd()) {
+ // Mali Utgard says it's alive
+ int client = mUtgardStartupUds.acceptConnection();
+ // Don't read from this connection, configure utgard and expect them to reconnect with annotations
+ close(client);
+ gSessionData->mExternalDriver.disconnect();
+ gSessionData->mExternalDriver.start();
} else if (fd == mAnnotate.getFd()) {
int client = mAnnotate.acceptConnection();
if (!setNonblock(client) || !mMonitor.add(client)) {
@@ -243,8 +279,14 @@ void ExternalSource::run() {
mBuffer.setDone();
+ if (mFtraceFd >= 0) {
+ gSessionData->mFtraceDriver.stop();
+ gSessionData->mAtraceDriver.stop();
+ close(mFtraceFd);
+ }
+
if (mMveUds >= 0) {
- gSessionData->maliVideo.stop(mMveUds);
+ gSessionData->mMaliVideo.stop(mMveUds);
}
mInterruptFd = -1;
diff --git a/daemon/ExternalSource.h b/daemon/ExternalSource.h
index 25ae7cd..69d16af 100644
--- a/daemon/ExternalSource.h
+++ b/daemon/ExternalSource.h
@@ -34,17 +34,20 @@ private:
void configureConnection(const int fd, const char *const handshake, size_t size);
bool connectMali();
bool connectMve();
+ void connectFtrace();
sem_t mBufferSem;
Buffer mBuffer;
Monitor mMonitor;
OlyServerSocket mMveStartupUds;
OlyServerSocket mMaliStartupUds;
+ OlyServerSocket mUtgardStartupUds;
OlyServerSocket mAnnotate;
OlyServerSocket mAnnotateUds;
int mInterruptFd;
int mMaliUds;
int mMveUds;
+ int mFtraceFd;
// Intentionally unimplemented
ExternalSource(const ExternalSource &);
diff --git a/daemon/FtraceDriver.cpp b/daemon/FtraceDriver.cpp
index 98bd0a5..7c57cfc 100644
--- a/daemon/FtraceDriver.cpp
+++ b/daemon/FtraceDriver.cpp
@@ -10,22 +10,25 @@
#include <regex.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "Config.h"
#include "DriverSource.h"
#include "Logging.h"
+#include "SessionData.h"
#include "Setup.h"
class FtraceCounter : public DriverCounter {
public:
- FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable);
+ FtraceCounter(DriverCounter *next, char *name, const char *enable);
~FtraceCounter();
void prepare();
- int read(const char *const line, int64_t *values);
void stop();
private:
- regex_t mReg;
char *const mEnable;
int mWasEnabled;
@@ -34,18 +37,10 @@ private:
FtraceCounter &operator=(const FtraceCounter &);
};
-FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable) : DriverCounter(next, name), mEnable(enable == NULL ? NULL : strdup(enable)) {
- int result = regcomp(&mReg, regex, REG_EXTENDED);
- if (result != 0) {
- char buf[128];
- regerror(result, &mReg, buf, sizeof(buf));
- logg->logError("Invalid regex '%s': %s", regex, buf);
- handleException();
- }
+FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *enable) : DriverCounter(next, name), mEnable(enable == NULL ? NULL : strdup(enable)) {
}
FtraceCounter::~FtraceCounter() {
- regfree(&mReg);
if (mEnable != NULL) {
free(mEnable);
}
@@ -57,7 +52,7 @@ void FtraceCounter::prepare() {
}
char buf[1<<10];
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
+ snprintf(buf, sizeof(buf), EVENTS_PATH "/%s/enable", mEnable);
if ((DriverSource::readIntDriver(buf, &mWasEnabled) != 0) ||
(DriverSource::writeDriver(buf, 1) != 0)) {
logg->logError("Unable to read or write to %s", buf);
@@ -65,43 +60,17 @@ void FtraceCounter::prepare() {
}
}
-int FtraceCounter::read(const char *const line, int64_t *values) {
- regmatch_t match[2];
- int result = regexec(&mReg, line, 2, match, 0);
- if (result != 0) {
- // No match
- return 0;
- }
-
- int64_t value;
- if (match[1].rm_so < 0) {
- value = 1;
- } else {
- errno = 0;
- value = strtoll(line + match[1].rm_so, NULL, 0);
- if (errno != 0) {
- logg->logError("Parsing %s failed: %s", getName(), strerror(errno));
- handleException();
- }
- }
-
- values[0] = getKey();
- values[1] = value;
-
- return 1;
-}
-
void FtraceCounter::stop() {
if (mEnable == NULL) {
return;
}
char buf[1<<10];
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
+ snprintf(buf, sizeof(buf), EVENTS_PATH "/%s/enable", mEnable);
DriverSource::writeDriver(buf, mWasEnabled);
}
-FtraceDriver::FtraceDriver() : mValues(NULL) {
+FtraceDriver::FtraceDriver() : mValues(NULL), mSupported(false), mTracingOn(0) {
}
FtraceDriver::~FtraceDriver() {
@@ -118,10 +87,20 @@ void FtraceDriver::readEvents(mxml_node_t *const xml) {
// The perf clock was added in 3.10
if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 10, 0)) {
+ mSupported = false;
logg->logMessage("Unsupported kernel version, to use ftrace please upgrade to Linux 3.10 or later");
return;
}
+ // Is debugfs or tracefs available?
+ if (access(TRACING_PATH, R_OK) != 0) {
+ mSupported = false;
+ logg->logMessage("Unable to locate the tracing directory, disabling ftrace");
+ return;
+ }
+
+ mSupported = true;
+
mxml_node_t *node = xml;
int count = 0;
while (true) {
@@ -143,20 +122,28 @@ void FtraceDriver::readEvents(mxml_node_t *const xml) {
logg->logError("The regex counter %s is missing the required regex attribute", counter);
handleException();
}
- bool addCounter = true;
+
+ const char *tracepoint = mxmlElementGetAttr(node, "tracepoint");
const char *enable = mxmlElementGetAttr(node, "enable");
+ if (enable == NULL) {
+ enable = tracepoint;
+ }
+ if (gSessionData->mPerf.isSetup() && tracepoint != NULL) {
+ logg->logMessage("Not using ftrace for counter %s", counter);
+ continue;
+ }
if (enable != NULL) {
char buf[1<<10];
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", enable);
+ snprintf(buf, sizeof(buf), EVENTS_PATH "/%s/enable", enable);
if (access(buf, W_OK) != 0) {
logg->logMessage("Disabling counter %s, %s not found", counter, buf);
- addCounter = false;
+ continue;
}
}
- if (addCounter) {
- setCounters(new FtraceCounter(getCounters(), strdup(counter), regex, enable));
- ++count;
- }
+
+ logg->logMessage("Using ftrace for %s", counter);
+ setCounters(new FtraceCounter(getCounters(), strdup(counter), enable));
+ ++count;
}
mValues = new int64_t[2*count];
@@ -169,23 +156,37 @@ void FtraceDriver::prepare() {
}
counter->prepare();
}
-}
-int FtraceDriver::read(const char *line, int64_t **buf) {
- int count = 0;
+ if (DriverSource::readIntDriver(TRACING_PATH "/tracing_on", &mTracingOn)) {
+ logg->logError("Unable to read if ftrace is enabled");
+ handleException();
+ }
- for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
- if (!counter->isEnabled()) {
- continue;
+ if (DriverSource::writeDriver(TRACING_PATH "/tracing_on", "0") != 0) {
+ logg->logError("Unable to turn ftrace off before truncating the buffer");
+ handleException();
+ }
+
+ {
+ int fd;
+ fd = open(TRACING_PATH "/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
+ if (fd < 0) {
+ logg->logError("Unable truncate ftrace buffer: %s", strerror(errno));
+ handleException();
}
- count += counter->read(line, mValues + 2*count);
+ close(fd);
}
- *buf = mValues;
- return count;
+ if (DriverSource::writeDriver(TRACING_PATH "/trace_clock", "perf") != 0) {
+ logg->logError("Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
+ handleException();
+ }
}
void FtraceDriver::stop() {
+ DriverSource::writeDriver(TRACING_PATH "/tracing_on", mTracingOn);
+ DriverSource::writeDriver(TRACING_PATH "/trace_clock", "local");
+
for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
if (!counter->isEnabled()) {
continue;
diff --git a/daemon/FtraceDriver.h b/daemon/FtraceDriver.h
index b79dc91..6e592d7 100644
--- a/daemon/FtraceDriver.h
+++ b/daemon/FtraceDriver.h
@@ -19,11 +19,14 @@ public:
void readEvents(mxml_node_t *const xml);
void prepare();
- int read(const char *line, int64_t **buf);
void stop();
+ bool isSupported() const { return mSupported; }
+
private:
int64_t *mValues;
+ bool mSupported;
+ int mTracingOn;
// Intentionally unimplemented
FtraceDriver(const FtraceDriver &);
diff --git a/daemon/FtraceSource.cpp b/daemon/FtraceSource.cpp
deleted file mode 100644
index 14a48b3..0000000
--- a/daemon/FtraceSource.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2010-2015. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "FtraceSource.h"
-
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#include "Child.h"
-#include "DriverSource.h"
-#include "Logging.h"
-#include "SessionData.h"
-
-extern Child *child;
-
-static void handler(int signum)
-{
- (void)signum;
-};
-
-FtraceSource::FtraceSource(sem_t *senderSem) : mFtraceFh(NULL), mBuffer(0, FRAME_BLOCK_COUNTER, 128*1024, senderSem), mTid(-1), mTracingOn(0) {
-}
-
-FtraceSource::~FtraceSource() {
-}
-
-bool FtraceSource::prepare() {
- {
- struct sigaction act;
- act.sa_handler = handler;
- act.sa_flags = (int)SA_RESETHAND;
- if (sigaction(SIGUSR1, &act, NULL) != 0) {
- logg->logError("sigaction failed: %s\n", strerror(errno));
- handleException();
- }
- }
-
- gSessionData->ftraceDriver.prepare();
-
- if (DriverSource::readIntDriver("/sys/kernel/debug/tracing/tracing_on", &mTracingOn)) {
- logg->logError("Unable to read if ftrace is enabled");
- handleException();
- }
-
- if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "0") != 0) {
- logg->logError("Unable to turn ftrace off before truncating the buffer");
- handleException();
- }
-
- {
- int fd;
- fd = open("/sys/kernel/debug/tracing/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
- if (fd < 0) {
- logg->logError("Unable truncate ftrace buffer: %s", strerror(errno));
- handleException();
- }
- close(fd);
- }
-
- if (DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "perf") != 0) {
- logg->logError("Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
- handleException();
- }
-
- mFtraceFh = fopen_cloexec("/sys/kernel/debug/tracing/trace_pipe", "rb");
- if (mFtraceFh == NULL) {
- logg->logError("Unable to open trace_pipe");
- handleException();
- }
-
- return true;
-}
-
-void FtraceSource::run() {
- prctl(PR_SET_NAME, (unsigned long)&"gatord-ftrace", 0, 0, 0);
- mTid = syscall(__NR_gettid);
-
- if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "1") != 0) {
- logg->logError("Unable to turn ftrace on");
- handleException();
- }
-
- // Wait until monotonicStarted is set before sending data
- int64_t monotonicStarted = 0;
- while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
- usleep(10);
-
- if (gSessionData->perf.isSetup()) {
- monotonicStarted = gSessionData->mMonotonicStarted;
- } else {
- if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
- logg->logError("Error reading gator driver start time");
- handleException();
- }
- }
- }
-
- while (gSessionData->mSessionIsActive) {
- char buf[1<<12];
-
- if (fgets(buf, sizeof(buf), mFtraceFh) == NULL) {
- if (errno == EINTR) {
- // Interrupted by interrupt - likely user request to terminate
- break;
- }
- logg->logError("Unable read trace data: %s", strerror(errno));
- handleException();
- }
-
- const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted;
-
- char *const colon = strstr(buf, ": ");
- if (colon == NULL) {
- if (strstr(buf, " [LOST ") != NULL) {
- logg->logError("Ftrace events lost, aborting the capture. It is recommended to discard this report and collect a new capture. If this error occurs often, please reduce the number of ftrace counters selected or the amount of ftrace events generated.");
- } else {
- logg->logError("Unable to find colon: %s", buf);
- }
- handleException();
- }
- *colon = '\0';
-
- char *const space = strrchr(buf, ' ');
- if (space == NULL) {
- logg->logError("Unable to find space: %s", buf);
- handleException();
- }
- *colon = ':';
-
- int64_t *data = NULL;
- int count = gSessionData->ftraceDriver.read(colon + 2, &data);
- if (count > 0) {
- errno = 0;
- const long long time = strtod(space, NULL) * 1000000000;
- if (errno != 0) {
- logg->logError("Unable to parse time: %s", strerror(errno));
- handleException();
- }
- mBuffer.event64(-1, time);
-
- for (int i = 0; i < count; ++i) {
- mBuffer.event64(data[2*i + 0], data[2*i + 1]);
- }
-
- mBuffer.check(currTime);
-
- if (gSessionData->mOneShot && gSessionData->mSessionIsActive && (mBuffer.bytesAvailable() <= 0)) {
- logg->logMessage("One shot (ftrace)");
- child->endSession();
- }
- }
-
- }
-
- mBuffer.setDone();
-
- DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", mTracingOn);
- fclose(mFtraceFh);
- DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "local");
- gSessionData->ftraceDriver.stop();
-}
-
-void FtraceSource::interrupt() {
- // Closing the underlying file handle does not result in the read on the ftrace file handle to return, so send a signal to the thread
- syscall(__NR_tgkill, getpid(), mTid, SIGUSR1);
-}
-
-bool FtraceSource::isDone() {
- return mBuffer.isDone();
-}
-
-void FtraceSource::write(Sender *sender) {
- // Don't send ftrace data until the summary packet is sent so that monotonic delta is available
- if (!gSessionData->mSentSummary) {
- return;
- }
- if (!mBuffer.isDone()) {
- mBuffer.write(sender);
- }
-}
diff --git a/daemon/FtraceSource.h b/daemon/FtraceSource.h
deleted file mode 100644
index bc068d2..0000000
--- a/daemon/FtraceSource.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2010-2015. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef FTRACESOURCE_H
-#define FTRACESOURCE_H
-
-#include <semaphore.h>
-#include <stdio.h>
-
-#include "Buffer.h"
-#include "Source.h"
-
-class FtraceSource : public Source {
-public:
- FtraceSource(sem_t *senderSem);
- ~FtraceSource();
-
- bool prepare();
- void run();
- void interrupt();
-
- bool isDone();
- void write(Sender *sender);
-
-private:
- void waitFor(const int bytes);
-
- FILE *mFtraceFh;
- Buffer mBuffer;
- int mTid;
- int mTracingOn;
-
- // Intentionally unimplemented
- FtraceSource(const FtraceSource &);
- FtraceSource &operator=(const FtraceSource &);
-};
-
-#endif // FTRACESOURCE_H
diff --git a/daemon/MaliVideoDriver.cpp b/daemon/MaliVideoDriver.cpp
index 2db332d..209a2d3 100644
--- a/daemon/MaliVideoDriver.cpp
+++ b/daemon/MaliVideoDriver.cpp
@@ -58,6 +58,7 @@ MaliVideoDriver::~MaliVideoDriver() {
}
void MaliVideoDriver::readEvents(mxml_node_t *const xml) {
+ // Always create the counters as /dev/mv500 may show up after gatord starts
mxml_node_t *node = xml;
while (true) {
node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
@@ -82,12 +83,22 @@ void MaliVideoDriver::readEvents(mxml_node_t *const xml) {
int MaliVideoDriver::writeCounters(mxml_node_t *root) const {
if (access("/dev/mv500", F_OK) != 0) {
+ // Don't show the counters in counter configuration
return 0;
}
return super::writeCounters(root);
}
+bool MaliVideoDriver::claimCounter(const Counter &counter) const {
+ if (access("/dev/mv500", F_OK) != 0) {
+ // Don't add the counters to captured XML
+ return 0;
+ }
+
+ return super::claimCounter(counter);
+}
+
void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos) {
// size
int numEnabled = 0;
@@ -104,20 +115,6 @@ void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const
}
}
-static bool writeAll(const int mveUds, const char *const buf, const int pos) {
- int written = 0;
- while (written < pos) {
- size_t bytes = ::write(mveUds, buf + written, pos - written);
- if (bytes <= 0) {
- logg->logMessage("write failed");
- return false;
- }
- written += bytes;
- }
-
- return true;
-}
-
bool MaliVideoDriver::start(const int mveUds) {
char buf[256];
int pos = 0;
@@ -146,7 +143,7 @@ bool MaliVideoDriver::start(const int mveUds) {
// data_protocol_version
Buffer::packInt(buf, sizeof(buf), pos, 1);
// sample_rate - convert samples/second to ms/sample
- Buffer::packInt(buf, sizeof(buf), pos, 1000/gSessionData->mSampleRate);
+ Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mSampleRate/1000);
// live_rate - convert ns/flush to ms/flush
Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mLiveRate/1000000);
@@ -183,7 +180,6 @@ void MaliVideoDriver::stop(const int mveUds) {
buf[pos++] = 'T';
buf[pos++] = 'O';
buf[pos++] = 'P';
- marshalEnable(MVCT_COUNTER, buf, sizeof(buf), pos);
writeAll(mveUds, buf, pos);
diff --git a/daemon/MaliVideoDriver.h b/daemon/MaliVideoDriver.h
index 35b0558..fd01b1b 100644
--- a/daemon/MaliVideoDriver.h
+++ b/daemon/MaliVideoDriver.h
@@ -30,6 +30,7 @@ public:
void readEvents(mxml_node_t *const root);
int writeCounters(mxml_node_t *root) const;
+ bool claimCounter(const Counter &counter) const;
bool start(const int mveUds);
void stop(const int mveUds);
diff --git a/daemon/MemInfoDriver.cpp b/daemon/MemInfoDriver.cpp
index 6818b97..4c0b051 100644
--- a/daemon/MemInfoDriver.cpp
+++ b/daemon/MemInfoDriver.cpp
@@ -44,7 +44,7 @@ MemInfoDriver::~MemInfoDriver() {
void MemInfoDriver::readEvents(mxml_node_t *const) {
// Only for use with perf
- if (!gSessionData->perf.isSetup()) {
+ if (!gSessionData->mPerf.isSetup()) {
return;
}
diff --git a/daemon/NetDriver.cpp b/daemon/NetDriver.cpp
index 56b25e0..ab36211 100644
--- a/daemon/NetDriver.cpp
+++ b/daemon/NetDriver.cpp
@@ -52,7 +52,7 @@ NetDriver::~NetDriver() {
void NetDriver::readEvents(mxml_node_t *const) {
// Only for use with perf
- if (!gSessionData->perf.isSetup()) {
+ if (!gSessionData->mPerf.isSetup()) {
return;
}
diff --git a/daemon/PerfDriver.cpp b/daemon/PerfDriver.cpp
index 796ee75..e5f8aaa 100644
--- a/daemon/PerfDriver.cpp
+++ b/daemon/PerfDriver.cpp
@@ -56,9 +56,9 @@ static const struct gator_cpu gator_cpus[] = {
{ 0x51049, "KraitSIM", "Krait", 4 },
{ 0x5104d, "Krait", "Krait", 4 },
{ 0x5106f, "Krait S4 Pro", "Krait", 4 },
- { 0x41d03, "Cortex-A53", "ARM_Cortex-A53", 6 },
- { 0x41d07, "Cortex-A57", "ARM_Cortex-A57", 6 },
- { 0x41d08, "Cortex-A72", "ARM_Cortex-A72", 6 },
+ { 0x41d03, "Cortex-A53", "ARMv8_Cortex_A53", 6 },
+ { 0x41d07, "Cortex-A57", "ARMv8_Cortex_A57", 6 },
+ { 0x41d08, "Cortex-A72", "ARMv8_Cortex_A72", 6 },
};
static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
@@ -75,14 +75,14 @@ struct uncore_counter {
static const struct uncore_counter uncore_counters[] = {
{ "CCI_400", "CCI_400", 4, true },
- { "CCI_400-r1", "CCI_400-r1", 4, true },
+ { "CCI_400_r1", "CCI_400_r1", 4, true },
{ "CCI_500", "CCI_500", 8, false },
{ "ccn", "ARM_CCN_5XX", 8, true },
};
class PerfCounter : public DriverCounter {
public:
- PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, uint64_t sampleType, uint64_t flags) : DriverCounter(next, name), mType(type), mConfig(config), mSampleType(sampleType), mFlags(flags), mCount(0) {}
+ PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, uint64_t sampleType, uint64_t flags, const int count) : DriverCounter(next, name), mType(type), mConfig(config), mSampleType(sampleType), mFlags(flags), mCount(count) {}
~PerfCounter() {
}
@@ -93,13 +93,14 @@ public:
uint64_t getConfig() const { return mConfig; }
void setConfig(const uint64_t config) { mConfig = config; }
uint64_t getSampleType() const { return mSampleType; }
+ void setSampleType(uint64_t sampleType) { mSampleType = sampleType; }
uint64_t getFlags() const { return mFlags; }
virtual void read(Buffer *const, const int) {}
private:
const uint32_t mType;
uint64_t mConfig;
- const uint64_t mSampleType;
+ uint64_t mSampleType;
const uint64_t mFlags;
int mCount;
@@ -110,7 +111,7 @@ private:
class CPUFreqDriver : public PerfCounter {
public:
- CPUFreqDriver(DriverCounter *next, uint64_t id) : PerfCounter(next, "Linux_power_cpu_freq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU) {}
+ CPUFreqDriver(DriverCounter *next, uint64_t id) : PerfCounter(next, "Linux_power_cpu_freq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU, 1) {}
void read(Buffer *const buffer, const int cpu) {
char buf[64];
@@ -135,17 +136,35 @@ PerfDriver::PerfDriver() : mIsSetup(false), mLegacySupport(false) {
PerfDriver::~PerfDriver() {
}
+class PerfTracepoint {
+public:
+ PerfTracepoint(PerfTracepoint *const next, const DriverCounter *const counter, const char *const tracepoint) : mNext(next), mCounter(counter), mTracepoint(tracepoint) {}
+
+ PerfTracepoint *getNext() const { return mNext; }
+ const DriverCounter *getCounter() const { return mCounter; }
+ const char *getTracepoint() const { return mTracepoint; }
+
+private:
+ PerfTracepoint *const mNext;
+ const DriverCounter *const mCounter;
+ const char *const mTracepoint;
+
+ // Intentionally undefined
+ PerfTracepoint(const PerfTracepoint &);
+ PerfTracepoint &operator=(const PerfTracepoint &);
+};
+
void PerfDriver::addCpuCounters(const char *const counterName, const int type, const int numCounters) {
int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
char *name = new char[len];
snprintf(name, len, "%s_ccnt", counterName);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
for (int j = 0; j < numCounters; ++j) {
len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
name = new char[len];
snprintf(name, len, "%s_cnt%d", counterName, j);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
}
@@ -157,14 +176,60 @@ void PerfDriver::addUncoreCounters(const char *const counterName, const int type
len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
name = new char[len];
snprintf(name, len, "%s_ccnt", counterName);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0, 0));
}
for (int j = 0; j < numCounters; ++j) {
len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
name = new char[len];
snprintf(name, len, "%s_cnt%d", counterName, j);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0, 0));
+ }
+}
+
+void PerfDriver::readEvents(mxml_node_t *const xml) {
+ mxml_node_t *node = xml;
+ DynBuf printb;
+
+ // Only for use with perf
+ if (!isSetup()) {
+ return;
+ }
+
+ while (true) {
+ node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
+ if (node == NULL) {
+ break;
+ }
+ const char *counter = mxmlElementGetAttr(node, "counter");
+ if (counter == NULL) {
+ continue;
+ }
+
+ if (strncmp(counter, "ftrace_", 7) != 0) {
+ continue;
+ }
+
+ const char *tracepoint = mxmlElementGetAttr(node, "tracepoint");
+ if (tracepoint == NULL) {
+ const char *regex = mxmlElementGetAttr(node, "regex");
+ if (regex == NULL) {
+ logg->logError("The tracepoint counter %s is missing the required tracepoint attribute", counter);
+ handleException();
+ } else {
+ logg->logMessage("Not using perf for counter %s", counter);
+ continue;
+ }
+ }
+
+ const char *arg = mxmlElementGetAttr(node, "arg");
+
+ long long id = getTracepointId(tracepoint, &printb);
+ if (id >= 0) {
+ logg->logMessage("Using perf for %s", counter);
+ setCounters(new PerfCounter(getCounters(), strdup(counter), PERF_TYPE_TRACEPOINT, id, arg == NULL ? 0 : PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU, 1));
+ mTracepoints = new PerfTracepoint(mTracepoints, getCounters(), strdup(tracepoint));
+ }
}
}
@@ -197,6 +262,7 @@ bool PerfDriver::setup() {
struct dirent *dirent;
while ((dirent = readdir(dir)) != NULL) {
+ logg->logMessage("perf pmu: %s", dirent->d_name);
for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
const struct gator_cpu *const gator_cpu = &gator_cpus[i];
@@ -217,7 +283,7 @@ bool PerfDriver::setup() {
}
foundCpu = true;
- logg->logMessage("Adding cpu counters for %s", gator_cpu->pmnc_name);
+ logg->logMessage("Adding cpu counters for %s with type %i", gator_cpu->pmnc_name, type);
addCpuCounters(gator_cpu->pmnc_name, type, gator_cpu->pmnc_counters);
}
@@ -233,7 +299,7 @@ bool PerfDriver::setup() {
continue;
}
- logg->logMessage("Adding uncore counters for %s", uncore_counters[i].gatorName);
+ logg->logMessage("Adding uncore counters for %s with type %i", uncore_counters[i].gatorName, type);
addUncoreCounters(uncore_counters[i].gatorName, type, uncore_counters[i].count, uncore_counters[i].hasCyclesCounter);
}
}
@@ -264,25 +330,25 @@ bool PerfDriver::setup() {
id = getTracepointId("irq/softirq_exit", &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
id = getTracepointId("irq/irq_handler_exit", &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
id = getTracepointId(SCHED_SWITCH, &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
id = getTracepointId(CPU_FREQUENCY, &printb);
- if (id >= 0) {
+ if (id >= 0 && access("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq", R_OK) == 0) {
setCounters(new CPUFreqDriver(getCounters(), id));
}
- setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, 0, 0));
+ setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, 0, 0, 0));
//Linux_cpu_wait_io
@@ -300,6 +366,12 @@ bool PerfDriver::summary(Buffer *const buffer) {
char buf[512];
snprintf(buf, sizeof(buf), "%s %s %s %s %s GNU/Linux", utsname.sysname, utsname.nodename, utsname.release, utsname.version, utsname.machine);
+ long pageSize = sysconf(_SC_PAGESIZE);
+ if (pageSize < 0) {
+ logg->logMessage("sysconf _SC_PAGESIZE failed");
+ return false;
+ }
+
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
logg->logMessage("clock_gettime failed");
@@ -311,7 +383,7 @@ bool PerfDriver::summary(Buffer *const buffer) {
gSessionData->mMonotonicStarted = monotonicStarted;
const uint64_t currTime = 0;//getTime() - gSessionData->mMonotonicStarted;
- buffer->summary(currTime, timestamp, monotonicStarted, monotonicStarted, buf);
+ buffer->summary(currTime, timestamp, monotonicStarted, monotonicStarted, buf, pageSize);
for (int i = 0; i < gSessionData->mCores; ++i) {
coreName(currTime, buffer, i);
@@ -322,27 +394,28 @@ bool PerfDriver::summary(Buffer *const buffer) {
}
void PerfDriver::coreName(const uint64_t currTime, Buffer *const buffer, const int cpu) {
+ const SharedData *const sharedData = gSessionData->mSharedData;
// Don't send information on a cpu we know nothing about
- if (gSessionData->mCpuIds[cpu] == -1) {
+ if (sharedData->mCpuIds[cpu] == -1) {
return;
}
int j;
for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) {
- if (gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
+ if (gator_cpus[j].cpuid == sharedData->mCpuIds[cpu]) {
break;
}
}
- if (j < ARRAY_LENGTH(gator_cpus) && gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
- buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], gator_cpus[j].core_name);
+ if (j < ARRAY_LENGTH(gator_cpus) && gator_cpus[j].cpuid == sharedData->mCpuIds[cpu]) {
+ buffer->coreName(currTime, cpu, sharedData->mCpuIds[cpu], gator_cpus[j].core_name);
} else {
char buf[32];
- if (gSessionData->mCpuIds[cpu] == -1) {
+ if (sharedData->mCpuIds[cpu] == -1) {
snprintf(buf, sizeof(buf), "Unknown");
} else {
- snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[cpu]);
+ snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", sharedData->mCpuIds[cpu]);
}
- buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], buf);
+ buffer->coreName(currTime, cpu, sharedData->mCpuIds[cpu], buf);
}
}
@@ -357,27 +430,22 @@ void PerfDriver::setupCounter(Counter &counter) {
if (counter.getEvent() != -1) {
perfCounter->setConfig(counter.getEvent());
}
- perfCounter->setCount(counter.getCount());
+ if (counter.getCount() > 0) {
+ // EBS
+ perfCounter->setCount(counter.getCount());
+ // Collect samples
+ perfCounter->setSampleType(perfCounter->getSampleType() | PERF_SAMPLE_TID | PERF_SAMPLE_IP);
+ }
perfCounter->setEnabled(true);
counter.setKey(perfCounter->getKey());
}
bool PerfDriver::enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const {
for (PerfCounter *counter = static_cast<PerfCounter *>(getCounters()); counter != NULL; counter = static_cast<PerfCounter *>(counter->getNext())) {
- if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
- int count = counter->getCount();
- uint64_t sampleType = counter->getSampleType();
- if (sampleType & PERF_SAMPLE_RAW) {
- // If raw is enabled, every sample is needed
- count = 1;
- }
- if (!group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), count,
- // use getCount instead of count as EBS counters need TID and IP but RAW tracepoints don't
- (counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0) | sampleType,
- counter->getFlags())) {
- logg->logMessage("PerfGroup::add failed");
- return false;
- }
+ if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED) &&
+ !group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), counter->getSampleType(), counter->getFlags())) {
+ logg->logMessage("PerfGroup::add failed");
+ return false;
}
}
@@ -393,6 +461,38 @@ void PerfDriver::read(Buffer *const buffer, const int cpu) {
}
}
+static bool sendTracepointFormat(const uint64_t currTime, Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
+ if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
+ logg->logMessage("DynBuf::printf failed");
+ return false;
+ }
+ if (!b->read(printb->getBuf())) {
+ logg->logMessage("DynBuf::read failed");
+ return false;
+ }
+ buffer->marshalFormat(currTime, b->getLength(), b->getBuf());
+
+ return true;
+}
+
+bool PerfDriver::sendTracepointFormats(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b) {
+ if (
+ !sendTracepointFormat(currTime, buffer, SCHED_SWITCH, printb, b) ||
+ !sendTracepointFormat(currTime, buffer, CPU_IDLE, printb, b) ||
+ !sendTracepointFormat(currTime, buffer, CPU_FREQUENCY, printb, b) ||
+ false) {
+ return false;
+ }
+
+ for (PerfTracepoint *tracepoint = mTracepoints; tracepoint != NULL; tracepoint = tracepoint->getNext()) {
+ if (tracepoint->getCounter()->isEnabled() && !sendTracepointFormat(currTime, buffer, tracepoint->getTracepoint(), printb, b)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
long long PerfDriver::getTracepointId(const char *const name, DynBuf *const printb) {
if (!printb->printf(EVENTS_PATH "/%s/id", name)) {
logg->logMessage("DynBuf::printf failed");
@@ -401,7 +501,7 @@ long long PerfDriver::getTracepointId(const char *const name, DynBuf *const prin
int64_t result;
if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) {
- logg->logMessage("DriverSource::readInt64Driver failed");
+ logg->logMessage("Unable to read tracepoint id for %s", printb->getBuf());
return -1;
}
diff --git a/daemon/PerfDriver.h b/daemon/PerfDriver.h
index 95b42bf..a38fcde 100644
--- a/daemon/PerfDriver.h
+++ b/daemon/PerfDriver.h
@@ -13,10 +13,6 @@
#include "Driver.h"
-// If debugfs is not mounted at /sys/kernel/debug, update DEBUGFS_PATH
-#define DEBUGFS_PATH "/sys/kernel/debug"
-#define EVENTS_PATH DEBUGFS_PATH "/tracing/events"
-
#define SCHED_SWITCH "sched/sched_switch"
#define CPU_IDLE "power/cpu_idle"
#define CPU_FREQUENCY "power/cpu_frequency"
@@ -24,6 +20,7 @@
class Buffer;
class DynBuf;
class PerfGroup;
+class PerfTracepoint;
class PerfDriver : public SimpleDriver {
public:
@@ -32,6 +29,7 @@ public:
bool getLegacySupport() const { return mLegacySupport; }
+ void readEvents(mxml_node_t *const xml);
bool setup();
bool summary(Buffer *const buffer);
void coreName(const uint64_t currTime, Buffer *const buffer, const int cpu);
@@ -41,6 +39,7 @@ public:
bool enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const;
void read(Buffer *const buffer, const int cpu);
+ bool sendTracepointFormats(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b);
static long long getTracepointId(const char *const name, DynBuf *const printb);
@@ -50,6 +49,7 @@ private:
bool mIsSetup;
bool mLegacySupport;
+ PerfTracepoint *mTracepoints;
// Intentionally undefined
PerfDriver(const PerfDriver &);
diff --git a/daemon/PerfGroup.cpp b/daemon/PerfGroup.cpp
index cfc62e4..9b71531 100644
--- a/daemon/PerfGroup.cpp
+++ b/daemon/PerfGroup.cpp
@@ -10,6 +10,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
@@ -23,12 +24,11 @@
#include "SessionData.h"
static const int schedSwitchKey = getEventKey();
-static const int clockKey = getEventKey();
#define DEFAULT_PEA_ARGS(pea, additionalSampleType) \
pea.size = sizeof(pea); \
/* Emit time, read_format below, group leader id, and raw tracepoint info */ \
- pea.sample_type = (gSessionData->perf.getLegacySupport() \
+ pea.sample_type = (gSessionData->mPerf.getLegacySupport() \
? PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_ID \
: PERF_SAMPLE_IDENTIFIER ) | PERF_SAMPLE_TIME | additionalSampleType; \
/* Emit emit value in group format */ \
@@ -132,7 +132,7 @@ bool PerfGroup::createCpuGroup(const uint64_t currTime, Buffer *const buffer) {
return false;
}
- if (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && doAdd(currTime, buffer, clockKey, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU) < 0) {
+ if (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && doAdd(currTime, buffer, INT_MAX-PERF_TYPE_HARDWARE, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU) < 0) {
return false;
}
@@ -152,8 +152,7 @@ bool PerfGroup::add(const uint64_t currTime, Buffer *const buffer, const int key
} else {
// Non-CPU PMUs are sampled every 100ms for Sample Rate: None and EBS, otherwise they would never be sampled
const uint64_t timeout = gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS ? 1000000000UL / gSessionData->mSampleRate : 100000000UL;
- // PERF_SAMPLE_TID | PERF_SAMPLE_IP aren't helpful on non-CPU or 'uncore' PMUs - which CPU is the right one to sample? But removing it causes problems, remove it later.
- mLeaders[effectiveType] = doAdd(currTime, buffer, clockKey, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, timeout, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_LEADER);
+ mLeaders[effectiveType] = doAdd(currTime, buffer, INT_MAX-effectiveType, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, timeout, PERF_SAMPLE_READ, PERF_GROUP_LEADER);
if (mLeaders[effectiveType] < 0) {
return false;
}
@@ -194,16 +193,12 @@ int PerfGroup::prepareCPU(const int cpu, Monitor *const monitor) {
// The core is offline
return PG_CPU_OFFLINE;
}
-#ifndef USE_STRICTER_CHECK
- continue;
-#else
if (errno == ENOENT) {
// This event doesn't apply to this CPU but should apply to a different one, ex bL
continue;
}
logg->logMessage("perf_event_open failed");
return PG_FAILURE;
-#endif
}
if (!mPb->useFd(cpu, mFds[offset])) {
@@ -236,7 +231,7 @@ static bool readAndSend(const uint64_t currTime, Buffer *const buffer, const int
int PerfGroup::onlineCPU(const uint64_t currTime, const int cpu, const bool enable, Buffer *const buffer) {
bool addedEvents = false;
- if (!gSessionData->perf.getLegacySupport()) {
+ if (!gSessionData->mPerf.getLegacySupport()) {
int idCount = 0;
int coreKeys[ARRAY_LENGTH(mKeys)];
__u64 ids[ARRAY_LENGTH(mKeys)];
diff --git a/daemon/PerfSource.cpp b/daemon/PerfSource.cpp
index 2c45de8..9f34bbd 100644
--- a/daemon/PerfSource.cpp
+++ b/daemon/PerfSource.cpp
@@ -33,20 +33,6 @@ extern Child *child;
static const int cpuIdleKey = getEventKey();
-static bool sendTracepointFormat(const uint64_t currTime, Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
- if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
- logg->logMessage("DynBuf::printf failed");
- return false;
- }
- if (!b->read(printb->getBuf())) {
- logg->logMessage("DynBuf::read failed");
- return false;
- }
- buffer->marshalFormat(currTime, b->getLength(), b->getBuf());
-
- return true;
-}
-
static void *syncFunc(void *arg)
{
struct timespec ts;
@@ -160,17 +146,14 @@ bool PerfSource::prepare() {
|| !mUEvent.init()
|| !mMonitor.add(mUEvent.getFd())
- || !sendTracepointFormat(currTime, mBuffer, SCHED_SWITCH, &printb, &b1)
-
|| (cpuIdleId = PerfDriver::getTracepointId(CPU_IDLE, &printb)) < 0
- || !sendTracepointFormat(currTime, mBuffer, CPU_IDLE, &printb, &b1)
- || !sendTracepointFormat(currTime, mBuffer, CPU_FREQUENCY, &printb, &b1)
+ || !gSessionData->mPerf.sendTracepointFormats(currTime, mBuffer, &printb, &b1)
|| !mCountersGroup.createCpuGroup(currTime, mBuffer)
|| !mCountersGroup.add(currTime, mBuffer, cpuIdleKey, PERF_TYPE_TRACEPOINT, cpuIdleId, 1, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU)
- || !gSessionData->perf.enable(currTime, &mCountersGroup, mBuffer)
+ || !gSessionData->mPerf.enable(currTime, &mCountersGroup, mBuffer)
|| 0) {
logg->logMessage("perf setup failed, are you running Linux 3.4 or later?");
return false;
@@ -194,7 +177,7 @@ bool PerfSource::prepare() {
}
// Send the summary right before the start so that the monotonic delta is close to the start time
- if (!gSessionData->perf.summary(&mSummary)) {
+ if (!gSessionData->mPerf.summary(&mSummary)) {
logg->logError("PerfDriver::summary failed");
handleException();
}
@@ -283,7 +266,7 @@ void PerfSource::run() {
mBuffer->perfCounterHeader(currTime);
for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
- gSessionData->perf.read(mBuffer, cpu);
+ gSessionData->mPerf.read(mBuffer, cpu);
}
mBuffer->perfCounterFooter(currTime);
@@ -396,7 +379,7 @@ bool PerfSource::handleUEvent(const uint64_t currTime) {
} else if (err == PG_SUCCESS) {
if (mCountersGroup.onlineCPU(currTime, cpu, true, mBuffer) > 0) {
mBuffer->perfCounterHeader(currTime);
- gSessionData->perf.read(mBuffer, cpu);
+ gSessionData->mPerf.read(mBuffer, cpu);
mBuffer->perfCounterFooter(currTime);
ret = true;
}
@@ -404,7 +387,7 @@ bool PerfSource::handleUEvent(const uint64_t currTime) {
mBuffer->commit(currTime);
gSessionData->readCpuInfo();
- gSessionData->perf.coreName(currTime, &mSummary, cpu);
+ gSessionData->mPerf.coreName(currTime, &mSummary, cpu);
mSummary.commit(currTime);
return ret;
} else if (strcmp(result.mAction, "offline") == 0) {
diff --git a/daemon/Proc.cpp b/daemon/Proc.cpp
index 4ba59b6..ffe1a78 100644
--- a/daemon/Proc.cpp
+++ b/daemon/Proc.cpp
@@ -72,12 +72,7 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti
const int err = b->readlink(printb->getBuf());
const char *image;
if (err == 0) {
- image = strrchr(b->getBuf(), '/');
- if (image == NULL) {
- image = b->getBuf();
- } else {
- ++image;
- }
+ image = b->getBuf();
} else if (err == -ENOENT) {
// readlink /proc/[pid]/exe returns ENOENT for kernel threads
image = "\0";
@@ -88,7 +83,7 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti
// Android apps are run by app_process but the cmdline is changed to reference the actual app name
// On 64-bit android app_process can be app_process32 or app_process64
- if (strncmp(image, APP_PROCESS, sizeof(APP_PROCESS) - 1) != 0) {
+ if (strstr(image, APP_PROCESS) == NULL) {
return image;
}
diff --git a/daemon/Sender.cpp b/daemon/Sender.cpp
index d7ad757..71ddfce 100644
--- a/daemon/Sender.cpp
+++ b/daemon/Sender.cpp
@@ -44,7 +44,15 @@ Sender::Sender(OlySocket* socket) {
logg->logMessage("Completed magic sequence");
}
- pthread_mutex_init(&mSendMutex, NULL);
+ pthread_mutexattr_t attr;
+ if (pthread_mutexattr_init(&attr) != 0 ||
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0 ||
+ pthread_mutex_init(&mSendMutex, &attr) != 0 ||
+ pthread_mutexattr_destroy(&attr) != 0 ||
+ false) {
+ logg->logError("Unable to setup mutex");
+ handleException();
+ }
}
Sender::~Sender() {
@@ -78,7 +86,10 @@ void Sender::writeData(const char* data, int length, int type) {
}
// Multiple threads call writeData()
- pthread_mutex_lock(&mSendMutex);
+ if (pthread_mutex_lock(&mSendMutex) != 0) {
+ logg->logError("pthread_mutex_lock failed");
+ handleException();
+ }
// Send data over the socket connection
if (mDataSocket) {
@@ -100,7 +111,7 @@ void Sender::writeData(const char* data, int length, int type) {
const int chunkSize = 100*1000 * alarmDuration / 8;
int pos = 0;
while (true) {
- mDataSocket->send((const char*)data + pos, min(length - pos, chunkSize));
+ mDataSocket->send(data + pos, min(length - pos, chunkSize));
pos += chunkSize;
if (pos >= length) {
break;
@@ -125,5 +136,8 @@ void Sender::writeData(const char* data, int length, int type) {
}
}
- pthread_mutex_unlock(&mSendMutex);
+ if (pthread_mutex_unlock(&mSendMutex) != 0) {
+ logg->logError("pthread_mutex_unlock failed");
+ handleException();
+ }
}
diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp
index 2b661bd..42917c0 100644
--- a/daemon/SessionData.cpp
+++ b/daemon/SessionData.cpp
@@ -25,33 +25,40 @@
SessionData* gSessionData = NULL;
+SharedData::SharedData() : mMaliUtgardCountersSize(0) {
+ memset(mCpuIds, -1, sizeof(mCpuIds));
+}
+
SessionData::SessionData() {
- usDrivers[0] = new HwmonDriver();
- usDrivers[1] = new FSDriver();
- usDrivers[2] = new MemInfoDriver();
- usDrivers[3] = new NetDriver();
- usDrivers[4] = new DiskIODriver();
+ mUsDrivers[0] = new HwmonDriver();
+ mUsDrivers[1] = new FSDriver();
+ mUsDrivers[2] = new MemInfoDriver();
+ mUsDrivers[3] = new NetDriver();
+ mUsDrivers[4] = new DiskIODriver();
initialize();
}
SessionData::~SessionData() {
}
+// Needed to use placement new
+inline void *operator new(size_t, void *ptr) { return ptr; }
+
void SessionData::initialize() {
+ mSharedData = (SharedData *)mmap(NULL, sizeof(*mSharedData), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (mSharedData == MAP_FAILED) {
+ logg->logError("Unable to mmap shared memory for cpuids");
+ handleException();
+ }
+ // Use placement new to construct but not allocate the object
+ new ((char *)mSharedData) SharedData();
+
mWaitingOnCommand = false;
mSessionIsActive = false;
mLocalCapture = false;
mOneShot = false;
mSentSummary = false;
mAllowCommands = false;
- const size_t cpuIdSize = sizeof(int)*NR_CPUS;
- // Share mCpuIds across all instances of gatord
- mCpuIds = (int *)mmap(NULL, cpuIdSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- if (mCpuIds == MAP_FAILED) {
- logg->logError("Unable to mmap shared memory for cpuids");
- handleException();
- }
- memset(mCpuIds, -1, cpuIdSize);
strcpy(mCoreName, CORE_NAME_UNKNOWN);
readModel();
readCpuInfo();
@@ -83,11 +90,11 @@ void SessionData::parseSessionXML(char* xmlString) {
// Set session data values - use prime numbers just below the desired value to reduce the chance of events firing at the same time
if (strcmp(session.parameters.sample_rate, "high") == 0) {
- mSampleRate = 9973; // 10000
+ mSampleRate = 10007; // 10000
} else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
- mSampleRate = 997; // 1000
+ mSampleRate = 1009; // 1000
} else if (strcmp(session.parameters.sample_rate, "low") == 0) {
- mSampleRate = 97; // 100
+ mSampleRate = 101; // 100
} else if (strcmp(session.parameters.sample_rate, "none") == 0) {
mSampleRate = 0;
} else {
@@ -126,7 +133,7 @@ void SessionData::parseSessionXML(char* xmlString) {
}
void SessionData::readModel() {
- FILE *fh = fopen("/proc/device-tree/model", "rb");
+ FILE *fh = fopen_cloexec("/proc/device-tree/model", "rb");
if (fh == NULL) {
return;
}
@@ -157,7 +164,7 @@ void SessionData::readCpuInfo() {
char temp[256]; // arbitrarily large amount
mMaxCpuId = -1;
- FILE *f = fopen("/proc/cpuinfo", "r");
+ FILE *f = fopen_cloexec("/proc/cpuinfo", "r");
if (f == NULL) {
logg->logMessage("Error opening /proc/cpuinfo\n"
"The core name in the captured xml file will be 'unknown'.");
@@ -169,17 +176,19 @@ void SessionData::readCpuInfo() {
while (fgets(temp, sizeof(temp), f)) {
const size_t len = strlen(temp);
+ if (len > 0) {
+ // Replace the line feed with a null
+ temp[len - 1] = '\0';
+ }
+
+ logg->logMessage("cpuinfo: %s", temp);
+
if (len == 1) {
// New section, clear the processor. Streamline will not know the cpus if the pre Linux 3.8 format of cpuinfo is encountered but also that no incorrect information will be transmitted.
processor = -1;
continue;
}
- if (len > 0) {
- // Replace the line feed with a null
- temp[len - 1] = '\0';
- }
-
const bool foundHardware = !foundCoreName && strstr(temp, "Hardware") != 0;
const bool foundCPUImplementer = strstr(temp, "CPU implementer") != 0;
const bool foundCPUPart = strstr(temp, "CPU part") != 0;
@@ -204,7 +213,7 @@ void SessionData::readCpuInfo() {
if (processor >= NR_CPUS) {
logg->logMessage("Too many processors, please increase NR_CPUS");
} else if (processor >= 0) {
- setImplementer(mCpuIds[processor], implementer);
+ setImplementer(mSharedData->mCpuIds[processor], implementer);
} else {
setImplementer(mMaxCpuId, implementer);
}
@@ -215,7 +224,7 @@ void SessionData::readCpuInfo() {
if (processor >= NR_CPUS) {
logg->logMessage("Too many processors, please increase NR_CPUS");
} else if (processor >= 0) {
- setPart(mCpuIds[processor], cpuId);
+ setPart(mSharedData->mCpuIds[processor], cpuId);
} else {
setPart(mMaxCpuId, cpuId);
}
@@ -229,8 +238,8 @@ void SessionData::readCpuInfo() {
// If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId
for (int i = 0; i < NR_CPUS; ++i) {
- if (mCpuIds[i] > mMaxCpuId) {
- mMaxCpuId = mCpuIds[i];
+ if (mSharedData->mCpuIds[i] > mMaxCpuId) {
+ mMaxCpuId = mSharedData->mCpuIds[i];
}
}
@@ -290,3 +299,48 @@ FILE *fopen_cloexec(const char *path, const char *mode) {
}
return fh;
}
+
+bool setNonblock(const int fd) {
+ int flags;
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags < 0) {
+ logg->logMessage("fcntl getfl failed");
+ return false;
+ }
+
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
+ logg->logMessage("fcntl setfl failed");
+ return false;
+ }
+
+ return true;
+}
+
+bool writeAll(const int fd, const void *const buf, const size_t pos) {
+ size_t written = 0;
+ while (written < pos) {
+ ssize_t bytes = write(fd, (const uint8_t *)buf + written, pos - written);
+ if (bytes <= 0) {
+ logg->logMessage("write failed");
+ return false;
+ }
+ written += bytes;
+ }
+
+ return true;
+}
+
+bool readAll(const int fd, void *const buf, const size_t count) {
+ size_t pos = 0;
+ while (pos < count) {
+ ssize_t bytes = read(fd, (uint8_t *)buf + pos, count - pos);
+ if (bytes <= 0) {
+ logg->logMessage("read failed");
+ return false;
+ }
+ pos += bytes;
+ }
+
+ return true;
+}
diff --git a/daemon/SessionData.h b/daemon/SessionData.h
index d0c8900..12432d0 100644
--- a/daemon/SessionData.h
+++ b/daemon/SessionData.h
@@ -11,14 +11,17 @@
#include <stdint.h>
+#include "AtraceDriver.h"
+#include "CCNDriver.h"
#include "Config.h"
#include "Counter.h"
+#include "ExternalDriver.h"
#include "FtraceDriver.h"
#include "KMod.h"
#include "MaliVideoDriver.h"
#include "PerfDriver.h"
-#define PROTOCOL_VERSION 21
+#define PROTOCOL_VERSION 22
// Differentiates development versions (timestamp) from release versions
#define PROTOCOL_DEV 1000
@@ -31,22 +34,41 @@ struct ImageLinkList {
struct ImageLinkList *next;
};
+class SharedData {
+public:
+ SharedData();
+
+ int mCpuIds[NR_CPUS];
+ size_t mMaliUtgardCountersSize;
+ char mMaliUtgardCounters[1<<12];
+
+private:
+ // Intentionally unimplemented
+ SharedData(const SharedData &);
+ SharedData &operator=(const SharedData &);
+};
+
class SessionData {
public:
static const size_t MAX_STRING_LEN = 80;
SessionData();
~SessionData();
- void initialize();
void parseSessionXML(char* xmlString);
void readModel();
void readCpuInfo();
- PolledDriver *usDrivers[5];
- KMod kmod;
- PerfDriver perf;
- MaliVideoDriver maliVideo;
- FtraceDriver ftraceDriver;
+ SharedData *mSharedData;
+
+ PolledDriver *mUsDrivers[5];
+ KMod mKmod;
+ PerfDriver mPerf;
+ MaliVideoDriver mMaliVideo;
+ // Intentionally above FtraceDriver as drivers are initialized in reverse order AtraceDriver references AtraceDriver
+ AtraceDriver mAtraceDriver;
+ FtraceDriver mFtraceDriver;
+ ExternalDriver mExternalDriver;
+ CCNDriver mCcnDriver;
char mCoreName[MAX_STRING_LEN];
struct ImageLinkList *mImages;
@@ -78,15 +100,16 @@ public:
int mDuration;
int mCores;
int mPageSize;
- int *mCpuIds;
int mMaxCpuId;
int mAnnotateStart;
// PMU Counters
- int mCounterOverflow;
+ char *mCountersError;
Counter mCounters[MAX_PERFORMANCE_COUNTERS];
private:
+ void initialize();
+
// Intentionally unimplemented
SessionData(const SessionData &);
SessionData &operator=(const SessionData &);
@@ -99,5 +122,8 @@ uint64_t getTime();
int getEventKey();
int pipe_cloexec(int pipefd[2]);
FILE *fopen_cloexec(const char *path, const char *mode);
+bool setNonblock(const int fd);
+bool writeAll(const int fd, const void *const buf, const size_t pos);
+bool readAll(const int fd, void *const buf, const size_t count);
#endif // SESSION_DATA_H
diff --git a/daemon/Setup.cpp b/daemon/Setup.cpp
index 7dd83ce..524a702 100644
--- a/daemon/Setup.cpp
+++ b/daemon/Setup.cpp
@@ -153,30 +153,34 @@ void update(const char *const gatorPath) {
handleException();
}
- if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(2, 6, 32)) {
- logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
- handleException();
- }
-
if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(3, 4, 0)) {
- logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device.");
+ logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
handleException();
}
if (geteuid() != 0) {
- printf(GATOR_MSG "trying sudo\n");
- execlp("sudo", "sudo", gatorPath, "-u", NULL);
- // Streamline will provide the password if needed
-
- printf(GATOR_MSG "trying su\n");
char buf[1<<10];
+ snprintf(buf, sizeof(buf),
+ "which sudo &&"
+ "("
+ "sudo -n %1$s -u ||"
+ "("
+ "echo " GATOR_MSG "trying sudo;"
+ // Streamline will provide the password
+ "sudo %1$s -u"
+ ")"
+ ") || ("
+ "echo " GATOR_MSG "trying su;"
/*
* Different versions of su handle additional -c command line options differently and expect the
* arguments in different ways. Try both ways wrapped in a shell.
*
* Then invoke another shell after su as it avoids odd failures on some Android systems
*/
- snprintf(buf, sizeof(buf), "su -c \"sh -c '%s -u'\" || su -c sh -c '%s -u'", gatorPath, gatorPath);
+ "su -c \"sh -c '%1$s -u'\" ||"
+ "su -c sh -c '%1$s -u'"
+ ")",
+ gatorPath);
execlp("sh", "sh", "-c", buf, NULL);
// Streamline will provide the password if needed
@@ -228,6 +232,11 @@ void update(const char *const gatorPath) {
umount("/dev/gator");
syscall(__NR_delete_module, "gator", O_NONBLOCK);
+ if (access("/sys/module/gator", F_OK) == 0) {
+ logg->logError(GATOR_ERROR "Unable to unload gator.ko, the gator module may be built into the kernel or gator.ko cannot be unloaded. Rebooting the device may resolve the issue.");
+ handleException();
+ }
+
rename("gatord", "gatord.old");
rename("gator.ko", "gator.ko.old");
@@ -314,8 +323,7 @@ void update(const char *const gatorPath) {
close(pipefd[1]);
const ssize_t bytes = read(pipefd[0], buf, sizeof(buf));
if (bytes > 0) {
- logg->logError("%s", buf);
- handleException();
+ printf("%s\n", buf);
}
close(pipefd[0]);
diff --git a/daemon/StreamlineSetup.cpp b/daemon/StreamlineSetup.cpp
index e37f271..66d1f4e 100644
--- a/daemon/StreamlineSetup.cpp
+++ b/daemon/StreamlineSetup.cpp
@@ -75,8 +75,8 @@ StreamlineSetup::StreamlineSetup(OlySocket* s) {
free(data);
}
- if (gSessionData->mCounterOverflow > 0) {
- logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
+ if (gSessionData->mCountersError != NULL) {
+ logg->logError("%s", gSessionData->mCountersError);
handleException();
}
}
@@ -197,7 +197,7 @@ void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
header[0] = type;
Buffer::writeLEInt(header + 1, length);
mSocket->send((char*)&header, sizeof(header));
- mSocket->send((const char*)data, length);
+ mSocket->send(data, length);
}
void StreamlineSetup::sendEvents() {
@@ -265,8 +265,8 @@ void StreamlineSetup::writeConfiguration(char* xml) {
// Re-populate gSessionData with the configuration, as it has now changed
{ ConfigurationXML configuration; }
- if (gSessionData->mCounterOverflow > 0) {
- logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
+ if (gSessionData->mCountersError != NULL) {
+ logg->logError("%s", gSessionData->mCountersError);
handleException();
}
}
diff --git a/daemon/UserSpaceSource.cpp b/daemon/UserSpaceSource.cpp
index f58f828..1036312 100644
--- a/daemon/UserSpaceSource.cpp
+++ b/daemon/UserSpaceSource.cpp
@@ -34,15 +34,15 @@ bool UserSpaceSource::prepare() {
void UserSpaceSource::run() {
prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
- for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
- gSessionData->usDrivers[i]->start();
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->mUsDrivers); ++i) {
+ gSessionData->mUsDrivers[i]->start();
}
int64_t monotonicStarted = 0;
while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
usleep(10);
- if (gSessionData->perf.isSetup()) {
+ if (gSessionData->mPerf.isSetup()) {
monotonicStarted = gSessionData->mMonotonicStarted;
} else {
if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
@@ -64,8 +64,8 @@ void UserSpaceSource::run() {
}
if (mBuffer.eventHeader(currTime)) {
- for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
- gSessionData->usDrivers[i]->read(&mBuffer);
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->mUsDrivers); ++i) {
+ gSessionData->mUsDrivers[i]->read(&mBuffer);
}
// Only check after writing all counters so that time and corresponding counters appear in the same frame
mBuffer.check(currTime);
diff --git a/daemon/defaults.xml b/daemon/defaults.xml
index 31b127c..9adde32 100644
--- a/daemon/defaults.xml
+++ b/daemon/defaults.xml
@@ -34,21 +34,21 @@
<configuration counter="ARMv7_Cortex_A17_cnt1" event="0x16"/>
<configuration counter="ARMv7_Cortex_A17_cnt2" event="0x10"/>
<configuration counter="ARMv7_Cortex_A17_cnt3" event="0x19"/>
- <configuration counter="ARM_Cortex-A53_ccnt" event="0x11"/>
- <configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/>
- <configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/>
- <configuration counter="ARM_Cortex-A53_cnt2" event="0x10"/>
- <configuration counter="ARM_Cortex-A53_cnt3" event="0x19"/>
- <configuration counter="ARM_Cortex-A57_ccnt" event="0x11"/>
- <configuration counter="ARM_Cortex-A57_cnt0" event="0x8"/>
- <configuration counter="ARM_Cortex-A57_cnt1" event="0x16"/>
- <configuration counter="ARM_Cortex-A57_cnt2" event="0x10"/>
- <configuration counter="ARM_Cortex-A57_cnt3" event="0x19"/>
- <configuration counter="ARM_Cortex-A72_ccnt" event="0x11"/>
- <configuration counter="ARM_Cortex-A72_cnt0" event="0x8"/>
- <configuration counter="ARM_Cortex-A72_cnt1" event="0x16"/>
- <configuration counter="ARM_Cortex-A72_cnt2" event="0x10"/>
- <configuration counter="ARM_Cortex-A72_cnt3" event="0x19"/>
+ <configuration counter="ARMv8_Cortex_A53_ccnt" event="0x11"/>
+ <configuration counter="ARMv8_Cortex_A53_cnt0" event="0x8"/>
+ <configuration counter="ARMv8_Cortex_A53_cnt1" event="0x16"/>
+ <configuration counter="ARMv8_Cortex_A53_cnt2" event="0x10"/>
+ <configuration counter="ARMv8_Cortex_A53_cnt3" event="0x19"/>
+ <configuration counter="ARMv8_Cortex_A57_ccnt" event="0x11"/>
+ <configuration counter="ARMv8_Cortex_A57_cnt0" event="0x8"/>
+ <configuration counter="ARMv8_Cortex_A57_cnt1" event="0x16"/>
+ <configuration counter="ARMv8_Cortex_A57_cnt2" event="0x10"/>
+ <configuration counter="ARMv8_Cortex_A57_cnt3" event="0x19"/>
+ <configuration counter="ARMv8_Cortex_A72_ccnt" event="0x11"/>
+ <configuration counter="ARMv8_Cortex_A72_cnt0" event="0x8"/>
+ <configuration counter="ARMv8_Cortex_A72_cnt1" event="0x16"/>
+ <configuration counter="ARMv8_Cortex_A72_cnt2" event="0x10"/>
+ <configuration counter="ARMv8_Cortex_A72_cnt3" event="0x19"/>
<configuration counter="Scorpion_ccnt" event="0xff"/>
<configuration counter="Scorpion_cnt0" event="0x08"/>
<configuration counter="Scorpion_cnt1" event="0x10"/>
diff --git a/daemon/events-CCI-400.xml b/daemon/events-CCI-400.xml
index 40d91e5..0dd72c0 100644
--- a/daemon/events-CCI-400.xml
+++ b/daemon/events-CCI-400.xml
@@ -41,9 +41,9 @@
<event event="0x19" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
<event event="0x1a" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase MIx_W_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
</category>
- <counter_set name="CCI_400-r1_cnt" count="4"/>
- <category name="CCI-400" counter_set="CCI_400-r1_cnt" per_cpu="no">
- <event counter="CCI_400-r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
+ <counter_set name="CCI_400_r1_cnt" count="4"/>
+ <category name="CCI-400" counter_set="CCI_400_r1_cnt" per_cpu="no">
+ <event counter="CCI_400_r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
<option_set name="Slave">
<option event_delta="0x00" name="S0" description="Slave interface 0"/>
<option event_delta="0x20" name="S1" description="Slave interface 1"/>
diff --git a/daemon/events-Cortex-A53.xml b/daemon/events-Cortex-A53.xml
index acdfe4e..c15cbd8 100644
--- a/daemon/events-Cortex-A53.xml
+++ b/daemon/events-Cortex-A53.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex-A53_cnt" count="6"/>
- <category name="Cortex-A53" counter_set="ARM_Cortex-A53_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex-A53_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv8_Cortex_A53_cnt" count="6"/>
+ <category name="Cortex-A53" counter_set="ARMv8_Cortex_A53_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv8_Cortex_A53_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Software increment. The register is incremented only on writes to the Software Increment Register."/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A57.xml b/daemon/events-Cortex-A57.xml
index 1da23e7..d1e97c3 100644
--- a/daemon/events-Cortex-A57.xml
+++ b/daemon/events-Cortex-A57.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex-A57_cnt" count="6"/>
- <category name="Cortex-A57" counter_set="ARM_Cortex-A57_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex-A57_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv8_Cortex_A57_cnt" count="6"/>
+ <category name="Cortex-A57" counter_set="ARMv8_Cortex_A57_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv8_Cortex_A57_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A72.xml b/daemon/events-Cortex-A72.xml
index 31c9cf3..683d0ae 100644
--- a/daemon/events-Cortex-A72.xml
+++ b/daemon/events-Cortex-A72.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex_A72_cnt" count="6"/>
- <category name="Cortex-A72" counter_set="ARM_Cortex_A72_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex_A72_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv8_Cortex_A72_cnt" count="6"/>
+ <category name="Cortex-A72" counter_set="ARMv8_Cortex_A72_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv8_Cortex_A72_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Mali-4xx.xml b/daemon/events-Mali-4xx.xml
index 801dd28..e2f4405 100644
--- a/daemon/events-Mali-4xx.xml
+++ b/daemon/events-Mali-4xx.xml
@@ -243,3 +243,14 @@
<event counter="ARM_Mali-4xx_SW_39" title="Geometry Statistics" name="Strip Lines" description="Number of lines passed to GLES using the mode GL_LINE_STRIP."/>
<event counter="ARM_Mali-4xx_SW_40" title="Geometry Statistics" name="Loop Lines" description="Number of lines passed to GLES using the mode GL_LINE_LOOP."/>
</category>
+ <category name="ARM_Mali-4xx_Total_alloc_pages" per_cpu="no">
+ <event counter="ARM_Mali-4xx_Total_alloc_pages" title="Mali GPU Alloc" name="pages" class="absolute" display="average" average_selection="yes" description="Total number of allocated pages"/>
+ </category>
+ <category name="Mali-4xx Session Memory usage" per_cpu="no">
+ <event counter="ARM_Mali-4xx_vertex_index_buffer" title="Mali Memory" name="Vertex and Index buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Vertex and index input"/>
+ <event counter="ARM_Mali-4xx_texture_buffer" title="Mali Memory" name="Texture buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Texture data"/>
+ <event counter="ARM_Mali-4xx_varying_buffer" title="Mali Memory" name="Varying buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Varying buffer"/>
+ <event counter="ARM_Mali-4xx_render_target" title="Mali Memory" name="Render target buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Render target buffer"/>
+ <event counter="ARM_Mali-4xx_plbu_heap" title="Mali Memory" name="Plbu heap" units="B" dclass="absolute" display="average" average_selection="yes" description="The memory to store commands from PLBU when Slave tilelist memory isn't enough"/>
+ <event counter="ARM_Mali-4xx_slave_tilelist" title="Mali Memory" name="Slave tilelist" units="B" dclass="absolute" display="average" average_selection="yes" description="Slave tilelist memory"/>
+ </category>
diff --git a/daemon/events-Mali-Midgard_hw.xml b/daemon/events-Mali-Midgard_hw.xml
index e8f0cb0..802db8b 100644
--- a/daemon/events-Mali-Midgard_hw.xml
+++ b/daemon/events-Mali-Midgard_hw.xml
@@ -44,8 +44,8 @@
<event counter="ARM_Mali-Midgard_FRAG_THREADS" title="Mali Core Threads" name="Fragment threads" description="Number of fragment threads started"/>
<event counter="ARM_Mali-Midgard_FRAG_DUMMY_THREADS" title="Mali Core Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
- <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS quads" description="Number of threads doing late ZS test"/>
- <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS quads" description="Number of threads killed by late ZS test"/>
+ <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
+ <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
<event counter="ARM_Mali-Midgard_FRAG_THREADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
<event counter="ARM_Mali-Midgard_FRAG_THREADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
diff --git a/daemon/events-Mali-T82x_hw.xml b/daemon/events-Mali-T82x_hw.xml
index 5caa464..994c8b1 100644
--- a/daemon/events-Mali-T82x_hw.xml
+++ b/daemon/events-Mali-T82x_hw.xml
@@ -1,108 +1,108 @@
-
- <category name="Mali Job Manager" per_cpu="no">
-
- <event counter="ARM_Mali-T82x_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles GPU active"/>
- <event counter="ARM_Mali-T82x_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles GPU interrupt pending"/>
- <event counter="ARM_Mali-T82x_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) active"/>
- <event counter="ARM_Mali-T82x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
- <event counter="ARM_Mali-T82x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
-
- <event counter="ARM_Mali-T82x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
- <event counter="ARM_Mali-T82x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
- <event counter="ARM_Mali-T82x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
-
- <event counter="ARM_Mali-T82x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
- <event counter="ARM_Mali-T82x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
- <event counter="ARM_Mali-T82x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
-
- </category>
-
- <category name="Mali Tiler" per_cpu="no">
-
- <event counter="ARM_Mali-T82x_TI_ACTIVE" title="Mali Tiler Cycles" name="Tiler cycles" description="Number of cycles Tiler active"/>
-
- <event counter="ARM_Mali-T82x_TI_POLYGONS" title="Mali Tiler Primitives" name="Polygons" description="Number of polygons processed"/>
- <event counter="ARM_Mali-T82x_TI_QUADS" title="Mali Tiler Primitives" name="Quads" description="Number of quads processed"/>
- <event counter="ARM_Mali-T82x_TI_TRIANGLES" title="Mali Tiler Primitives" name="Triangles" description="Number of triangles processed"/>
- <event counter="ARM_Mali-T82x_TI_LINES" title="Mali Tiler Primitives" name="Lines" description="Number of lines processed"/>
- <event counter="ARM_Mali-T82x_TI_POINTS" title="Mali Tiler Primitives" name="Points" description="Number of points processed"/>
-
- <event counter="ARM_Mali-T82x_TI_FRONT_FACING" title="Mali Tiler Culling" name="Front facing prims" description="Number of front facing primitives"/>
- <event counter="ARM_Mali-T82x_TI_BACK_FACING" title="Mali Tiler Culling" name="Back facing prims" description="Number of back facing primitives"/>
- <event counter="ARM_Mali-T82x_TI_PRIM_VISIBLE" title="Mali Tiler Culling" name="Visible prims" description="Number of visible primitives"/>
- <event counter="ARM_Mali-T82x_TI_PRIM_CULLED" title="Mali Tiler Culling" name="Culled prims" description="Number of culled primitives"/>
- <event counter="ARM_Mali-T82x_TI_PRIM_CLIPPED" title="Mali Tiler Culling" name="Clipped prims" description="Number of clipped primitives"/>
-
- </category>
-
- <category name="Mali Shader Core" per_cpu="no">
-
- <event counter="ARM_Mali-T82x_TRIPIPE_ACTIVE" title="Mali Core Cycles" name="Tripipe cycles" description="Number of cycles tripipe was active"/>
- <event counter="ARM_Mali-T82x_FRAG_ACTIVE" title="Mali Core Cycles" name="Fragment cycles" description="Number of cycles fragment processing was active"/>
- <event counter="ARM_Mali-T82x_COMPUTE_ACTIVE" title="Mali Core Cycles" name="Compute cycles" description="Number of cycles vertex\compute processing was active"/>
- <event counter="ARM_Mali-T82x_FRAG_CYCLES_NO_TILE" title="Mali Core Cycles" name="Fragment cycles waiting for tile" description="Number of cycles spent waiting for a physical tile buffer"/>
- <event counter="ARM_Mali-T82x_FRAG_CYCLES_FPKQ_ACTIVE" title="Mali Core Cycles" name="Fragment cycles pre-pipe buffer not empty" description="Number of cycles the pre-pipe queue contains quads"/>
-
- <event counter="ARM_Mali-T82x_FRAG_THREADS" title="Mali Fragment Threads" name="Fragment threads" description="Number of fragment threads started"/>
- <event counter="ARM_Mali-T82x_FRAG_DUMMY_THREADS" title="Mali Fragment Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
- <event counter="ARM_Mali-T82x_FRAG_THREADS_LZS_TEST" title="Mali Fragment Threads" name="Fragment threads doing late ZS" description="Number of threads doing late ZS test"/>
- <event counter="ARM_Mali-T82x_FRAG_THREADS_LZS_KILLED" title="Mali Fragment Threads" name="Fragment threads killed late ZS" description="Number of threads killed by late ZS test"/>
-
- <event counter="ARM_Mali-T82x_COMPUTE_TASKS" title="Mali Compute Tasks" name="Compute tasks" description="Number of compute tasks"/>
- <event counter="ARM_Mali-T82x_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads" description="Number of compute threads started"/>
-
- <event counter="ARM_Mali-T82x_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
- <event counter="ARM_Mali-T82x_FRAG_PRIMITIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
-
- <event counter="ARM_Mali-T82x_FRAG_QUADS_RAST" title="Mali Fragment Quads" name="Quads rasterized" description="Number of quads rasterized"/>
- <event counter="ARM_Mali-T82x_FRAG_QUADS_EZS_TEST" title="Mali Fragment Quads" name="Quads doing early ZS" description="Number of quads doing early ZS test"/>
- <event counter="ARM_Mali-T82x_FRAG_QUADS_EZS_KILLED" title="Mali Fragment Quads" name="Quads killed early Z" description="Number of quads killed by early ZS test"/>
-
- <event counter="ARM_Mali-T82x_FRAG_NUM_TILES" title="Mali Fragment Tasks" name="Tiles rendered" description="Number of tiles rendered"/>
- <event counter="ARM_Mali-T82x_FRAG_TRANS_ELIM" title="Mali Fragment Tasks" name="Tile writes killed by TE" description="Number of tile writes skipped by transaction elimination"/>
-
- <event counter="ARM_Mali-T82x_ARITH_WORDS" title="Mali Arithmetic Pipe" name="A instructions" description="Number of batched instructions executed by the A-pipe (normalized per pipe)"/>
-
- <event counter="ARM_Mali-T82x_LS_WORDS" title="Mali Load/Store Pipe" name="LS instructions" description="Number of instructions completed by the LS-pipe"/>
- <event counter="ARM_Mali-T82x_LS_ISSUES" title="Mali Load/Store Pipe" name="LS instruction issues" description="Number of instructions issued to the LS-pipe, including restarts"/>
-
- <event counter="ARM_Mali-T82x_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>
- <event counter="ARM_Mali-T82x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
- <event counter="ARM_Mali-T82x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
-
- <event counter="ARM_Mali-T82x_LSC_READ_OP" title="Mali Load/Store Cache Reads" name="Read operations" description="Number of read operations in the Load/Store cache"/>
- <event counter="ARM_Mali-T82x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
-
- <event counter="ARM_Mali-T82x_LSC_WRITE_OP" title="Mali Load/Store Cache Writes" name="Write operations" description="Number of write operations in the Load/Store cache"/>
- <event counter="ARM_Mali-T82x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
-
- <event counter="ARM_Mali-T82x_LSC_ATOMIC_OP" title="Mali Load/Store Cache Atomics" name="Atomic operations" description="Number of atomic operations in the Load/Store cache"/>
- <event counter="ARM_Mali-T82x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
-
- <event counter="ARM_Mali-T82x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
- <event counter="ARM_Mali-T82x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
-
- <event counter="ARM_Mali-T82x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
-
- </category>
-
- <category name="Mali L2 Cache" per_cpu="no">
-
- <event counter="ARM_Mali-T82x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>
- <event counter="ARM_Mali-T82x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
- <event counter="ARM_Mali-T82x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
-
- <event counter="ARM_Mali-T82x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
- <event counter="ARM_Mali-T82x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
- <event counter="ARM_Mali-T82x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>
-
- <event counter="ARM_Mali-T82x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
- <event counter="ARM_Mali-T82x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T82x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
- <event counter="ARM_Mali-T82x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
-
- <event counter="ARM_Mali-T82x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
- <event counter="ARM_Mali-T82x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T82x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
-
- </category>
+
+ <category name="Mali Job Manager" per_cpu="no">
+
+ <event counter="ARM_Mali-T82x_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles GPU active"/>
+ <event counter="ARM_Mali-T82x_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles GPU interrupt pending"/>
+ <event counter="ARM_Mali-T82x_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) active"/>
+ <event counter="ARM_Mali-T82x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
+ <event counter="ARM_Mali-T82x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
+
+ <event counter="ARM_Mali-T82x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
+ <event counter="ARM_Mali-T82x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
+ <event counter="ARM_Mali-T82x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-T82x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
+ <event counter="ARM_Mali-T82x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
+ <event counter="ARM_Mali-T82x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
+
+ </category>
+
+ <category name="Mali Tiler" per_cpu="no">
+
+ <event counter="ARM_Mali-T82x_TI_ACTIVE" title="Mali Tiler Cycles" name="Tiler cycles" description="Number of cycles Tiler active"/>
+
+ <event counter="ARM_Mali-T82x_TI_POLYGONS" title="Mali Tiler Primitives" name="Polygons" description="Number of polygons processed"/>
+ <event counter="ARM_Mali-T82x_TI_QUADS" title="Mali Tiler Primitives" name="Quads" description="Number of quads processed"/>
+ <event counter="ARM_Mali-T82x_TI_TRIANGLES" title="Mali Tiler Primitives" name="Triangles" description="Number of triangles processed"/>
+ <event counter="ARM_Mali-T82x_TI_LINES" title="Mali Tiler Primitives" name="Lines" description="Number of lines processed"/>
+ <event counter="ARM_Mali-T82x_TI_POINTS" title="Mali Tiler Primitives" name="Points" description="Number of points processed"/>
+
+ <event counter="ARM_Mali-T82x_TI_FRONT_FACING" title="Mali Tiler Culling" name="Front facing prims" description="Number of front facing primitives"/>
+ <event counter="ARM_Mali-T82x_TI_BACK_FACING" title="Mali Tiler Culling" name="Back facing prims" description="Number of back facing primitives"/>
+ <event counter="ARM_Mali-T82x_TI_PRIM_VISIBLE" title="Mali Tiler Culling" name="Visible prims" description="Number of visible primitives"/>
+ <event counter="ARM_Mali-T82x_TI_PRIM_CULLED" title="Mali Tiler Culling" name="Culled prims" description="Number of culled primitives"/>
+ <event counter="ARM_Mali-T82x_TI_PRIM_CLIPPED" title="Mali Tiler Culling" name="Clipped prims" description="Number of clipped primitives"/>
+
+ </category>
+
+ <category name="Mali Shader Core" per_cpu="no">
+
+ <event counter="ARM_Mali-T82x_TRIPIPE_ACTIVE" title="Mali Core Cycles" name="Tripipe cycles" description="Number of cycles tripipe was active"/>
+ <event counter="ARM_Mali-T82x_FRAG_ACTIVE" title="Mali Core Cycles" name="Fragment cycles" description="Number of cycles fragment processing was active"/>
+ <event counter="ARM_Mali-T82x_COMPUTE_ACTIVE" title="Mali Core Cycles" name="Compute cycles" description="Number of cycles vertex\compute processing was active"/>
+ <event counter="ARM_Mali-T82x_FRAG_CYCLES_NO_TILE" title="Mali Core Cycles" name="Fragment cycles waiting for tile" description="Number of cycles spent waiting for a physical tile buffer"/>
+ <event counter="ARM_Mali-T82x_FRAG_CYCLES_FPKQ_ACTIVE" title="Mali Core Cycles" name="Fragment cycles pre-pipe buffer not empty" description="Number of cycles the pre-pipe queue contains quads"/>
+
+ <event counter="ARM_Mali-T82x_FRAG_THREADS" title="Mali Fragment Threads" name="Fragment threads" description="Number of fragment threads started"/>
+ <event counter="ARM_Mali-T82x_FRAG_DUMMY_THREADS" title="Mali Fragment Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
+ <event counter="ARM_Mali-T82x_FRAG_THREADS_LZS_TEST" title="Mali Fragment Threads" name="Fragment threads doing late ZS" description="Number of threads doing late ZS test"/>
+ <event counter="ARM_Mali-T82x_FRAG_THREADS_LZS_KILLED" title="Mali Fragment Threads" name="Fragment threads killed late ZS" description="Number of threads killed by late ZS test"/>
+
+ <event counter="ARM_Mali-T82x_COMPUTE_TASKS" title="Mali Compute Tasks" name="Compute tasks" description="Number of compute tasks"/>
+ <event counter="ARM_Mali-T82x_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads" description="Number of compute threads started"/>
+
+ <event counter="ARM_Mali-T82x_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
+ <event counter="ARM_Mali-T82x_FRAG_PRIMITIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
+
+ <event counter="ARM_Mali-T82x_FRAG_QUADS_RAST" title="Mali Fragment Quads" name="Quads rasterized" description="Number of quads rasterized"/>
+ <event counter="ARM_Mali-T82x_FRAG_QUADS_EZS_TEST" title="Mali Fragment Quads" name="Quads doing early ZS" description="Number of quads doing early ZS test"/>
+ <event counter="ARM_Mali-T82x_FRAG_QUADS_EZS_KILLED" title="Mali Fragment Quads" name="Quads killed early Z" description="Number of quads killed by early ZS test"/>
+
+ <event counter="ARM_Mali-T82x_FRAG_NUM_TILES" title="Mali Fragment Tasks" name="Tiles rendered" description="Number of tiles rendered"/>
+ <event counter="ARM_Mali-T82x_FRAG_TRANS_ELIM" title="Mali Fragment Tasks" name="Tile writes killed by TE" description="Number of tile writes skipped by transaction elimination"/>
+
+ <event counter="ARM_Mali-T82x_ARITH_WORDS" title="Mali Arithmetic Pipe" name="A instructions" description="Number of batched instructions executed by the A-pipe (normalized per pipe)"/>
+
+ <event counter="ARM_Mali-T82x_LS_WORDS" title="Mali Load/Store Pipe" name="LS instructions" description="Number of instructions completed by the LS-pipe"/>
+ <event counter="ARM_Mali-T82x_LS_ISSUES" title="Mali Load/Store Pipe" name="LS instruction issues" description="Number of instructions issued to the LS-pipe, including restarts"/>
+
+ <event counter="ARM_Mali-T82x_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>
+ <event counter="ARM_Mali-T82x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
+ <event counter="ARM_Mali-T82x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
+
+ <event counter="ARM_Mali-T82x_LSC_READ_OP" title="Mali Load/Store Cache Reads" name="Read operations" description="Number of read operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T82x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T82x_LSC_WRITE_OP" title="Mali Load/Store Cache Writes" name="Write operations" description="Number of write operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T82x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T82x_LSC_ATOMIC_OP" title="Mali Load/Store Cache Atomics" name="Atomic operations" description="Number of atomic operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T82x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T82x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
+ <event counter="ARM_Mali-T82x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T82x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
+
+ </category>
+
+ <category name="Mali L2 Cache" per_cpu="no">
+
+ <event counter="ARM_Mali-T82x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T82x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
+ <event counter="ARM_Mali-T82x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
+
+ <event counter="ARM_Mali-T82x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
+ <event counter="ARM_Mali-T82x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
+ <event counter="ARM_Mali-T82x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+
+ <event counter="ARM_Mali-T82x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
+ <event counter="ARM_Mali-T82x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T82x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
+ <event counter="ARM_Mali-T82x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
+
+ <event counter="ARM_Mali-T82x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
+ <event counter="ARM_Mali-T82x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T82x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+
+ </category>
diff --git a/daemon/events-Mali-V500.xml b/daemon/events-Mali-V500.xml
index 89bc7f4..bc2d6aa 100644
--- a/daemon/events-Mali-V500.xml
+++ b/daemon/events-Mali-V500.xml
@@ -25,6 +25,6 @@
<event counter="ARM_Mali-V500_evn2" title="MVE-V500 Frames" name="Frame Processed" description="Generated when the MVE has finished processing a frame"/>
<event counter="ARM_Mali-V500_evn3" title="MVE-V500 Output" name="Output buffer received" description="Generated when an an output buffer is returned to us from the MVE"/>
<event counter="ARM_Mali-V500_evn4" title="MVE-V500 Input" name="Input buffer received" description="Generated when we an input buffer is returned to us from the MVE"/>
- <event counter="ARM_Mali-V500_act0" title="MVE-V500 Parsed" name="Activity" class="activity" activity1="activity" activity_color1="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" cores="8" description="Mali-V500 Activity"/>
- <event counter="ARM_Mali-V500_act1" title="MVE-V500 Piped" name="Activity" class="activity" activity1="activity" activity_color1="0x0000ff00" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" cores="8" description="Mali-V500 Activity"/>
+ <event counter="ARM_Mali-V500_act0" title="MVE-V500 Parsed" name="Activity" class="activity" activity1="activity" activity_color1="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" per_cpu="yes" cores="8" description="Mali-V500 Activity"/>
+ <event counter="ARM_Mali-V500_act1" title="MVE-V500 Piped" name="Activity" class="activity" activity1="activity" activity_color1="0x0000ff00" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" per_cpu="yes" cores="8" description="Mali-V500 Activity"/>
</category>
diff --git a/daemon/events-atrace.xml b/daemon/events-atrace.xml
new file mode 100644
index 0000000..432b6af
--- /dev/null
+++ b/daemon/events-atrace.xml
@@ -0,0 +1,19 @@
+ <category name="Atrace">
+ <event counter="atrace_graphics" flag="0x2" title="Atrace" name="Graphics" description="Graphics"/>
+ <event counter="atrace_input" flag="0x4" title="Atrace" name="Input" description="Input"/>
+ <event counter="atrace_view" flag="0x8" title="Atrace" name="View" description="View"/>
+ <event counter="atrace_webview" flag="0x10" title="Atrace" name="Webview" description="Webview"/>
+ <event counter="atrace_window_manager" flag="0x20" title="Atrace" name="Window manager" description="Window manager"/>
+ <event counter="atrace_activity_manager" flag="0x40" title="Atrace" name="Activity manager" description="Activity manager"/>
+ <event counter="atrace_sync_manager" flag="0x80" title="Atrace" name="Sync manager" description="Sync manager"/>
+ <event counter="atrace_audio" flag="0x100" title="Atrace" name="Audio" description="Audio"/>
+ <event counter="atrace_video" flag="0x200" title="Atrace" name="Video" description="Video"/>
+ <event counter="atrace_camera" flag="0x400" title="Atrace" name="Camera" description="Camera"/>
+ <event counter="atrace_hal" flag="0x800" title="Atrace" name="Hal" description="Hal"/>
+ <event counter="atrace_app" flag="0x1000" title="Atrace" name="App" description="App"/>
+ <event counter="atrace_resources" flag="0x2000" title="Atrace" name="Resources" description="Resources"/>
+ <event counter="atrace_dalvik" flag="0x4000" title="Atrace" name="Dalvik" description="Dalvik"/>
+ <event counter="atrace_rs" flag="0x8000" title="Atrace" name="Rs" description="Rs"/>
+ <event counter="atrace_bionic" flag="0x10000" title="Atrace" name="Bionic" description="Bionic"/>
+ <event counter="atrace_power" flag="0x20000" title="Atrace" name="Power" description="Power"/>
+ </category>
diff --git a/daemon/events-ftrace.xml b/daemon/events-ftrace.xml
index ae5529f..17fad17 100644
--- a/daemon/events-ftrace.xml
+++ b/daemon/events-ftrace.xml
@@ -1,22 +1,24 @@
<category name="Ftrace">
<!--
- Ftrace counters require Linux 3.10 or later. If you do you see ftrace counters in counter configuration, please check your Linux version.
+ ftrace counters require Linux 3.10 or later; if you do not see ftrace counters in counter configuration, please check your Linux version
'counter' attribute must start with ftrace_ and be unique
the regex item in () is the value shown or, if the parentheses are missing, the number of regex matches is counted
'enable' (optional) is the ftrace event to enable associated with the gator event
+ 'tracepoint' (optional) same meaning as enable, but will use perf instead of ftrace when using user space gator
+ 'arg' (optional) used in conjunction with 'tracepoint' to specify the value to show otherwise the number of tracepoint events is counted
-->
<!--
- <event counter="ftrace_trace_marker_numbers" title="ftrace" name="trace_marker" regex="^tracing_mark_write: ([0-9]+)\s$" class="absolute" description="Numbers written to /sys/kernel/debug/tracing/trace_marker, ex: echo 42 > /sys/kernel/debug/tracing/trace_marker"/>
+ <event counter="ftrace_trace_marker_numbers" title="ftrace" name="trace_marker" regex="^tracing_mark_write: ([0-9]+)$" class="absolute" description="Numbers written to /sys/kernel/debug/tracing/trace_marker, ex: echo 42 > /sys/kernel/debug/tracing/trace_marker"/>
-->
<!-- ftrace counters -->
- <event counter="ftrace_kmem_kmalloc" title="Kmem" name="kmalloc" regex="^kmalloc:.* bytes_alloc=([0-9]+) " enable="kmem/kmalloc" class="incident" description="Number of bytes allocated in the kernel using kmalloc"/>
- <event counter="ftrace_ext4_ext4_da_write" title="Ext4" name="ext4_da_write" regex="^ext4_da_write_end:.* len ([0-9]+) " enable="ext4/ext4_da_write_end" class="incident" description="Number of bytes written to an ext4 filesystem"/>
- <event counter="ftrace_f2fs_f2fs_write" title="F2FS" name="f2fs_write" regex="^f2fs_write_end:.* len ([0-9]+), " enable="f2fs/f2fs_write_end" class="incident" description="Number of bytes written to an f2fs filesystem"/>
- <event counter="ftrace_power_clock_set_rate" title="Power" name="clock_set_rate" regex="^clock_set_rate:.* state=([0-9]+) " enable="power/clock_set_rate" class="absolute" description="Clock rate state"/>
+ <event counter="ftrace_kmem_kmalloc" title="Kmem" name="kmalloc" regex="^kmalloc:.* bytes_alloc=([0-9]+) " tracepoint="kmem/kmalloc" arg="bytes_alloc" class="incident" description="Number of bytes allocated in the kernel using kmalloc"/>
+ <event counter="ftrace_ext4_ext4_da_write" title="Ext4" name="ext4_da_write" regex="^ext4_da_write_end:.* len ([0-9]+) " tracepoint="ext4/ext4_da_write_end" arg="len" class="incident" description="Number of bytes written to an ext4 filesystem"/>
+ <event counter="ftrace_f2fs_f2fs_write" title="F2FS" name="f2fs_write" regex="^f2fs_write_end:.* len ([0-9]+), " tracepoint="f2fs/f2fs_write_end" arg="len" class="incident" description="Number of bytes written to an f2fs filesystem"/>
+ <event counter="ftrace_power_clock_set_rate" title="Power" name="clock_set_rate" regex="^clock_set_rate:.* state=([0-9]+) " tracepoint="power/clock_set_rate" arg="state" class="absolute" description="Clock rate state"/>
<!-- counting ftrace counters -->
- <event counter="ftrace_block_block_rq_complete" title="Block" name="block_rq_complete" regex="^block_rq_complete: " enable="block/block_rq_complete" class="delta" description="Number of block IO operations completed by device driver"/>
- <event counter="ftrace_block_block_rq_issue" title="Block" name="block_rq_issue" regex="^block_rq_issue: " enable="block/block_rq_issue" class="delta" description="Number of block IO operations issued to device driver"/>
- <event counter="ftrace_power_cpu_idle" title="Power" name="cpu_idle" regex="^cpu_idle: " enable="power/cpu_idle" class="delta" description="Number of times cpu_idle is entered or exited"/>
+ <event counter="ftrace_block_block_rq_complete" title="Block" name="block_rq_complete" regex="^block_rq_complete: " tracepoint="block/block_rq_complete" class="delta" description="Number of block IO operations completed by device driver"/>
+ <event counter="ftrace_block_block_rq_issue" title="Block" name="block_rq_issue" regex="^block_rq_issue: " tracepoint="block/block_rq_issue" class="delta" description="Number of block IO operations issued to device driver"/>
+ <event counter="ftrace_power_cpu_idle" title="Power" name="cpu_idle" regex="^cpu_idle: " tracepoint="power/cpu_idle" class="delta" description="Number of times cpu_idle is entered or exited"/>
</category>
diff --git a/daemon/k/perf_event.3.12.h b/daemon/k/perf_event.3.12.h
deleted file mode 100644
index e886c48..0000000
--- a/daemon/k/perf_event.3.12.h
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * Performance events:
- *
- * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
- * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
- * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra
- *
- * Data type definitions, declarations, prototypes.
- *
- * Started by: Thomas Gleixner and Ingo Molnar
- *
- * For licencing details see kernel-base/COPYING
- */
-#ifndef _LINUX_PERF_EVENT_H
-#define _LINUX_PERF_EVENT_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <asm/byteorder.h>
-
-/*
- * User-space ABI bits:
- */
-
-/*
- * attr.type
- */
-enum perf_type_id {
- PERF_TYPE_HARDWARE = 0,
- PERF_TYPE_SOFTWARE = 1,
- PERF_TYPE_TRACEPOINT = 2,
- PERF_TYPE_HW_CACHE = 3,
- PERF_TYPE_RAW = 4,
- PERF_TYPE_BREAKPOINT = 5,
-
- PERF_TYPE_MAX, /* non-ABI */
-};
-
-/*
- * Generalized performance event event_id types, used by the
- * attr.event_id parameter of the sys_perf_event_open()
- * syscall:
- */
-enum perf_hw_id {
- /*
- * Common hardware events, generalized by the kernel:
- */
- PERF_COUNT_HW_CPU_CYCLES = 0,
- PERF_COUNT_HW_INSTRUCTIONS = 1,
- PERF_COUNT_HW_CACHE_REFERENCES = 2,
- PERF_COUNT_HW_CACHE_MISSES = 3,
- PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
- PERF_COUNT_HW_BRANCH_MISSES = 5,
- PERF_COUNT_HW_BUS_CYCLES = 6,
- PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
- PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
- PERF_COUNT_HW_REF_CPU_CYCLES = 9,
-
- PERF_COUNT_HW_MAX, /* non-ABI */
-};
-
-/*
- * Generalized hardware cache events:
- *
- * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
- * { read, write, prefetch } x
- * { accesses, misses }
- */
-enum perf_hw_cache_id {
- PERF_COUNT_HW_CACHE_L1D = 0,
- PERF_COUNT_HW_CACHE_L1I = 1,
- PERF_COUNT_HW_CACHE_LL = 2,
- PERF_COUNT_HW_CACHE_DTLB = 3,
- PERF_COUNT_HW_CACHE_ITLB = 4,
- PERF_COUNT_HW_CACHE_BPU = 5,
- PERF_COUNT_HW_CACHE_NODE = 6,
-
- PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
-};
-
-enum perf_hw_cache_op_id {
- PERF_COUNT_HW_CACHE_OP_READ = 0,
- PERF_COUNT_HW_CACHE_OP_WRITE = 1,
- PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
-
- PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
-};
-
-enum perf_hw_cache_op_result_id {
- PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
- PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
-
- PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
-};
-
-/*
- * Special "software" events provided by the kernel, even if the hardware
- * does not support performance events. These events measure various
- * physical and sw events of the kernel (and allow the profiling of them as
- * well):
- */
-enum perf_sw_ids {
- PERF_COUNT_SW_CPU_CLOCK = 0,
- PERF_COUNT_SW_TASK_CLOCK = 1,
- PERF_COUNT_SW_PAGE_FAULTS = 2,
- PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
- PERF_COUNT_SW_CPU_MIGRATIONS = 4,
- PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
- PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
- PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
- PERF_COUNT_SW_EMULATION_FAULTS = 8,
- PERF_COUNT_SW_DUMMY = 9,
-
- PERF_COUNT_SW_MAX, /* non-ABI */
-};
-
-/*
- * Bits that can be set in attr.sample_type to request information
- * in the overflow packets.
- */
-enum perf_event_sample_format {
- PERF_SAMPLE_IP = 1U << 0,
- PERF_SAMPLE_TID = 1U << 1,
- PERF_SAMPLE_TIME = 1U << 2,
- PERF_SAMPLE_ADDR = 1U << 3,
- PERF_SAMPLE_READ = 1U << 4,
- PERF_SAMPLE_CALLCHAIN = 1U << 5,
- PERF_SAMPLE_ID = 1U << 6,
- PERF_SAMPLE_CPU = 1U << 7,
- PERF_SAMPLE_PERIOD = 1U << 8,
- PERF_SAMPLE_STREAM_ID = 1U << 9,
- PERF_SAMPLE_RAW = 1U << 10,
- PERF_SAMPLE_BRANCH_STACK = 1U << 11,
- PERF_SAMPLE_REGS_USER = 1U << 12,
- PERF_SAMPLE_STACK_USER = 1U << 13,
- PERF_SAMPLE_WEIGHT = 1U << 14,
- PERF_SAMPLE_DATA_SRC = 1U << 15,
- PERF_SAMPLE_IDENTIFIER = 1U << 16,
-
- PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */
-};
-
-/*
- * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
- *
- * If the user does not pass priv level information via branch_sample_type,
- * the kernel uses the event's priv level. Branch and event priv levels do
- * not have to match. Branch priv level is checked for permissions.
- *
- * The branch types can be combined, however BRANCH_ANY covers all types
- * of branches and therefore it supersedes all the other types.
- */
-enum perf_branch_sample_type {
- PERF_SAMPLE_BRANCH_USER = 1U << 0, /* user branches */
- PERF_SAMPLE_BRANCH_KERNEL = 1U << 1, /* kernel branches */
- PERF_SAMPLE_BRANCH_HV = 1U << 2, /* hypervisor branches */
-
- PERF_SAMPLE_BRANCH_ANY = 1U << 3, /* any branch types */
- PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 4, /* any call branch */
- PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 5, /* any return branch */
- PERF_SAMPLE_BRANCH_IND_CALL = 1U << 6, /* indirect calls */
- PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */
- PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */
- PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */
-
- PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */
-};
-
-#define PERF_SAMPLE_BRANCH_PLM_ALL \
- (PERF_SAMPLE_BRANCH_USER|\
- PERF_SAMPLE_BRANCH_KERNEL|\
- PERF_SAMPLE_BRANCH_HV)
-
-/*
- * Values to determine ABI of the registers dump.
- */
-enum perf_sample_regs_abi {
- PERF_SAMPLE_REGS_ABI_NONE = 0,
- PERF_SAMPLE_REGS_ABI_32 = 1,
- PERF_SAMPLE_REGS_ABI_64 = 2,
-};
-
-/*
- * The format of the data returned by read() on a perf event fd,
- * as specified by attr.read_format:
- *
- * struct read_format {
- * { u64 value;
- * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
- * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
- * { u64 id; } && PERF_FORMAT_ID
- * } && !PERF_FORMAT_GROUP
- *
- * { u64 nr;
- * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
- * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
- * { u64 value;
- * { u64 id; } && PERF_FORMAT_ID
- * } cntr[nr];
- * } && PERF_FORMAT_GROUP
- * };
- */
-enum perf_event_read_format {
- PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
- PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
- PERF_FORMAT_ID = 1U << 2,
- PERF_FORMAT_GROUP = 1U << 3,
-
- PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
-};
-
-#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
-#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */
-#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
-#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
- /* add: sample_stack_user */
-
-/*
- * Hardware event_id to monitor via a performance monitoring event:
- */
-struct perf_event_attr {
-
- /*
- * Major type: hardware/software/tracepoint/etc.
- */
- __u32 type;
-
- /*
- * Size of the attr structure, for fwd/bwd compat.
- */
- __u32 size;
-
- /*
- * Type specific configuration information.
- */
- __u64 config;
-
- union {
- __u64 sample_period;
- __u64 sample_freq;
- };
-
- __u64 sample_type;
- __u64 read_format;
-
- __u64 disabled : 1, /* off by default */
- inherit : 1, /* children inherit it */
- pinned : 1, /* must always be on PMU */
- exclusive : 1, /* only group on PMU */
- exclude_user : 1, /* don't count user */
- exclude_kernel : 1, /* ditto kernel */
- exclude_hv : 1, /* ditto hypervisor */
- exclude_idle : 1, /* don't count when idle */
- mmap : 1, /* include mmap data */
- comm : 1, /* include comm data */
- freq : 1, /* use freq, not period */
- inherit_stat : 1, /* per task counts */
- enable_on_exec : 1, /* next exec enables */
- task : 1, /* trace fork/exit */
- watermark : 1, /* wakeup_watermark */
- /*
- * precise_ip:
- *
- * 0 - SAMPLE_IP can have arbitrary skid
- * 1 - SAMPLE_IP must have constant skid
- * 2 - SAMPLE_IP requested to have 0 skid
- * 3 - SAMPLE_IP must have 0 skid
- *
- * See also PERF_RECORD_MISC_EXACT_IP
- */
- precise_ip : 2, /* skid constraint */
- mmap_data : 1, /* non-exec mmap data */
- sample_id_all : 1, /* sample_type all events */
-
- exclude_host : 1, /* don't count in host */
- exclude_guest : 1, /* don't count in guest */
-
- exclude_callchain_kernel : 1, /* exclude kernel callchains */
- exclude_callchain_user : 1, /* exclude user callchains */
- mmap2 : 1, /* include mmap with inode data */
-
- __reserved_1 : 40;
-
- union {
- __u32 wakeup_events; /* wakeup every n events */
- __u32 wakeup_watermark; /* bytes before wakeup */
- };
-
- __u32 bp_type;
- union {
- __u64 bp_addr;
- __u64 config1; /* extension of config */
- };
- union {
- __u64 bp_len;
- __u64 config2; /* extension of config1 */
- };
- __u64 branch_sample_type; /* enum perf_branch_sample_type */
-
- /*
- * Defines set of user regs to dump on samples.
- * See asm/perf_regs.h for details.
- */
- __u64 sample_regs_user;
-
- /*
- * Defines size of the user stack to dump on samples.
- */
- __u32 sample_stack_user;
-
- /* Align to u64. */
- __u32 __reserved_2;
-};
-
-#define perf_flags(attr) (*(&(attr)->read_format + 1))
-
-/*
- * Ioctls that can be done on a perf event fd:
- */
-#define PERF_EVENT_IOC_ENABLE _IO ('$', 0)
-#define PERF_EVENT_IOC_DISABLE _IO ('$', 1)
-#define PERF_EVENT_IOC_REFRESH _IO ('$', 2)
-#define PERF_EVENT_IOC_RESET _IO ('$', 3)
-#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64)
-#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
-#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
-#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
-
-enum perf_event_ioc_flags {
- PERF_IOC_FLAG_GROUP = 1U << 0,
-};
-
-/*
- * Structure of the page that can be mapped via mmap
- */
-struct perf_event_mmap_page {
- __u32 version; /* version number of this structure */
- __u32 compat_version; /* lowest version this is compat with */
-
- /*
- * Bits needed to read the hw events in user-space.
- *
- * u32 seq, time_mult, time_shift, idx, width;
- * u64 count, enabled, running;
- * u64 cyc, time_offset;
- * s64 pmc = 0;
- *
- * do {
- * seq = pc->lock;
- * barrier()
- *
- * enabled = pc->time_enabled;
- * running = pc->time_running;
- *
- * if (pc->cap_usr_time && enabled != running) {
- * cyc = rdtsc();
- * time_offset = pc->time_offset;
- * time_mult = pc->time_mult;
- * time_shift = pc->time_shift;
- * }
- *
- * idx = pc->index;
- * count = pc->offset;
- * if (pc->cap_usr_rdpmc && idx) {
- * width = pc->pmc_width;
- * pmc = rdpmc(idx - 1);
- * }
- *
- * barrier();
- * } while (pc->lock != seq);
- *
- * NOTE: for obvious reason this only works on self-monitoring
- * processes.
- */
- __u32 lock; /* seqlock for synchronization */
- __u32 index; /* hardware event identifier */
- __s64 offset; /* add to hardware event value */
- __u64 time_enabled; /* time event active */
- __u64 time_running; /* time event on cpu */
- union {
- __u64 capabilities;
- struct {
- __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
- cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */
-
- cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */
- cap_user_time : 1, /* The time_* fields are used */
- cap_user_time_zero : 1, /* The time_zero field is used */
- cap_____res : 59;
- };
- };
-
- /*
- * If cap_usr_rdpmc this field provides the bit-width of the value
- * read using the rdpmc() or equivalent instruction. This can be used
- * to sign extend the result like:
- *
- * pmc <<= 64 - width;
- * pmc >>= 64 - width; // signed shift right
- * count += pmc;
- */
- __u16 pmc_width;
-
- /*
- * If cap_usr_time the below fields can be used to compute the time
- * delta since time_enabled (in ns) using rdtsc or similar.
- *
- * u64 quot, rem;
- * u64 delta;
- *
- * quot = (cyc >> time_shift);
- * rem = cyc & ((1 << time_shift) - 1);
- * delta = time_offset + quot * time_mult +
- * ((rem * time_mult) >> time_shift);
- *
- * Where time_offset,time_mult,time_shift and cyc are read in the
- * seqcount loop described above. This delta can then be added to
- * enabled and possible running (if idx), improving the scaling:
- *
- * enabled += delta;
- * if (idx)
- * running += delta;
- *
- * quot = count / running;
- * rem = count % running;
- * count = quot * enabled + (rem * enabled) / running;
- */
- __u16 time_shift;
- __u32 time_mult;
- __u64 time_offset;
- /*
- * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
- * from sample timestamps.
- *
- * time = timestamp - time_zero;
- * quot = time / time_mult;
- * rem = time % time_mult;
- * cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
- *
- * And vice versa:
- *
- * quot = cyc >> time_shift;
- * rem = cyc & ((1 << time_shift) - 1);
- * timestamp = time_zero + quot * time_mult +
- * ((rem * time_mult) >> time_shift);
- */
- __u64 time_zero;
- __u32 size; /* Header size up to __reserved[] fields. */
-
- /*
- * Hole for extension of the self monitor capabilities
- */
-
- __u8 __reserved[118*8+4]; /* align to 1k. */
-
- /*
- * Control data for the mmap() data buffer.
- *
- * User-space reading the @data_head value should issue an smp_rmb(),
- * after reading this value.
- *
- * When the mapping is PROT_WRITE the @data_tail value should be
- * written by userspace to reflect the last read data, after issueing
- * an smp_mb() to separate the data read from the ->data_tail store.
- * In this case the kernel will not over-write unread data.
- *
- * See perf_output_put_handle() for the data ordering.
- */
- __u64 data_head; /* head in the data section */
- __u64 data_tail; /* user-space written tail */
-};
-
-#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
-#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
-#define PERF_RECORD_MISC_KERNEL (1 << 0)
-#define PERF_RECORD_MISC_USER (2 << 0)
-#define PERF_RECORD_MISC_HYPERVISOR (3 << 0)
-#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0)
-#define PERF_RECORD_MISC_GUEST_USER (5 << 0)
-
-#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
-/*
- * Indicates that the content of PERF_SAMPLE_IP points to
- * the actual instruction that triggered the event. See also
- * perf_event_attr::precise_ip.
- */
-#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
-/*
- * Reserve the last bit to indicate some extended misc field
- */
-#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15)
-
-struct perf_event_header {
- __u32 type;
- __u16 misc;
- __u16 size;
-};
-
-enum perf_event_type {
-
- /*
- * If perf_event_attr.sample_id_all is set then all event types will
- * have the sample_type selected fields related to where/when
- * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
- * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
- * just after the perf_event_header and the fields already present for
- * the existing fields, i.e. at the end of the payload. That way a newer
- * perf.data file will be supported by older perf tools, with these new
- * optional fields being ignored.
- *
- * struct sample_id {
- * { u32 pid, tid; } && PERF_SAMPLE_TID
- * { u64 time; } && PERF_SAMPLE_TIME
- * { u64 id; } && PERF_SAMPLE_ID
- * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
- * { u32 cpu, res; } && PERF_SAMPLE_CPU
- * { u64 id; } && PERF_SAMPLE_IDENTIFIER
- * } && perf_event_attr::sample_id_all
- *
- * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The
- * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
- * relative to header.size.
- */
-
- /*
- * The MMAP events record the PROT_EXEC mappings so that we can
- * correlate userspace IPs to code. They have the following structure:
- *
- * struct {
- * struct perf_event_header header;
- *
- * u32 pid, tid;
- * u64 addr;
- * u64 len;
- * u64 pgoff;
- * char filename[];
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_MMAP = 1,
-
- /*
- * struct {
- * struct perf_event_header header;
- * u64 id;
- * u64 lost;
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_LOST = 2,
-
- /*
- * struct {
- * struct perf_event_header header;
- *
- * u32 pid, tid;
- * char comm[];
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_COMM = 3,
-
- /*
- * struct {
- * struct perf_event_header header;
- * u32 pid, ppid;
- * u32 tid, ptid;
- * u64 time;
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_EXIT = 4,
-
- /*
- * struct {
- * struct perf_event_header header;
- * u64 time;
- * u64 id;
- * u64 stream_id;
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_THROTTLE = 5,
- PERF_RECORD_UNTHROTTLE = 6,
-
- /*
- * struct {
- * struct perf_event_header header;
- * u32 pid, ppid;
- * u32 tid, ptid;
- * u64 time;
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_FORK = 7,
-
- /*
- * struct {
- * struct perf_event_header header;
- * u32 pid, tid;
- *
- * struct read_format values;
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_READ = 8,
-
- /*
- * struct {
- * struct perf_event_header header;
- *
- * #
- * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
- * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
- * # is fixed relative to header.
- * #
- *
- * { u64 id; } && PERF_SAMPLE_IDENTIFIER
- * { u64 ip; } && PERF_SAMPLE_IP
- * { u32 pid, tid; } && PERF_SAMPLE_TID
- * { u64 time; } && PERF_SAMPLE_TIME
- * { u64 addr; } && PERF_SAMPLE_ADDR
- * { u64 id; } && PERF_SAMPLE_ID
- * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
- * { u32 cpu, res; } && PERF_SAMPLE_CPU
- * { u64 period; } && PERF_SAMPLE_PERIOD
- *
- * { struct read_format values; } && PERF_SAMPLE_READ
- *
- * { u64 nr,
- * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
- *
- * #
- * # The RAW record below is opaque data wrt the ABI
- * #
- * # That is, the ABI doesn't make any promises wrt to
- * # the stability of its content, it may vary depending
- * # on event, hardware, kernel version and phase of
- * # the moon.
- * #
- * # In other words, PERF_SAMPLE_RAW contents are not an ABI.
- * #
- *
- * { u32 size;
- * char data[size];}&& PERF_SAMPLE_RAW
- *
- * { u64 nr;
- * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
- *
- * { u64 abi; # enum perf_sample_regs_abi
- * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
- *
- * { u64 size;
- * char data[size];
- * u64 dyn_size; } && PERF_SAMPLE_STACK_USER
- *
- * { u64 weight; } && PERF_SAMPLE_WEIGHT
- * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
- * };
- */
- PERF_RECORD_SAMPLE = 9,
-
- /*
- * The MMAP2 records are an augmented version of MMAP, they add
- * maj, min, ino numbers to be used to uniquely identify each mapping
- *
- * struct {
- * struct perf_event_header header;
- *
- * u32 pid, tid;
- * u64 addr;
- * u64 len;
- * u64 pgoff;
- * u32 maj;
- * u32 min;
- * u64 ino;
- * u64 ino_generation;
- * char filename[];
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_MMAP2 = 10,
-
- PERF_RECORD_MAX, /* non-ABI */
-};
-
-#define PERF_MAX_STACK_DEPTH 127
-
-enum perf_callchain_context {
- PERF_CONTEXT_HV = (__u64)-32,
- PERF_CONTEXT_KERNEL = (__u64)-128,
- PERF_CONTEXT_USER = (__u64)-512,
-
- PERF_CONTEXT_GUEST = (__u64)-2048,
- PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176,
- PERF_CONTEXT_GUEST_USER = (__u64)-2560,
-
- PERF_CONTEXT_MAX = (__u64)-4095,
-};
-
-#define PERF_FLAG_FD_NO_GROUP (1U << 0)
-#define PERF_FLAG_FD_OUTPUT (1U << 1)
-#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */
-
-union perf_mem_data_src {
- __u64 val;
- struct {
- __u64 mem_op:5, /* type of opcode */
- mem_lvl:14, /* memory hierarchy level */
- mem_snoop:5, /* snoop mode */
- mem_lock:2, /* lock instr */
- mem_dtlb:7, /* tlb access */
- mem_rsvd:31;
- };
-};
-
-/* type of opcode (load/store/prefetch,code) */
-#define PERF_MEM_OP_NA 0x01 /* not available */
-#define PERF_MEM_OP_LOAD 0x02 /* load instruction */
-#define PERF_MEM_OP_STORE 0x04 /* store instruction */
-#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */
-#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */
-#define PERF_MEM_OP_SHIFT 0
-
-/* memory hierarchy (memory level, hit or miss) */
-#define PERF_MEM_LVL_NA 0x01 /* not available */
-#define PERF_MEM_LVL_HIT 0x02 /* hit level */
-#define PERF_MEM_LVL_MISS 0x04 /* miss level */
-#define PERF_MEM_LVL_L1 0x08 /* L1 */
-#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */
-#define PERF_MEM_LVL_L2 0x20 /* L2 */
-#define PERF_MEM_LVL_L3 0x40 /* L3 */
-#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */
-#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */
-#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */
-#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */
-#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */
-#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */
-#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */
-#define PERF_MEM_LVL_SHIFT 5
-
-/* snoop mode */
-#define PERF_MEM_SNOOP_NA 0x01 /* not available */
-#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */
-#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */
-#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */
-#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */
-#define PERF_MEM_SNOOP_SHIFT 19
-
-/* locked instruction */
-#define PERF_MEM_LOCK_NA 0x01 /* not available */
-#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */
-#define PERF_MEM_LOCK_SHIFT 24
-
-/* TLB access */
-#define PERF_MEM_TLB_NA 0x01 /* not available */
-#define PERF_MEM_TLB_HIT 0x02 /* hit level */
-#define PERF_MEM_TLB_MISS 0x04 /* miss level */
-#define PERF_MEM_TLB_L1 0x08 /* L1 */
-#define PERF_MEM_TLB_L2 0x10 /* L2 */
-#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/
-#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
-#define PERF_MEM_TLB_SHIFT 26
-
-#define PERF_MEM_S(a, s) \
- (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
-
-/*
- * single taken branch record layout:
- *
- * from: source instruction (may not always be a branch insn)
- * to: branch target
- * mispred: branch target was mispredicted
- * predicted: branch target was predicted
- *
- * support for mispred, predicted is optional. In case it
- * is not supported mispred = predicted = 0.
- *
- * in_tx: running in a hardware transaction
- * abort: aborting a hardware transaction
- */
-struct perf_branch_entry {
- __u64 from;
- __u64 to;
- __u64 mispred:1, /* target mispredicted */
- predicted:1,/* target predicted */
- in_tx:1, /* in transaction */
- abort:1, /* transaction abort */
- reserved:60;
-};
-
-#endif /* _LINUX_PERF_EVENT_H */
diff --git a/daemon/k/perf_event.h b/daemon/k/perf_event.h
index e5dff8c..e886c48 120000..100644
--- a/daemon/k/perf_event.h
+++ b/daemon/k/perf_event.h
@@ -1 +1,792 @@
-perf_event.3.12.h \ No newline at end of file
+/*
+ * Performance events:
+ *
+ * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
+ * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra
+ *
+ * Data type definitions, declarations, prototypes.
+ *
+ * Started by: Thomas Gleixner and Ingo Molnar
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+#ifndef _LINUX_PERF_EVENT_H
+#define _LINUX_PERF_EVENT_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/byteorder.h>
+
+/*
+ * User-space ABI bits:
+ */
+
+/*
+ * attr.type
+ */
+enum perf_type_id {
+ PERF_TYPE_HARDWARE = 0,
+ PERF_TYPE_SOFTWARE = 1,
+ PERF_TYPE_TRACEPOINT = 2,
+ PERF_TYPE_HW_CACHE = 3,
+ PERF_TYPE_RAW = 4,
+ PERF_TYPE_BREAKPOINT = 5,
+
+ PERF_TYPE_MAX, /* non-ABI */
+};
+
+/*
+ * Generalized performance event event_id types, used by the
+ * attr.event_id parameter of the sys_perf_event_open()
+ * syscall:
+ */
+enum perf_hw_id {
+ /*
+ * Common hardware events, generalized by the kernel:
+ */
+ PERF_COUNT_HW_CPU_CYCLES = 0,
+ PERF_COUNT_HW_INSTRUCTIONS = 1,
+ PERF_COUNT_HW_CACHE_REFERENCES = 2,
+ PERF_COUNT_HW_CACHE_MISSES = 3,
+ PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
+ PERF_COUNT_HW_BRANCH_MISSES = 5,
+ PERF_COUNT_HW_BUS_CYCLES = 6,
+ PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
+ PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
+ PERF_COUNT_HW_REF_CPU_CYCLES = 9,
+
+ PERF_COUNT_HW_MAX, /* non-ABI */
+};
+
+/*
+ * Generalized hardware cache events:
+ *
+ * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
+ * { read, write, prefetch } x
+ * { accesses, misses }
+ */
+enum perf_hw_cache_id {
+ PERF_COUNT_HW_CACHE_L1D = 0,
+ PERF_COUNT_HW_CACHE_L1I = 1,
+ PERF_COUNT_HW_CACHE_LL = 2,
+ PERF_COUNT_HW_CACHE_DTLB = 3,
+ PERF_COUNT_HW_CACHE_ITLB = 4,
+ PERF_COUNT_HW_CACHE_BPU = 5,
+ PERF_COUNT_HW_CACHE_NODE = 6,
+
+ PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
+};
+
+enum perf_hw_cache_op_id {
+ PERF_COUNT_HW_CACHE_OP_READ = 0,
+ PERF_COUNT_HW_CACHE_OP_WRITE = 1,
+ PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
+
+ PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
+};
+
+enum perf_hw_cache_op_result_id {
+ PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
+ PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
+
+ PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
+};
+
+/*
+ * Special "software" events provided by the kernel, even if the hardware
+ * does not support performance events. These events measure various
+ * physical and sw events of the kernel (and allow the profiling of them as
+ * well):
+ */
+enum perf_sw_ids {
+ PERF_COUNT_SW_CPU_CLOCK = 0,
+ PERF_COUNT_SW_TASK_CLOCK = 1,
+ PERF_COUNT_SW_PAGE_FAULTS = 2,
+ PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
+ PERF_COUNT_SW_CPU_MIGRATIONS = 4,
+ PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
+ PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
+ PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
+ PERF_COUNT_SW_EMULATION_FAULTS = 8,
+ PERF_COUNT_SW_DUMMY = 9,
+
+ PERF_COUNT_SW_MAX, /* non-ABI */
+};
+
+/*
+ * Bits that can be set in attr.sample_type to request information
+ * in the overflow packets.
+ */
+enum perf_event_sample_format {
+ PERF_SAMPLE_IP = 1U << 0,
+ PERF_SAMPLE_TID = 1U << 1,
+ PERF_SAMPLE_TIME = 1U << 2,
+ PERF_SAMPLE_ADDR = 1U << 3,
+ PERF_SAMPLE_READ = 1U << 4,
+ PERF_SAMPLE_CALLCHAIN = 1U << 5,
+ PERF_SAMPLE_ID = 1U << 6,
+ PERF_SAMPLE_CPU = 1U << 7,
+ PERF_SAMPLE_PERIOD = 1U << 8,
+ PERF_SAMPLE_STREAM_ID = 1U << 9,
+ PERF_SAMPLE_RAW = 1U << 10,
+ PERF_SAMPLE_BRANCH_STACK = 1U << 11,
+ PERF_SAMPLE_REGS_USER = 1U << 12,
+ PERF_SAMPLE_STACK_USER = 1U << 13,
+ PERF_SAMPLE_WEIGHT = 1U << 14,
+ PERF_SAMPLE_DATA_SRC = 1U << 15,
+ PERF_SAMPLE_IDENTIFIER = 1U << 16,
+
+ PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */
+};
+
+/*
+ * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
+ *
+ * If the user does not pass priv level information via branch_sample_type,
+ * the kernel uses the event's priv level. Branch and event priv levels do
+ * not have to match. Branch priv level is checked for permissions.
+ *
+ * The branch types can be combined, however BRANCH_ANY covers all types
+ * of branches and therefore it supersedes all the other types.
+ */
+enum perf_branch_sample_type {
+ PERF_SAMPLE_BRANCH_USER = 1U << 0, /* user branches */
+ PERF_SAMPLE_BRANCH_KERNEL = 1U << 1, /* kernel branches */
+ PERF_SAMPLE_BRANCH_HV = 1U << 2, /* hypervisor branches */
+
+ PERF_SAMPLE_BRANCH_ANY = 1U << 3, /* any branch types */
+ PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 4, /* any call branch */
+ PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 5, /* any return branch */
+ PERF_SAMPLE_BRANCH_IND_CALL = 1U << 6, /* indirect calls */
+ PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */
+ PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */
+ PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */
+
+ PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */
+};
+
+#define PERF_SAMPLE_BRANCH_PLM_ALL \
+ (PERF_SAMPLE_BRANCH_USER|\
+ PERF_SAMPLE_BRANCH_KERNEL|\
+ PERF_SAMPLE_BRANCH_HV)
+
+/*
+ * Values to determine ABI of the registers dump.
+ */
+enum perf_sample_regs_abi {
+ PERF_SAMPLE_REGS_ABI_NONE = 0,
+ PERF_SAMPLE_REGS_ABI_32 = 1,
+ PERF_SAMPLE_REGS_ABI_64 = 2,
+};
+
+/*
+ * The format of the data returned by read() on a perf event fd,
+ * as specified by attr.read_format:
+ *
+ * struct read_format {
+ * { u64 value;
+ * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
+ * { u64 id; } && PERF_FORMAT_ID
+ * } && !PERF_FORMAT_GROUP
+ *
+ * { u64 nr;
+ * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
+ * { u64 value;
+ * { u64 id; } && PERF_FORMAT_ID
+ * } cntr[nr];
+ * } && PERF_FORMAT_GROUP
+ * };
+ */
+enum perf_event_read_format {
+ PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
+ PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
+ PERF_FORMAT_ID = 1U << 2,
+ PERF_FORMAT_GROUP = 1U << 3,
+
+ PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
+};
+
+#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
+#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */
+#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
+#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
+ /* add: sample_stack_user */
+
+/*
+ * Hardware event_id to monitor via a performance monitoring event:
+ */
+struct perf_event_attr {
+
+ /*
+ * Major type: hardware/software/tracepoint/etc.
+ */
+ __u32 type;
+
+ /*
+ * Size of the attr structure, for fwd/bwd compat.
+ */
+ __u32 size;
+
+ /*
+ * Type specific configuration information.
+ */
+ __u64 config;
+
+ union {
+ __u64 sample_period;
+ __u64 sample_freq;
+ };
+
+ __u64 sample_type;
+ __u64 read_format;
+
+ __u64 disabled : 1, /* off by default */
+ inherit : 1, /* children inherit it */
+ pinned : 1, /* must always be on PMU */
+ exclusive : 1, /* only group on PMU */
+ exclude_user : 1, /* don't count user */
+ exclude_kernel : 1, /* ditto kernel */
+ exclude_hv : 1, /* ditto hypervisor */
+ exclude_idle : 1, /* don't count when idle */
+ mmap : 1, /* include mmap data */
+ comm : 1, /* include comm data */
+ freq : 1, /* use freq, not period */
+ inherit_stat : 1, /* per task counts */
+ enable_on_exec : 1, /* next exec enables */
+ task : 1, /* trace fork/exit */
+ watermark : 1, /* wakeup_watermark */
+ /*
+ * precise_ip:
+ *
+ * 0 - SAMPLE_IP can have arbitrary skid
+ * 1 - SAMPLE_IP must have constant skid
+ * 2 - SAMPLE_IP requested to have 0 skid
+ * 3 - SAMPLE_IP must have 0 skid
+ *
+ * See also PERF_RECORD_MISC_EXACT_IP
+ */
+ precise_ip : 2, /* skid constraint */
+ mmap_data : 1, /* non-exec mmap data */
+ sample_id_all : 1, /* sample_type all events */
+
+ exclude_host : 1, /* don't count in host */
+ exclude_guest : 1, /* don't count in guest */
+
+ exclude_callchain_kernel : 1, /* exclude kernel callchains */
+ exclude_callchain_user : 1, /* exclude user callchains */
+ mmap2 : 1, /* include mmap with inode data */
+
+ __reserved_1 : 40;
+
+ union {
+ __u32 wakeup_events; /* wakeup every n events */
+ __u32 wakeup_watermark; /* bytes before wakeup */
+ };
+
+ __u32 bp_type;
+ union {
+ __u64 bp_addr;
+ __u64 config1; /* extension of config */
+ };
+ union {
+ __u64 bp_len;
+ __u64 config2; /* extension of config1 */
+ };
+ __u64 branch_sample_type; /* enum perf_branch_sample_type */
+
+ /*
+ * Defines set of user regs to dump on samples.
+ * See asm/perf_regs.h for details.
+ */
+ __u64 sample_regs_user;
+
+ /*
+ * Defines size of the user stack to dump on samples.
+ */
+ __u32 sample_stack_user;
+
+ /* Align to u64. */
+ __u32 __reserved_2;
+};
+
+#define perf_flags(attr) (*(&(attr)->read_format + 1))
+
+/*
+ * Ioctls that can be done on a perf event fd:
+ */
+#define PERF_EVENT_IOC_ENABLE _IO ('$', 0)
+#define PERF_EVENT_IOC_DISABLE _IO ('$', 1)
+#define PERF_EVENT_IOC_REFRESH _IO ('$', 2)
+#define PERF_EVENT_IOC_RESET _IO ('$', 3)
+#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64)
+#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
+#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
+#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
+
+enum perf_event_ioc_flags {
+ PERF_IOC_FLAG_GROUP = 1U << 0,
+};
+
+/*
+ * Structure of the page that can be mapped via mmap
+ */
+struct perf_event_mmap_page {
+ __u32 version; /* version number of this structure */
+ __u32 compat_version; /* lowest version this is compat with */
+
+ /*
+ * Bits needed to read the hw events in user-space.
+ *
+ * u32 seq, time_mult, time_shift, idx, width;
+ * u64 count, enabled, running;
+ * u64 cyc, time_offset;
+ * s64 pmc = 0;
+ *
+ * do {
+ * seq = pc->lock;
+ * barrier()
+ *
+ * enabled = pc->time_enabled;
+ * running = pc->time_running;
+ *
+ * if (pc->cap_usr_time && enabled != running) {
+ * cyc = rdtsc();
+ * time_offset = pc->time_offset;
+ * time_mult = pc->time_mult;
+ * time_shift = pc->time_shift;
+ * }
+ *
+ * idx = pc->index;
+ * count = pc->offset;
+ * if (pc->cap_usr_rdpmc && idx) {
+ * width = pc->pmc_width;
+ * pmc = rdpmc(idx - 1);
+ * }
+ *
+ * barrier();
+ * } while (pc->lock != seq);
+ *
+ * NOTE: for obvious reason this only works on self-monitoring
+ * processes.
+ */
+ __u32 lock; /* seqlock for synchronization */
+ __u32 index; /* hardware event identifier */
+ __s64 offset; /* add to hardware event value */
+ __u64 time_enabled; /* time event active */
+ __u64 time_running; /* time event on cpu */
+ union {
+ __u64 capabilities;
+ struct {
+ __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
+ cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */
+
+ cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */
+ cap_user_time : 1, /* The time_* fields are used */
+ cap_user_time_zero : 1, /* The time_zero field is used */
+ cap_____res : 59;
+ };
+ };
+
+ /*
+ * If cap_usr_rdpmc this field provides the bit-width of the value
+ * read using the rdpmc() or equivalent instruction. This can be used
+ * to sign extend the result like:
+ *
+ * pmc <<= 64 - width;
+ * pmc >>= 64 - width; // signed shift right
+ * count += pmc;
+ */
+ __u16 pmc_width;
+
+ /*
+ * If cap_usr_time the below fields can be used to compute the time
+ * delta since time_enabled (in ns) using rdtsc or similar.
+ *
+ * u64 quot, rem;
+ * u64 delta;
+ *
+ * quot = (cyc >> time_shift);
+ * rem = cyc & ((1 << time_shift) - 1);
+ * delta = time_offset + quot * time_mult +
+ * ((rem * time_mult) >> time_shift);
+ *
+ * Where time_offset,time_mult,time_shift and cyc are read in the
+ * seqcount loop described above. This delta can then be added to
+ * enabled and possible running (if idx), improving the scaling:
+ *
+ * enabled += delta;
+ * if (idx)
+ * running += delta;
+ *
+ * quot = count / running;
+ * rem = count % running;
+ * count = quot * enabled + (rem * enabled) / running;
+ */
+ __u16 time_shift;
+ __u32 time_mult;
+ __u64 time_offset;
+ /*
+ * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
+ * from sample timestamps.
+ *
+ * time = timestamp - time_zero;
+ * quot = time / time_mult;
+ * rem = time % time_mult;
+ * cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
+ *
+ * And vice versa:
+ *
+ * quot = cyc >> time_shift;
+ * rem = cyc & ((1 << time_shift) - 1);
+ * timestamp = time_zero + quot * time_mult +
+ * ((rem * time_mult) >> time_shift);
+ */
+ __u64 time_zero;
+ __u32 size; /* Header size up to __reserved[] fields. */
+
+ /*
+ * Hole for extension of the self monitor capabilities
+ */
+
+ __u8 __reserved[118*8+4]; /* align to 1k. */
+
+ /*
+ * Control data for the mmap() data buffer.
+ *
+ * User-space reading the @data_head value should issue an smp_rmb(),
+ * after reading this value.
+ *
+ * When the mapping is PROT_WRITE the @data_tail value should be
+ * written by userspace to reflect the last read data, after issueing
+ * an smp_mb() to separate the data read from the ->data_tail store.
+ * In this case the kernel will not over-write unread data.
+ *
+ * See perf_output_put_handle() for the data ordering.
+ */
+ __u64 data_head; /* head in the data section */
+ __u64 data_tail; /* user-space written tail */
+};
+
+#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
+#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
+#define PERF_RECORD_MISC_KERNEL (1 << 0)
+#define PERF_RECORD_MISC_USER (2 << 0)
+#define PERF_RECORD_MISC_HYPERVISOR (3 << 0)
+#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0)
+#define PERF_RECORD_MISC_GUEST_USER (5 << 0)
+
+#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
+/*
+ * Indicates that the content of PERF_SAMPLE_IP points to
+ * the actual instruction that triggered the event. See also
+ * perf_event_attr::precise_ip.
+ */
+#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
+/*
+ * Reserve the last bit to indicate some extended misc field
+ */
+#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15)
+
+struct perf_event_header {
+ __u32 type;
+ __u16 misc;
+ __u16 size;
+};
+
+enum perf_event_type {
+
+ /*
+ * If perf_event_attr.sample_id_all is set then all event types will
+ * have the sample_type selected fields related to where/when
+ * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
+ * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
+ * just after the perf_event_header and the fields already present for
+ * the existing fields, i.e. at the end of the payload. That way a newer
+ * perf.data file will be supported by older perf tools, with these new
+ * optional fields being ignored.
+ *
+ * struct sample_id {
+ * { u32 pid, tid; } && PERF_SAMPLE_TID
+ * { u64 time; } && PERF_SAMPLE_TIME
+ * { u64 id; } && PERF_SAMPLE_ID
+ * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
+ * { u32 cpu, res; } && PERF_SAMPLE_CPU
+ * { u64 id; } && PERF_SAMPLE_IDENTIFIER
+ * } && perf_event_attr::sample_id_all
+ *
+ * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The
+ * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
+ * relative to header.size.
+ */
+
+ /*
+ * The MMAP events record the PROT_EXEC mappings so that we can
+ * correlate userspace IPs to code. They have the following structure:
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * char filename[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_MMAP = 1,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u64 id;
+ * u64 lost;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_LOST = 2,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * char comm[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_COMM = 3,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, ppid;
+ * u32 tid, ptid;
+ * u64 time;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_EXIT = 4,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u64 time;
+ * u64 id;
+ * u64 stream_id;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_THROTTLE = 5,
+ PERF_RECORD_UNTHROTTLE = 6,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, ppid;
+ * u32 tid, ptid;
+ * u64 time;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_FORK = 7,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, tid;
+ *
+ * struct read_format values;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_READ = 8,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ *
+ * #
+ * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
+ * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
+ * # is fixed relative to header.
+ * #
+ *
+ * { u64 id; } && PERF_SAMPLE_IDENTIFIER
+ * { u64 ip; } && PERF_SAMPLE_IP
+ * { u32 pid, tid; } && PERF_SAMPLE_TID
+ * { u64 time; } && PERF_SAMPLE_TIME
+ * { u64 addr; } && PERF_SAMPLE_ADDR
+ * { u64 id; } && PERF_SAMPLE_ID
+ * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
+ * { u32 cpu, res; } && PERF_SAMPLE_CPU
+ * { u64 period; } && PERF_SAMPLE_PERIOD
+ *
+ * { struct read_format values; } && PERF_SAMPLE_READ
+ *
+ * { u64 nr,
+ * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
+ *
+ * #
+ * # The RAW record below is opaque data wrt the ABI
+ * #
+ * # That is, the ABI doesn't make any promises wrt to
+ * # the stability of its content, it may vary depending
+ * # on event, hardware, kernel version and phase of
+ * # the moon.
+ * #
+ * # In other words, PERF_SAMPLE_RAW contents are not an ABI.
+ * #
+ *
+ * { u32 size;
+ * char data[size];}&& PERF_SAMPLE_RAW
+ *
+ * { u64 nr;
+ * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+ *
+ * { u64 abi; # enum perf_sample_regs_abi
+ * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
+ *
+ * { u64 size;
+ * char data[size];
+ * u64 dyn_size; } && PERF_SAMPLE_STACK_USER
+ *
+ * { u64 weight; } && PERF_SAMPLE_WEIGHT
+ * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
+ * };
+ */
+ PERF_RECORD_SAMPLE = 9,
+
+ /*
+ * The MMAP2 records are an augmented version of MMAP, they add
+ * maj, min, ino numbers to be used to uniquely identify each mapping
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * u32 maj;
+ * u32 min;
+ * u64 ino;
+ * u64 ino_generation;
+ * char filename[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_MMAP2 = 10,
+
+ PERF_RECORD_MAX, /* non-ABI */
+};
+
+#define PERF_MAX_STACK_DEPTH 127
+
+enum perf_callchain_context {
+ PERF_CONTEXT_HV = (__u64)-32,
+ PERF_CONTEXT_KERNEL = (__u64)-128,
+ PERF_CONTEXT_USER = (__u64)-512,
+
+ PERF_CONTEXT_GUEST = (__u64)-2048,
+ PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176,
+ PERF_CONTEXT_GUEST_USER = (__u64)-2560,
+
+ PERF_CONTEXT_MAX = (__u64)-4095,
+};
+
+#define PERF_FLAG_FD_NO_GROUP (1U << 0)
+#define PERF_FLAG_FD_OUTPUT (1U << 1)
+#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */
+
+union perf_mem_data_src {
+ __u64 val;
+ struct {
+ __u64 mem_op:5, /* type of opcode */
+ mem_lvl:14, /* memory hierarchy level */
+ mem_snoop:5, /* snoop mode */
+ mem_lock:2, /* lock instr */
+ mem_dtlb:7, /* tlb access */
+ mem_rsvd:31;
+ };
+};
+
+/* type of opcode (load/store/prefetch,code) */
+#define PERF_MEM_OP_NA 0x01 /* not available */
+#define PERF_MEM_OP_LOAD 0x02 /* load instruction */
+#define PERF_MEM_OP_STORE 0x04 /* store instruction */
+#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */
+#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */
+#define PERF_MEM_OP_SHIFT 0
+
+/* memory hierarchy (memory level, hit or miss) */
+#define PERF_MEM_LVL_NA 0x01 /* not available */
+#define PERF_MEM_LVL_HIT 0x02 /* hit level */
+#define PERF_MEM_LVL_MISS 0x04 /* miss level */
+#define PERF_MEM_LVL_L1 0x08 /* L1 */
+#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */
+#define PERF_MEM_LVL_L2 0x20 /* L2 */
+#define PERF_MEM_LVL_L3 0x40 /* L3 */
+#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */
+#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */
+#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */
+#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */
+#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */
+#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */
+#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */
+#define PERF_MEM_LVL_SHIFT 5
+
+/* snoop mode */
+#define PERF_MEM_SNOOP_NA 0x01 /* not available */
+#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */
+#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */
+#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */
+#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */
+#define PERF_MEM_SNOOP_SHIFT 19
+
+/* locked instruction */
+#define PERF_MEM_LOCK_NA 0x01 /* not available */
+#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */
+#define PERF_MEM_LOCK_SHIFT 24
+
+/* TLB access */
+#define PERF_MEM_TLB_NA 0x01 /* not available */
+#define PERF_MEM_TLB_HIT 0x02 /* hit level */
+#define PERF_MEM_TLB_MISS 0x04 /* miss level */
+#define PERF_MEM_TLB_L1 0x08 /* L1 */
+#define PERF_MEM_TLB_L2 0x10 /* L2 */
+#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/
+#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
+#define PERF_MEM_TLB_SHIFT 26
+
+#define PERF_MEM_S(a, s) \
+ (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
+
+/*
+ * single taken branch record layout:
+ *
+ * from: source instruction (may not always be a branch insn)
+ * to: branch target
+ * mispred: branch target was mispredicted
+ * predicted: branch target was predicted
+ *
+ * support for mispred, predicted is optional. In case it
+ * is not supported mispred = predicted = 0.
+ *
+ * in_tx: running in a hardware transaction
+ * abort: aborting a hardware transaction
+ */
+struct perf_branch_entry {
+ __u64 from;
+ __u64 to;
+ __u64 mispred:1, /* target mispredicted */
+ predicted:1,/* target predicted */
+ in_tx:1, /* in transaction */
+ abort:1, /* transaction abort */
+ reserved:60;
+};
+
+#endif /* _LINUX_PERF_EVENT_H */
diff --git a/daemon/main.cpp b/daemon/main.cpp
index c68a892..95e179e 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -20,8 +20,8 @@
#include <unistd.h>
#include "AnnotateListener.h"
-#include "CCNDriver.h"
#include "Child.h"
+#include "DriverSource.h"
#include "EventsXML.h"
#include "Logging.h"
#include "Monitor.h"
@@ -297,15 +297,10 @@ static bool setupFilesystem(char* module) {
}
// Load driver
- bool success = init_module(location);
- if (!success) {
- logg->logMessage("init_module failed, trying insmod");
- snprintf(command, sizeof(command), "insmod %s >/dev/null 2>&1", location);
- if (system(command) != 0) {
- logg->logMessage("Unable to load gator.ko driver with command: %s", command);
- logg->logError("Unable to load (insmod) gator.ko driver:\n >>> gator.ko must be built against the current kernel version & configuration\n >>> See dmesg for more details");
- handleException();
- }
+ if (!init_module(location)) {
+ logg->logMessage("Unable to load gator.ko driver with command: %s", command);
+ logg->logError("Unable to load (insmod) gator.ko driver:\n >>> gator.ko must be built against the current kernel version & configuration\n >>> See dmesg for more details");
+ handleException();
}
if (mountGatorFS() == -1) {
@@ -323,10 +318,7 @@ static int shutdownFilesystem() {
}
if (driverRunningAtStart == false) {
if (syscall(__NR_delete_module, "gator", O_NONBLOCK) != 0) {
- logg->logMessage("delete_module failed, trying rmmod");
- if (system("rmmod gator >/dev/null 2>&1") != 0) {
- return -1;
- }
+ return -1;
}
}
@@ -496,16 +488,13 @@ int main(int argc, char** argv) {
// e.g. it may not be the group leader when launched as 'sudo gatord'
setsid();
- // Set up global thread-safe logging
+ // Set up global thread-safe logging
logg = new Logging(hasDebugFlag(argc, argv));
// Global data class
gSessionData = new SessionData();
// Set up global utility class
util = new OlyUtility();
- // Initialize drivers
- new CCNDriver();
-
prctl(PR_SET_NAME, (unsigned long)&"gatord-main", 0, 0, 0);
pthread_mutex_init(&numSessions_mutex, NULL);
@@ -535,9 +524,11 @@ int main(int argc, char** argv) {
}
// Call before setting up the SIGCHLD handler, as system() spawns child processes
- if (!setupFilesystem(cmdline.module)) {
+ if (setupFilesystem(cmdline.module)) {
+ DriverSource::checkVersion();
+ } else {
logg->logMessage("Unable to set up gatorfs, trying perf");
- if (!gSessionData->perf.setup()) {
+ if (!gSessionData->mPerf.setup()) {
logg->logError(
"Unable to locate gator.ko driver:\n"
" >>> gator.ko should be co-located with gatord in the same directory\n"
diff --git a/daemon/notify/COPYING b/daemon/notify/COPYING
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/daemon/notify/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/daemon/notify/Makefile b/daemon/notify/Makefile
new file mode 100644
index 0000000..0d8f041
--- /dev/null
+++ b/daemon/notify/Makefile
@@ -0,0 +1,24 @@
+ifneq ($(SDKDIR),)
+
+# Find the oldest SDK Platform installed >= 16
+SDK_PLATFORM := $(shell ls -d $(SDKDIR)/platforms/android-1[6-9] $(SDKDIR)/platforms/android-[2-9][0-9] | head -1)
+# Find the newest SDK Build-tools
+SDK_BUILD_TOOLS := $(shell ls -d $(SDKDIR)/build-tools/* | tail -1)
+
+all: notify.dex
+
+notify.dex: Notify.java
+ javac -cp $(SDK_PLATFORM)/data/layoutlib.jar -source 1.6 -target 1.6 $^
+ $(SDK_BUILD_TOOLS)/dx --dex --output=$@ $(^:%.java=%.class)
+
+else
+
+all:
+ $(error Please specify SDKDIR as the location to the Android SDK)
+
+endif
+
+.PHONY: clean
+
+clean:
+ rm -f *~ *.class *.dex
diff --git a/daemon/notify/Notify.java b/daemon/notify/Notify.java
new file mode 100644
index 0000000..9702451
--- /dev/null
+++ b/daemon/notify/Notify.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) ARM Limited 2015. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+public class Notify {
+ public static void main(String[] args) throws RemoteException {
+ for (String service : ServiceManager.listServices()) {
+ IBinder b = ServiceManager.checkService(service);
+ if (b != null) {
+ Parcel p = null;
+ try {
+ p = Parcel.obtain();
+ b.transact(IBinder.SYSPROPS_TRANSACTION, p, null, 0);
+ } finally {
+ if (p != null) {
+ p.recycle();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/driver/Makefile b/driver/Makefile
index d14e2a0..4f97237 100644
--- a/driver/Makefile
+++ b/driver/Makefile
@@ -77,7 +77,7 @@ clean-files := gator_src_md5.h
silent_chk_events.h = :
$(obj)/gator_src_md5.h: FORCE
@$($(quiet)chk_events.h)
- $(Q)cd $(srctree) && cd $(src) ; $(CONFIG_SHELL) -c "echo 'static char *gator_src_md5 = \"'\`ls *.c *.h mali/*.h | grep -Ev '^(gator_src_md5\.c|gator\.mod\.c)$$' | LC_ALL=C sort | xargs cat | md5sum | cut -b 1-32\`'\";'" > $(abspath $@)
+ $(Q)cd $(srctree) && cd $(src) ; $(CONFIG_SHELL) -c "echo 'static char *gator_src_md5 = \"'\`ls *.c *.h mali/*.h | grep -Ev '^(gator_src_md5\.h|gator\.mod\.c)$$' | LC_ALL=C sort | xargs cat | md5sum | cut -b 1-32\`'\";'" > $(abspath $@)
else
diff --git a/driver/gator.h b/driver/gator.h
index 202eb41..50b0180 100644
--- a/driver/gator.h
+++ b/driver/gator.h
@@ -77,8 +77,8 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
/******************************************************************************
* Tracepoints
******************************************************************************/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
-# error Kernels prior to 2.6.32 not supported
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
+# error Kernels prior to 3.4.0 not supported. DS-5 v5.21 and earlier supported 2.6.32 and later.
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
# define GATOR_DEFINE_PROBE(probe_name, proto) \
static void probe_##probe_name(PARAMS(proto))
@@ -103,10 +103,15 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
tracepoint_probe_unregister(gator_tracepoint_##probe_name, probe_##probe_name, NULL)
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+#define setup_deferrable_timer_on_stack setup_timer
+#endif
+
/******************************************************************************
* Events
******************************************************************************/
struct gator_interface {
+ const char *const name;
/* Complementary function to init */
void (*shutdown)(void);
int (*create_files)(struct super_block *sb, struct dentry *root);
@@ -120,11 +125,12 @@ struct gator_interface {
/* called in process context but may not be running on core 'cpu' */
void (*offline_dispatch)(int cpu, bool migrate);
int (*read)(int **buffer, bool sched_switch);
- int (*read64)(long long **buffer);
+ int (*read64)(long long **buffer, bool sched_switch);
int (*read_proc)(long long **buffer, struct task_struct *);
struct list_head list;
};
+u64 gator_get_time(void);
int gator_events_install(struct gator_interface *interface);
int gator_events_get_key(void);
u32 gator_cpuid(void);
diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c
index 9bd4c8b..7636726 100644
--- a/driver/gator_cookies.c
+++ b/driver/gator_cookies.c
@@ -7,6 +7,29 @@
*
*/
+#include <linux/mount.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+
+struct mount {
+ struct mount *mnt_parent;
+ struct dentry *mnt_mountpoint;
+ struct vfsmount mnt;
+};
+
+static inline struct mount *real_mount(struct vfsmount *mnt)
+{
+ return container_of(mnt, struct mount, mnt);
+}
+
+#define GET_MNT_ROOT(mount) (mount)->mnt.mnt_root
+
+#else
+
+#define GET_MNT_ROOT(mount) (mount)->mnt_root
+
+#endif
+
/* must be power of 2 */
#define COOKIEMAP_ENTRIES 1024
/* must be a power of 2 - 512/4 = 128 entries */
@@ -23,6 +46,7 @@ struct cookie_args {
};
static DEFINE_PER_CPU(char *, translate_text);
+static DEFINE_PER_CPU(char *, scratch);
static DEFINE_PER_CPU(uint32_t, cookie_next_key);
static DEFINE_PER_CPU(uint64_t *, cookie_keys);
static DEFINE_PER_CPU(uint32_t *, cookie_values);
@@ -285,7 +309,7 @@ static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text,
return cookie;
/* On 64-bit android app_process can be app_process32 or app_process64 */
- if (strncmp(text, APP_PROCESS, sizeof(APP_PROCESS) - 1) == 0) {
+ if (strstr(text, APP_PROCESS) != NULL) {
if (!translate_app_process(&text, cpu, task, from_wq))
return UNRESOLVED_COOKIE;
}
@@ -305,6 +329,75 @@ static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text,
return cookie;
}
+/* Can't call d_path in interrupt context so create something similar */
+static const char *gator_d_path(const struct path *path, char *buf, int buflen)
+{
+ struct dentry *dentry = path->dentry;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+ struct mount *mount = real_mount(path->mnt);
+#else
+ struct vfsmount *mount = path->mnt;
+#endif
+ int pos = buflen - 1;
+ int len;
+
+ buf[pos] = '\0';
+
+ for (;;) {
+ if (dentry == NULL) {
+ pr_err("gator: dentry is null!\n");
+ break;
+ }
+ if (dentry->d_name.name[0] == '\0') {
+ pr_err("gator: path is empty string\n");
+ break;
+ }
+ if (dentry->d_name.name[0] == '/' && dentry->d_name.name[1] == '\0') {
+ /* Normal operation */
+ /* pr_err("gator: path is /\n"); */
+ break;
+ }
+
+ len = strlen(dentry->d_name.name);
+ if (pos < len) {
+ pr_err("gator: path is too long\n");
+ break;
+ }
+ pos -= len;
+ memcpy(buf + pos, dentry->d_name.name, len);
+
+ if (pos == 0) {
+ pr_err("gator: no room for slash\n");
+ /* Fall back to name only */
+ return path->dentry->d_name.name;
+ }
+ --pos;
+ buf[pos] = '/';
+
+ if (dentry->d_parent == GET_MNT_ROOT(mount)) {
+ /* pr_err("gator: filesystem is complete, moving to next '%s'\n", buf + pos); */
+ dentry = mount->mnt_mountpoint;
+ mount = mount->mnt_parent;
+ continue;
+ }
+ if (dentry == dentry->d_parent) {
+ pr_err("gator: parent is self\n");
+ break;
+ }
+ dentry = dentry->d_parent;
+ }
+
+ if (pos < 0) {
+ pr_err("gator: pos is somenow negative\n");
+ /* Fall back to name only */
+ return path->dentry->d_name.name;
+ }
+
+ return buf + pos;
+}
+
+#define d_path gator_d_path
+
static int get_exec_cookie(int cpu, struct task_struct *task)
{
struct mm_struct *mm = task->mm;
@@ -315,7 +408,7 @@ static int get_exec_cookie(int cpu, struct task_struct *task)
return NO_COOKIE;
if (task && task->mm && task->mm->exe_file) {
- text = task->mm->exe_file->f_path.dentry->d_name.name;
+ text = d_path(&task->mm->exe_file->f_path, per_cpu(scratch, get_physical_cpu()), PAGE_SIZE);
return get_cookie(cpu, task, text, false);
}
@@ -337,7 +430,7 @@ static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsig
continue;
if (vma->vm_file) {
- text = vma->vm_file->f_path.dentry->d_name.name;
+ text = d_path(&vma->vm_file->f_path, per_cpu(scratch, get_physical_cpu()), PAGE_SIZE);
cookie = get_cookie(cpu, task, text, false);
*offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
} else {
@@ -394,6 +487,12 @@ static int cookies_initialize(void)
err = -ENOMEM;
goto cookie_setup_error;
}
+
+ per_cpu(scratch, cpu) = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!per_cpu(scratch, cpu)) {
+ err = -ENOMEM;
+ goto cookie_setup_error;
+ }
}
/* build CRC32 table */
@@ -414,7 +513,7 @@ static int cookies_initialize(void)
gator_crc32_table[i] = crc;
}
- setup_timer(&app_process_wake_up_timer, app_process_wake_up_handler, 0);
+ setup_deferrable_timer_on_stack(&app_process_wake_up_timer, app_process_wake_up_handler, 0);
cookie_setup_error:
return err;
@@ -438,6 +537,9 @@ static void cookies_release(void)
kfree(per_cpu(translate_text, cpu));
per_cpu(translate_text, cpu) = NULL;
+
+ kfree(per_cpu(scratch, cpu));
+ per_cpu(scratch, cpu) = NULL;
}
del_timer_sync(&app_process_wake_up_timer);
diff --git a/driver/gator_events_armv6.c b/driver/gator_events_armv6.c
index 1783970..62bd6eb 100644
--- a/driver/gator_events_armv6.c
+++ b/driver/gator_events_armv6.c
@@ -198,6 +198,7 @@ static int gator_events_armv6_read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_armv6_interface = {
+ .name = "armv6",
.create_files = gator_events_armv6_create_files,
.stop = gator_events_armv6_stop,
.online = gator_events_armv6_online,
diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c
index e1f6a5f..0db857c 100644
--- a/driver/gator_events_armv7.c
+++ b/driver/gator_events_armv7.c
@@ -263,6 +263,7 @@ static int gator_events_armv7_read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_armv7_interface = {
+ .name = "armv7",
.create_files = gator_events_armv7_create_files,
.stop = gator_events_armv7_stop,
.online = gator_events_armv7_online,
diff --git a/driver/gator_events_block.c b/driver/gator_events_block.c
index b3467b1..0bb4085 100644
--- a/driver/gator_events_block.c
+++ b/driver/gator_events_block.c
@@ -142,6 +142,7 @@ static int gator_events_block_read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_block_interface = {
+ .name = "block",
.create_files = gator_events_block_create_files,
.start = gator_events_block_start,
.stop = gator_events_block_stop,
diff --git a/driver/gator_events_irq.c b/driver/gator_events_irq.c
index 81b976a..aa1ebbb 100644
--- a/driver/gator_events_irq.c
+++ b/driver/gator_events_irq.c
@@ -144,6 +144,7 @@ static int gator_events_irq_read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_irq_interface = {
+ .name = "irq",
.create_files = gator_events_irq_create_files,
.online = gator_events_irq_online,
.start = gator_events_irq_start,
diff --git a/driver/gator_events_l2c-310.c b/driver/gator_events_l2c-310.c
index 063a060..de3b383 100644
--- a/driver/gator_events_l2c-310.c
+++ b/driver/gator_events_l2c-310.c
@@ -121,6 +121,7 @@ static int gator_events_l2c310_read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_l2c310_interface = {
+ .name = "l2c-310",
.create_files = gator_events_l2c310_create_files,
.start = gator_events_l2c310_start,
.stop = gator_events_l2c310_stop,
diff --git a/driver/gator_events_mali_4xx.c b/driver/gator_events_mali_4xx.c
index 423b4e0..fb3909a 100644
--- a/driver/gator_events_mali_4xx.c
+++ b/driver/gator_events_mali_4xx.c
@@ -66,9 +66,7 @@ static unsigned long counter_event[NUMBER_OF_EVENTS];
static unsigned long counter_key[NUMBER_OF_EVENTS];
/* The data we have recorded */
-static u32 counter_data[NUMBER_OF_EVENTS];
-/* The address to sample (or 0 if samples are sent to us) */
-static u32 *counter_address[NUMBER_OF_EVENTS];
+static atomic_t counter_data[NUMBER_OF_EVENTS];
/* An array used to return the data we recorded
* as key,value pairs hence the *2
@@ -116,7 +114,7 @@ static inline int is_hw_counter(unsigned int event_id)
GATOR_DEFINE_PROBE(mali_hw_counter, TP_PROTO(unsigned int event_id, unsigned int value))
{
if (is_hw_counter(event_id))
- counter_data[event_id] = value;
+ atomic_add(value, &counter_data[event_id]);
}
GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surface_id, unsigned int *counters))
@@ -126,7 +124,7 @@ GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surfac
/* Copy over the values for those counters which are enabled. */
for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++) {
if (counter_enabled[i])
- counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]);
+ atomic_add(counters[i - FIRST_SW_COUNTER], &counter_data[i]);
}
}
@@ -375,22 +373,22 @@ static void mali_counter_initialize(void)
if (mali_get_counters)
pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", mali_get_counters);
else
- pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined\n");
+ pr_debug("gator: mali _mali_profiling_get_counters symbol not defined\n");
mali_get_l2_counters = symbol_get(_mali_profiling_get_l2_counters);
if (mali_get_l2_counters)
pr_debug("gator: mali online _mali_profiling_get_l2_counters symbol @ %p\n", mali_get_l2_counters);
else
- pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined\n");
+ pr_debug("gator: mali _mali_profiling_get_l2_counters symbol not defined\n");
if (!mali_get_counters && !mali_get_l2_counters) {
- pr_debug("gator: WARNING: no L2 counters available\n");
+ pr_err("gator: no L2 counters available\n");
n_l2_cores = 0;
}
/* Clear counters in the start */
for (i = 0; i < NUMBER_OF_EVENTS; i++) {
- counter_data[i] = 0;
+ atomic_set(&counter_data[i], 0);
prev_set[i] = false;
}
}
@@ -477,7 +475,6 @@ static void stop(void)
for (cnt = 0; cnt < NUMBER_OF_EVENTS; cnt++) {
counter_enabled[cnt] = 0;
counter_event[cnt] = 0;
- counter_address[cnt] = NULL;
}
mali_counter_deinitialize();
@@ -489,10 +486,12 @@ static void dump_counters(unsigned int from_counter, unsigned int to_counter, un
for (counter_id = from_counter; counter_id <= to_counter; counter_id++) {
if (counter_enabled[counter_id]) {
- counter_dump[(*len)++] = counter_key[counter_id];
- counter_dump[(*len)++] = counter_data[counter_id];
+ unsigned int value;
- counter_data[counter_id] = 0;
+ counter_dump[(*len)++] = counter_key[counter_id];
+ value = atomic_read(&counter_data[counter_id]);
+ atomic_sub(value, &counter_data[counter_id]);
+ counter_dump[(*len)++] = value;
}
}
}
@@ -564,17 +563,19 @@ static int read(int **buffer, bool sched_switch)
* Add in the voltage and frequency counters if enabled. Note
* that, since these are actually passed as events, the counter
* value should not be cleared.
+ *
+ * Intentionally use atomic_read as these are absolute counters
*/
cnt = COUNTER_FREQUENCY;
if (counter_enabled[cnt]) {
counter_dump[len++] = counter_key[cnt];
- counter_dump[len++] = counter_data[cnt];
+ counter_dump[len++] = atomic_read(&counter_data[cnt]);
}
cnt = COUNTER_VOLTAGE;
if (counter_enabled[cnt]) {
counter_dump[len++] = counter_key[cnt];
- counter_dump[len++] = counter_data[cnt];
+ counter_dump[len++] = atomic_read(&counter_data[cnt]);
}
}
#endif
@@ -586,6 +587,7 @@ static int read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_mali_interface = {
+ .name = "mali_4xx",
.create_files = create_files,
.start = start,
.stop = stop,
@@ -595,8 +597,9 @@ static struct gator_interface gator_events_mali_interface = {
extern void gator_events_mali_log_dvfs_event(unsigned int frequency_mhz, unsigned int voltage_mv)
{
#ifdef DVFS_REPORTED_BY_DDK
- counter_data[COUNTER_FREQUENCY] = frequency_mhz;
- counter_data[COUNTER_VOLTAGE] = voltage_mv;
+ /* Intentionally use atomic_set as these are absolute counters */
+ atomic_set(&counter_data[COUNTER_FREQUENCY], frequency_mhz);
+ atomic_set(&counter_data[COUNTER_VOLTAGE], voltage_mv);
#endif
}
@@ -612,8 +615,7 @@ int gator_events_mali_init(void)
counter_enabled[cnt] = 0;
counter_event[cnt] = 0;
counter_key[cnt] = gator_events_get_key();
- counter_address[cnt] = NULL;
- counter_data[cnt] = 0;
+ atomic_set(&counter_data[cnt], 0);
}
trace_registered = 0;
diff --git a/driver/gator_events_mali_common.c b/driver/gator_events_mali_common.c
index 7741f25..60fece8 100644
--- a/driver/gator_events_mali_common.c
+++ b/driver/gator_events_mali_common.c
@@ -25,31 +25,31 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even
dir = gatorfs_mkdir(sb, root, buf);
if (dir == NULL) {
- pr_debug("gator: %s: error creating file system for: %s (%s)\n", mali_name, event_name, buf);
+ pr_err("gator: %s: error creating file system for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
err = gatorfs_create_ulong(sb, dir, "enabled", &counter->enabled);
if (err != 0) {
- pr_debug("gator: %s: error calling gatorfs_create_ulong for: %s (%s)\n", mali_name, event_name, buf);
+ pr_err("gator: %s: error calling gatorfs_create_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
err = gatorfs_create_ro_ulong(sb, dir, "key", &counter->key);
if (err != 0) {
- pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
+ pr_err("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
if (counter->cores != -1) {
err = gatorfs_create_ro_ulong(sb, dir, "cores", &counter->cores);
if (err != 0) {
- pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
+ pr_err("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
}
if (event != NULL) {
err = gatorfs_create_ulong(sb, dir, "event", event);
if (err != 0) {
- pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
+ pr_err("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
}
diff --git a/driver/gator_events_mali_midgard.c b/driver/gator_events_mali_midgard.c
index 3b0963a..5b84975 100644
--- a/driver/gator_events_mali_midgard.c
+++ b/driver/gator_events_mali_midgard.c
@@ -146,6 +146,10 @@ static unsigned int accumulators_data[NUMBER_OF_ACCUMULATORS];
/* Hold the previous timestamp, used to calculate the sample interval. */
static struct timespec prev_timestamp;
+static unsigned long long previous_shader_bitmask;
+static unsigned long long previous_tiler_bitmask;
+static unsigned long long previous_l2_bitmask;
+
/**
* Returns the timespan (in microseconds) between the two specified timestamps.
*
@@ -209,10 +213,6 @@ GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long
#define L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */
#define BIT_AT(value, pos) ((value >> pos) & 1)
- static unsigned long long previous_shader_bitmask;
- static unsigned long long previous_tiler_bitmask;
- static unsigned long long previous_l2_bitmask;
-
switch (event_id) {
case SHADER_PRESENT_LO:
{
@@ -324,27 +324,27 @@ static int create_files(struct super_block *sb, struct dentry *root)
static int register_tracepoints(void)
{
if (GATOR_REGISTER_TRACE(mali_pm_status)) {
- pr_debug("gator: Mali-Midgard: mali_pm_status tracepoint failed to activate\n");
+ pr_err("gator: Mali-Midgard: mali_pm_status tracepoint failed to activate\n");
return 0;
}
if (GATOR_REGISTER_TRACE(mali_page_fault_insert_pages)) {
- pr_debug("gator: Mali-Midgard: mali_page_fault_insert_pages tracepoint failed to activate\n");
+ pr_err("gator: Mali-Midgard: mali_page_fault_insert_pages tracepoint failed to activate\n");
return 0;
}
if (GATOR_REGISTER_TRACE(mali_mmu_as_in_use)) {
- pr_debug("gator: Mali-Midgard: mali_mmu_as_in_use tracepoint failed to activate\n");
+ pr_err("gator: Mali-Midgard: mali_mmu_as_in_use tracepoint failed to activate\n");
return 0;
}
if (GATOR_REGISTER_TRACE(mali_mmu_as_released)) {
- pr_debug("gator: Mali-Midgard: mali_mmu_as_released tracepoint failed to activate\n");
+ pr_err("gator: Mali-Midgard: mali_mmu_as_released tracepoint failed to activate\n");
return 0;
}
if (GATOR_REGISTER_TRACE(mali_total_alloc_pages_change)) {
- pr_debug("gator: Mali-Midgard: mali_total_alloc_pages_change tracepoint failed to activate\n");
+ pr_err("gator: Mali-Midgard: mali_total_alloc_pages_change tracepoint failed to activate\n");
return 0;
}
@@ -363,6 +363,10 @@ static int start(void)
unsigned int cnt;
mali_profiling_control_type *mali_control;
+ previous_shader_bitmask = 0;
+ previous_tiler_bitmask = 0;
+ previous_l2_bitmask = 0;
+
/* Clean all data for the next capture */
for (cnt = 0; cnt < NUMBER_OF_TIMELINE_EVENTS; cnt++) {
timeline_event_starttime[cnt].tv_sec = timeline_event_starttime[cnt].tv_nsec = 0;
@@ -546,6 +550,7 @@ static int read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_mali_midgard_interface = {
+ .name = "mali_midgard",
.create_files = create_files,
.start = start,
.stop = stop,
diff --git a/driver/gator_events_mali_midgard_hw.c b/driver/gator_events_mali_midgard_hw.c
index 7e1eee3..db91c42 100644
--- a/driver/gator_events_mali_midgard_hw.c
+++ b/driver/gator_events_mali_midgard_hw.c
@@ -433,7 +433,8 @@ static unsigned int num_hardware_counters_enabled;
static struct mali_counter *counters;
/* An array used to return the data we recorded as key,value pairs */
-static int *counter_dump;
+static long long *counter_dump;
+static uint64_t last_read_time;
extern struct mali_counter mali_activity[3];
@@ -517,31 +518,6 @@ static void clean_symbols(void)
#endif
}
-/**
- * Determines whether a read should take place
- * @param current_time The current time, obtained from getnstimeofday()
- * @param prev_time_s The number of seconds at the previous read attempt.
- * @param next_read_time_ns The time (in ns) when the next read should be allowed.
- *
- * Note that this function has been separated out here to allow it to be tested.
- */
-static int is_read_scheduled(const struct timespec *current_time, u32 *prev_time_s, s32 *next_read_time_ns)
-{
- /* If the current ns count rolls over a second, roll the next read time too. */
- if (current_time->tv_sec != *prev_time_s)
- *next_read_time_ns = *next_read_time_ns - NSEC_PER_SEC;
-
- /* Abort the read if the next read time has not arrived. */
- if (current_time->tv_nsec < *next_read_time_ns)
- return 0;
-
- /* Set the next read some fixed time after this one, and update the read timestamp. */
- *next_read_time_ns = current_time->tv_nsec + READ_INTERVAL_NSEC;
-
- *prev_time_s = current_time->tv_sec;
- return 1;
-}
-
static int start(void)
{
#if MALI_DDK_GATOR_API_VERSION != 3
@@ -552,6 +528,8 @@ static int start(void)
#endif
int cnt;
+ last_read_time = 0;
+
#if MALI_DDK_GATOR_API_VERSION == 3
/* Setup HW counters */
num_hardware_counters_enabled = 0;
@@ -620,14 +598,14 @@ static int start(void)
/* If we already got a context, fail */
if (kbcontext) {
- pr_debug("gator: Mali-Midgard: error context already present\n");
+ pr_err("gator: Mali-Midgard: error context already present\n");
goto out;
}
/* kbcontext will only be valid after all the Mali symbols are loaded successfully */
kbcontext = kbase_create_context_symbol(kbdevice);
if (!kbcontext) {
- pr_debug("gator: Mali-Midgard: error creating kbase context\n");
+ pr_err("gator: Mali-Midgard: error creating kbase context\n");
goto out;
}
@@ -650,7 +628,7 @@ static int start(void)
kernel_dump_buffer = kbase_va_alloc_symbol(kbcontext, 4096, &kernel_dump_buffer_handle);
#endif
if (!kernel_dump_buffer) {
- pr_debug("gator: Mali-Midgard: error trying to allocate va\n");
+ pr_err("gator: Mali-Midgard: error trying to allocate va\n");
goto destroy_context;
}
@@ -665,7 +643,7 @@ static int start(void)
/* Use kbase API to enable hardware counters and provide dump buffer */
err = kbase_instr_hwcnt_enable_symbol(kbcontext, &setup);
if (err != MALI_ERROR_NONE) {
- pr_debug("gator: Mali-Midgard: can't setup hardware counters\n");
+ pr_err("gator: Mali-Midgard: can't setup hardware counters\n");
goto free_buffer;
}
pr_debug("gator: Mali-Midgard: hardware counters enabled\n");
@@ -813,68 +791,80 @@ static int read_counter(const int cnt, const int len, const struct mali_counter
return 2;
}
-static int read(int **buffer, bool sched_switch)
+static int read(long long **buffer, bool sched_switch)
{
int cnt;
int len = 0;
uint32_t success;
- struct timespec current_time;
- static u32 prev_time_s;
- static s32 next_read_time_ns;
+ uint64_t curr_time;
if (!on_primary_core() || sched_switch)
return 0;
- getnstimeofday(&current_time);
+ /*
+ * Report the HW counters
+ * Only process hardware counters if at least one of the hardware counters is enabled.
+ */
+ if (num_hardware_counters_enabled <= 0)
+ return 0;
+
+ curr_time = gator_get_time();
/*
* Discard reads unless a respectable time has passed. This
* reduces the load on the GPU without sacrificing accuracy on
* the Streamline display.
*/
- if (!is_read_scheduled(&current_time, &prev_time_s, &next_read_time_ns))
+ if (curr_time - last_read_time < READ_INTERVAL_NSEC)
return 0;
- /*
- * Report the HW counters
- * Only process hardware counters if at least one of the hardware counters is enabled.
- */
- if (num_hardware_counters_enabled > 0) {
#if MALI_DDK_GATOR_API_VERSION == 3
- if (!handles)
- return -1;
+ if (!handles)
+ return -1;
- /* Mali symbols can be called safely since a kbcontext is valid */
- if (kbase_gator_instr_hwcnt_dump_complete_symbol(handles, &success)) {
+ /* Mali symbols can be called safely since a kbcontext is valid */
+ if (kbase_gator_instr_hwcnt_dump_complete_symbol(handles, &success)) {
#else
- if (!kbcontext)
- return -1;
+ if (!kbcontext)
+ return -1;
- /* Mali symbols can be called safely since a kbcontext is valid */
- if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success)) {
+ /* Mali symbols can be called safely since a kbcontext is valid */
+ if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success)) {
#endif
- kbase_device_busy = false;
+ kbase_device_busy = false;
+
+ /*
+ * If last_read_time is zero, then this result is from a previous
+ * capture or in error.
+ */
+ if (success && last_read_time > 0) {
+ /* Backdate these events to when they were requested */
+ counter_dump[len++] = 0;
+ counter_dump[len++] = last_read_time;
- if (success) {
- /* Cycle through hardware counters and accumulate totals */
- for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
- const struct mali_counter *counter = &counters[cnt];
+ /* Cycle through hardware counters and accumulate totals */
+ for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
+ const struct mali_counter *counter = &counters[cnt];
- if (counter->enabled)
- len += read_counter(cnt, len, counter);
- }
+ if (counter->enabled)
+ len += read_counter(cnt, len, counter);
}
+
+ /* Restore the timestamp */
+ counter_dump[len++] = 0;
+ counter_dump[len++] = curr_time;
}
+ }
- if (!kbase_device_busy) {
- kbase_device_busy = true;
+ if (!kbase_device_busy) {
+ kbase_device_busy = true;
+ last_read_time = curr_time;
#if MALI_DDK_GATOR_API_VERSION == 3
- kbase_gator_instr_hwcnt_dump_irq_symbol(handles);
+ kbase_gator_instr_hwcnt_dump_irq_symbol(handles);
#else
- kbase_instr_hwcnt_dump_irq_symbol(kbcontext);
+ kbase_instr_hwcnt_dump_irq_symbol(kbcontext);
#endif
- }
}
/* Update the buffer */
@@ -920,7 +910,7 @@ static void shutdown(void)
hardware_counter_names = NULL;
if (kbase_gator_hwcnt_term_names_symbol != NULL) {
kbase_gator_hwcnt_term_names_symbol();
- pr_err("Released symbols\n");
+ pr_debug("gator: Released symbols\n");
}
SYMBOL_CLEANUP(kbase_gator_hwcnt_term_names);
@@ -928,11 +918,12 @@ static void shutdown(void)
}
static struct gator_interface gator_events_mali_midgard_interface = {
+ .name = "mali_midgard_hw",
.shutdown = shutdown,
.create_files = create_files,
.start = start,
.stop = stop,
- .read = read
+ .read64 = read
};
int gator_events_mali_midgard_hw_init(void)
@@ -969,7 +960,7 @@ int gator_events_mali_midgard_hw_init(void)
#endif
counters = kmalloc(sizeof(*counters)*number_of_hardware_counters, GFP_KERNEL);
- counter_dump = kmalloc(sizeof(*counter_dump)*number_of_hardware_counters*2, GFP_KERNEL);
+ counter_dump = kmalloc(sizeof(*counter_dump)*number_of_hardware_counters*2 + 4, GFP_KERNEL);
gator_mali_initialise_counters(mali_activity, ARRAY_SIZE(mali_activity));
gator_mali_initialise_counters(counters, number_of_hardware_counters);
diff --git a/driver/gator_events_mali_midgard_hw_test.c b/driver/gator_events_mali_midgard_hw_test.c
index 87c569c..9fd44bc 100644
--- a/driver/gator_events_mali_midgard_hw_test.c
+++ b/driver/gator_events_mali_midgard_hw_test.c
@@ -10,46 +10,3 @@
/**
* Test functions for mali_t600_hw code.
*/
-
-static int is_read_scheduled(const struct timespec *current_time, u32 *prev_time_s, s32 *next_read_time_ns);
-
-static int test_is_read_scheduled(u32 s, u32 ns, u32 prev_s, s32 next_ns, int expected_result, s32 expected_next_ns)
-{
- struct timespec current_time;
- u32 prev_time_s = prev_s;
- s32 next_read_time_ns = next_ns;
-
- current_time.tv_sec = s;
- current_time.tv_nsec = ns;
-
- if (is_read_scheduled(&current_time, &prev_time_s, &next_read_time_ns) != expected_result) {
- pr_err("Failed do_read(%u, %u, %u, %d): expected %d\n", s, ns, prev_s, next_ns, expected_result);
- return 0;
- }
-
- if (next_read_time_ns != expected_next_ns) {
- pr_err("Failed: next_read_ns expected=%d, actual=%d\n", expected_next_ns, next_read_time_ns);
- return 0;
- }
-
- return 1;
-}
-
-static void test_all_is_read_scheduled(void)
-{
- const int HIGHEST_NS = 999999999;
- int n_tests_passed = 0;
-
- pr_err("gator: running tests on %s\n", __FILE__);
-
- n_tests_passed += test_is_read_scheduled(0, 0, 0, 0, 1, READ_INTERVAL_NSEC); /* Null time */
- n_tests_passed += test_is_read_scheduled(100, 1000, 0, 0, 1, READ_INTERVAL_NSEC + 1000); /* Initial values */
-
- n_tests_passed += test_is_read_scheduled(100, HIGHEST_NS, 100, HIGHEST_NS + 500, 0, HIGHEST_NS + 500);
- n_tests_passed += test_is_read_scheduled(101, 0001, 100, HIGHEST_NS + 500, 0, HIGHEST_NS + 500 - NSEC_PER_SEC);
- n_tests_passed += test_is_read_scheduled(101, 600, 100, HIGHEST_NS + 500 - NSEC_PER_SEC, 1, 600 + READ_INTERVAL_NSEC);
-
- n_tests_passed += test_is_read_scheduled(101, 600, 100, HIGHEST_NS + 500, 1, 600 + READ_INTERVAL_NSEC);
-
- pr_err("gator: %d tests passed\n", n_tests_passed);
-}
diff --git a/driver/gator_events_meminfo.c b/driver/gator_events_meminfo.c
index 985b312..42a6947 100644
--- a/driver/gator_events_meminfo.c
+++ b/driver/gator_events_meminfo.c
@@ -80,7 +80,7 @@ static void notify(void)
static unsigned int mem_event;
static void wq_sched_handler(struct work_struct *wsptr);
-DECLARE_WORK(work, wq_sched_handler);
+static DECLARE_WORK(work, wq_sched_handler);
static struct timer_list meminfo_wake_up_timer;
static void meminfo_wake_up_handler(unsigned long unused_data);
@@ -187,7 +187,7 @@ static int gator_events_meminfo_start(void)
if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo")))
goto kthread_run_exit;
#else
- setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
+ setup_deferrable_timer_on_stack(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
#endif
return 0;
@@ -313,7 +313,7 @@ static void meminfo_wake_up_handler(unsigned long unused_data)
#endif
-static int gator_events_meminfo_read(long long **buffer)
+static int gator_events_meminfo_read(long long **buffer, bool sched_switch)
{
#if !USE_THREAD
static unsigned int last_mem_event;
@@ -446,6 +446,7 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
}
static struct gator_interface gator_events_meminfo_interface = {
+ .name = "meminfo",
.create_files = gator_events_meminfo_create_files,
.start = gator_events_meminfo_start,
.stop = gator_events_meminfo_stop,
diff --git a/driver/gator_events_mmapped.c b/driver/gator_events_mmapped.c
index 7b51761..30ca980 100644
--- a/driver/gator_events_mmapped.c
+++ b/driver/gator_events_mmapped.c
@@ -189,6 +189,7 @@ static int gator_events_mmapped_read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_mmapped_interface = {
+ .name = "mmapped",
.create_files = gator_events_mmapped_create_files,
.start = gator_events_mmapped_start,
.stop = gator_events_mmapped_stop,
diff --git a/driver/gator_events_net.c b/driver/gator_events_net.c
index 1e36731..053f719 100644
--- a/driver/gator_events_net.c
+++ b/driver/gator_events_net.c
@@ -45,7 +45,7 @@ static void get_network_stats(struct work_struct *wsptr)
tx_total = tx;
}
-DECLARE_WORK(wq_get_stats, get_network_stats);
+static DECLARE_WORK(wq_get_stats, get_network_stats);
static void net_wake_up_handler(unsigned long unused_data)
{
@@ -98,11 +98,7 @@ static int gator_events_net_start(void)
get_network_stats(0);
netPrev[NETRX] = rx_total;
netPrev[NETTX] = tx_total;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
- setup_timer(&net_wake_up_timer, net_wake_up_handler, 0);
-#else
setup_deferrable_timer_on_stack(&net_wake_up_timer, net_wake_up_handler, 0);
-#endif
return 0;
}
@@ -154,6 +150,7 @@ static int gator_events_net_read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_net_interface = {
+ .name = "net",
.create_files = gator_events_net_create_files,
.start = gator_events_net_start,
.stop = gator_events_net_stop,
diff --git a/driver/gator_events_perf_pmu.c b/driver/gator_events_perf_pmu.c
index f6b4f18..d49277d 100644
--- a/driver/gator_events_perf_pmu.c
+++ b/driver/gator_events_perf_pmu.c
@@ -153,13 +153,13 @@ static void __online_dispatch(int cpu, bool migrate, struct gator_attr *const at
event->pevent = perf_event_create_kernel_counter(event->pevent_attr, cpu, 0, handler, 0);
#endif
if (IS_ERR(event->pevent)) {
- pr_debug("gator: unable to online a counter on cpu %d\n", cpu);
+ pr_err("gator: unable to online a counter on cpu %d\n", cpu);
event->pevent = NULL;
return;
}
if (event->pevent->state != PERF_EVENT_STATE_ACTIVE) {
- pr_debug("gator: inactive counter on cpu %d\n", cpu);
+ pr_err("gator: inactive counter on cpu %d\n", cpu);
perf_event_release_kernel(event->pevent);
event->pevent = NULL;
return;
@@ -369,6 +369,7 @@ static int gator_events_perf_pmu_read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_perf_pmu_interface = {
+ .name = "perf_pmu",
.create_files = gator_events_perf_pmu_create_files,
.start = gator_events_perf_pmu_start,
.stop = gator_events_perf_pmu_stop,
@@ -463,10 +464,10 @@ static void gator_events_perf_pmu_cci_400_init(const int type)
cci_name = "CCI_400";
break;
case 1:
- cci_name = "CCI_400-r1";
+ cci_name = "CCI_400_r1";
break;
default:
- pr_debug("gator: unrecognized cci-400 revision\n");
+ pr_err("gator: unrecognized cci-400 revision\n");
return;
}
@@ -536,14 +537,19 @@ int gator_events_perf_pmu_init(void)
}
if (pe->pmu != NULL && type == pe->pmu->type) {
- if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0 || strcmp("CCI_400-r1", pe->pmu->name) == 0) {
+ pr_notice("gator: perf pmu: %s\n", pe->pmu->name);
+ if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0 || strcmp("CCI_400_r1", pe->pmu->name) == 0) {
+ pr_notice("gator: Adding CCI-400 counters with type %i\n", type);
gator_events_perf_pmu_cci_400_init(type);
} else if (strcmp("CCI_500", pe->pmu->name) == 0) {
+ pr_notice("gator: Adding CCI-500 counters with type %i\n", type);
gator_events_perf_pmu_uncore_init("CCI_500", type, CCI_500, false);
} else if (strcmp("ccn", pe->pmu->name) == 0) {
+ pr_notice("gator: Adding CCN counters with type %i\n", type);
gator_events_perf_pmu_uncore_init("ARM_CCN_5XX", type, CCN_5XX, true);
} else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) {
found_cpu = true;
+ pr_notice("gator: Adding cpu counters for %s with type %i\n", gator_cpu->pmnc_name, type);
gator_events_perf_pmu_cpu_init(gator_cpu, type);
}
/* Initialize gator_attrs for dynamic PMUs here */
@@ -562,6 +568,7 @@ int gator_events_perf_pmu_init(void)
return -1;
}
}
+ pr_notice("gator: Adding cpu counters (based on cpuid) for %s\n", gator_cpu->pmnc_name);
gator_events_perf_pmu_cpu_init(gator_cpu, PERF_TYPE_RAW);
}
diff --git a/driver/gator_events_sched.c b/driver/gator_events_sched.c
index 463d834..d352415 100644
--- a/driver/gator_events_sched.c
+++ b/driver/gator_events_sched.c
@@ -97,6 +97,7 @@ static int gator_events_sched_read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_sched_interface = {
+ .name = "sched",
.create_files = gator_events_sched_create_files,
.start = gator_events_sched_start,
.stop = gator_events_sched_stop,
diff --git a/driver/gator_events_scorpion.c b/driver/gator_events_scorpion.c
index b51dcd3..efb5e7a 100644
--- a/driver/gator_events_scorpion.c
+++ b/driver/gator_events_scorpion.c
@@ -635,6 +635,7 @@ static int gator_events_scorpion_read(int **buffer, bool sched_switch)
}
static struct gator_interface gator_events_scorpion_interface = {
+ .name = "scorpion",
.create_files = gator_events_scorpion_create_files,
.stop = gator_events_scorpion_stop,
.online = gator_events_scorpion_online,
diff --git a/driver/gator_fs.c b/driver/gator_fs.c
index d8fb357..205da8b 100644
--- a/driver/gator_fs.c
+++ b/driver/gator_fs.c
@@ -18,7 +18,7 @@
#define gatorfs_MAGIC 0x24051020
#define TMPBUFSIZE 50
-DEFINE_SPINLOCK(gatorfs_lock);
+static DEFINE_SPINLOCK(gatorfs_lock);
static struct inode *gatorfs_get_inode(struct super_block *sb, int mode)
{
diff --git a/driver/gator_hrtimer_gator.c b/driver/gator_hrtimer_gator.c
index 36961f8..8b86ede 100644
--- a/driver/gator_hrtimer_gator.c
+++ b/driver/gator_hrtimer_gator.c
@@ -7,10 +7,10 @@
*
*/
-void (*callback)(void);
-DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
-DEFINE_PER_CPU(ktime_t, hrtimer_expire);
-DEFINE_PER_CPU(int, hrtimer_is_active);
+static void (*callback)(void);
+static DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
+static DEFINE_PER_CPU(ktime_t, hrtimer_expire);
+static DEFINE_PER_CPU(int, hrtimer_is_active);
static ktime_t profiling_interval;
static void gator_hrtimer_online(void);
static void gator_hrtimer_offline(void);
diff --git a/driver/gator_main.c b/driver/gator_main.c
index affa1dc..2d55afe 100644
--- a/driver/gator_main.c
+++ b/driver/gator_main.c
@@ -8,7 +8,7 @@
*/
/* This version must match the gator daemon version */
-#define PROTOCOL_VERSION 21
+#define PROTOCOL_VERSION 22
static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#include <linux/slab.h>
@@ -180,7 +180,6 @@ static DEFINE_PER_CPU(bool, in_scheduler_context);
/******************************************************************************
* Prototypes
******************************************************************************/
-static u64 gator_get_time(void);
static void gator_emit_perf_time(u64 time);
static void gator_op_create_files(struct super_block *sb, struct dentry *root);
@@ -378,21 +377,21 @@ static const struct gator_cpu gator_cpus[] = {
{
.cpuid = CORTEX_A53,
.core_name = "Cortex-A53",
- .pmnc_name = "ARM_Cortex-A53",
+ .pmnc_name = "ARMv8_Cortex_A53",
.dt_name = "arm,cortex-a53",
.pmnc_counters = 6,
},
{
.cpuid = CORTEX_A57,
.core_name = "Cortex-A57",
- .pmnc_name = "ARM_Cortex-A57",
+ .pmnc_name = "ARMv8_Cortex_A57",
.dt_name = "arm,cortex-a57",
.pmnc_counters = 6,
},
{
.cpuid = CORTEX_A72,
.core_name = "Cortex-A72",
- .pmnc_name = "ARM_Cortex-A72",
+ .pmnc_name = "ARMv8_Cortex_A72",
.dt_name = "arm,cortex-a72",
.pmnc_counters = 6,
},
@@ -551,6 +550,8 @@ static void gator_timer_offline(void *migrate)
list_for_each_entry(gi, &gator_events, list) {
if (gi->offline) {
len = gi->offline(&buffer, migrate);
+ if (len < 0)
+ pr_err("gator: offline failed for %s\n", gi->name);
marshal_event(len, buffer);
}
}
@@ -639,6 +640,8 @@ static void gator_timer_online(void *migrate)
list_for_each_entry(gi, &gator_events, list) {
if (gi->online) {
len = gi->online(&buffer, migrate);
+ if (len < 0)
+ pr_err("gator: online failed for %s\n", gi->name);
marshal_event(len, buffer);
}
}
@@ -699,7 +702,7 @@ static int gator_timer_start(unsigned long sample_rate)
return 0;
}
-static u64 gator_get_time(void)
+u64 gator_get_time(void)
{
struct timespec ts;
u64 timestamp;
@@ -1366,6 +1369,7 @@ static void gator_op_create_files(struct super_block *sb, struct dentry *root)
struct dentry *dir;
struct gator_interface *gi;
int cpu;
+ int err;
/* reinitialize default values */
gator_cpu_cores = 0;
@@ -1393,8 +1397,12 @@ static void gator_op_create_files(struct super_block *sb, struct dentry *root)
/* Linux Events */
dir = gatorfs_mkdir(sb, root, "events");
list_for_each_entry(gi, &gator_events, list)
- if (gi->create_files)
- gi->create_files(sb, dir);
+ if (gi->create_files) {
+ err = gi->create_files(sb, dir);
+ if (err != 0) {
+ pr_err("gator: create_files failed for %s\n", gi->name);
+ }
+ }
/* Sched Events */
sched_trace_create_files(sb, dir);
@@ -1473,7 +1481,7 @@ static int __init gator_module_init(void)
return -1;
}
- setup_timer(&gator_buffer_wake_up_timer, gator_buffer_wake_up, 0);
+ setup_deferrable_timer_on_stack(&gator_buffer_wake_up_timer, gator_buffer_wake_up, 0);
/* Initialize the list of cpuids */
memset(gator_cpuids, -1, sizeof(gator_cpuids));
diff --git a/driver/gator_marshaling.c b/driver/gator_marshaling.c
index f5b8184..cb75a34 100644
--- a/driver/gator_marshaling.c
+++ b/driver/gator_marshaling.c
@@ -27,6 +27,7 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
{
unsigned long flags;
int cpu = 0;
+ char buf[32];
local_irq_save(flags);
gator_buffer_write_packed_int(cpu, SUMMARY_BUF, MESSAGE_SUMMARY);
@@ -36,6 +37,9 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, monotonic_delta);
gator_buffer_write_string(cpu, SUMMARY_BUF, "uname");
gator_buffer_write_string(cpu, SUMMARY_BUF, uname);
+ gator_buffer_write_string(cpu, SUMMARY_BUF, "PAGESIZE");
+ snprintf(buf, sizeof(buf), "%lu", PAGE_SIZE);
+ gator_buffer_write_string(cpu, SUMMARY_BUF, buf);
#if GATOR_IKS_SUPPORT
gator_buffer_write_string(cpu, SUMMARY_BUF, "iks");
gator_buffer_write_string(cpu, SUMMARY_BUF, "");
diff --git a/driver/gator_trace_gpu.c b/driver/gator_trace_gpu.c
index d9b82ee..b35ccd5 100644
--- a/driver/gator_trace_gpu.c
+++ b/driver/gator_trace_gpu.c
@@ -132,7 +132,7 @@ static void mali_activity_stop(int core, int key)
gator_marshal_activity_switch(core, key, last_activity, last_pid);
}
-void mali_activity_clear(struct mali_counter mali_activity[], size_t mali_activity_size)
+static void mali_activity_clear(struct mali_counter mali_activity[], size_t mali_activity_size)
{
int activity;
int cores;
diff --git a/driver/gator_trace_sched.c b/driver/gator_trace_sched.c
index ad7c39e..700dd2e 100644
--- a/driver/gator_trace_sched.c
+++ b/driver/gator_trace_sched.c
@@ -104,13 +104,19 @@ static void collect_counters(u64 time, struct task_struct *task, bool sched_swit
list_for_each_entry(gi, &gator_events, list) {
if (gi->read) {
len = gi->read(&buffer, sched_switch);
+ if (len < 0)
+ pr_err("gator: read failed for %s\n", gi->name);
marshal_event(len, buffer);
} else if (gi->read64) {
- len = gi->read64(&buffer64);
+ len = gi->read64(&buffer64, sched_switch);
+ if (len < 0)
+ pr_err("gator: read64 failed for %s\n", gi->name);
marshal_event64(len, buffer64);
}
if (gi->read_proc && task != NULL) {
len = gi->read_proc(&buffer64, task);
+ if (len < 0)
+ pr_err("gator: read_proc failed for %s\n", gi->name);
marshal_event64(len, buffer64);
}
}
diff --git a/driver/mali_midgard.mk b/driver/mali_midgard.mk
index b0076c2..bd0ac77 100644
--- a/driver/mali_midgard.mk
+++ b/driver/mali_midgard.mk
@@ -36,5 +36,6 @@ EXTRA_CFLAGS += -I$(KBASE_DIR)/ \
-I$(DDK_DIR)/include \
-I$(KBASE_DIR)/osk/src/linux/include \
-I$(KBASE_DIR)/platform_dummy \
- -I$(KBASE_DIR)/src
+ -I$(KBASE_DIR)/src \
+ -Idrivers/staging/android \