summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Medhurst2013-04-03 05:59:40 -0500
committerJon Medhurst2013-04-03 06:54:15 -0500
commit7ef1b3596e3625d6335fd03904dfdcc75f365919 (patch)
tree4b309e83ab767e561a2235668b3ad6cd830bb40c
parent06ebd1eab0a782377611efee820bb57f09692cbf (diff)
downloadarm-ds5-gator-7ef1b3596e3625d6335fd03904dfdcc75f365919.tar.gz
arm-ds5-gator-7ef1b3596e3625d6335fd03904dfdcc75f365919.tar.xz
arm-ds5-gator-7ef1b3596e3625d6335fd03904dfdcc75f365919.zip
gator: Version 5.14
Signed-off-by: Jon Medhurst <tixy@linaro.org>
-rw-r--r--README_Streamline.txt250
-rw-r--r--daemon/Android.mk14
-rw-r--r--daemon/Buffer.cpp354
-rw-r--r--daemon/Buffer.h66
-rw-r--r--daemon/CapturedXML.cpp76
-rw-r--r--daemon/CapturedXML.h3
-rw-r--r--daemon/Child.cpp131
-rw-r--r--daemon/Child.h6
-rw-r--r--daemon/Collector.cpp141
-rw-r--r--daemon/Collector.h19
-rw-r--r--daemon/ConfigurationXML.cpp153
-rw-r--r--daemon/ConfigurationXML.h2
-rw-r--r--daemon/Counter.h97
-rw-r--r--daemon/Driver.cpp15
-rw-r--r--daemon/Driver.h44
-rw-r--r--daemon/Fifo.cpp20
-rw-r--r--daemon/Fifo.h8
-rw-r--r--daemon/Hwmon.cpp277
-rw-r--r--daemon/Hwmon.h39
-rw-r--r--daemon/KMod.cpp102
-rw-r--r--daemon/KMod.h27
-rw-r--r--daemon/LocalCapture.cpp12
-rw-r--r--daemon/LocalCapture.h4
-rw-r--r--daemon/Logging.cpp3
-rw-r--r--daemon/Logging.h4
-rw-r--r--daemon/Makefile55
-rw-r--r--daemon/Makefile_aarch6415
-rw-r--r--daemon/OlySocket.cpp2
-rw-r--r--daemon/OlySocket.h2
-rw-r--r--daemon/OlyUtility.cpp2
-rw-r--r--daemon/OlyUtility.h2
-rw-r--r--daemon/Sender.cpp27
-rw-r--r--daemon/Sender.h5
-rw-r--r--daemon/SessionData.cpp122
-rw-r--r--daemon/SessionData.h38
-rw-r--r--daemon/SessionXML.cpp6
-rw-r--r--daemon/SessionXML.h6
-rw-r--r--daemon/StreamlineSetup.cpp81
-rw-r--r--daemon/StreamlineSetup.h3
-rw-r--r--daemon/common.mk50
-rw-r--r--daemon/configuration.xml24
-rw-r--r--daemon/escape.c8
-rw-r--r--daemon/events-ARM11.xml2
-rw-r--r--daemon/events-ARM11MPCore.xml2
-rw-r--r--daemon/events-CCI-400.xml47
-rw-r--r--daemon/events-Cortex-A15.xml12
-rw-r--r--daemon/events-Cortex-A5.xml6
-rw-r--r--daemon/events-Cortex-A53.xml2
-rw-r--r--daemon/events-Cortex-A57.xml2
-rw-r--r--daemon/events-Cortex-A7.xml11
-rw-r--r--daemon/events-Cortex-A8.xml4
-rw-r--r--daemon/events-Cortex-A9.xml2
-rw-r--r--daemon/events-Krait-architected.xml2
-rw-r--r--daemon/events-Mali-400.xml404
-rw-r--r--daemon/events-Mali-T6xx_hw.xml12
-rw-r--r--daemon/events-Scorpion.xml2
-rw-r--r--daemon/events-ScorpionMP.xml2
-rw-r--r--daemon/libsensors/COPYING.LGPL502
-rw-r--r--daemon/libsensors/access.c561
-rw-r--r--daemon/libsensors/access.h33
-rw-r--r--daemon/libsensors/conf-lex.c2881
-rw-r--r--daemon/libsensors/conf-lex.l372
-rw-r--r--daemon/libsensors/conf-parse.c2042
-rw-r--r--daemon/libsensors/conf-parse.h84
-rw-r--r--daemon/libsensors/conf-parse.y347
-rw-r--r--daemon/libsensors/conf.h34
-rw-r--r--daemon/libsensors/data.c278
-rw-r--r--daemon/libsensors/data.h184
-rw-r--r--daemon/libsensors/error.c92
-rw-r--r--daemon/libsensors/error.h74
-rw-r--r--daemon/libsensors/general.c85
-rw-r--r--daemon/libsensors/general.h39
-rw-r--r--daemon/libsensors/init.c341
-rw-r--r--daemon/libsensors/init.h28
-rw-r--r--daemon/libsensors/scanner.h32
-rw-r--r--daemon/libsensors/sensors.h311
-rw-r--r--daemon/libsensors/sysfs.c926
-rw-r--r--daemon/libsensors/sysfs.h43
-rw-r--r--daemon/libsensors/version.h1
-rw-r--r--daemon/main.cpp26
-rw-r--r--driver/Makefile1
-rw-r--r--driver/gator.h43
-rw-r--r--driver/gator_annotate.c23
-rw-r--r--driver/gator_annotate_kernel.c2
-rw-r--r--driver/gator_backtrace.c39
-rw-r--r--driver/gator_cookies.c8
-rwxr-xr-x[-rw-r--r--]driver/gator_events.sh0
-rw-r--r--driver/gator_events_armv6.c6
-rw-r--r--driver/gator_events_armv7.c6
-rw-r--r--driver/gator_events_block.c9
-rw-r--r--driver/gator_events_irq.c48
-rw-r--r--driver/gator_events_l2c-310.c74
-rw-r--r--driver/gator_events_mali_400.c12
-rw-r--r--driver/gator_events_mali_400.h2
-rw-r--r--driver/gator_events_mali_common.c2
-rw-r--r--driver/gator_events_mali_common.h2
-rw-r--r--driver/gator_events_mali_t6xx.c4
-rw-r--r--driver/gator_events_mali_t6xx_hw.c4
-rw-r--r--driver/gator_events_mali_t6xx_hw_test.c2
-rw-r--r--driver/gator_events_meminfo.c4
-rw-r--r--driver/gator_events_mmaped.c6
-rw-r--r--driver/gator_events_net.c4
-rw-r--r--driver/gator_events_perf_pmu.c520
-rw-r--r--driver/gator_events_sched.c6
-rw-r--r--driver/gator_events_scorpion.c6
-rw-r--r--driver/gator_fs.c87
-rw-r--r--driver/gator_hrtimer_gator.c35
-rw-r--r--driver/gator_hrtimer_perf.c2
-rw-r--r--driver/gator_iks.c144
-rw-r--r--driver/gator_main.c335
-rw-r--r--driver/gator_marshaling.c119
-rw-r--r--driver/gator_pack.c2
-rw-r--r--driver/gator_trace_gpu.c86
-rw-r--r--driver/gator_trace_gpu.h2
-rw-r--r--driver/gator_trace_power.c43
-rw-r--r--driver/gator_trace_sched.c28
116 files changed, 12452 insertions, 1407 deletions
diff --git a/README_Streamline.txt b/README_Streamline.txt
index 0445e3f..5472c07 100644
--- a/README_Streamline.txt
+++ b/README_Streamline.txt
@@ -1,108 +1,142 @@
1 1
2*** Purpose *** 2*** Purpose ***
3 3
4Instructions on setting up ARM Streamline on the target. 4Instructions on setting up ARM Streamline on the target.
5The gator driver and gator daemon are required to run on the ARM linux target in order for ARM Streamline to operate. 5The gator driver and gator daemon are required to run on the ARM linux target in order for ARM Streamline to operate.
6The driver should be built as a module and the daemon must run with root permissions on the target. 6The driver should be built as a module and the daemon must run with root permissions on the target.
7 7
8*** Introduction *** 8*** Introduction ***
9 9
10A linux development environment with cross compiling tools is most likely required, depending on what is already created and provided. 10A linux development environment with cross compiling tools is most likely required, depending on what is already created and provided.
11-For users, the ideal environment is to be given a BSP with gatord and gator.ko already running on a properly configured kernel. In such a scenario, a development environment is not needed, root permission may or may not be needed (gatord must be executed with root permissions but can be automatically started, see below), and the user can run Streamline and profile the system without any setup. 11-For users, the ideal environment is to be given a BSP with gatord and gator.ko already running on a properly configured kernel. In such a scenario, a development environment is not needed, root permission may or may not be needed (gatord must be executed with root permissions but can be automatically started, see below), and the user can run Streamline and profile the system without any setup.
12-The ideal development environment has the kernel source code available to be rebuilt and executed on the target. This environment allows the greatest flexibility in configuring the kernel and building the gator driver module. 12-The ideal development environment has the kernel source code available to be rebuilt, usually by cross-compiling on a host machine. This environment allows the greatest flexibility in configuring the kernel and building the gator driver module.
13-However, it is possible that a user/developer has a kernel but does not have the source code. In this scenario it may or may not be possible to obtain a valid profile. 13-However, it is possible that a user/developer has a kernel but does not have the source code. In this scenario it may or may not be possible to obtain a valid profile.
14 -First, check if the kernel has the proper configuration options (see below). Profiling cannot occur using a kernel that is not configured properly, a new kernel must be created. 14 -First, check if the kernel has the proper configuration options (see below). Profiling cannot occur using a kernel that is not configured properly, a new kernel must be created. See if /proc/config.gz exists on the target.
15 -Second, given a properly configured kernel, check if the filesystem contains the kernel source/headers, which can be used to re-create the gator driver. 15 -Second, given a properly configured kernel, check if the filesystem contains the kernel source/headers, which can be used to re-create the gator driver. These files may be located in different areas, but common locations are /lib/modules/ and /usr/src.
16 -If the kernel is not properly configured or sources/headers are not available, the developer is on their own and kernel creation is beyond the scope of this document. Note: It is possible for a module to work when compiled against a similar kernel source code, though this is not guaranteed to work due to differences in kernel structures, exported symbols and incompatible configuration parameters. 16 -If the kernel is not properly configured or sources/headers are not available, the developer is on their own and kernel creation is beyond the scope of this document. Note: It is possible for a module to work when compiled against a similar kernel source code, though this is not guaranteed to work due to differences in kernel structures, exported symbols and incompatible configuration parameters.
17 17
18*** Preparing and building the kernel *** 18*** Kernel configuration ***
19 19
20cd into the root source dir of the linux kernel 20menuconfig options (depending on the kernel version, the location of these configuration settings within menuconfig may differ)
21if your target has never been configured, choose the appropriate configuration for your target 21- General Setup
22 make ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- <platform_defconfig> 22 - Kernel Performance Events And Counters
23make ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- menuconfig 23 - [*] Kernel performance events and counters (enables CONFIG_PERF_EVENTS)
24 24 - [*] Profiling Support (enables CONFIG_PROFILING)
25Required Kernel Changes (depending on the kernel version, the location of these configuration settings within menuconfig may be different) 25- Kernel Features
26- General Setup 26 - [*] High Resolution Timer Support (enables CONFIG_HIGH_RES_TIMERS)
27 - [*] Profiling Support 27 - [*] Use local timer interrupts (only required for SMP, enables CONFIG_LOCAL_TIMERS)
28- Kernel hacking 28 - [*] Enable hardware performance counter support for perf events (enables CONFIG_HW_PERF_EVENTS)
29 - [*] Tracers 29- CPU Power Management
30 - [*] Trace process context switches and events 30 - CPU Frequency scaling
31- Kernel Features 31 - [*] CPU Frequency scaling (enables CONFIG_CPU_FREQ)
32 - [*] High Resolution Timer Support 32- Kernel hacking
33 - [*] Use local timer interrupts (only required for SMP) 33 - [*] Mutex debugging: basic checks (optional, enables CONFIG_DEBUG_MUTEXES)
34 34 - [*] Compile the kernel with debug info (optional, enables CONFIG_DEBUG_INFO)
35The "context switches and events" option will not be available if other trace configurations are enabled. Other trace configurations being enabled is sufficient to turn on context switches and events. 35 - [*] Tracers
36 36 - [*] Trace process context switches and events (#)
37Optional Kernel Changes (depending on the kernel version, the location of these configuration settings within menuconfig may be different) 37
38Note: Configurations may not be supported on all targets 38(#) The "Trace process context switches and events" is not the only option that enables tracing (CONFIG_GENERIC_TRACER or CONFIG_TRACING) and may not be visible in menuconfig as an option if other trace configurations are enabled. Other trace configurations being enabled is sufficient to turn on tracing.
39- System Type 39
40 - [*] <SoC name> debugging peripherals (enable core performance counters on supported SoCs) /* kernels before 2.6.35 */ 40The configuration options:
41 41CONFIG_GENERIC_TRACER or CONFIG_TRACING
42make -j5 ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- uImage 42CONFIG_PROFILING
43 43CONFIG_HIGH_RES_TIMERS
44*** Checking the gator requirements *** 44CONFIG_LOCAL_TIMERS (for SMP systems)
45 45CONFIG_PERF_EVENTS and CONFIG_HW_PERF_EVENTS (kernel versions 3.0 and greater)
46(optional) Use the hrtimer_module utility to validate the kernel High Resolution Timer requirement. 46CONFIG_DEBUG_MUTEXES (optional, provides 'mutex' as a reason code when a thread stops running)
47 47CONFIG_DEBUG_INFO (optional, used for analyzing the kernel)
48*** Building the gator module *** 48CONFIG_CPU_FREQ (optional, provides frequency setting of the CPU)
49 49
50To create the gator.ko module, 50These may be verified on a running system using /proc/config.gz (if this file exists) by running 'zcat /proc/config.gz | grep <option>'. For example, confirming that CONFIG_PROFILING is enabled
51 cd /path/to/gator/driver-src 51 > zcat /proc/config.gz | grep CONFIG_PROFILING
52 tar xzf gator-driver.tar.gz 52 CONFIG_PROFILING=y
53 cd gator-driver 53
54 make -C <kernel_build_dir> M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules 54*** Checking the gator requirements ***
55for example 55
56 make -C /home/username/kernel_2.6.32/ M=`pwd` ARCH=arm CROSS_COMPILE=/home/username/CodeSourcery/Sourcery_G++_Lite/bin/arm-none-linux-gnueabi- modules 56(optional) Use the hrtimer_module utility to validate the kernel High Resolution Timer requirement.
57If successful, a gator.ko module should be generated 57
58 58*** Building the gator module ***
59*** Building the gator daemon *** 59
60 60To create the gator.ko module,
61cd /path/to/gator/daemon-src 61 cd /path/to/gator/driver-src
62tar -xzf gator-daemon.tar.gz 62 tar xzf gator-driver.tar.gz
63For Linux, 63 cd gator-driver
64 build with 'make' 64 make -C <kernel_build_dir> M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules
65For Android, 65for example when using the linaro-toolchain-binaries
66 mv gator-daemon jni 66 make -C /home/username/kernel_2.6.32/ M=`pwd` ARCH=arm CROSS_COMPILE=/home/username/gcc-linaro-arm-linux-gnueabihf-4.7-2013.01-20130125_linux/bin/arm-linux-gnueabihf- modules
67 install the android ndk, see developer.android.com 67If successful, a gator.ko module should be generated
68 /path/to/ndk/ndk-build 68
69 gatord should now be created and located in libs/armeabi 69*** Building the gator daemon ***
70 70
71*** Running gator *** 71cd /path/to/gator/daemon-src
72 72tar -xzf gator-daemon.tar.gz (may need to issue with 'sudo')
73Load the kernel onto the target and copy gatord and gator.ko into the target's filesystem. 73For Linux targets,
74Ensure gatord has execute permissions 74 cd gator-daemon
75 chmod +x gatord 75 make CROSS_COMPILE=<...> # For ARMv7 targets
76gator.ko must be located in the same directory as gatord on the target. 76 make -f Makefile_aarch64 CROSS_COMPILE=<...> # For ARMv8 targets
77With root privileges, run the daemon 77 gatord should now be created
78 sudo ./gatord & 78For Android targets (install the android ndk, see developer.android.com)
79 79 mv gator-daemon jni
80*** Compiling an application or shared library *** 80 ndk-build
81 81 or execute /path/to/ndk/ndk-build if the ndk is not on your path
82Recommended compiler settings: 82 gatord should now be created and located in libs/armeabi
83 "-g": Debug symbols needed for best analysis results. 83
84 "-fno-inline": Speed improvement when processing the image files and most accurate analysis results. 84*** Running gator ***
85 "-fno-omit-frame-pointer": ARM EABI frame pointers (Code Sourcery cross compiler) allow the call stack to be recorded with each sample taken when in ARM state (i.e. not -mthumb). 85
86 86Load the kernel onto the target and copy gatord and gator.ko into the target's filesystem.
87*** Profiling the kernel (optional) *** 87Ensure gatord has execute permissions
88 88 chmod +x gatord
89make ARCH=arm CROSS_COMPILE=$(CROSS_TOOLS}/bin/arm-none-linux-gnueabi- menuconfig 89gator.ko must be located in the same directory as gatord on the target or the location specified with the -m option or already insmod'ed.
90- Kernel Hacking 90With root privileges, run the daemon
91 - [*] Compile the kernel with debug info 91 sudo ./gatord &
92 92Note: gatord requires libstdc++.so.6 which is usually supplied by the Linux distribution on the target. A copy of libstdc++.so.6 is available in the DS-5 Linux example distribution.
93make -j5 ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- uImage 93
94Use vmlinux as the image for debug symbols in Streamline. 94*** Customizing the l2c-310 Counter ***
95Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the module as an image. 95
96To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko. 96The l2c-310 counter in gator_events_l2c-310.c contains hard coded offsets where the L2 cache counter registers are located. This offset can also be configured via a module parameter specified when gator.ko is loaded, ex:
97 97 insmod gator.ko l2c310_addr=<offset>
98*** Automatically start gator on boot (optional) *** 98Further, the l2c-310 counter can be disabled by providing an offset of zero, ex:
99 99 insmod gator.ko l2c310_addr=0
100cd /etc/init.d 100
101vi rungator.sh 101*** Compiling an application or shared library ***
102 #!/bin/bash 102
103 /path/to/gatord & 103Recommended compiler settings:
104update-rc.d rungator.sh defaults 104 "-g": Debug symbols needed for best analysis results.
105 105 "-fno-inline": Speed improvement when processing the image files and most accurate analysis results.
106*** GPL License *** 106 "-fno-omit-frame-pointer": ARM EABI frame pointers (Code Sourcery cross compiler) allow recording of the call stack with each sample taken when in ARM state (i.e. not -mthumb).
107 107 "-marm": This option is required if your compiler is configured with --with-mode=thumb, otherwise call stack unwinding will not work.
108For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz. 108
109*** Hardfloat EABI ***
110Binary applications built for the soft or softfp ABI are not compatible on a hardfloat system. All soft/softfp applications need to be rebuilt for hardfloat. To see if your ARM compiler supports hardfloat, run "gcc -v" and look for --with-float=hard.
111To compile for non-hardfloat targets it is necessary to add options '-marm -march=armv4t -mfloat-abi=soft'. It may also be necessary to provide a softfloat filesystem by adding the option --sysroot, ex: '--sysroot=../DS-5Examples/distribution/filesystem/armv5t_mtx'. The gatord makefile will do this when run as 'make SOFTFLOAT=1 SYSROOT=/path/to/sysroot'
112The armv5t_mtx filesystem is provided as part of the "DS-5 Linux Example Distribution" package which can be downloaded from the DS-5 Downloads page.
113Attempting to run an incompatible binary often results in the confusing error message "No such file or directory" when clearly the file exists.
114
115*** Bugs ***
116
117There is a bug in some Linux kernels where perf misidentifies the CPU type. To see if you are affected by this, run ls /sys/bus/event_source/devices/ and verify the listed processor type matches what is expected. For example, an A9 should show the following.
118
119# ls /sys/bus/event_source/devices/
120ARMv7_Cortex_A9 breakpoint software tracepoint
121
122To workaround the issue try upgrading to a later kernel or comment out the gator_events_perf_pmu_cpu_init(gator_cpu, type); cal in gator_events_perf_pmu.c
123
124*** Profiling the kernel (optional) ***
125
126CONFIG_DEBUG_INFO must be enabled, see "Kernel configuration" section above.
127Use vmlinux as the image for debug symbols in Streamline.
128Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the driver as an image to Streamline.
129To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko.
130
131*** Automatically start gator on boot (optional) ***
132
133cd /etc/init.d
134vi rungator.sh
135 #!/bin/bash
136 /path/to/gatord &
137update-rc.d rungator.sh defaults
138
139*** GPL License ***
140
141For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz.
142
diff --git a/daemon/Android.mk b/daemon/Android.mk
index b8cc7ff..86483f3 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -3,14 +3,18 @@ include $(CLEAR_VARS)
3 3
4XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h configuration_xml.h) 4XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h configuration_xml.h)
5 5
6LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions 6LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -DETCDIR=\"/etc\" -Ilibsensors
7 7
8LOCAL_SRC_FILES := \ 8LOCAL_SRC_FILES := \
9 Buffer.cpp \
9 CapturedXML.cpp \ 10 CapturedXML.cpp \
10 Child.cpp \ 11 Child.cpp \
11 Collector.cpp \ 12 Collector.cpp \
12 ConfigurationXML.cpp \ 13 ConfigurationXML.cpp \
14 Driver.cpp \
13 Fifo.cpp \ 15 Fifo.cpp \
16 Hwmon.cpp \
17 KMod.cpp \
14 LocalCapture.cpp \ 18 LocalCapture.cpp \
15 Logging.cpp \ 19 Logging.cpp \
16 main.cpp \ 20 main.cpp \
@@ -20,6 +24,14 @@ LOCAL_SRC_FILES := \
20 SessionData.cpp \ 24 SessionData.cpp \
21 SessionXML.cpp \ 25 SessionXML.cpp \
22 StreamlineSetup.cpp \ 26 StreamlineSetup.cpp \
27 libsensors/access.c \
28 libsensors/conf-lex.c \
29 libsensors/conf-parse.c \
30 libsensors/data.c \
31 libsensors/error.c \
32 libsensors/general.c \
33 libsensors/init.c \
34 libsensors/sysfs.c \
23 mxml/mxml-attr.c \ 35 mxml/mxml-attr.c \
24 mxml/mxml-entity.c \ 36 mxml/mxml-entity.c \
25 mxml/mxml-file.c \ 37 mxml/mxml-file.c \
diff --git a/daemon/Buffer.cpp b/daemon/Buffer.cpp
new file mode 100644
index 0000000..ee391bc
--- /dev/null
+++ b/daemon/Buffer.cpp
@@ -0,0 +1,354 @@
1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Buffer.h"
10
11#include "Logging.h"
12#include "Sender.h"
13#include "SessionData.h"
14
15#define mask (size - 1)
16
17Buffer::Buffer (const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : core(core), buftype(buftype), size(size), readPos(0), writePos(0), commitPos(0), available(true), done(false), buf(new char[size]),
18#ifdef GATOR_LIVE
19 commitTime(gSessionData->mLiveRate),
20#endif
21 readerSem(readerSem) {
22 if ((size & mask) != 0) {
23 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
24 handleException();
25 }
26 frame();
27}
28
29Buffer::~Buffer () {
30 delete [] buf;
31}
32
33void Buffer::write (Sender * const sender) {
34 if (!commitReady()) {
35 return;
36 }
37
38 // determine the size of two halves
39 int length1 = commitPos - readPos;
40 char * buffer1 = buf + readPos;
41 int length2 = 0;
42 char * buffer2 = buf;
43 if (length1 < 0) {
44 length1 = size - readPos;
45 length2 = commitPos;
46 }
47
48 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
49
50 // start, middle or end
51 if (length1 > 0) {
52 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
53 }
54
55 // possible wrap around
56 if (length2 > 0) {
57 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
58 }
59
60 readPos = commitPos;
61}
62
63bool Buffer::commitReady () const {
64 return commitPos != readPos;
65}
66
67int Buffer::bytesAvailable () const {
68 int filled = writePos - readPos;
69 if (filled < 0) {
70 filled += size;
71 }
72
73 int remaining = size - filled;
74
75 if (available) {
76 // Give some extra room; also allows space to insert the overflow error packet
77 remaining -= 200;
78 } else {
79 // Hysteresis, prevents multiple overflow messages
80 remaining -= 2000;
81 }
82
83 return remaining;
84}
85
86bool Buffer::checkSpace (const int bytes) {
87 const int remaining = bytesAvailable();
88
89 if (remaining < bytes) {
90 available = false;
91 } else {
92 available = true;
93 }
94
95 return available;
96}
97
98void Buffer::commit (const uint64_t time) {
99 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
100 const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
101 int length = writePos - commitPos;
102 if (length < 0) {
103 length += size;
104 }
105 length = length - typeLength - sizeof(int32_t);
106 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
107 buf[(commitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
108 }
109
110 logg->logMessage("Committing data readPos: %i writePos: %i commitPos: %i", readPos, writePos, commitPos);
111 commitPos = writePos;
112
113#ifdef GATOR_LIVE
114 if (gSessionData->mLiveRate > 0) {
115 while (time > commitTime) {
116 commitTime += gSessionData->mLiveRate;
117 }
118 }
119#endif
120
121 if (!done) {
122 frame();
123 }
124
125 // send a notification that data is ready
126 sem_post(readerSem);
127}
128
129void Buffer::check (const uint64_t time) {
130 int filled = writePos - commitPos;
131 if (filled < 0) {
132 filled += size;
133 }
134 if (filled >= ((size * 3) / 4)
135#ifdef GATOR_LIVE
136 || (gSessionData->mLiveRate > 0 && time >= commitTime)
137#endif
138 ) {
139 commit(time);
140 }
141}
142
143void Buffer::packInt (const int32_t x) {
144 const int write0 = (writePos + 0) & mask;
145 const int write1 = (writePos + 1) & mask;
146
147 if ((x & 0xffffff80) == 0) {
148 buf[write0] = x & 0x7f;
149 writePos = write1;
150 } else if ((x & 0xffffc000) == 0) {
151 const int write2 = (writePos + 2) & mask;
152 buf[write0] = x | 0x80;
153 buf[write1] = (x >> 7) & 0x7f;
154 writePos = write2;
155 } else if ((x & 0xffe00000) == 0) {
156 const int write2 = (writePos + 2) & mask;
157 const int write3 = (writePos + 3) & mask;
158 buf[write0] = x | 0x80;
159 buf[write1] = (x >> 7) | 0x80;
160 buf[write2] = (x >> 14) & 0x7f;
161 writePos = write3;
162 } else if ((x & 0xf0000000) == 0) {
163 const int write2 = (writePos + 2) & mask;
164 const int write3 = (writePos + 3) & mask;
165 const int write4 = (writePos + 4) & mask;
166 buf[write0] = x | 0x80;
167 buf[write1] = (x >> 7) | 0x80;
168 buf[write2] = (x >> 14) | 0x80;
169 buf[write3] = (x >> 21) & 0x7f;
170 writePos = write4;
171 } else {
172 const int write2 = (writePos + 2) & mask;
173 const int write3 = (writePos + 3) & mask;
174 const int write4 = (writePos + 4) & mask;
175 const int write5 = (writePos + 5) & mask;
176 buf[write0] = x | 0x80;
177 buf[write1] = (x >> 7) | 0x80;
178 buf[write2] = (x >> 14) | 0x80;
179 buf[write3] = (x >> 21) | 0x80;
180 buf[write4] = (x >> 28) & 0x0f;
181 writePos = write5;
182 }
183}
184
185void Buffer::packInt64 (const int64_t x) {
186 const int write0 = (writePos + 0) & mask;
187 const int write1 = (writePos + 1) & mask;
188
189 if ((x & 0xffffffffffffff80LL) == 0) {
190 buf[write0] = x & 0x7f;
191 writePos = write1;
192 } else if ((x & 0xffffffffffffc000LL) == 0) {
193 const int write2 = (writePos + 2) & mask;
194 buf[write0] = x | 0x80;
195 buf[write1] = (x >> 7) & 0x7f;
196 writePos = write2;
197 } else if ((x & 0xffffffffffe00000LL) == 0) {
198 const int write2 = (writePos + 2) & mask;
199 const int write3 = (writePos + 3) & mask;
200 buf[write0] = x | 0x80;
201 buf[write1] = (x >> 7) | 0x80;
202 buf[write2] = (x >> 14) & 0x7f;
203 writePos = write3;
204 } else if ((x & 0xfffffffff0000000LL) == 0) {
205 const int write2 = (writePos + 2) & mask;
206 const int write3 = (writePos + 3) & mask;
207 const int write4 = (writePos + 4) & mask;
208 buf[write0] = x | 0x80;
209 buf[write1] = (x >> 7) | 0x80;
210 buf[write2] = (x >> 14) | 0x80;
211 buf[write3] = (x >> 21) & 0x7f;
212 writePos = write4;
213 } else if ((x & 0xfffffff800000000LL) == 0) {
214 const int write2 = (writePos + 2) & mask;
215 const int write3 = (writePos + 3) & mask;
216 const int write4 = (writePos + 4) & mask;
217 const int write5 = (writePos + 5) & mask;
218 buf[write0] = x | 0x80;
219 buf[write1] = (x >> 7) | 0x80;
220 buf[write2] = (x >> 14) | 0x80;
221 buf[write3] = (x >> 21) | 0x80;
222 buf[write4] = (x >> 28) & 0x7f;
223 writePos = write5;
224 } else if ((x & 0xfffffc0000000000LL) == 0) {
225 const int write2 = (writePos + 2) & mask;
226 const int write3 = (writePos + 3) & mask;
227 const int write4 = (writePos + 4) & mask;
228 const int write5 = (writePos + 5) & mask;
229 const int write6 = (writePos + 6) & mask;
230 buf[write0] = x | 0x80;
231 buf[write1] = (x >> 7) | 0x80;
232 buf[write2] = (x >> 14) | 0x80;
233 buf[write3] = (x >> 21) | 0x80;
234 buf[write4] = (x >> 28) | 0x80;
235 buf[write5] = (x >> 35) & 0x7f;
236 writePos = write6;
237 } else if ((x & 0xfffe000000000000LL) == 0) {
238 const int write2 = (writePos + 2) & mask;
239 const int write3 = (writePos + 3) & mask;
240 const int write4 = (writePos + 4) & mask;
241 const int write5 = (writePos + 5) & mask;
242 const int write6 = (writePos + 6) & mask;
243 const int write7 = (writePos + 7) & mask;
244 buf[write0] = x | 0x80;
245 buf[write1] = (x >> 7) | 0x80;
246 buf[write2] = (x >> 14) | 0x80;
247 buf[write3] = (x >> 21) | 0x80;
248 buf[write4] = (x >> 28) | 0x80;
249 buf[write5] = (x >> 35) | 0x80;
250 buf[write6] = (x >> 42) & 0x7f;
251 writePos = write7;
252 } else if ((x & 0xff00000000000000LL) == 0) {
253 const int write2 = (writePos + 2) & mask;
254 const int write3 = (writePos + 3) & mask;
255 const int write4 = (writePos + 4) & mask;
256 const int write5 = (writePos + 5) & mask;
257 const int write6 = (writePos + 6) & mask;
258 const int write7 = (writePos + 7) & mask;
259 const int write8 = (writePos + 8) & mask;
260 buf[write0] = x | 0x80;
261 buf[write1] = (x >> 7) | 0x80;
262 buf[write2] = (x >> 14) | 0x80;
263 buf[write3] = (x >> 21) | 0x80;
264 buf[write4] = (x >> 28) | 0x80;
265 buf[write5] = (x >> 35) | 0x80;
266 buf[write6] = (x >> 42) | 0x80;
267 buf[write7] = (x >> 49) & 0x7f;
268 writePos = write8;
269 } else if ((x & 0x8000000000000000LL) == 0) {
270 const int write2 = (writePos + 2) & mask;
271 const int write3 = (writePos + 3) & mask;
272 const int write4 = (writePos + 4) & mask;
273 const int write5 = (writePos + 5) & mask;
274 const int write6 = (writePos + 6) & mask;
275 const int write7 = (writePos + 7) & mask;
276 const int write8 = (writePos + 8) & mask;
277 const int write9 = (writePos + 9) & mask;
278 buf[write0] = x | 0x80;
279 buf[write1] = (x >> 7) | 0x80;
280 buf[write2] = (x >> 14) | 0x80;
281 buf[write3] = (x >> 21) | 0x80;
282 buf[write4] = (x >> 28) | 0x80;
283 buf[write5] = (x >> 35) | 0x80;
284 buf[write6] = (x >> 42) | 0x80;
285 buf[write7] = (x >> 49) | 0x80;
286 buf[write8] = (x >> 56) & 0x7f;
287 writePos = write9;
288 } else {
289 const int write2 = (writePos + 2) & mask;
290 const int write3 = (writePos + 3) & mask;
291 const int write4 = (writePos + 4) & mask;
292 const int write5 = (writePos + 5) & mask;
293 const int write6 = (writePos + 6) & mask;
294 const int write7 = (writePos + 7) & mask;
295 const int write8 = (writePos + 8) & mask;
296 const int write9 = (writePos + 9) & mask;
297 const int write10 = (writePos + 10) & mask;
298 buf[write0] = x | 0x80;
299 buf[write1] = (x >> 7) | 0x80;
300 buf[write2] = (x >> 14) | 0x80;
301 buf[write3] = (x >> 21) | 0x80;
302 buf[write4] = (x >> 28) | 0x80;
303 buf[write5] = (x >> 35) | 0x80;
304 buf[write6] = (x >> 42) | 0x80;
305 buf[write7] = (x >> 49) | 0x80;
306 buf[write8] = (x >> 56) | 0x80;
307 buf[write9] = (x >> 63) & 0x7f;
308 writePos = write10;
309 }
310}
311
312void Buffer::frame () {
313 if (!gSessionData->mLocalCapture) {
314 packInt(RESPONSE_APC_DATA);
315 }
316 // Reserve space for the length
317 writePos += sizeof(int32_t);
318 packInt(buftype);
319 packInt(core);
320}
321
322bool Buffer::eventHeader (const uint64_t curr_time) {
323 bool retval = false;
324 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
325 packInt(0); // key of zero indicates a timestamp
326 packInt64(curr_time);
327 retval = true;
328 }
329
330 return retval;
331}
332
333void Buffer::event (const int32_t key, const int32_t value) {
334 if (checkSpace(2 * MAXSIZE_PACK32)) {
335 packInt(key);
336 packInt(value);
337 }
338}
339
340void Buffer::event64 (const int64_t key, const int64_t value) {
341 if (checkSpace(2 * MAXSIZE_PACK64)) {
342 packInt64(key);
343 packInt64(value);
344 }
345}
346
347void Buffer::setDone () {
348 done = true;
349 commit(0);
350}
351
352bool Buffer::isDone () const {
353 return done && readPos == commitPos && commitPos == writePos;
354}
diff --git a/daemon/Buffer.h b/daemon/Buffer.h
new file mode 100644
index 0000000..c460fb7
--- /dev/null
+++ b/daemon/Buffer.h
@@ -0,0 +1,66 @@
1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef BUFFER_H
10#define BUFFER_H
11
12#include <stddef.h>
13#include <stdint.h>
14#include <semaphore.h>
15
16#define GATOR_LIVE
17
18class Sender;
19
20class Buffer {
21public:
22 static const size_t MAXSIZE_PACK32 = 5;
23 static const size_t MAXSIZE_PACK64 = 10;
24
25 Buffer (int32_t core, int32_t buftype, const int size, sem_t *const readerSem);
26 ~Buffer ();
27
28 void write (Sender * sender);
29
30 int bytesAvailable () const;
31 void commit (const uint64_t time);
32 void check (const uint64_t time);
33
34 void frame ();
35
36 bool eventHeader (uint64_t curr_time);
37 void event (int32_t key, int32_t value);
38 void event64 (int64_t key, int64_t value);
39
40 void setDone ();
41 bool isDone () const;
42
43private:
44 bool commitReady () const;
45 bool checkSpace (int bytes);
46
47 void packInt (int32_t x);
48 void packInt64 (int64_t x);
49
50 const int32_t core;
51 const int32_t buftype;
52 const int size;
53 int readPos;
54 int writePos;
55 int commitPos;
56 bool available;
57 bool done;
58 char *const buf;
59#ifdef GATOR_LIVE
60 uint64_t commitTime;
61#endif
62
63 sem_t *const readerSem;
64};
65
66#endif // BUFFER_H
diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp
index cc218d7..8b037cb 100644
--- a/daemon/CapturedXML.cpp
+++ b/daemon/CapturedXML.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -21,21 +21,11 @@ CapturedXML::~CapturedXML() {
21} 21}
22 22
23mxml_node_t* CapturedXML::getTree(bool includeTime) { 23mxml_node_t* CapturedXML::getTree(bool includeTime) {
24 bool perfCounters = false;
25 mxml_node_t *xml; 24 mxml_node_t *xml;
26 mxml_node_t *captured; 25 mxml_node_t *captured;
27 mxml_node_t *target; 26 mxml_node_t *target;
28 mxml_node_t *counters;
29 mxml_node_t *counter;
30 int x; 27 int x;
31 28
32 for (x=0; x<MAX_PERFORMANCE_COUNTERS; x++) {
33 if (gSessionData->mPerfCounterEnabled[x]) {
34 perfCounters = true;
35 break;
36 }
37 }
38
39 xml = mxmlNewXML("1.0"); 29 xml = mxmlNewXML("1.0");
40 30
41 captured = mxmlNewElement(xml, "captured"); 31 captured = mxmlNewElement(xml, "captured");
@@ -51,35 +41,40 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
51 mxmlElementSetAttr(target, "name", gSessionData->mCoreName); 41 mxmlElementSetAttr(target, "name", gSessionData->mCoreName);
52 mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate); 42 mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate);
53 mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores); 43 mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores);
54 44 mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mCpuId);
55 if (perfCounters) { 45
56 counters = mxmlNewElement(captured, "counters"); 46 mxml_node_t *counters = NULL;
57 for (x = 0; x < MAX_PERFORMANCE_COUNTERS; x++) { 47 for (x = 0; x < MAX_PERFORMANCE_COUNTERS; x++) {
58 if (gSessionData->mPerfCounterEnabled[x]) { 48 const Counter & counter = gSessionData->mCounters[x];
59 counter = mxmlNewElement(counters, "counter"); 49 if (counter.isEnabled()) {
60 mxmlElementSetAttr(counter, "title", gSessionData->mPerfCounterTitle[x]); 50 if (counters == NULL) {
61 mxmlElementSetAttr(counter, "name", gSessionData->mPerfCounterName[x]); 51 counters = mxmlNewElement(captured, "counters");
62 mxmlElementSetAttrf(counter, "color", "0x%08x", gSessionData->mPerfCounterColor[x]); 52 }
63 mxmlElementSetAttrf(counter, "key", "0x%08x", gSessionData->mPerfCounterKey[x]); 53 mxml_node_t *const node = mxmlNewElement(counters, "counter");
64 mxmlElementSetAttr(counter, "type", gSessionData->mPerfCounterType[x]); 54 mxmlElementSetAttr(node, "title", counter.getTitle());
65 mxmlElementSetAttrf(counter, "event", "0x%08x", gSessionData->mPerfCounterEvent[x]); 55 mxmlElementSetAttr(node, "name", counter.getName());
66 if (gSessionData->mPerfCounterPerCPU[x]) { 56 mxmlElementSetAttrf(node, "key", "0x%08x", counter.getKey());
67 mxmlElementSetAttr(counter, "per_cpu", "yes"); 57 mxmlElementSetAttr(node, "type", counter.getType());
68 } 58 mxmlElementSetAttrf(node, "event", "0x%08x", counter.getEvent());
69 if (gSessionData->mPerfCounterCount[x] > 0) { 59 if (counter.isPerCPU()) {
70 mxmlElementSetAttrf(counter, "count", "%d", gSessionData->mPerfCounterCount[x]); 60 mxmlElementSetAttr(node, "per_cpu", "yes");
71 } 61 }
72 if (strlen(gSessionData->mPerfCounterDisplay[x]) > 0) { 62 if (counter.getCount() > 0) {
73 mxmlElementSetAttr(counter, "display", gSessionData->mPerfCounterDisplay[x]); 63 mxmlElementSetAttrf(node, "count", "%d", counter.getCount());
74 } 64 }
75 if (strlen(gSessionData->mPerfCounterUnits[x]) > 0) { 65 if (strlen(counter.getDisplay()) > 0) {
76 mxmlElementSetAttr(counter, "units", gSessionData->mPerfCounterUnits[x]); 66 mxmlElementSetAttr(node, "display", counter.getDisplay());
77 } 67 }
78 if (gSessionData->mPerfCounterAverageSelection[x]) { 68 if (strlen(counter.getUnits()) > 0) {
79 mxmlElementSetAttr(counter, "average_selection", "yes"); 69 mxmlElementSetAttr(node, "units", counter.getUnits());
80 } 70 }
81 mxmlElementSetAttr(counter, "description", gSessionData->mPerfCounterDescription[x]); 71 if (counter.getModifier() != 1) {
72 mxmlElementSetAttrf(node, "modifier", "%d", counter.getModifier());
73 }
74 if (counter.isAverageSelection()) {
75 mxmlElementSetAttr(node, "average_selection", "yes");
82 } 76 }
77 mxmlElementSetAttr(node, "description", counter.getDescription());
83 } 78 }
84 } 79 }
85 80
@@ -95,7 +90,7 @@ char* CapturedXML::getXML(bool includeTime) {
95} 90}
96 91
97void CapturedXML::write(char* path) { 92void CapturedXML::write(char* path) {
98 char *file = (char*)malloc(PATH_MAX); 93 char file[PATH_MAX];
99 94
100 // Set full path 95 // Set full path
101 snprintf(file, PATH_MAX, "%s/captured.xml", path); 96 snprintf(file, PATH_MAX, "%s/captured.xml", path);
@@ -107,7 +102,6 @@ void CapturedXML::write(char* path) {
107 } 102 }
108 103
109 free(xml); 104 free(xml);
110 free(file);
111} 105}
112 106
113// whitespace callback utility function used with mini-xml 107// whitespace callback utility function used with mini-xml
diff --git a/daemon/CapturedXML.h b/daemon/CapturedXML.h
index 3cac576..b0482f5 100644
--- a/daemon/CapturedXML.h
+++ b/daemon/CapturedXML.h
@@ -1,6 +1,5 @@
1/** 1/**
2 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * Copyright (C) ARM Limited 2010-2012. All rights reserved.
4 * 3 *
5 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Child.cpp b/daemon/Child.cpp
index b97e0db..c784847 100644
--- a/daemon/Child.cpp
+++ b/daemon/Child.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,8 +9,6 @@
9#include <stdlib.h> 9#include <stdlib.h>
10#include <string.h> 10#include <string.h>
11#include <signal.h> 11#include <signal.h>
12#include <sys/syscall.h>
13#include <sys/resource.h>
14#include <unistd.h> 12#include <unistd.h>
15#include <sys/prctl.h> 13#include <sys/prctl.h>
16#include "Logging.h" 14#include "Logging.h"
@@ -23,11 +21,18 @@
23#include "OlyUtility.h" 21#include "OlyUtility.h"
24#include "StreamlineSetup.h" 22#include "StreamlineSetup.h"
25#include "ConfigurationXML.h" 23#include "ConfigurationXML.h"
24#include "Driver.h"
25#include "Fifo.h"
26#include "Buffer.h"
26 27
27static sem_t haltPipeline, senderThreadStarted, startProfile; // Shared by Child and spawned threads 28#define NS_PER_S ((uint64_t)1000000000)
29#define NS_PER_US 1000
30
31static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads
28static Fifo* collectorFifo = NULL; // Shared by Child.cpp and spawned threads 32static Fifo* collectorFifo = NULL; // Shared by Child.cpp and spawned threads
33static Buffer* buffer = NULL;
29static Sender* sender = NULL; // Shared by Child.cpp and spawned threads 34static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
30Collector* collector = NULL; 35static Collector* collector = NULL;
31Child* child = NULL; // shared by Child.cpp and main.cpp 36Child* child = NULL; // shared by Child.cpp and main.cpp
32 37
33extern void cleanUp(); 38extern void cleanUp();
@@ -62,7 +67,7 @@ void handleException() {
62} 67}
63 68
64// CTRL C Signal Handler for child process 69// CTRL C Signal Handler for child process
65void child_handler(int signum) { 70static void child_handler(int signum) {
66 static bool beenHere = false; 71 static bool beenHere = false;
67 if (beenHere == true) { 72 if (beenHere == true) {
68 logg->logMessage("Gator is being forced to shut down."); 73 logg->logMessage("Gator is being forced to shut down.");
@@ -78,7 +83,7 @@ void child_handler(int signum) {
78 } 83 }
79} 84}
80 85
81void* durationThread(void* pVoid) { 86static void* durationThread(void* pVoid) {
82 prctl(PR_SET_NAME, (unsigned long)&"gatord-duration", 0, 0, 0); 87 prctl(PR_SET_NAME, (unsigned long)&"gatord-duration", 0, 0, 0);
83 sem_wait(&startProfile); 88 sem_wait(&startProfile);
84 if (gSessionData->mSessionIsActive) { 89 if (gSessionData->mSessionIsActive) {
@@ -94,7 +99,7 @@ void* durationThread(void* pVoid) {
94 return 0; 99 return 0;
95} 100}
96 101
97void* stopThread(void* pVoid) { 102static void* stopThread(void* pVoid) {
98 int length; 103 int length;
99 char type; 104 char type;
100 OlySocket* socket = child->socket; 105 OlySocket* socket = child->socket;
@@ -134,8 +139,61 @@ void* stopThread(void* pVoid) {
134 return 0; 139 return 0;
135} 140}
136 141
137void* senderThread(void* pVoid) { 142void* countersThread(void* pVoid) {
138 int length; 143 prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
144
145 gSessionData->hwmon.start();
146
147 int64_t monotonic_started = 0;
148 while (monotonic_started <= 0) {
149 usleep(10);
150
151 if (Collector::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
152 logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
153 handleException();
154 }
155 }
156
157 uint64_t next_time = 0;
158 while (gSessionData->mSessionIsActive) {
159 struct timespec ts;
160#ifndef CLOCK_MONOTONIC_RAW
161 // Android doesn't have this defined but it was added in Linux 2.6.28
162#define CLOCK_MONOTONIC_RAW 4
163#endif
164 if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
165 logg->logError(__FILE__, __LINE__, "Failed to get uptime");
166 handleException();
167 }
168 const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started;
169 // Sample ten times a second ignoring gSessionData->mSampleRate
170 next_time += NS_PER_S/10;//gSessionData->mSampleRate;
171 if (next_time < curr_time) {
172 logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
173 next_time = curr_time;
174 }
175
176 if (buffer->eventHeader(curr_time)) {
177 gSessionData->hwmon.read(buffer);
178 // Only check after writing all counters so that time and corresponding counters appear in the same frame
179 buffer->check(curr_time);
180 }
181
182 if (buffer->bytesAvailable() <= 0) {
183 logg->logMessage("One shot (counters)");
184 child->endSession();
185 }
186
187 usleep((next_time - curr_time)/NS_PER_US);
188 }
189
190 buffer->setDone();
191
192 return NULL;
193}
194
195static void* senderThread(void* pVoid) {
196 int length = 1;
139 char* data; 197 char* data;
140 char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0}; 198 char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0};
141 199
@@ -143,10 +201,17 @@ void* senderThread(void* pVoid) {
143 prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0); 201 prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0);
144 sem_wait(&haltPipeline); 202 sem_wait(&haltPipeline);
145 203
146 do { 204 while (length > 0 || !buffer->isDone()) {
205 sem_wait(&senderSem);
147 data = collectorFifo->read(&length); 206 data = collectorFifo->read(&length);
148 sender->writeData(data, length, RESPONSE_APC_DATA); 207 if (data != NULL) {
149 } while (length > 0); 208 sender->writeData(data, length, RESPONSE_APC_DATA);
209 collectorFifo->release();
210 }
211 if (!buffer->isDone()) {
212 buffer->write(sender);
213 }
214 }
150 215
151 // write end-of-capture sequence 216 // write end-of-capture sequence
152 if (!gSessionData->mLocalCapture) { 217 if (!gSessionData->mLocalCapture) {
@@ -185,6 +250,7 @@ void Child::initialization() {
185 // Initialize semaphores 250 // Initialize semaphores
186 sem_init(&senderThreadStarted, 0, 0); 251 sem_init(&senderThreadStarted, 0, 0);
187 sem_init(&startProfile, 0, 0); 252 sem_init(&startProfile, 0, 0);
253 sem_init(&senderSem, 0, 0);
188} 254}
189 255
190void Child::endSession() { 256void Child::endSession() {
@@ -197,7 +263,7 @@ void Child::run() {
197 char* collectBuffer; 263 char* collectBuffer;
198 int bytesCollected = 0; 264 int bytesCollected = 0;
199 LocalCapture* localCapture = NULL; 265 LocalCapture* localCapture = NULL;
200 pthread_t durationThreadID, stopThreadID, senderThreadID; 266 pthread_t durationThreadID, stopThreadID, senderThreadID, countersThreadID;
201 267
202 prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0); 268 prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0);
203 269
@@ -213,11 +279,24 @@ void Child::run() {
213 } 279 }
214 280
215 // Populate gSessionData with the configuration 281 // Populate gSessionData with the configuration
216 new ConfigurationXML(); 282 { ConfigurationXML configuration; }
217 283
218 // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated 284 // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
219 collector = new Collector(); 285 collector = new Collector();
220 286
287 // Initialize all drivers
288 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
289 driver->resetCounters();
290 }
291
292 // Set up counters using the associated driver's setup function
293 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
294 Counter & counter = gSessionData->mCounters[i];
295 if (counter.isEnabled()) {
296 counter.getDriver()->setupCounter(counter);
297 }
298 }
299
221 // Start up and parse session xml 300 // Start up and parse session xml
222 if (socket) { 301 if (socket) {
223 // Respond to Streamline requests 302 // Respond to Streamline requests
@@ -238,16 +317,16 @@ void Child::run() {
238 free(xmlString); 317 free(xmlString);
239 } 318 }
240 319
241 // Write configuration into the driver
242 collector->setupPerfCounters();
243
244 // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length 320 // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
245 logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, collector->getBufferSize()); 321 logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, collector->getBufferSize());
246 collectorFifo = new Fifo(collector->getBufferSize() + 5, gSessionData->mTotalBufferSize* 1024 * 1024); 322 collectorFifo = new Fifo(collector->getBufferSize() + 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem);
247 323
248 // Get the initial pointer to the collect buffer 324 // Get the initial pointer to the collect buffer
249 collectBuffer = collectorFifo->start(); 325 collectBuffer = collectorFifo->start();
250 326
327 // Create a new Block Counter Buffer
328 buffer = new Buffer(0, 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem);
329
251 // Sender thread shall be halted until it is signaled for one shot mode 330 // Sender thread shall be halted until it is signaled for one shot mode
252 sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2); 331 sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
253 332
@@ -261,6 +340,15 @@ void Child::run() {
261 thread_creation_success = false; 340 thread_creation_success = false;
262 } 341 }
263 342
343 if (gSessionData->hwmon.countersEnabled()) {
344 if (pthread_create(&countersThreadID, NULL, countersThread, this)) {
345 thread_creation_success = false;
346 }
347 } else {
348 // Let senderThread know there is no buffer data to send
349 buffer->setDone();
350 }
351
264 if (!thread_creation_success) { 352 if (!thread_creation_success) {
265 logg->logError(__FILE__, __LINE__, "Failed to create gator threads"); 353 logg->logError(__FILE__, __LINE__, "Failed to create gator threads");
266 handleException(); 354 handleException();
@@ -290,6 +378,10 @@ void Child::run() {
290 } while (bytesCollected > 0); 378 } while (bytesCollected > 0);
291 logg->logMessage("Exit collect data loop"); 379 logg->logMessage("Exit collect data loop");
292 380
381 if (gSessionData->hwmon.countersEnabled()) {
382 pthread_join(countersThreadID, NULL);
383 }
384
293 // Wait for the other threads to exit 385 // Wait for the other threads to exit
294 pthread_join(senderThreadID, NULL); 386 pthread_join(senderThreadID, NULL);
295 387
@@ -308,6 +400,7 @@ void Child::run() {
308 400
309 logg->logMessage("Profiling ended."); 401 logg->logMessage("Profiling ended.");
310 402
403 delete buffer;
311 delete collectorFifo; 404 delete collectorFifo;
312 delete sender; 405 delete sender;
313 delete collector; 406 delete collector;
diff --git a/daemon/Child.h b/daemon/Child.h
index 612ca7c..e39d182 100644
--- a/daemon/Child.h
+++ b/daemon/Child.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -10,8 +10,8 @@
10#define __CHILD_H__ 10#define __CHILD_H__
11 11
12#include <pthread.h> 12#include <pthread.h>
13#include "Fifo.h" 13
14#include "OlySocket.h" 14class OlySocket;
15 15
16class Child { 16class Child {
17public: 17public:
diff --git a/daemon/Collector.cpp b/daemon/Collector.cpp
index 2e4af0c..bf73534 100644
--- a/daemon/Collector.cpp
+++ b/daemon/Collector.cpp
@@ -1,18 +1,20 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#define __STDC_FORMAT_MACROS
10
9#include <fcntl.h> 11#include <fcntl.h>
10#include <malloc.h>
11#include <unistd.h> 12#include <unistd.h>
12#include <string.h> 13#include <string.h>
13#include <stdlib.h> 14#include <stdlib.h>
14#include <errno.h> 15#include <errno.h>
15#include <sys/time.h> 16#include <sys/time.h>
17#include <inttypes.h>
16#include "Collector.h" 18#include "Collector.h"
17#include "SessionData.h" 19#include "SessionData.h"
18#include "Logging.h" 20#include "Logging.h"
@@ -20,8 +22,6 @@
20 22
21// Driver initialization independent of session settings 23// Driver initialization independent of session settings
22Collector::Collector() { 24Collector::Collector() {
23 char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/<file>
24
25 mBufferFD = 0; 25 mBufferFD = 0;
26 26
27 checkVersion(); 27 checkVersion();
@@ -42,18 +42,6 @@ Collector::Collector() {
42 logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size"); 42 logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size");
43 handleException(); 43 handleException();
44 } 44 }
45
46 getCoreName();
47
48 enablePerfCounters();
49
50 // Read unchanging keys from driver which are created at insmod'ing of gator.ko
51 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
52 if (gSessionData->mPerfCounterEnabled[i]) {
53 snprintf(text, sizeof(text), "/dev/gator/events/%s/key", gSessionData->mPerfCounterType[i]);
54 readIntDriver(text, &gSessionData->mPerfCounterKey[i]);
55 }
56 }
57} 45}
58 46
59Collector::~Collector() { 47Collector::~Collector() {
@@ -66,63 +54,6 @@ Collector::~Collector() {
66 } 54 }
67} 55}
68 56
69#include <dirent.h>
70void Collector::enablePerfCounters() {
71 char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/enabled
72
73 // Initialize all perf counters in the driver, i.e. set enabled to zero
74 struct dirent *ent;
75 DIR* dir = opendir("/dev/gator/events");
76 if (dir) {
77 while ((ent = readdir(dir)) != NULL) {
78 // skip hidden files, current dir, and parent dir
79 if (ent->d_name[0] == '.')
80 continue;
81 snprintf(text, sizeof(text), "/dev/gator/events/%s/enabled", ent->d_name);
82 writeDriver(text, 0);
83 }
84 closedir (dir);
85 }
86
87 for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
88 if (!gSessionData->mPerfCounterEnabled[i]) {
89 continue;
90 }
91 snprintf(text, sizeof(text), "/dev/gator/events/%s/enabled", gSessionData->mPerfCounterType[i]);
92 if (writeReadDriver(text, &gSessionData->mPerfCounterEnabled[i])) {
93 // Disable those events that don't exist on this hardware platform even though they exist in configuration.xml
94 gSessionData->mPerfCounterEnabled[i] = 0;
95 continue;
96 }
97 }
98}
99
100void Collector::setupPerfCounters() {
101 char base[sizeof(gSessionData->mPerfCounterType[0]) + 20]; // sufficiently large to hold all /dev/gator/events/<types>
102 char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/<file>
103
104 for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
105 if (!gSessionData->mPerfCounterEnabled[i]) {
106 continue;
107 }
108 snprintf(base, sizeof(base), "/dev/gator/events/%s", gSessionData->mPerfCounterType[i]);
109 snprintf(text, sizeof(text), "%s/event", base);
110 writeDriver(text, gSessionData->mPerfCounterEvent[i]);
111 if (gSessionData->mPerfCounterEBSCapable[i]) {
112 snprintf(text, sizeof(text), "%s/count", base);
113 if (access(text, F_OK) == 0) {
114 if (writeReadDriver(text, &gSessionData->mPerfCounterCount[i]) && gSessionData->mPerfCounterCount[i] > 0) {
115 logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%s with a count of %d\n", gSessionData->mPerfCounterTitle[i], gSessionData->mPerfCounterName[i], gSessionData->mPerfCounterCount[i]);
116 handleException();
117 }
118 } else if (gSessionData->mPerfCounterCount[i] > 0) {
119 logg->logError(__FILE__, __LINE__, "Event Based Sampling is only supported with kernel versions 3.0.0 and higher with CONFIG_PERF_EVENTS=y, and CONFIG_HW_PERF_EVENTS=y\n");
120 handleException();
121 }
122 }
123 }
124}
125
126void Collector::checkVersion() { 57void Collector::checkVersion() {
127 int driver_version = 0; 58 int driver_version = 0;
128 59
@@ -179,6 +110,12 @@ void Collector::start() {
179 handleException(); 110 handleException();
180 } 111 }
181 112
113 // Set the live rate
114 if (writeReadDriver("/dev/gator/live_rate", &gSessionData->mLiveRate)) {
115 logg->logError(__FILE__, __LINE__, "Unable to set the driver live rate");
116 handleException();
117 }
118
182 logg->logMessage("Start the driver"); 119 logg->logMessage("Start the driver");
183 120
184 // This command makes the driver start profiling by calling gator_op_start() in the driver 121 // This command makes the driver start profiling by calling gator_op_start() in the driver
@@ -215,47 +152,26 @@ int Collector::collect(char* buffer) {
215 return bytesRead; 152 return bytesRead;
216} 153}
217 154
218void Collector::getCoreName() { 155int Collector::readIntDriver(const char* fullpath, int* value) {
219 char temp[256]; // arbitrarily large amount 156 FILE* file = fopen(fullpath, "r");
220 strcpy(gSessionData->mCoreName, "unknown"); 157 if (file == NULL) {
221 158 return -1;
222 FILE* f = fopen("/proc/cpuinfo", "r");
223 if (f == NULL) {
224 logg->logMessage("Error opening /proc/cpuinfo\n"
225 "The core name in the captured xml file will be 'unknown'.");
226 return;
227 } 159 }
228 160 if (fscanf(file, "%u", value) != 1) {
229 while (fgets(temp, sizeof(temp), f)) { 161 fclose(file);
230 if (strlen(temp) > 0) { 162 logg->logMessage("Invalid value in file %s", fullpath);
231 temp[strlen(temp) - 1] = 0; // Replace the line feed with a null 163 return -1;
232 }
233
234 if (strstr(temp, "Hardware") != 0) {
235 char* position = strchr(temp, ':');
236 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
237 logg->logMessage("Unknown format of /proc/cpuinfo\n"
238 "The core name in the captured xml file will be 'unknown'.");
239 return;
240 }
241 strncpy(gSessionData->mCoreName, (char*)((long)position + 2), sizeof(gSessionData->mCoreName));
242 gSessionData->mCoreName[sizeof(gSessionData->mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
243 fclose(f);
244 return;
245 }
246 } 164 }
247 165 fclose(file);
248 logg->logMessage("Could not determine core name from /proc/cpuinfo\n" 166 return 0;
249 "The core name in the captured xml file will be 'unknown'.");
250 fclose(f);
251} 167}
252 168
253int Collector::readIntDriver(const char* fullpath, int* value) { 169int Collector::readInt64Driver(const char* fullpath, int64_t* value) {
254 FILE* file = fopen(fullpath, "r"); 170 FILE* file = fopen(fullpath, "r");
255 if (file == NULL) { 171 if (file == NULL) {
256 return -1; 172 return -1;
257 } 173 }
258 if (fscanf(file, "%u", value) != 1) { 174 if (fscanf(file, "%" SCNi64, value) != 1) {
259 fclose(file); 175 fclose(file);
260 logg->logMessage("Invalid value in file %s", fullpath); 176 logg->logMessage("Invalid value in file %s", fullpath);
261 return -1; 177 return -1;
@@ -270,6 +186,12 @@ int Collector::writeDriver(const char* path, int value) {
270 return writeDriver(path, data); 186 return writeDriver(path, data);
271} 187}
272 188
189int Collector::writeDriver(const char* path, int64_t value) {
190 char data[40]; // Sufficiently large to hold any integer
191 snprintf(data, sizeof(data), "%" PRIi64, value);
192 return writeDriver(path, data);
193}
194
273int Collector::writeDriver(const char* fullpath, const char* data) { 195int Collector::writeDriver(const char* fullpath, const char* data) {
274 int fd = open(fullpath, O_WRONLY); 196 int fd = open(fullpath, O_WRONLY);
275 if (fd < 0) { 197 if (fd < 0) {
@@ -290,3 +212,10 @@ int Collector::writeReadDriver(const char* path, int* value) {
290 } 212 }
291 return 0; 213 return 0;
292} 214}
215
216int Collector::writeReadDriver(const char* path, int64_t* value) {
217 if (writeDriver(path, *value) || readInt64Driver(path, value)) {
218 return -1;
219 }
220 return 0;
221}
diff --git a/daemon/Collector.h b/daemon/Collector.h
index 5977a72..c5e9eac 100644
--- a/daemon/Collector.h
+++ b/daemon/Collector.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -18,20 +18,21 @@ public:
18 void start(); 18 void start();
19 void stop(); 19 void stop();
20 int collect(char* buffer); 20 int collect(char* buffer);
21 void enablePerfCounters();
22 void setupPerfCounters();
23 int getBufferSize() {return mBufferSize;} 21 int getBufferSize() {return mBufferSize;}
22
23 static int readIntDriver(const char* path, int* value);
24 static int readInt64Driver(const char* path, int64_t* value);
25 static int writeDriver(const char* path, int value);
26 static int writeDriver(const char* path, int64_t value);
27 static int writeDriver(const char* path, const char* data);
28 static int writeReadDriver(const char* path, int* value);
29 static int writeReadDriver(const char* path, int64_t* value);
30
24private: 31private:
25 int mBufferSize; 32 int mBufferSize;
26 int mBufferFD; 33 int mBufferFD;
27 34
28 void checkVersion(); 35 void checkVersion();
29 void getCoreName();
30
31 int readIntDriver(const char* path, int* value);
32 int writeDriver(const char* path, int value);
33 int writeDriver(const char* path, const char* data);
34 int writeReadDriver(const char* path, int* value);
35}; 36};
36 37
37#endif //__COLLECTOR_H__ 38#endif //__COLLECTOR_H__
diff --git a/daemon/ConfigurationXML.cpp b/daemon/ConfigurationXML.cpp
index 14c2809..9d51f26 100644
--- a/daemon/ConfigurationXML.cpp
+++ b/daemon/ConfigurationXML.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -10,30 +10,31 @@
10#include <stdlib.h> 10#include <stdlib.h>
11#include <dirent.h> 11#include <dirent.h>
12#include "ConfigurationXML.h" 12#include "ConfigurationXML.h"
13#include "Driver.h"
13#include "Logging.h" 14#include "Logging.h"
14#include "OlyUtility.h" 15#include "OlyUtility.h"
15#include "SessionData.h" 16#include "SessionData.h"
16 17
17static const char* ATTR_COUNTER = "counter"; 18static const char* ATTR_COUNTER = "counter";
18static const char* ATTR_REVISION = "revision"; 19static const char* ATTR_REVISION = "revision";
19static const char* ATTR_TITLE = "title"; 20static const char* ATTR_TITLE = "title";
20static const char* ATTR_NAME = "name"; 21static const char* ATTR_NAME = "name";
21static const char* ATTR_EVENT = "event"; 22static const char* ATTR_EVENT = "event";
22static const char* ATTR_COUNT = "count"; 23static const char* ATTR_COUNT = "count";
23static const char* ATTR_PER_CPU = "per_cpu"; 24static const char* ATTR_PER_CPU = "per_cpu";
24static const char* ATTR_DESCRIPTION = "description"; 25static const char* ATTR_DESCRIPTION = "description";
25static const char* ATTR_EBS = "supports_event_based_sampling"; 26static const char* ATTR_EBS = "supports_event_based_sampling";
26static const char* ATTR_DISPLAY = "display"; 27static const char* ATTR_DISPLAY = "display";
27static const char* ATTR_UNITS = "units"; 28static const char* ATTR_UNITS = "units";
28static const char* ATTR_AVERAGE_SELECTION = "average_selection"; 29static const char* ATTR_MODIFIER = "modifier";
30static const char* ATTR_AVERAGE_SELECTION = "average_selection";
29 31
30ConfigurationXML::ConfigurationXML() { 32ConfigurationXML::ConfigurationXML() {
31 const char * configuration_xml; 33 const char * configuration_xml;
32 unsigned int configuration_xml_len; 34 unsigned int configuration_xml_len;
33 getDefaultConfigurationXml(configuration_xml, configuration_xml_len); 35 getDefaultConfigurationXml(configuration_xml, configuration_xml_len);
34 36
35 mIndex = 0; 37 char path[PATH_MAX];
36 char* path = (char*)malloc(PATH_MAX);
37 38
38 if (gSessionData->mConfigurationXMLPath) { 39 if (gSessionData->mConfigurationXMLPath) {
39 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX); 40 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX);
@@ -45,35 +46,34 @@ ConfigurationXML::ConfigurationXML() {
45 } 46 }
46 mConfigurationXML = util->readFromDisk(path); 47 mConfigurationXML = util->readFromDisk(path);
47 48
48 if (mConfigurationXML == NULL) { 49 for (int retryCount = 0; retryCount < 2; ++retryCount) {
49 logg->logMessage("Unable to locate configuration.xml, using default in binary"); 50 if (mConfigurationXML == NULL) {
50 // null-terminate configuration_xml 51 logg->logMessage("Unable to locate configuration.xml, using default in binary");
51 mConfigurationXML = (char*)malloc(configuration_xml_len + 1); 52 // null-terminate configuration_xml
52 memcpy(mConfigurationXML, (const void*)configuration_xml, configuration_xml_len); 53 mConfigurationXML = (char*)malloc(configuration_xml_len + 1);
53 mConfigurationXML[configuration_xml_len] = 0; 54 memcpy(mConfigurationXML, (const void*)configuration_xml, configuration_xml_len);
54 } 55 mConfigurationXML[configuration_xml_len] = 0;
55 56 }
56 // disable all counters prior to parsing the configuration xml
57 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
58 gSessionData->mPerfCounterEnabled[i] = 0;
59 }
60 57
61 // clear counter overflow 58 int ret = parse(mConfigurationXML);
62 gSessionData->mCounterOverflow = false; 59 if (ret == 1) {
60 // remove configuration.xml on disk to use the default
61 if (remove(path) != 0) {
62 logg->logError(__FILE__, __LINE__, "Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk");
63 handleException();
64 }
65 logg->logMessage("Invalid configuration.xml file detected and removed");
63 66
64 int ret = parse(mConfigurationXML); 67 // Free the current configuration and reload
65 if (ret == 1) { 68 free((void*)mConfigurationXML);
66 // remove configuration.xml on disk to use the default 69 mConfigurationXML = NULL;
67 if (remove(path) != 0) { 70 continue;
68 logg->logError(__FILE__, __LINE__, "Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk");
69 handleException();
70 } 71 }
71 logg->logMessage("Invalid configuration.xml file detected and removed"); 72
73 break;
72 } 74 }
73 75
74 validate(); 76 validate();
75
76 free(path);
77} 77}
78 78
79ConfigurationXML::~ConfigurationXML() { 79ConfigurationXML::~ConfigurationXML() {
@@ -86,6 +86,15 @@ int ConfigurationXML::parse(const char* configurationXML) {
86 mxml_node_t *tree, *node; 86 mxml_node_t *tree, *node;
87 int ret; 87 int ret;
88 88
89 // clear counter overflow
90 gSessionData->mCounterOverflow = false;
91 mIndex = 0;
92
93 // disable all counters prior to parsing the configuration xml
94 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
95 gSessionData->mCounters[i].setEnabled(false);
96 }
97
89 tree = mxmlLoadString(NULL, configurationXML, MXML_NO_CALLBACK); 98 tree = mxmlLoadString(NULL, configurationXML, MXML_NO_CALLBACK);
90 99
91 node = mxmlGetFirstChild(tree); 100 node = mxmlGetFirstChild(tree);
@@ -111,18 +120,20 @@ int ConfigurationXML::parse(const char* configurationXML) {
111 120
112void ConfigurationXML::validate(void) { 121void ConfigurationXML::validate(void) {
113 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) { 122 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
114 if (gSessionData->mPerfCounterEnabled[i]) { 123 const Counter & counter = gSessionData->mCounters[i];
115 if (strcmp(gSessionData->mPerfCounterType[i], "") == 0) { 124 if (counter.isEnabled()) {
116 logg->logError(__FILE__, __LINE__, "Invalid required attribute in configuration.xml:\n counter=\"%s\"\n title=\"%s\"\n name=\"%s\"\n event=%d\n", gSessionData->mPerfCounterType[i], gSessionData->mPerfCounterTitle[i], gSessionData->mPerfCounterName[i], gSessionData->mPerfCounterEvent[i]); 125 if (strcmp(counter.getType(), "") == 0) {
126 logg->logError(__FILE__, __LINE__, "Invalid required attribute in configuration.xml:\n counter=\"%s\"\n title=\"%s\"\n name=\"%s\"\n event=%d\n", counter.getType(), counter.getTitle(), counter.getName(), counter.getEvent());
117 handleException(); 127 handleException();
118 } 128 }
119 129
120 // iterate through the remaining enabled performance counters 130 // iterate through the remaining enabled performance counters
121 for (int j = i + 1; j < MAX_PERFORMANCE_COUNTERS; j++) { 131 for (int j = i + 1; j < MAX_PERFORMANCE_COUNTERS; j++) {
122 if (gSessionData->mPerfCounterEnabled[j]) { 132 const Counter & counter2 = gSessionData->mCounters[j];
133 if (counter2.isEnabled()) {
123 // check if the types are the same 134 // check if the types are the same
124 if (strcmp(gSessionData->mPerfCounterType[i], gSessionData->mPerfCounterType[j]) == 0) { 135 if (strcmp(counter.getType(), counter2.getType()) == 0) {
125 logg->logError(__FILE__, __LINE__, "Duplicate performance counter type in configuration.xml: %s", gSessionData->mPerfCounterType[i]); 136 logg->logError(__FILE__, __LINE__, "Duplicate performance counter type in configuration.xml: %s", counter.getType());
126 handleException(); 137 handleException();
127 } 138 }
128 } 139 }
@@ -131,7 +142,7 @@ void ConfigurationXML::validate(void) {
131 } 142 }
132} 143}
133 144
134#define CONFIGURATION_REVISION 1 145#define CONFIGURATION_REVISION 2
135int ConfigurationXML::configurationsTag(mxml_node_t *node) { 146int ConfigurationXML::configurationsTag(mxml_node_t *node) {
136 const char* revision_string; 147 const char* revision_string;
137 148
@@ -156,26 +167,38 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
156 } 167 }
157 168
158 // read attributes 169 // read attributes
159 if (mxmlElementGetAttr(node, ATTR_COUNTER)) strncpy(gSessionData->mPerfCounterType[mIndex], mxmlElementGetAttr(node, ATTR_COUNTER), sizeof(gSessionData->mPerfCounterType[mIndex])); 170 Counter & counter = gSessionData->mCounters[mIndex];
160 if (mxmlElementGetAttr(node, ATTR_TITLE)) strncpy(gSessionData->mPerfCounterTitle[mIndex], mxmlElementGetAttr(node, ATTR_TITLE), sizeof(gSessionData->mPerfCounterTitle[mIndex])); 171 counter.clear();
161 if (mxmlElementGetAttr(node, ATTR_NAME)) strncpy(gSessionData->mPerfCounterName[mIndex], mxmlElementGetAttr(node, ATTR_NAME), sizeof(gSessionData->mPerfCounterName[mIndex])); 172 if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER));
162 if (mxmlElementGetAttr(node, ATTR_DESCRIPTION)) strncpy(gSessionData->mPerfCounterDescription[mIndex], mxmlElementGetAttr(node, ATTR_DESCRIPTION), sizeof(gSessionData->mPerfCounterDescription[mIndex])); 173 if (mxmlElementGetAttr(node, ATTR_TITLE)) counter.setTitle(mxmlElementGetAttr(node, ATTR_TITLE));
163 if (mxmlElementGetAttr(node, ATTR_EVENT)) gSessionData->mPerfCounterEvent[mIndex] = strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16); 174 if (mxmlElementGetAttr(node, ATTR_NAME)) counter.setName(mxmlElementGetAttr(node, ATTR_NAME));
164 if (mxmlElementGetAttr(node, ATTR_COUNT)) gSessionData->mPerfCounterCount[mIndex] = strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10); 175 if (mxmlElementGetAttr(node, ATTR_DESCRIPTION)) counter.setDescription(mxmlElementGetAttr(node, ATTR_DESCRIPTION));
165 if (mxmlElementGetAttr(node, ATTR_PER_CPU)) gSessionData->mPerfCounterPerCPU[mIndex] = util->stringToBool(mxmlElementGetAttr(node, ATTR_PER_CPU), false); 176 if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16));
166 if (mxmlElementGetAttr(node, ATTR_EBS)) gSessionData->mPerfCounterEBSCapable[mIndex] = util->stringToBool(mxmlElementGetAttr(node, ATTR_EBS), false); 177 if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10));
167 if (mxmlElementGetAttr(node, ATTR_DISPLAY)) strncpy(gSessionData->mPerfCounterDisplay[mIndex], mxmlElementGetAttr(node, ATTR_DISPLAY), sizeof(gSessionData->mPerfCounterDisplay[mIndex])); 178 if (mxmlElementGetAttr(node, ATTR_PER_CPU)) counter.setPerCPU(util->stringToBool(mxmlElementGetAttr(node, ATTR_PER_CPU), false));
168 if (mxmlElementGetAttr(node, ATTR_UNITS)) strncpy(gSessionData->mPerfCounterUnits[mIndex], mxmlElementGetAttr(node, ATTR_UNITS), sizeof(gSessionData->mPerfCounterUnits[mIndex])); 179 if (mxmlElementGetAttr(node, ATTR_EBS)) counter.setEBSCapable(util->stringToBool(mxmlElementGetAttr(node, ATTR_EBS), false));
169 if (mxmlElementGetAttr(node, ATTR_AVERAGE_SELECTION)) gSessionData->mPerfCounterAverageSelection[mIndex] = util->stringToBool(mxmlElementGetAttr(node, ATTR_AVERAGE_SELECTION), false); 180 if (mxmlElementGetAttr(node, ATTR_DISPLAY)) counter.setDisplay(mxmlElementGetAttr(node, ATTR_DISPLAY));
170 gSessionData->mPerfCounterEnabled[mIndex] = true; 181 if (mxmlElementGetAttr(node, ATTR_UNITS)) counter.setUnits(mxmlElementGetAttr(node, ATTR_UNITS));
171 182 if (mxmlElementGetAttr(node, ATTR_MODIFIER)) counter.setModifier(strtol(mxmlElementGetAttr(node, ATTR_MODIFIER), NULL, 10));
172 // strncpy does not guarantee a null-terminated string 183 if (mxmlElementGetAttr(node, ATTR_AVERAGE_SELECTION)) counter.setAverageSelection(util->stringToBool(mxmlElementGetAttr(node, ATTR_AVERAGE_SELECTION), false));
173 gSessionData->mPerfCounterType[mIndex][sizeof(gSessionData->mPerfCounterType[mIndex]) - 1] = 0; 184 counter.setEnabled(true);
174 gSessionData->mPerfCounterTitle[mIndex][sizeof(gSessionData->mPerfCounterTitle[mIndex]) - 1] = 0; 185
175 gSessionData->mPerfCounterName[mIndex][sizeof(gSessionData->mPerfCounterName[mIndex]) - 1] = 0; 186 // Associate a driver with each counter
176 gSessionData->mPerfCounterDescription[mIndex][sizeof(gSessionData->mPerfCounterDescription[mIndex]) - 1] = 0; 187 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
177 gSessionData->mPerfCounterDisplay[mIndex][sizeof(gSessionData->mPerfCounterDisplay[mIndex]) - 1] = 0; 188 if (driver->claimCounter(counter)) {
178 gSessionData->mPerfCounterUnits[mIndex][sizeof(gSessionData->mPerfCounterUnits[mIndex]) - 1] = 0; 189 if (counter.getDriver() != NULL) {
190 logg->logError(__FILE__, __LINE__, "More than one driver has claimed %s: %s", counter.getTitle(), counter.getName());
191 handleException();
192 }
193 counter.setDriver(driver);
194 }
195 }
196
197 // If no driver is associated with the counter, disable it
198 if (counter.getDriver() == NULL) {
199 logg->logMessage("No driver has claimed %s (%s: %s)", counter.getType(), counter.getTitle(), counter.getName());
200 counter.setEnabled(false);
201 }
179 202
180 // update counter index 203 // update counter index
181 mIndex++; 204 mIndex++;
diff --git a/daemon/ConfigurationXML.h b/daemon/ConfigurationXML.h
index 66ad587..f709ad1 100644
--- a/daemon/ConfigurationXML.h
+++ b/daemon/ConfigurationXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Counter.h b/daemon/Counter.h
new file mode 100644
index 0000000..041020b
--- /dev/null
+++ b/daemon/Counter.h
@@ -0,0 +1,97 @@
1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef COUNTER_H
10#define COUNTER_H
11
12#include <string.h>
13
14class Driver;
15
16class Counter {
17public:
18 static const size_t MAX_STRING_LEN = 80;
19 static const size_t MAX_DESCRIPTION_LEN = 400;
20
21 Counter () {
22 clear();
23 }
24
25 void clear () {
26 mType[0] = '\0';
27 mTitle[0] = '\0';
28 mName[0] = '\0';
29 mDescription[0] = '\0';
30 mDisplay[0] = '\0';
31 mUnits[0] = '\0';
32 mModifier = 1;
33 mEnabled = false;
34 mEvent = 0;
35 mCount = 0;
36 mKey = 0;
37 mPerCPU = false;
38 mEBSCapable = false;
39 mAverageSelection = false;
40 mDriver = NULL;
41 }
42
43 void setType(const char *const type) { strncpy(mType, type, sizeof(mType)); mType[sizeof(mType) - 1] = '\0'; }
44 void setTitle(const char *const title) { strncpy(mTitle, title, sizeof(mTitle)); mTitle[sizeof(mTitle) - 1] = '\0'; }
45 void setName(const char *const name) { strncpy(mName, name, sizeof(mName)); mName[sizeof(mName) - 1] = '\0'; }
46 void setDescription(const char *const description) { strncpy(mDescription, description, sizeof(mDescription)); mDescription[sizeof(mDescription) - 1] = '\0'; }
47 void setDisplay(const char *const display) { strncpy(mDisplay, display, sizeof(mDisplay)); mDisplay[sizeof(mDisplay) - 1] = '\0'; }
48 void setUnits(const char *const units) { strncpy(mUnits, units, sizeof(mUnits)); mUnits[sizeof(mUnits) - 1] = '\0'; }
49 void setModifier(const int modifier) { mModifier = modifier; }
50 void setEnabled(const bool enabled) { mEnabled = enabled; }
51 void setEvent(const int event) { mEvent = event; }
52 void setCount(const int count) { mCount = count; }
53 void setKey(const int key) { mKey = key; }
54 void setPerCPU(const bool perCPU) { mPerCPU = perCPU; }
55 void setEBSCapable(const bool ebsCapable) { mEBSCapable = ebsCapable; }
56 void setAverageSelection(const bool averageSelection) { mAverageSelection = averageSelection; }
57 void setDriver(Driver *const driver) { mDriver = driver; }
58
59 const char *getType() const { return mType;}
60 const char *getTitle() const { return mTitle; }
61 const char *getName() const { return mName; }
62 const char *getDescription() const { return mDescription; }
63 const char *getDisplay() const { return mDisplay; }
64 const char *getUnits() const { return mUnits; }
65 int getModifier() const { return mModifier; }
66 bool isEnabled() const { return mEnabled; }
67 int getEvent() const { return mEvent; }
68 int getCount() const { return mCount; }
69 int getKey() const { return mKey; }
70 bool isPerCPU() const { return mPerCPU; }
71 bool isEBSCapable() const { return mEBSCapable; }
72 bool isAverageSelection() const { return mAverageSelection; }
73 Driver *getDriver() const { return mDriver; }
74
75private:
76 // Intentionally unimplemented
77 Counter(const Counter &);
78 Counter & operator=(const Counter &);
79
80 char mType[MAX_STRING_LEN];
81 char mTitle[MAX_STRING_LEN];
82 char mName[MAX_STRING_LEN];
83 char mDescription[MAX_DESCRIPTION_LEN];
84 char mDisplay[MAX_STRING_LEN];
85 char mUnits[MAX_STRING_LEN];
86 int mModifier;
87 bool mEnabled;
88 int mEvent;
89 int mCount;
90 int mKey;
91 bool mPerCPU;
92 bool mEBSCapable;
93 bool mAverageSelection;
94 Driver *mDriver;
95};
96
97#endif // COUNTER_H
diff --git a/daemon/Driver.cpp b/daemon/Driver.cpp
new file mode 100644
index 0000000..c262467
--- /dev/null
+++ b/daemon/Driver.cpp
@@ -0,0 +1,15 @@
1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Driver.h"
10
11Driver *Driver::head = NULL;
12
13Driver::Driver() : next(head) {
14 head = this;
15}
diff --git a/daemon/Driver.h b/daemon/Driver.h
new file mode 100644
index 0000000..dd1dc27
--- /dev/null
+++ b/daemon/Driver.h
@@ -0,0 +1,44 @@
1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef DRIVER_H
10#define DRIVER_H
11
12#include "mxml/mxml.h"
13
14class Counter;
15
16class Driver {
17public:
18 static Driver *getHead() { return head; }
19
20 virtual ~Driver() {}
21
22 // Returns true if this driver can manage the counter
23 virtual bool claimCounter(const Counter &counter) const = 0;
24 // Clears and disables all counters
25 virtual void resetCounters() = 0;
26 // Enables and prepares the counter for capture
27 virtual void setupCounter(Counter &counter) = 0;
28
29 // Emits available counters
30 virtual void writeCounters(mxml_node_t *root) const = 0;
31 // Emits possible dynamically generated events/counters
32 virtual void writeEvents(mxml_node_t *root) const {}
33
34 Driver *getNext() const { return next; }
35
36protected:
37 Driver ();
38
39private:
40 static Driver *head;
41 Driver *next;
42};
43
44#endif // DRIVER_H
diff --git a/daemon/Fifo.cpp b/daemon/Fifo.cpp
index 4a27452..f0b0178 100644
--- a/daemon/Fifo.cpp
+++ b/daemon/Fifo.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -15,10 +15,11 @@
15// bufferSize is the amount of data to be filled 15// bufferSize is the amount of data to be filled
16// singleBufferSize is the maximum size that may be filled during a single write 16// singleBufferSize is the maximum size that may be filled during a single write
17// (bufferSize + singleBufferSize) will be allocated 17// (bufferSize + singleBufferSize) will be allocated
18Fifo::Fifo(int singleBufferSize, int bufferSize) { 18Fifo::Fifo(int singleBufferSize, int bufferSize, sem_t* readerSem) {
19 mWrite = mRead = mReadCommit = mRaggedEnd = 0; 19 mWrite = mRead = mReadCommit = mRaggedEnd = 0;
20 mWrapThreshold = bufferSize; 20 mWrapThreshold = bufferSize;
21 mSingleBufferSize = singleBufferSize; 21 mSingleBufferSize = singleBufferSize;
22 mReaderSem = readerSem;
22 mBuffer = (char*)valloc(bufferSize + singleBufferSize); 23 mBuffer = (char*)valloc(bufferSize + singleBufferSize);
23 mEnd = false; 24 mEnd = false;
24 25
@@ -27,7 +28,7 @@ Fifo::Fifo(int singleBufferSize, int bufferSize) {
27 handleException(); 28 handleException();
28 } 29 }
29 30
30 if (sem_init(&mWaitForSpaceSem, 0, 0) || sem_init(&mWaitForDataSem, 0, 0)) { 31 if (sem_init(&mWaitForSpaceSem, 0, 0)) {
31 logg->logError(__FILE__, __LINE__, "sem_init() failed"); 32 logg->logError(__FILE__, __LINE__, "sem_init() failed");
32 handleException(); 33 handleException();
33 } 34 }
@@ -36,7 +37,6 @@ Fifo::Fifo(int singleBufferSize, int bufferSize) {
36Fifo::~Fifo() { 37Fifo::~Fifo() {
37 free(mBuffer); 38 free(mBuffer);
38 sem_destroy(&mWaitForSpaceSem); 39 sem_destroy(&mWaitForSpaceSem);
39 sem_destroy(&mWaitForDataSem);
40} 40}
41 41
42int Fifo::numBytesFilled() const { 42int Fifo::numBytesFilled() const {
@@ -87,7 +87,7 @@ char* Fifo::write(int length) {
87 } 87 }
88 88
89 // send a notification that data is ready 89 // send a notification that data is ready
90 sem_post(&mWaitForDataSem); 90 sem_post(mReaderSem);
91 91
92 // wait for space 92 // wait for space
93 while (isFull()) { 93 while (isFull()) {
@@ -97,8 +97,7 @@ char* Fifo::write(int length) {
97 return &mBuffer[mWrite]; 97 return &mBuffer[mWrite];
98} 98}
99 99
100// This function will stall until data is available 100void Fifo::release() {
101char* Fifo::read(int *const length) {
102 // update the read pointer now that the data has been handled 101 // update the read pointer now that the data has been handled
103 mRead = mReadCommit; 102 mRead = mReadCommit;
104 103
@@ -109,10 +108,13 @@ char* Fifo::read(int *const length) {
109 108
110 // send a notification that data is free (space is available) 109 // send a notification that data is free (space is available)
111 sem_post(&mWaitForSpaceSem); 110 sem_post(&mWaitForSpaceSem);
111}
112 112
113// This function will return null if no data is available
114char* Fifo::read(int *const length) {
113 // wait for data 115 // wait for data
114 while (isEmpty() && !mEnd) { 116 if (isEmpty() && !mEnd) {
115 sem_wait(&mWaitForDataSem); 117 return NULL;
116 } 118 }
117 119
118 // obtain the length 120 // obtain the length
diff --git a/daemon/Fifo.h b/daemon/Fifo.h
index e2a5d94..d46e1af 100644
--- a/daemon/Fifo.h
+++ b/daemon/Fifo.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -13,7 +13,7 @@
13 13
14class Fifo { 14class Fifo {
15public: 15public:
16 Fifo(int singleBufferSize, int totalBufferSize); 16 Fifo(int singleBufferSize, int totalBufferSize, sem_t* readerSem);
17 ~Fifo(); 17 ~Fifo();
18 int numBytesFilled() const; 18 int numBytesFilled() const;
19 bool isEmpty() const; 19 bool isEmpty() const;
@@ -21,11 +21,13 @@ public:
21 bool willFill(int additional) const; 21 bool willFill(int additional) const;
22 char* start() const; 22 char* start() const;
23 char* write(int length); 23 char* write(int length);
24 void release();
24 char* read(int *const length); 25 char* read(int *const length);
25 26
26private: 27private:
27 int mSingleBufferSize, mWrite, mRead, mReadCommit, mRaggedEnd, mWrapThreshold; 28 int mSingleBufferSize, mWrite, mRead, mReadCommit, mRaggedEnd, mWrapThreshold;
28 sem_t mWaitForSpaceSem, mWaitForDataSem; 29 sem_t mWaitForSpaceSem;
30 sem_t* mReaderSem;
29 char* mBuffer; 31 char* mBuffer;
30 bool mEnd; 32 bool mEnd;
31}; 33};
diff --git a/daemon/Hwmon.cpp b/daemon/Hwmon.cpp
new file mode 100644
index 0000000..9603411
--- /dev/null
+++ b/daemon/Hwmon.cpp
@@ -0,0 +1,277 @@
1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Hwmon.h"
10
11#include "libsensors/sensors.h"
12
13#include "Buffer.h"
14#include "Counter.h"
15#include "Logging.h"
16#include "SessionData.h"
17
18class HwmonCounter {
19public:
20 HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature);
21 ~HwmonCounter();
22
23 HwmonCounter *getNext() const { return next; }
24 int getKey() const { return key; }
25 bool isEnabled() const { return enabled; }
26 const char *getName() const { return name; }
27 const char *getLabel() const { return label; }
28 const char *getTitle() const { return title; }
29 const char *getDisplay() const { return display; }
30 const char *getUnit() const { return unit; }
31 int getModifier() const { return modifier; }
32
33 void setEnabled(const bool enabled) { this->enabled = enabled; }
34
35 double read();
36
37private:
38 void init(const sensors_chip_name *chip, const sensors_feature *feature);
39
40 HwmonCounter *const next;
41 const int key;
42 bool enabled;
43
44 const sensors_chip_name *chip;
45 const sensors_feature *feature;
46
47 char *name;
48 char *label;
49 const char *title;
50 const char *display;
51 const char *unit;
52 int modifier;
53 bool monotonic;
54 double previous_value;
55
56 sensors_subfeature_type input;
57};
58
59HwmonCounter::HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(key), enabled(false), chip(chip), feature(feature) {
60
61 int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
62 char *chip_name = new char[len];
63 sensors_snprintf_chip_name(chip_name, len, chip);
64
65 len = snprintf(NULL, 0, "hwmon_%s_%d", chip_name, feature->number) + 1;
66 name = new char[len];
67 len = snprintf(name, len, "hwmon_%s_%d", chip_name, feature->number);
68
69 delete [] chip_name;
70
71 label = sensors_get_label(chip, feature);
72
73 switch (feature->type) {
74 case SENSORS_FEATURE_IN:
75 title = "Voltage";
76 input = SENSORS_SUBFEATURE_IN_INPUT;
77 display = "average";
78 unit = "V";
79 modifier = 1000;
80 monotonic = false;
81 break;
82 case SENSORS_FEATURE_FAN:
83 title = "Fan";
84 input = SENSORS_SUBFEATURE_FAN_INPUT;
85 display = "average";
86 unit = "RPM";
87 modifier = 1;
88 monotonic = false;
89 break;
90 case SENSORS_FEATURE_TEMP:
91 title = "Temperature";
92 input = SENSORS_SUBFEATURE_TEMP_INPUT;
93 display = "maximum";
94 unit = "°C";
95 modifier = 1000;
96 monotonic = false;
97 break;
98 case SENSORS_FEATURE_POWER:
99 title = "Power";
100 input = SENSORS_SUBFEATURE_POWER_INPUT;
101 display = "average";
102 unit = "W";
103 modifier = 1000000;
104 monotonic = false;
105 break;
106 case SENSORS_FEATURE_ENERGY:
107 title = "Energy";
108 input = SENSORS_SUBFEATURE_ENERGY_INPUT;
109 display = "accumulate";
110 unit = "J";
111 modifier = 1000000;
112 monotonic = true;
113 break;
114 case SENSORS_FEATURE_CURR:
115 title = "Current";
116 input = SENSORS_SUBFEATURE_CURR_INPUT;
117 display = "average";
118 unit = "A";
119 modifier = 1000;
120 monotonic = false;
121 break;
122 case SENSORS_FEATURE_HUMIDITY:
123 title = "Humidity";
124 input = SENSORS_SUBFEATURE_HUMIDITY_INPUT;
125 display = "average";
126 unit = "%";
127 modifier = 1000;
128 monotonic = false;
129 break;
130 default:
131 logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", feature->type);
132 handleException();
133 }
134}
135
136HwmonCounter::~HwmonCounter() {
137 free((void *)label);
138 delete [] name;
139}
140
141double HwmonCounter::read() {
142 double value;
143 double result;
144 const sensors_subfeature *subfeature;
145
146 subfeature = sensors_get_subfeature(chip, feature, input);
147 if (!subfeature) {
148 logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label);
149 handleException();
150 }
151
152 if (sensors_get_value(chip, subfeature->number, &value) != 0) {
153 logg->logError(__FILE__, __LINE__, "Can't get input value for hwmon sensor %s", label);
154 handleException();
155 }
156
157 result = (monotonic ? value - previous_value : value);
158 previous_value = value;
159
160 return result;
161}
162
163
164Hwmon::Hwmon() : counters(NULL) {
165 int err = sensors_init(NULL);
166 if (err) {
167 logg->logMessage("Failed to initialize libsensors! (%d)", err);
168 return;
169 }
170 sensors_sysfs_no_scaling = 1;
171
172 int chip_nr = 0;
173 const sensors_chip_name *chip;
174 while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
175 int feature_nr = 0;
176 const sensors_feature *feature;
177 while ((feature = sensors_get_features(chip, &feature_nr))) {
178 counters = new HwmonCounter(counters, getEventKey(), chip, feature);
179 }
180 }
181}
182
183Hwmon::~Hwmon() {
184 while (counters != NULL) {
185 HwmonCounter * counter = counters;
186 counters = counter->getNext();
187 delete counter;
188 }
189 sensors_cleanup();
190}
191
192HwmonCounter *Hwmon::findCounter(const Counter &counter) const {
193 for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) {
194 if (strcmp(hwmonCounter->getName(), counter.getType()) == 0) {
195 return hwmonCounter;
196 }
197 }
198
199 return NULL;
200}
201
202bool Hwmon::claimCounter(const Counter &counter) const {
203 return findCounter(counter) != NULL;
204}
205
206bool Hwmon::countersEnabled() const {
207 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
208 if (counter->isEnabled()) {
209 return true;
210 }
211 }
212 return false;
213}
214
215void Hwmon::resetCounters() {
216 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
217 counter->setEnabled(false);
218 }
219}
220
221void Hwmon::setupCounter(Counter &counter) {
222 HwmonCounter *const hwmonCounter = findCounter(counter);
223 if (hwmonCounter == NULL) {
224 counter.setEnabled(false);
225 return;
226 }
227 hwmonCounter->setEnabled(true);
228 counter.setKey(hwmonCounter->getKey());
229}
230
231void Hwmon::writeCounters(mxml_node_t *root) const {
232 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
233 mxml_node_t *node = mxmlNewElement(root, "counter");
234 mxmlElementSetAttr(node, "name", counter->getName());
235 }
236}
237
238void Hwmon::writeEvents(mxml_node_t *root) const {
239 root = mxmlNewElement(root, "category");
240 mxmlElementSetAttr(root, "name", "hwmon");
241
242 char buf[1024];
243 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
244 mxml_node_t *node = mxmlNewElement(root, "event");
245 mxmlElementSetAttr(node, "counter", counter->getName());
246 mxmlElementSetAttr(node, "title", counter->getTitle());
247 mxmlElementSetAttr(node, "name", counter->getLabel());
248 mxmlElementSetAttr(node, "display", counter->getDisplay());
249 mxmlElementSetAttr(node, "units", counter->getUnit());
250 if (counter->getModifier() != 1) {
251 mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier());
252 }
253 if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
254 mxmlElementSetAttr(node, "average_selection", "yes");
255 }
256 snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName());
257 mxmlElementSetAttr(node, "description", buf);
258 }
259}
260
261void Hwmon::start() {
262 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
263 if (!counter->isEnabled()) {
264 continue;
265 }
266 counter->read();
267 }
268}
269
270void Hwmon::read(Buffer * const buffer) {
271 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
272 if (!counter->isEnabled()) {
273 continue;
274 }
275 buffer->event(counter->getKey(), counter->read());
276 }
277}
diff --git a/daemon/Hwmon.h b/daemon/Hwmon.h
new file mode 100644
index 0000000..35981dc
--- /dev/null
+++ b/daemon/Hwmon.h
@@ -0,0 +1,39 @@
1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef HWMON_H
10#define HWMON_H
11
12#include "Driver.h"
13
14class Buffer;
15class HwmonCounter;
16
17class Hwmon : public Driver {
18public:
19 Hwmon();
20 ~Hwmon();
21
22 bool claimCounter(const Counter &counter) const;
23 bool countersEnabled() const;
24 void resetCounters();
25 void setupCounter(Counter &counter);
26
27 void writeCounters(mxml_node_t *root) const;
28 void writeEvents(mxml_node_t *root) const;
29
30 void start();
31 void read(Buffer * buffer);
32
33private:
34 HwmonCounter *findCounter(const Counter &counter) const;
35
36 HwmonCounter *counters;
37};
38
39#endif // HWMON_H
diff --git a/daemon/KMod.cpp b/daemon/KMod.cpp
new file mode 100644
index 0000000..5f12046
--- /dev/null
+++ b/daemon/KMod.cpp
@@ -0,0 +1,102 @@
1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "KMod.h"
10
11#include <sys/types.h>
12#include <dirent.h>
13#include <unistd.h>
14
15#include "Collector.h"
16#include "Counter.h"
17#include "Logging.h"
18
19// Claim all the counters in /dev/gator/events
20bool KMod::claimCounter(const Counter &counter) const {
21 char text[128];
22 snprintf(text, sizeof(text), "/dev/gator/events/%s", counter.getType());
23 return access(text, F_OK) == 0;
24}
25
26void KMod::resetCounters() {
27 char base[128];
28 char text[128];
29
30 // Initialize all perf counters in the driver, i.e. set enabled to zero
31 struct dirent *ent;
32 DIR* dir = opendir("/dev/gator/events");
33 if (dir) {
34 while ((ent = readdir(dir)) != NULL) {
35 // skip hidden files, current dir, and parent dir
36 if (ent->d_name[0] == '.')
37 continue;
38 snprintf(base, sizeof(base), "/dev/gator/events/%s", ent->d_name);
39 snprintf(text, sizeof(text), "%s/enabled", base);
40 Collector::writeDriver(text, 0);
41 snprintf(text, sizeof(text), "%s/count", base);
42 Collector::writeDriver(text, 0);
43 }
44 closedir(dir);
45 }
46}
47
48void KMod::setupCounter(Counter &counter) {
49 char base[128];
50 char text[128];
51 snprintf(base, sizeof(base), "/dev/gator/events/%s", counter.getType());
52
53 snprintf(text, sizeof(text), "%s/enabled", base);
54 int enabled = true;
55 if (Collector::writeReadDriver(text, &enabled) || !enabled) {
56 counter.setEnabled(false);
57 return;
58 }
59
60 snprintf(text, sizeof(text), "%s/key", base);
61 int key;
62 Collector::readIntDriver(text, &key);
63 counter.setKey(key);
64
65 snprintf(text, sizeof(text), "%s/event", base);
66 Collector::writeDriver(text, counter.getEvent());
67 if (counter.isEBSCapable()) {
68 snprintf(text, sizeof(text), "%s/count", base);
69 if (access(text, F_OK) == 0) {
70 int count = counter.getCount();
71 if (Collector::writeReadDriver(text, &count) && counter.getCount() > 0) {
72 logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%s with a count of %d\n", counter.getTitle(), counter.getName(), counter.getCount());
73 handleException();
74 }
75 counter.setCount(count);
76 } else if (counter.getCount() > 0) {
77 logg->logError(__FILE__, __LINE__, "Event Based Sampling is only supported with kernel versions 3.0.0 and higher with CONFIG_PERF_EVENTS=y, and CONFIG_HW_PERF_EVENTS=y\n");
78 handleException();
79 }
80 }
81}
82
83void KMod::writeCounters(mxml_node_t *root) const {
84 struct dirent *ent;
85 mxml_node_t *counter;
86
87 // counters.xml is simply a file listing of /dev/gator/events
88 DIR* dir = opendir("/dev/gator/events");
89 if (dir == NULL) {
90 logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events");
91 handleException();
92 }
93
94 while ((ent = readdir(dir)) != NULL) {
95 // skip hidden files, current dir, and parent dir
96 if (ent->d_name[0] == '.')
97 continue;
98 counter = mxmlNewElement(root, "counter");
99 mxmlElementSetAttr(counter, "name", ent->d_name);
100 }
101 closedir(dir);
102}
diff --git a/daemon/KMod.h b/daemon/KMod.h
new file mode 100644
index 0000000..7974262
--- /dev/null
+++ b/daemon/KMod.h
@@ -0,0 +1,27 @@
1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef KMOD_H
10#define KMOD_H
11
12#include "Driver.h"
13
14// Driver for the gator kernel module
15class KMod : public Driver {
16public:
17 KMod() {}
18 ~KMod() {}
19
20 bool claimCounter(const Counter &counter) const;
21 void resetCounters();
22 void setupCounter(Counter &counter);
23
24 void writeCounters(mxml_node_t *root) const;
25};
26
27#endif // KMOD_H
diff --git a/daemon/LocalCapture.cpp b/daemon/LocalCapture.cpp
index 2dd3aff..baa3dd9 100644
--- a/daemon/LocalCapture.cpp
+++ b/daemon/LocalCapture.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -30,7 +30,7 @@ void LocalCapture::createAPCDirectory(char* target_path) {
30} 30}
31 31
32void LocalCapture::write(char* string) { 32void LocalCapture::write(char* string) {
33 char* file = (char*)malloc(PATH_MAX); 33 char file[PATH_MAX];
34 34
35 // Set full path 35 // Set full path
36 snprintf(file, PATH_MAX, "%s/session.xml", gSessionData->mAPCDir); 36 snprintf(file, PATH_MAX, "%s/session.xml", gSessionData->mAPCDir);
@@ -40,13 +40,11 @@ void LocalCapture::write(char* string) {
40 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); 40 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
41 handleException(); 41 handleException();
42 } 42 }
43
44 free(file);
45} 43}
46 44
47char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* ending) { 45char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* ending) {
48 char* output; 46 char* output;
49 char* path = (char*)malloc(PATH_MAX); 47 char path[PATH_MAX];
50 48
51 // Ensure the path is an absolute path, i.e. starts with a slash 49 // Ensure the path is an absolute path, i.e. starts with a slash
52 if (initialPath == 0 || strlen(initialPath) == 0) { 50 if (initialPath == 0 || strlen(initialPath) == 0) {
@@ -70,7 +68,6 @@ char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* e
70 68
71 output = strdup(path); 69 output = strdup(path);
72 70
73 free(path);
74 return output; 71 return output;
75} 72}
76 73
@@ -107,7 +104,7 @@ int LocalCapture::removeDirAndAllContents(char* path) {
107} 104}
108 105
109void LocalCapture::copyImages(ImageLinkList* ptr) { 106void LocalCapture::copyImages(ImageLinkList* ptr) {
110 char* dstfilename = (char*)malloc(PATH_MAX); 107 char dstfilename[PATH_MAX];
111 108
112 while (ptr) { 109 while (ptr) {
113 strncpy(dstfilename, gSessionData->mAPCDir, PATH_MAX); 110 strncpy(dstfilename, gSessionData->mAPCDir, PATH_MAX);
@@ -124,5 +121,4 @@ void LocalCapture::copyImages(ImageLinkList* ptr) {
124 121
125 ptr = ptr->next; 122 ptr = ptr->next;
126 } 123 }
127 free(dstfilename);
128} 124}
diff --git a/daemon/LocalCapture.h b/daemon/LocalCapture.h
index 40f7883..8042d6a 100644
--- a/daemon/LocalCapture.h
+++ b/daemon/LocalCapture.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,7 +9,7 @@
9#ifndef __LOCAL_CAPTURE_H__ 9#ifndef __LOCAL_CAPTURE_H__
10#define __LOCAL_CAPTURE_H__ 10#define __LOCAL_CAPTURE_H__
11 11
12#include "SessionXML.h" 12struct ImageLinkList;
13 13
14class LocalCapture { 14class LocalCapture {
15public: 15public:
diff --git a/daemon/Logging.cpp b/daemon/Logging.cpp
index 3e6f8a3..5fd45b5 100644
--- a/daemon/Logging.cpp
+++ b/daemon/Logging.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -10,7 +10,6 @@
10#include <stdlib.h> 10#include <stdlib.h>
11#include <stdarg.h> 11#include <stdarg.h>
12#include <string.h> 12#include <string.h>
13#include "OlyUtility.h"
14 13
15#ifdef WIN32 14#ifdef WIN32
16#define MUTEX_INIT() mLoggingMutex = CreateMutex(NULL, false, NULL); 15#define MUTEX_INIT() mLoggingMutex = CreateMutex(NULL, false, NULL);
diff --git a/daemon/Logging.h b/daemon/Logging.h
index 37f7dd3..8f960de 100644
--- a/daemon/Logging.h
+++ b/daemon/Logging.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -42,6 +42,6 @@ private:
42 42
43extern Logging* logg; 43extern Logging* logg;
44 44
45extern void handleException(); 45extern void handleException() __attribute__ ((noreturn));
46 46
47#endif //__LOGGING_H__ 47#endif //__LOGGING_H__
diff --git a/daemon/Makefile b/daemon/Makefile
index 95d1809..24ee940 100644
--- a/daemon/Makefile
+++ b/daemon/Makefile
@@ -5,54 +5,21 @@
5# Uncomment and define CROSS_COMPILE if it is not already defined 5# Uncomment and define CROSS_COMPILE if it is not already defined
6# CROSS_COMPILE=/path/to/cross-compiler/arm-linux-gnueabihf- 6# CROSS_COMPILE=/path/to/cross-compiler/arm-linux-gnueabihf-
7# NOTE: This toolchain uses the hardfloat abi by default. For non-hardfloat 7# NOTE: This toolchain uses the hardfloat abi by default. For non-hardfloat
8# targets it is necessary to add options 8# targets run 'make SOFTFLOAT=1 SYSROOT=/path/to/sysroot', see
9# '-marm -march=armv4t -mfloat-abi=soft'. 9# README_Streamline.txt for more details
10 10
11CPP = $(CROSS_COMPILE)g++ 11CPP = $(CROSS_COMPILE)g++
12GCC = $(CROSS_COMPILE)gcc 12GCC = $(CROSS_COMPILE)gcc
13 13
14# -g produces debugging information
15# -O3 maximum optimization
16# -O0 no optimization, used for debugging
17# -Wall enables most warnings
18# -Werror treats warnings as errors
19# -std=c++0x is the planned new c++ standard
20# -std=c++98 is the 1998 c++ standard
21# -mthumb-interwork is required for interworking to ARM or Thumb stdlibc 14# -mthumb-interwork is required for interworking to ARM or Thumb stdlibc
22CFLAGS = -O3 -Wall -mthumb-interwork -fno-exceptions 15CFLAGS += -mthumb-interwork
23CXXFLAGS = -fno-rtti
24ifeq ($(WERROR),1)
25 CFLAGS += -Werror
26endif
27# -s strips the binary of debug info
28LDFLAGS = -s
29TARGET = gatord
30C_SRC = $(wildcard mxml/*.c)
31CPP_SRC = $(wildcard *.cpp)
32
33all: $(TARGET)
34
35events.xml: events_header.xml $(wildcard events-*.xml) events_footer.xml
36 cat $^ > $@
37
38StreamlineSetup.cpp: events_xml.h
39ConfigurationXML.cpp: configuration_xml.h
40
41%_xml.h: %.xml escape
42 ./escape $< > $@
43 16
44%.o: %.c *.h 17ifeq ($(SOFTFLOAT),1)
45 $(GCC) -c $(CFLAGS) -o $@ $< 18 CFLAGS += -marm -march=armv4t -mfloat-abi=soft
46 19 LDFLAGS += -marm -march=armv4t -mfloat-abi=soft
47%.o: %.cpp *.h 20endif
48 $(CPP) -c $(CFLAGS) $(CXXFLAGS) -o $@ $< 21ifneq ($(SYSROOT),)
49 22 LDFLAGS += --sysroot=$(SYSROOT)
50$(TARGET): $(CPP_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o) 23endif
51 $(CPP) $(LDFLAGS) -o $@ $^ -lc -lrt -lpthread
52 rm -f events_xml.h configuration_xml.h
53
54escape: escape.c
55 gcc $^ -o $@
56 24
57clean: 25include common.mk
58 rm -f *.o mxml/*.o $(TARGET) escape events.xml events_xml.h configuration_xml.h
diff --git a/daemon/Makefile_aarch64 b/daemon/Makefile_aarch64
new file mode 100644
index 0000000..10b4b4a
--- /dev/null
+++ b/daemon/Makefile_aarch64
@@ -0,0 +1,15 @@
1#
2# Makefile for ARM Streamline - Gator Daemon
3# make -f Makefile_aarch64
4#
5
6# Uncomment and define CROSS_COMPILE if it is not already defined
7# CROSS_COMPILE=/path/to/cross-compiler/arm-linux-gnueabihf-
8# NOTE: This toolchain uses the hardfloat abi by default. For non-hardfloat
9# targets it is necessary to add options
10# '-marm -march=armv4t -mfloat-abi=soft'.
11
12CPP = $(CROSS_COMPILE)g++
13GCC = $(CROSS_COMPILE)gcc
14
15include common.mk
diff --git a/daemon/OlySocket.cpp b/daemon/OlySocket.cpp
index 6128dc0..499f68c 100644
--- a/daemon/OlySocket.cpp
+++ b/daemon/OlySocket.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/OlySocket.h b/daemon/OlySocket.h
index b306908..5bab7d1 100644
--- a/daemon/OlySocket.h
+++ b/daemon/OlySocket.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/OlyUtility.cpp b/daemon/OlyUtility.cpp
index df4fe22..2f85131 100644
--- a/daemon/OlyUtility.cpp
+++ b/daemon/OlyUtility.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/OlyUtility.h b/daemon/OlyUtility.h
index 424c583..5c68a58 100644
--- a/daemon/OlyUtility.h
+++ b/daemon/OlyUtility.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Sender.cpp b/daemon/Sender.cpp
index 54f2207..159503f 100644
--- a/daemon/Sender.cpp
+++ b/daemon/Sender.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,7 @@
15#include <unistd.h> 15#include <unistd.h>
16#include "Sender.h" 16#include "Sender.h"
17#include "Logging.h" 17#include "Logging.h"
18#include "OlySocket.h"
18#include "SessionData.h" 19#include "SessionData.h"
19 20
20Sender::Sender(OlySocket* socket) { 21Sender::Sender(OlySocket* socket) {
@@ -69,6 +70,11 @@ void Sender::createDataFile(char* apcDir) {
69 } 70 }
70} 71}
71 72
73template<typename T>
74inline T min(const T a, const T b) {
75 return (a < b ? a : b);
76}
77
72void Sender::writeData(const char* data, int length, int type) { 78void Sender::writeData(const char* data, int length, int type) {
73 if (length < 0 || (data == NULL && length > 0)) { 79 if (length < 0 || (data == NULL && length > 0)) {
74 return; 80 return;
@@ -80,7 +86,8 @@ void Sender::writeData(const char* data, int length, int type) {
80 // Send data over the socket connection 86 // Send data over the socket connection
81 if (mDataSocket) { 87 if (mDataSocket) {
82 // Start alarm 88 // Start alarm
83 alarm(8); 89 const int alarmDuration = 8;
90 alarm(alarmDuration);
84 91
85 // Send data over the socket, sending the type and size first 92 // Send data over the socket, sending the type and size first
86 logg->logMessage("Sending data with length %d", length); 93 logg->logMessage("Sending data with length %d", length);
@@ -89,7 +96,21 @@ void Sender::writeData(const char* data, int length, int type) {
89 mDataSocket->send((char*)&type, 1); 96 mDataSocket->send((char*)&type, 1);
90 mDataSocket->send((char*)&length, sizeof(length)); 97 mDataSocket->send((char*)&length, sizeof(length));
91 } 98 }
92 mDataSocket->send((char*)data, length); 99
100 // 100Kbits/sec * alarmDuration sec / 8 bits/byte
101 const int chunkSize = 100*1000 * alarmDuration / 8;
102 int pos = 0;
103 while (true) {
104 mDataSocket->send((char*)data + pos, min(length - pos, chunkSize));
105 pos += chunkSize;
106 if (pos >= length) {
107 break;
108 }
109
110 // Reset the alarm
111 alarm(alarmDuration);
112 logg->logMessage("Resetting the alarm");
113 }
93 114
94 // Stop alarm 115 // Stop alarm
95 alarm(0); 116 alarm(0);
diff --git a/daemon/Sender.h b/daemon/Sender.h
index ceab343..8f23361 100644
--- a/daemon/Sender.h
+++ b/daemon/Sender.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -11,7 +11,8 @@
11 11
12#include <stdio.h> 12#include <stdio.h>
13#include <pthread.h> 13#include <pthread.h>
14#include "OlySocket.h" 14
15class OlySocket;
15 16
16enum { 17enum {
17 RESPONSE_XML = 1, 18 RESPONSE_XML = 1,
diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp
index 53a3ea6..4068d4e 100644
--- a/daemon/SessionData.cpp
+++ b/daemon/SessionData.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -25,39 +25,19 @@ void SessionData::initialize() {
25 mSessionIsActive = false; 25 mSessionIsActive = false;
26 mLocalCapture = false; 26 mLocalCapture = false;
27 mOneShot = false; 27 mOneShot = false;
28 strcpy(mCoreName, "unknown"); 28 readCpuInfo();
29 mConfigurationXMLPath = NULL; 29 mConfigurationXMLPath = NULL;
30 mSessionXMLPath = NULL; 30 mSessionXMLPath = NULL;
31 mEventsXMLPath = NULL; 31 mEventsXMLPath = NULL;
32 mTargetPath = NULL; 32 mTargetPath = NULL;
33 mAPCDir = NULL; 33 mAPCDir = NULL;
34 mSampleRate = 0; 34 mSampleRate = 0;
35 mLiveRate = 0;
35 mDuration = 0; 36 mDuration = 0;
36 mBacktraceDepth = 0; 37 mBacktraceDepth = 0;
37 mTotalBufferSize = 0; 38 mTotalBufferSize = 0;
39 // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
38 mCores = 1; 40 mCores = 1;
39
40 initializeCounters();
41}
42
43void SessionData::initializeCounters() {
44 // PMU Counters
45 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
46 mPerfCounterType[i][0] = 0;
47 mPerfCounterTitle[i][0] = 0;
48 mPerfCounterName[i][0] = 0;
49 mPerfCounterDescription[i][0] = 0;
50 mPerfCounterDisplay[i][0] = 0;
51 mPerfCounterUnits[i][0] = 0;
52 mPerfCounterEnabled[i] = 0;
53 mPerfCounterEvent[i] = 0;
54 mPerfCounterColor[i] = 0;
55 mPerfCounterKey[i] = 0;
56 mPerfCounterCount[i] = 0;
57 mPerfCounterPerCPU[i] = false;
58 mPerfCounterEBSCapable[i] = false;
59 mPerfCounterAverageSelection[i] = false;
60 }
61} 41}
62 42
63void SessionData::parseSessionXML(char* xmlString) { 43void SessionData::parseSessionXML(char* xmlString) {
@@ -66,35 +46,103 @@ void SessionData::parseSessionXML(char* xmlString) {
66 46
67 // Set session data values 47 // Set session data values
68 if (strcmp(session.parameters.sample_rate, "high") == 0) { 48 if (strcmp(session.parameters.sample_rate, "high") == 0) {
69 gSessionData->mSampleRate = 10000; 49 mSampleRate = 10000;
70 } else if (strcmp(session.parameters.sample_rate, "normal") == 0) { 50 } else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
71 gSessionData->mSampleRate = 1000; 51 mSampleRate = 1000;
72 } else if (strcmp(session.parameters.sample_rate, "low") == 0) { 52 } else if (strcmp(session.parameters.sample_rate, "low") == 0) {
73 gSessionData->mSampleRate = 100; 53 mSampleRate = 100;
74 } else if (strcmp(session.parameters.sample_rate, "none") == 0) { 54 } else if (strcmp(session.parameters.sample_rate, "none") == 0) {
75 gSessionData->mSampleRate = 0; 55 mSampleRate = 0;
76 } else { 56 } else {
77 logg->logError(__FILE__, __LINE__, "Invalid sample rate (%s) in session xml.", session.parameters.sample_rate); 57 logg->logError(__FILE__, __LINE__, "Invalid sample rate (%s) in session xml.", session.parameters.sample_rate);
78 handleException(); 58 handleException();
79 } 59 }
80 gSessionData->mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0; 60 mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0;
81 gSessionData->mDuration = session.parameters.duration; 61 mDuration = session.parameters.duration;
82 62
83 // Determine buffer size (in MB) based on buffer mode 63 // Determine buffer size (in MB) based on buffer mode
84 gSessionData->mOneShot = true; 64 mOneShot = true;
85 if (strcmp(session.parameters.buffer_mode, "streaming") == 0) { 65 if (strcmp(session.parameters.buffer_mode, "streaming") == 0) {
86 gSessionData->mOneShot = false; 66 mOneShot = false;
87 gSessionData->mTotalBufferSize = 1; 67 mTotalBufferSize = 1;
88 } else if (strcmp(session.parameters.buffer_mode, "small") == 0) { 68 } else if (strcmp(session.parameters.buffer_mode, "small") == 0) {
89 gSessionData->mTotalBufferSize = 1; 69 mTotalBufferSize = 1;
90 } else if (strcmp(session.parameters.buffer_mode, "normal") == 0) { 70 } else if (strcmp(session.parameters.buffer_mode, "normal") == 0) {
91 gSessionData->mTotalBufferSize = 4; 71 mTotalBufferSize = 4;
92 } else if (strcmp(session.parameters.buffer_mode, "large") == 0) { 72 } else if (strcmp(session.parameters.buffer_mode, "large") == 0) {
93 gSessionData->mTotalBufferSize = 16; 73 mTotalBufferSize = 16;
94 } else { 74 } else {
95 logg->logError(__FILE__, __LINE__, "Invalid value for buffer mode in session xml."); 75 logg->logError(__FILE__, __LINE__, "Invalid value for buffer mode in session xml.");
96 handleException(); 76 handleException();
97 } 77 }
98 78
99 gSessionData->mImages = session.parameters.images; 79 mImages = session.parameters.images;
80 // Convert milli- to nanoseconds
81 mLiveRate = session.parameters.live_rate * (int64_t)1000000;
82 if (mLiveRate > 0 && mLocalCapture) {
83 logg->logMessage("Local capture is not compatable with live, disabling live");
84 mLiveRate = 0;
85 }
86}
87
88void SessionData::readCpuInfo() {
89 char temp[256]; // arbitrarily large amount
90 strcpy(mCoreName, "unknown");
91 mCpuId = -1;
92
93 FILE* f = fopen("/proc/cpuinfo", "r");
94 if (f == NULL) {
95 logg->logMessage("Error opening /proc/cpuinfo\n"
96 "The core name in the captured xml file will be 'unknown'.");
97 return;
98 }
99
100 bool foundCoreName = false;
101 bool foundCpuId = false;
102 while (fgets(temp, sizeof(temp), f) && (!foundCoreName || !foundCpuId)) {
103 if (strlen(temp) > 0) {
104 temp[strlen(temp) - 1] = 0; // Replace the line feed with a null
105 }
106
107 const bool foundHardware = strstr(temp, "Hardware") != 0;
108 const bool foundCPUPart = strstr(temp, "CPU part") != 0;
109 if (foundHardware || foundCPUPart) {
110 char* position = strchr(temp, ':');
111 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
112 logg->logMessage("Unknown format of /proc/cpuinfo\n"
113 "The core name in the captured xml file will be 'unknown'.");
114 return;
115 }
116 position += 2;
117
118 if (foundHardware) {
119 strncpy(mCoreName, position, sizeof(mCoreName));
120 mCoreName[sizeof(mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
121 foundCoreName = true;
122 }
123
124 if (foundCPUPart) {
125 int cpuId = strtol(position, NULL, 16);
126 if (cpuId > mCpuId) {
127 mCpuId = cpuId;
128 }
129 foundCpuId = true;
130 }
131 }
132 }
133
134 if (!foundCoreName) {
135 logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
136 "The core name in the captured xml file will be 'unknown'.");
137 }
138 fclose(f);
139 }
140
141int getEventKey() {
142 // Start one after the gator.ko's value of 1
143 static int key = 2;
144
145 const int ret = key;
146 key += 2;
147 return ret;
100} 148}
diff --git a/daemon/SessionData.h b/daemon/SessionData.h
index e0e0b7a..5b6899b 100644
--- a/daemon/SessionData.h
+++ b/daemon/SessionData.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,11 +9,14 @@
9#ifndef SESSION_DATA_H 9#ifndef SESSION_DATA_H
10#define SESSION_DATA_H 10#define SESSION_DATA_H
11 11
12#include <stdint.h>
13
14#include "Counter.h"
15#include "Hwmon.h"
16
12#define MAX_PERFORMANCE_COUNTERS 50 17#define MAX_PERFORMANCE_COUNTERS 50
13#define MAX_STRING_LEN 80
14#define MAX_DESCRIPTION_LEN 400
15 18
16#define PROTOCOL_VERSION 12 19#define PROTOCOL_VERSION 13
17#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions 20#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions
18 21
19struct ImageLinkList { 22struct ImageLinkList {
@@ -23,12 +26,15 @@ struct ImageLinkList {
23 26
24class SessionData { 27class SessionData {
25public: 28public:
29 static const size_t MAX_STRING_LEN = 80;
30
26 SessionData(); 31 SessionData();
27 ~SessionData(); 32 ~SessionData();
28 void initialize(); 33 void initialize();
29 void initializeCounters();
30 void parseSessionXML(char* xmlString); 34 void parseSessionXML(char* xmlString);
31 35
36 Hwmon hwmon;
37
32 char mCoreName[MAX_STRING_LEN]; 38 char mCoreName[MAX_STRING_LEN];
33 struct ImageLinkList *mImages; 39 struct ImageLinkList *mImages;
34 char* mConfigurationXMLPath; 40 char* mConfigurationXMLPath;
@@ -45,27 +51,21 @@ public:
45 int mBacktraceDepth; 51 int mBacktraceDepth;
46 int mTotalBufferSize; // number of MB to use for the entire collection buffer 52 int mTotalBufferSize; // number of MB to use for the entire collection buffer
47 int mSampleRate; 53 int mSampleRate;
54 int64_t mLiveRate;
48 int mDuration; 55 int mDuration;
49 int mCores; 56 int mCores;
57 int mCpuId;
50 58
51 // PMU Counters 59 // PMU Counters
52 bool mCounterOverflow; 60 bool mCounterOverflow;
53 char mPerfCounterType[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN]; 61 Counter mCounters[MAX_PERFORMANCE_COUNTERS];
54 char mPerfCounterTitle[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN]; 62
55 char mPerfCounterName[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN]; 63private:
56 char mPerfCounterDescription[MAX_PERFORMANCE_COUNTERS][MAX_DESCRIPTION_LEN]; 64 void readCpuInfo();
57 char mPerfCounterDisplay[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
58 char mPerfCounterUnits[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
59 int mPerfCounterEnabled[MAX_PERFORMANCE_COUNTERS];
60 int mPerfCounterEvent[MAX_PERFORMANCE_COUNTERS];
61 int mPerfCounterColor[MAX_PERFORMANCE_COUNTERS];
62 int mPerfCounterCount[MAX_PERFORMANCE_COUNTERS];
63 int mPerfCounterKey[MAX_PERFORMANCE_COUNTERS];
64 bool mPerfCounterPerCPU[MAX_PERFORMANCE_COUNTERS];
65 bool mPerfCounterEBSCapable[MAX_PERFORMANCE_COUNTERS];
66 bool mPerfCounterAverageSelection[MAX_PERFORMANCE_COUNTERS];
67}; 65};
68 66
69extern SessionData* gSessionData; 67extern SessionData* gSessionData;
70 68
69int getEventKey();
70
71#endif // SESSION_DATA_H 71#endif // SESSION_DATA_H
diff --git a/daemon/SessionXML.cpp b/daemon/SessionXML.cpp
index b2b6c30..0a0a027 100644
--- a/daemon/SessionXML.cpp
+++ b/daemon/SessionXML.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -12,6 +12,7 @@
12#include "SessionXML.h" 12#include "SessionXML.h"
13#include "Logging.h" 13#include "Logging.h"
14#include "OlyUtility.h" 14#include "OlyUtility.h"
15#include "SessionData.h"
15 16
16static const char* TAG_SESSION = "session"; 17static const char* TAG_SESSION = "session";
17static const char* TAG_IMAGE = "image"; 18static const char* TAG_IMAGE = "image";
@@ -22,12 +23,14 @@ static const char* ATTR_BUFFER_MODE = "buffer_mode";
22static const char* ATTR_SAMPLE_RATE = "sample_rate"; 23static const char* ATTR_SAMPLE_RATE = "sample_rate";
23static const char* ATTR_DURATION = "duration"; 24static const char* ATTR_DURATION = "duration";
24static const char* ATTR_PATH = "path"; 25static const char* ATTR_PATH = "path";
26static const char* ATTR_LIVE_RATE = "live_rate";
25 27
26SessionXML::SessionXML(const char* str) { 28SessionXML::SessionXML(const char* str) {
27 parameters.buffer_mode[0] = 0; 29 parameters.buffer_mode[0] = 0;
28 parameters.sample_rate[0] = 0; 30 parameters.sample_rate[0] = 0;
29 parameters.duration = 0; 31 parameters.duration = 0;
30 parameters.call_stack_unwinding = false; 32 parameters.call_stack_unwinding = false;
33 parameters.live_rate = 0;
31 parameters.images = NULL; 34 parameters.images = NULL;
32 mPath = 0; 35 mPath = 0;
33 mSessionXML = (char*)str; 36 mSessionXML = (char*)str;
@@ -78,6 +81,7 @@ void SessionXML::sessionTag(mxml_node_t *tree, mxml_node_t *node) {
78 // integers/bools 81 // integers/bools
79 parameters.call_stack_unwinding = util->stringToBool(mxmlElementGetAttr(node, ATTR_CALL_STACK_UNWINDING), false); 82 parameters.call_stack_unwinding = util->stringToBool(mxmlElementGetAttr(node, ATTR_CALL_STACK_UNWINDING), false);
80 if (mxmlElementGetAttr(node, ATTR_DURATION)) parameters.duration = strtol(mxmlElementGetAttr(node, ATTR_DURATION), NULL, 10); 83 if (mxmlElementGetAttr(node, ATTR_DURATION)) parameters.duration = strtol(mxmlElementGetAttr(node, ATTR_DURATION), NULL, 10);
84 if (mxmlElementGetAttr(node, ATTR_LIVE_RATE)) parameters.live_rate = strtol(mxmlElementGetAttr(node, ATTR_LIVE_RATE), NULL, 10);
81 85
82 // parse subtags 86 // parse subtags
83 node = mxmlGetFirstChild(node); 87 node = mxmlGetFirstChild(node);
diff --git a/daemon/SessionXML.h b/daemon/SessionXML.h
index f7a5641..c7e3798 100644
--- a/daemon/SessionXML.h
+++ b/daemon/SessionXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -10,13 +10,15 @@
10#define SESSION_XML_H 10#define SESSION_XML_H
11 11
12#include "mxml/mxml.h" 12#include "mxml/mxml.h"
13#include "SessionData.h" 13
14struct ImageLinkList;
14 15
15struct ConfigParameters { 16struct ConfigParameters {
16 char buffer_mode[64]; // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size 17 char buffer_mode[64]; // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size
17 char sample_rate[64]; // capture mode, "high", "normal", or "low" 18 char sample_rate[64]; // capture mode, "high", "normal", or "low"
18 int duration; // length of profile in seconds 19 int duration; // length of profile in seconds
19 bool call_stack_unwinding; // whether stack unwinding is performed 20 bool call_stack_unwinding; // whether stack unwinding is performed
21 int live_rate;
20 struct ImageLinkList *images; // linked list of image strings 22 struct ImageLinkList *images; // linked list of image strings
21}; 23};
22 24
diff --git a/daemon/StreamlineSetup.cpp b/daemon/StreamlineSetup.cpp
index d13cf1d..88c07a6 100644
--- a/daemon/StreamlineSetup.cpp
+++ b/daemon/StreamlineSetup.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,8 +9,6 @@
9#include <string.h> 9#include <string.h>
10#include <stdlib.h> 10#include <stdlib.h>
11#include <unistd.h> 11#include <unistd.h>
12#include <dirent.h>
13#include <sys/types.h>
14#include <arpa/inet.h> 12#include <arpa/inet.h>
15#include <sys/socket.h> 13#include <sys/socket.h>
16#include <netinet/in.h> 14#include <netinet/in.h>
@@ -21,6 +19,7 @@
21#include "CapturedXML.h" 19#include "CapturedXML.h"
22#include "StreamlineSetup.h" 20#include "StreamlineSetup.h"
23#include "ConfigurationXML.h" 21#include "ConfigurationXML.h"
22#include "Driver.h"
24 23
25static const char* TAG_SESSION = "session"; 24static const char* TAG_SESSION = "session";
26static const char* TAG_REQUEST = "request"; 25static const char* TAG_REQUEST = "request";
@@ -30,7 +29,6 @@ static const char* ATTR_TYPE = "type";
30static const char* VALUE_EVENTS = "events"; 29static const char* VALUE_EVENTS = "events";
31static const char* VALUE_CONFIGURATION = "configuration"; 30static const char* VALUE_CONFIGURATION = "configuration";
32static const char* VALUE_COUNTERS = "counters"; 31static const char* VALUE_COUNTERS = "counters";
33static const char* VALUE_SESSION = "session";
34static const char* VALUE_CAPTURED = "captured"; 32static const char* VALUE_CAPTURED = "captured";
35static const char* VALUE_DEFAULTS = "defaults"; 33static const char* VALUE_DEFAULTS = "defaults";
36 34
@@ -40,7 +38,6 @@ StreamlineSetup::StreamlineSetup(OlySocket* s) {
40 int type; 38 int type;
41 39
42 mSocket = s; 40 mSocket = s;
43 mSessionXML = NULL;
44 41
45 // Receive commands from Streamline (master) 42 // Receive commands from Streamline (master)
46 while (!ready) { 43 while (!ready) {
@@ -87,9 +84,6 @@ StreamlineSetup::StreamlineSetup(OlySocket* s) {
87} 84}
88 85
89StreamlineSetup::~StreamlineSetup() { 86StreamlineSetup::~StreamlineSetup() {
90 if (mSessionXML) {
91 free(mSessionXML);
92 }
93} 87}
94 88
95char* StreamlineSetup::readCommand(int* command) { 89char* StreamlineSetup::readCommand(int* command) {
@@ -162,9 +156,6 @@ void StreamlineSetup::handleRequest(char* xml) {
162 } else if (attr && strcmp(attr, VALUE_COUNTERS) == 0) { 156 } else if (attr && strcmp(attr, VALUE_COUNTERS) == 0) {
163 sendCounters(); 157 sendCounters();
164 logg->logMessage("Sent counters xml response"); 158 logg->logMessage("Sent counters xml response");
165 } else if (attr && strcmp(attr, VALUE_SESSION) == 0) {
166 sendData(mSessionXML, strlen(mSessionXML), RESPONSE_XML);
167 logg->logMessage("Sent session xml response");
168 } else if (attr && strcmp(attr, VALUE_CAPTURED) == 0) { 159 } else if (attr && strcmp(attr, VALUE_CAPTURED) == 0) {
169 CapturedXML capturedXML; 160 CapturedXML capturedXML;
170 char* capturedText = capturedXML.getXML(false); 161 char* capturedText = capturedXML.getXML(false);
@@ -191,13 +182,6 @@ void StreamlineSetup::handleDeliver(char* xml) {
191 if (mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND_FIRST)) { 182 if (mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND_FIRST)) {
192 // Session XML 183 // Session XML
193 gSessionData->parseSessionXML(xml); 184 gSessionData->parseSessionXML(xml);
194
195 // Save xml
196 mSessionXML = strdup(xml);
197 if (mSessionXML == NULL) {
198 logg->logError(__FILE__, __LINE__, "malloc failed for size %d", strlen(xml) + 1);
199 handleException();
200 }
201 sendData(NULL, 0, RESPONSE_ACK); 185 sendData(NULL, 0, RESPONSE_ACK);
202 logg->logMessage("Received session xml"); 186 logg->logMessage("Received session xml");
203 } else if (mxmlFindElement(tree, tree, TAG_CONFIGURATIONS, NULL, NULL, MXML_DESCEND_FIRST)) { 187 } else if (mxmlFindElement(tree, tree, TAG_CONFIGURATIONS, NULL, NULL, MXML_DESCEND_FIRST)) {
@@ -222,28 +206,43 @@ void StreamlineSetup::sendData(const char* data, int length, int type) {
222 206
223void StreamlineSetup::sendEvents() { 207void StreamlineSetup::sendEvents() {
224#include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len 208#include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
225 char* path = (char*)malloc(PATH_MAX);; 209 char path[PATH_MAX];
226 char* buffer; 210 mxml_node_t *xml;
227 unsigned int size = 0; 211 FILE *fl;
228 212
213 // Avoid unused variable warning
214 (void)events_xml_len;
215
216 // Load the provided or default events xml
229 if (gSessionData->mEventsXMLPath) { 217 if (gSessionData->mEventsXMLPath) {
230 strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX); 218 strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
231 } else { 219 } else {
232 util->getApplicationFullPath(path, PATH_MAX); 220 util->getApplicationFullPath(path, PATH_MAX);
233 strncat(path, "events.xml", PATH_MAX - strlen(path) - 1); 221 strncat(path, "events.xml", PATH_MAX - strlen(path) - 1);
234 } 222 }
235 buffer = util->readFromDisk(path, &size); 223 fl = fopen(path, "r");
236 if (buffer == NULL) { 224 if (fl) {
225 xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
226 fclose(fl);
227 } else {
237 logg->logMessage("Unable to locate events.xml, using default"); 228 logg->logMessage("Unable to locate events.xml, using default");
238 buffer = (char*)events_xml; 229 xml = mxmlLoadString(NULL, (char *)events_xml, MXML_NO_CALLBACK);
239 size = events_xml_len;
240 } 230 }
241 231
242 sendData(buffer, size, RESPONSE_XML); 232 // Add dynamic events from the drivers
243 if (buffer != (char*)events_xml) { 233 mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
244 free(buffer); 234 if (!events) {
235 logg->logMessage("Unable to find <events> node in the events.xml");
236 handleException();
237 }
238 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
239 driver->writeEvents(events);
245 } 240 }
246 free(path); 241
242 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
243 sendString(string, RESPONSE_XML);
244 free(string);
245 mxmlDelete(xml);
247} 246}
248 247
249void StreamlineSetup::sendConfiguration() { 248void StreamlineSetup::sendConfiguration() {
@@ -268,30 +267,15 @@ void StreamlineSetup::sendDefaults() {
268 sendData(xml, size, RESPONSE_XML); 267 sendData(xml, size, RESPONSE_XML);
269} 268}
270 269
271#include <dirent.h>
272void StreamlineSetup::sendCounters() { 270void StreamlineSetup::sendCounters() {
273 struct dirent *ent;
274 mxml_node_t *xml; 271 mxml_node_t *xml;
275 mxml_node_t *counters; 272 mxml_node_t *counters;
276 mxml_node_t *counter;
277
278 // counters.xml is simply a file listing of /dev/gator/events
279 DIR* dir = opendir("/dev/gator/events");
280 if (dir == NULL) {
281 logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events");
282 handleException();
283 }
284 273
285 xml = mxmlNewXML("1.0"); 274 xml = mxmlNewXML("1.0");
286 counters = mxmlNewElement(xml, "counters"); 275 counters = mxmlNewElement(xml, "counters");
287 while ((ent = readdir(dir)) != NULL) { 276 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
288 // skip hidden files, current dir, and parent dir 277 driver->writeCounters(counters);
289 if (ent->d_name[0] == '.')
290 continue;
291 counter = mxmlNewElement(counters, "counter");
292 mxmlElementSetAttr(counter, "name", ent->d_name);
293 } 278 }
294 closedir (dir);
295 279
296 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB); 280 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
297 sendString(string, RESPONSE_XML); 281 sendString(string, RESPONSE_XML);
@@ -301,7 +285,7 @@ void StreamlineSetup::sendCounters() {
301} 285}
302 286
303void StreamlineSetup::writeConfiguration(char* xml) { 287void StreamlineSetup::writeConfiguration(char* xml) {
304 char* path = (char*)malloc(PATH_MAX); 288 char path[PATH_MAX];
305 289
306 if (gSessionData->mConfigurationXMLPath) { 290 if (gSessionData->mConfigurationXMLPath) {
307 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX); 291 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX);
@@ -316,8 +300,7 @@ void StreamlineSetup::writeConfiguration(char* xml) {
316 } 300 }
317 301
318 // Re-populate gSessionData with the configuration, as it has now changed 302 // Re-populate gSessionData with the configuration, as it has now changed
319 new ConfigurationXML(); 303 { ConfigurationXML configuration; }
320 free(path);
321 304
322 if (gSessionData->mCounterOverflow) { 305 if (gSessionData->mCounterOverflow) {
323 logg->logError(__FILE__, __LINE__, "Exceeded maximum number of %d performance counters", MAX_PERFORMANCE_COUNTERS); 306 logg->logError(__FILE__, __LINE__, "Exceeded maximum number of %d performance counters", MAX_PERFORMANCE_COUNTERS);
diff --git a/daemon/StreamlineSetup.h b/daemon/StreamlineSetup.h
index 8086fe2..841735d 100644
--- a/daemon/StreamlineSetup.h
+++ b/daemon/StreamlineSetup.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -28,7 +28,6 @@ public:
28private: 28private:
29 int mNumConnections; 29 int mNumConnections;
30 OlySocket* mSocket; 30 OlySocket* mSocket;
31 char* mSessionXML;
32 31
33 char* readCommand(int*); 32 char* readCommand(int*);
34 void handleRequest(char* xml); 33 void handleRequest(char* xml);
diff --git a/daemon/common.mk b/daemon/common.mk
new file mode 100644
index 0000000..112b990
--- /dev/null
+++ b/daemon/common.mk
@@ -0,0 +1,50 @@
1# -g produces debugging information
2# -O3 maximum optimization
3# -O0 no optimization, used for debugging
4# -Wall enables most warnings
5# -Werror treats warnings as errors
6# -std=c++0x is the planned new c++ standard
7# -std=c++98 is the 1998 c++ standard
8CFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors
9CXXFLAGS += -fno-rtti
10ifeq ($(WERROR),1)
11 CFLAGS += -Werror
12endif
13# -s strips the binary of debug info
14LDFLAGS += -s
15TARGET = gatord
16C_SRC = $(wildcard mxml/*.c) $(wildcard libsensors/*.c)
17CPP_SRC = $(wildcard *.cpp)
18
19all: $(TARGET)
20
21events.xml: events_header.xml $(wildcard events-*.xml) events_footer.xml
22 cat $^ > $@
23
24include $(wildcard *.d)
25include $(wildcard mxml/*.d)
26
27StreamlineSetup.cpp: events_xml.h
28ConfigurationXML.cpp: configuration_xml.h
29
30# Don't regenerate conf-lex.c or conf-parse.c
31libsensors/conf-lex.c: ;
32libsensors/conf-parse.c: ;
33
34%_xml.h: %.xml escape
35 ./escape $< > $@
36
37%.o: %.c
38 $(GCC) -c $(CFLAGS) -o $@ $<
39
40%.o: %.cpp
41 $(CPP) -c $(CFLAGS) $(CXXFLAGS) -o $@ $<
42
43$(TARGET): $(CPP_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o)
44 $(CPP) $(LDFLAGS) -o $@ $^ -lrt -pthread
45
46escape: escape.c
47 gcc $^ -o $@
48
49clean:
50 rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h configuration_xml.h
diff --git a/daemon/configuration.xml b/daemon/configuration.xml
index fbdef31..62ccd08 100644
--- a/daemon/configuration.xml
+++ b/daemon/configuration.xml
@@ -1,41 +1,41 @@
1<?xml version="1.0" encoding='UTF-8'?> 1<?xml version="1.0" encoding='UTF-8'?>
2<configurations revision="1"> 2<configurations revision="2">
3 <configuration counter="ARM_ARM11_ccnt" title="Clock" name="Cycles" per_cpu="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <configuration counter="ARM_ARM11_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <configuration counter="ARM_ARM11_cnt0" event="0x7" title="Instruction" name="Executed" per_cpu="yes" description="Instructions executed"/> 4 <configuration counter="ARM_ARM11_cnt0" event="0x7" title="Instruction" name="Executed" per_cpu="yes" description="Instructions executed"/>
5 <configuration counter="ARM_ARM11_cnt1" event="0xb" title="Cache" name="Data miss" per_cpu="yes" description="Data cache miss, not including Cache Operations"/> 5 <configuration counter="ARM_ARM11_cnt1" event="0xb" title="Cache" name="Data miss" per_cpu="yes" description="Data cache miss, not including Cache Operations"/>
6 <configuration counter="ARM_ARM11MPCore_ccnt" title="Clock" name="Cycles" per_cpu="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 6 <configuration counter="ARM_ARM11MPCore_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
7 <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08" title="Core" name="Instructions" per_cpu="yes" description="Instructions executed"/> 7 <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08" title="Core" name="Instructions" per_cpu="yes" description="Instructions executed"/>
8 <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b" title="Cache" name="Data read miss" per_cpu="yes" description="Data cache miss, not including Cache Operations"/> 8 <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b" title="Cache" name="Data read miss" per_cpu="yes" description="Data cache miss, not including Cache Operations"/>
9 <configuration counter="ARM_Cortex-A5_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 9 <configuration counter="ARM_Cortex-A5_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
10 <configuration counter="ARM_Cortex-A5_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 10 <configuration counter="ARM_Cortex-A5_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
11 <configuration counter="ARM_Cortex-A5_cnt1" event="0x1" title="Cache" name="Instruction refill" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 11 <configuration counter="ARM_Cortex-A5_cnt1" event="0x1" title="Cache" name="Instruction refill" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
12 <configuration counter="ARM_Cortex-A7_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 12 <configuration counter="ARM_Cortex-A7_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
13 <configuration counter="ARM_Cortex-A7_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 13 <configuration counter="ARM_Cortex-A7_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
14 <configuration counter="ARM_Cortex-A7_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 14 <configuration counter="ARM_Cortex-A7_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
15 <configuration counter="ARM_Cortex-A7_cnt2" event="0x16" title="Cache" name="L2 data access" per_cpu="yes" supports_event_based_sampling="yes" description="Level 2 data cache access"/> 15 <configuration counter="ARM_Cortex-A7_cnt2" event="0x16" title="Cache" name="L2 data access" per_cpu="yes" supports_event_based_sampling="yes" description="Level 2 data cache access"/>
16 <configuration counter="ARM_Cortex-A8_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 16 <configuration counter="ARM_Cortex-A8_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
17 <configuration counter="ARM_Cortex-A8_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 17 <configuration counter="ARM_Cortex-A8_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
18 <configuration counter="ARM_Cortex-A8_cnt1" event="0x44" title="Cache" name="L2 miss" per_cpu="yes" supports_event_based_sampling="yes" description="Any cacheable miss in the L2 cache"/> 18 <configuration counter="ARM_Cortex-A8_cnt1" event="0x44" title="Cache" name="L2 miss" per_cpu="yes" supports_event_based_sampling="yes" description="Any cacheable miss in the L2 cache"/>
19 <configuration counter="ARM_Cortex-A8_cnt2" event="0x43" title="Cache" name="L1 miss" per_cpu="yes" supports_event_based_sampling="yes" description="Any accesses to the L2 cache"/> 19 <configuration counter="ARM_Cortex-A8_cnt2" event="0x43" title="Cache" name="L1 miss" per_cpu="yes" supports_event_based_sampling="yes" description="Any accesses to the L2 cache"/>
20 <configuration counter="ARM_Cortex-A8_cnt3" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 20 <configuration counter="ARM_Cortex-A8_cnt3" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
21 <configuration counter="ARM_Cortex-A9_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 21 <configuration counter="ARM_Cortex-A9_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
22 <configuration counter="ARM_Cortex-A9_cnt0" event="0x68" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and even more approximate of the total number of instructions architecturally executed"/> 22 <configuration counter="ARM_Cortex-A9_cnt0" event="0x68" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and even more approximate of the total number of instructions architecturally executed"/>
23 <configuration counter="ARM_Cortex-A9_cnt1" event="0x06" title="Instruction" name="Memory read" per_cpu="yes" supports_event_based_sampling="yes" description="Memory-reading instruction architecturally executed"/> 23 <configuration counter="ARM_Cortex-A9_cnt1" event="0x06" title="Instruction" name="Memory read" per_cpu="yes" supports_event_based_sampling="yes" description="Memory-reading instruction architecturally executed"/>
24 <configuration counter="ARM_Cortex-A9_cnt2" event="0x07" title="Instruction" name="Memory write" per_cpu="yes" supports_event_based_sampling="yes" description="Memory-writing instruction architecturally executed"/> 24 <configuration counter="ARM_Cortex-A9_cnt2" event="0x07" title="Instruction" name="Memory write" per_cpu="yes" supports_event_based_sampling="yes" description="Memory-writing instruction architecturally executed"/>
25 <configuration counter="ARM_Cortex-A9_cnt3" event="0x03" title="Cache" name="Data refill" per_cpu="yes" supports_event_based_sampling="yes" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/> 25 <configuration counter="ARM_Cortex-A9_cnt3" event="0x03" title="Cache" name="Data refill" per_cpu="yes" supports_event_based_sampling="yes" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
26 <configuration counter="ARM_Cortex-A9_cnt4" event="0x04" title="Cache" name="Data access" per_cpu="yes" supports_event_based_sampling="yes" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/> 26 <configuration counter="ARM_Cortex-A9_cnt4" event="0x04" title="Cache" name="Data access" per_cpu="yes" supports_event_based_sampling="yes" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
27 <configuration counter="ARM_Cortex-A15_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 27 <configuration counter="ARM_Cortex-A15_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
28 <configuration counter="ARM_Cortex-A15_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 28 <configuration counter="ARM_Cortex-A15_cnt0" event="0x8" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
29 <configuration counter="ARM_Cortex-A15_cnt1" event="0x16" title="Cache" name="L2 data access" per_cpu="yes" supports_event_based_sampling="yes" description="Level 2 data cache access"/> 29 <configuration counter="ARM_Cortex-A15_cnt1" event="0x16" title="Cache" name="L2 data access" per_cpu="yes" supports_event_based_sampling="yes" description="Level 2 data cache access"/>
30 <configuration counter="ARM_Cortex-A15_cnt2" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 30 <configuration counter="ARM_Cortex-A15_cnt2" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
31 <configuration counter="ARM_Cortex-A15_cnt3" event="0x19" title="Bus" name="Access" per_cpu="yes" supports_event_based_sampling="yes" description=""/> 31 <configuration counter="ARM_Cortex-A15_cnt3" event="0x19" title="Bus" name="Access" per_cpu="yes" supports_event_based_sampling="yes" description="Bus - Access"/>
32 <configuration counter="Scorpion_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 32 <configuration counter="Scorpion_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
33 <configuration counter="Scorpion_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 33 <configuration counter="Scorpion_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
34 <configuration counter="Scorpion_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 34 <configuration counter="Scorpion_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
35 <configuration counter="ScorpionMP_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 35 <configuration counter="ScorpionMP_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
36 <configuration counter="ScorpionMP_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 36 <configuration counter="ScorpionMP_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
37 <configuration counter="ScorpionMP_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 37 <configuration counter="ScorpionMP_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
38 <configuration counter="Krait_ccnt" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 38 <configuration counter="Krait_ccnt" event="0xff" title="Clock" name="Cycles" per_cpu="yes" supports_event_based_sampling="yes" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
39 <configuration counter="Krait_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/> 39 <configuration counter="Krait_cnt0" event="0x08" title="Instruction" name="Executed" per_cpu="yes" supports_event_based_sampling="yes" description="Instruction architecturally executed"/>
40 <configuration counter="Krait_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/> 40 <configuration counter="Krait_cnt1" event="0x10" title="Branch" name="Mispredicted" per_cpu="yes" supports_event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
41 <configuration counter="Linux_block_rq_wr" title="Disk IO" name="Write" units="B" description="Disk IO Bytes Written"/> 41 <configuration counter="Linux_block_rq_wr" title="Disk IO" name="Write" units="B" description="Disk IO Bytes Written"/>
diff --git a/daemon/escape.c b/daemon/escape.c
index c0f47f1..a154515 100644
--- a/daemon/escape.c
+++ b/daemon/escape.c
@@ -1,11 +1,17 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9/*
10 * The Makefile in the daemon folder builds and executes 'escape'
11 * 'escape' creates configuration_xml.h from configuration.xml and events_xml.h from events-*.xml
12 * these genereated xml files are then #included and built as part of the gatord binary
13 */
14
9#include <errno.h> 15#include <errno.h>
10#include <stdio.h> 16#include <stdio.h>
11#include <stdlib.h> 17#include <stdlib.h>
diff --git a/daemon/events-ARM11.xml b/daemon/events-ARM11.xml
index 0a5ee66..9f31313 100644
--- a/daemon/events-ARM11.xml
+++ b/daemon/events-ARM11.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_ARM11_cnt" count="3"/> 1 <counter_set name="ARM_ARM11_cnt" count="3"/>
2 <category name="ARM11" counter_set="ARM_ARM11_cnt" per_cpu="yes"> 2 <category name="ARM11" counter_set="ARM_ARM11_cnt" per_cpu="yes">
3 <event counter="ARM_ARM11_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ARM_ARM11_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/> 4 <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/>
5 <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/> 5 <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/>
6 <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/> 6 <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/>
diff --git a/daemon/events-ARM11MPCore.xml b/daemon/events-ARM11MPCore.xml
index 1a9ca3f..68ca9a5 100644
--- a/daemon/events-ARM11MPCore.xml
+++ b/daemon/events-ARM11MPCore.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_ARM11MPCore_cnt" count="3"/> 1 <counter_set name="ARM_ARM11MPCore_cnt" count="3"/>
2 <category name="ARM11MPCore" counter_set="ARM_ARM11MPCore_cnt" per_cpu="yes"> 2 <category name="ARM11MPCore" counter_set="ARM_ARM11MPCore_cnt" per_cpu="yes">
3 <event counter="ARM_ARM11MPCore_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ARM_ARM11MPCore_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/> 4 <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/>
5 <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/> 5 <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/>
6 <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/> 6 <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/>
diff --git a/daemon/events-CCI-400.xml b/daemon/events-CCI-400.xml
new file mode 100644
index 0000000..2be0df3
--- /dev/null
+++ b/daemon/events-CCI-400.xml
@@ -0,0 +1,47 @@
1 <counter_set name="cci-400_cnt" count="4"/>
2 <category name="CCI-400" counter_set="cci-400_cnt" per_cpu="no" supports_event_based_sampling="yes">
3 <event counter="cci-400_ccnt" event="0xff" title="CCI-400" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4
5 <option_set name="Slave">
6 <option event_delta="0x00" name="S0" description="Slave interface 0"/>
7 <option event_delta="0x20" name="S1" description="Slave interface 1"/>
8 <option event_delta="0x40" name="S2" description="Slave interface 2"/>
9 <option event_delta="0x60" name="S3" description="Slave interface 3"/>
10 <option event_delta="0x80" name="S4" description="Slave interface 4"/>
11 </option_set>
12
13 <event event="0x00" option_set="Slave" title="CCI-400" name="Read: any" description="Read request handshake: any"/>
14 <event event="0x01" option_set="Slave" title="CCI-400" name="Read: transaction" description="Read request handshake: device transaction"/>
15 <event event="0x02" option_set="Slave" title="CCI-400" name="Read: normal" description="Read request handshake: normal, non-shareable or system-shareable, but not barrier or cache maintenance operation"/>
16 <event event="0x03" option_set="Slave" title="CCI-400" name="Read: shareable" description="Read request handshake: inner- or outer-shareable, but not barrier, DVM message or cache maintenance operation"/>
17 <event event="0x04" option_set="Slave" title="CCI-400" name="Read: cache" description="Read request handshake: cache maintenance operation, CleanInvalid, CleanShared, MakeInvalid"/>
18 <event event="0x05" option_set="Slave" title="CCI-400" name="Read: memory barrier" description="Read request handshake: memory barrier"/>
19 <event event="0x06" option_set="Slave" title="CCI-400" name="Read: sync barrier" description="Read request handshake: synchronization barrier"/>
20 <event event="0x07" option_set="Slave" title="CCI-400" name="Read: DVM message, no sync" description="Read request handshake: DVM message, no synchronization"/>
21 <event event="0x08" option_set="Slave" title="CCI-400" name="Read: DVM message, sync" description="Read request handshake: DVM message, synchronization"/>
22 <event event="0x09" option_set="Slave" title="CCI-400" name="Read: stall" description="Read request stall cycle because the transaction tracker is full. Increase SIx_R_MAX to avoid this stall"/>
23 <event event="0x0a" option_set="Slave" title="CCI-400" name="Read data last handshake" description="Read data last handshake: data returned from the snoop instead of from downstream"/>
24 <event event="0x0b" option_set="Slave" title="CCI-400" name="Read data stall cycle" description="Read data stall cycle: RVALIDS is HIGH, RREADYS is LOW"/>
25 <event event="0x0c" option_set="Slave" title="CCI-400" name="Write: any" description="Write request handshake: any"/>
26 <event event="0x0d" option_set="Slave" title="CCI-400" name="Write: transaction" description="Write request handshake: device transaction"/>
27 <event event="0x0e" option_set="Slave" title="CCI-400" name="Write: normal" description="Write request handshake: normal, non-shareable, or system-shareable, but not barrier"/>
28 <event event="0x0f" option_set="Slave" title="CCI-400" name="Write: shareable" description="Write request handshake: inner- or outer-shareable, WriteBack or WriteClean"/>
29 <event event="0x10" option_set="Slave" title="CCI-400" name="Write: WriteUnique" description="Write request handshake: WriteUnique"/>
30 <event event="0x11" option_set="Slave" title="CCI-400" name="Write: WriteLineUnique" description="Write request handshake: WriteLineUnique"/>
31 <event event="0x12" option_set="Slave" title="CCI-400" name="Write: Evict" description="Write request handshake: Evict"/>
32 <event event="0x13" option_set="Slave" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase SIx_W_MAX to avoid this stall"/>
33
34 <option_set name="Master">
35 <option event_delta="0xa0" name="M0" description="Master interface 0"/>
36 <option event_delta="0xc0" name="M1" description="Master interface 1"/>
37 <option event_delta="0xe0" name="M2" description="Master interface 2"/>
38 </option_set>
39
40 <event event="0x14" option_set="Master" title="CCI-400" name="Retry fetch" description="RETRY of speculative fetch transaction"/>
41 <event event="0x15" option_set="Master" title="CCI-400" name="Read stall: address hazard" description="Read request stall cycle because of an address hazard"/>
42 <event event="0x16" option_set="Master" title="CCI-400" name="Read stall: ID hazard" description="Read request stall cycle because of an ID hazard"/>
43 <event event="0x17" option_set="Master" title="CCI-400" name="Read stall: tracker full" description="Read request stall cycle because the transaction tracker is full. Increase MIx_R_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
44 <event event="0x18" option_set="Master" title="CCI-400" name="Read stall: barrier hazard" description="Read request stall cycle because of a barrier hazard"/>
45 <event event="0x19" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
46 <event event="0x1a" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase MIx_W_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
47 </category>
diff --git a/daemon/events-Cortex-A15.xml b/daemon/events-Cortex-A15.xml
index e0bd201..e3de814 100644
--- a/daemon/events-Cortex-A15.xml
+++ b/daemon/events-Cortex-A15.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A15_cnt" count="6"/> 1 <counter_set name="ARM_Cortex-A15_cnt" count="6"/>
2 <category name="Cortex-A15" counter_set="ARM_Cortex-A15_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A15" counter_set="ARM_Cortex-A15_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A15_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ARM_Cortex-A15_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/> 4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
@@ -19,13 +19,13 @@
19 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/> 19 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
20 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/> 20 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
21 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/> 21 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
22 <event event="0x19" title="Bus" name="Access" description=""/> 22 <event event="0x19" title="Bus" name="Access" description="Bus - Access"/>
23 <event event="0x1a" title="Memory" name="Error" description="Local memory error"/> 23 <event event="0x1a" title="Memory" name="Error" description="Local memory error"/>
24 <event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/> 24 <event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/>
25 <event event="0x1c" title="Memory" name="Translation table" description="Write to translation table base architecturally executed"/> 25 <event event="0x1c" title="Memory" name="Translation table" description="Write to translation table base architecturally executed"/>
26 <event event="0x1d" title="Bus" name="Cycle" description=""/> 26 <event event="0x1d" title="Bus" name="Cycle" description="Bus - Cycle"/>
27 <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/> 27 <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
28 <event event="0x41" title="Cache" name="L1 data write" description="Level 1 data cache access - Write"/> 28 <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/>
29 <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/> 29 <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/>
30 <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/> 30 <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/>
31 <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-Back - Victim"/> 31 <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-Back - Victim"/>
@@ -34,7 +34,7 @@
34 <event event="0x4c" title="TLB" name="L1 data refill read" description="Level 1 data TLB refill - Read"/> 34 <event event="0x4c" title="TLB" name="L1 data refill read" description="Level 1 data TLB refill - Read"/>
35 <event event="0x4d" title="TLB" name="L1 data refill write" description="Level 1 data TLB refill - Write"/> 35 <event event="0x4d" title="TLB" name="L1 data refill write" description="Level 1 data TLB refill - Write"/>
36 <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/> 36 <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
37 <event event="0x51" title="Cache" name="L2 data write" description="Level 2 data cache access - Write"/> 37 <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/>
38 <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/> 38 <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/>
39 <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/> 39 <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/>
40 <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-Back - Victim"/> 40 <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-Back - Victim"/>
@@ -42,7 +42,7 @@
42 <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/> 42 <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
43 <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/> 43 <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
44 <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/> 44 <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
45 <event event="0x64" title="Bus" name="Access" description="Bus access - Normal"/> 45 <event event="0x64" title="Bus" name="Access normal" description="Bus access - Normal"/>
46 <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/> 46 <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
47 <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/> 47 <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
48 <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/> 48 <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
diff --git a/daemon/events-Cortex-A5.xml b/daemon/events-Cortex-A5.xml
index 4a894d3..77dd838 100644
--- a/daemon/events-Cortex-A5.xml
+++ b/daemon/events-Cortex-A5.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A5_cnt" count="2"/> 1 <counter_set name="ARM_Cortex-A5_cnt" count="2"/>
2 <category name="Cortex-A5" counter_set="ARM_Cortex-A5_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A5" counter_set="ARM_Cortex-A5_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A5_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ARM_Cortex-A5_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
@@ -30,7 +30,7 @@
30 <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/> 30 <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
31 <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/> 31 <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
32 <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/> 32 <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
33 <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description=""/> 33 <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description="ETM - ETM Ext Out[0]"/>
34 <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description=""/> 34 <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description="ETM - ETM Ext Out[1]"/>
35 <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/> 35 <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
36 </category> 36 </category>
diff --git a/daemon/events-Cortex-A53.xml b/daemon/events-Cortex-A53.xml
index 3fa9c66..0ffa412 100644
--- a/daemon/events-Cortex-A53.xml
+++ b/daemon/events-Cortex-A53.xml
@@ -1,7 +1,7 @@
1 <counter_set name="ARM_Cortex-A53_cnt" count="6"/> 1 <counter_set name="ARM_Cortex-A53_cnt" count="6"/>
2 <category name="Cortex-A53" counter_set="ARM_Cortex-A53_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A53" counter_set="ARM_Cortex-A53_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <!-- 0x11 CPU_CYCLES - Cycle --> 3 <!-- 0x11 CPU_CYCLES - Cycle -->
4 <event counter="ARM_Cortex-A53_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 4 <event counter="ARM_Cortex-A53_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
5 <!-- 0x00 SW_INCR - Instruction architecturally executed (condition check pass) - Software increment --> 5 <!-- 0x00 SW_INCR - Instruction architecturally executed (condition check pass) - Software increment -->
6 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 6 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
7 <!-- 0x01 L1I_CACHE_REFILL - Level 1 instruction cache refill --> 7 <!-- 0x01 L1I_CACHE_REFILL - Level 1 instruction cache refill -->
diff --git a/daemon/events-Cortex-A57.xml b/daemon/events-Cortex-A57.xml
index 5db6dc2..e8c0a61 100644
--- a/daemon/events-Cortex-A57.xml
+++ b/daemon/events-Cortex-A57.xml
@@ -1,7 +1,7 @@
1 <counter_set name="ARM_Cortex-A57_cnt" count="6"/> 1 <counter_set name="ARM_Cortex-A57_cnt" count="6"/>
2 <category name="Cortex-A57" counter_set="ARM_Cortex-A57_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A57" counter_set="ARM_Cortex-A57_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <!-- 0x11 CPU_CYCLES - Cycle --> 3 <!-- 0x11 CPU_CYCLES - Cycle -->
4 <event counter="ARM_Cortex-A57_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 4 <event counter="ARM_Cortex-A57_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
5 <!-- 0x00 SW_INCR - Instruction architecturally executed number (condition check pass) - Software increment --> 5 <!-- 0x00 SW_INCR - Instruction architecturally executed number (condition check pass) - Software increment -->
6 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 6 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
7 <!-- 0x01 L1I_CACHE_REFILL - Level 1 instruction cache refill --> 7 <!-- 0x01 L1I_CACHE_REFILL - Level 1 instruction cache refill -->
diff --git a/daemon/events-Cortex-A7.xml b/daemon/events-Cortex-A7.xml
index 50bba7f..bbd7a26 100644
--- a/daemon/events-Cortex-A7.xml
+++ b/daemon/events-Cortex-A7.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A7_cnt" count="4"/> 1 <counter_set name="ARM_Cortex-A7_cnt" count="4"/>
2 <category name="Cortex-A7" counter_set="ARM_Cortex-A7_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A7" counter_set="ARM_Cortex-A7_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A7_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ARM_Cortex-A7_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/> 4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
@@ -17,7 +17,6 @@
17 <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/> 17 <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
18 <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/> 18 <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
19 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/> 19 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
20 <event event="0x11" title="Cycle" name="Counter" description=""/>
21 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/> 20 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
22 <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/> 21 <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
23 <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/> 22 <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/>
@@ -25,8 +24,8 @@
25 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/> 24 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
26 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/> 25 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
27 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/> 26 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
28 <event event="0x19" title="Bus" name="Access" description=""/> 27 <event event="0x19" title="Bus" name="Access" description="Bus - Access"/>
29 <event event="0x1d" title="Bus" name="Cycle" description=""/> 28 <event event="0x1d" title="Bus" name="Cycle" description="Bus - Cycle"/>
30 <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/> 29 <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
31 <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/> 30 <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
32 <event event="0x86" title="Exception" name="IRQ" description="IRQ exception taken"/> 31 <event event="0x86" title="Exception" name="IRQ" description="IRQ exception taken"/>
@@ -37,8 +36,8 @@
37 <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/> 36 <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
38 <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/> 37 <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
39 <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/> 38 <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
40 <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description=""/> 39 <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description="ETM - ETM Ext Out[0]"/>
41 <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description=""/> 40 <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description="ETM - ETM Ext Out[1]"/>
42 <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/> 41 <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
43 <event event="0xCA" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local cluster, rather than accessing the L2 cache or issuing an external read."/> 42 <event event="0xCA" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local cluster, rather than accessing the L2 cache or issuing an external read."/>
44 </category> 43 </category>
diff --git a/daemon/events-Cortex-A8.xml b/daemon/events-Cortex-A8.xml
index fe4c69d..a301f1f 100644
--- a/daemon/events-Cortex-A8.xml
+++ b/daemon/events-Cortex-A8.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A8_cnt" count="4"/> 1 <counter_set name="ARM_Cortex-A8_cnt" count="4"/>
2 <category name="Cortex-A8" counter_set="ARM_Cortex-A8_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A8" counter_set="ARM_Cortex-A8_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A8_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ARM_Cortex-A8_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
@@ -27,7 +27,7 @@
27 <event event="0x45" title="AXI" name="Read" description="The number of AXI read data transfers"/> 27 <event event="0x45" title="AXI" name="Read" description="The number of AXI read data transfers"/>
28 <event event="0x46" title="AXI" name="Write" description="The number of AXI write data transfers"/> 28 <event event="0x46" title="AXI" name="Write" description="The number of AXI write data transfers"/>
29 <event event="0x47" title="Memory" name="Replay event" description="Any replay event in the memory system"/> 29 <event event="0x47" title="Memory" name="Replay event" description="Any replay event in the memory system"/>
30 <event event="0x48" title="Memory" name="Unaligned access" description="Any unaligned memory access that results in a replay"/> 30 <event event="0x48" title="Memory" name="Unaligned access replay" description="Any unaligned memory access that results in a replay"/>
31 <event event="0x49" title="Cache" name="L1 data hash miss" description="Any L1 data memory access that misses in the cache as a result of the hashing algorithm"/> 31 <event event="0x49" title="Cache" name="L1 data hash miss" description="Any L1 data memory access that misses in the cache as a result of the hashing algorithm"/>
32 <event event="0x4a" title="Cache" name="L1 inst hash miss" description="Any L1 instruction memory access that misses in the cache as a result of the hashing algorithm"/> 32 <event event="0x4a" title="Cache" name="L1 inst hash miss" description="Any L1 instruction memory access that misses in the cache as a result of the hashing algorithm"/>
33 <event event="0x4b" title="Cache" name="L1 page coloring" description="Any L1 data memory access in which a page coloring alias occurs"/> 33 <event event="0x4b" title="Cache" name="L1 page coloring" description="Any L1 data memory access in which a page coloring alias occurs"/>
diff --git a/daemon/events-Cortex-A9.xml b/daemon/events-Cortex-A9.xml
index 89d6a19..9ebb308 100644
--- a/daemon/events-Cortex-A9.xml
+++ b/daemon/events-Cortex-A9.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A9_cnt" count="6"/> 1 <counter_set name="ARM_Cortex-A9_cnt" count="6"/>
2 <category name="Cortex-A9" counter_set="ARM_Cortex-A9_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A9" counter_set="ARM_Cortex-A9_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A9_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ARM_Cortex-A9_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Krait-architected.xml b/daemon/events-Krait-architected.xml
index 06c1901..4254666 100644
--- a/daemon/events-Krait-architected.xml
+++ b/daemon/events-Krait-architected.xml
@@ -1,6 +1,6 @@
1 <counter_set name="Krait_cnt" count="4"/> 1 <counter_set name="Krait_cnt" count="4"/>
2 <category name="Krait" counter_set="Krait_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Krait" counter_set="Krait_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="Krait_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="Krait_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Mali-400.xml b/daemon/events-Mali-400.xml
index cb0b9d5..dceccfb 100644
--- a/daemon/events-Mali-400.xml
+++ b/daemon/events-Mali-400.xml
@@ -1,8 +1,4 @@
1 <counter_set name="ARM_Mali-400_VP_cnt" count="2"/> 1 <counter_set name="ARM_Mali-400_VP_cnt" count="2"/>
2 <counter_set name="ARM_Mali-400_FP0_cnt" count="2"/>
3 <counter_set name="ARM_Mali-400_FP1_cnt" count="2"/>
4 <counter_set name="ARM_Mali-400_FP2_cnt" count="2"/>
5 <counter_set name="ARM_Mali-400_FP3_cnt" count="2"/>
6 <counter_set name="ARM_Mali-400_L2_cnt" count="2"/> 2 <counter_set name="ARM_Mali-400_L2_cnt" count="2"/>
7 <counter_set name="ARM_Mali-400_SW_cnt" count="0"/> 3 <counter_set name="ARM_Mali-400_SW_cnt" count="0"/>
8 <counter_set name="ARM_Mali-400_Filmstrip_cnt" count="1"/> 4 <counter_set name="ARM_Mali-400_Filmstrip_cnt" count="1"/>
@@ -33,308 +29,110 @@
33 <event event="0x20" title="Mali GPU Vertex Processor" name="Active cycles, Scissor tile iterator" description="Number of active cycles per frame spent by the MaliGP2 PLBU iterating over tiles to perform scissoring. This includes time spent waiting on the bus."/> 29 <event event="0x20" title="Mali GPU Vertex Processor" name="Active cycles, Scissor tile iterator" description="Number of active cycles per frame spent by the MaliGP2 PLBU iterating over tiles to perform scissoring. This includes time spent waiting on the bus."/>
34 <event event="0x21" title="Mali GPU Vertex Processor" name="Active cycles, PLBU tile iterator" description="Number of active cycles per frame spent by the MaliGP2 PLBU iterating over the tiles in the bounding box generating commands (mainly graphics primitives). This includes time spent waiting on the bus."/> 30 <event event="0x21" title="Mali GPU Vertex Processor" name="Active cycles, PLBU tile iterator" description="Number of active cycles per frame spent by the MaliGP2 PLBU iterating over the tiles in the bounding box generating commands (mainly graphics primitives). This includes time spent waiting on the bus."/>
35 </category> 31 </category>
36 <category name="Mali-400-FP0" counter_set="ARM_Mali-400_FP0_cnt" per_cpu="no"> 32 <category name="Mali GPU Fragment Processor" per_cpu="no">
37 <event event="0x00" title="Mali GPU Fragment Processor 0" name="Active clock cycles" description="Active clock cycles, between polygon start and IRQ."/> 33 <counter_set name="ARM_Mali-400_FP0_cnt" title="Mali-400 FP0" description="Mali GPU Fragment Processor 0" count="2"/>
38 <event event="0x02" title="Mali GPU Fragment Processor 0" name="Total bus reads" description="Total number of 64-bit words read from the bus."/> 34 <counter_set name="ARM_Mali-400_FP1_cnt" title="Mali-400 FP1" description="Mali GPU Fragment Processor 1" count="2"/>
39 <event event="0x03" title="Mali GPU Fragment Processor 0" name="Total bus writes" description="Total number of 64-bit words written to the bus."/> 35 <counter_set name="ARM_Mali-400_FP2_cnt" title="Mali-400 FP2" description="Mali GPU Fragment Processor 2" count="2"/>
40 <event event="0x04" title="Mali GPU Fragment Processor 0" name="Bus read request cycles" description="Number of cycles during which the bus read request signal was HIGH."/> 36 <counter_set name="ARM_Mali-400_FP3_cnt" title="Mali-400 FP3" description="Mali GPU Fragment Processor 3" count="2"/>
41 <event event="0x05" title="Mali GPU Fragment Processor 0" name="Bus write request cycles" description="Number of cycles during which the bus write request signal was HIGH."/> 37
42 <event event="0x06" title="Mali GPU Fragment Processor 0" name="Bus read transactions count" description="Number of read requests accepted by the bus."/> 38 <event event="0x00" title="Mali-400 FP" name="Active clock cycles" description="Active clock cycles, between polygon start and IRQ."/>
43 <event event="0x07" title="Mali GPU Fragment Processor 0" name="Bus write transactions" description="Number of write requests accepted by the bus."/> 39 <event event="0x02" title="Mali-400 FP" name="Total bus reads" description="Total number of 64-bit words read from the bus."/>
44 <event event="0x09" title="Mali GPU Fragment Processor 0" name="Tile writeback writes" description="64-bit words written to the bus by the writeback unit."/> 40 <event event="0x03" title="Mali-400 FP" name="Total bus writes" description="Total number of 64-bit words written to the bus."/>
45 <event event="0x0a" title="Mali GPU Fragment Processor 0" name="Store unit writes" description="64-bit words written to the bus by the store unit."/> 41 <event event="0x04" title="Mali-400 FP" name="Bus read request cycles" description="Number of cycles during which the bus read request signal was HIGH."/>
46 <event event="0x0d" title="Mali GPU Fragment Processor 0" name="Texture cache uncompressed reads" description="Number of 64-bit words read from the bus into the uncompressed textures cache."/> 42 <event event="0x05" title="Mali-400 FP" name="Bus write request cycles" description="Number of cycles during which the bus write request signal was HIGH."/>
47 <event event="0x0e" title="Mali GPU Fragment Processor 0" name="Polygon list reads" description="Number of 64-bit words read from the bus by the polygon list reader."/> 43 <event event="0x06" title="Mali-400 FP" name="Bus read transactions count" description="Number of read requests accepted by the bus."/>
48 <event event="0x0f" title="Mali GPU Fragment Processor 0" name="RSW reads" description="Number of 64-bit words read from the bus into the Render State Word register."/> 44 <event event="0x07" title="Mali-400 FP" name="Bus write transactions" description="Number of write requests accepted by the bus."/>
49 <event event="0x10" title="Mali GPU Fragment Processor 0" name="Vertex cache reads" description="Number of 64-bit words read from the bus into the vertex cache."/> 45 <event event="0x09" title="Mali-400 FP" name="Tile writeback writes" description="64-bit words written to the bus by the writeback unit."/>
50 <event event="0x11" title="Mali GPU Fragment Processor 0" name="Uniform remapping reads" description="Number of 64-bit words read from the bus when reading from the uniform remapping table."/> 46 <event event="0x0a" title="Mali-400 FP" name="Store unit writes" description="64-bit words written to the bus by the store unit."/>
51 <event event="0x12" title="Mali GPU Fragment Processor 0" name="Program cache reads" description="Number of 64-bit words read from the bus into the fragment shader program cache."/> 47 <event event="0x0d" title="Mali-400 FP" name="Texture cache uncompressed reads" description="Number of 64-bit words read from the bus into the uncompressed textures cache."/>
52 <event event="0x13" title="Mali GPU Fragment Processor 0" name="Varying reads" description="Number of 64-bit words containing varyings generated by the vertex processing read from the bus."/> 48 <event event="0x0e" title="Mali-400 FP" name="Polygon list reads" description="Number of 64-bit words read from the bus by the polygon list reader."/>
53 <event event="0x14" title="Mali GPU Fragment Processor 0" name="Texture descriptors reads" description="Number of 64-bit words containing texture descriptors read from the bus."/> 49 <event event="0x0f" title="Mali-400 FP" name="RSW reads" description="Number of 64-bit words read from the bus into the Render State Word register."/>
54 <event event="0x15" title="Mali GPU Fragment Processor 0" name="Texture descriptor remapping reads" description="Number of 64-bit words read from the bus when reading from the texture descriptor remapping table."/> 50 <event event="0x10" title="Mali-400 FP" name="Vertex cache reads" description="Number of 64-bit words read from the bus into the vertex cache."/>
55 <event event="0x17" title="Mali GPU Fragment Processor 0" name="Load unit reads" description="Number of 64-bit words read from the bus by the LOAD sub-instruction."/> 51 <event event="0x11" title="Mali-400 FP" name="Uniform remapping reads" description="Number of 64-bit words read from the bus when reading from the uniform remapping table."/>
56 <event event="0x18" title="Mali GPU Fragment Processor 0" name="Polygon count" description="Number of triangles read from the polygon list."/> 52 <event event="0x12" title="Mali-400 FP" name="Program cache reads" description="Number of 64-bit words read from the bus into the fragment shader program cache."/>
57 <event event="0x19" title="Mali GPU Fragment Processor 0" name="Pixel rectangle count" description="Number of pixel rectangles read from the polygon list."/> 53 <event event="0x13" title="Mali-400 FP" name="Varying reads" description="Number of 64-bit words containing varyings generated by the vertex processing read from the bus."/>
58 <event event="0x1a" title="Mali GPU Fragment Processor 0" name="Lines count" description="Number of lines read from the polygon list."/> 54 <event event="0x14" title="Mali-400 FP" name="Texture descriptors reads" description="Number of 64-bit words containing texture descriptors read from the bus."/>
59 <event event="0x1b" title="Mali GPU Fragment Processor 0" name="Points count" description="Number of points read from the polygon list."/> 55 <event event="0x15" title="Mali-400 FP" name="Texture descriptor remapping reads" description="Number of 64-bit words read from the bus when reading from the texture descriptor remapping table."/>
60 <event event="0x1c" title="Mali GPU Fragment Processor 0" name="Stall cycles PolygonListReader" description="Number of clock cycles the Polygon List Reader waited for output being collected."/> 56 <event event="0x17" title="Mali-400 FP" name="Load unit reads" description="Number of 64-bit words read from the bus by the LOAD sub-instruction."/>
61 <event event="0x1d" title="Mali GPU Fragment Processor 0" name="Stall cycles triangle setup" description="Number of clock cycles the TSC waited for input."/> 57 <event event="0x18" title="Mali-400 FP" name="Polygon count" description="Number of triangles read from the polygon list."/>
62 <event event="0x1e" title="Mali GPU Fragment Processor 0" name="Quad rasterized count" description="Number of 2x?2 quads output from rasterizer."/> 58 <event event="0x19" title="Mali-400 FP" name="Pixel rectangle count" description="Number of pixel rectangles read from the polygon list."/>
63 <event event="0x1f" title="Mali GPU Fragment Processor 0" name="Fragment rasterized count" description="Number of fragment rasterized. Fragments/(Quads*4) gives average actual fragments per quad."/> 59 <event event="0x1a" title="Mali-400 FP" name="Lines count" description="Number of lines read from the polygon list."/>
64 <event event="0x20" title="Mali GPU Fragment Processor 0" name="Fragment rejected fragment-kill count" description="Number of fragments exiting the fragment shader as killed."/> 60 <event event="0x1b" title="Mali-400 FP" name="Points count" description="Number of points read from the polygon list."/>
65 <event event="0x21" title="Mali GPU Fragment Processor 0" name="Fragment rejected fwd-fragment-kill count" description="Number of fragments killed by forward fragment kill."/> 61 <event event="0x1c" title="Mali-400 FP" name="Stall cycles PolygonListReader" description="Number of clock cycles the Polygon List Reader waited for output being collected."/>
66 <event event="0x22" title="Mali GPU Fragment Processor 0" name="Fragment passed z/stencil count" description="Number of fragments passing Z and stencil test."/> 62 <event event="0x1d" title="Mali-400 FP" name="Stall cycles triangle setup" description="Number of clock cycles the TSC waited for input."/>
67 <event event="0x23" title="Mali GPU Fragment Processor 0" name="Patches rejected early z/stencil count" description="Number of patches rejected by EarlyZ. A patch can be 8x8, 4x4 or 2x2 pixels."/> 63 <event event="0x1e" title="Mali-400 FP" name="Quad rasterized count" description="Number of 2x?2 quads output from rasterizer."/>
68 <event event="0x24" title="Mali GPU Fragment Processor 0" name="Patches evaluated" description="Number of patches evaluated for EarlyZ rejection."/> 64 <event event="0x1f" title="Mali-400 FP" name="Fragment rasterized count" description="Number of fragment rasterized. Fragments/(Quads*4) gives average actual fragments per quad."/>
69 <event event="0x25" title="Mali GPU Fragment Processor 0" name="Instruction completed count" description="Number of fragment shader instruction words completed. It is a function of pixels processed and the length of the shader programs."/> 65 <event event="0x20" title="Mali-400 FP" name="Fragment rejected fragment-kill count" description="Number of fragments exiting the fragment shader as killed."/>
70 <event event="0x26" title="Mali GPU Fragment Processor 0" name="Instruction failed rendezvous count" description="Number of fragment shader instructions not completed because of failed Rendezvous."/> 66 <event event="0x21" title="Mali-400 FP" name="Fragment rejected fwd-fragment-kill count" description="Number of fragments killed by forward fragment kill."/>
71 <event event="0x27" title="Mali GPU Fragment Processor 0" name="Instruction failed varying-miss count" description="Number of fragment shader instructions not completed because of failed varying operation."/> 67 <event event="0x22" title="Mali-400 FP" name="Fragment passed z/stencil count" description="Number of fragments passing Z and stencil test."/>
72 <event event="0x28" title="Mali GPU Fragment Processor 0" name="Instruction failed texture-miss count" description="Number of fragment shader instructions not completed because of failed texture operation."/> 68 <event event="0x23" title="Mali-400 FP" name="Patches rejected early z/stencil count" description="Number of patches rejected by EarlyZ. A patch can be 8x8, 4x4 or 2x2 pixels."/>
73 <event event="0x29" title="Mali GPU Fragment Processor 0" name="Instruction failed load-miss count" description="Number of fragment shader instructions not completed because of failed load operation."/> 69 <event event="0x24" title="Mali-400 FP" name="Patches evaluated" description="Number of patches evaluated for EarlyZ rejection."/>
74 <event event="0x2a" title="Mali GPU Fragment Processor 0" name="Instruction failed tile read-miss count" description="Number of fragment shader instructions not completed because of failed read from the tilebuffer."/> 70 <event event="0x25" title="Mali-400 FP" name="Instruction completed count" description="Number of fragment shader instruction words completed. It is a function of pixels processed and the length of the shader programs."/>
75 <event event="0x2b" title="Mali GPU Fragment Processor 0" name="Instruction failed store-miss count" description="Number of fragment shader instructions not completed because of failed store operation."/> 71 <event event="0x26" title="Mali-400 FP" name="Instruction failed rendezvous count" description="Number of fragment shader instructions not completed because of failed Rendezvous."/>
76 <event event="0x2c" title="Mali GPU Fragment Processor 0" name="Rendezvous breakage count" description="Number of Rendezvous breakages reported."/> 72 <event event="0x27" title="Mali-400 FP" name="Instruction failed varying-miss count" description="Number of fragment shader instructions not completed because of failed varying operation."/>
77 <event event="0x2d" title="Mali GPU Fragment Processor 0" name="Pipeline bubbles cycle count" description="Number of unused cycles in the fragment shader while rendering is active."/> 73 <event event="0x28" title="Mali-400 FP" name="Instruction failed texture-miss count" description="Number of fragment shader instructions not completed because of failed texture operation."/>
78 <event event="0x2e" title="Mali GPU Fragment Processor 0" name="Texture mapper multipass count" description="Number of texture operations looped because of more texture passes needed."/> 74 <event event="0x29" title="Mali-400 FP" name="Instruction failed load-miss count" description="Number of fragment shader instructions not completed because of failed load operation."/>
79 <event event="0x2f" title="Mali GPU Fragment Processor 0" name="Texture mapper cycle count" description="Number of texture operation cycles."/> 75 <event event="0x2a" title="Mali-400 FP" name="Instruction failed tile read-miss count" description="Number of fragment shader instructions not completed because of failed read from the tilebuffer."/>
80 <event event="0x30" title="Mali GPU Fragment Processor 0" name="Vertex cache hit count" description="Number of times a requested vertex was found in the cache (Number of vertex cache hits)."/> 76 <event event="0x2b" title="Mali-400 FP" name="Instruction failed store-miss count" description="Number of fragment shader instructions not completed because of failed store operation."/>
81 <event event="0x31" title="Mali GPU Fragment Processor 0" name="Vertex cache miss count" description="Number of times a requested vertex was not found in the cache (Number of vertex cache misses)."/> 77 <event event="0x2c" title="Mali-400 FP" name="Rendezvous breakage count" description="Number of Rendezvous breakages reported."/>
82 <event event="0x32" title="Mali GPU Fragment Processor 0" name="Varying cache hit count" description="Number of times a requested varying was found in the cache (Number of varying cache hits)."/> 78 <event event="0x2d" title="Mali-400 FP" name="Pipeline bubbles cycle count" description="Number of unused cycles in the fragment shader while rendering is active."/>
83 <event event="0x33" title="Mali GPU Fragment Processor 0" name="Varying cache miss count" description="Number of times a requested varying was not found in the cache (Number of varying cache misses)."/> 79 <event event="0x2e" title="Mali-400 FP" name="Texture mapper multipass count" description="Number of texture operations looped because of more texture passes needed."/>
84 <event event="0x34" title="Mali GPU Fragment Processor 0" name="Varying cache conflict miss count" description="Number of times a requested varying was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/> 80 <event event="0x2f" title="Mali-400 FP" name="Texture mapper cycle count" description="Number of texture operation cycles."/>
85 <event event="0x35" title="Mali GPU Fragment Processor 0" name="Texture cache hit count" description="Number of times a requested texel was found in the texture cache (Number of texture cache hits)."/> 81 <event event="0x30" title="Mali-400 FP" name="Vertex cache hit count" description="Number of times a requested vertex was found in the cache (Number of vertex cache hits)."/>
86 <event event="0x36" title="Mali GPU Fragment Processor 0" name="Texture cache miss count" description="Number of times a requested texel was not found in the texture cache (Number of texture cache misses)."/> 82 <event event="0x31" title="Mali-400 FP" name="Vertex cache miss count" description="Number of times a requested vertex was not found in the cache (Number of vertex cache misses)."/>
87 <event event="0x37" title="Mali GPU Fragment Processor 0" name="Texture cache conflict miss count" description="Number of times a requested texel was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/> 83 <event event="0x32" title="Mali-400 FP" name="Varying cache hit count" description="Number of times a requested varying was found in the cache (Number of varying cache hits)."/>
88 <event event="0x38" title="Mali GPU Fragment Processor 0" name="Compressed texture cache hit count" description="Number of times a requested item was found in the cache."/> 84 <event event="0x33" title="Mali-400 FP" name="Varying cache miss count" description="Number of times a requested varying was not found in the cache (Number of varying cache misses)."/>
89 <event event="0x39" title="Mali GPU Fragment Processor 0" name="Compressed texture cache miss count" description="Number of times a requested item was not found in the cache."/> 85 <event event="0x34" title="Mali-400 FP" name="Varying cache conflict miss count" description="Number of times a requested varying was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/>
90 <event event="0x3a" title="Mali GPU Fragment Processor 0" name="Load/Store cache hit count" description="Number of hits in the load/store cache."/> 86 <event event="0x35" title="Mali-400 FP" name="Texture cache hit count" description="Number of times a requested texel was found in the texture cache (Number of texture cache hits)."/>
91 <event event="0x3b" title="Mali GPU Fragment Processor 0" name="Load/Store cache miss count" description="Number of misses in the load/store cache."/> 87 <event event="0x36" title="Mali-400 FP" name="Texture cache miss count" description="Number of times a requested texel was not found in the texture cache (Number of texture cache misses)."/>
92 <event event="0x3c" title="Mali GPU Fragment Processor 0" name="Program cache hit count" description="Number of hits in the program cache."/> 88 <event event="0x37" title="Mali-400 FP" name="Texture cache conflict miss count" description="Number of times a requested texel was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/>
93 <event event="0x3d" title="Mali GPU Fragment Processor 0" name="Program cache miss count" description="Number of misses in the program cache."/> 89 <event event="0x38" title="Mali-400 FP" name="Compressed texture cache hit count" description="Number of times a requested item was found in the cache."/>
94 </category> 90 <event event="0x39" title="Mali-400 FP" name="Compressed texture cache miss count" description="Number of times a requested item was not found in the cache."/>
95 <category name="Mali-400-FP1" counter_set="ARM_Mali-400_FP1_cnt" per_cpu="no"> 91 <event event="0x3a" title="Mali-400 FP" name="Load/Store cache hit count" description="Number of hits in the load/store cache."/>
96 <event event="0x00" title="Mali GPU Fragment Processor 1" name="Active clock cycles" description="Active clock cycles, between polygon start and IRQ."/> 92 <event event="0x3b" title="Mali-400 FP" name="Load/Store cache miss count" description="Number of misses in the load/store cache."/>
97 <event event="0x02" title="Mali GPU Fragment Processor 1" name="Total bus reads" description="Total number of 64-bit words read from the bus."/> 93 <event event="0x3c" title="Mali-400 FP" name="Program cache hit count" description="Number of hits in the program cache."/>
98 <event event="0x03" title="Mali GPU Fragment Processor 1" name="Total bus writes" description="Total number of 64-bit words written to the bus."/> 94 <event event="0x3d" title="Mali-400 FP" name="Program cache miss count" description="Number of misses in the program cache."/>
99 <event event="0x04" title="Mali GPU Fragment Processor 1" name="Bus read request cycles" description="Number of cycles during which the bus read request signal was HIGH."/>
100 <event event="0x05" title="Mali GPU Fragment Processor 1" name="Bus write request cycles" description="Number of cycles during which the bus write request signal was HIGH."/>
101 <event event="0x06" title="Mali GPU Fragment Processor 1" name="Bus read transactions count" description="Number of read requests accepted by the bus."/>
102 <event event="0x07" title="Mali GPU Fragment Processor 1" name="Bus write transactions" description="Number of write requests accepted by the bus."/>
103 <event event="0x09" title="Mali GPU Fragment Processor 1" name="Tile writeback writes" description="64-bit words written to the bus by the writeback unit."/>
104 <event event="0x0a" title="Mali GPU Fragment Processor 1" name="Store unit writes" description="64-bit words written to the bus by the store unit."/>
105 <event event="0x0d" title="Mali GPU Fragment Processor 1" name="Texture cache uncompressed reads" description="Number of 64-bit words read from the bus into the uncompressed textures cache."/>
106 <event event="0x0e" title="Mali GPU Fragment Processor 1" name="Polygon list reads" description="Number of 64-bit words read from the bus by the polygon list reader."/>
107 <event event="0x0f" title="Mali GPU Fragment Processor 1" name="RSW reads" description="Number of 64-bit words read from the bus into the Render State Word register."/>
108 <event event="0x10" title="Mali GPU Fragment Processor 1" name="Vertex cache reads" description="Number of 64-bit words read from the bus into the vertex cache."/>
109 <event event="0x11" title="Mali GPU Fragment Processor 1" name="Uniform remapping reads" description="Number of 64-bit words read from the bus when reading from the uniform remapping table."/>
110 <event event="0x12" title="Mali GPU Fragment Processor 1" name="Program cache reads" description="Number of 64-bit words read from the bus into the fragment shader program cache."/>
111 <event event="0x13" title="Mali GPU Fragment Processor 1" name="Varying reads" description="Number of 64-bit words containing varyings generated by the vertex processing read from the bus."/>
112 <event event="0x14" title="Mali GPU Fragment Processor 1" name="Texture descriptors reads" description="Number of 64-bit words containing texture descriptors read from the bus."/>
113 <event event="0x15" title="Mali GPU Fragment Processor 1" name="Texture descriptor remapping reads" description="Number of 64-bit words read from the bus when reading from the texture descriptor remapping table."/>
114 <event event="0x17" title="Mali GPU Fragment Processor 1" name="Load unit reads" description="Number of 64-bit words read from the bus by the LOAD sub-instruction."/>
115 <event event="0x18" title="Mali GPU Fragment Processor 1" name="Polygon count" description="Number of triangles read from the polygon list."/>
116 <event event="0x19" title="Mali GPU Fragment Processor 1" name="Pixel rectangle count" description="Number of pixel rectangles read from the polygon list."/>
117 <event event="0x1a" title="Mali GPU Fragment Processor 1" name="Lines count" description="Number of lines read from the polygon list."/>
118 <event event="0x1b" title="Mali GPU Fragment Processor 1" name="Points count" description="Number of points read from the polygon list."/>
119 <event event="0x1c" title="Mali GPU Fragment Processor 1" name="Stall cycles PolygonListReader" description="Number of clock cycles the Polygon List Reader waited for output being collected."/>
120 <event event="0x1d" title="Mali GPU Fragment Processor 1" name="Stall cycles triangle setup" description="Number of clock cycles the TSC waited for input."/>
121 <event event="0x1e" title="Mali GPU Fragment Processor 1" name="Quad rasterized count" description="Number of 2x?2 quads output from rasterizer."/>
122 <event event="0x1f" title="Mali GPU Fragment Processor 1" name="Fragment rasterized count" description="Number of fragment rasterized. Fragments/(Quads*4) gives average actual fragments per quad."/>
123 <event event="0x20" title="Mali GPU Fragment Processor 1" name="Fragment rejected fragment-kill count" description="Number of fragments exiting the fragment shader as killed."/>
124 <event event="0x21" title="Mali GPU Fragment Processor 1" name="Fragment rejected fwd-fragment-kill count" description="Number of fragments killed by forward fragment kill."/>
125 <event event="0x22" title="Mali GPU Fragment Processor 1" name="Fragment passed z/stencil count" description="Number of fragments passing Z and stencil test."/>
126 <event event="0x23" title="Mali GPU Fragment Processor 1" name="Patches rejected early z/stencil count" description="Number of patches rejected by EarlyZ. A patch can be 8x8, 4x4 or 2x2 pixels."/>
127 <event event="0x24" title="Mali GPU Fragment Processor 1" name="Patches evaluated" description="Number of patches evaluated for EarlyZ rejection."/>
128 <event event="0x25" title="Mali GPU Fragment Processor 1" name="Instruction completed count" description="Number of fragment shader instruction words completed. It is a function of pixels processed and the length of the shader programs."/>
129 <event event="0x26" title="Mali GPU Fragment Processor 1" name="Instruction failed rendezvous count" description="Number of fragment shader instructions not completed because of failed Rendezvous."/>
130 <event event="0x27" title="Mali GPU Fragment Processor 1" name="Instruction failed varying-miss count" description="Number of fragment shader instructions not completed because of failed varying operation."/>
131 <event event="0x28" title="Mali GPU Fragment Processor 1" name="Instruction failed texture-miss count" description="Number of fragment shader instructions not completed because of failed texture operation."/>
132 <event event="0x29" title="Mali GPU Fragment Processor 1" name="Instruction failed load-miss count" description="Number of fragment shader instructions not completed because of failed load operation."/>
133 <event event="0x2a" title="Mali GPU Fragment Processor 1" name="Instruction failed tile read-miss count" description="Number of fragment shader instructions not completed because of failed read from the tilebuffer."/>
134 <event event="0x2b" title="Mali GPU Fragment Processor 1" name="Instruction failed store-miss count" description="Number of fragment shader instructions not completed because of failed store operation."/>
135 <event event="0x2c" title="Mali GPU Fragment Processor 1" name="Rendezvous breakage count" description="Number of Rendezvous breakages reported."/>
136 <event event="0x2d" title="Mali GPU Fragment Processor 1" name="Pipeline bubbles cycle count" description="Number of unused cycles in the fragment shader while rendering is active."/>
137 <event event="0x2e" title="Mali GPU Fragment Processor 1" name="Texture mapper multipass count" description="Number of texture operations looped because of more texture passes needed."/>
138 <event event="0x2f" title="Mali GPU Fragment Processor 1" name="Texture mapper cycle count" description="Number of texture operation cycles."/>
139 <event event="0x30" title="Mali GPU Fragment Processor 1" name="Vertex cache hit count" description="Number of times a requested vertex was found in the cache (Number of vertex cache hits)."/>
140 <event event="0x31" title="Mali GPU Fragment Processor 1" name="Vertex cache miss count" description="Number of times a requested vertex was not found in the cache (Number of vertex cache misses)."/>
141 <event event="0x32" title="Mali GPU Fragment Processor 1" name="Varying cache hit count" description="Number of times a requested varying was found in the cache (Number of varying cache hits)."/>
142 <event event="0x33" title="Mali GPU Fragment Processor 1" name="Varying cache miss count" description="Number of times a requested varying was not found in the cache (Number of varying cache misses)."/>
143 <event event="0x34" title="Mali GPU Fragment Processor 1" name="Varying cache conflict miss count" description="Number of times a requested varying was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/>
144 <event event="0x35" title="Mali GPU Fragment Processor 1" name="Texture cache hit count" description="Number of times a requested texel was found in the texture cache (Number of texture cache hits)."/>
145 <event event="0x36" title="Mali GPU Fragment Processor 1" name="Texture cache miss count" description="Number of times a requested texel was not found in the texture cache (Number of texture cache misses)."/>
146 <event event="0x37" title="Mali GPU Fragment Processor 1" name="Texture cache conflict miss count" description="Number of times a requested texel was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/>
147 <event event="0x38" title="Mali GPU Fragment Processor 1" name="Compressed texture cache hit count" description="Number of times a requested item was found in the cache."/>
148 <event event="0x39" title="Mali GPU Fragment Processor 1" name="Compressed texture cache miss count" description="Number of times a requested item was not found in the cache."/>
149 <event event="0x3a" title="Mali GPU Fragment Processor 1" name="Load/Store cache hit count" description="Number of hits in the load/store cache."/>
150 <event event="0x3b" title="Mali GPU Fragment Processor 1" name="Load/Store cache miss count" description="Number of misses in the load/store cache."/>
151 <event event="0x3c" title="Mali GPU Fragment Processor 1" name="Program cache hit count" description="Number of hits in the program cache."/>
152 <event event="0x3d" title="Mali GPU Fragment Processor 1" name="Program cache miss count" description="Number of misses in the program cache."/>
153 </category>
154 <category name="Mali-400-FP2" counter_set="ARM_Mali-400_FP2_cnt" per_cpu="no">
155 <event event="0x00" title="Mali GPU Fragment Processor 2" name="Active clock cycles" description="Active clock cycles, between polygon start and IRQ."/>
156 <event event="0x02" title="Mali GPU Fragment Processor 2" name="Total bus reads" description="Total number of 64-bit words read from the bus."/>
157 <event event="0x03" title="Mali GPU Fragment Processor 2" name="Total bus writes" description="Total number of 64-bit words written to the bus."/>
158 <event event="0x04" title="Mali GPU Fragment Processor 2" name="Bus read request cycles" description="Number of cycles during which the bus read request signal was HIGH."/>
159 <event event="0x05" title="Mali GPU Fragment Processor 2" name="Bus write request cycles" description="Number of cycles during which the bus write request signal was HIGH."/>
160 <event event="0x06" title="Mali GPU Fragment Processor 2" name="Bus read transactions count" description="Number of read requests accepted by the bus."/>
161 <event event="0x07" title="Mali GPU Fragment Processor 2" name="Bus write transactions" description="Number of write requests accepted by the bus."/>
162 <event event="0x09" title="Mali GPU Fragment Processor 2" name="Tile writeback writes" description="64-bit words written to the bus by the writeback unit."/>
163 <event event="0x0a" title="Mali GPU Fragment Processor 2" name="Store unit writes" description="64-bit words written to the bus by the store unit."/>
164 <event event="0x0d" title="Mali GPU Fragment Processor 2" name="Texture cache uncompressed reads" description="Number of 64-bit words read from the bus into the uncompressed textures cache."/>
165 <event event="0x0e" title="Mali GPU Fragment Processor 2" name="Polygon list reads" description="Number of 64-bit words read from the bus by the polygon list reader."/>
166 <event event="0x0f" title="Mali GPU Fragment Processor 2" name="RSW reads" description="Number of 64-bit words read from the bus into the Render State Word register."/>
167 <event event="0x10" title="Mali GPU Fragment Processor 2" name="Vertex cache reads" description="Number of 64-bit words read from the bus into the vertex cache."/>
168 <event event="0x11" title="Mali GPU Fragment Processor 2" name="Uniform remapping reads" description="Number of 64-bit words read from the bus when reading from the uniform remapping table."/>
169 <event event="0x12" title="Mali GPU Fragment Processor 2" name="Program cache reads" description="Number of 64-bit words read from the bus into the fragment shader program cache."/>
170 <event event="0x13" title="Mali GPU Fragment Processor 2" name="Varying reads" description="Number of 64-bit words containing varyings generated by the vertex processing read from the bus."/>
171 <event event="0x14" title="Mali GPU Fragment Processor 2" name="Texture descriptors reads" description="Number of 64-bit words containing texture descriptors read from the bus."/>
172 <event event="0x15" title="Mali GPU Fragment Processor 2" name="Texture descriptor remapping reads" description="Number of 64-bit words read from the bus when reading from the texture descriptor remapping table."/>
173 <event event="0x17" title="Mali GPU Fragment Processor 2" name="Load unit reads" description="Number of 64-bit words read from the bus by the LOAD sub-instruction."/>
174 <event event="0x18" title="Mali GPU Fragment Processor 2" name="Polygon count" description="Number of triangles read from the polygon list."/>
175 <event event="0x19" title="Mali GPU Fragment Processor 2" name="Pixel rectangle count" description="Number of pixel rectangles read from the polygon list."/>
176 <event event="0x1a" title="Mali GPU Fragment Processor 2" name="Lines count" description="Number of lines read from the polygon list."/>
177 <event event="0x1b" title="Mali GPU Fragment Processor 2" name="Points count" description="Number of points read from the polygon list."/>
178 <event event="0x1c" title="Mali GPU Fragment Processor 2" name="Stall cycles PolygonListReader" description="Number of clock cycles the Polygon List Reader waited for output being collected."/>
179 <event event="0x1d" title="Mali GPU Fragment Processor 2" name="Stall cycles triangle setup" description="Number of clock cycles the TSC waited for input."/>
180 <event event="0x1e" title="Mali GPU Fragment Processor 2" name="Quad rasterized count" description="Number of 2x?2 quads output from rasterizer."/>
181 <event event="0x1f" title="Mali GPU Fragment Processor 2" name="Fragment rasterized count" description="Number of fragment rasterized. Fragments/(Quads*4) gives average actual fragments per quad."/>
182 <event event="0x20" title="Mali GPU Fragment Processor 2" name="Fragment rejected fragment-kill count" description="Number of fragments exiting the fragment shader as killed."/>
183 <event event="0x21" title="Mali GPU Fragment Processor 2" name="Fragment rejected fwd-fragment-kill count" description="Number of fragments killed by forward fragment kill."/>
184 <event event="0x22" title="Mali GPU Fragment Processor 2" name="Fragment passed z/stencil count" description="Number of fragments passing Z and stencil test."/>
185 <event event="0x23" title="Mali GPU Fragment Processor 2" name="Patches rejected early z/stencil count" description="Number of patches rejected by EarlyZ. A patch can be 8x8, 4x4 or 2x2 pixels."/>
186 <event event="0x24" title="Mali GPU Fragment Processor 2" name="Patches evaluated" description="Number of patches evaluated for EarlyZ rejection."/>
187 <event event="0x25" title="Mali GPU Fragment Processor 2" name="Instruction completed count" description="Number of fragment shader instruction words completed. It is a function of pixels processed and the length of the shader programs."/>
188 <event event="0x26" title="Mali GPU Fragment Processor 2" name="Instruction failed rendezvous count" description="Number of fragment shader instructions not completed because of failed Rendezvous."/>
189 <event event="0x27" title="Mali GPU Fragment Processor 2" name="Instruction failed varying-miss count" description="Number of fragment shader instructions not completed because of failed varying operation."/>
190 <event event="0x28" title="Mali GPU Fragment Processor 2" name="Instruction failed texture-miss count" description="Number of fragment shader instructions not completed because of failed texture operation."/>
191 <event event="0x29" title="Mali GPU Fragment Processor 2" name="Instruction failed load-miss count" description="Number of fragment shader instructions not completed because of failed load operation."/>
192 <event event="0x2a" title="Mali GPU Fragment Processor 2" name="Instruction failed tile read-miss count" description="Number of fragment shader instructions not completed because of failed read from the tilebuffer."/>
193 <event event="0x2b" title="Mali GPU Fragment Processor 2" name="Instruction failed store-miss count" description="Number of fragment shader instructions not completed because of failed store operation."/>
194 <event event="0x2c" title="Mali GPU Fragment Processor 2" name="Rendezvous breakage count" description="Number of Rendezvous breakages reported."/>
195 <event event="0x2d" title="Mali GPU Fragment Processor 2" name="Pipeline bubbles cycle count" description="Number of unused cycles in the fragment shader while rendering is active."/>
196 <event event="0x2e" title="Mali GPU Fragment Processor 2" name="Texture mapper multipass count" description="Number of texture operations looped because of more texture passes needed."/>
197 <event event="0x2f" title="Mali GPU Fragment Processor 2" name="Texture mapper cycle count" description="Number of texture operation cycles."/>
198 <event event="0x30" title="Mali GPU Fragment Processor 2" name="Vertex cache hit count" description="Number of times a requested vertex was found in the cache (Number of vertex cache hits)."/>
199 <event event="0x31" title="Mali GPU Fragment Processor 2" name="Vertex cache miss count" description="Number of times a requested vertex was not found in the cache (Number of vertex cache misses)."/>
200 <event event="0x32" title="Mali GPU Fragment Processor 2" name="Varying cache hit count" description="Number of times a requested varying was found in the cache (Number of varying cache hits)."/>
201 <event event="0x33" title="Mali GPU Fragment Processor 2" name="Varying cache miss count" description="Number of times a requested varying was not found in the cache (Number of varying cache misses)."/>
202 <event event="0x34" title="Mali GPU Fragment Processor 2" name="Varying cache conflict miss count" description="Number of times a requested varying was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/>
203 <event event="0x35" title="Mali GPU Fragment Processor 2" name="Texture cache hit count" description="Number of times a requested texel was found in the texture cache (Number of texture cache hits)."/>
204 <event event="0x36" title="Mali GPU Fragment Processor 2" name="Texture cache miss count" description="Number of times a requested texel was not found in the texture cache (Number of texture cache misses)."/>
205 <event event="0x37" title="Mali GPU Fragment Processor 2" name="Texture cache conflict miss count" description="Number of times a requested texel was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/>
206 <event event="0x38" title="Mali GPU Fragment Processor 2" name="Compressed texture cache hit count" description="Number of times a requested item was found in the cache."/>
207 <event event="0x39" title="Mali GPU Fragment Processor 2" name="Compressed texture cache miss count" description="Number of times a requested item was not found in the cache."/>
208 <event event="0x3a" title="Mali GPU Fragment Processor 2" name="Load/Store cache hit count" description="Number of hits in the load/store cache."/>
209 <event event="0x3b" title="Mali GPU Fragment Processor 2" name="Load/Store cache miss count" description="Number of misses in the load/store cache."/>
210 <event event="0x3c" title="Mali GPU Fragment Processor 2" name="Program cache hit count" description="Number of hits in the program cache."/>
211 <event event="0x3d" title="Mali GPU Fragment Processor 2" name="Program cache miss count" description="Number of misses in the program cache."/>
212 </category>
213 <category name="Mali-400-FP3" counter_set="ARM_Mali-400_FP3_cnt" per_cpu="no">
214 <event event="0x00" title="Mali GPU Fragment Processor 3" name="Active clock cycles" description="Active clock cycles, between polygon start and IRQ."/>
215 <event event="0x02" title="Mali GPU Fragment Processor 3" name="Total bus reads" description="Total number of 64-bit words read from the bus."/>
216 <event event="0x03" title="Mali GPU Fragment Processor 3" name="Total bus writes" description="Total number of 64-bit words written to the bus."/>
217 <event event="0x04" title="Mali GPU Fragment Processor 3" name="Bus read request cycles" description="Number of cycles during which the bus read request signal was HIGH."/>
218 <event event="0x05" title="Mali GPU Fragment Processor 3" name="Bus write request cycles" description="Number of cycles during which the bus write request signal was HIGH."/>
219 <event event="0x06" title="Mali GPU Fragment Processor 3" name="Bus read transactions count" description="Number of read requests accepted by the bus."/>
220 <event event="0x07" title="Mali GPU Fragment Processor 3" name="Bus write transactions" description="Number of write requests accepted by the bus."/>
221 <event event="0x09" title="Mali GPU Fragment Processor 3" name="Tile writeback writes" description="64-bit words written to the bus by the writeback unit."/>
222 <event event="0x0a" title="Mali GPU Fragment Processor 3" name="Store unit writes" description="64-bit words written to the bus by the store unit."/>
223 <event event="0x0d" title="Mali GPU Fragment Processor 3" name="Texture cache uncompressed reads" description="Number of 64-bit words read from the bus into the uncompressed textures cache."/>
224 <event event="0x0e" title="Mali GPU Fragment Processor 3" name="Polygon list reads" description="Number of 64-bit words read from the bus by the polygon list reader."/>
225 <event event="0x0f" title="Mali GPU Fragment Processor 3" name="RSW reads" description="Number of 64-bit words read from the bus into the Render State Word register."/>
226 <event event="0x10" title="Mali GPU Fragment Processor 3" name="Vertex cache reads" description="Number of 64-bit words read from the bus into the vertex cache."/>
227 <event event="0x11" title="Mali GPU Fragment Processor 3" name="Uniform remapping reads" description="Number of 64-bit words read from the bus when reading from the uniform remapping table."/>
228 <event event="0x12" title="Mali GPU Fragment Processor 3" name="Program cache reads" description="Number of 64-bit words read from the bus into the fragment shader program cache."/>
229 <event event="0x13" title="Mali GPU Fragment Processor 3" name="Varying reads" description="Number of 64-bit words containing varyings generated by the vertex processing read from the bus."/>
230 <event event="0x14" title="Mali GPU Fragment Processor 3" name="Texture descriptors reads" description="Number of 64-bit words containing texture descriptors read from the bus."/>
231 <event event="0x15" title="Mali GPU Fragment Processor 3" name="Texture descriptor remapping reads" description="Number of 64-bit words read from the bus when reading from the texture descriptor remapping table."/>
232 <event event="0x17" title="Mali GPU Fragment Processor 3" name="Load unit reads" description="Number of 64-bit words read from the bus by the LOAD sub-instruction."/>
233 <event event="0x18" title="Mali GPU Fragment Processor 3" name="Polygon count" description="Number of triangles read from the polygon list."/>
234 <event event="0x19" title="Mali GPU Fragment Processor 3" name="Pixel rectangle count" description="Number of pixel rectangles read from the polygon list."/>
235 <event event="0x1a" title="Mali GPU Fragment Processor 3" name="Lines count" description="Number of lines read from the polygon list."/>
236 <event event="0x1b" title="Mali GPU Fragment Processor 3" name="Points count" description="Number of points read from the polygon list."/>
237 <event event="0x1c" title="Mali GPU Fragment Processor 3" name="Stall cycles PolygonListReader" description="Number of clock cycles the Polygon List Reader waited for output being collected."/>
238 <event event="0x1d" title="Mali GPU Fragment Processor 3" name="Stall cycles triangle setup" description="Number of clock cycles the TSC waited for input."/>
239 <event event="0x1e" title="Mali GPU Fragment Processor 3" name="Quad rasterized count" description="Number of 2x?2 quads output from rasterizer."/>
240 <event event="0x1f" title="Mali GPU Fragment Processor 3" name="Fragment rasterized count" description="Number of fragment rasterized. Fragments/(Quads*4) gives average actual fragments per quad."/>
241 <event event="0x20" title="Mali GPU Fragment Processor 3" name="Fragment rejected fragment-kill count" description="Number of fragments exiting the fragment shader as killed."/>
242 <event event="0x21" title="Mali GPU Fragment Processor 3" name="Fragment rejected fwd-fragment-kill count" description="Number of fragments killed by forward fragment kill."/>
243 <event event="0x22" title="Mali GPU Fragment Processor 3" name="Fragment passed z/stencil count" description="Number of fragments passing Z and stencil test."/>
244 <event event="0x23" title="Mali GPU Fragment Processor 3" name="Patches rejected early z/stencil count" description="Number of patches rejected by EarlyZ. A patch can be 8x8, 4x4 or 2x2 pixels."/>
245 <event event="0x24" title="Mali GPU Fragment Processor 3" name="Patches evaluated" description="Number of patches evaluated for EarlyZ rejection."/>
246 <event event="0x25" title="Mali GPU Fragment Processor 3" name="Instruction completed count" description="Number of fragment shader instruction words completed. It is a function of pixels processed and the length of the shader programs."/>
247 <event event="0x26" title="Mali GPU Fragment Processor 3" name="Instruction failed rendezvous count" description="Number of fragment shader instructions not completed because of failed Rendezvous."/>
248 <event event="0x27" title="Mali GPU Fragment Processor 3" name="Instruction failed varying-miss count" description="Number of fragment shader instructions not completed because of failed varying operation."/>
249 <event event="0x28" title="Mali GPU Fragment Processor 3" name="Instruction failed texture-miss count" description="Number of fragment shader instructions not completed because of failed texture operation."/>
250 <event event="0x29" title="Mali GPU Fragment Processor 3" name="Instruction failed load-miss count" description="Number of fragment shader instructions not completed because of failed load operation."/>
251 <event event="0x2a" title="Mali GPU Fragment Processor 3" name="Instruction failed tile read-miss count" description="Number of fragment shader instructions not completed because of failed read from the tilebuffer."/>
252 <event event="0x2b" title="Mali GPU Fragment Processor 3" name="Instruction failed store-miss count" description="Number of fragment shader instructions not completed because of failed store operation."/>
253 <event event="0x2c" title="Mali GPU Fragment Processor 3" name="Rendezvous breakage count" description="Number of Rendezvous breakages reported."/>
254 <event event="0x2d" title="Mali GPU Fragment Processor 3" name="Pipeline bubbles cycle count" description="Number of unused cycles in the fragment shader while rendering is active."/>
255 <event event="0x2e" title="Mali GPU Fragment Processor 3" name="Texture mapper multipass count" description="Number of texture operations looped because of more texture passes needed."/>
256 <event event="0x2f" title="Mali GPU Fragment Processor 3" name="Texture mapper cycle count" description="Number of texture operation cycles."/>
257 <event event="0x30" title="Mali GPU Fragment Processor 3" name="Vertex cache hit count" description="Number of times a requested vertex was found in the cache (Number of vertex cache hits)."/>
258 <event event="0x31" title="Mali GPU Fragment Processor 3" name="Vertex cache miss count" description="Number of times a requested vertex was not found in the cache (Number of vertex cache misses)."/>
259 <event event="0x32" title="Mali GPU Fragment Processor 3" name="Varying cache hit count" description="Number of times a requested varying was found in the cache (Number of varying cache hits)."/>
260 <event event="0x33" title="Mali GPU Fragment Processor 3" name="Varying cache miss count" description="Number of times a requested varying was not found in the cache (Number of varying cache misses)."/>
261 <event event="0x34" title="Mali GPU Fragment Processor 3" name="Varying cache conflict miss count" description="Number of times a requested varying was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/>
262 <event event="0x35" title="Mali GPU Fragment Processor 3" name="Texture cache hit count" description="Number of times a requested texel was found in the texture cache (Number of texture cache hits)."/>
263 <event event="0x36" title="Mali GPU Fragment Processor 3" name="Texture cache miss count" description="Number of times a requested texel was not found in the texture cache (Number of texture cache misses)."/>
264 <event event="0x37" title="Mali GPU Fragment Processor 3" name="Texture cache conflict miss count" description="Number of times a requested texel was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/>
265 <event event="0x38" title="Mali GPU Fragment Processor 3" name="Compressed texture cache hit count" description="Number of times a requested item was found in the cache."/>
266 <event event="0x39" title="Mali GPU Fragment Processor 3" name="Compressed texture cache miss count" description="Number of times a requested item was not found in the cache."/>
267 <event event="0x3a" title="Mali GPU Fragment Processor 3" name="Load/Store cache hit count" description="Number of hits in the load/store cache."/>
268 <event event="0x3b" title="Mali GPU Fragment Processor 3" name="Load/Store cache miss count" description="Number of misses in the load/store cache."/>
269 <event event="0x3c" title="Mali GPU Fragment Processor 3" name="Program cache hit count" description="Number of hits in the program cache."/>
270 <event event="0x3d" title="Mali GPU Fragment Processor 3" name="Program cache miss count" description="Number of misses in the program cache."/>
271 </category> 95 </category>
272 <category name="Mali-400-L2" counter_set="ARM_Mali-400_L2_cnt" per_cpu="no"> 96 <category name="Mali-400-L2" counter_set="ARM_Mali-400_L2_cnt" per_cpu="no">
273 <event event="0x01" title="Mali L2 Cache" name="Total clock cycles" description="Total clock cycles."/> 97 <event event="0x01" title="Mali L2 Cache" name="Total clock cycles" description="Total clock cycles"/>
274 <event event="0x02" title="Mali L2 Cache" name="Active clock cycles" description="Active clock cycles." /> 98 <event event="0x02" title="Mali L2 Cache" name="Active clock cycles" description="Active clock cycles"/>
275 <event event="0x08" title="Mali L2 Cache" name="Read transactions, master" description="Read transactions, master." /> 99
276 <event event="0x09" title="Mali L2 Cache" name="Write transactions, master" description="Write transactions, master." /> 100 <option_set name="All">
277 <event event="0x0a" title="Mali L2 Cache" name="Words read, master" description="Words read, master." /> 101 <option event_delta="0x08" name="Master" description="Master"/>
278 <event event="0x0b" title="Mali L2 Cache" name="Words written, master" description="Words written, master." /> 102 <option event_delta="0x10" name="All slaves" description="All slaves"/>
279 <event event="0x10" title="Mali L2 Cache" name="Read transactions, all slaves" description="Read transactions, all slaves." /> 103 <option event_delta="0x20" name="Slave 0" description="Slave 0"/>
280 <event event="0x11" title="Mali L2 Cache" name="Write transactions, all slaves" description="Write transactions, all slaves." /> 104 <option event_delta="0x30" name="Slave 1" description="Slave 1"/>
281 <event event="0x12" title="Mali L2 Cache" name="Words read, all slaves" description="Words read, all slaves." /> 105 <option event_delta="0x40" name="Slave 2" description="Slave 2"/>
282 <event event="0x13" title="Mali L2 Cache" name="Words written, all slaves" description="Words written, all slaves." /> 106 <option event_delta="0x50" name="Slave 3" description="Slave 3"/>
283 <event event="0x14" title="Mali L2 Cache" name="Read hits, all slaves" description="Read hits, all slaves." /> 107 <option event_delta="0x60" name="Slave 4" description="Slave 4"/>
284 <event event="0x15" title="Mali L2 Cache" name="Read misses, all slaves" description="Read misses, all slaves." /> 108 </option_set>
285 <event event="0x16" title="Mali L2 Cache" name="Write invalidates, all slaves" description="Write invalidates, all slaves." /> 109
286 <event event="0x17" title="Mali L2 Cache" name="Read invalidates, all slaves" description="Read invalidates, all slaves." /> 110 <option_set name="Slaves">
287 <event event="0x18" title="Mali L2 Cache" name="Cacheable read transactions, all slaves" description="Cacheable read transactions, all slaves." /> 111 <option event_delta="0x10" name="All slaves" description="All slaves"/>
288 <event event="0x20" title="Mali L2 Cache" name="Read transactions, slave 0" description="Read transactions, slave 0." /> 112 <option event_delta="0x20" name="Slave 0" description="Slave 0"/>
289 <event event="0x21" title="Mali L2 Cache" name="Write transactions, slave 0" description="Write transactions, slave 0." /> 113 <option event_delta="0x30" name="Slave 1" description="Slave 1"/>
290 <event event="0x22" title="Mali L2 Cache" name="Words read, slave 0" description="Words read, slave 0." /> 114 <option event_delta="0x40" name="Slave 2" description="Slave 2"/>
291 <event event="0x23" title="Mali L2 Cache" name="Words written, slave 0" description="Words written, slave 0." /> 115 <option event_delta="0x50" name="Slave 3" description="Slave 3"/>
292 <event event="0x24" title="Mali L2 Cache" name="Read hits, slave 0" description="Read hits, slave 0." /> 116 <option event_delta="0x60" name="Slave 4" description="Slave 4"/>
293 <event event="0x25" title="Mali L2 Cache" name="Read misses, slave 0" description="Read misses, slave 0." /> 117 </option_set>
294 <event event="0x26" title="Mali L2 Cache" name="Write invalidates, slave 0" description="Write invalidates, slave 0." /> 118
295 <event event="0x27" title="Mali L2 Cache" name="Read invalidates, slave 0" description="Read invalidates, slave 0." /> 119 <event event="0x00" option_set="All" title="Mali L2 Cache" name="Read transactions" description="Read transactions"/>
296 <event event="0x28" title="Mali L2 Cache" name="Cacheable read transactions, slave 0" description="Cacheable read transactions, slave 0." /> 120 <event event="0x01" option_set="All" title="Mali L2 Cache" name="Write transactions" description="Write transactions"/>
297 <event event="0x30" title="Mali L2 Cache" name="Read transactions, slave 1" description="Read transactions, slave 1." /> 121 <event event="0x02" option_set="All" title="Mali L2 Cache" name="Words read" description="Words read"/>
298 <event event="0x31" title="Mali L2 Cache" name="Write transactions, slave 1" description="Write transactions, slave 1." /> 122 <event event="0x03" option_set="All" title="Mali L2 Cache" name="Words written" description="Words written"/>
299 <event event="0x32" title="Mali L2 Cache" name="Words read, slave 1" description="Words read, slave 1." /> 123 <event event="0x04" option_set="Slaves" title="Mali L2 Cache" name="Read hits" description="Read hits"/>
300 <event event="0x33" title="Mali L2 Cache" name="Words written, slave 1" description="Words written, slave 1." /> 124 <event event="0x05" option_set="Slaves" title="Mali L2 Cache" name="Read misses" description="Read misses"/>
301 <event event="0x34" title="Mali L2 Cache" name="Read hits, slave 1" description="Read hits, slave 1." /> 125 <event event="0x06" option_set="Slaves" title="Mali L2 Cache" name="Write invalidates" description="Write invalidates"/>
302 <event event="0x35" title="Mali L2 Cache" name="Read misses, slave 1" description="Read misses, slave 1." /> 126 <event event="0x07" option_set="Slaves" title="Mali L2 Cache" name="Read invalidates" description="Read invalidates"/>
303 <event event="0x36" title="Mali L2 Cache" name="Write invalidates, slave 1" description="Write invalidates, slave 1." /> 127 <event event="0x08" option_set="Slaves" title="Mali L2 Cache" name="Cacheable read transactions" description="Cacheable read transactions"/>
304 <event event="0x37" title="Mali L2 Cache" name="Read invalidates, slave 1" description="Read invalidates, slave 1." />
305 <event event="0x38" title="Mali L2 Cache" name="Cacheable read transactions, slave 1" description="Cacheable read transactions, slave 1." />
306 <event event="0x40" title="Mali L2 Cache" name="Read transactions, slave 2" description="Read transactions, slave 2." />
307 <event event="0x41" title="Mali L2 Cache" name="Write transactions, slave 2" description="Write transactions, slave 2." />
308 <event event="0x42" title="Mali L2 Cache" name="Words read, slave 2" description="Words read, slave 2." />
309 <event event="0x43" title="Mali L2 Cache" name="Words written, slave 2" description="Words written, slave 2." />
310 <event event="0x44" title="Mali L2 Cache" name="Read hits, slave 2" description="Read hits, slave 2." />
311 <event event="0x45" title="Mali L2 Cache" name="Read misses, slave 2" description="Read misses, slave 2." />
312 <event event="0x46" title="Mali L2 Cache" name="Write invalidates, slave 2" description="Write invalidates, slave 2." />
313 <event event="0x47" title="Mali L2 Cache" name="Read invalidates, slave 2" description="Read invalidates, slave 2." />
314 <event event="0x48" title="Mali L2 Cache" name="Cacheable read transactions, slave 2" description="Cacheable read transactions, slave 2." />
315 <event event="0x50" title="Mali L2 Cache" name="Read transactions, slave 3" description="Read transactions, slave 3." />
316 <event event="0x51" title="Mali L2 Cache" name="Write transactions, slave 3" description="Write transactions, slave 3." />
317 <event event="0x52" title="Mali L2 Cache" name="Words read, slave 3" description="Words read, slave 3." />
318 <event event="0x53" title="Mali L2 Cache" name="Words written, slave 3" description="Words written, slave 3." />
319 <event event="0x54" title="Mali L2 Cache" name="Read hits, slave 3" description="Read hits, slave 3." />
320 <event event="0x55" title="Mali L2 Cache" name="Read misses, slave 3" description="Read misses, slave 3." />
321 <event event="0x56" title="Mali L2 Cache" name="Write invalidates, slave 3" description="Write invalidates, slave 3." />
322 <event event="0x57" title="Mali L2 Cache" name="Read invalidates, slave 3" description="Read invalidates, slave 3." />
323 <event event="0x58" title="Mali L2 Cache" name="Cacheable read transactions, slave 3" description="Cacheable read transactions, slave 3." />
324 <event event="0x60" title="Mali L2 Cache" name="Read transactions, slave 4" description="Read transactions, slave 4." />
325 <event event="0x61" title="Mali L2 Cache" name="Write transactions, slave 4" description="Write transactions, slave 4." />
326 <event event="0x62" title="Mali L2 Cache" name="Words read, slave 4" description="Words read, slave 4." />
327 <event event="0x63" title="Mali L2 Cache" name="Words written, slave 4" description="Words written, slave 4." />
328 <event event="0x64" title="Mali L2 Cache" name="Read hits, slave 4" description="Read hits, slave 4." />
329 <event event="0x65" title="Mali L2 Cache" name="Read misses, slave 4" description="Read misses, slave 4." />
330 <event event="0x66" title="Mali L2 Cache" name="Write invalidates, slave 4" description="Write invalidates, slave 4." />
331 <event event="0x67" title="Mali L2 Cache" name="Read invalidates, slave 4" description="Read invalidates, slave 4." />
332 <event event="0x68" title="Mali L2 Cache" name="Cacheable read transactions, slave 4" description="Cacheable read transactions, slave 4." />
333 </category> 128 </category>
334 <category name="ARM_Mali-400_Filmstrip" counter_set="ARM_Mali-400_Filmstrip_cnt" per_cpu="no"> 129 <category name="ARM Mali-400 Filmstrip" counter_set="ARM_Mali-400_Filmstrip_cnt" per_cpu="no">
335 <event event="0x040a" title="ARM_Mali-400_Filmstrip" name="Freq 1:10" description="Scaled framebuffer captures every 10th frame." /> 130 <option_set name="fs">
336 <event event="0x041e" title="ARM_Mali-400_Filmstrip" name="Freq 1:30" description="Scaled framebuffer captures every 30th frame." /> 131 <option event_delta="0x3c" name="1:60" description="captures every 60th frame"/>
337 <event event="0x043c" title="ARM_Mali-400_Filmstrip" name="Freq 1:60" description="Scaled framebuffer captures every 60th frame." /> 132 <option event_delta="0x1e" name="1:30" description="captures every 30th frame"/>
133 <option event_delta="0xa" name="1:10" description="captures every 10th frame"/>
134 </option_set>
135 <event event="0x0400" option_set="fs" title="ARM Mali-400" name="Filmstrip" description="Scaled framebuffer"/>
338 </category> 136 </category>
339 <category name="ARM_Mali-400_Voltage" per_cpu="no"> 137 <category name="ARM_Mali-400_Voltage" per_cpu="no">
340 <event counter="ARM_Mali-400_Voltage" title="Mali GPU Voltage" name="Voltage" display="average" average_selection="yes" units="mV" description="GPU core voltage."/> 138 <event counter="ARM_Mali-400_Voltage" title="Mali GPU Voltage" name="Voltage" display="average" average_selection="yes" units="mV" description="GPU core voltage."/>
diff --git a/daemon/events-Mali-T6xx_hw.xml b/daemon/events-Mali-T6xx_hw.xml
index 825b668..7c7b1ea 100644
--- a/daemon/events-Mali-T6xx_hw.xml
+++ b/daemon/events-Mali-T6xx_hw.xml
@@ -109,7 +109,7 @@
109 109
110 <event counter="ARM_Mali-T6xx_PCACHE_HIT" title="Mali GPU Tiler" name="Pointer-cache hits" description="Number of pointer-cache hits."/> 110 <event counter="ARM_Mali-T6xx_PCACHE_HIT" title="Mali GPU Tiler" name="Pointer-cache hits" description="Number of pointer-cache hits."/>
111 <event counter="ARM_Mali-T6xx_PCACHE_MISS" title="Mali GPU Tiler" name="Pointer-cache misses" description="Number of pointer-cache misses."/> 111 <event counter="ARM_Mali-T6xx_PCACHE_MISS" title="Mali GPU Tiler" name="Pointer-cache misses" description="Number of pointer-cache misses."/>
112 <event counter="ARM_Mali-T6xx_PCACHE_LINE" title="Mali GPU Tiler" name="Pointer-cache line-fils" description="Number of pointer-cache line-fills."/> 112 <event counter="ARM_Mali-T6xx_PCACHE_LINE" title="Mali GPU Tiler" name="Pointer-cache line-fills" description="Number of pointer-cache line-fills."/>
113 <event counter="ARM_Mali-T6xx_PCACHE_STALL" title="Mali GPU Tiler" name="Pointer-cache stalls" description="Number of pointer-cache stalls."/> 113 <event counter="ARM_Mali-T6xx_PCACHE_STALL" title="Mali GPU Tiler" name="Pointer-cache stalls" description="Number of pointer-cache stalls."/>
114 114
115 <event counter="ARM_Mali-T6xx_WRBUF_HIT" title="Mali GPU Tiler" name="Write-buffer hits" description="Number of write-buffer hits."/> 115 <event counter="ARM_Mali-T6xx_WRBUF_HIT" title="Mali GPU Tiler" name="Write-buffer hits" description="Number of write-buffer hits."/>
@@ -128,7 +128,7 @@
128 <event counter="ARM_Mali-T6xx_WRBUF_WAIT" title="Mali GPU Tiler" name="Cycles no write buffer entry" description="Number of cycles a command could be written to the write buffer, but no write buffer entry is available."/> 128 <event counter="ARM_Mali-T6xx_WRBUF_WAIT" title="Mali GPU Tiler" name="Cycles no write buffer entry" description="Number of cycles a command could be written to the write buffer, but no write buffer entry is available."/>
129 129
130 <event counter="ARM_Mali-T6xx_BUS_READ" title="Mali GPU Tiler" name="Data beats from L2 cache read." description="Number of data beats (64-bit) on read from the L2 cache."/> 130 <event counter="ARM_Mali-T6xx_BUS_READ" title="Mali GPU Tiler" name="Data beats from L2 cache read." description="Number of data beats (64-bit) on read from the L2 cache."/>
131 <event counter="ARM_Mali-T6xx_BUS_WRITE" title="Mali GPU Tiler" name="Data beats from L2 chache write" description="Number of data beats (64-bit) on written to the L2 cache."/> 131 <event counter="ARM_Mali-T6xx_BUS_WRITE" title="Mali GPU Tiler" name="Data beats from L2 cache write" description="Number of data beats (64-bit) on written to the L2 cache."/>
132 132
133 <event counter="ARM_Mali-T6xx_UTLB_STALL" title="Mali GPU Tiler" name="uTLB cycles stall" description="uTLB: Cycles with stall on input AXI address channel."/> 133 <event counter="ARM_Mali-T6xx_UTLB_STALL" title="Mali GPU Tiler" name="uTLB cycles stall" description="uTLB: Cycles with stall on input AXI address channel."/>
134 134
@@ -170,11 +170,11 @@
170 <event counter="ARM_Mali-T6xx_COMPUTE_THREADS" title="Compute" name="Compute threads started" description="Number of compute threads started."/> 170 <event counter="ARM_Mali-T6xx_COMPUTE_THREADS" title="Compute" name="Compute threads started" description="Number of compute threads started."/>
171 <event counter="ARM_Mali-T6xx_COMPUTE_CYCLES_DESC" title="Compute" name="Stall: Waiting for descriptors" description="Number of cycles spent waiting for descriptors."/> 171 <event counter="ARM_Mali-T6xx_COMPUTE_CYCLES_DESC" title="Compute" name="Stall: Waiting for descriptors" description="Number of cycles spent waiting for descriptors."/>
172 <event counter="ARM_Mali-T6xx_TRIPIPE_ACTIVE" title="Tripipe" name="Tripipe active cycles" description="Number of cycles the Tripipe was active."/> 172 <event counter="ARM_Mali-T6xx_TRIPIPE_ACTIVE" title="Tripipe" name="Tripipe active cycles" description="Number of cycles the Tripipe was active."/>
173 <event counter="ARM_Mali-T6xx_ARITH_WORDS" title="Arithmetic Pipeline" name="Instructions per pipe" description="Number of instruction words in the arithmethic pipelines, divided by the number of arithmethic pipelines."/> 173 <event counter="ARM_Mali-T6xx_ARITH_WORDS" title="Arithmetic Pipeline" name="Instructions per pipe" description="Number of instruction words in the arithmetic pipelines, divided by the number of arithmetic pipelines."/>
174 174
175 <event counter="ARM_Mali-T6xx_ARITH_CYCLES_REG" title="Arithmetic Pipeline" name="Stall: Register scheduling" description="Number of cycles lost in the arithmethic pipelines due to register scheduling, divided by the number of arithmethic pipelines."/> 175 <event counter="ARM_Mali-T6xx_ARITH_CYCLES_REG" title="Arithmetic Pipeline" name="Stall: Register scheduling" description="Number of cycles lost in the arithmetic pipelines due to register scheduling, divided by the number of arithmetic pipelines."/>
176 <event counter="ARM_Mali-T6xx_ARITH_CYCLES_L0" title="Arithmetic Pipeline" name="Stall: Icache miss per pipe" description="Number of cycles lost in the arithmethic pipelines due to L0 instruction cache misses, divided by the number of arithmethic pipelines."/> 176 <event counter="ARM_Mali-T6xx_ARITH_CYCLES_L0" title="Arithmetic Pipeline" name="Stall: Icache miss per pipe" description="Number of cycles lost in the arithmetic pipelines due to L0 instruction cache misses, divided by the number of arithmetic pipelines."/>
177 <event counter="ARM_Mali-T6xx_ARITH_FRAG_DEPEND" title="Arithmetic Pipeline" name="Stall: Fragment dependency fails per pipe" description="Number of fragment dependency check failures in the arithmethic pipelines, divided by the number of arithmethic pipelines."/> 177 <event counter="ARM_Mali-T6xx_ARITH_FRAG_DEPEND" title="Arithmetic Pipeline" name="Stall: Fragment dependency fails per pipe" description="Number of fragment dependency check failures in the arithmetic pipelines, divided by the number of arithmetic pipelines."/>
178 <event counter="ARM_Mali-T6xx_LS_WORDS" title="Load/Store Pipeline" name="Load/Store instruction words completed" description="Number of instruction words completed in the Load/Store pipeline."/> 178 <event counter="ARM_Mali-T6xx_LS_WORDS" title="Load/Store Pipeline" name="Load/Store instruction words completed" description="Number of instruction words completed in the Load/Store pipeline."/>
179 179
180 <event counter="ARM_Mali-T6xx_LS_ISSUES" title="Load/Store Pipeline" name="Full pipeline issues" description="Number of full pipeline issues in the Load/Store pipeline."/> 180 <event counter="ARM_Mali-T6xx_LS_ISSUES" title="Load/Store Pipeline" name="Full pipeline issues" description="Number of full pipeline issues in the Load/Store pipeline."/>
diff --git a/daemon/events-Scorpion.xml b/daemon/events-Scorpion.xml
index 1642e85..d08a5a2 100644
--- a/daemon/events-Scorpion.xml
+++ b/daemon/events-Scorpion.xml
@@ -1,6 +1,6 @@
1 <counter_set name="Scorpion_cnt" count="4"/> 1 <counter_set name="Scorpion_cnt" count="4"/>
2 <category name="Scorpion" counter_set="Scorpion_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Scorpion" counter_set="Scorpion_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="Scorpion_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="Scorpion_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-ScorpionMP.xml b/daemon/events-ScorpionMP.xml
index 309f103..dad4c70 100644
--- a/daemon/events-ScorpionMP.xml
+++ b/daemon/events-ScorpionMP.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ScorpionMP_cnt" count="4"/> 1 <counter_set name="ScorpionMP_cnt" count="4"/>
2 <category name="ScorpionMP" counter_set="ScorpionMP_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="ScorpionMP" counter_set="ScorpionMP_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ScorpionMP_ccnt" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> 3 <event counter="ScorpionMP_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/libsensors/COPYING.LGPL b/daemon/libsensors/COPYING.LGPL
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/daemon/libsensors/COPYING.LGPL
@@ -0,0 +1,502 @@
1 GNU LESSER GENERAL PUBLIC LICENSE
2 Version 2.1, February 1999
3
4 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9[This is the first released version of the Lesser GPL. It also counts
10 as the successor of the GNU Library Public License, version 2, hence
11 the version number 2.1.]
12
13 Preamble
14
15 The licenses for most software are designed to take away your
16freedom to share and change it. By contrast, the GNU General Public
17Licenses are intended to guarantee your freedom to share and change
18free software--to make sure the software is free for all its users.
19
20 This license, the Lesser General Public License, applies to some
21specially designated software packages--typically libraries--of the
22Free Software Foundation and other authors who decide to use it. You
23can use it too, but we suggest you first think carefully about whether
24this license or the ordinary General Public License is the better
25strategy to use in any particular case, based on the explanations below.
26
27 When we speak of free software, we are referring to freedom of use,
28not price. Our General Public Licenses are designed to make sure that
29you have the freedom to distribute copies of free software (and charge
30for this service if you wish); that you receive source code or can get
31it if you want it; that you can change the software and use pieces of
32it in new free programs; and that you are informed that you can do
33these things.
34
35 To protect your rights, we need to make restrictions that forbid
36distributors to deny you these rights or to ask you to surrender these
37rights. These restrictions translate to certain responsibilities for
38you if you distribute copies of the library or if you modify it.
39
40 For example, if you distribute copies of the library, whether gratis
41or for a fee, you must give the recipients all the rights that we gave
42you. You must make sure that they, too, receive or can get the source
43code. If you link other code with the library, you must provide
44complete object files to the recipients, so that they can relink them
45with the library after making changes to the library and recompiling
46it. And you must show them these terms so they know their rights.
47
48 We protect your rights with a two-step method: (1) we copyright the
49library, and (2) we offer you this license, which gives you legal
50permission to copy, distribute and/or modify the library.
51
52 To protect each distributor, we want to make it very clear that
53there is no warranty for the free library. Also, if the library is
54modified by someone else and passed on, the recipients should know
55that what they have is not the original version, so that the original
56author's reputation will not be affected by problems that might be
57introduced by others.
58
59 Finally, software patents pose a constant threat to the existence of
60any free program. We wish to make sure that a company cannot
61effectively restrict the users of a free program by obtaining a
62restrictive license from a patent holder. Therefore, we insist that
63any patent license obtained for a version of the library must be
64consistent with the full freedom of use specified in this license.
65
66 Most GNU software, including some libraries, is covered by the
67ordinary GNU General Public License. This license, the GNU Lesser
68General Public License, applies to certain designated libraries, and
69is quite different from the ordinary General Public License. We use
70this license for certain libraries in order to permit linking those
71libraries into non-free programs.
72
73 When a program is linked with a library, whether statically or using
74a shared library, the combination of the two is legally speaking a
75combined work, a derivative of the original library. The ordinary
76General Public License therefore permits such linking only if the
77entire combination fits its criteria of freedom. The Lesser General
78Public License permits more lax criteria for linking other code with
79the library.
80
81 We call this license the "Lesser" General Public License because it
82does Less to protect the user's freedom than the ordinary General
83Public License. It also provides other free software developers Less
84of an advantage over competing non-free programs. These disadvantages
85are the reason we use the ordinary General Public License for many
86libraries. However, the Lesser license provides advantages in certain
87special circumstances.
88
89 For example, on rare occasions, there may be a special need to
90encourage the widest possible use of a certain library, so that it becomes
91a de-facto standard. To achieve this, non-free programs must be
92allowed to use the library. A more frequent case is that a free
93library does the same job as widely used non-free libraries. In this
94case, there is little to gain by limiting the free library to free
95software only, so we use the Lesser General Public License.
96
97 In other cases, permission to use a particular library in non-free
98programs enables a greater number of people to use a large body of
99free software. For example, permission to use the GNU C Library in
100non-free programs enables many more people to use the whole GNU
101operating system, as well as its variant, the GNU/Linux operating
102system.
103
104 Although the Lesser General Public License is Less protective of the
105users' freedom, it does ensure that the user of a program that is
106linked with the Library has the freedom and the wherewithal to run
107that program using a modified version of the Library.
108
109 The precise terms and conditions for copying, distribution and
110modification follow. Pay close attention to the difference between a
111"work based on the library" and a "work that uses the library". The
112former contains code derived from the library, whereas the latter must
113be combined with the library in order to run.
114
115 GNU LESSER GENERAL PUBLIC LICENSE
116 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117
118 0. This License Agreement applies to any software library or other
119program which contains a notice placed by the copyright holder or
120other authorized party saying it may be distributed under the terms of
121this Lesser General Public License (also called "this License").
122Each licensee is addressed as "you".
123
124 A "library" means a collection of software functions and/or data
125prepared so as to be conveniently linked with application programs
126(which use some of those functions and data) to form executables.
127
128 The "Library", below, refers to any such software library or work
129which has been distributed under these terms. A "work based on the
130Library" means either the Library or any derivative work under
131copyright law: that is to say, a work containing the Library or a
132portion of it, either verbatim or with modifications and/or translated
133straightforwardly into another language. (Hereinafter, translation is
134included without limitation in the term "modification".)
135
136 "Source code" for a work means the preferred form of the work for
137making modifications to it. For a library, complete source code means
138all the source code for all modules it contains, plus any associated
139interface definition files, plus the scripts used to control compilation
140and installation of the library.
141
142 Activities other than copying, distribution and modification are not
143covered by this License; they are outside its scope. The act of
144running a program using the Library is not restricted, and output from
145such a program is covered only if its contents constitute a work based
146on the Library (independent of the use of the Library in a tool for
147writing it). Whether that is true depends on what the Library does
148and what the program that uses the Library does.
149
150 1. You may copy and distribute verbatim copies of the Library's
151complete source code as you receive it, in any medium, provided that
152you conspicuously and appropriately publish on each copy an
153appropriate copyright notice and disclaimer of warranty; keep intact
154all the notices that refer to this License and to the absence of any
155warranty; and distribute a copy of this License along with the
156Library.
157
158 You may charge a fee for the physical act of transferring a copy,
159and you may at your option offer warranty protection in exchange for a
160fee.
161
162 2. You may modify your copy or copies of the Library or any portion
163of it, thus forming a work based on the Library, and copy and
164distribute such modifications or work under the terms of Section 1
165above, provided that you also meet all of these conditions:
166
167 a) The modified work must itself be a software library.
168
169 b) You must cause the files modified to carry prominent notices
170 stating that you changed the files and the date of any change.
171
172 c) You must cause the whole of the work to be licensed at no
173 charge to all third parties under the terms of this License.
174
175 d) If a facility in the modified Library refers to a function or a
176 table of data to be supplied by an application program that uses
177 the facility, other than as an argument passed when the facility
178 is invoked, then you must make a good faith effort to ensure that,
179 in the event an application does not supply such function or
180 table, the facility still operates, and performs whatever part of
181 its purpose remains meaningful.
182
183 (For example, a function in a library to compute square roots has
184 a purpose that is entirely well-defined independent of the
185 application. Therefore, Subsection 2d requires that any
186 application-supplied function or table used by this function must
187 be optional: if the application does not supply it, the square
188 root function must still compute square roots.)
189
190These requirements apply to the modified work as a whole. If
191identifiable sections of that work are not derived from the Library,
192and can be reasonably considered independent and separate works in
193themselves, then this License, and its terms, do not apply to those
194sections when you distribute them as separate works. But when you
195distribute the same sections as part of a whole which is a work based
196on the Library, the distribution of the whole must be on the terms of
197this License, whose permissions for other licensees extend to the
198entire whole, and thus to each and every part regardless of who wrote
199it.
200
201Thus, it is not the intent of this section to claim rights or contest
202your rights to work written entirely by you; rather, the intent is to
203exercise the right to control the distribution of derivative or
204collective works based on the Library.
205
206In addition, mere aggregation of another work not based on the Library
207with the Library (or with a work based on the Library) on a volume of
208a storage or distribution medium does not bring the other work under
209the scope of this License.
210
211 3. You may opt to apply the terms of the ordinary GNU General Public
212License instead of this License to a given copy of the Library. To do
213this, you must alter all the notices that refer to this License, so
214that they refer to the ordinary GNU General Public License, version 2,
215instead of to this License. (If a newer version than version 2 of the
216ordinary GNU General Public License has appeared, then you can specify
217that version instead if you wish.) Do not make any other change in
218these notices.
219
220 Once this change is made in a given copy, it is irreversible for
221that copy, so the ordinary GNU General Public License applies to all
222subsequent copies and derivative works made from that copy.
223
224 This option is useful when you wish to copy part of the code of
225the Library into a program that is not a library.
226
227 4. You may copy and distribute the Library (or a portion or
228derivative of it, under Section 2) in object code or executable form
229under the terms of Sections 1 and 2 above provided that you accompany
230it with the complete corresponding machine-readable source code, which
231must be distributed under the terms of Sections 1 and 2 above on a
232medium customarily used for software interchange.
233
234 If distribution of object code is made by offering access to copy
235from a designated place, then offering equivalent access to copy the
236source code from the same place satisfies the requirement to
237distribute the source code, even though third parties are not
238compelled to copy the source along with the object code.
239
240 5. A program that contains no derivative of any portion of the
241Library, but is designed to work with the Library by being compiled or
242linked with it, is called a "work that uses the Library". Such a
243work, in isolation, is not a derivative work of the Library, and
244therefore falls outside the scope of this License.
245
246 However, linking a "work that uses the Library" with the Library
247creates an executable that is a derivative of the Library (because it
248contains portions of the Library), rather than a "work that uses the
249library". The executable is therefore covered by this License.
250Section 6 states terms for distribution of such executables.
251
252 When a "work that uses the Library" uses material from a header file
253that is part of the Library, the object code for the work may be a
254derivative work of the Library even though the source code is not.
255Whether this is true is especially significant if the work can be
256linked without the Library, or if the work is itself a library. The
257threshold for this to be true is not precisely defined by law.
258
259 If such an object file uses only numerical parameters, data
260structure layouts and accessors, and small macros and small inline
261functions (ten lines or less in length), then the use of the object
262file is unrestricted, regardless of whether it is legally a derivative
263work. (Executables containing this object code plus portions of the
264Library will still fall under Section 6.)
265
266 Otherwise, if the work is a derivative of the Library, you may
267distribute the object code for the work under the terms of Section 6.
268Any executables containing that work also fall under Section 6,
269whether or not they are linked directly with the Library itself.
270
271 6. As an exception to the Sections above, you may also combine or
272link a "work that uses the Library" with the Library to produce a
273work containing portions of the Library, and distribute that work
274under terms of your choice, provided that the terms permit
275modification of the work for the customer's own use and reverse
276engineering for debugging such modifications.
277
278 You must give prominent notice with each copy of the work that the
279Library is used in it and that the Library and its use are covered by
280this License. You must supply a copy of this License. If the work
281during execution displays copyright notices, you must include the
282copyright notice for the Library among them, as well as a reference
283directing the user to the copy of this License. Also, you must do one
284of these things:
285
286 a) Accompany the work with the complete corresponding
287 machine-readable source code for the Library including whatever
288 changes were used in the work (which must be distributed under
289 Sections 1 and 2 above); and, if the work is an executable linked
290 with the Library, with the complete machine-readable "work that
291 uses the Library", as object code and/or source code, so that the
292 user can modify the Library and then relink to produce a modified
293 executable containing the modified Library. (It is understood
294 that the user who changes the contents of definitions files in the
295 Library will not necessarily be able to recompile the application
296 to use the modified definitions.)
297
298 b) Use a suitable shared library mechanism for linking with the
299 Library. A suitable mechanism is one that (1) uses at run time a
300 copy of the library already present on the user's computer system,
301 rather than copying library functions into the executable, and (2)
302 will operate properly with a modified version of the library, if
303 the user installs one, as long as the modified version is
304 interface-compatible with the version that the work was made with.
305
306 c) Accompany the work with a written offer, valid for at
307 least three years, to give the same user the materials
308 specified in Subsection 6a, above, for a charge no more
309 than the cost of performing this distribution.
310
311 d) If distribution of the work is made by offering access to copy
312 from a designated place, offer equivalent access to copy the above
313 specified materials from the same place.
314
315 e) Verify that the user has already received a copy of these
316 materials or that you have already sent this user a copy.
317
318 For an executable, the required form of the "work that uses the
319Library" must include any data and utility programs needed for
320reproducing the executable from it. However, as a special exception,
321the materials to be distributed need not include anything that is
322normally distributed (in either source or binary form) with the major
323components (compiler, kernel, and so on) of the operating system on
324which the executable runs, unless that component itself accompanies
325the executable.
326
327 It may happen that this requirement contradicts the license
328restrictions of other proprietary libraries that do not normally
329accompany the operating system. Such a contradiction means you cannot
330use both them and the Library together in an executable that you
331distribute.
332
333 7. You may place library facilities that are a work based on the
334Library side-by-side in a single library together with other library
335facilities not covered by this License, and distribute such a combined
336library, provided that the separate distribution of the work based on
337the Library and of the other library facilities is otherwise
338permitted, and provided that you do these two things:
339
340 a) Accompany the combined library with a copy of the same work
341 based on the Library, uncombined with any other library
342 facilities. This must be distributed under the terms of the
343 Sections above.
344
345 b) Give prominent notice with the combined library of the fact
346 that part of it is a work based on the Library, and explaining
347 where to find the accompanying uncombined form of the same work.
348
349 8. You may not copy, modify, sublicense, link with, or distribute
350the Library except as expressly provided under this License. Any
351attempt otherwise to copy, modify, sublicense, link with, or
352distribute the Library is void, and will automatically terminate your
353rights under this License. However, parties who have received copies,
354or rights, from you under this License will not have their licenses
355terminated so long as such parties remain in full compliance.
356
357 9. You are not required to accept this License, since you have not
358signed it. However, nothing else grants you permission to modify or
359distribute the Library or its derivative works. These actions are
360prohibited by law if you do not accept this License. Therefore, by
361modifying or distributing the Library (or any work based on the
362Library), you indicate your acceptance of this License to do so, and
363all its terms and conditions for copying, distributing or modifying
364the Library or works based on it.
365
366 10. Each time you redistribute the Library (or any work based on the
367Library), the recipient automatically receives a license from the
368original licensor to copy, distribute, link with or modify the Library
369subject to these terms and conditions. You may not impose any further
370restrictions on the recipients' exercise of the rights granted herein.
371You are not responsible for enforcing compliance by third parties with
372this License.
373
374 11. If, as a consequence of a court judgment or allegation of patent
375infringement or for any other reason (not limited to patent issues),
376conditions are imposed on you (whether by court order, agreement or
377otherwise) that contradict the conditions of this License, they do not
378excuse you from the conditions of this License. If you cannot
379distribute so as to satisfy simultaneously your obligations under this
380License and any other pertinent obligations, then as a consequence you
381may not distribute the Library at all. For example, if a patent
382license would not permit royalty-free redistribution of the Library by
383all those who receive copies directly or indirectly through you, then
384the only way you could satisfy both it and this License would be to
385refrain entirely from distribution of the Library.
386
387If any portion of this section is held invalid or unenforceable under any
388particular circumstance, the balance of the section is intended to apply,
389and the section as a whole is intended to apply in other circumstances.
390
391It is not the purpose of this section to induce you to infringe any
392patents or other property right claims or to contest validity of any
393such claims; this section has the sole purpose of protecting the
394integrity of the free software distribution system which is
395implemented by public license practices. Many people have made
396generous contributions to the wide range of software distributed
397through that system in reliance on consistent application of that
398system; it is up to the author/donor to decide if he or she is willing
399to distribute software through any other system and a licensee cannot
400impose that choice.
401
402This section is intended to make thoroughly clear what is believed to
403be a consequence of the rest of this License.
404
405 12. If the distribution and/or use of the Library is restricted in
406certain countries either by patents or by copyrighted interfaces, the
407original copyright holder who places the Library under this License may add
408an explicit geographical distribution limitation excluding those countries,
409so that distribution is permitted only in or among countries not thus
410excluded. In such case, this License incorporates the limitation as if
411written in the body of this License.
412
413 13. The Free Software Foundation may publish revised and/or new
414versions of the Lesser General Public License from time to time.
415Such new versions will be similar in spirit to the present version,
416but may differ in detail to address new problems or concerns.
417
418Each version is given a distinguishing version number. If the Library
419specifies a version number of this License which applies to it and
420"any later version", you have the option of following the terms and
421conditions either of that version or of any later version published by
422the Free Software Foundation. If the Library does not specify a
423license version number, you may choose any version ever published by
424the Free Software Foundation.
425
426 14. If you wish to incorporate parts of the Library into other free
427programs whose distribution conditions are incompatible with these,
428write to the author to ask for permission. For software which is
429copyrighted by the Free Software Foundation, write to the Free
430Software Foundation; we sometimes make exceptions for this. Our
431decision will be guided by the two goals of preserving the free status
432of all derivatives of our free software and of promoting the sharing
433and reuse of software generally.
434
435 NO WARRANTY
436
437 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
447 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456DAMAGES.
457
458 END OF TERMS AND CONDITIONS
459
460 How to Apply These Terms to Your New Libraries
461
462 If you develop a new library, and you want it to be of the greatest
463possible use to the public, we recommend making it free software that
464everyone can redistribute and change. You can do so by permitting
465redistribution under these terms (or, alternatively, under the terms of the
466ordinary General Public License).
467
468 To apply these terms, attach the following notices to the library. It is
469safest to attach them to the start of each source file to most effectively
470convey the exclusion of warranty; and each file should have at least the
471"copyright" line and a pointer to where the full notice is found.
472
473 <one line to give the library's name and a brief idea of what it does.>
474 Copyright (C) <year> <name of author>
475
476 This library is free software; you can redistribute it and/or
477 modify it under the terms of the GNU Lesser General Public
478 License as published by the Free Software Foundation; either
479 version 2.1 of the License, or (at your option) any later version.
480
481 This library is distributed in the hope that it will be useful,
482 but WITHOUT ANY WARRANTY; without even the implied warranty of
483 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484 Lesser General Public License for more details.
485
486 You should have received a copy of the GNU Lesser General Public
487 License along with this library; if not, write to the Free Software
488 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
489
490Also add information on how to contact you by electronic and paper mail.
491
492You should also get your employer (if you work as a programmer) or your
493school, if any, to sign a "copyright disclaimer" for the library, if
494necessary. Here is a sample; alter the names:
495
496 Yoyodyne, Inc., hereby disclaims all copyright interest in the
497 library `Frob' (a library for tweaking knobs) written by James Random Hacker.
498
499 <signature of Ty Coon>, 1 April 1990
500 Ty Coon, President of Vice
501
502That's all there is to it!
diff --git a/daemon/libsensors/access.c b/daemon/libsensors/access.c
new file mode 100644
index 0000000..8e227e2
--- /dev/null
+++ b/daemon/libsensors/access.c
@@ -0,0 +1,561 @@
1/*
2 access.c - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007-2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#include <stdlib.h>
23#include <string.h>
24#include <math.h>
25#include "access.h"
26#include "sensors.h"
27#include "data.h"
28#include "error.h"
29#include "sysfs.h"
30
31/* We watch the recursion depth for variables only, as an easy way to
32 detect cycles. */
33#define DEPTH_MAX 8
34
35static int sensors_eval_expr(const sensors_chip_features *chip_features,
36 const sensors_expr *expr,
37 double val, int depth, double *result);
38
39/* Compare two chips name descriptions, to see whether they could match.
40 Return 0 if it does not match, return 1 if it does match. */
41static int sensors_match_chip(const sensors_chip_name *chip1,
42 const sensors_chip_name *chip2)
43{
44 if ((chip1->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
45 (chip2->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
46 strcmp(chip1->prefix, chip2->prefix))
47 return 0;
48
49 if ((chip1->bus.type != SENSORS_BUS_TYPE_ANY) &&
50 (chip2->bus.type != SENSORS_BUS_TYPE_ANY) &&
51 (chip1->bus.type != chip2->bus.type))
52 return 0;
53
54 if ((chip1->bus.nr != SENSORS_BUS_NR_ANY) &&
55 (chip2->bus.nr != SENSORS_BUS_NR_ANY) &&
56 (chip1->bus.nr != chip2->bus.nr))
57 return 0;
58
59 if ((chip1->addr != chip2->addr) &&
60 (chip1->addr != SENSORS_CHIP_NAME_ADDR_ANY) &&
61 (chip2->addr != SENSORS_CHIP_NAME_ADDR_ANY))
62 return 0;
63
64 return 1;
65}
66
67/* Returns, one by one, a pointer to all sensor_chip structs of the
68 config file which match with the given chip name. Last should be
69 the value returned by the last call, or NULL if this is the first
70 call. Returns NULL if no more matches are found. Do not modify
71 the struct the return value points to!
72 Note that this visits the list of chips from last to first. Usually,
73 you want the match that was latest in the config file. */
74static sensors_chip *
75sensors_for_all_config_chips(const sensors_chip_name *name,
76 const sensors_chip *last)
77{
78 int nr, i;
79 sensors_chip_name_list chips;
80
81 for (nr = last ? last - sensors_config_chips - 1 :
82 sensors_config_chips_count - 1; nr >= 0; nr--) {
83
84 chips = sensors_config_chips[nr].chips;
85 for (i = 0; i < chips.fits_count; i++) {
86 if (sensors_match_chip(&chips.fits[i], name))
87 return sensors_config_chips + nr;
88 }
89 }
90 return NULL;
91}
92
93/* Look up a chip in the intern chip list, and return a pointer to it.
94 Do not modify the struct the return value points to! Returns NULL if
95 not found.*/
96static const sensors_chip_features *
97sensors_lookup_chip(const sensors_chip_name *name)
98{
99 int i;
100
101 for (i = 0; i < sensors_proc_chips_count; i++)
102 if (sensors_match_chip(&sensors_proc_chips[i].chip, name))
103 return &sensors_proc_chips[i];
104
105 return NULL;
106}
107
108/* Look up a subfeature of the given chip, and return a pointer to it.
109 Do not modify the struct the return value points to! Returns NULL if
110 not found.*/
111static const sensors_subfeature *
112sensors_lookup_subfeature_nr(const sensors_chip_features *chip,
113 int subfeat_nr)
114{
115 if (subfeat_nr < 0 ||
116 subfeat_nr >= chip->subfeature_count)
117 return NULL;
118 return chip->subfeature + subfeat_nr;
119}
120
121/* Look up a feature of the given chip, and return a pointer to it.
122 Do not modify the struct the return value points to! Returns NULL if
123 not found.*/
124static const sensors_feature *
125sensors_lookup_feature_nr(const sensors_chip_features *chip, int feat_nr)
126{
127 if (feat_nr < 0 ||
128 feat_nr >= chip->feature_count)
129 return NULL;
130 return chip->feature + feat_nr;
131}
132
133/* Look up a subfeature by name, and return a pointer to it.
134 Do not modify the struct the return value points to! Returns NULL if
135 not found.*/
136static const sensors_subfeature *
137sensors_lookup_subfeature_name(const sensors_chip_features *chip,
138 const char *name)
139{
140 int j;
141
142 for (j = 0; j < chip->subfeature_count; j++)
143 if (!strcmp(chip->subfeature[j].name, name))
144 return chip->subfeature + j;
145 return NULL;
146}
147
148/* Check whether the chip name is an 'absolute' name, which can only match
149 one chip, or whether it has wildcards. Returns 0 if it is absolute, 1
150 if there are wildcards. */
151int sensors_chip_name_has_wildcards(const sensors_chip_name *chip)
152{
153 if ((chip->prefix == SENSORS_CHIP_NAME_PREFIX_ANY) ||
154 (chip->bus.type == SENSORS_BUS_TYPE_ANY) ||
155 (chip->bus.nr == SENSORS_BUS_NR_ANY) ||
156 (chip->addr == SENSORS_CHIP_NAME_ADDR_ANY))
157 return 1;
158 else
159 return 0;
160}
161
162/* Look up the label for a given feature. Note that chip should not
163 contain wildcard values! The returned string is newly allocated (free it
164 yourself). On failure, NULL is returned.
165 If no label exists for this feature, its name is returned itself. */
166char *sensors_get_label(const sensors_chip_name *name,
167 const sensors_feature *feature)
168{
169 char *label;
170 const sensors_chip *chip;
171 char buf[PATH_MAX];
172 FILE *f;
173 int i;
174
175 if (sensors_chip_name_has_wildcards(name))
176 return NULL;
177
178 for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
179 for (i = 0; i < chip->labels_count; i++)
180 if (!strcmp(feature->name, chip->labels[i].name)) {
181 label = chip->labels[i].value;
182 goto sensors_get_label_exit;
183 }
184
185 /* No user specified label, check for a _label sysfs file */
186 snprintf(buf, PATH_MAX, "%s/%s_label", name->path, feature->name);
187
188 if ((f = fopen(buf, "r"))) {
189 i = fread(buf, 1, sizeof(buf), f);
190 fclose(f);
191 if (i > 0) {
192 /* i - 1 to strip the '\n' at the end */
193 buf[i - 1] = 0;
194 label = buf;
195 goto sensors_get_label_exit;
196 }
197 }
198
199 /* No label, return the feature name instead */
200 label = feature->name;
201
202sensors_get_label_exit:
203 label = strdup(label);
204 if (!label)
205 sensors_fatal_error(__func__, "Allocating label text");
206 return label;
207}
208
209/* Looks up whether a feature should be ignored. Returns
210 1 if it should be ignored, 0 if not. */
211static int sensors_get_ignored(const sensors_chip_name *name,
212 const sensors_feature *feature)
213{
214 const sensors_chip *chip;
215 int i;
216
217 for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
218 for (i = 0; i < chip->ignores_count; i++)
219 if (!strcmp(feature->name, chip->ignores[i].name))
220 return 1;
221 return 0;
222}
223
224/* Read the value of a subfeature of a certain chip. Note that chip should not
225 contain wildcard values! This function will return 0 on success, and <0
226 on failure. */
227static int __sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
228 int depth, double *result)
229{
230 const sensors_chip_features *chip_features;
231 const sensors_subfeature *subfeature;
232 const sensors_expr *expr = NULL;
233 double val;
234 int res, i;
235
236 if (depth >= DEPTH_MAX)
237 return -SENSORS_ERR_RECURSION;
238 if (sensors_chip_name_has_wildcards(name))
239 return -SENSORS_ERR_WILDCARDS;
240 if (!(chip_features = sensors_lookup_chip(name)))
241 return -SENSORS_ERR_NO_ENTRY;
242 if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
243 subfeat_nr)))
244 return -SENSORS_ERR_NO_ENTRY;
245 if (!(subfeature->flags & SENSORS_MODE_R))
246 return -SENSORS_ERR_ACCESS_R;
247
248 /* Apply compute statement if it exists */
249 if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
250 const sensors_feature *feature;
251 const sensors_chip *chip;
252
253 feature = sensors_lookup_feature_nr(chip_features,
254 subfeature->mapping);
255
256 chip = NULL;
257 while (!expr &&
258 (chip = sensors_for_all_config_chips(name, chip)))
259 for (i = 0; i < chip->computes_count; i++) {
260 if (!strcmp(feature->name,
261 chip->computes[i].name)) {
262 expr = chip->computes[i].from_proc;
263 break;
264 }
265 }
266 }
267
268 res = sensors_read_sysfs_attr(name, subfeature, &val);
269 if (res)
270 return res;
271 if (!expr)
272 *result = val;
273 else if ((res = sensors_eval_expr(chip_features, expr, val, depth,
274 result)))
275 return res;
276 return 0;
277}
278
279int sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
280 double *result)
281{
282 return __sensors_get_value(name, subfeat_nr, 0, result);
283}
284
285/* Set the value of a subfeature of a certain chip. Note that chip should not
286 contain wildcard values! This function will return 0 on success, and <0
287 on failure. */
288int sensors_set_value(const sensors_chip_name *name, int subfeat_nr,
289 double value)
290{
291 const sensors_chip_features *chip_features;
292 const sensors_subfeature *subfeature;
293 const sensors_expr *expr = NULL;
294 int i, res;
295 double to_write;
296
297 if (sensors_chip_name_has_wildcards(name))
298 return -SENSORS_ERR_WILDCARDS;
299 if (!(chip_features = sensors_lookup_chip(name)))
300 return -SENSORS_ERR_NO_ENTRY;
301 if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
302 subfeat_nr)))
303 return -SENSORS_ERR_NO_ENTRY;
304 if (!(subfeature->flags & SENSORS_MODE_W))
305 return -SENSORS_ERR_ACCESS_W;
306
307 /* Apply compute statement if it exists */
308 if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
309 const sensors_feature *feature;
310 const sensors_chip *chip;
311
312 feature = sensors_lookup_feature_nr(chip_features,
313 subfeature->mapping);
314
315 chip = NULL;
316 while (!expr &&
317 (chip = sensors_for_all_config_chips(name, chip)))
318 for (i = 0; i < chip->computes_count; i++) {
319 if (!strcmp(feature->name,
320 chip->computes[i].name)) {
321 expr = chip->computes[i].to_proc;
322 break;
323 }
324 }
325 }
326
327 to_write = value;
328 if (expr)
329 if ((res = sensors_eval_expr(chip_features, expr,
330 value, 0, &to_write)))
331 return res;
332 return sensors_write_sysfs_attr(name, subfeature, to_write);
333}
334
335const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
336 *match, int *nr)
337{
338 const sensors_chip_name *res;
339
340 while (*nr < sensors_proc_chips_count) {
341 res = &sensors_proc_chips[(*nr)++].chip;
342 if (!match || sensors_match_chip(res, match))
343 return res;
344 }
345 return NULL;
346}
347
348const char *sensors_get_adapter_name(const sensors_bus_id *bus)
349{
350 int i;
351
352 /* bus types with a single instance */
353 switch (bus->type) {
354 case SENSORS_BUS_TYPE_ISA:
355 return "ISA adapter";
356 case SENSORS_BUS_TYPE_PCI:
357 return "PCI adapter";
358 /* SPI should not be here, but for now SPI adapters have no name
359 so we don't have any custom string to return. */
360 case SENSORS_BUS_TYPE_SPI:
361 return "SPI adapter";
362 case SENSORS_BUS_TYPE_VIRTUAL:
363 return "Virtual device";
364 case SENSORS_BUS_TYPE_ACPI:
365 return "ACPI interface";
366 /* HID should probably not be there either, but I don't know if
367 HID buses have a name nor where to find it. */
368 case SENSORS_BUS_TYPE_HID:
369 return "HID adapter";
370 }
371
372 /* bus types with several instances */
373 for (i = 0; i < sensors_proc_bus_count; i++)
374 if (sensors_proc_bus[i].bus.type == bus->type &&
375 sensors_proc_bus[i].bus.nr == bus->nr)
376 return sensors_proc_bus[i].adapter;
377 return NULL;
378}
379
380const sensors_feature *
381sensors_get_features(const sensors_chip_name *name, int *nr)
382{
383 const sensors_chip_features *chip;
384
385 if (!(chip = sensors_lookup_chip(name)))
386 return NULL; /* No such chip */
387
388 while (*nr < chip->feature_count
389 && sensors_get_ignored(name, &chip->feature[*nr]))
390 (*nr)++;
391 if (*nr >= chip->feature_count)
392 return NULL;
393 return &chip->feature[(*nr)++];
394}
395
396const sensors_subfeature *
397sensors_get_all_subfeatures(const sensors_chip_name *name,
398 const sensors_feature *feature, int *nr)
399{
400 const sensors_chip_features *chip;
401 const sensors_subfeature *subfeature;
402
403 if (!(chip = sensors_lookup_chip(name)))
404 return NULL; /* No such chip */
405
406 /* Seek directly to the first subfeature */
407 if (*nr < feature->first_subfeature)
408 *nr = feature->first_subfeature;
409
410 if (*nr >= chip->subfeature_count)
411 return NULL; /* end of list */
412 subfeature = &chip->subfeature[(*nr)++];
413 if (subfeature->mapping == feature->number)
414 return subfeature;
415 return NULL; /* end of subfeature list */
416}
417
418const sensors_subfeature *
419sensors_get_subfeature(const sensors_chip_name *name,
420 const sensors_feature *feature,
421 sensors_subfeature_type type)
422{
423 const sensors_chip_features *chip;
424 int i;
425
426 if (!(chip = sensors_lookup_chip(name)))
427 return NULL; /* No such chip */
428
429 for (i = feature->first_subfeature; i < chip->subfeature_count &&
430 chip->subfeature[i].mapping == feature->number; i++) {
431 if (chip->subfeature[i].type == type)
432 return &chip->subfeature[i];
433 }
434 return NULL; /* No such subfeature */
435}
436
437/* Evaluate an expression */
438int sensors_eval_expr(const sensors_chip_features *chip_features,
439 const sensors_expr *expr,
440 double val, int depth, double *result)
441{
442 double res1, res2;
443 int res;
444 const sensors_subfeature *subfeature;
445
446 if (expr->kind == sensors_kind_val) {
447 *result = expr->data.val;
448 return 0;
449 }
450 if (expr->kind == sensors_kind_source) {
451 *result = val;
452 return 0;
453 }
454 if (expr->kind == sensors_kind_var) {
455 if (!(subfeature = sensors_lookup_subfeature_name(chip_features,
456 expr->data.var)))
457 return -SENSORS_ERR_NO_ENTRY;
458 return __sensors_get_value(&chip_features->chip,
459 subfeature->number, depth + 1,
460 result);
461 }
462 if ((res = sensors_eval_expr(chip_features, expr->data.subexpr.sub1,
463 val, depth, &res1)))
464 return res;
465 if (expr->data.subexpr.sub2 &&
466 (res = sensors_eval_expr(chip_features, expr->data.subexpr.sub2,
467 val, depth, &res2)))
468 return res;
469 switch (expr->data.subexpr.op) {
470 case sensors_add:
471 *result = res1 + res2;
472 return 0;
473 case sensors_sub:
474 *result = res1 - res2;
475 return 0;
476 case sensors_multiply:
477 *result = res1 * res2;
478 return 0;
479 case sensors_divide:
480 if (res2 == 0.0)
481 return -SENSORS_ERR_DIV_ZERO;
482 *result = res1 / res2;
483 return 0;
484 case sensors_negate:
485 *result = -res1;
486 return 0;
487 case sensors_exp:
488 *result = exp(res1);
489 return 0;
490 case sensors_log:
491 if (res1 < 0.0)
492 return -SENSORS_ERR_DIV_ZERO;
493 *result = log(res1);
494 return 0;
495 }
496 return 0;
497}
498
499/* Execute all set statements for this particular chip. The chip may not
500 contain wildcards! This function will return 0 on success, and <0 on
501 failure. */
502static int sensors_do_this_chip_sets(const sensors_chip_name *name)
503{
504 const sensors_chip_features *chip_features;
505 sensors_chip *chip;
506 double value;
507 int i;
508 int err = 0, res;
509 const sensors_subfeature *subfeature;
510
511 chip_features = sensors_lookup_chip(name); /* Can't fail */
512
513 for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
514 for (i = 0; i < chip->sets_count; i++) {
515 subfeature = sensors_lookup_subfeature_name(chip_features,
516 chip->sets[i].name);
517 if (!subfeature) {
518 sensors_parse_error_wfn("Unknown feature name",
519 chip->sets[i].line.filename,
520 chip->sets[i].line.lineno);
521 err = -SENSORS_ERR_NO_ENTRY;
522 continue;
523 }
524
525 res = sensors_eval_expr(chip_features,
526 chip->sets[i].value, 0,
527 0, &value);
528 if (res) {
529 sensors_parse_error_wfn("Error parsing expression",
530 chip->sets[i].line.filename,
531 chip->sets[i].line.lineno);
532 err = res;
533 continue;
534 }
535 if ((res = sensors_set_value(name, subfeature->number,
536 value))) {
537 sensors_parse_error_wfn("Failed to set value",
538 chip->sets[i].line.filename,
539 chip->sets[i].line.lineno);
540 err = res;
541 continue;
542 }
543 }
544 return err;
545}
546
547/* Execute all set statements for this particular chip. The chip may contain
548 wildcards! This function will return 0 on success, and <0 on failure. */
549int sensors_do_chip_sets(const sensors_chip_name *name)
550{
551 int nr, this_res;
552 const sensors_chip_name *found_name;
553 int res = 0;
554
555 for (nr = 0; (found_name = sensors_get_detected_chips(name, &nr));) {
556 this_res = sensors_do_this_chip_sets(found_name);
557 if (this_res)
558 res = this_res;
559 }
560 return res;
561}
diff --git a/daemon/libsensors/access.h b/daemon/libsensors/access.h
new file mode 100644
index 0000000..1d37843
--- /dev/null
+++ b/daemon/libsensors/access.h
@@ -0,0 +1,33 @@
1/*
2 access.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#ifndef LIB_SENSORS_ACCESS_H
23#define LIB_SENSORS_ACCESS_H
24
25#include "sensors.h"
26#include "data.h"
27
28/* Check whether the chip name is an 'absolute' name, which can only match
29 one chip, or whether it has wildcards. Returns 0 if it is absolute, 1
30 if there are wildcards. */
31int sensors_chip_name_has_wildcards(const sensors_chip_name *chip);
32
33#endif /* def LIB_SENSORS_ACCESS_H */
diff --git a/daemon/libsensors/conf-lex.c b/daemon/libsensors/conf-lex.c
new file mode 100644
index 0000000..a54664b
--- /dev/null
+++ b/daemon/libsensors/conf-lex.c
@@ -0,0 +1,2881 @@
1
2#line 3 "<stdout>"
3
4#define YY_INT_ALIGNED short int
5
6/* A lexical scanner generated by flex */
7
8#define yy_create_buffer sensors_yy_create_buffer
9#define yy_delete_buffer sensors_yy_delete_buffer
10#define yy_flex_debug sensors_yy_flex_debug
11#define yy_init_buffer sensors_yy_init_buffer
12#define yy_flush_buffer sensors_yy_flush_buffer
13#define yy_load_buffer_state sensors_yy_load_buffer_state
14#define yy_switch_to_buffer sensors_yy_switch_to_buffer
15#define yyin sensors_yyin
16#define yyleng sensors_yyleng
17#define yylex sensors_yylex
18#define yylineno sensors_yylineno
19#define yyout sensors_yyout
20#define yyrestart sensors_yyrestart
21#define yytext sensors_yytext
22#define yywrap sensors_yywrap
23#define yyalloc sensors_yyalloc
24#define yyrealloc sensors_yyrealloc
25#define yyfree sensors_yyfree
26
27#define FLEX_SCANNER
28#define YY_FLEX_MAJOR_VERSION 2
29#define YY_FLEX_MINOR_VERSION 5
30#define YY_FLEX_SUBMINOR_VERSION 35
31#if YY_FLEX_SUBMINOR_VERSION > 0
32#define FLEX_BETA
33#endif
34
35/* First, we deal with platform-specific or compiler-specific issues. */
36
37/* begin standard C headers. */
38#include <stdio.h>
39#include <string.h>
40#include <errno.h>
41#include <stdlib.h>
42
43/* end standard C headers. */
44
45/* flex integer type definitions */
46
47#ifndef FLEXINT_H
48#define FLEXINT_H
49
50/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
51
52#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
53
54/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
55 * if you want the limit (max/min) macros for int types.
56 */
57#ifndef __STDC_LIMIT_MACROS
58#define __STDC_LIMIT_MACROS 1
59#endif
60
61#include <inttypes.h>
62typedef int8_t flex_int8_t;
63typedef uint8_t flex_uint8_t;
64typedef int16_t flex_int16_t;
65typedef uint16_t flex_uint16_t;
66typedef int32_t flex_int32_t;
67typedef uint32_t flex_uint32_t;
68#else
69typedef signed char flex_int8_t;
70typedef short int flex_int16_t;
71typedef int flex_int32_t;
72typedef unsigned char flex_uint8_t;
73typedef unsigned short int flex_uint16_t;
74typedef unsigned int flex_uint32_t;
75
76/* Limits of integral types. */
77#ifndef INT8_MIN
78#define INT8_MIN (-128)
79#endif
80#ifndef INT16_MIN
81#define INT16_MIN (-32767-1)
82#endif
83#ifndef INT32_MIN
84#define INT32_MIN (-2147483647-1)
85#endif
86#ifndef INT8_MAX
87#define INT8_MAX (127)
88#endif
89#ifndef INT16_MAX
90#define INT16_MAX (32767)
91#endif
92#ifndef INT32_MAX
93#define INT32_MAX (2147483647)
94#endif
95#ifndef UINT8_MAX
96#define UINT8_MAX (255U)
97#endif
98#ifndef UINT16_MAX
99#define UINT16_MAX (65535U)
100#endif
101#ifndef UINT32_MAX
102#define UINT32_MAX (4294967295U)
103#endif
104
105#endif /* ! C99 */
106
107#endif /* ! FLEXINT_H */
108
109#ifdef __cplusplus
110
111/* The "const" storage-class-modifier is valid. */
112#define YY_USE_CONST
113
114#else /* ! __cplusplus */
115
116/* C99 requires __STDC__ to be defined as 1. */
117#if defined (__STDC__)
118
119#define YY_USE_CONST
120
121#endif /* defined (__STDC__) */
122#endif /* ! __cplusplus */
123
124#ifdef YY_USE_CONST
125#define yyconst const
126#else
127#define yyconst
128#endif
129
130/* Returned upon end-of-file. */
131#define YY_NULL 0
132
133/* Promotes a possibly negative, possibly signed char to an unsigned
134 * integer for use as an array index. If the signed char is negative,
135 * we want to instead treat it as an 8-bit unsigned char, hence the
136 * double cast.
137 */
138#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
139
140/* Enter a start condition. This macro really ought to take a parameter,
141 * but we do it the disgusting crufty way forced on us by the ()-less
142 * definition of BEGIN.
143 */
144#define BEGIN (yy_start) = 1 + 2 *
145
146/* Translate the current start state into a value that can be later handed
147 * to BEGIN to return to the state. The YYSTATE alias is for lex
148 * compatibility.
149 */
150#define YY_START (((yy_start) - 1) / 2)
151#define YYSTATE YY_START
152
153/* Action number for EOF rule of a given start state. */
154#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
155
156/* Special action meaning "start processing a new file". */
157#define YY_NEW_FILE sensors_yyrestart(sensors_yyin )
158
159#define YY_END_OF_BUFFER_CHAR 0
160
161/* Size of default input buffer. */
162#ifndef YY_BUF_SIZE
163#ifdef __ia64__
164/* On IA-64, the buffer size is 16k, not 8k.
165 * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
166 * Ditto for the __ia64__ case accordingly.
167 */
168#define YY_BUF_SIZE 32768
169#else
170#define YY_BUF_SIZE 16384
171#endif /* __ia64__ */
172#endif
173
174/* The state buf must be large enough to hold one state per character in the main buffer.
175 */
176#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
177
178#ifndef YY_TYPEDEF_YY_BUFFER_STATE
179#define YY_TYPEDEF_YY_BUFFER_STATE
180typedef struct yy_buffer_state *YY_BUFFER_STATE;
181#endif
182
183extern int sensors_yyleng;
184
185extern FILE *sensors_yyin, *sensors_yyout;
186
187#define EOB_ACT_CONTINUE_SCAN 0
188#define EOB_ACT_END_OF_FILE 1
189#define EOB_ACT_LAST_MATCH 2
190
191 #define YY_LESS_LINENO(n)
192
193/* Return all but the first "n" matched characters back to the input stream. */
194#define yyless(n) \
195 do \
196 { \
197 /* Undo effects of setting up sensors_yytext. */ \
198 int yyless_macro_arg = (n); \
199 YY_LESS_LINENO(yyless_macro_arg);\
200 *yy_cp = (yy_hold_char); \
201 YY_RESTORE_YY_MORE_OFFSET \
202 (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
203 YY_DO_BEFORE_ACTION; /* set up sensors_yytext again */ \
204 } \
205 while ( 0 )
206
207#define unput(c) yyunput( c, (yytext_ptr) )
208
209#ifndef YY_TYPEDEF_YY_SIZE_T
210#define YY_TYPEDEF_YY_SIZE_T
211typedef size_t yy_size_t;
212#endif
213
214#ifndef YY_STRUCT_YY_BUFFER_STATE
215#define YY_STRUCT_YY_BUFFER_STATE
216struct yy_buffer_state
217 {
218 FILE *yy_input_file;
219
220 char *yy_ch_buf; /* input buffer */
221 char *yy_buf_pos; /* current position in input buffer */
222
223 /* Size of input buffer in bytes, not including room for EOB
224 * characters.
225 */
226 yy_size_t yy_buf_size;
227
228 /* Number of characters read into yy_ch_buf, not including EOB
229 * characters.
230 */
231 int yy_n_chars;
232
233 /* Whether we "own" the buffer - i.e., we know we created it,
234 * and can realloc() it to grow it, and should free() it to
235 * delete it.
236 */
237 int yy_is_our_buffer;
238
239 /* Whether this is an "interactive" input source; if so, and
240 * if we're using stdio for input, then we want to use getc()
241 * instead of fread(), to make sure we stop fetching input after
242 * each newline.
243 */
244 int yy_is_interactive;
245
246 /* Whether we're considered to be at the beginning of a line.
247 * If so, '^' rules will be active on the next match, otherwise
248 * not.
249 */
250 int yy_at_bol;
251
252 int yy_bs_lineno; /**< The line count. */
253 int yy_bs_column; /**< The column count. */
254
255 /* Whether to try to fill the input buffer when we reach the
256 * end of it.
257 */
258 int yy_fill_buffer;
259
260 int yy_buffer_status;
261
262#define YY_BUFFER_NEW 0
263#define YY_BUFFER_NORMAL 1
264 /* When an EOF's been seen but there's still some text to process
265 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
266 * shouldn't try reading from the input source any more. We might
267 * still have a bunch of tokens to match, though, because of
268 * possible backing-up.
269 *
270 * When we actually see the EOF, we change the status to "new"
271 * (via sensors_yyrestart()), so that the user can continue scanning by
272 * just pointing sensors_yyin at a new input file.
273 */
274#define YY_BUFFER_EOF_PENDING 2
275
276 };
277#endif /* !YY_STRUCT_YY_BUFFER_STATE */
278
279/* Stack of input buffers. */
280static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
281static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
282static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
283
284/* We provide macros for accessing buffer states in case in the
285 * future we want to put the buffer states in a more general
286 * "scanner state".
287 *
288 * Returns the top of the stack, or NULL.
289 */
290#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
291 ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
292 : NULL)
293
294/* Same as previous macro, but useful when we know that the buffer stack is not
295 * NULL or when we need an lvalue. For internal use only.
296 */
297#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
298
299/* yy_hold_char holds the character lost when sensors_yytext is formed. */
300static char yy_hold_char;
301static int yy_n_chars; /* number of characters read into yy_ch_buf */
302int sensors_yyleng;
303
304/* Points to current character in buffer. */
305static char *yy_c_buf_p = (char *) 0;
306static int yy_init = 0; /* whether we need to initialize */
307static int yy_start = 0; /* start state number */
308
309/* Flag which is used to allow sensors_yywrap()'s to do buffer switches
310 * instead of setting up a fresh sensors_yyin. A bit of a hack ...
311 */
312static int yy_did_buffer_switch_on_eof;
313
314void sensors_yyrestart (FILE *input_file );
315void sensors_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
316YY_BUFFER_STATE sensors_yy_create_buffer (FILE *file,int size );
317void sensors_yy_delete_buffer (YY_BUFFER_STATE b );
318void sensors_yy_flush_buffer (YY_BUFFER_STATE b );
319void sensors_yypush_buffer_state (YY_BUFFER_STATE new_buffer );
320void sensors_yypop_buffer_state (void );
321
322static void sensors_yyensure_buffer_stack (void );
323static void sensors_yy_load_buffer_state (void );
324static void sensors_yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
325
326#define YY_FLUSH_BUFFER sensors_yy_flush_buffer(YY_CURRENT_BUFFER )
327
328YY_BUFFER_STATE sensors_yy_scan_buffer (char *base,yy_size_t size );
329YY_BUFFER_STATE sensors_yy_scan_string (yyconst char *yy_str );
330YY_BUFFER_STATE sensors_yy_scan_bytes (yyconst char *bytes,int len );
331
332void *sensors_yyalloc (yy_size_t );
333void *sensors_yyrealloc (void *,yy_size_t );
334void sensors_yyfree (void * );
335
336#define yy_new_buffer sensors_yy_create_buffer
337
338#define yy_set_interactive(is_interactive) \
339 { \
340 if ( ! YY_CURRENT_BUFFER ){ \
341 sensors_yyensure_buffer_stack (); \
342 YY_CURRENT_BUFFER_LVALUE = \
343 sensors_yy_create_buffer(sensors_yyin,YY_BUF_SIZE ); \
344 } \
345 YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
346 }
347
348#define yy_set_bol(at_bol) \
349 { \
350 if ( ! YY_CURRENT_BUFFER ){\
351 sensors_yyensure_buffer_stack (); \
352 YY_CURRENT_BUFFER_LVALUE = \
353 sensors_yy_create_buffer(sensors_yyin,YY_BUF_SIZE ); \
354 } \
355 YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
356 }
357
358#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
359
360/* Begin user sect3 */
361
362#define sensors_yywrap(n) 1
363#define YY_SKIP_YYWRAP
364
365typedef unsigned char YY_CHAR;
366
367FILE *sensors_yyin = (FILE *) 0, *sensors_yyout = (FILE *) 0;
368
369typedef int yy_state_type;
370
371extern int sensors_yylineno;
372
373int sensors_yylineno = 1;
374
375extern char *sensors_yytext;
376#define yytext_ptr sensors_yytext
377static yyconst flex_int16_t yy_nxt[][39] =
378 {
379 {
380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383 0, 0, 0, 0, 0, 0, 0, 0, 0
384 },
385
386 {
387 9, 10, 11, 12, 10, 13, 10, 10, 10, 10,
388 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
389 14, 15, 16, 14, 14, 14, 14, 14, 17, 18,
390 14, 14, 14, 14, 14, 19, 14, 14, 14
391 },
392
393 {
394 9, 10, 11, 12, 10, 13, 10, 10, 10, 10,
395 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
396
397 14, 15, 16, 14, 14, 14, 14, 14, 17, 18,
398 14, 14, 14, 14, 14, 19, 14, 14, 14
399 },
400
401 {
402 9, 20, 21, 22, 23, 24, 25, 26, 27, 28,
403 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
404 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
405 35, 35, 35, 35, 35, 35, 35, 35, 35
406 },
407
408 {
409 9, 20, 21, 22, 23, 24, 25, 26, 27, 28,
410 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
411 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
412 35, 35, 35, 35, 35, 35, 35, 35, 35
413
414 },
415
416 {
417 9, 39, 39, 40, 41, 39, 39, 39, 39, 39,
418 39, 39, 39, 39, 39, 39, 39, 42, 39, 39,
419 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
420 39, 39, 39, 39, 39, 39, 39, 39, 39
421 },
422
423 {
424 9, 39, 39, 40, 41, 39, 39, 39, 39, 39,
425 39, 39, 39, 39, 39, 39, 39, 42, 39, 39,
426 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
427 39, 39, 39, 39, 39, 39, 39, 39, 39
428 },
429
430 {
431 9, 43, 43, 44, 43, 43, 43, 43, 43, 43,
432 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
433
434 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
435 43, 43, 43, 43, 43, 43, 43, 43, 43
436 },
437
438 {
439 9, 43, 43, 44, 43, 43, 43, 43, 43, 43,
440 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
441 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
442 43, 43, 43, 43, 43, 43, 43, 43, 43
443 },
444
445 {
446 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
447 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
448 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
449 -9, -9, -9, -9, -9, -9, -9, -9, -9
450
451 },
452
453 {
454 9, -10, -10, -10, -10, -10, -10, -10, -10, -10,
455 -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
456 -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
457 -10, -10, -10, -10, -10, -10, -10, -10, -10
458 },
459
460 {
461 9, -11, 45, 46, -11, -11, -11, -11, -11, -11,
462 -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
463 -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
464 -11, -11, -11, -11, -11, -11, -11, -11, -11
465 },
466
467 {
468 9, -12, -12, -12, -12, -12, -12, -12, -12, -12,
469 -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
470
471 -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
472 -12, -12, -12, -12, -12, -12, -12, -12, -12
473 },
474
475 {
476 9, 47, 47, 48, 47, 47, 47, 47, 47, 47,
477 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
478 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
479 47, 47, 47, 47, 47, 47, 47, 47, 47
480 },
481
482 {
483 9, -14, -14, -14, -14, -14, -14, -14, -14, -14,
484 -14, -14, -14, -14, -14, -14, -14, -14, -14, -14,
485 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
486 49, 49, 49, 49, 49, 49, 49, 49, 49
487
488 },
489
490 {
491 9, -15, -15, -15, -15, -15, -15, -15, -15, -15,
492 -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
493 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
494 49, 49, 49, 49, 49, 49, 49, 50, 49
495 },
496
497 {
498 9, -16, -16, -16, -16, -16, -16, -16, -16, -16,
499 -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
500 49, 49, 49, 49, 49, 49, 49, 51, 49, 49,
501 49, 49, 52, 49, 49, 49, 49, 49, 49
502 },
503
504 {
505 9, -17, -17, -17, -17, -17, -17, -17, -17, -17,
506 -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
507
508 49, 49, 49, 49, 49, 49, 53, 49, 49, 49,
509 49, 49, 49, 49, 49, 49, 49, 49, 49
510 },
511
512 {
513 9, -18, -18, -18, -18, -18, -18, -18, -18, -18,
514 -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
515 54, 49, 49, 49, 49, 49, 49, 49, 49, 49,
516 49, 49, 49, 49, 49, 49, 49, 49, 49
517 },
518
519 {
520 9, -19, -19, -19, -19, -19, -19, -19, -19, -19,
521 -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
522 49, 49, 49, 49, 55, 49, 49, 49, 49, 49,
523 49, 49, 49, 49, 49, 49, 49, 49, 49
524
525 },
526
527 {
528 9, -20, -20, -20, -20, -20, -20, -20, -20, -20,
529 -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
530 -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
531 -20, -20, -20, -20, -20, -20, -20, -20, -20
532 },
533
534 {
535 9, -21, 56, -21, -21, -21, -21, -21, -21, -21,
536 -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
537 -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
538 -21, -21, -21, -21, -21, -21, -21, -21, -21
539 },
540
541 {
542 9, -22, -22, -22, -22, -22, -22, -22, -22, -22,
543 -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
544
545 -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
546 -22, -22, -22, -22, -22, -22, -22, -22, -22
547 },
548
549 {
550 9, -23, -23, -23, -23, -23, -23, -23, -23, -23,
551 -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
552 -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
553 -23, -23, -23, -23, -23, -23, -23, -23, -23
554 },
555
556 {
557 9, 57, 57, 58, 57, 57, 57, 57, 57, 57,
558 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
559 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
560 57, 57, 57, 57, 57, 57, 57, 57, 57
561
562 },
563
564 {
565 9, -25, -25, -25, -25, -25, -25, -25, -25, -25,
566 -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
567 -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
568 -25, -25, -25, -25, -25, -25, -25, -25, -25
569 },
570
571 {
572 9, -26, -26, -26, -26, -26, -26, -26, -26, -26,
573 -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
574 -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
575 -26, -26, -26, -26, -26, -26, -26, -26, -26
576 },
577
578 {
579 9, -27, -27, -27, -27, -27, -27, -27, -27, -27,
580 -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
581
582 -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
583 -27, -27, -27, -27, -27, -27, -27, -27, -27
584 },
585
586 {
587 9, -28, -28, -28, -28, -28, -28, -28, -28, -28,
588 -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
589 -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
590 -28, -28, -28, -28, -28, -28, -28, -28, -28
591 },
592
593 {
594 9, -29, -29, -29, -29, -29, -29, -29, -29, -29,
595 -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
596 -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
597 -29, -29, -29, -29, -29, -29, -29, -29, -29
598
599 },
600
601 {
602 9, -30, -30, -30, -30, -30, -30, -30, -30, -30,
603 -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
604 -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
605 -30, -30, -30, -30, -30, -30, -30, -30, -30
606 },
607
608 {
609 9, -31, -31, -31, -31, -31, -31, -31, -31, -31,
610 -31, -31, -31, -31, 59, -31, -31, -31, -31, -31,
611 -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
612 -31, -31, -31, -31, -31, -31, -31, -31, -31
613 },
614
615 {
616 9, -32, -32, -32, -32, -32, -32, -32, -32, -32,
617 -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
618
619 -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
620 -32, -32, -32, -32, -32, -32, -32, -32, -32
621 },
622
623 {
624 9, -33, -33, -33, -33, -33, -33, -33, -33, -33,
625 -33, -33, 60, -33, 61, -33, 62, -33, -33, -33,
626 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
627 62, 62, 62, 62, 62, 62, 62, 62, 62
628 },
629
630 {
631 9, -34, -34, -34, -34, -34, -34, -34, -34, -34,
632 -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
633 -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
634 -34, -34, -34, -34, -34, -34, -34, -34, -34
635
636 },
637
638 {
639 9, -35, -35, -35, -35, -35, -35, -35, -35, -35,
640 -35, -35, -35, -35, 62, -35, 62, -35, -35, -35,
641 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
642 62, 62, 62, 62, 62, 62, 62, 62, 62
643 },
644
645 {
646 9, -36, 63, 64, -36, -36, -36, -36, -36, -36,
647 -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
648 -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
649 -36, -36, -36, -36, -36, -36, -36, -36, -36
650 },
651
652 {
653 9, -37, -37, -37, -37, -37, -37, -37, -37, -37,
654 -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
655
656 -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
657 -37, -37, -37, -37, -37, -37, -37, -37, -37
658 },
659
660 {
661 9, -38, -38, -38, -38, -38, -38, -38, -38, -38,
662 -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
663 -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
664 -38, -38, -38, -38, -38, -38, -38, -38, -38
665 },
666
667 {
668 9, 65, 65, -39, -39, 65, 65, 65, 65, 65,
669 65, 65, 65, 65, 65, 65, 65, -39, 65, 65,
670 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
671 65, 65, 65, 65, 65, 65, 65, 65, 65
672
673 },
674
675 {
676 9, -40, -40, -40, -40, -40, -40, -40, -40, -40,
677 -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
678 -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
679 -40, -40, -40, -40, -40, -40, -40, -40, -40
680 },
681
682 {
683 9, -41, -41, -41, 66, -41, -41, -41, -41, -41,
684 -41, -41, -41, -41, -41, -41, -41, -41, -41, -41,
685 -41, -41, -41, -41, -41, -41, -41, -41, -41, -41,
686 -41, -41, -41, -41, -41, -41, -41, -41, -41
687 },
688
689 {
690 9, 67, 67, 68, 67, 67, 67, 67, 67, 67,
691 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
692
693 69, 70, 67, 67, 67, 71, 67, 67, 67, 67,
694 67, 72, 67, 67, 73, 67, 74, 67, 75
695 },
696
697 {
698 9, 76, 76, -43, 76, 76, 76, 76, 76, 76,
699 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
700 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
701 76, 76, 76, 76, 76, 76, 76, 76, 76
702 },
703
704 {
705 9, -44, -44, -44, -44, -44, -44, -44, -44, -44,
706 -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
707 -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
708 -44, -44, -44, -44, -44, -44, -44, -44, -44
709
710 },
711
712 {
713 9, -45, 45, 46, -45, -45, -45, -45, -45, -45,
714 -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
715 -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
716 -45, -45, -45, -45, -45, -45, -45, -45, -45
717 },
718
719 {
720 9, -46, -46, -46, -46, -46, -46, -46, -46, -46,
721 -46, -46, -46, -46, -46, -46, -46, -46, -46, -46,
722 -46, -46, -46, -46, -46, -46, -46, -46, -46, -46,
723 -46, -46, -46, -46, -46, -46, -46, -46, -46
724 },
725
726 {
727 9, 47, 47, 48, 47, 47, 47, 47, 47, 47,
728 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
729
730 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
731 47, 47, 47, 47, 47, 47, 47, 47, 47
732 },
733
734 {
735 9, -48, -48, -48, -48, -48, -48, -48, -48, -48,
736 -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
737 -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
738 -48, -48, -48, -48, -48, -48, -48, -48, -48
739 },
740
741 {
742 9, -49, -49, -49, -49, -49, -49, -49, -49, -49,
743 -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
744 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
745 49, 49, 49, 49, 49, 49, 49, 49, 49
746
747 },
748
749 {
750 9, -50, -50, -50, -50, -50, -50, -50, -50, -50,
751 -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
752 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
753 49, 49, 49, 49, 49, 77, 49, 49, 49
754 },
755
756 {
757 9, -51, -51, -51, -51, -51, -51, -51, -51, -51,
758 -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
759 49, 49, 49, 49, 49, 49, 49, 49, 78, 49,
760 49, 49, 49, 49, 49, 49, 49, 49, 49
761 },
762
763 {
764 9, -52, -52, -52, -52, -52, -52, -52, -52, -52,
765 -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
766
767 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
768 79, 49, 49, 49, 49, 49, 49, 49, 49
769 },
770
771 {
772 9, -53, -53, -53, -53, -53, -53, -53, -53, -53,
773 -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
774 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
775 49, 80, 49, 49, 49, 49, 49, 49, 49
776 },
777
778 {
779 9, -54, -54, -54, -54, -54, -54, -54, -54, -54,
780 -54, -54, -54, -54, -54, -54, -54, -54, -54, -54,
781 49, 81, 49, 49, 49, 49, 49, 49, 49, 49,
782 49, 49, 49, 49, 49, 49, 49, 49, 49
783
784 },
785
786 {
787 9, -55, -55, -55, -55, -55, -55, -55, -55, -55,
788 -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
789 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
790 49, 49, 49, 49, 49, 49, 82, 49, 49
791 },
792
793 {
794 9, -56, 56, -56, -56, -56, -56, -56, -56, -56,
795 -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
796 -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
797 -56, -56, -56, -56, -56, -56, -56, -56, -56
798 },
799
800 {
801 9, 57, 57, 58, 57, 57, 57, 57, 57, 57,
802 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
803
804 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
805 57, 57, 57, 57, 57, 57, 57, 57, 57
806 },
807
808 {
809 9, -58, -58, -58, -58, -58, -58, -58, -58, -58,
810 -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
811 -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
812 -58, -58, -58, -58, -58, -58, -58, -58, -58
813 },
814
815 {
816 9, -59, -59, -59, -59, -59, -59, -59, -59, -59,
817 -59, -59, -59, -59, 59, -59, -59, -59, -59, -59,
818 -59, -59, -59, -59, -59, -59, -59, -59, -59, -59,
819 -59, -59, -59, -59, -59, -59, -59, -59, -59
820
821 },
822
823 {
824 9, -60, -60, -60, -60, -60, -60, -60, -60, -60,
825 -60, -60, -60, -60, 59, -60, -60, -60, -60, -60,
826 -60, -60, -60, -60, -60, -60, -60, -60, -60, -60,
827 -60, -60, -60, -60, -60, -60, -60, -60, -60
828 },
829
830 {
831 9, -61, -61, -61, -61, -61, -61, -61, -61, -61,
832 -61, -61, 60, -61, 61, -61, 62, -61, -61, -61,
833 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
834 62, 62, 62, 62, 62, 62, 62, 62, 62
835 },
836
837 {
838 9, -62, -62, -62, -62, -62, -62, -62, -62, -62,
839 -62, -62, -62, -62, 62, -62, 62, -62, -62, -62,
840
841 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
842 62, 62, 62, 62, 62, 62, 62, 62, 62
843 },
844
845 {
846 9, -63, 63, 64, -63, -63, -63, -63, -63, -63,
847 -63, -63, -63, -63, -63, -63, -63, -63, -63, -63,
848 -63, -63, -63, -63, -63, -63, -63, -63, -63, -63,
849 -63, -63, -63, -63, -63, -63, -63, -63, -63
850 },
851
852 {
853 9, -64, -64, -64, -64, -64, -64, -64, -64, -64,
854 -64, -64, -64, -64, -64, -64, -64, -64, -64, -64,
855 -64, -64, -64, -64, -64, -64, -64, -64, -64, -64,
856 -64, -64, -64, -64, -64, -64, -64, -64, -64
857
858 },
859
860 {
861 9, 65, 65, -65, -65, 65, 65, 65, 65, 65,
862 65, 65, 65, 65, 65, 65, 65, -65, 65, 65,
863 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
864 65, 65, 65, 65, 65, 65, 65, 65, 65
865 },
866
867 {
868 9, -66, -66, -66, -66, -66, -66, -66, -66, -66,
869 -66, -66, -66, -66, -66, -66, -66, -66, -66, -66,
870 -66, -66, -66, -66, -66, -66, -66, -66, -66, -66,
871 -66, -66, -66, -66, -66, -66, -66, -66, -66
872 },
873
874 {
875 9, -67, -67, -67, -67, -67, -67, -67, -67, -67,
876 -67, -67, -67, -67, -67, -67, -67, -67, -67, -67,
877
878 -67, -67, -67, -67, -67, -67, -67, -67, -67, -67,
879 -67, -67, -67, -67, -67, -67, -67, -67, -67
880 },
881
882 {
883 9, -68, -68, -68, -68, -68, -68, -68, -68, -68,
884 -68, -68, -68, -68, -68, -68, -68, -68, -68, -68,
885 -68, -68, -68, -68, -68, -68, -68, -68, -68, -68,
886 -68, -68, -68, -68, -68, -68, -68, -68, -68
887 },
888
889 {
890 9, -69, -69, -69, -69, -69, -69, -69, -69, -69,
891 -69, -69, -69, -69, -69, -69, -69, -69, -69, -69,
892 -69, -69, -69, -69, -69, -69, -69, -69, -69, -69,
893 -69, -69, -69, -69, -69, -69, -69, -69, -69
894
895 },
896
897 {
898 9, -70, -70, -70, -70, -70, -70, -70, -70, -70,
899 -70, -70, -70, -70, -70, -70, -70, -70, -70, -70,
900 -70, -70, -70, -70, -70, -70, -70, -70, -70, -70,
901 -70, -70, -70, -70, -70, -70, -70, -70, -70
902 },
903
904 {
905 9, -71, -71, -71, -71, -71, -71, -71, -71, -71,
906 -71, -71, -71, -71, -71, -71, -71, -71, -71, -71,
907 -71, -71, -71, -71, -71, -71, -71, -71, -71, -71,
908 -71, -71, -71, -71, -71, -71, -71, -71, -71
909 },
910
911 {
912 9, -72, -72, -72, -72, -72, -72, -72, -72, -72,
913 -72, -72, -72, -72, -72, -72, -72, -72, -72, -72,
914
915 -72, -72, -72, -72, -72, -72, -72, -72, -72, -72,
916 -72, -72, -72, -72, -72, -72, -72, -72, -72
917 },
918
919 {
920 9, -73, -73, -73, -73, -73, -73, -73, -73, -73,
921 -73, -73, -73, -73, -73, -73, -73, -73, -73, -73,
922 -73, -73, -73, -73, -73, -73, -73, -73, -73, -73,
923 -73, -73, -73, -73, -73, -73, -73, -73, -73
924 },
925
926 {
927 9, -74, -74, -74, -74, -74, -74, -74, -74, -74,
928 -74, -74, -74, -74, -74, -74, -74, -74, -74, -74,
929 -74, -74, -74, -74, -74, -74, -74, -74, -74, -74,
930 -74, -74, -74, -74, -74, -74, -74, -74, -74
931
932 },
933
934 {
935 9, -75, -75, -75, -75, -75, -75, -75, -75, -75,
936 -75, -75, -75, -75, -75, -75, -75, -75, -75, -75,
937 -75, -75, -75, -75, -75, -75, -75, -75, -75, -75,
938 -75, -75, -75, -75, -75, -75, -75, -75, -75
939 },
940
941 {
942 9, 76, 76, -76, 76, 76, 76, 76, 76, 76,
943 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
944 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
945 76, 76, 76, 76, 76, 76, 76, 76, 76
946 },
947
948 {
949 9, -77, 83, -77, -77, -77, -77, -77, -77, -77,
950 -77, -77, -77, -77, -77, -77, -77, -77, -77, -77,
951
952 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
953 49, 49, 49, 49, 49, 49, 49, 49, 49
954 },
955
956 {
957 9, -78, -78, -78, -78, -78, -78, -78, -78, -78,
958 -78, -78, -78, -78, -78, -78, -78, -78, -78, -78,
959 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
960 49, 49, 49, 84, 49, 49, 49, 49, 49
961 },
962
963 {
964 9, -79, -79, -79, -79, -79, -79, -79, -79, -79,
965 -79, -79, -79, -79, -79, -79, -79, -79, -79, -79,
966 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
967 49, 49, 49, 85, 49, 49, 49, 49, 49
968
969 },
970
971 {
972 9, -80, -80, -80, -80, -80, -80, -80, -80, -80,
973 -80, -80, -80, -80, -80, -80, -80, -80, -80, -80,
974 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
975 49, 49, 86, 49, 49, 49, 49, 49, 49
976 },
977
978 {
979 9, -81, -81, -81, -81, -81, -81, -81, -81, -81,
980 -81, -81, -81, -81, -81, -81, -81, -81, -81, -81,
981 49, 49, 49, 49, 87, 49, 49, 49, 49, 49,
982 49, 49, 49, 49, 49, 49, 49, 49, 49
983 },
984
985 {
986 9, -82, 88, -82, -82, -82, -82, -82, -82, -82,
987 -82, -82, -82, -82, -82, -82, -82, -82, -82, -82,
988
989 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
990 49, 49, 49, 49, 49, 49, 49, 49, 49
991 },
992
993 {
994 9, -83, 83, -83, -83, -83, -83, -83, -83, -83,
995 -83, -83, -83, -83, -83, -83, -83, -83, -83, -83,
996 -83, -83, -83, -83, -83, -83, -83, -83, -83, -83,
997 -83, -83, -83, -83, -83, -83, -83, -83, -83
998 },
999
1000 {
1001 9, -84, 89, -84, -84, -84, -84, -84, -84, -84,
1002 -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
1003 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1004 49, 49, 49, 49, 49, 49, 49, 49, 49
1005
1006 },
1007
1008 {
1009 9, -85, -85, -85, -85, -85, -85, -85, -85, -85,
1010 -85, -85, -85, -85, -85, -85, -85, -85, -85, -85,
1011 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1012 49, 49, 49, 49, 49, 49, 49, 90, 49
1013 },
1014
1015 {
1016 9, -86, -86, -86, -86, -86, -86, -86, -86, -86,
1017 -86, -86, -86, -86, -86, -86, -86, -86, -86, -86,
1018 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1019 49, 49, 49, 49, 91, 49, 49, 49, 49
1020 },
1021
1022 {
1023 9, -87, -87, -87, -87, -87, -87, -87, -87, -87,
1024 -87, -87, -87, -87, -87, -87, -87, -87, -87, -87,
1025
1026 49, 49, 49, 49, 49, 49, 49, 49, 49, 92,
1027 49, 49, 49, 49, 49, 49, 49, 49, 49
1028 },
1029
1030 {
1031 9, -88, 88, -88, -88, -88, -88, -88, -88, -88,
1032 -88, -88, -88, -88, -88, -88, -88, -88, -88, -88,
1033 -88, -88, -88, -88, -88, -88, -88, -88, -88, -88,
1034 -88, -88, -88, -88, -88, -88, -88, -88, -88
1035 },
1036
1037 {
1038 9, -89, 89, -89, -89, -89, -89, -89, -89, -89,
1039 -89, -89, -89, -89, -89, -89, -89, -89, -89, -89,
1040 -89, -89, -89, -89, -89, -89, -89, -89, -89, -89,
1041 -89, -89, -89, -89, -89, -89, -89, -89, -89
1042
1043 },
1044
1045 {
1046 9, -90, -90, -90, -90, -90, -90, -90, -90, -90,
1047 -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
1048 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1049 49, 49, 49, 49, 49, 49, 93, 49, 49
1050 },
1051
1052 {
1053 9, -91, -91, -91, -91, -91, -91, -91, -91, -91,
1054 -91, -91, -91, -91, -91, -91, -91, -91, -91, -91,
1055 49, 49, 49, 49, 94, 49, 49, 49, 49, 49,
1056 49, 49, 49, 49, 49, 49, 49, 49, 49
1057 },
1058
1059 {
1060 9, -92, 95, -92, -92, -92, -92, -92, -92, -92,
1061 -92, -92, -92, -92, -92, -92, -92, -92, -92, -92,
1062
1063 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1064 49, 49, 49, 49, 49, 49, 49, 49, 49
1065 },
1066
1067 {
1068 9, -93, -93, -93, -93, -93, -93, -93, -93, -93,
1069 -93, -93, -93, -93, -93, -93, -93, -93, -93, -93,
1070 49, 49, 49, 49, 96, 49, 49, 49, 49, 49,
1071 49, 49, 49, 49, 49, 49, 49, 49, 49
1072 },
1073
1074 {
1075 9, -94, 97, -94, -94, -94, -94, -94, -94, -94,
1076 -94, -94, -94, -94, -94, -94, -94, -94, -94, -94,
1077 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1078 49, 49, 49, 49, 49, 49, 49, 49, 49
1079
1080 },
1081
1082 {
1083 9, -95, 95, -95, -95, -95, -95, -95, -95, -95,
1084 -95, -95, -95, -95, -95, -95, -95, -95, -95, -95,
1085 -95, -95, -95, -95, -95, -95, -95, -95, -95, -95,
1086 -95, -95, -95, -95, -95, -95, -95, -95, -95
1087 },
1088
1089 {
1090 9, -96, 98, -96, -96, -96, -96, -96, -96, -96,
1091 -96, -96, -96, -96, -96, -96, -96, -96, -96, -96,
1092 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1093 49, 49, 49, 49, 49, 49, 49, 49, 49
1094 },
1095
1096 {
1097 9, -97, 97, -97, -97, -97, -97, -97, -97, -97,
1098 -97, -97, -97, -97, -97, -97, -97, -97, -97, -97,
1099
1100 -97, -97, -97, -97, -97, -97, -97, -97, -97, -97,
1101 -97, -97, -97, -97, -97, -97, -97, -97, -97
1102 },
1103
1104 {
1105 9, -98, 98, -98, -98, -98, -98, -98, -98, -98,
1106 -98, -98, -98, -98, -98, -98, -98, -98, -98, -98,
1107 -98, -98, -98, -98, -98, -98, -98, -98, -98, -98,
1108 -98, -98, -98, -98, -98, -98, -98, -98, -98
1109 },
1110
1111 } ;
1112
1113static yy_state_type yy_get_previous_state (void );
1114static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
1115static int yy_get_next_buffer (void );
1116static void yy_fatal_error (yyconst char msg[] );
1117
1118/* Done after the current pattern has been matched and before the
1119 * corresponding action - sets up sensors_yytext.
1120 */
1121#define YY_DO_BEFORE_ACTION \
1122 (yytext_ptr) = yy_bp; \
1123 sensors_yyleng = (size_t) (yy_cp - yy_bp); \
1124 (yy_hold_char) = *yy_cp; \
1125 *yy_cp = '\0'; \
1126 (yy_c_buf_p) = yy_cp;
1127
1128#define YY_NUM_RULES 50
1129#define YY_END_OF_BUFFER 51
1130/* This struct is not used in this scanner,
1131 but its presence is necessary. */
1132struct yy_trans_info
1133 {
1134 flex_int32_t yy_verify;
1135 flex_int32_t yy_nxt;
1136 };
1137static yyconst flex_int16_t yy_accept[99] =
1138 { 0,
1139 0, 0, 0, 0, 0, 0, 13, 13, 51, 12,
1140 1, 2, 3, 11, 11, 11, 11, 11, 11, 33,
1141 15, 16, 31, 18, 25, 26, 23, 21, 27, 22,
1142 33, 24, 20, 28, 32, 33, 29, 30, 49, 36,
1143 39, 48, 13, 14, 1, 2, 3, 4, 11, 11,
1144 11, 11, 11, 11, 11, 15, 18, 19, 20, 34,
1145 20, 32, 35, 17, 49, 38, 47, 37, 40, 41,
1146 42, 43, 44, 45, 46, 13, 8, 11, 11, 11,
1147 11, 6, 8, 9, 11, 11, 11, 6, 9, 11,
1148 11, 5, 11, 10, 5, 7, 10, 7
1149
1150 } ;
1151
1152static yyconst flex_int32_t yy_ec[256] =
1153 { 0,
1154 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
1155 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
1156 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1157 1, 2, 1, 4, 5, 1, 1, 1, 1, 6,
1158 7, 8, 9, 10, 11, 12, 13, 14, 14, 14,
1159 14, 14, 14, 14, 14, 14, 14, 1, 1, 1,
1160 1, 1, 1, 15, 16, 16, 16, 16, 16, 16,
1161 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
1162 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
1163 1, 17, 1, 18, 16, 19, 20, 21, 22, 23,
1164
1165 24, 25, 26, 27, 28, 23, 23, 29, 30, 31,
1166 32, 33, 23, 34, 35, 36, 37, 38, 23, 23,
1167 23, 23, 1, 1, 1, 1, 1, 1, 1, 1,
1168 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1169 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1170 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1171 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1173 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1174 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1175
1176 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1177 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1178 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1179 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1180 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1181 1, 1, 1, 1, 1
1182 } ;
1183
1184extern int sensors_yy_flex_debug;
1185int sensors_yy_flex_debug = 0;
1186
1187/* The intent behind this definition is that it'll catch
1188 * any uses of REJECT which flex missed.
1189 */
1190#define REJECT reject_used_but_not_detected
1191#define yymore() yymore_used_but_not_detected
1192#define YY_MORE_ADJ 0
1193#define YY_RESTORE_YY_MORE_OFFSET
1194char *sensors_yytext;
1195#line 1 "lib/conf-lex.l"
1196#line 2 "lib/conf-lex.l"
1197/*
1198 conf-lex.l - Part of libsensors, a Linux library for reading sensor data.
1199 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
1200
1201 This library is free software; you can redistribute it and/or
1202 modify it under the terms of the GNU Lesser General Public
1203 License as published by the Free Software Foundation; either
1204 version 2.1 of the License, or (at your option) any later version.
1205
1206 This library is distributed in the hope that it will be useful,
1207 but WITHOUT ANY WARRANTY; without even the implied warranty of
1208 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1209 GNU Lesser General Public License for more details.
1210
1211 You should have received a copy of the GNU General Public License
1212 along with this program; if not, write to the Free Software
1213 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
1214 MA 02110-1301 USA.
1215*/
1216
1217#include <stdlib.h>
1218#include <string.h>
1219
1220#include "general.h"
1221#include "data.h"
1222#include "conf-parse.h"
1223#include "error.h"
1224#include "scanner.h"
1225
1226static int buffer_count;
1227static int buffer_max;
1228static char *buffer;
1229
1230char sensors_lex_error[100];
1231
1232const char *sensors_yyfilename;
1233int sensors_yylineno;
1234
1235#define buffer_malloc() sensors_malloc_array(&buffer,&buffer_count,\
1236 &buffer_max,1)
1237#define buffer_free() sensors_free_array(&buffer,&buffer_count,\
1238 &buffer_max)
1239#define buffer_add_char(c) sensors_add_array_el(c,&buffer,\
1240 &buffer_count,\
1241 &buffer_max,1)
1242#define buffer_add_string(s) sensors_add_array_els(s,strlen(s),\
1243 &buffer, \
1244 &buffer_count,&buffer_max,1)
1245
1246/* Scanner for configuration files */
1247/* All states are exclusive */
1248
1249
1250
1251/* Any whitespace-like character */
1252/* Note: `10', `10.4' and `.4' are valid, `10.' is not */
1253/* Only positive whole numbers are recognized here */
1254#line 1255 "<stdout>"
1255
1256#define INITIAL 0
1257#define MIDDLE 1
1258#define STRING 2
1259#define ERR 3
1260
1261#ifndef YY_NO_UNISTD_H
1262/* Special case for "unistd.h", since it is non-ANSI. We include it way
1263 * down here because we want the user's section 1 to have been scanned first.
1264 * The user has a chance to override it with an option.
1265 */
1266#include <unistd.h>
1267#endif
1268
1269#ifndef YY_EXTRA_TYPE
1270#define YY_EXTRA_TYPE void *
1271#endif
1272
1273static int yy_init_globals (void );
1274
1275/* Accessor methods to globals.
1276 These are made visible to non-reentrant scanners for convenience. */
1277
1278int sensors_yylex_destroy (void );
1279
1280int sensors_yyget_debug (void );
1281
1282void sensors_yyset_debug (int debug_flag );
1283
1284YY_EXTRA_TYPE sensors_yyget_extra (void );
1285
1286void sensors_yyset_extra (YY_EXTRA_TYPE user_defined );
1287
1288FILE *sensors_yyget_in (void );
1289
1290void sensors_yyset_in (FILE * in_str );
1291
1292FILE *sensors_yyget_out (void );
1293
1294void sensors_yyset_out (FILE * out_str );
1295
1296int sensors_yyget_leng (void );
1297
1298char *sensors_yyget_text (void );
1299
1300int sensors_yyget_lineno (void );
1301
1302void sensors_yyset_lineno (int line_number );
1303
1304/* Macros after this point can all be overridden by user definitions in
1305 * section 1.
1306 */
1307
1308#ifndef YY_SKIP_YYWRAP
1309#ifdef __cplusplus
1310extern "C" int sensors_yywrap (void );
1311#else
1312extern int sensors_yywrap (void );
1313#endif
1314#endif
1315
1316#ifndef yytext_ptr
1317static void yy_flex_strncpy (char *,yyconst char *,int );
1318#endif
1319
1320#ifdef YY_NEED_STRLEN
1321static int yy_flex_strlen (yyconst char * );
1322#endif
1323
1324#ifndef YY_NO_INPUT
1325
1326#ifdef __cplusplus
1327static int yyinput (void );
1328#else
1329static int input (void );
1330#endif
1331
1332#endif
1333
1334/* Amount of stuff to slurp up with each read. */
1335#ifndef YY_READ_BUF_SIZE
1336#ifdef __ia64__
1337/* On IA-64, the buffer size is 16k, not 8k */
1338#define YY_READ_BUF_SIZE 16384
1339#else
1340#define YY_READ_BUF_SIZE 8192
1341#endif /* __ia64__ */
1342#endif
1343
1344/* Copy whatever the last rule matched to the standard output. */
1345#ifndef ECHO
1346/* This used to be an fputs(), but since the string might contain NUL's,
1347 * we now use fwrite().
1348 */
1349#define ECHO do { if (fwrite( sensors_yytext, sensors_yyleng, 1, sensors_yyout )) {} } while (0)
1350#endif
1351
1352/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
1353 * is returned in "result".
1354 */
1355#ifndef YY_INPUT
1356#define YY_INPUT(buf,result,max_size) \
1357 if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
1358 { \
1359 int c = '*'; \
1360 size_t n; \
1361 for ( n = 0; n < max_size && \
1362 (c = getc( sensors_yyin )) != EOF && c != '\n'; ++n ) \
1363 buf[n] = (char) c; \
1364 if ( c == '\n' ) \
1365 buf[n++] = (char) c; \
1366 if ( c == EOF && ferror( sensors_yyin ) ) \
1367 YY_FATAL_ERROR( "input in flex scanner failed" ); \
1368 result = n; \
1369 } \
1370 else \
1371 { \
1372 errno=0; \
1373 while ( (result = fread(buf, 1, max_size, sensors_yyin))==0 && ferror(sensors_yyin)) \
1374 { \
1375 if( errno != EINTR) \
1376 { \
1377 YY_FATAL_ERROR( "input in flex scanner failed" ); \
1378 break; \
1379 } \
1380 errno=0; \
1381 clearerr(sensors_yyin); \
1382 } \
1383 }\
1384\
1385
1386#endif
1387
1388/* No semi-colon after return; correct usage is to write "yyterminate();" -
1389 * we don't want an extra ';' after the "return" because that will cause
1390 * some compilers to complain about unreachable statements.
1391 */
1392#ifndef yyterminate
1393#define yyterminate() return YY_NULL
1394#endif
1395
1396/* Number of entries by which start-condition stack grows. */
1397#ifndef YY_START_STACK_INCR
1398#define YY_START_STACK_INCR 25
1399#endif
1400
1401/* Report a fatal error. */
1402#ifndef YY_FATAL_ERROR
1403#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
1404#endif
1405
1406/* end tables serialization structures and prototypes */
1407
1408/* Default declaration of generated scanner - a define so the user can
1409 * easily add parameters.
1410 */
1411#ifndef YY_DECL
1412#define YY_DECL_IS_OURS 1
1413
1414extern int sensors_yylex (void);
1415
1416#define YY_DECL int sensors_yylex (void)
1417#endif /* !YY_DECL */
1418
1419/* Code executed at the beginning of each rule, after sensors_yytext and sensors_yyleng
1420 * have been set up.
1421 */
1422#ifndef YY_USER_ACTION
1423#define YY_USER_ACTION
1424#endif
1425
1426/* Code executed at the end of each rule. */
1427#ifndef YY_BREAK
1428#define YY_BREAK break;
1429#endif
1430
1431#define YY_RULE_SETUP \
1432 YY_USER_ACTION
1433
1434/** The main scanner function which does all the work.
1435 */
1436YY_DECL
1437{
1438 register yy_state_type yy_current_state;
1439 register char *yy_cp, *yy_bp;
1440 register int yy_act;
1441
1442#line 80 "lib/conf-lex.l"
1443
1444
1445 /*
1446 * STATE: INITIAL
1447 */
1448
1449#line 1450 "<stdout>"
1450
1451 if ( !(yy_init) )
1452 {
1453 (yy_init) = 1;
1454
1455#ifdef YY_USER_INIT
1456 YY_USER_INIT;
1457#endif
1458
1459 if ( ! (yy_start) )
1460 (yy_start) = 1; /* first start state */
1461
1462 if ( ! sensors_yyin )
1463 sensors_yyin = stdin;
1464
1465 if ( ! sensors_yyout )
1466 sensors_yyout = stdout;
1467
1468 if ( ! YY_CURRENT_BUFFER ) {
1469 sensors_yyensure_buffer_stack ();
1470 YY_CURRENT_BUFFER_LVALUE =
1471 sensors_yy_create_buffer(sensors_yyin,YY_BUF_SIZE );
1472 }
1473
1474 sensors_yy_load_buffer_state( );
1475 }
1476
1477 while ( 1 ) /* loops until end-of-file is reached */
1478 {
1479 yy_cp = (yy_c_buf_p);
1480
1481 /* Support of sensors_yytext. */
1482 *yy_cp = (yy_hold_char);
1483
1484 /* yy_bp points to the position in yy_ch_buf of the start of
1485 * the current run.
1486 */
1487 yy_bp = yy_cp;
1488
1489 yy_current_state = (yy_start);
1490yy_match:
1491 while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 )
1492 ++yy_cp;
1493
1494 yy_current_state = -yy_current_state;
1495
1496yy_find_action:
1497 yy_act = yy_accept[yy_current_state];
1498
1499 YY_DO_BEFORE_ACTION;
1500
1501do_action: /* This label is used only to access EOF actions. */
1502
1503 switch ( yy_act )
1504 { /* beginning of action switch */
1505
1506case YY_STATE_EOF(INITIAL):
1507#line 88 "lib/conf-lex.l"
1508{ /* EOF from this state terminates */
1509 return 0;
1510 }
1511 YY_BREAK
1512case 1:
1513YY_RULE_SETUP
1514#line 92 "lib/conf-lex.l"
1515; /* eat as many blanks as possible at once */
1516 YY_BREAK
1517case 2:
1518/* rule 2 can match eol */
1519YY_RULE_SETUP
1520#line 94 "lib/conf-lex.l"
1521{ /* eat a bare newline (possibly preceded by blanks) */
1522 sensors_yylineno++;
1523 }
1524 YY_BREAK
1525/* comments */
1526case 3:
1527YY_RULE_SETUP
1528#line 100 "lib/conf-lex.l"
1529; /* eat the rest of the line after comment char */
1530 YY_BREAK
1531case 4:
1532/* rule 4 can match eol */
1533YY_RULE_SETUP
1534#line 102 "lib/conf-lex.l"
1535{ /* eat the rest of the line after comment char */
1536 sensors_yylineno++;
1537 }
1538 YY_BREAK
1539/*
1540 * Keywords must be followed by whitespace - eat that too.
1541 * If there isn't trailing whitespace, we still need to
1542 * accept it as lexically correct (even though the parser
1543 * will reject it anyway.)
1544 */
1545case 5:
1546YY_RULE_SETUP
1547#line 113 "lib/conf-lex.l"
1548{
1549 sensors_yylval.line.filename = sensors_yyfilename;
1550 sensors_yylval.line.lineno = sensors_yylineno;
1551 BEGIN(MIDDLE);
1552 return LABEL;
1553 }
1554 YY_BREAK
1555case 6:
1556YY_RULE_SETUP
1557#line 120 "lib/conf-lex.l"
1558{
1559 sensors_yylval.line.filename = sensors_yyfilename;
1560 sensors_yylval.line.lineno = sensors_yylineno;
1561 BEGIN(MIDDLE);
1562 return SET;
1563 }
1564 YY_BREAK
1565case 7:
1566YY_RULE_SETUP
1567#line 127 "lib/conf-lex.l"
1568{
1569 sensors_yylval.line.filename = sensors_yyfilename;
1570 sensors_yylval.line.lineno = sensors_yylineno;
1571 BEGIN(MIDDLE);
1572 return COMPUTE;
1573 }
1574 YY_BREAK
1575case 8:
1576YY_RULE_SETUP
1577#line 134 "lib/conf-lex.l"
1578{
1579 sensors_yylval.line.filename = sensors_yyfilename;
1580 sensors_yylval.line.lineno = sensors_yylineno;
1581 BEGIN(MIDDLE);
1582 return BUS;
1583 }
1584 YY_BREAK
1585case 9:
1586YY_RULE_SETUP
1587#line 141 "lib/conf-lex.l"
1588{
1589 sensors_yylval.line.filename = sensors_yyfilename;
1590 sensors_yylval.line.lineno = sensors_yylineno;
1591 BEGIN(MIDDLE);
1592 return CHIP;
1593 }
1594 YY_BREAK
1595case 10:
1596YY_RULE_SETUP
1597#line 148 "lib/conf-lex.l"
1598{
1599 sensors_yylval.line.filename = sensors_yyfilename;
1600 sensors_yylval.line.lineno = sensors_yylineno;
1601 BEGIN(MIDDLE);
1602 return IGNORE;
1603 }
1604 YY_BREAK
1605/* Anything else at the beginning of a line is an error */
1606case 11:
1607#line 158 "lib/conf-lex.l"
1608case 12:
1609YY_RULE_SETUP
1610#line 158 "lib/conf-lex.l"
1611{
1612 BEGIN(ERR);
1613 strcpy(sensors_lex_error,"Invalid keyword");
1614 return ERROR;
1615 }
1616 YY_BREAK
1617
1618/*
1619 * STATE: ERROR
1620 */
1621
1622case 13:
1623YY_RULE_SETUP
1624#line 171 "lib/conf-lex.l"
1625; /* eat whatever is left on this line */
1626 YY_BREAK
1627case 14:
1628/* rule 14 can match eol */
1629YY_RULE_SETUP
1630#line 173 "lib/conf-lex.l"
1631{
1632 BEGIN(INITIAL);
1633 sensors_yylineno++;
1634 return EOL;
1635 }
1636 YY_BREAK
1637
1638/*
1639 * STATE: MIDDLE
1640 */
1641
1642case 15:
1643YY_RULE_SETUP
1644#line 186 "lib/conf-lex.l"
1645; /* eat as many blanks as possible at once */
1646 YY_BREAK
1647case 16:
1648/* rule 16 can match eol */
1649YY_RULE_SETUP
1650#line 188 "lib/conf-lex.l"
1651{ /* newline here sends EOL token to parser */
1652 BEGIN(INITIAL);
1653 sensors_yylineno++;
1654 return EOL;
1655 }
1656 YY_BREAK
1657case YY_STATE_EOF(MIDDLE):
1658#line 194 "lib/conf-lex.l"
1659{ /* EOF here sends EOL token to parser also */
1660 BEGIN(INITIAL);
1661 return EOL;
1662 }
1663 YY_BREAK
1664case 17:
1665/* rule 17 can match eol */
1666YY_RULE_SETUP
1667#line 199 "lib/conf-lex.l"
1668{ /* eat an escaped newline with no state change */
1669 sensors_yylineno++;
1670 }
1671 YY_BREAK
1672/* comments */
1673case 18:
1674YY_RULE_SETUP
1675#line 205 "lib/conf-lex.l"
1676; /* eat the rest of the line after comment char */
1677 YY_BREAK
1678case 19:
1679/* rule 19 can match eol */
1680YY_RULE_SETUP
1681#line 207 "lib/conf-lex.l"
1682{ /* eat the rest of the line after comment char */
1683 BEGIN(INITIAL);
1684 sensors_yylineno++;
1685 return EOL;
1686 }
1687 YY_BREAK
1688/* A number */
1689case 20:
1690YY_RULE_SETUP
1691#line 215 "lib/conf-lex.l"
1692{
1693 sensors_yylval.value = atof(sensors_yytext);
1694 return FLOAT;
1695 }
1696 YY_BREAK
1697/* Some operators */
1698case 21:
1699YY_RULE_SETUP
1700#line 222 "lib/conf-lex.l"
1701return '+';
1702 YY_BREAK
1703case 22:
1704YY_RULE_SETUP
1705#line 223 "lib/conf-lex.l"
1706return '-';
1707 YY_BREAK
1708case 23:
1709YY_RULE_SETUP
1710#line 224 "lib/conf-lex.l"
1711return '*';
1712 YY_BREAK
1713case 24:
1714YY_RULE_SETUP
1715#line 225 "lib/conf-lex.l"
1716return '/';
1717 YY_BREAK
1718case 25:
1719YY_RULE_SETUP
1720#line 226 "lib/conf-lex.l"
1721return '(';
1722 YY_BREAK
1723case 26:
1724YY_RULE_SETUP
1725#line 227 "lib/conf-lex.l"
1726return ')';
1727 YY_BREAK
1728case 27:
1729YY_RULE_SETUP
1730#line 228 "lib/conf-lex.l"
1731return ',';
1732 YY_BREAK
1733case 28:
1734YY_RULE_SETUP
1735#line 229 "lib/conf-lex.l"
1736return '@';
1737 YY_BREAK
1738case 29:
1739YY_RULE_SETUP
1740#line 230 "lib/conf-lex.l"
1741return '^';
1742 YY_BREAK
1743case 30:
1744YY_RULE_SETUP
1745#line 231 "lib/conf-lex.l"
1746return '`';
1747 YY_BREAK
1748/* Quoted string */
1749case 31:
1750YY_RULE_SETUP
1751#line 235 "lib/conf-lex.l"
1752{
1753 buffer_malloc();
1754 BEGIN(STRING);
1755 }
1756 YY_BREAK
1757/* A normal, unquoted identifier */
1758case 32:
1759YY_RULE_SETUP
1760#line 242 "lib/conf-lex.l"
1761{
1762 sensors_yylval.name = strdup(sensors_yytext);
1763 if (! sensors_yylval.name)
1764 sensors_fatal_error("conf-lex.l",
1765 "Allocating a new string");
1766
1767 return NAME;
1768 }
1769 YY_BREAK
1770/* anything else is bogus */
1771case 33:
1772#line 254 "lib/conf-lex.l"
1773case 34:
1774#line 255 "lib/conf-lex.l"
1775case 35:
1776YY_RULE_SETUP
1777#line 255 "lib/conf-lex.l"
1778{
1779 BEGIN(ERR);
1780 return ERROR;
1781 }
1782 YY_BREAK
1783
1784/*
1785 * STATE: STRING
1786 */
1787
1788/* Oops, newline or EOF while in a string is not good */
1789case 36:
1790/* rule 36 can match eol */
1791#line 270 "lib/conf-lex.l"
1792case 37:
1793/* rule 37 can match eol */
1794YY_RULE_SETUP
1795#line 270 "lib/conf-lex.l"
1796{
1797 buffer_add_char("\0");
1798 strcpy(sensors_lex_error,
1799 "No matching double quote.");
1800 buffer_free();
1801 yyless(0);
1802 BEGIN(ERR);
1803 return ERROR;
1804 }
1805 YY_BREAK
1806case YY_STATE_EOF(STRING):
1807#line 280 "lib/conf-lex.l"
1808{
1809 strcpy(sensors_lex_error,
1810 "Reached end-of-file without a matching double quote.");
1811 buffer_free();
1812 BEGIN(MIDDLE);
1813 return ERROR;
1814 }
1815 YY_BREAK
1816/* At the end */
1817case 38:
1818YY_RULE_SETUP
1819#line 290 "lib/conf-lex.l"
1820{
1821 buffer_add_char("\0");
1822 strcpy(sensors_lex_error,
1823 "Quoted strings must be separated by whitespace.");
1824 buffer_free();
1825 BEGIN(ERR);
1826 return ERROR;
1827 }
1828 YY_BREAK
1829case 39:
1830YY_RULE_SETUP
1831#line 299 "lib/conf-lex.l"
1832{
1833 buffer_add_char("\0");
1834 sensors_yylval.name = strdup(buffer);
1835 if (! sensors_yylval.name)
1836 sensors_fatal_error("conf-lex.l",
1837 "Allocating a new string");
1838 buffer_free();
1839 BEGIN(MIDDLE);
1840 return NAME;
1841 }
1842 YY_BREAK
1843case 40:
1844YY_RULE_SETUP
1845#line 310 "lib/conf-lex.l"
1846buffer_add_char("\a");
1847 YY_BREAK
1848case 41:
1849YY_RULE_SETUP
1850#line 311 "lib/conf-lex.l"
1851buffer_add_char("\b");
1852 YY_BREAK
1853case 42:
1854YY_RULE_SETUP
1855#line 312 "lib/conf-lex.l"
1856buffer_add_char("\f");
1857 YY_BREAK
1858case 43:
1859YY_RULE_SETUP
1860#line 313 "lib/conf-lex.l"
1861buffer_add_char("\n");
1862 YY_BREAK
1863case 44:
1864YY_RULE_SETUP
1865#line 314 "lib/conf-lex.l"
1866buffer_add_char("\r");
1867 YY_BREAK
1868case 45:
1869YY_RULE_SETUP
1870#line 315 "lib/conf-lex.l"
1871buffer_add_char("\t");
1872 YY_BREAK
1873case 46:
1874YY_RULE_SETUP
1875#line 316 "lib/conf-lex.l"
1876buffer_add_char("\v");
1877 YY_BREAK
1878/* Other escapes: just copy the character behind the slash */
1879case 47:
1880YY_RULE_SETUP
1881#line 320 "lib/conf-lex.l"
1882{
1883 buffer_add_char(&sensors_yytext[1]);
1884 }
1885 YY_BREAK
1886/* Anything else (including a bare '\' which may be followed by EOF) */
1887case 48:
1888#line 327 "lib/conf-lex.l"
1889case 49:
1890YY_RULE_SETUP
1891#line 327 "lib/conf-lex.l"
1892{
1893 buffer_add_string(sensors_yytext);
1894 }
1895 YY_BREAK
1896
1897case 50:
1898YY_RULE_SETUP
1899#line 332 "lib/conf-lex.l"
1900YY_FATAL_ERROR( "flex scanner jammed" );
1901 YY_BREAK
1902#line 1903 "<stdout>"
1903 case YY_STATE_EOF(ERR):
1904 yyterminate();
1905
1906 case YY_END_OF_BUFFER:
1907 {
1908 /* Amount of text matched not including the EOB char. */
1909 int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
1910
1911 /* Undo the effects of YY_DO_BEFORE_ACTION. */
1912 *yy_cp = (yy_hold_char);
1913 YY_RESTORE_YY_MORE_OFFSET
1914
1915 if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
1916 {
1917 /* We're scanning a new file or input source. It's
1918 * possible that this happened because the user
1919 * just pointed sensors_yyin at a new source and called
1920 * sensors_yylex(). If so, then we have to assure
1921 * consistency between YY_CURRENT_BUFFER and our
1922 * globals. Here is the right place to do so, because
1923 * this is the first action (other than possibly a
1924 * back-up) that will match for the new input source.
1925 */
1926 (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
1927 YY_CURRENT_BUFFER_LVALUE->yy_input_file = sensors_yyin;
1928 YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
1929 }
1930
1931 /* Note that here we test for yy_c_buf_p "<=" to the position
1932 * of the first EOB in the buffer, since yy_c_buf_p will
1933 * already have been incremented past the NUL character
1934 * (since all states make transitions on EOB to the
1935 * end-of-buffer state). Contrast this with the test
1936 * in input().
1937 */
1938 if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
1939 { /* This was really a NUL. */
1940 yy_state_type yy_next_state;
1941
1942 (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
1943
1944 yy_current_state = yy_get_previous_state( );
1945
1946 /* Okay, we're now positioned to make the NUL
1947 * transition. We couldn't have
1948 * yy_get_previous_state() go ahead and do it
1949 * for us because it doesn't know how to deal
1950 * with the possibility of jamming (and we don't
1951 * want to build jamming into it because then it
1952 * will run more slowly).
1953 */
1954
1955 yy_next_state = yy_try_NUL_trans( yy_current_state );
1956
1957 yy_bp = (yytext_ptr) + YY_MORE_ADJ;
1958
1959 if ( yy_next_state )
1960 {
1961 /* Consume the NUL. */
1962 yy_cp = ++(yy_c_buf_p);
1963 yy_current_state = yy_next_state;
1964 goto yy_match;
1965 }
1966
1967 else
1968 {
1969 yy_cp = (yy_c_buf_p);
1970 goto yy_find_action;
1971 }
1972 }
1973
1974 else switch ( yy_get_next_buffer( ) )
1975 {
1976 case EOB_ACT_END_OF_FILE:
1977 {
1978 (yy_did_buffer_switch_on_eof) = 0;
1979
1980 if ( sensors_yywrap( ) )
1981 {
1982 /* Note: because we've taken care in
1983 * yy_get_next_buffer() to have set up
1984 * sensors_yytext, we can now set up
1985 * yy_c_buf_p so that if some total
1986 * hoser (like flex itself) wants to
1987 * call the scanner after we return the
1988 * YY_NULL, it'll still work - another
1989 * YY_NULL will get returned.
1990 */
1991 (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
1992
1993 yy_act = YY_STATE_EOF(YY_START);
1994 goto do_action;
1995 }
1996
1997 else
1998 {
1999 if ( ! (yy_did_buffer_switch_on_eof) )
2000 YY_NEW_FILE;
2001 }
2002 break;
2003 }
2004
2005 case EOB_ACT_CONTINUE_SCAN:
2006 (yy_c_buf_p) =
2007 (yytext_ptr) + yy_amount_of_matched_text;
2008
2009 yy_current_state = yy_get_previous_state( );
2010
2011 yy_cp = (yy_c_buf_p);
2012 yy_bp = (yytext_ptr) + YY_MORE_ADJ;
2013 goto yy_match;
2014
2015 case EOB_ACT_LAST_MATCH:
2016 (yy_c_buf_p) =
2017 &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
2018
2019 yy_current_state = yy_get_previous_state( );
2020
2021 yy_cp = (yy_c_buf_p);
2022 yy_bp = (yytext_ptr) + YY_MORE_ADJ;
2023 goto yy_find_action;
2024 }
2025 break;
2026 }
2027
2028 default:
2029 YY_FATAL_ERROR(
2030 "fatal flex scanner internal error--no action found" );
2031 } /* end of action switch */
2032 } /* end of scanning one token */
2033} /* end of sensors_yylex */
2034
2035/* yy_get_next_buffer - try to read in a new buffer
2036 *
2037 * Returns a code representing an action:
2038 * EOB_ACT_LAST_MATCH -
2039 * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
2040 * EOB_ACT_END_OF_FILE - end of file
2041 */
2042static int yy_get_next_buffer (void)
2043{
2044 register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
2045 register char *source = (yytext_ptr);
2046 register int number_to_move, i;
2047 int ret_val;
2048
2049 if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
2050 YY_FATAL_ERROR(
2051 "fatal flex scanner internal error--end of buffer missed" );
2052
2053 if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
2054 { /* Don't try to fill the buffer, so this is an EOF. */
2055 if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
2056 {
2057 /* We matched a single character, the EOB, so
2058 * treat this as a final EOF.
2059 */
2060 return EOB_ACT_END_OF_FILE;
2061 }
2062
2063 else
2064 {
2065 /* We matched some text prior to the EOB, first
2066 * process it.
2067 */
2068 return EOB_ACT_LAST_MATCH;
2069 }
2070 }
2071
2072 /* Try to read more data. */
2073
2074 /* First move last chars to start of buffer. */
2075 number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
2076
2077 for ( i = 0; i < number_to_move; ++i )
2078 *(dest++) = *(source++);
2079
2080 if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
2081 /* don't do the read, it's not guaranteed to return an EOF,
2082 * just force an EOF
2083 */
2084 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
2085
2086 else
2087 {
2088 int num_to_read =
2089 YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
2090
2091 while ( num_to_read <= 0 )
2092 { /* Not enough room in the buffer - grow it. */
2093
2094 /* just a shorter name for the current buffer */
2095 YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
2096
2097 int yy_c_buf_p_offset =
2098 (int) ((yy_c_buf_p) - b->yy_ch_buf);
2099
2100 if ( b->yy_is_our_buffer )
2101 {
2102 int new_size = b->yy_buf_size * 2;
2103
2104 if ( new_size <= 0 )
2105 b->yy_buf_size += b->yy_buf_size / 8;
2106 else
2107 b->yy_buf_size *= 2;
2108
2109 b->yy_ch_buf = (char *)
2110 /* Include room in for 2 EOB chars. */
2111 sensors_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
2112 }
2113 else
2114 /* Can't grow it, we don't own it. */
2115 b->yy_ch_buf = 0;
2116
2117 if ( ! b->yy_ch_buf )
2118 YY_FATAL_ERROR(
2119 "fatal error - scanner input buffer overflow" );
2120
2121 (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
2122
2123 num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
2124 number_to_move - 1;
2125
2126 }
2127
2128 if ( num_to_read > YY_READ_BUF_SIZE )
2129 num_to_read = YY_READ_BUF_SIZE;
2130
2131 /* Read in more data. */
2132 YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
2133 (yy_n_chars), (size_t) num_to_read );
2134
2135 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
2136 }
2137
2138 if ( (yy_n_chars) == 0 )
2139 {
2140 if ( number_to_move == YY_MORE_ADJ )
2141 {
2142 ret_val = EOB_ACT_END_OF_FILE;
2143 sensors_yyrestart(sensors_yyin );
2144 }
2145
2146 else
2147 {
2148 ret_val = EOB_ACT_LAST_MATCH;
2149 YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
2150 YY_BUFFER_EOF_PENDING;
2151 }
2152 }
2153
2154 else
2155 ret_val = EOB_ACT_CONTINUE_SCAN;
2156
2157 if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
2158 /* Extend the array by 50%, plus the number we really need. */
2159 yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
2160 YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) sensors_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
2161 if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
2162 YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
2163 }
2164
2165 (yy_n_chars) += number_to_move;
2166 YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
2167 YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
2168
2169 (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
2170
2171 return ret_val;
2172}
2173
2174/* yy_get_previous_state - get the state just before the EOB char was reached */
2175
2176 static yy_state_type yy_get_previous_state (void)
2177{
2178 register yy_state_type yy_current_state;
2179 register char *yy_cp;
2180
2181 yy_current_state = (yy_start);
2182
2183 for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
2184 {
2185 yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
2186 }
2187
2188 return yy_current_state;
2189}
2190
2191/* yy_try_NUL_trans - try to make a transition on the NUL character
2192 *
2193 * synopsis
2194 * next_state = yy_try_NUL_trans( current_state );
2195 */
2196 static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
2197{
2198 register int yy_is_jam;
2199
2200 yy_current_state = yy_nxt[yy_current_state][1];
2201 yy_is_jam = (yy_current_state <= 0);
2202
2203 return yy_is_jam ? 0 : yy_current_state;
2204}
2205
2206#ifndef YY_NO_INPUT
2207#ifdef __cplusplus
2208 static int yyinput (void)
2209#else
2210 static int input (void)
2211#endif
2212
2213{
2214 int c;
2215
2216 *(yy_c_buf_p) = (yy_hold_char);
2217
2218 if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
2219 {
2220 /* yy_c_buf_p now points to the character we want to return.
2221 * If this occurs *before* the EOB characters, then it's a
2222 * valid NUL; if not, then we've hit the end of the buffer.
2223 */
2224 if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
2225 /* This was really a NUL. */
2226 *(yy_c_buf_p) = '\0';
2227
2228 else
2229 { /* need more input */
2230 int offset = (yy_c_buf_p) - (yytext_ptr);
2231 ++(yy_c_buf_p);
2232
2233 switch ( yy_get_next_buffer( ) )
2234 {
2235 case EOB_ACT_LAST_MATCH:
2236 /* This happens because yy_g_n_b()
2237 * sees that we've accumulated a
2238 * token and flags that we need to
2239 * try matching the token before
2240 * proceeding. But for input(),
2241 * there's no matching to consider.
2242 * So convert the EOB_ACT_LAST_MATCH
2243 * to EOB_ACT_END_OF_FILE.
2244 */
2245
2246 /* Reset buffer status. */
2247 sensors_yyrestart(sensors_yyin );
2248
2249 /*FALLTHROUGH*/
2250
2251 case EOB_ACT_END_OF_FILE:
2252 {
2253 if ( sensors_yywrap( ) )
2254 return EOF;
2255
2256 if ( ! (yy_did_buffer_switch_on_eof) )
2257 YY_NEW_FILE;
2258#ifdef __cplusplus
2259 return yyinput();
2260#else
2261 return input();
2262#endif
2263 }
2264
2265 case EOB_ACT_CONTINUE_SCAN:
2266 (yy_c_buf_p) = (yytext_ptr) + offset;
2267 break;
2268 }
2269 }
2270 }
2271
2272 c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
2273 *(yy_c_buf_p) = '\0'; /* preserve sensors_yytext */
2274 (yy_hold_char) = *++(yy_c_buf_p);
2275
2276 return c;
2277}
2278#endif /* ifndef YY_NO_INPUT */
2279
2280/** Immediately switch to a different input stream.
2281 * @param input_file A readable stream.
2282 *
2283 * @note This function does not reset the start condition to @c INITIAL .
2284 */
2285 void sensors_yyrestart (FILE * input_file )
2286{
2287
2288 if ( ! YY_CURRENT_BUFFER ){
2289 sensors_yyensure_buffer_stack ();
2290 YY_CURRENT_BUFFER_LVALUE =
2291 sensors_yy_create_buffer(sensors_yyin,YY_BUF_SIZE );
2292 }
2293
2294 sensors_yy_init_buffer(YY_CURRENT_BUFFER,input_file );
2295 sensors_yy_load_buffer_state( );
2296}
2297
2298/** Switch to a different input buffer.
2299 * @param new_buffer The new input buffer.
2300 *
2301 */
2302 void sensors_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
2303{
2304
2305 /* TODO. We should be able to replace this entire function body
2306 * with
2307 * sensors_yypop_buffer_state();
2308 * sensors_yypush_buffer_state(new_buffer);
2309 */
2310 sensors_yyensure_buffer_stack ();
2311 if ( YY_CURRENT_BUFFER == new_buffer )
2312 return;
2313
2314 if ( YY_CURRENT_BUFFER )
2315 {
2316 /* Flush out information for old buffer. */
2317 *(yy_c_buf_p) = (yy_hold_char);
2318 YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
2319 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
2320 }
2321
2322 YY_CURRENT_BUFFER_LVALUE = new_buffer;
2323 sensors_yy_load_buffer_state( );
2324
2325 /* We don't actually know whether we did this switch during
2326 * EOF (sensors_yywrap()) processing, but the only time this flag
2327 * is looked at is after sensors_yywrap() is called, so it's safe
2328 * to go ahead and always set it.
2329 */
2330 (yy_did_buffer_switch_on_eof) = 1;
2331}
2332
2333static void sensors_yy_load_buffer_state (void)
2334{
2335 (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
2336 (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
2337 sensors_yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
2338 (yy_hold_char) = *(yy_c_buf_p);
2339}
2340
2341/** Allocate and initialize an input buffer state.
2342 * @param file A readable stream.
2343 * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
2344 *
2345 * @return the allocated buffer state.
2346 */
2347 YY_BUFFER_STATE sensors_yy_create_buffer (FILE * file, int size )
2348{
2349 YY_BUFFER_STATE b;
2350
2351 b = (YY_BUFFER_STATE) sensors_yyalloc(sizeof( struct yy_buffer_state ) );
2352 if ( ! b )
2353 YY_FATAL_ERROR( "out of dynamic memory in sensors_yy_create_buffer()" );
2354
2355 b->yy_buf_size = size;
2356
2357 /* yy_ch_buf has to be 2 characters longer than the size given because
2358 * we need to put in 2 end-of-buffer characters.
2359 */
2360 b->yy_ch_buf = (char *) sensors_yyalloc(b->yy_buf_size + 2 );
2361 if ( ! b->yy_ch_buf )
2362 YY_FATAL_ERROR( "out of dynamic memory in sensors_yy_create_buffer()" );
2363
2364 b->yy_is_our_buffer = 1;
2365
2366 sensors_yy_init_buffer(b,file );
2367
2368 return b;
2369}
2370
2371/** Destroy the buffer.
2372 * @param b a buffer created with sensors_yy_create_buffer()
2373 *
2374 */
2375 void sensors_yy_delete_buffer (YY_BUFFER_STATE b )
2376{
2377
2378 if ( ! b )
2379 return;
2380
2381 if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
2382 YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
2383
2384 if ( b->yy_is_our_buffer )
2385 sensors_yyfree((void *) b->yy_ch_buf );
2386
2387 sensors_yyfree((void *) b );
2388}
2389
2390#ifndef __cplusplus
2391extern int isatty (int );
2392#endif /* __cplusplus */
2393
2394/* Initializes or reinitializes a buffer.
2395 * This function is sometimes called more than once on the same buffer,
2396 * such as during a sensors_yyrestart() or at EOF.
2397 */
2398 static void sensors_yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
2399
2400{
2401 int oerrno = errno;
2402
2403 sensors_yy_flush_buffer(b );
2404
2405 b->yy_input_file = file;
2406 b->yy_fill_buffer = 1;
2407
2408 /* If b is the current buffer, then sensors_yy_init_buffer was _probably_
2409 * called from sensors_yyrestart() or through yy_get_next_buffer.
2410 * In that case, we don't want to reset the lineno or column.
2411 */
2412 if (b != YY_CURRENT_BUFFER){
2413 b->yy_bs_lineno = 1;
2414 b->yy_bs_column = 0;
2415 }
2416
2417 b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
2418
2419 errno = oerrno;
2420}
2421
2422/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
2423 * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
2424 *
2425 */
2426 void sensors_yy_flush_buffer (YY_BUFFER_STATE b )
2427{
2428 if ( ! b )
2429 return;
2430
2431 b->yy_n_chars = 0;
2432
2433 /* We always need two end-of-buffer characters. The first causes
2434 * a transition to the end-of-buffer state. The second causes
2435 * a jam in that state.
2436 */
2437 b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
2438 b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
2439
2440 b->yy_buf_pos = &b->yy_ch_buf[0];
2441
2442 b->yy_at_bol = 1;
2443 b->yy_buffer_status = YY_BUFFER_NEW;
2444
2445 if ( b == YY_CURRENT_BUFFER )
2446 sensors_yy_load_buffer_state( );
2447}
2448
2449/** Pushes the new state onto the stack. The new state becomes
2450 * the current state. This function will allocate the stack
2451 * if necessary.
2452 * @param new_buffer The new state.
2453 *
2454 */
2455void sensors_yypush_buffer_state (YY_BUFFER_STATE new_buffer )
2456{
2457 if (new_buffer == NULL)
2458 return;
2459
2460 sensors_yyensure_buffer_stack();
2461
2462 /* This block is copied from sensors_yy_switch_to_buffer. */
2463 if ( YY_CURRENT_BUFFER )
2464 {
2465 /* Flush out information for old buffer. */
2466 *(yy_c_buf_p) = (yy_hold_char);
2467 YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
2468 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
2469 }
2470
2471 /* Only push if top exists. Otherwise, replace top. */
2472 if (YY_CURRENT_BUFFER)
2473 (yy_buffer_stack_top)++;
2474 YY_CURRENT_BUFFER_LVALUE = new_buffer;
2475
2476 /* copied from sensors_yy_switch_to_buffer. */
2477 sensors_yy_load_buffer_state( );
2478 (yy_did_buffer_switch_on_eof) = 1;
2479}
2480
2481/** Removes and deletes the top of the stack, if present.
2482 * The next element becomes the new top.
2483 *
2484 */
2485void sensors_yypop_buffer_state (void)
2486{
2487 if (!YY_CURRENT_BUFFER)
2488 return;
2489
2490 sensors_yy_delete_buffer(YY_CURRENT_BUFFER );
2491 YY_CURRENT_BUFFER_LVALUE = NULL;
2492 if ((yy_buffer_stack_top) > 0)
2493 --(yy_buffer_stack_top);
2494
2495 if (YY_CURRENT_BUFFER) {
2496 sensors_yy_load_buffer_state( );
2497 (yy_did_buffer_switch_on_eof) = 1;
2498 }
2499}
2500
2501/* Allocates the stack if it does not exist.
2502 * Guarantees space for at least one push.
2503 */
2504static void sensors_yyensure_buffer_stack (void)
2505{
2506 int num_to_alloc;
2507
2508 if (!(yy_buffer_stack)) {
2509
2510 /* First allocation is just for 2 elements, since we don't know if this
2511 * scanner will even need a stack. We use 2 instead of 1 to avoid an
2512 * immediate realloc on the next call.
2513 */
2514 num_to_alloc = 1;
2515 (yy_buffer_stack) = (struct yy_buffer_state**)sensors_yyalloc
2516 (num_to_alloc * sizeof(struct yy_buffer_state*)
2517 );
2518 if ( ! (yy_buffer_stack) )
2519 YY_FATAL_ERROR( "out of dynamic memory in sensors_yyensure_buffer_stack()" );
2520
2521 memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
2522
2523 (yy_buffer_stack_max) = num_to_alloc;
2524 (yy_buffer_stack_top) = 0;
2525 return;
2526 }
2527
2528 if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
2529
2530 /* Increase the buffer to prepare for a possible push. */
2531 int grow_size = 8 /* arbitrary grow size */;
2532
2533 num_to_alloc = (yy_buffer_stack_max) + grow_size;
2534 (yy_buffer_stack) = (struct yy_buffer_state**)sensors_yyrealloc
2535 ((yy_buffer_stack),
2536 num_to_alloc * sizeof(struct yy_buffer_state*)
2537 );
2538 if ( ! (yy_buffer_stack) )
2539 YY_FATAL_ERROR( "out of dynamic memory in sensors_yyensure_buffer_stack()" );
2540
2541 /* zero only the new slots.*/
2542 memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
2543 (yy_buffer_stack_max) = num_to_alloc;
2544 }
2545}
2546
2547/** Setup the input buffer state to scan directly from a user-specified character buffer.
2548 * @param base the character buffer
2549 * @param size the size in bytes of the character buffer
2550 *
2551 * @return the newly allocated buffer state object.
2552 */
2553YY_BUFFER_STATE sensors_yy_scan_buffer (char * base, yy_size_t size )
2554{
2555 YY_BUFFER_STATE b;
2556
2557 if ( size < 2 ||
2558 base[size-2] != YY_END_OF_BUFFER_CHAR ||
2559 base[size-1] != YY_END_OF_BUFFER_CHAR )
2560 /* They forgot to leave room for the EOB's. */
2561 return 0;
2562
2563 b = (YY_BUFFER_STATE) sensors_yyalloc(sizeof( struct yy_buffer_state ) );
2564 if ( ! b )
2565 YY_FATAL_ERROR( "out of dynamic memory in sensors_yy_scan_buffer()" );
2566
2567 b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
2568 b->yy_buf_pos = b->yy_ch_buf = base;
2569 b->yy_is_our_buffer = 0;
2570 b->yy_input_file = 0;
2571 b->yy_n_chars = b->yy_buf_size;
2572 b->yy_is_interactive = 0;
2573 b->yy_at_bol = 1;
2574 b->yy_fill_buffer = 0;
2575 b->yy_buffer_status = YY_BUFFER_NEW;
2576
2577 sensors_yy_switch_to_buffer(b );
2578
2579 return b;
2580}
2581
2582/** Setup the input buffer state to scan a string. The next call to sensors_yylex() will
2583 * scan from a @e copy of @a str.
2584 * @param yystr a NUL-terminated string to scan
2585 *
2586 * @return the newly allocated buffer state object.
2587 * @note If you want to scan bytes that may contain NUL values, then use
2588 * sensors_yy_scan_bytes() instead.
2589 */
2590YY_BUFFER_STATE sensors_yy_scan_string (yyconst char * yystr )
2591{
2592
2593 return sensors_yy_scan_bytes(yystr,strlen(yystr) );
2594}
2595
2596/** Setup the input buffer state to scan the given bytes. The next call to sensors_yylex() will
2597 * scan from a @e copy of @a bytes.
2598 * @param yybytes the byte buffer to scan
2599 * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
2600 *
2601 * @return the newly allocated buffer state object.
2602 */
2603YY_BUFFER_STATE sensors_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
2604{
2605 YY_BUFFER_STATE b;
2606 char *buf;
2607 yy_size_t n;
2608 int i;
2609
2610 /* Get memory for full buffer, including space for trailing EOB's. */
2611 n = _yybytes_len + 2;
2612 buf = (char *) sensors_yyalloc(n );
2613 if ( ! buf )
2614 YY_FATAL_ERROR( "out of dynamic memory in sensors_yy_scan_bytes()" );
2615
2616 for ( i = 0; i < _yybytes_len; ++i )
2617 buf[i] = yybytes[i];
2618
2619 buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
2620
2621 b = sensors_yy_scan_buffer(buf,n );
2622 if ( ! b )
2623 YY_FATAL_ERROR( "bad buffer in sensors_yy_scan_bytes()" );
2624
2625 /* It's okay to grow etc. this buffer, and we should throw it
2626 * away when we're done.
2627 */
2628 b->yy_is_our_buffer = 1;
2629
2630 return b;
2631}
2632
2633#ifndef YY_EXIT_FAILURE
2634#define YY_EXIT_FAILURE 2
2635#endif
2636
2637static void yy_fatal_error (yyconst char* msg )
2638{
2639 (void) fprintf( stderr, "%s\n", msg );
2640 exit( YY_EXIT_FAILURE );
2641}
2642
2643/* Redefine yyless() so it works in section 3 code. */
2644
2645#undef yyless
2646#define yyless(n) \
2647 do \
2648 { \
2649 /* Undo effects of setting up sensors_yytext. */ \
2650 int yyless_macro_arg = (n); \
2651 YY_LESS_LINENO(yyless_macro_arg);\
2652 sensors_yytext[sensors_yyleng] = (yy_hold_char); \
2653 (yy_c_buf_p) = sensors_yytext + yyless_macro_arg; \
2654 (yy_hold_char) = *(yy_c_buf_p); \
2655 *(yy_c_buf_p) = '\0'; \
2656 sensors_yyleng = yyless_macro_arg; \
2657 } \
2658 while ( 0 )
2659
2660/* Accessor methods (get/set functions) to struct members. */
2661
2662/** Get the current line number.
2663 *
2664 */
2665int sensors_yyget_lineno (void)
2666{
2667
2668 return sensors_yylineno;
2669}
2670
2671/** Get the input stream.
2672 *
2673 */
2674FILE *sensors_yyget_in (void)
2675{
2676 return sensors_yyin;
2677}
2678
2679/** Get the output stream.
2680 *
2681 */
2682FILE *sensors_yyget_out (void)
2683{
2684 return sensors_yyout;
2685}
2686
2687/** Get the length of the current token.
2688 *
2689 */
2690int sensors_yyget_leng (void)
2691{
2692 return sensors_yyleng;
2693}
2694
2695/** Get the current token.
2696 *
2697 */
2698
2699char *sensors_yyget_text (void)
2700{
2701 return sensors_yytext;
2702}
2703
2704/** Set the current line number.
2705 * @param line_number
2706 *
2707 */
2708void sensors_yyset_lineno (int line_number )
2709{
2710
2711 sensors_yylineno = line_number;
2712}
2713
2714/** Set the input stream. This does not discard the current
2715 * input buffer.
2716 * @param in_str A readable stream.
2717 *
2718 * @see sensors_yy_switch_to_buffer
2719 */
2720void sensors_yyset_in (FILE * in_str )
2721{
2722 sensors_yyin = in_str ;
2723}
2724
2725void sensors_yyset_out (FILE * out_str )
2726{
2727 sensors_yyout = out_str ;
2728}
2729
2730int sensors_yyget_debug (void)
2731{
2732 return sensors_yy_flex_debug;
2733}
2734
2735void sensors_yyset_debug (int bdebug )
2736{
2737 sensors_yy_flex_debug = bdebug ;
2738}
2739
2740static int yy_init_globals (void)
2741{
2742 /* Initialization is the same as for the non-reentrant scanner.
2743 * This function is called from sensors_yylex_destroy(), so don't allocate here.
2744 */
2745
2746 (yy_buffer_stack) = 0;
2747 (yy_buffer_stack_top) = 0;
2748 (yy_buffer_stack_max) = 0;
2749 (yy_c_buf_p) = (char *) 0;
2750 (yy_init) = 0;
2751 (yy_start) = 0;
2752
2753/* Defined in main.c */
2754#ifdef YY_STDINIT
2755 sensors_yyin = stdin;
2756 sensors_yyout = stdout;
2757#else
2758 sensors_yyin = (FILE *) 0;
2759 sensors_yyout = (FILE *) 0;
2760#endif
2761
2762 /* For future reference: Set errno on error, since we are called by
2763 * sensors_yylex_init()
2764 */
2765 return 0;
2766}
2767
2768/* sensors_yylex_destroy is for both reentrant and non-reentrant scanners. */
2769int sensors_yylex_destroy (void)
2770{
2771
2772 /* Pop the buffer stack, destroying each element. */
2773 while(YY_CURRENT_BUFFER){
2774 sensors_yy_delete_buffer(YY_CURRENT_BUFFER );
2775 YY_CURRENT_BUFFER_LVALUE = NULL;
2776 sensors_yypop_buffer_state();
2777 }
2778
2779 /* Destroy the stack itself. */
2780 sensors_yyfree((yy_buffer_stack) );
2781 (yy_buffer_stack) = NULL;
2782
2783 /* Reset the globals. This is important in a non-reentrant scanner so the next time
2784 * sensors_yylex() is called, initialization will occur. */
2785 yy_init_globals( );
2786
2787 return 0;
2788}
2789
2790/*
2791 * Internal utility routines.
2792 */
2793
2794#ifndef yytext_ptr
2795static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
2796{
2797 register int i;
2798 for ( i = 0; i < n; ++i )
2799 s1[i] = s2[i];
2800}
2801#endif
2802
2803#ifdef YY_NEED_STRLEN
2804static int yy_flex_strlen (yyconst char * s )
2805{
2806 register int n;
2807 for ( n = 0; s[n]; ++n )
2808 ;
2809
2810 return n;
2811}
2812#endif
2813
2814void *sensors_yyalloc (yy_size_t size )
2815{
2816 return (void *) malloc( size );
2817}
2818
2819void *sensors_yyrealloc (void * ptr, yy_size_t size )
2820{
2821 /* The cast to (char *) in the following accommodates both
2822 * implementations that use char* generic pointers, and those
2823 * that use void* generic pointers. It works with the latter
2824 * because both ANSI C and C++ allow castless assignment from
2825 * any pointer type to void*, and deal with argument conversions
2826 * as though doing an assignment.
2827 */
2828 return (void *) realloc( (char *) ptr, size );
2829}
2830
2831void sensors_yyfree (void * ptr )
2832{
2833 free( (char *) ptr ); /* see sensors_yyrealloc() for (char *) cast */
2834}
2835
2836#define YYTABLES_NAME "yytables"
2837
2838#line 332 "lib/conf-lex.l"
2839
2840
2841
2842/*
2843 Do the buffer handling manually. This allows us to scan as many
2844 config files as we need to, while cleaning up properly after each
2845 one. The "BEGIN(0)" line ensures that we start in the default state,
2846 even if e.g. the previous config file was syntactically broken.
2847
2848 Returns 0 if successful, !0 otherwise.
2849*/
2850
2851static YY_BUFFER_STATE scan_buf = (YY_BUFFER_STATE)0;
2852
2853int sensors_scanner_init(FILE *input, const char *filename)
2854{
2855 BEGIN(0);
2856 if (!(scan_buf = sensors_yy_create_buffer(input, YY_BUF_SIZE)))
2857 return -1;
2858
2859 sensors_yy_switch_to_buffer(scan_buf);
2860 sensors_yyfilename = filename;
2861 sensors_yylineno = 1;
2862 return 0;
2863}
2864
2865void sensors_scanner_exit(void)
2866{
2867 sensors_yy_delete_buffer(scan_buf);
2868 scan_buf = (YY_BUFFER_STATE)0;
2869
2870/* As of flex 2.5.9, sensors_yylex_destroy() must be called when done with the
2871 scaller, otherwise we'll leak memory. */
2872#if defined(YY_FLEX_MAJOR_VERSION) && defined(YY_FLEX_MINOR_VERSION) && defined(YY_FLEX_SUBMINOR_VERSION)
2873#if YY_FLEX_MAJOR_VERSION > 2 || \
2874 (YY_FLEX_MAJOR_VERSION == 2 && (YY_FLEX_MINOR_VERSION > 5 || \
2875 (YY_FLEX_MINOR_VERSION == 5 && YY_FLEX_SUBMINOR_VERSION >= 9)))
2876 sensors_yylex_destroy();
2877#endif
2878#endif
2879}
2880
2881
diff --git a/daemon/libsensors/conf-lex.l b/daemon/libsensors/conf-lex.l
new file mode 100644
index 0000000..43ddbd8
--- /dev/null
+++ b/daemon/libsensors/conf-lex.l
@@ -0,0 +1,372 @@
1%{
2/*
3 conf-lex.l - Part of libsensors, a Linux library for reading sensor data.
4 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#include <stdlib.h>
23#include <string.h>
24
25#include "general.h"
26#include "data.h"
27#include "conf-parse.h"
28#include "error.h"
29#include "scanner.h"
30
31static int buffer_count;
32static int buffer_max;
33static char *buffer;
34
35char sensors_lex_error[100];
36
37const char *sensors_yyfilename;
38int sensors_yylineno;
39
40#define buffer_malloc() sensors_malloc_array(&buffer,&buffer_count,\
41 &buffer_max,1)
42#define buffer_free() sensors_free_array(&buffer,&buffer_count,\
43 &buffer_max)
44#define buffer_add_char(c) sensors_add_array_el(c,&buffer,\
45 &buffer_count,\
46 &buffer_max,1)
47#define buffer_add_string(s) sensors_add_array_els(s,strlen(s),\
48 &buffer, \
49 &buffer_count,&buffer_max,1)
50
51%}
52
53 /* Scanner for configuration files */
54
55%option nodefault
56%option noyywrap
57%option nounput
58
59 /* All states are exclusive */
60
61%x MIDDLE
62%x STRING
63%x ERR
64
65 /* Any whitespace-like character */
66
67BLANK [ \f\r\t\v]
68
69IDCHAR [[:alnum:]_]
70
71 /* Note: `10', `10.4' and `.4' are valid, `10.' is not */
72
73FLOAT [[:digit:]]*\.?[[:digit:]]+
74
75 /* Only positive whole numbers are recognized here */
76
77NUM 0|([1-9][[:digit:]]*)
78
79
80%%
81
82 /*
83 * STATE: INITIAL
84 */
85
86<INITIAL>{
87
88<<EOF>> { /* EOF from this state terminates */
89 return 0;
90 }
91
92{BLANK}+ ; /* eat as many blanks as possible at once */
93
94{BLANK}*\n { /* eat a bare newline (possibly preceded by blanks) */
95 sensors_yylineno++;
96 }
97
98 /* comments */
99
100#.* ; /* eat the rest of the line after comment char */
101
102#.*\n { /* eat the rest of the line after comment char */
103 sensors_yylineno++;
104 }
105
106 /*
107 * Keywords must be followed by whitespace - eat that too.
108 * If there isn't trailing whitespace, we still need to
109 * accept it as lexically correct (even though the parser
110 * will reject it anyway.)
111 */
112
113label{BLANK}* {
114 sensors_yylval.line.filename = sensors_yyfilename;
115 sensors_yylval.line.lineno = sensors_yylineno;
116 BEGIN(MIDDLE);
117 return LABEL;
118 }
119
120set{BLANK}* {
121 sensors_yylval.line.filename = sensors_yyfilename;
122 sensors_yylval.line.lineno = sensors_yylineno;
123 BEGIN(MIDDLE);
124 return SET;
125 }
126
127compute{BLANK}* {
128 sensors_yylval.line.filename = sensors_yyfilename;
129 sensors_yylval.line.lineno = sensors_yylineno;
130 BEGIN(MIDDLE);
131 return COMPUTE;
132 }
133
134bus{BLANK}* {
135 sensors_yylval.line.filename = sensors_yyfilename;
136 sensors_yylval.line.lineno = sensors_yylineno;
137 BEGIN(MIDDLE);
138 return BUS;
139 }
140
141chip{BLANK}* {
142 sensors_yylval.line.filename = sensors_yyfilename;
143 sensors_yylval.line.lineno = sensors_yylineno;
144 BEGIN(MIDDLE);
145 return CHIP;
146 }
147
148ignore{BLANK}* {
149 sensors_yylval.line.filename = sensors_yyfilename;
150 sensors_yylval.line.lineno = sensors_yylineno;
151 BEGIN(MIDDLE);
152 return IGNORE;
153 }
154
155 /* Anything else at the beginning of a line is an error */
156
157[a-z]+ |
158. {
159 BEGIN(ERR);
160 strcpy(sensors_lex_error,"Invalid keyword");
161 return ERROR;
162 }
163}
164
165 /*
166 * STATE: ERROR
167 */
168
169<ERR>{
170
171.* ; /* eat whatever is left on this line */
172
173\n {
174 BEGIN(INITIAL);
175 sensors_yylineno++;
176 return EOL;
177 }
178}
179
180 /*
181 * STATE: MIDDLE
182 */
183
184<MIDDLE>{
185
186{BLANK}+ ; /* eat as many blanks as possible at once */
187
188\n { /* newline here sends EOL token to parser */
189 BEGIN(INITIAL);
190 sensors_yylineno++;
191 return EOL;
192 }
193
194<<EOF>> { /* EOF here sends EOL token to parser also */
195 BEGIN(INITIAL);
196 return EOL;
197 }
198
199\\{BLANK}*\n { /* eat an escaped newline with no state change */
200 sensors_yylineno++;
201 }
202
203 /* comments */
204
205#.* ; /* eat the rest of the line after comment char */
206
207#.*\n { /* eat the rest of the line after comment char */
208 BEGIN(INITIAL);
209 sensors_yylineno++;
210 return EOL;
211 }
212
213 /* A number */
214
215{FLOAT} {
216 sensors_yylval.value = atof(sensors_yytext);
217 return FLOAT;
218 }
219
220 /* Some operators */
221
222"+" return '+';
223"-" return '-';
224"*" return '*';
225"/" return '/';
226"(" return '(';
227")" return ')';
228"," return ',';
229"@" return '@';
230"^" return '^';
231"`" return '`';
232
233 /* Quoted string */
234
235\" {
236 buffer_malloc();
237 BEGIN(STRING);
238 }
239
240 /* A normal, unquoted identifier */
241
242{IDCHAR}+ {
243 sensors_yylval.name = strdup(sensors_yytext);
244 if (! sensors_yylval.name)
245 sensors_fatal_error("conf-lex.l",
246 "Allocating a new string");
247
248 return NAME;
249 }
250
251 /* anything else is bogus */
252
253. |
254[[:digit:]]*\. |
255\\{BLANK}* {
256 BEGIN(ERR);
257 return ERROR;
258 }
259}
260
261 /*
262 * STATE: STRING
263 */
264
265<STRING>{
266
267 /* Oops, newline or EOF while in a string is not good */
268
269\n |
270\\\n {
271 buffer_add_char("\0");
272 strcpy(sensors_lex_error,
273 "No matching double quote.");
274 buffer_free();
275 yyless(0);
276 BEGIN(ERR);
277 return ERROR;
278 }
279
280<<EOF>> {
281 strcpy(sensors_lex_error,
282 "Reached end-of-file without a matching double quote.");
283 buffer_free();
284 BEGIN(MIDDLE);
285 return ERROR;
286 }
287
288 /* At the end */
289
290\"\" {
291 buffer_add_char("\0");
292 strcpy(sensors_lex_error,
293 "Quoted strings must be separated by whitespace.");
294 buffer_free();
295 BEGIN(ERR);
296 return ERROR;
297 }
298
299\" {
300 buffer_add_char("\0");
301 sensors_yylval.name = strdup(buffer);
302 if (! sensors_yylval.name)
303 sensors_fatal_error("conf-lex.l",
304 "Allocating a new string");
305 buffer_free();
306 BEGIN(MIDDLE);
307 return NAME;
308 }
309
310\\a buffer_add_char("\a");
311\\b buffer_add_char("\b");
312\\f buffer_add_char("\f");
313\\n buffer_add_char("\n");
314\\r buffer_add_char("\r");
315\\t buffer_add_char("\t");
316\\v buffer_add_char("\v");
317
318 /* Other escapes: just copy the character behind the slash */
319
320\\. {
321 buffer_add_char(&sensors_yytext[1]);
322 }
323
324 /* Anything else (including a bare '\' which may be followed by EOF) */
325
326\\ |
327[^\\\n\"]+ {
328 buffer_add_string(sensors_yytext);
329 }
330}
331
332%%
333
334/*
335 Do the buffer handling manually. This allows us to scan as many
336 config files as we need to, while cleaning up properly after each
337 one. The "BEGIN(0)" line ensures that we start in the default state,
338 even if e.g. the previous config file was syntactically broken.
339
340 Returns 0 if successful, !0 otherwise.
341*/
342
343static YY_BUFFER_STATE scan_buf = (YY_BUFFER_STATE)0;
344
345int sensors_scanner_init(FILE *input, const char *filename)
346{
347 BEGIN(0);
348 if (!(scan_buf = sensors_yy_create_buffer(input, YY_BUF_SIZE)))
349 return -1;
350
351 sensors_yy_switch_to_buffer(scan_buf);
352 sensors_yyfilename = filename;
353 sensors_yylineno = 1;
354 return 0;
355}
356
357void sensors_scanner_exit(void)
358{
359 sensors_yy_delete_buffer(scan_buf);
360 scan_buf = (YY_BUFFER_STATE)0;
361
362/* As of flex 2.5.9, yylex_destroy() must be called when done with the
363 scaller, otherwise we'll leak memory. */
364#if defined(YY_FLEX_MAJOR_VERSION) && defined(YY_FLEX_MINOR_VERSION) && defined(YY_FLEX_SUBMINOR_VERSION)
365#if YY_FLEX_MAJOR_VERSION > 2 || \
366 (YY_FLEX_MAJOR_VERSION == 2 && (YY_FLEX_MINOR_VERSION > 5 || \
367 (YY_FLEX_MINOR_VERSION == 5 && YY_FLEX_SUBMINOR_VERSION >= 9)))
368 sensors_yylex_destroy();
369#endif
370#endif
371}
372
diff --git a/daemon/libsensors/conf-parse.c b/daemon/libsensors/conf-parse.c
new file mode 100644
index 0000000..fb77546
--- /dev/null
+++ b/daemon/libsensors/conf-parse.c
@@ -0,0 +1,2042 @@
1/* A Bison parser, made by GNU Bison 2.5. */
2
3/* Bison implementation for Yacc-like parsers in C
4
5 Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20/* As a special exception, you may create a larger work that contains
21 part or all of the Bison parser skeleton and distribute that work
22 under terms of your choice, so long as that work isn't itself a
23 parser generator using the skeleton or a modified version thereof
24 as a parser skeleton. Alternatively, if you modify or redistribute
25 the parser skeleton itself, you may (at your option) remove this
26 special exception, which will cause the skeleton and the resulting
27 Bison output files to be licensed under the GNU General Public
28 License without this special exception.
29
30 This special exception was added by the Free Software Foundation in
31 version 2.2 of Bison. */
32
33/* C LALR(1) parser skeleton written by Richard Stallman, by
34 simplifying the original so-called "semantic" parser. */
35
36/* All symbols defined below should begin with yy or YY, to avoid
37 infringing on user name space. This should be done even for local
38 variables, as they might otherwise be expanded by user macros.
39 There are some unavoidable exceptions within include files to
40 define necessary library symbols; they are noted "INFRINGES ON
41 USER NAME SPACE" below. */
42
43/* Identify Bison output. */
44#define YYBISON 1
45
46/* Bison version. */
47#define YYBISON_VERSION "2.5"
48
49/* Skeleton name. */
50#define YYSKELETON_NAME "yacc.c"
51
52/* Pure parsers. */
53#define YYPURE 0
54
55/* Push parsers. */
56#define YYPUSH 0
57
58/* Pull parsers. */
59#define YYPULL 1
60
61/* Using locations. */
62#define YYLSP_NEEDED 0
63
64/* Substitute the variable and function names. */
65#define yyparse sensors_yyparse
66#define yylex sensors_yylex
67#define yyerror sensors_yyerror
68#define yylval sensors_yylval
69#define yychar sensors_yychar
70#define yydebug sensors_yydebug
71#define yynerrs sensors_yynerrs
72
73
74/* Copy the first part of user declarations. */
75
76/* Line 268 of yacc.c */
77#line 1 "lib/conf-parse.y"
78
79/*
80 conf-parse.y - Part of libsensors, a Linux library for reading sensor data.
81 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
82
83 This library is free software; you can redistribute it and/or
84 modify it under the terms of the GNU Lesser General Public
85 License as published by the Free Software Foundation; either
86 version 2.1 of the License, or (at your option) any later version.
87
88 This library is distributed in the hope that it will be useful,
89 but WITHOUT ANY WARRANTY; without even the implied warranty of
90 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
91 GNU Lesser General Public License for more details.
92
93 You should have received a copy of the GNU General Public License
94 along with this program; if not, write to the Free Software
95 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
96 MA 02110-1301 USA.
97*/
98
99#define YYERROR_VERBOSE
100
101#include <stdio.h>
102#include <string.h>
103#include <stdlib.h>
104
105#include "data.h"
106#include "general.h"
107#include "error.h"
108#include "conf.h"
109#include "access.h"
110#include "init.h"
111
112static void sensors_yyerror(const char *err);
113static sensors_expr *malloc_expr(void);
114
115static sensors_chip *current_chip = NULL;
116
117#define bus_add_el(el) sensors_add_array_el(el,\
118 &sensors_config_busses,\
119 &sensors_config_busses_count,\
120 &sensors_config_busses_max,\
121 sizeof(sensors_bus))
122#define label_add_el(el) sensors_add_array_el(el,\
123 &current_chip->labels,\
124 &current_chip->labels_count,\
125 &current_chip->labels_max,\
126 sizeof(sensors_label));
127#define set_add_el(el) sensors_add_array_el(el,\
128 &current_chip->sets,\
129 &current_chip->sets_count,\
130 &current_chip->sets_max,\
131 sizeof(sensors_set));
132#define compute_add_el(el) sensors_add_array_el(el,\
133 &current_chip->computes,\
134 &current_chip->computes_count,\
135 &current_chip->computes_max,\
136 sizeof(sensors_compute));
137#define ignore_add_el(el) sensors_add_array_el(el,\
138 &current_chip->ignores,\
139 &current_chip->ignores_count,\
140 &current_chip->ignores_max,\
141 sizeof(sensors_ignore));
142#define chip_add_el(el) sensors_add_array_el(el,\
143 &sensors_config_chips,\
144 &sensors_config_chips_count,\
145 &sensors_config_chips_max,\
146 sizeof(sensors_chip));
147
148#define fits_add_el(el,list) sensors_add_array_el(el,\
149 &(list).fits,\
150 &(list).fits_count,\
151 &(list).fits_max, \
152 sizeof(sensors_chip_name));
153
154
155
156/* Line 268 of yacc.c */
157#line 158 "lib/conf-parse.c"
158
159/* Enabling traces. */
160#ifndef YYDEBUG
161# define YYDEBUG 0
162#endif
163
164/* Enabling verbose error messages. */
165#ifdef YYERROR_VERBOSE
166# undef YYERROR_VERBOSE
167# define YYERROR_VERBOSE 1
168#else
169# define YYERROR_VERBOSE 0
170#endif
171
172/* Enabling the token table. */
173#ifndef YYTOKEN_TABLE
174# define YYTOKEN_TABLE 0
175#endif
176
177
178/* Tokens. */
179#ifndef YYTOKENTYPE
180# define YYTOKENTYPE
181 /* Put the tokens into the symbol table, so that GDB and other debuggers
182 know about them. */
183 enum yytokentype {
184 NEG = 258,
185 EOL = 259,
186 BUS = 260,
187 LABEL = 261,
188 SET = 262,
189 CHIP = 263,
190 COMPUTE = 264,
191 IGNORE = 265,
192 FLOAT = 266,
193 NAME = 267,
194 ERROR = 268
195 };
196#endif
197
198
199
200#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
201typedef union YYSTYPE
202{
203
204/* Line 293 of yacc.c */
205#line 79 "lib/conf-parse.y"
206
207 double value;
208 char *name;
209 void *nothing;
210 sensors_chip_name_list chips;
211 sensors_expr *expr;
212 sensors_bus_id bus;
213 sensors_chip_name chip;
214 sensors_config_line line;
215
216
217
218/* Line 293 of yacc.c */
219#line 220 "lib/conf-parse.c"
220} YYSTYPE;
221# define YYSTYPE_IS_TRIVIAL 1
222# define yystype YYSTYPE /* obsolescent; will be withdrawn */
223# define YYSTYPE_IS_DECLARED 1
224#endif
225
226
227/* Copy the second part of user declarations. */
228
229
230/* Line 343 of yacc.c */
231#line 232 "lib/conf-parse.c"
232
233#ifdef short
234# undef short
235#endif
236
237#ifdef YYTYPE_UINT8
238typedef YYTYPE_UINT8 yytype_uint8;
239#else
240typedef unsigned char yytype_uint8;
241#endif
242
243#ifdef YYTYPE_INT8
244typedef YYTYPE_INT8 yytype_int8;
245#elif (defined __STDC__ || defined __C99__FUNC__ \
246 || defined __cplusplus || defined _MSC_VER)
247typedef signed char yytype_int8;
248#else
249typedef short int yytype_int8;
250#endif
251
252#ifdef YYTYPE_UINT16
253typedef YYTYPE_UINT16 yytype_uint16;
254#else
255typedef unsigned short int yytype_uint16;
256#endif
257
258#ifdef YYTYPE_INT16
259typedef YYTYPE_INT16 yytype_int16;
260#else
261typedef short int yytype_int16;
262#endif
263
264#ifndef YYSIZE_T
265# ifdef __SIZE_TYPE__
266# define YYSIZE_T __SIZE_TYPE__
267# elif defined size_t
268# define YYSIZE_T size_t
269# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
270 || defined __cplusplus || defined _MSC_VER)
271# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
272# define YYSIZE_T size_t
273# else
274# define YYSIZE_T unsigned int
275# endif
276#endif
277
278#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
279
280#ifndef YY_
281# if defined YYENABLE_NLS && YYENABLE_NLS
282# if ENABLE_NLS
283# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
284# define YY_(msgid) dgettext ("bison-runtime", msgid)
285# endif
286# endif
287# ifndef YY_
288# define YY_(msgid) msgid
289# endif
290#endif
291
292/* Suppress unused-variable warnings by "using" E. */
293#if ! defined lint || defined __GNUC__
294# define YYUSE(e) ((void) (e))
295#else
296# define YYUSE(e) /* empty */
297#endif
298
299/* Identity function, used to suppress warnings about constant conditions. */
300#ifndef lint
301# define YYID(n) (n)
302#else
303#if (defined __STDC__ || defined __C99__FUNC__ \
304 || defined __cplusplus || defined _MSC_VER)
305static int
306YYID (int yyi)
307#else
308static int
309YYID (yyi)
310 int yyi;
311#endif
312{
313 return yyi;
314}
315#endif
316
317#if ! defined yyoverflow || YYERROR_VERBOSE
318
319/* The parser invokes alloca or malloc; define the necessary symbols. */
320
321# ifdef YYSTACK_USE_ALLOCA
322# if YYSTACK_USE_ALLOCA
323# ifdef __GNUC__
324# define YYSTACK_ALLOC __builtin_alloca
325# elif defined __BUILTIN_VA_ARG_INCR
326# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
327# elif defined _AIX
328# define YYSTACK_ALLOC __alloca
329# elif defined _MSC_VER
330# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
331# define alloca _alloca
332# else
333# define YYSTACK_ALLOC alloca
334# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
335 || defined __cplusplus || defined _MSC_VER)
336# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
337# ifndef EXIT_SUCCESS
338# define EXIT_SUCCESS 0
339# endif
340# endif
341# endif
342# endif
343# endif
344
345# ifdef YYSTACK_ALLOC
346 /* Pacify GCC's `empty if-body' warning. */
347# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
348# ifndef YYSTACK_ALLOC_MAXIMUM
349 /* The OS might guarantee only one guard page at the bottom of the stack,
350 and a page size can be as small as 4096 bytes. So we cannot safely
351 invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
352 to allow for a few compiler-allocated temporary stack slots. */
353# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
354# endif
355# else
356# define YYSTACK_ALLOC YYMALLOC
357# define YYSTACK_FREE YYFREE
358# ifndef YYSTACK_ALLOC_MAXIMUM
359# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
360# endif
361# if (defined __cplusplus && ! defined EXIT_SUCCESS \
362 && ! ((defined YYMALLOC || defined malloc) \
363 && (defined YYFREE || defined free)))
364# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
365# ifndef EXIT_SUCCESS
366# define EXIT_SUCCESS 0
367# endif
368# endif
369# ifndef YYMALLOC
370# define YYMALLOC malloc
371# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
372 || defined __cplusplus || defined _MSC_VER)
373void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
374# endif
375# endif
376# ifndef YYFREE
377# define YYFREE free
378# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
379 || defined __cplusplus || defined _MSC_VER)
380void free (void *); /* INFRINGES ON USER NAME SPACE */
381# endif
382# endif
383# endif
384#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
385
386
387#if (! defined yyoverflow \
388 && (! defined __cplusplus \
389 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
390
391/* A type that is properly aligned for any stack member. */
392union yyalloc
393{
394 yytype_int16 yyss_alloc;
395 YYSTYPE yyvs_alloc;
396};
397
398/* The size of the maximum gap between one aligned stack and the next. */
399# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
400
401/* The size of an array large to enough to hold all stacks, each with
402 N elements. */
403# define YYSTACK_BYTES(N) \
404 ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
405 + YYSTACK_GAP_MAXIMUM)
406
407# define YYCOPY_NEEDED 1
408
409/* Relocate STACK from its old location to the new one. The
410 local variables YYSIZE and YYSTACKSIZE give the old and new number of
411 elements in the stack, and YYPTR gives the new location of the
412 stack. Advance YYPTR to a properly aligned location for the next
413 stack. */
414# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
415 do \
416 { \
417 YYSIZE_T yynewbytes; \
418 YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
419 Stack = &yyptr->Stack_alloc; \
420 yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
421 yyptr += yynewbytes / sizeof (*yyptr); \
422 } \
423 while (YYID (0))
424
425#endif
426
427#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
428/* Copy COUNT objects from FROM to TO. The source and destination do
429 not overlap. */
430# ifndef YYCOPY
431# if defined __GNUC__ && 1 < __GNUC__
432# define YYCOPY(To, From, Count) \
433 __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
434# else
435# define YYCOPY(To, From, Count) \
436 do \
437 { \
438 YYSIZE_T yyi; \
439 for (yyi = 0; yyi < (Count); yyi++) \
440 (To)[yyi] = (From)[yyi]; \
441 } \
442 while (YYID (0))
443# endif
444# endif
445#endif /* !YYCOPY_NEEDED */
446
447/* YYFINAL -- State number of the termination state. */
448#define YYFINAL 2
449/* YYLAST -- Last index in YYTABLE. */
450#define YYLAST 58
451
452/* YYNTOKENS -- Number of terminals. */
453#define YYNTOKENS 24
454/* YYNNTS -- Number of nonterminals. */
455#define YYNNTS 16
456/* YYNRULES -- Number of rules. */
457#define YYNRULES 34
458/* YYNRULES -- Number of states. */
459#define YYNSTATES 63
460
461/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
462#define YYUNDEFTOK 2
463#define YYMAXUTOK 268
464
465#define YYTRANSLATE(YYX) \
466 ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
467
468/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
469static const yytype_uint8 yytranslate[] =
470{
471 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
472 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
473 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
474 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
475 22, 23, 5, 4, 10, 3, 2, 6, 2, 2,
476 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
477 2, 2, 2, 2, 21, 2, 2, 2, 2, 2,
478 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
479 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
480 2, 2, 2, 2, 8, 2, 9, 2, 2, 2,
481 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
482 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
483 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
484 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
485 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
486 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
487 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
488 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
489 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
490 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
491 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
492 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
493 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
494 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
495 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
496 2, 2, 2, 2, 2, 2, 1, 2, 7, 11,
497 12, 13, 14, 15, 16, 17, 18, 19, 20
498};
499
500#if YYDEBUG
501/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
502 YYRHS. */
503static const yytype_uint8 yyprhs[] =
504{
505 0, 0, 3, 4, 7, 10, 13, 16, 19, 22,
506 25, 28, 32, 36, 40, 46, 49, 52, 54, 57,
507 59, 61, 63, 67, 71, 75, 79, 82, 86, 89,
508 92, 94, 96, 98, 100
509};
510
511/* YYRHS -- A `-1'-separated list of the rules' RHS. */
512static const yytype_int8 yyrhs[] =
513{
514 25, 0, -1, -1, 25, 26, -1, 27, 11, -1,
515 28, 11, -1, 29, 11, -1, 32, 11, -1, 30,
516 11, -1, 31, 11, -1, 1, 11, -1, 12, 35,
517 36, -1, 13, 37, 38, -1, 14, 37, 34, -1,
518 16, 37, 34, 10, 34, -1, 17, 37, -1, 15,
519 33, -1, 39, -1, 33, 39, -1, 18, -1, 19,
520 -1, 21, -1, 34, 4, 34, -1, 34, 3, 34,
521 -1, 34, 5, 34, -1, 34, 6, 34, -1, 3,
522 34, -1, 22, 34, 23, -1, 8, 34, -1, 9,
523 34, -1, 19, -1, 19, -1, 19, -1, 19, -1,
524 19, -1
525};
526
527/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
528static const yytype_uint16 yyrline[] =
529{
530 0, 119, 119, 120, 123, 124, 125, 126, 127, 128,
531 129, 132, 141, 156, 171, 188, 201, 219, 225, 231,
532 236, 241, 245, 252, 259, 266, 273, 280, 282, 289,
533 298, 308, 312, 316, 320
534};
535#endif
536
537#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
538/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
539 First, the terminals, then, starting at YYNTOKENS, nonterminals. */
540static const char *const yytname[] =
541{
542 "$end", "error", "$undefined", "'-'", "'+'", "'*'", "'/'", "NEG", "'^'",
543 "'`'", "','", "EOL", "BUS", "LABEL", "SET", "CHIP", "COMPUTE", "IGNORE",
544 "FLOAT", "NAME", "ERROR", "'@'", "'('", "')'", "$accept", "input",
545 "line", "bus_statement", "label_statement", "set_statement",
546 "compute_statement", "ignore_statement", "chip_statement",
547 "chip_name_list", "expression", "bus_id", "adapter_name",
548 "function_name", "string", "chip_name", 0
549};
550#endif
551
552# ifdef YYPRINT
553/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
554 token YYLEX-NUM. */
555static const yytype_uint16 yytoknum[] =
556{
557 0, 256, 257, 45, 43, 42, 47, 258, 94, 96,
558 44, 259, 260, 261, 262, 263, 264, 265, 266, 267,
559 268, 64, 40, 41
560};
561# endif
562
563/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
564static const yytype_uint8 yyr1[] =
565{
566 0, 24, 25, 25, 26, 26, 26, 26, 26, 26,
567 26, 27, 28, 29, 30, 31, 32, 33, 33, 34,
568 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
569 35, 36, 37, 38, 39
570};
571
572/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
573static const yytype_uint8 yyr2[] =
574{
575 0, 2, 0, 2, 2, 2, 2, 2, 2, 2,
576 2, 3, 3, 3, 5, 2, 2, 1, 2, 1,
577 1, 1, 3, 3, 3, 3, 2, 3, 2, 2,
578 1, 1, 1, 1, 1
579};
580
581/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
582 Performed when YYTABLE doesn't specify something else to do. Zero
583 means the default is an error. */
584static const yytype_uint8 yydefact[] =
585{
586 2, 0, 1, 0, 0, 0, 0, 0, 0, 0,
587 3, 0, 0, 0, 0, 0, 0, 10, 30, 0,
588 32, 0, 0, 34, 16, 17, 0, 15, 4, 5,
589 6, 8, 9, 7, 31, 11, 33, 12, 0, 0,
590 0, 19, 20, 21, 0, 13, 18, 0, 26, 28,
591 29, 0, 0, 0, 0, 0, 0, 27, 23, 22,
592 24, 25, 14
593};
594
595/* YYDEFGOTO[NTERM-NUM]. */
596static const yytype_int8 yydefgoto[] =
597{
598 -1, 1, 10, 11, 12, 13, 14, 15, 16, 24,
599 45, 19, 35, 21, 37, 25
600};
601
602/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
603 STATE-NUM. */
604#define YYPACT_NINF -27
605static const yytype_int8 yypact[] =
606{
607 -27, 37, -27, -4, -3, 1, 1, 6, 1, 1,
608 -27, 8, 13, 20, 23, 32, 34, -27, -27, 29,
609 -27, 39, 14, -27, 6, -27, 14, -27, -27, -27,
610 -27, -27, -27, -27, -27, -27, -27, -27, 14, 14,
611 14, -27, -27, -27, 14, 36, -27, 5, -27, -27,
612 -27, -2, 14, 14, 14, 14, 14, -27, 0, 0,
613 -27, -27, 36
614};
615
616/* YYPGOTO[NTERM-NUM]. */
617static const yytype_int8 yypgoto[] =
618{
619 -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
620 -26, -27, -27, 38, -27, 31
621};
622
623/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
624 positive, shift that token. If negative, reduce the rule which
625 number is the opposite. If YYTABLE_NINF, syntax error. */
626#define YYTABLE_NINF -1
627static const yytype_uint8 yytable[] =
628{
629 47, 52, 53, 54, 55, 54, 55, 17, 52, 53,
630 54, 55, 48, 49, 50, 56, 18, 38, 51, 28,
631 20, 57, 39, 40, 29, 23, 58, 59, 60, 61,
632 62, 30, 41, 42, 31, 43, 44, 2, 3, 52,
633 53, 54, 55, 32, 22, 33, 26, 27, 34, 4,
634 5, 6, 7, 8, 9, 46, 0, 0, 36
635};
636
637#define yypact_value_is_default(yystate) \
638 ((yystate) == (-27))
639
640#define yytable_value_is_error(yytable_value) \
641 YYID (0)
642
643static const yytype_int8 yycheck[] =
644{
645 26, 3, 4, 5, 6, 5, 6, 11, 3, 4,
646 5, 6, 38, 39, 40, 10, 19, 3, 44, 11,
647 19, 23, 8, 9, 11, 19, 52, 53, 54, 55,
648 56, 11, 18, 19, 11, 21, 22, 0, 1, 3,
649 4, 5, 6, 11, 6, 11, 8, 9, 19, 12,
650 13, 14, 15, 16, 17, 24, -1, -1, 19
651};
652
653/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
654 symbol of state STATE-NUM. */
655static const yytype_uint8 yystos[] =
656{
657 0, 25, 0, 1, 12, 13, 14, 15, 16, 17,
658 26, 27, 28, 29, 30, 31, 32, 11, 19, 35,
659 19, 37, 37, 19, 33, 39, 37, 37, 11, 11,
660 11, 11, 11, 11, 19, 36, 19, 38, 3, 8,
661 9, 18, 19, 21, 22, 34, 39, 34, 34, 34,
662 34, 34, 3, 4, 5, 6, 10, 23, 34, 34,
663 34, 34, 34
664};
665
666#define yyerrok (yyerrstatus = 0)
667#define yyclearin (yychar = YYEMPTY)
668#define YYEMPTY (-2)
669#define YYEOF 0
670
671#define YYACCEPT goto yyacceptlab
672#define YYABORT goto yyabortlab
673#define YYERROR goto yyerrorlab
674
675
676/* Like YYERROR except do call yyerror. This remains here temporarily
677 to ease the transition to the new meaning of YYERROR, for GCC.
678 Once GCC version 2 has supplanted version 1, this can go. However,
679 YYFAIL appears to be in use. Nevertheless, it is formally deprecated
680 in Bison 2.4.2's NEWS entry, where a plan to phase it out is
681 discussed. */
682
683#define YYFAIL goto yyerrlab
684#if defined YYFAIL
685 /* This is here to suppress warnings from the GCC cpp's
686 -Wunused-macros. Normally we don't worry about that warning, but
687 some users do, and we want to make it easy for users to remove
688 YYFAIL uses, which will produce warnings from Bison 2.5. */
689#endif
690
691#define YYRECOVERING() (!!yyerrstatus)
692
693#define YYBACKUP(Token, Value) \
694do \
695 if (yychar == YYEMPTY && yylen == 1) \
696 { \
697 yychar = (Token); \
698 yylval = (Value); \
699 YYPOPSTACK (1); \
700 goto yybackup; \
701 } \
702 else \
703 { \
704 yyerror (YY_("syntax error: cannot back up")); \
705 YYERROR; \
706 } \
707while (YYID (0))
708
709
710#define YYTERROR 1
711#define YYERRCODE 256
712
713
714/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
715 If N is 0, then set CURRENT to the empty location which ends
716 the previous symbol: RHS[0] (always defined). */
717
718#define YYRHSLOC(Rhs, K) ((Rhs)[K])
719#ifndef YYLLOC_DEFAULT
720# define YYLLOC_DEFAULT(Current, Rhs, N) \
721 do \
722 if (YYID (N)) \
723 { \
724 (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
725 (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
726 (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
727 (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
728 } \
729 else \
730 { \
731 (Current).first_line = (Current).last_line = \
732 YYRHSLOC (Rhs, 0).last_line; \
733 (Current).first_column = (Current).last_column = \
734 YYRHSLOC (Rhs, 0).last_column; \
735 } \
736 while (YYID (0))
737#endif
738
739
740/* This macro is provided for backward compatibility. */
741
742#ifndef YY_LOCATION_PRINT
743# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
744#endif
745
746
747/* YYLEX -- calling `yylex' with the right arguments. */
748
749#ifdef YYLEX_PARAM
750# define YYLEX yylex (YYLEX_PARAM)
751#else
752# define YYLEX yylex ()
753#endif
754
755/* Enable debugging if requested. */
756#if YYDEBUG
757
758# ifndef YYFPRINTF
759# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
760# define YYFPRINTF fprintf
761# endif
762
763# define YYDPRINTF(Args) \
764do { \
765 if (yydebug) \
766 YYFPRINTF Args; \
767} while (YYID (0))
768
769# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
770do { \
771 if (yydebug) \
772 { \
773 YYFPRINTF (stderr, "%s ", Title); \
774 yy_symbol_print (stderr, \
775 Type, Value); \
776 YYFPRINTF (stderr, "\n"); \
777 } \
778} while (YYID (0))
779
780
781/*--------------------------------.
782| Print this symbol on YYOUTPUT. |
783`--------------------------------*/
784
785/*ARGSUSED*/
786#if (defined __STDC__ || defined __C99__FUNC__ \
787 || defined __cplusplus || defined _MSC_VER)
788static void
789yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
790#else
791static void
792yy_symbol_value_print (yyoutput, yytype, yyvaluep)
793 FILE *yyoutput;
794 int yytype;
795 YYSTYPE const * const yyvaluep;
796#endif
797{
798 if (!yyvaluep)
799 return;
800# ifdef YYPRINT
801 if (yytype < YYNTOKENS)
802 YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
803# else
804 YYUSE (yyoutput);
805# endif
806 switch (yytype)
807 {
808 default:
809 break;
810 }
811}
812
813
814/*--------------------------------.
815| Print this symbol on YYOUTPUT. |
816`--------------------------------*/
817
818#if (defined __STDC__ || defined __C99__FUNC__ \
819 || defined __cplusplus || defined _MSC_VER)
820static void
821yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
822#else
823static void
824yy_symbol_print (yyoutput, yytype, yyvaluep)
825 FILE *yyoutput;
826 int yytype;
827 YYSTYPE const * const yyvaluep;
828#endif
829{
830 if (yytype < YYNTOKENS)
831 YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
832 else
833 YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
834
835 yy_symbol_value_print (yyoutput, yytype, yyvaluep);
836 YYFPRINTF (yyoutput, ")");
837}
838
839/*------------------------------------------------------------------.
840| yy_stack_print -- Print the state stack from its BOTTOM up to its |
841| TOP (included). |
842`------------------------------------------------------------------*/
843
844#if (defined __STDC__ || defined __C99__FUNC__ \
845 || defined __cplusplus || defined _MSC_VER)
846static void
847yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
848#else
849static void
850yy_stack_print (yybottom, yytop)
851 yytype_int16 *yybottom;
852 yytype_int16 *yytop;
853#endif
854{
855 YYFPRINTF (stderr, "Stack now");
856 for (; yybottom <= yytop; yybottom++)
857 {
858 int yybot = *yybottom;
859 YYFPRINTF (stderr, " %d", yybot);
860 }
861 YYFPRINTF (stderr, "\n");
862}
863
864# define YY_STACK_PRINT(Bottom, Top) \
865do { \
866 if (yydebug) \
867 yy_stack_print ((Bottom), (Top)); \
868} while (YYID (0))
869
870
871/*------------------------------------------------.
872| Report that the YYRULE is going to be reduced. |
873`------------------------------------------------*/
874
875#if (defined __STDC__ || defined __C99__FUNC__ \
876 || defined __cplusplus || defined _MSC_VER)
877static void
878yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
879#else
880static void
881yy_reduce_print (yyvsp, yyrule)
882 YYSTYPE *yyvsp;
883 int yyrule;
884#endif
885{
886 int yynrhs = yyr2[yyrule];
887 int yyi;
888 unsigned long int yylno = yyrline[yyrule];
889 YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
890 yyrule - 1, yylno);
891 /* The symbols being reduced. */
892 for (yyi = 0; yyi < yynrhs; yyi++)
893 {
894 YYFPRINTF (stderr, " $%d = ", yyi + 1);
895 yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
896 &(yyvsp[(yyi + 1) - (yynrhs)])
897 );
898 YYFPRINTF (stderr, "\n");
899 }
900}
901
902# define YY_REDUCE_PRINT(Rule) \
903do { \
904 if (yydebug) \
905 yy_reduce_print (yyvsp, Rule); \
906} while (YYID (0))
907
908/* Nonzero means print parse trace. It is left uninitialized so that
909 multiple parsers can coexist. */
910int yydebug;
911#else /* !YYDEBUG */
912# define YYDPRINTF(Args)
913# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
914# define YY_STACK_PRINT(Bottom, Top)
915# define YY_REDUCE_PRINT(Rule)
916#endif /* !YYDEBUG */
917
918
919/* YYINITDEPTH -- initial size of the parser's stacks. */
920#ifndef YYINITDEPTH
921# define YYINITDEPTH 200
922#endif
923
924/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
925 if the built-in stack extension method is used).
926
927 Do not make this value too large; the results are undefined if
928 YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
929 evaluated with infinite-precision integer arithmetic. */
930
931#ifndef YYMAXDEPTH
932# define YYMAXDEPTH 10000
933#endif
934
935
936#if YYERROR_VERBOSE
937
938# ifndef yystrlen
939# if defined __GLIBC__ && defined _STRING_H
940# define yystrlen strlen
941# else
942/* Return the length of YYSTR. */
943#if (defined __STDC__ || defined __C99__FUNC__ \
944 || defined __cplusplus || defined _MSC_VER)
945static YYSIZE_T
946yystrlen (const char *yystr)
947#else
948static YYSIZE_T
949yystrlen (yystr)
950 const char *yystr;
951#endif
952{
953 YYSIZE_T yylen;
954 for (yylen = 0; yystr[yylen]; yylen++)
955 continue;
956 return yylen;
957}
958# endif
959# endif
960
961# ifndef yystpcpy
962# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
963# define yystpcpy stpcpy
964# else
965/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
966 YYDEST. */
967#if (defined __STDC__ || defined __C99__FUNC__ \
968 || defined __cplusplus || defined _MSC_VER)
969static char *
970yystpcpy (char *yydest, const char *yysrc)
971#else
972static char *
973yystpcpy (yydest, yysrc)
974 char *yydest;
975 const char *yysrc;
976#endif
977{
978 char *yyd = yydest;
979 const char *yys = yysrc;
980
981 while ((*yyd++ = *yys++) != '\0')
982 continue;
983
984 return yyd - 1;
985}
986# endif
987# endif
988
989# ifndef yytnamerr
990/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
991 quotes and backslashes, so that it's suitable for yyerror. The
992 heuristic is that double-quoting is unnecessary unless the string
993 contains an apostrophe, a comma, or backslash (other than
994 backslash-backslash). YYSTR is taken from yytname. If YYRES is
995 null, do not copy; instead, return the length of what the result
996 would have been. */
997static YYSIZE_T
998yytnamerr (char *yyres, const char *yystr)
999{
1000 if (*yystr == '"')
1001 {
1002 YYSIZE_T yyn = 0;
1003 char const *yyp = yystr;
1004
1005 for (;;)
1006 switch (*++yyp)
1007 {
1008 case '\'':
1009 case ',':
1010 goto do_not_strip_quotes;
1011
1012 case '\\':
1013 if (*++yyp != '\\')
1014 goto do_not_strip_quotes;
1015 /* Fall through. */
1016 default:
1017 if (yyres)
1018 yyres[yyn] = *yyp;
1019 yyn++;
1020 break;
1021
1022 case '"':
1023 if (yyres)
1024 yyres[yyn] = '\0';
1025 return yyn;
1026 }
1027 do_not_strip_quotes: ;
1028 }
1029
1030 if (! yyres)
1031 return yystrlen (yystr);
1032
1033 return yystpcpy (yyres, yystr) - yyres;
1034}
1035# endif
1036
1037/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
1038 about the unexpected token YYTOKEN for the state stack whose top is
1039 YYSSP.
1040
1041 Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
1042 not large enough to hold the message. In that case, also set
1043 *YYMSG_ALLOC to the required number of bytes. Return 2 if the
1044 required number of bytes is too large to store. */
1045static int
1046yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
1047 yytype_int16 *yyssp, int yytoken)
1048{
1049 YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
1050 YYSIZE_T yysize = yysize0;
1051 YYSIZE_T yysize1;
1052 enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
1053 /* Internationalized format string. */
1054 const char *yyformat = 0;
1055 /* Arguments of yyformat. */
1056 char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
1057 /* Number of reported tokens (one for the "unexpected", one per
1058 "expected"). */
1059 int yycount = 0;
1060
1061 /* There are many possibilities here to consider:
1062 - Assume YYFAIL is not used. It's too flawed to consider. See
1063 <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
1064 for details. YYERROR is fine as it does not invoke this
1065 function.
1066 - If this state is a consistent state with a default action, then
1067 the only way this function was invoked is if the default action
1068 is an error action. In that case, don't check for expected
1069 tokens because there are none.
1070 - The only way there can be no lookahead present (in yychar) is if
1071 this state is a consistent state with a default action. Thus,
1072 detecting the absence of a lookahead is sufficient to determine
1073 that there is no unexpected or expected token to report. In that
1074 case, just report a simple "syntax error".
1075 - Don't assume there isn't a lookahead just because this state is a
1076 consistent state with a default action. There might have been a
1077 previous inconsistent state, consistent state with a non-default
1078 action, or user semantic action that manipulated yychar.
1079 - Of course, the expected token list depends on states to have
1080 correct lookahead information, and it depends on the parser not
1081 to perform extra reductions after fetching a lookahead from the
1082 scanner and before detecting a syntax error. Thus, state merging
1083 (from LALR or IELR) and default reductions corrupt the expected
1084 token list. However, the list is correct for canonical LR with
1085 one exception: it will still contain any token that will not be
1086 accepted due to an error action in a later state.
1087 */
1088 if (yytoken != YYEMPTY)
1089 {
1090 int yyn = yypact[*yyssp];
1091 yyarg[yycount++] = yytname[yytoken];
1092 if (!yypact_value_is_default (yyn))
1093 {
1094 /* Start YYX at -YYN if negative to avoid negative indexes in
1095 YYCHECK. In other words, skip the first -YYN actions for
1096 this state because they are default actions. */
1097 int yyxbegin = yyn < 0 ? -yyn : 0;
1098 /* Stay within bounds of both yycheck and yytname. */
1099 int yychecklim = YYLAST - yyn + 1;
1100 int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
1101 int yyx;
1102
1103 for (yyx = yyxbegin; yyx < yyxend; ++yyx)
1104 if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
1105 && !yytable_value_is_error (yytable[yyx + yyn]))
1106 {
1107 if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
1108 {
1109 yycount = 1;
1110 yysize = yysize0;
1111 break;
1112 }
1113 yyarg[yycount++] = yytname[yyx];
1114 yysize1 = yysize + yytnamerr (0, yytname[yyx]);
1115 if (! (yysize <= yysize1
1116 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
1117 return 2;
1118 yysize = yysize1;
1119 }
1120 }
1121 }
1122
1123 switch (yycount)
1124 {
1125# define YYCASE_(N, S) \
1126 case N: \
1127 yyformat = S; \
1128 break
1129 YYCASE_(0, YY_("syntax error"));
1130 YYCASE_(1, YY_("syntax error, unexpected %s"));
1131 YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
1132 YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
1133 YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
1134 YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
1135# undef YYCASE_
1136 }
1137
1138 yysize1 = yysize + yystrlen (yyformat);
1139 if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
1140 return 2;
1141 yysize = yysize1;
1142
1143 if (*yymsg_alloc < yysize)
1144 {
1145 *yymsg_alloc = 2 * yysize;
1146 if (! (yysize <= *yymsg_alloc
1147 && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
1148 *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
1149 return 1;
1150 }
1151
1152 /* Avoid sprintf, as that infringes on the user's name space.
1153 Don't have undefined behavior even if the translation
1154 produced a string with the wrong number of "%s"s. */
1155 {
1156 char *yyp = *yymsg;
1157 int yyi = 0;
1158 while ((*yyp = *yyformat) != '\0')
1159 if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
1160 {
1161 yyp += yytnamerr (yyp, yyarg[yyi++]);
1162 yyformat += 2;
1163 }
1164 else
1165 {
1166 yyp++;
1167 yyformat++;
1168 }
1169 }
1170 return 0;
1171}
1172#endif /* YYERROR_VERBOSE */
1173
1174/*-----------------------------------------------.
1175| Release the memory associated to this symbol. |
1176`-----------------------------------------------*/
1177
1178/*ARGSUSED*/
1179#if (defined __STDC__ || defined __C99__FUNC__ \
1180 || defined __cplusplus || defined _MSC_VER)
1181static void
1182yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
1183#else
1184static void
1185yydestruct (yymsg, yytype, yyvaluep)
1186 const char *yymsg;
1187 int yytype;
1188 YYSTYPE *yyvaluep;
1189#endif
1190{
1191 YYUSE (yyvaluep);
1192
1193 if (!yymsg)
1194 yymsg = "Deleting";
1195 YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
1196
1197 switch (yytype)
1198 {
1199
1200 default:
1201 break;
1202 }
1203}
1204
1205
1206/* Prevent warnings from -Wmissing-prototypes. */
1207#ifdef YYPARSE_PARAM
1208#if defined __STDC__ || defined __cplusplus
1209int yyparse (void *YYPARSE_PARAM);
1210#else
1211int yyparse ();
1212#endif
1213#else /* ! YYPARSE_PARAM */
1214#if defined __STDC__ || defined __cplusplus
1215int yyparse (void);
1216#else
1217int yyparse ();
1218#endif
1219#endif /* ! YYPARSE_PARAM */
1220
1221
1222/* The lookahead symbol. */
1223int yychar;
1224
1225/* The semantic value of the lookahead symbol. */
1226YYSTYPE yylval;
1227
1228/* Number of syntax errors so far. */
1229int yynerrs;
1230
1231
1232/*----------.
1233| yyparse. |
1234`----------*/
1235
1236#ifdef YYPARSE_PARAM
1237#if (defined __STDC__ || defined __C99__FUNC__ \
1238 || defined __cplusplus || defined _MSC_VER)
1239int
1240yyparse (void *YYPARSE_PARAM)
1241#else
1242int
1243yyparse (YYPARSE_PARAM)
1244 void *YYPARSE_PARAM;
1245#endif
1246#else /* ! YYPARSE_PARAM */
1247#if (defined __STDC__ || defined __C99__FUNC__ \
1248 || defined __cplusplus || defined _MSC_VER)
1249int
1250yyparse (void)
1251#else
1252int
1253yyparse ()
1254
1255#endif
1256#endif
1257{
1258 int yystate;
1259 /* Number of tokens to shift before error messages enabled. */
1260 int yyerrstatus;
1261
1262 /* The stacks and their tools:
1263 `yyss': related to states.
1264 `yyvs': related to semantic values.
1265
1266 Refer to the stacks thru separate pointers, to allow yyoverflow
1267 to reallocate them elsewhere. */
1268
1269 /* The state stack. */
1270 yytype_int16 yyssa[YYINITDEPTH];
1271 yytype_int16 *yyss;
1272 yytype_int16 *yyssp;
1273
1274 /* The semantic value stack. */
1275 YYSTYPE yyvsa[YYINITDEPTH];
1276 YYSTYPE *yyvs;
1277 YYSTYPE *yyvsp;
1278
1279 YYSIZE_T yystacksize;
1280
1281 int yyn;
1282 int yyresult;
1283 /* Lookahead token as an internal (translated) token number. */
1284 int yytoken;
1285 /* The variables used to return semantic value and location from the
1286 action routines. */
1287 YYSTYPE yyval;
1288
1289#if YYERROR_VERBOSE
1290 /* Buffer for error messages, and its allocated size. */
1291 char yymsgbuf[128];
1292 char *yymsg = yymsgbuf;
1293 YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
1294#endif
1295
1296#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
1297
1298 /* The number of symbols on the RHS of the reduced rule.
1299 Keep to zero when no symbol should be popped. */
1300 int yylen = 0;
1301
1302 yytoken = 0;
1303 yyss = yyssa;
1304 yyvs = yyvsa;
1305 yystacksize = YYINITDEPTH;
1306
1307 YYDPRINTF ((stderr, "Starting parse\n"));
1308
1309 yystate = 0;
1310 yyerrstatus = 0;
1311 yynerrs = 0;
1312 yychar = YYEMPTY; /* Cause a token to be read. */
1313
1314 /* Initialize stack pointers.
1315 Waste one element of value and location stack
1316 so that they stay on the same level as the state stack.
1317 The wasted elements are never initialized. */
1318 yyssp = yyss;
1319 yyvsp = yyvs;
1320
1321 goto yysetstate;
1322
1323/*------------------------------------------------------------.
1324| yynewstate -- Push a new state, which is found in yystate. |
1325`------------------------------------------------------------*/
1326 yynewstate:
1327 /* In all cases, when you get here, the value and location stacks
1328 have just been pushed. So pushing a state here evens the stacks. */
1329 yyssp++;
1330
1331 yysetstate:
1332 *yyssp = yystate;
1333
1334 if (yyss + yystacksize - 1 <= yyssp)
1335 {
1336 /* Get the current used size of the three stacks, in elements. */
1337 YYSIZE_T yysize = yyssp - yyss + 1;
1338
1339#ifdef yyoverflow
1340 {
1341 /* Give user a chance to reallocate the stack. Use copies of
1342 these so that the &'s don't force the real ones into
1343 memory. */
1344 YYSTYPE *yyvs1 = yyvs;
1345 yytype_int16 *yyss1 = yyss;
1346
1347 /* Each stack pointer address is followed by the size of the
1348 data in use in that stack, in bytes. This used to be a
1349 conditional around just the two extra args, but that might
1350 be undefined if yyoverflow is a macro. */
1351 yyoverflow (YY_("memory exhausted"),
1352 &yyss1, yysize * sizeof (*yyssp),
1353 &yyvs1, yysize * sizeof (*yyvsp),
1354 &yystacksize);
1355
1356 yyss = yyss1;
1357 yyvs = yyvs1;
1358 }
1359#else /* no yyoverflow */
1360# ifndef YYSTACK_RELOCATE
1361 goto yyexhaustedlab;
1362# else
1363 /* Extend the stack our own way. */
1364 if (YYMAXDEPTH <= yystacksize)
1365 goto yyexhaustedlab;
1366 yystacksize *= 2;
1367 if (YYMAXDEPTH < yystacksize)
1368 yystacksize = YYMAXDEPTH;
1369
1370 {
1371 yytype_int16 *yyss1 = yyss;
1372 union yyalloc *yyptr =
1373 (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
1374 if (! yyptr)
1375 goto yyexhaustedlab;
1376 YYSTACK_RELOCATE (yyss_alloc, yyss);
1377 YYSTACK_RELOCATE (yyvs_alloc, yyvs);
1378# undef YYSTACK_RELOCATE
1379 if (yyss1 != yyssa)
1380 YYSTACK_FREE (yyss1);
1381 }
1382# endif
1383#endif /* no yyoverflow */
1384
1385 yyssp = yyss + yysize - 1;
1386 yyvsp = yyvs + yysize - 1;
1387
1388 YYDPRINTF ((stderr, "Stack size increased to %lu\n",
1389 (unsigned long int) yystacksize));
1390
1391 if (yyss + yystacksize - 1 <= yyssp)
1392 YYABORT;
1393 }
1394
1395 YYDPRINTF ((stderr, "Entering state %d\n", yystate));
1396
1397 if (yystate == YYFINAL)
1398 YYACCEPT;
1399
1400 goto yybackup;
1401
1402/*-----------.
1403| yybackup. |
1404`-----------*/
1405yybackup:
1406
1407 /* Do appropriate processing given the current state. Read a
1408 lookahead token if we need one and don't already have one. */
1409
1410 /* First try to decide what to do without reference to lookahead token. */
1411 yyn = yypact[yystate];
1412 if (yypact_value_is_default (yyn))
1413 goto yydefault;
1414
1415 /* Not known => get a lookahead token if don't already have one. */
1416
1417 /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
1418 if (yychar == YYEMPTY)
1419 {
1420 YYDPRINTF ((stderr, "Reading a token: "));
1421 yychar = YYLEX;
1422 }
1423
1424 if (yychar <= YYEOF)
1425 {
1426 yychar = yytoken = YYEOF;
1427 YYDPRINTF ((stderr, "Now at end of input.\n"));
1428 }
1429 else
1430 {
1431 yytoken = YYTRANSLATE (yychar);
1432 YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
1433 }
1434
1435 /* If the proper action on seeing token YYTOKEN is to reduce or to
1436 detect an error, take that action. */
1437 yyn += yytoken;
1438 if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
1439 goto yydefault;
1440 yyn = yytable[yyn];
1441 if (yyn <= 0)
1442 {
1443 if (yytable_value_is_error (yyn))
1444 goto yyerrlab;
1445 yyn = -yyn;
1446 goto yyreduce;
1447 }
1448
1449 /* Count tokens shifted since error; after three, turn off error
1450 status. */
1451 if (yyerrstatus)
1452 yyerrstatus--;
1453
1454 /* Shift the lookahead token. */
1455 YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
1456
1457 /* Discard the shifted token. */
1458 yychar = YYEMPTY;
1459
1460 yystate = yyn;
1461 *++yyvsp = yylval;
1462
1463 goto yynewstate;
1464
1465
1466/*-----------------------------------------------------------.
1467| yydefault -- do the default action for the current state. |
1468`-----------------------------------------------------------*/
1469yydefault:
1470 yyn = yydefact[yystate];
1471 if (yyn == 0)
1472 goto yyerrlab;
1473 goto yyreduce;
1474
1475
1476/*-----------------------------.
1477| yyreduce -- Do a reduction. |
1478`-----------------------------*/
1479yyreduce:
1480 /* yyn is the number of a rule to reduce with. */
1481 yylen = yyr2[yyn];
1482
1483 /* If YYLEN is nonzero, implement the default value of the action:
1484 `$$ = $1'.
1485
1486 Otherwise, the following line sets YYVAL to garbage.
1487 This behavior is undocumented and Bison
1488 users should not rely upon it. Assigning to YYVAL
1489 unconditionally makes the parser a bit smaller, and it avoids a
1490 GCC warning that YYVAL may be used uninitialized. */
1491 yyval = yyvsp[1-yylen];
1492
1493
1494 YY_REDUCE_PRINT (yyn);
1495 switch (yyn)
1496 {
1497 case 11:
1498
1499/* Line 1806 of yacc.c */
1500#line 133 "lib/conf-parse.y"
1501 { sensors_bus new_el;
1502 new_el.line = (yyvsp[(1) - (3)].line);
1503 new_el.bus = (yyvsp[(2) - (3)].bus);
1504 new_el.adapter = (yyvsp[(3) - (3)].name);
1505 bus_add_el(&new_el);
1506 }
1507 break;
1508
1509 case 12:
1510
1511/* Line 1806 of yacc.c */
1512#line 142 "lib/conf-parse.y"
1513 { sensors_label new_el;
1514 if (!current_chip) {
1515 sensors_yyerror("Label statement before first chip statement");
1516 free((yyvsp[(2) - (3)].name));
1517 free((yyvsp[(3) - (3)].name));
1518 YYERROR;
1519 }
1520 new_el.line = (yyvsp[(1) - (3)].line);
1521 new_el.name = (yyvsp[(2) - (3)].name);
1522 new_el.value = (yyvsp[(3) - (3)].name);
1523 label_add_el(&new_el);
1524 }
1525 break;
1526
1527 case 13:
1528
1529/* Line 1806 of yacc.c */
1530#line 157 "lib/conf-parse.y"
1531 { sensors_set new_el;
1532 if (!current_chip) {
1533 sensors_yyerror("Set statement before first chip statement");
1534 free((yyvsp[(2) - (3)].name));
1535 sensors_free_expr((yyvsp[(3) - (3)].expr));
1536 YYERROR;
1537 }
1538 new_el.line = (yyvsp[(1) - (3)].line);
1539 new_el.name = (yyvsp[(2) - (3)].name);
1540 new_el.value = (yyvsp[(3) - (3)].expr);
1541 set_add_el(&new_el);
1542 }
1543 break;
1544
1545 case 14:
1546
1547/* Line 1806 of yacc.c */
1548#line 172 "lib/conf-parse.y"
1549 { sensors_compute new_el;
1550 if (!current_chip) {
1551 sensors_yyerror("Compute statement before first chip statement");
1552 free((yyvsp[(2) - (5)].name));
1553 sensors_free_expr((yyvsp[(3) - (5)].expr));
1554 sensors_free_expr((yyvsp[(5) - (5)].expr));
1555 YYERROR;
1556 }
1557 new_el.line = (yyvsp[(1) - (5)].line);
1558 new_el.name = (yyvsp[(2) - (5)].name);
1559 new_el.from_proc = (yyvsp[(3) - (5)].expr);
1560 new_el.to_proc = (yyvsp[(5) - (5)].expr);
1561 compute_add_el(&new_el);
1562 }
1563 break;
1564
1565 case 15:
1566
1567/* Line 1806 of yacc.c */
1568#line 189 "lib/conf-parse.y"
1569 { sensors_ignore new_el;
1570 if (!current_chip) {
1571 sensors_yyerror("Ignore statement before first chip statement");
1572 free((yyvsp[(2) - (2)].name));
1573 YYERROR;
1574 }
1575 new_el.line = (yyvsp[(1) - (2)].line);
1576 new_el.name = (yyvsp[(2) - (2)].name);
1577 ignore_add_el(&new_el);
1578 }
1579 break;
1580
1581 case 16:
1582
1583/* Line 1806 of yacc.c */
1584#line 202 "lib/conf-parse.y"
1585 { sensors_chip new_el;
1586 new_el.line = (yyvsp[(1) - (2)].line);
1587 new_el.labels = NULL;
1588 new_el.sets = NULL;
1589 new_el.computes = NULL;
1590 new_el.ignores = NULL;
1591 new_el.labels_count = new_el.labels_max = 0;
1592 new_el.sets_count = new_el.sets_max = 0;
1593 new_el.computes_count = new_el.computes_max = 0;
1594 new_el.ignores_count = new_el.ignores_max = 0;
1595 new_el.chips = (yyvsp[(2) - (2)].chips);
1596 chip_add_el(&new_el);
1597 current_chip = sensors_config_chips +
1598 sensors_config_chips_count - 1;
1599 }
1600 break;
1601
1602 case 17:
1603
1604/* Line 1806 of yacc.c */
1605#line 220 "lib/conf-parse.y"
1606 {
1607 (yyval.chips).fits = NULL;
1608 (yyval.chips).fits_count = (yyval.chips).fits_max = 0;
1609 fits_add_el(&(yyvsp[(1) - (1)].chip),(yyval.chips));
1610 }
1611 break;
1612
1613 case 18:
1614
1615/* Line 1806 of yacc.c */
1616#line 226 "lib/conf-parse.y"
1617 { (yyval.chips) = (yyvsp[(1) - (2)].chips);
1618 fits_add_el(&(yyvsp[(2) - (2)].chip),(yyval.chips));
1619 }
1620 break;
1621
1622 case 19:
1623
1624/* Line 1806 of yacc.c */
1625#line 232 "lib/conf-parse.y"
1626 { (yyval.expr) = malloc_expr();
1627 (yyval.expr)->data.val = (yyvsp[(1) - (1)].value);
1628 (yyval.expr)->kind = sensors_kind_val;
1629 }
1630 break;
1631
1632 case 20:
1633
1634/* Line 1806 of yacc.c */
1635#line 237 "lib/conf-parse.y"
1636 { (yyval.expr) = malloc_expr();
1637 (yyval.expr)->data.var = (yyvsp[(1) - (1)].name);
1638 (yyval.expr)->kind = sensors_kind_var;
1639 }
1640 break;
1641
1642 case 21:
1643
1644/* Line 1806 of yacc.c */
1645#line 242 "lib/conf-parse.y"
1646 { (yyval.expr) = malloc_expr();
1647 (yyval.expr)->kind = sensors_kind_source;
1648 }
1649 break;
1650
1651 case 22:
1652
1653/* Line 1806 of yacc.c */
1654#line 246 "lib/conf-parse.y"
1655 { (yyval.expr) = malloc_expr();
1656 (yyval.expr)->kind = sensors_kind_sub;
1657 (yyval.expr)->data.subexpr.op = sensors_add;
1658 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(1) - (3)].expr);
1659 (yyval.expr)->data.subexpr.sub2 = (yyvsp[(3) - (3)].expr);
1660 }
1661 break;
1662
1663 case 23:
1664
1665/* Line 1806 of yacc.c */
1666#line 253 "lib/conf-parse.y"
1667 { (yyval.expr) = malloc_expr();
1668 (yyval.expr)->kind = sensors_kind_sub;
1669 (yyval.expr)->data.subexpr.op = sensors_sub;
1670 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(1) - (3)].expr);
1671 (yyval.expr)->data.subexpr.sub2 = (yyvsp[(3) - (3)].expr);
1672 }
1673 break;
1674
1675 case 24:
1676
1677/* Line 1806 of yacc.c */
1678#line 260 "lib/conf-parse.y"
1679 { (yyval.expr) = malloc_expr();
1680 (yyval.expr)->kind = sensors_kind_sub;
1681 (yyval.expr)->data.subexpr.op = sensors_multiply;
1682 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(1) - (3)].expr);
1683 (yyval.expr)->data.subexpr.sub2 = (yyvsp[(3) - (3)].expr);
1684 }
1685 break;
1686
1687 case 25:
1688
1689/* Line 1806 of yacc.c */
1690#line 267 "lib/conf-parse.y"
1691 { (yyval.expr) = malloc_expr();
1692 (yyval.expr)->kind = sensors_kind_sub;
1693 (yyval.expr)->data.subexpr.op = sensors_divide;
1694 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(1) - (3)].expr);
1695 (yyval.expr)->data.subexpr.sub2 = (yyvsp[(3) - (3)].expr);
1696 }
1697 break;
1698
1699 case 26:
1700
1701/* Line 1806 of yacc.c */
1702#line 274 "lib/conf-parse.y"
1703 { (yyval.expr) = malloc_expr();
1704 (yyval.expr)->kind = sensors_kind_sub;
1705 (yyval.expr)->data.subexpr.op = sensors_negate;
1706 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(2) - (2)].expr);
1707 (yyval.expr)->data.subexpr.sub2 = NULL;
1708 }
1709 break;
1710
1711 case 27:
1712
1713/* Line 1806 of yacc.c */
1714#line 281 "lib/conf-parse.y"
1715 { (yyval.expr) = (yyvsp[(2) - (3)].expr); }
1716 break;
1717
1718 case 28:
1719
1720/* Line 1806 of yacc.c */
1721#line 283 "lib/conf-parse.y"
1722 { (yyval.expr) = malloc_expr();
1723 (yyval.expr)->kind = sensors_kind_sub;
1724 (yyval.expr)->data.subexpr.op = sensors_exp;
1725 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(2) - (2)].expr);
1726 (yyval.expr)->data.subexpr.sub2 = NULL;
1727 }
1728 break;
1729
1730 case 29:
1731
1732/* Line 1806 of yacc.c */
1733#line 290 "lib/conf-parse.y"
1734 { (yyval.expr) = malloc_expr();
1735 (yyval.expr)->kind = sensors_kind_sub;
1736 (yyval.expr)->data.subexpr.op = sensors_log;
1737 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(2) - (2)].expr);
1738 (yyval.expr)->data.subexpr.sub2 = NULL;
1739 }
1740 break;
1741
1742 case 30:
1743
1744/* Line 1806 of yacc.c */
1745#line 299 "lib/conf-parse.y"
1746 { int res = sensors_parse_bus_id((yyvsp[(1) - (1)].name),&(yyval.bus));
1747 free((yyvsp[(1) - (1)].name));
1748 if (res) {
1749 sensors_yyerror("Parse error in bus id");
1750 YYERROR;
1751 }
1752 }
1753 break;
1754
1755 case 31:
1756
1757/* Line 1806 of yacc.c */
1758#line 309 "lib/conf-parse.y"
1759 { (yyval.name) = (yyvsp[(1) - (1)].name); }
1760 break;
1761
1762 case 32:
1763
1764/* Line 1806 of yacc.c */
1765#line 313 "lib/conf-parse.y"
1766 { (yyval.name) = (yyvsp[(1) - (1)].name); }
1767 break;
1768
1769 case 33:
1770
1771/* Line 1806 of yacc.c */
1772#line 317 "lib/conf-parse.y"
1773 { (yyval.name) = (yyvsp[(1) - (1)].name); }
1774 break;
1775
1776 case 34:
1777
1778/* Line 1806 of yacc.c */
1779#line 321 "lib/conf-parse.y"
1780 { int res = sensors_parse_chip_name((yyvsp[(1) - (1)].name),&(yyval.chip));
1781 free((yyvsp[(1) - (1)].name));
1782 if (res) {
1783 sensors_yyerror("Parse error in chip name");
1784 YYERROR;
1785 }
1786 }
1787 break;
1788
1789
1790
1791/* Line 1806 of yacc.c */
1792#line 1793 "lib/conf-parse.c"
1793 default: break;
1794 }
1795 /* User semantic actions sometimes alter yychar, and that requires
1796 that yytoken be updated with the new translation. We take the
1797 approach of translating immediately before every use of yytoken.
1798 One alternative is translating here after every semantic action,
1799 but that translation would be missed if the semantic action invokes
1800 YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
1801 if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
1802 incorrect destructor might then be invoked immediately. In the
1803 case of YYERROR or YYBACKUP, subsequent parser actions might lead
1804 to an incorrect destructor call or verbose syntax error message
1805 before the lookahead is translated. */
1806 YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
1807
1808 YYPOPSTACK (yylen);
1809 yylen = 0;
1810 YY_STACK_PRINT (yyss, yyssp);
1811
1812 *++yyvsp = yyval;
1813
1814 /* Now `shift' the result of the reduction. Determine what state
1815 that goes to, based on the state we popped back to and the rule
1816 number reduced by. */
1817
1818 yyn = yyr1[yyn];
1819
1820 yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
1821 if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
1822 yystate = yytable[yystate];
1823 else
1824 yystate = yydefgoto[yyn - YYNTOKENS];
1825
1826 goto yynewstate;
1827
1828
1829/*------------------------------------.
1830| yyerrlab -- here on detecting error |
1831`------------------------------------*/
1832yyerrlab:
1833 /* Make sure we have latest lookahead translation. See comments at
1834 user semantic actions for why this is necessary. */
1835 yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
1836
1837 /* If not already recovering from an error, report this error. */
1838 if (!yyerrstatus)
1839 {
1840 ++yynerrs;
1841#if ! YYERROR_VERBOSE
1842 yyerror (YY_("syntax error"));
1843#else
1844# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
1845 yyssp, yytoken)
1846 {
1847 char const *yymsgp = YY_("syntax error");
1848 int yysyntax_error_status;
1849 yysyntax_error_status = YYSYNTAX_ERROR;
1850 if (yysyntax_error_status == 0)
1851 yymsgp = yymsg;
1852 else if (yysyntax_error_status == 1)
1853 {
1854 if (yymsg != yymsgbuf)
1855 YYSTACK_FREE (yymsg);
1856 yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
1857 if (!yymsg)
1858 {
1859 yymsg = yymsgbuf;
1860 yymsg_alloc = sizeof yymsgbuf;
1861 yysyntax_error_status = 2;
1862 }
1863 else
1864 {
1865 yysyntax_error_status = YYSYNTAX_ERROR;
1866 yymsgp = yymsg;
1867 }
1868 }
1869 yyerror (yymsgp);
1870 if (yysyntax_error_status == 2)
1871 goto yyexhaustedlab;
1872 }
1873# undef YYSYNTAX_ERROR
1874#endif
1875 }
1876
1877
1878
1879 if (yyerrstatus == 3)
1880 {
1881 /* If just tried and failed to reuse lookahead token after an
1882 error, discard it. */
1883
1884 if (yychar <= YYEOF)
1885 {
1886 /* Return failure if at end of input. */
1887 if (yychar == YYEOF)
1888 YYABORT;
1889 }
1890 else
1891 {
1892 yydestruct ("Error: discarding",
1893 yytoken, &yylval);
1894 yychar = YYEMPTY;
1895 }
1896 }
1897
1898 /* Else will try to reuse lookahead token after shifting the error
1899 token. */
1900 goto yyerrlab1;
1901
1902
1903/*---------------------------------------------------.
1904| yyerrorlab -- error raised explicitly by YYERROR. |
1905`---------------------------------------------------*/
1906yyerrorlab:
1907
1908 /* Pacify compilers like GCC when the user code never invokes
1909 YYERROR and the label yyerrorlab therefore never appears in user
1910 code. */
1911 if (/*CONSTCOND*/ 0)
1912 goto yyerrorlab;
1913
1914 /* Do not reclaim the symbols of the rule which action triggered
1915 this YYERROR. */
1916 YYPOPSTACK (yylen);
1917 yylen = 0;
1918 YY_STACK_PRINT (yyss, yyssp);
1919 yystate = *yyssp;
1920 goto yyerrlab1;
1921
1922
1923/*-------------------------------------------------------------.
1924| yyerrlab1 -- common code for both syntax error and YYERROR. |
1925`-------------------------------------------------------------*/
1926yyerrlab1:
1927 yyerrstatus = 3; /* Each real token shifted decrements this. */
1928
1929 for (;;)
1930 {
1931 yyn = yypact[yystate];
1932 if (!yypact_value_is_default (yyn))
1933 {
1934 yyn += YYTERROR;
1935 if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
1936 {
1937 yyn = yytable[yyn];
1938 if (0 < yyn)
1939 break;
1940 }
1941 }
1942
1943 /* Pop the current state because it cannot handle the error token. */
1944 if (yyssp == yyss)
1945 YYABORT;
1946
1947
1948 yydestruct ("Error: popping",
1949 yystos[yystate], yyvsp);
1950 YYPOPSTACK (1);
1951 yystate = *yyssp;
1952 YY_STACK_PRINT (yyss, yyssp);
1953 }
1954
1955 *++yyvsp = yylval;
1956
1957
1958 /* Shift the error token. */
1959 YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
1960
1961 yystate = yyn;
1962 goto yynewstate;
1963
1964
1965/*-------------------------------------.
1966| yyacceptlab -- YYACCEPT comes here. |
1967`-------------------------------------*/
1968yyacceptlab:
1969 yyresult = 0;
1970 goto yyreturn;
1971
1972/*-----------------------------------.
1973| yyabortlab -- YYABORT comes here. |
1974`-----------------------------------*/
1975yyabortlab:
1976 yyresult = 1;
1977 goto yyreturn;
1978
1979#if !defined(yyoverflow) || YYERROR_VERBOSE
1980/*-------------------------------------------------.
1981| yyexhaustedlab -- memory exhaustion comes here. |
1982`-------------------------------------------------*/
1983yyexhaustedlab:
1984 yyerror (YY_("memory exhausted"));
1985 yyresult = 2;
1986 /* Fall through. */
1987#endif
1988
1989yyreturn:
1990 if (yychar != YYEMPTY)
1991 {
1992 /* Make sure we have latest lookahead translation. See comments at
1993 user semantic actions for why this is necessary. */
1994 yytoken = YYTRANSLATE (yychar);
1995 yydestruct ("Cleanup: discarding lookahead",
1996 yytoken, &yylval);
1997 }
1998 /* Do not reclaim the symbols of the rule which action triggered
1999 this YYABORT or YYACCEPT. */
2000 YYPOPSTACK (yylen);
2001 YY_STACK_PRINT (yyss, yyssp);
2002 while (yyssp != yyss)
2003 {
2004 yydestruct ("Cleanup: popping",
2005 yystos[*yyssp], yyvsp);
2006 YYPOPSTACK (1);
2007 }
2008#ifndef yyoverflow
2009 if (yyss != yyssa)
2010 YYSTACK_FREE (yyss);
2011#endif
2012#if YYERROR_VERBOSE
2013 if (yymsg != yymsgbuf)
2014 YYSTACK_FREE (yymsg);
2015#endif
2016 /* Make sure YYID is used. */
2017 return YYID (yyresult);
2018}
2019
2020
2021
2022/* Line 2067 of yacc.c */
2023#line 330 "lib/conf-parse.y"
2024
2025
2026void sensors_yyerror(const char *err)
2027{
2028 if (sensors_lex_error[0]) {
2029 sensors_parse_error_wfn(sensors_lex_error, sensors_yyfilename, sensors_yylineno);
2030 sensors_lex_error[0] = '\0';
2031 } else
2032 sensors_parse_error_wfn(err, sensors_yyfilename, sensors_yylineno);
2033}
2034
2035sensors_expr *malloc_expr(void)
2036{
2037 sensors_expr *res = malloc(sizeof(sensors_expr));
2038 if (! res)
2039 sensors_fatal_error(__func__, "Allocating a new expression");
2040 return res;
2041}
2042
diff --git a/daemon/libsensors/conf-parse.h b/daemon/libsensors/conf-parse.h
new file mode 100644
index 0000000..89c9c1a
--- /dev/null
+++ b/daemon/libsensors/conf-parse.h
@@ -0,0 +1,84 @@
1/* A Bison parser, made by GNU Bison 2.5. */
2
3/* Bison interface for Yacc-like parsers in C
4
5 Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20/* As a special exception, you may create a larger work that contains
21 part or all of the Bison parser skeleton and distribute that work
22 under terms of your choice, so long as that work isn't itself a
23 parser generator using the skeleton or a modified version thereof
24 as a parser skeleton. Alternatively, if you modify or redistribute
25 the parser skeleton itself, you may (at your option) remove this
26 special exception, which will cause the skeleton and the resulting
27 Bison output files to be licensed under the GNU General Public
28 License without this special exception.
29
30 This special exception was added by the Free Software Foundation in
31 version 2.2 of Bison. */
32
33
34/* Tokens. */
35#ifndef YYTOKENTYPE
36# define YYTOKENTYPE
37 /* Put the tokens into the symbol table, so that GDB and other debuggers
38 know about them. */
39 enum yytokentype {
40 NEG = 258,
41 EOL = 259,
42 BUS = 260,
43 LABEL = 261,
44 SET = 262,
45 CHIP = 263,
46 COMPUTE = 264,
47 IGNORE = 265,
48 FLOAT = 266,
49 NAME = 267,
50 ERROR = 268
51 };
52#endif
53
54
55
56#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
57typedef union YYSTYPE
58{
59
60/* Line 2068 of yacc.c */
61#line 79 "lib/conf-parse.y"
62
63 double value;
64 char *name;
65 void *nothing;
66 sensors_chip_name_list chips;
67 sensors_expr *expr;
68 sensors_bus_id bus;
69 sensors_chip_name chip;
70 sensors_config_line line;
71
72
73
74/* Line 2068 of yacc.c */
75#line 76 "lib/conf-parse.h"
76} YYSTYPE;
77# define YYSTYPE_IS_TRIVIAL 1
78# define yystype YYSTYPE /* obsolescent; will be withdrawn */
79# define YYSTYPE_IS_DECLARED 1
80#endif
81
82extern YYSTYPE sensors_yylval;
83
84
diff --git a/daemon/libsensors/conf-parse.y b/daemon/libsensors/conf-parse.y
new file mode 100644
index 0000000..1937f54
--- /dev/null
+++ b/daemon/libsensors/conf-parse.y
@@ -0,0 +1,347 @@
1%{
2/*
3 conf-parse.y - Part of libsensors, a Linux library for reading sensor data.
4 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#define YYERROR_VERBOSE
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27
28#include "data.h"
29#include "general.h"
30#include "error.h"
31#include "conf.h"
32#include "access.h"
33#include "init.h"
34
35static void sensors_yyerror(const char *err);
36static sensors_expr *malloc_expr(void);
37
38static sensors_chip *current_chip = NULL;
39
40#define bus_add_el(el) sensors_add_array_el(el,\
41 &sensors_config_busses,\
42 &sensors_config_busses_count,\
43 &sensors_config_busses_max,\
44 sizeof(sensors_bus))
45#define label_add_el(el) sensors_add_array_el(el,\
46 &current_chip->labels,\
47 &current_chip->labels_count,\
48 &current_chip->labels_max,\
49 sizeof(sensors_label));
50#define set_add_el(el) sensors_add_array_el(el,\
51 &current_chip->sets,\
52 &current_chip->sets_count,\
53 &current_chip->sets_max,\
54 sizeof(sensors_set));
55#define compute_add_el(el) sensors_add_array_el(el,\
56 &current_chip->computes,\
57 &current_chip->computes_count,\
58 &current_chip->computes_max,\
59 sizeof(sensors_compute));
60#define ignore_add_el(el) sensors_add_array_el(el,\
61 &current_chip->ignores,\
62 &current_chip->ignores_count,\
63 &current_chip->ignores_max,\
64 sizeof(sensors_ignore));
65#define chip_add_el(el) sensors_add_array_el(el,\
66 &sensors_config_chips,\
67 &sensors_config_chips_count,\
68 &sensors_config_chips_max,\
69 sizeof(sensors_chip));
70
71#define fits_add_el(el,list) sensors_add_array_el(el,\
72 &(list).fits,\
73 &(list).fits_count,\
74 &(list).fits_max, \
75 sizeof(sensors_chip_name));
76
77%}
78
79%union {
80 double value;
81 char *name;
82 void *nothing;
83 sensors_chip_name_list chips;
84 sensors_expr *expr;
85 sensors_bus_id bus;
86 sensors_chip_name chip;
87 sensors_config_line line;
88}
89
90%left <nothing> '-' '+'
91%left <nothing> '*' '/'
92%left <nothing> NEG
93%right <nothing> '^' '`'
94
95%token <nothing> ','
96%token <nothing> EOL
97%token <line> BUS
98%token <line> LABEL
99%token <line> SET
100%token <line> CHIP
101%token <line> COMPUTE
102%token <line> IGNORE
103%token <value> FLOAT
104%token <name> NAME
105%token <nothing> ERROR
106
107%type <chips> chip_name_list
108%type <expr> expression
109%type <bus> bus_id
110%type <name> adapter_name
111%type <name> function_name
112%type <name> string
113%type <chip> chip_name
114
115%start input
116
117%%
118
119input: /* empty */
120 | input line
121;
122
123line: bus_statement EOL
124 | label_statement EOL
125 | set_statement EOL
126 | chip_statement EOL
127 | compute_statement EOL
128 | ignore_statement EOL
129 | error EOL
130;
131
132bus_statement: BUS bus_id adapter_name
133 { sensors_bus new_el;
134 new_el.line = $1;
135 new_el.bus = $2;
136 new_el.adapter = $3;
137 bus_add_el(&new_el);
138 }
139;
140
141label_statement: LABEL function_name string
142 { sensors_label new_el;
143 if (!current_chip) {
144 sensors_yyerror("Label statement before first chip statement");
145 free($2);
146 free($3);
147 YYERROR;
148 }
149 new_el.line = $1;
150 new_el.name = $2;
151 new_el.value = $3;
152 label_add_el(&new_el);
153 }
154;
155
156set_statement: SET function_name expression
157 { sensors_set new_el;
158 if (!current_chip) {
159 sensors_yyerror("Set statement before first chip statement");
160 free($2);
161 sensors_free_expr($3);
162 YYERROR;
163 }
164 new_el.line = $1;
165 new_el.name = $2;
166 new_el.value = $3;
167 set_add_el(&new_el);
168 }
169;
170
171compute_statement: COMPUTE function_name expression ',' expression
172 { sensors_compute new_el;
173 if (!current_chip) {
174 sensors_yyerror("Compute statement before first chip statement");
175 free($2);
176 sensors_free_expr($3);
177 sensors_free_expr($5);
178 YYERROR;
179 }
180 new_el.line = $1;
181 new_el.name = $2;
182 new_el.from_proc = $3;
183 new_el.to_proc = $5;
184 compute_add_el(&new_el);
185 }
186;
187
188ignore_statement: IGNORE function_name
189 { sensors_ignore new_el;
190 if (!current_chip) {
191 sensors_yyerror("Ignore statement before first chip statement");
192 free($2);
193 YYERROR;
194 }
195 new_el.line = $1;
196 new_el.name = $2;
197 ignore_add_el(&new_el);
198 }
199;
200
201chip_statement: CHIP chip_name_list
202 { sensors_chip new_el;
203 new_el.line = $1;
204 new_el.labels = NULL;
205 new_el.sets = NULL;
206 new_el.computes = NULL;
207 new_el.ignores = NULL;
208 new_el.labels_count = new_el.labels_max = 0;
209 new_el.sets_count = new_el.sets_max = 0;
210 new_el.computes_count = new_el.computes_max = 0;
211 new_el.ignores_count = new_el.ignores_max = 0;
212 new_el.chips = $2;
213 chip_add_el(&new_el);
214 current_chip = sensors_config_chips +
215 sensors_config_chips_count - 1;
216 }
217;
218
219chip_name_list: chip_name
220 {
221 $$.fits = NULL;
222 $$.fits_count = $$.fits_max = 0;
223 fits_add_el(&$1,$$);
224 }
225 | chip_name_list chip_name
226 { $$ = $1;
227 fits_add_el(&$2,$$);
228 }
229;
230
231expression: FLOAT
232 { $$ = malloc_expr();
233 $$->data.val = $1;
234 $$->kind = sensors_kind_val;
235 }
236 | NAME
237 { $$ = malloc_expr();
238 $$->data.var = $1;
239 $$->kind = sensors_kind_var;
240 }
241 | '@'
242 { $$ = malloc_expr();
243 $$->kind = sensors_kind_source;
244 }
245 | expression '+' expression
246 { $$ = malloc_expr();
247 $$->kind = sensors_kind_sub;
248 $$->data.subexpr.op = sensors_add;
249 $$->data.subexpr.sub1 = $1;
250 $$->data.subexpr.sub2 = $3;
251 }
252 | expression '-' expression
253 { $$ = malloc_expr();
254 $$->kind = sensors_kind_sub;
255 $$->data.subexpr.op = sensors_sub;
256 $$->data.subexpr.sub1 = $1;
257 $$->data.subexpr.sub2 = $3;
258 }
259 | expression '*' expression
260 { $$ = malloc_expr();
261 $$->kind = sensors_kind_sub;
262 $$->data.subexpr.op = sensors_multiply;
263 $$->data.subexpr.sub1 = $1;
264 $$->data.subexpr.sub2 = $3;
265 }
266 | expression '/' expression
267 { $$ = malloc_expr();
268 $$->kind = sensors_kind_sub;
269 $$->data.subexpr.op = sensors_divide;
270 $$->data.subexpr.sub1 = $1;
271 $$->data.subexpr.sub2 = $3;
272 }
273 | '-' expression %prec NEG
274 { $$ = malloc_expr();
275 $$->kind = sensors_kind_sub;
276 $$->data.subexpr.op = sensors_negate;
277 $$->data.subexpr.sub1 = $2;
278 $$->data.subexpr.sub2 = NULL;
279 }
280 | '(' expression ')'
281 { $$ = $2; }
282 | '^' expression
283 { $$ = malloc_expr();
284 $$->kind = sensors_kind_sub;
285 $$->data.subexpr.op = sensors_exp;
286 $$->data.subexpr.sub1 = $2;
287 $$->data.subexpr.sub2 = NULL;
288 }
289 | '`' expression
290 { $$ = malloc_expr();
291 $$->kind = sensors_kind_sub;
292 $$->data.subexpr.op = sensors_log;
293 $$->data.subexpr.sub1 = $2;
294 $$->data.subexpr.sub2 = NULL;
295 }
296;
297
298bus_id: NAME
299 { int res = sensors_parse_bus_id($1,&$$);
300 free($1);
301 if (res) {
302 sensors_yyerror("Parse error in bus id");
303 YYERROR;
304 }
305 }
306;
307
308adapter_name: NAME
309 { $$ = $1; }
310;
311
312function_name: NAME
313 { $$ = $1; }
314;
315
316string: NAME
317 { $$ = $1; }
318;
319
320chip_name: NAME
321 { int res = sensors_parse_chip_name($1,&$$);
322 free($1);
323 if (res) {
324 sensors_yyerror("Parse error in chip name");
325 YYERROR;
326 }
327 }
328;
329
330%%
331
332void sensors_yyerror(const char *err)
333{
334 if (sensors_lex_error[0]) {
335 sensors_parse_error_wfn(sensors_lex_error, sensors_yyfilename, sensors_yylineno);
336 sensors_lex_error[0] = '\0';
337 } else
338 sensors_parse_error_wfn(err, sensors_yyfilename, sensors_yylineno);
339}
340
341sensors_expr *malloc_expr(void)
342{
343 sensors_expr *res = malloc(sizeof(sensors_expr));
344 if (! res)
345 sensors_fatal_error(__func__, "Allocating a new expression");
346 return res;
347}
diff --git a/daemon/libsensors/conf.h b/daemon/libsensors/conf.h
new file mode 100644
index 0000000..b7ce4f7
--- /dev/null
+++ b/daemon/libsensors/conf.h
@@ -0,0 +1,34 @@
1/*
2 conf.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 MA 02110-1301 USA.
19*/
20
21#ifndef LIB_SENSORS_CONF_H
22#define LIB_SENSORS_CONF_H
23
24/* This is defined in conf-lex.l */
25int sensors_yylex(void);
26extern char sensors_lex_error[];
27extern const char *sensors_yyfilename;
28extern int sensors_yylineno;
29extern FILE *sensors_yyin;
30
31/* This is defined in conf-parse.y */
32int sensors_yyparse(void);
33
34#endif /* LIB_SENSORS_CONF_H */
diff --git a/daemon/libsensors/data.c b/daemon/libsensors/data.c
new file mode 100644
index 0000000..cac9c8d
--- /dev/null
+++ b/daemon/libsensors/data.c
@@ -0,0 +1,278 @@
1/*
2 data.c - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007, 2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22/*** This file modified by ARM on Jan 23, 2013 to move version.h to the current directory. ***/
23
24/* this define needed for strndup() */
25#define _GNU_SOURCE
26
27#include <stdlib.h>
28#include <string.h>
29
30#include "access.h"
31#include "error.h"
32#include "data.h"
33#include "sensors.h"
34#include "version.h"
35
36const char *libsensors_version = LM_VERSION;
37
38char **sensors_config_files = NULL;
39int sensors_config_files_count = 0;
40int sensors_config_files_max = 0;
41
42sensors_chip *sensors_config_chips = NULL;
43int sensors_config_chips_count = 0;
44int sensors_config_chips_subst = 0;
45int sensors_config_chips_max = 0;
46
47sensors_bus *sensors_config_busses = NULL;
48int sensors_config_busses_count = 0;
49int sensors_config_busses_max = 0;
50
51sensors_chip_features *sensors_proc_chips = NULL;
52int sensors_proc_chips_count = 0;
53int sensors_proc_chips_max = 0;
54
55sensors_bus *sensors_proc_bus = NULL;
56int sensors_proc_bus_count = 0;
57int sensors_proc_bus_max = 0;
58
59void sensors_free_chip_name(sensors_chip_name *chip)
60{
61 free(chip->prefix);
62}
63
64/*
65 Parse a chip name to the internal representation. These are valid names:
66
67 lm78-i2c-10-5e *-i2c-10-5e
68 lm78-i2c-10-* *-i2c-10-*
69 lm78-i2c-*-5e *-i2c-*-5e
70 lm78-i2c-*-* *-i2c-*-*
71 lm78-isa-10dd *-isa-10dd
72 lm78-isa-* *-isa-*
73 lm78-* *-*
74
75 Here 'lm78' can be any prefix. 'i2c' and 'isa' are
76 literal strings, just like all dashes '-' and wildcards '*'. '10' can
77 be any decimal i2c bus number. '5e' can be any hexadecimal i2c device
78 address, and '10dd' any hexadecimal isa address.
79
80 The 'prefix' part in the result is freshly allocated. All old contents
81 of res is overwritten. res itself is not allocated. In case of an error
82 return (ie. != 0), res is undefined, but all allocations are undone.
83*/
84
85int sensors_parse_chip_name(const char *name, sensors_chip_name *res)
86{
87 char *dash;
88
89 /* First, the prefix. It's either "*" or a real chip name. */
90 if (!strncmp(name, "*-", 2)) {
91 res->prefix = SENSORS_CHIP_NAME_PREFIX_ANY;
92 name += 2;
93 } else {
94 if (!(dash = strchr(name, '-')))
95 return -SENSORS_ERR_CHIP_NAME;
96 res->prefix = strndup(name, dash - name);
97 if (!res->prefix)
98 sensors_fatal_error(__func__,
99 "Allocating name prefix");
100 name = dash + 1;
101 }
102
103 /* Then we have either a sole "*" (all chips with this name) or a bus
104 type and an address. */
105 if (!strcmp(name, "*")) {
106 res->bus.type = SENSORS_BUS_TYPE_ANY;
107 res->bus.nr = SENSORS_BUS_NR_ANY;
108 res->addr = SENSORS_CHIP_NAME_ADDR_ANY;
109 return 0;
110 }
111
112 if (!(dash = strchr(name, '-')))
113 goto ERROR;
114 if (!strncmp(name, "i2c", dash - name))
115 res->bus.type = SENSORS_BUS_TYPE_I2C;
116 else if (!strncmp(name, "isa", dash - name))
117 res->bus.type = SENSORS_BUS_TYPE_ISA;
118 else if (!strncmp(name, "pci", dash - name))
119 res->bus.type = SENSORS_BUS_TYPE_PCI;
120 else if (!strncmp(name, "spi", dash - name))
121 res->bus.type = SENSORS_BUS_TYPE_SPI;
122 else if (!strncmp(name, "virtual", dash - name))
123 res->bus.type = SENSORS_BUS_TYPE_VIRTUAL;
124 else if (!strncmp(name, "acpi", dash - name))
125 res->bus.type = SENSORS_BUS_TYPE_ACPI;
126 else if (!strncmp(name, "hid", dash - name))
127 res->bus.type = SENSORS_BUS_TYPE_HID;
128 else
129 goto ERROR;
130 name = dash + 1;
131
132 /* Some bus types (i2c, spi) have an additional bus number.
133 For these, the next part is either a "*" (any bus of that type)
134 or a decimal number. */
135 switch (res->bus.type) {
136 case SENSORS_BUS_TYPE_I2C:
137 case SENSORS_BUS_TYPE_SPI:
138 case SENSORS_BUS_TYPE_HID:
139 if (!strncmp(name, "*-", 2)) {
140 res->bus.nr = SENSORS_BUS_NR_ANY;
141 name += 2;
142 break;
143 }
144
145 res->bus.nr = strtoul(name, &dash, 10);
146 if (*name == '\0' || *dash != '-' || res->bus.nr < 0)
147 goto ERROR;
148 name = dash + 1;
149 break;
150 default:
151 res->bus.nr = SENSORS_BUS_NR_ANY;
152 }
153
154 /* Last part is the chip address, or "*" for any address. */
155 if (!strcmp(name, "*")) {
156 res->addr = SENSORS_CHIP_NAME_ADDR_ANY;
157 } else {
158 res->addr = strtoul(name, &dash, 16);
159 if (*name == '\0' || *dash != '\0' || res->addr < 0)
160 goto ERROR;
161 }
162
163 return 0;
164
165ERROR:
166 free(res->prefix);
167 return -SENSORS_ERR_CHIP_NAME;
168}
169
170int sensors_snprintf_chip_name(char *str, size_t size,
171 const sensors_chip_name *chip)
172{
173 if (sensors_chip_name_has_wildcards(chip))
174 return -SENSORS_ERR_WILDCARDS;
175
176 switch (chip->bus.type) {
177 case SENSORS_BUS_TYPE_ISA:
178 return snprintf(str, size, "%s-isa-%04x", chip->prefix,
179 chip->addr);
180 case SENSORS_BUS_TYPE_PCI:
181 return snprintf(str, size, "%s-pci-%04x", chip->prefix,
182 chip->addr);
183 case SENSORS_BUS_TYPE_I2C:
184 return snprintf(str, size, "%s-i2c-%hd-%02x", chip->prefix,
185 chip->bus.nr, chip->addr);
186 case SENSORS_BUS_TYPE_SPI:
187 return snprintf(str, size, "%s-spi-%hd-%x", chip->prefix,
188 chip->bus.nr, chip->addr);
189 case SENSORS_BUS_TYPE_VIRTUAL:
190 return snprintf(str, size, "%s-virtual-%x", chip->prefix,
191 chip->addr);
192 case SENSORS_BUS_TYPE_ACPI:
193 return snprintf(str, size, "%s-acpi-%x", chip->prefix,
194 chip->addr);
195 case SENSORS_BUS_TYPE_HID:
196 return snprintf(str, size, "%s-hid-%hd-%x", chip->prefix,
197 chip->bus.nr, chip->addr);
198 }
199
200 return -SENSORS_ERR_CHIP_NAME;
201}
202
203int sensors_parse_bus_id(const char *name, sensors_bus_id *bus)
204{
205 char *endptr;
206
207 if (strncmp(name, "i2c-", 4)) {
208 return -SENSORS_ERR_BUS_NAME;
209 }
210 name += 4;
211 bus->type = SENSORS_BUS_TYPE_I2C;
212 bus->nr = strtoul(name, &endptr, 10);
213 if (*name == '\0' || *endptr != '\0' || bus->nr < 0)
214 return -SENSORS_ERR_BUS_NAME;
215 return 0;
216}
217
218static int sensors_substitute_chip(sensors_chip_name *name,
219 const char *filename, int lineno)
220{
221 int i, j;
222 for (i = 0; i < sensors_config_busses_count; i++)
223 if (sensors_config_busses[i].bus.type == name->bus.type &&
224 sensors_config_busses[i].bus.nr == name->bus.nr)
225 break;
226
227 if (i == sensors_config_busses_count) {
228 sensors_parse_error_wfn("Undeclared bus id referenced",
229 filename, lineno);
230 name->bus.nr = SENSORS_BUS_NR_IGNORE;
231 return -SENSORS_ERR_BUS_NAME;
232 }
233
234 /* Compare the adapter names */
235 for (j = 0; j < sensors_proc_bus_count; j++) {
236 if (!strcmp(sensors_config_busses[i].adapter,
237 sensors_proc_bus[j].adapter)) {
238 name->bus.nr = sensors_proc_bus[j].bus.nr;
239 return 0;
240 }
241 }
242
243 /* We did not find a matching bus name, simply ignore this chip
244 config entry. */
245 name->bus.nr = SENSORS_BUS_NR_IGNORE;
246 return 0;
247}
248
249/* Bus substitution is on a per-configuration file basis, so we keep
250 memory (in sensors_config_chips_subst) of which chip entries have been
251 already substituted. */
252int sensors_substitute_busses(void)
253{
254 int err, i, j, lineno;
255 sensors_chip_name_list *chips;
256 const char *filename;
257 int res = 0;
258
259 for (i = sensors_config_chips_subst;
260 i < sensors_config_chips_count; i++) {
261 filename = sensors_config_chips[i].line.filename;
262 lineno = sensors_config_chips[i].line.lineno;
263 chips = &sensors_config_chips[i].chips;
264 for (j = 0; j < chips->fits_count; j++) {
265 /* We can only substitute if a specific bus number
266 is given. */
267 if (chips->fits[j].bus.nr == SENSORS_BUS_NR_ANY)
268 continue;
269
270 err = sensors_substitute_chip(&chips->fits[j],
271 filename, lineno);
272 if (err)
273 res = err;
274 }
275 }
276 sensors_config_chips_subst = sensors_config_chips_count;
277 return res;
278}
diff --git a/daemon/libsensors/data.h b/daemon/libsensors/data.h
new file mode 100644
index 0000000..4a23eab
--- /dev/null
+++ b/daemon/libsensors/data.h
@@ -0,0 +1,184 @@
1/*
2 data.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007, 2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#ifndef LIB_SENSORS_DATA_H
23#define LIB_SENSORS_DATA_H
24
25#include "sensors.h"
26#include "general.h"
27
28/* This header file contains all kinds of data structures which are used
29 for the representation of the config file data and the sensors
30 data. */
31
32/* Kinds of expression operators recognized */
33typedef enum sensors_operation {
34 sensors_add, sensors_sub, sensors_multiply, sensors_divide,
35 sensors_negate, sensors_exp, sensors_log,
36} sensors_operation;
37
38/* An expression can have several forms */
39typedef enum sensors_expr_kind {
40 sensors_kind_val, sensors_kind_source, sensors_kind_var,
41 sensors_kind_sub
42} sensors_expr_kind;
43
44/* An expression. It is either a floating point value, a variable name,
45 an operation on subexpressions, or the special value 'sub' } */
46struct sensors_expr;
47
48typedef struct sensors_subexpr {
49 sensors_operation op;
50 struct sensors_expr *sub1;
51 struct sensors_expr *sub2;
52} sensors_subexpr;
53
54typedef struct sensors_expr {
55 sensors_expr_kind kind;
56 union {
57 double val;
58 char *var;
59 sensors_subexpr subexpr;
60 } data;
61} sensors_expr;
62
63/* Config file line reference */
64typedef struct sensors_config_line {
65 const char *filename;
66 int lineno;
67} sensors_config_line;
68
69/* Config file label declaration: a feature name, combined with the label
70 value */
71typedef struct sensors_label {
72 char *name;
73 char *value;
74 sensors_config_line line;
75} sensors_label;
76
77/* Config file set declaration: a subfeature name, combined with an
78 expression */
79typedef struct sensors_set {
80 char *name;
81 sensors_expr *value;
82 sensors_config_line line;
83} sensors_set;
84
85/* Config file compute declaration: a feature name, combined with two
86 expressions */
87typedef struct sensors_compute {
88 char *name;
89 sensors_expr *from_proc;
90 sensors_expr *to_proc;
91 sensors_config_line line;
92} sensors_compute;
93
94/* Config file ignore declaration: a feature name */
95typedef struct sensors_ignore {
96 char *name;
97 sensors_config_line line;
98} sensors_ignore;
99
100/* A list of chip names, used to represent a config file chips declaration */
101typedef struct sensors_chip_name_list {
102 sensors_chip_name *fits;
103 int fits_count;
104 int fits_max;
105} sensors_chip_name_list;
106
107/* A config file chip block */
108typedef struct sensors_chip {
109 sensors_chip_name_list chips;
110 sensors_label *labels;
111 int labels_count;
112 int labels_max;
113 sensors_set *sets;
114 int sets_count;
115 int sets_max;
116 sensors_compute *computes;
117 int computes_count;
118 int computes_max;
119 sensors_ignore *ignores;
120 int ignores_count;
121 int ignores_max;
122 sensors_config_line line;
123} sensors_chip;
124
125/* Config file bus declaration: the bus type and number, combined with adapter
126 name */
127typedef struct sensors_bus {
128 char *adapter;
129 sensors_bus_id bus;
130 sensors_config_line line;
131} sensors_bus;
132
133/* Internal data about all features and subfeatures of a chip */
134typedef struct sensors_chip_features {
135 struct sensors_chip_name chip;
136 struct sensors_feature *feature;
137 struct sensors_subfeature *subfeature;
138 int feature_count;
139 int subfeature_count;
140} sensors_chip_features;
141
142extern char **sensors_config_files;
143extern int sensors_config_files_count;
144extern int sensors_config_files_max;
145
146#define sensors_add_config_files(el) sensors_add_array_el( \
147 (el), &sensors_config_files, &sensors_config_files_count, \
148 &sensors_config_files_max, sizeof(char *))
149
150extern sensors_chip *sensors_config_chips;
151extern int sensors_config_chips_count;
152extern int sensors_config_chips_subst;
153extern int sensors_config_chips_max;
154
155extern sensors_bus *sensors_config_busses;
156extern int sensors_config_busses_count;
157extern int sensors_config_busses_max;
158
159extern sensors_chip_features *sensors_proc_chips;
160extern int sensors_proc_chips_count;
161extern int sensors_proc_chips_max;
162
163#define sensors_add_proc_chips(el) sensors_add_array_el( \
164 (el), &sensors_proc_chips, &sensors_proc_chips_count,\
165 &sensors_proc_chips_max, sizeof(struct sensors_chip_features))
166
167extern sensors_bus *sensors_proc_bus;
168extern int sensors_proc_bus_count;
169extern int sensors_proc_bus_max;
170
171#define sensors_add_proc_bus(el) sensors_add_array_el( \
172 (el), &sensors_proc_bus, &sensors_proc_bus_count,\
173 &sensors_proc_bus_max, sizeof(struct sensors_bus))
174
175/* Substitute configuration bus numbers with real-world bus numbers
176 in the chips lists */
177int sensors_substitute_busses(void);
178
179
180/* Parse a bus id into its components. Returns 0 on success, a value from
181 error.h on failure. */
182int sensors_parse_bus_id(const char *name, sensors_bus_id *bus);
183
184#endif /* def LIB_SENSORS_DATA_H */
diff --git a/daemon/libsensors/error.c b/daemon/libsensors/error.c
new file mode 100644
index 0000000..55bde81
--- /dev/null
+++ b/daemon/libsensors/error.c
@@ -0,0 +1,92 @@
1/*
2 error.c - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007-2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#include <stdlib.h>
23#include <stdio.h>
24#include "error.h"
25#include "general.h"
26
27static void sensors_default_parse_error(const char *err, int lineno);
28static void sensors_default_parse_error_wfn(const char *err,
29 const char *filename, int lineno);
30static void sensors_default_fatal_error(const char *proc, const char *err);
31
32void (*sensors_parse_error) (const char *err, int lineno) =
33 sensors_default_parse_error;
34void (*sensors_parse_error_wfn) (const char *err, const char *filename,
35 int lineno) = sensors_default_parse_error_wfn;
36void (*sensors_fatal_error) (const char *proc, const char *err) =
37 sensors_default_fatal_error;
38
39static const char *errorlist[] = {
40 /* Invalid error code */ "Unknown error",
41 /* SENSORS_ERR_WILDCARDS */ "Wildcard found in chip name",
42 /* SENSORS_ERR_NO_ENTRY */ "No such subfeature known",
43 /* SENSORS_ERR_ACCESS_R */ "Can't read",
44 /* SENSORS_ERR_KERNEL */ "Kernel interface error",
45 /* SENSORS_ERR_DIV_ZERO */ "Divide by zero",
46 /* SENSORS_ERR_CHIP_NAME */ "Can't parse chip name",
47 /* SENSORS_ERR_BUS_NAME */ "Can't parse bus name",
48 /* SENSORS_ERR_PARSE */ "General parse error",
49 /* SENSORS_ERR_ACCESS_W */ "Can't write",
50 /* SENSORS_ERR_IO */ "I/O error",
51 /* SENSORS_ERR_RECURSION */ "Evaluation recurses too deep",
52};
53
54const char *sensors_strerror(int errnum)
55{
56 if (errnum < 0)
57 errnum = -errnum;
58 if (errnum >= ARRAY_SIZE(errorlist))
59 errnum = 0;
60 return errorlist[errnum];
61}
62
63void sensors_default_parse_error(const char *err, int lineno)
64{
65 if (lineno)
66 fprintf(stderr, "Error: Line %d: %s\n", lineno, err);
67 else
68 fprintf(stderr, "Error: %s\n", err);
69}
70
71void sensors_default_parse_error_wfn(const char *err,
72 const char *filename, int lineno)
73{
74 /* If application provided a custom parse error reporting function
75 but not the variant with the filename, fall back to the original
76 variant without the filename, for backwards compatibility. */
77 if (sensors_parse_error != sensors_default_parse_error ||
78 !filename)
79 return sensors_parse_error(err, lineno);
80
81 if (lineno)
82 fprintf(stderr, "Error: File %s, line %d: %s\n", filename,
83 lineno, err);
84 else
85 fprintf(stderr, "Error: File %s: %s\n", filename, err);
86}
87
88void sensors_default_fatal_error(const char *proc, const char *err)
89{
90 fprintf(stderr, "Fatal error in `%s': %s\n", proc, err);
91 exit(1);
92}
diff --git a/daemon/libsensors/error.h b/daemon/libsensors/error.h
new file mode 100644
index 0000000..37cdc95
--- /dev/null
+++ b/daemon/libsensors/error.h
@@ -0,0 +1,74 @@
1/*
2 error.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007-2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#ifndef LIB_SENSORS_ERROR_H
23#define LIB_SENSORS_ERROR_H
24
25#define SENSORS_ERR_WILDCARDS 1 /* Wildcard found in chip name */
26#define SENSORS_ERR_NO_ENTRY 2 /* No such subfeature known */
27#define SENSORS_ERR_ACCESS_R 3 /* Can't read */
28#define SENSORS_ERR_KERNEL 4 /* Kernel interface error */
29#define SENSORS_ERR_DIV_ZERO 5 /* Divide by zero */
30#define SENSORS_ERR_CHIP_NAME 6 /* Can't parse chip name */
31#define SENSORS_ERR_BUS_NAME 7 /* Can't parse bus name */
32#define SENSORS_ERR_PARSE 8 /* General parse error */
33#define SENSORS_ERR_ACCESS_W 9 /* Can't write */
34#define SENSORS_ERR_IO 10 /* I/O error */
35#define SENSORS_ERR_RECURSION 11 /* Evaluation recurses too deep */
36
37#ifdef __cplusplus
38extern "C" {
39#endif /* __cplusplus */
40
41
42/* This function returns a pointer to a string which describes the error.
43 errnum may be negative (the corresponding positive error is returned).
44 You may not modify the result! */
45const char *sensors_strerror(int errnum);
46
47/* These functions are called when a parse error is detected. Give them new
48 values, and your own functions are called instead of the default (which
49 print to stderr). These functions may terminate the program, but they
50 usually output an error and return. The first function is the original
51 one, the second one was added later when support for multiple
52 configuration files was added.
53 The library code now only calls the second function. However, for
54 backwards compatibility, if an application provides a custom handling
55 function for the first function but not the second, then all parse
56 errors will be reported using the first function (that is, the filename
57 is never reported.)
58 Note that filename can be NULL (if filename isn't known) and lineno
59 can be 0 (if the error occurs before the actual parsing starts.) */
60extern void (*sensors_parse_error) (const char *err, int lineno);
61extern void (*sensors_parse_error_wfn) (const char *err,
62 const char *filename, int lineno);
63
64/* This function is called when an immediately fatal error (like no
65 memory left) is detected. Give it a new value, and your own function
66 is called instead of the default (which prints to stderr and ends
67 the program). Never let it return! */
68extern void (*sensors_fatal_error) (const char *proc, const char *err);
69
70#ifdef __cplusplus
71}
72#endif /* __cplusplus */
73
74#endif /* def LIB_SENSORS_ERROR_H */
diff --git a/daemon/libsensors/general.c b/daemon/libsensors/general.c
new file mode 100644
index 0000000..f237e3b
--- /dev/null
+++ b/daemon/libsensors/general.c
@@ -0,0 +1,85 @@
1/*
2 general.c - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 MA 02110-1301 USA.
19*/
20
21#include "error.h"
22#include "general.h"
23#include <errno.h>
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27
28
29#define A_BUNCH 16
30
31void sensors_malloc_array(void *list, int *num_el, int *max_el, int el_size)
32{
33 void **my_list = (void **)list;
34
35 *my_list = malloc(el_size*A_BUNCH);
36 if (! *my_list)
37 sensors_fatal_error(__func__, "Allocating new elements");
38 *max_el = A_BUNCH;
39 *num_el = 0;
40}
41
42void sensors_free_array(void *list, int *num_el, int *max_el)
43{
44 void **my_list = (void **)list;
45
46 free(*my_list);
47 *my_list = NULL;
48 *num_el = 0;
49 *max_el = 0;
50}
51
52void sensors_add_array_el(const void *el, void *list, int *num_el,
53 int *max_el, int el_size)
54{
55 int new_max_el;
56 void **my_list = (void *)list;
57 if (*num_el + 1 > *max_el) {
58 new_max_el = *max_el + A_BUNCH;
59 *my_list = realloc(*my_list, new_max_el * el_size);
60 if (! *my_list)
61 sensors_fatal_error(__func__,
62 "Allocating new elements");
63 *max_el = new_max_el;
64 }
65 memcpy(((char *) *my_list) + *num_el * el_size, el, el_size);
66 (*num_el) ++;
67}
68
69void sensors_add_array_els(const void *els, int nr_els, void *list,
70 int *num_el, int *max_el, int el_size)
71{
72 int new_max_el;
73 void **my_list = (void *)list;
74 if (*num_el + nr_els > *max_el) {
75 new_max_el = (*max_el + nr_els + A_BUNCH);
76 new_max_el -= new_max_el % A_BUNCH;
77 *my_list = realloc(*my_list, new_max_el * el_size);
78 if (! *my_list)
79 sensors_fatal_error(__func__,
80 "Allocating new elements");
81 *max_el = new_max_el;
82 }
83 memcpy(((char *)*my_list) + *num_el * el_size, els, el_size * nr_els);
84 *num_el += nr_els;
85}
diff --git a/daemon/libsensors/general.h b/daemon/libsensors/general.h
new file mode 100644
index 0000000..a3971e0
--- /dev/null
+++ b/daemon/libsensors/general.h
@@ -0,0 +1,39 @@
1/*
2 general.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 MA 02110-1301 USA.
19*/
20
21#ifndef LIB_SENSORS_GENERAL
22#define LIB_SENSORS_GENERAL
23
24/* These are general purpose functions. They allow you to use variable-
25 length arrays, which are extended automatically. A distinction is
26 made between the current number of elements and the maximum number.
27 You can only add elements at the end. Primitive, but very useful
28 for internal use. */
29void sensors_malloc_array(void *list, int *num_el, int *max_el,
30 int el_size);
31void sensors_free_array(void *list, int *num_el, int *max_el);
32void sensors_add_array_el(const void *el, void *list, int *num_el,
33 int *max_el, int el_size);
34void sensors_add_array_els(const void *els, int nr_els, void *list,
35 int *num_el, int *max_el, int el_size);
36
37#define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0]))
38
39#endif /* LIB_SENSORS_GENERAL */
diff --git a/daemon/libsensors/init.c b/daemon/libsensors/init.c
new file mode 100644
index 0000000..558046e
--- /dev/null
+++ b/daemon/libsensors/init.c
@@ -0,0 +1,341 @@
1/*
2 init.c - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007, 2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22/*** This file modified by ARM on Jan 23, 2013 to cast alphasort to supress a warning as it's prototype is different on android. ***/
23
24/* Needed for scandir() and alphasort() */
25#define _BSD_SOURCE
26
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <locale.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <string.h>
33#include <errno.h>
34#include <dirent.h>
35#include <unistd.h>
36#include "sensors.h"
37#include "data.h"
38#include "error.h"
39#include "access.h"
40#include "conf.h"
41#include "sysfs.h"
42#include "scanner.h"
43#include "init.h"
44
45#define DEFAULT_CONFIG_FILE ETCDIR "/sensors3.conf"
46#define ALT_CONFIG_FILE ETCDIR "/sensors.conf"
47#define DEFAULT_CONFIG_DIR ETCDIR "/sensors.d"
48
49/* Wrapper around sensors_yyparse(), which clears the locale so that
50 the decimal numbers are always parsed properly. */
51static int sensors_parse(void)
52{
53 int res;
54 char *locale;
55
56 /* Remember the current locale and clear it */
57 locale = setlocale(LC_ALL, NULL);
58 if (locale) {
59 locale = strdup(locale);
60 if (!locale)
61 sensors_fatal_error(__func__, "Out of memory");
62
63 setlocale(LC_ALL, "C");
64 }
65
66 res = sensors_yyparse();
67
68 /* Restore the old locale */
69 if (locale) {
70 setlocale(LC_ALL, locale);
71 free(locale);
72 }
73
74 return res;
75}
76
77static void free_bus(sensors_bus *bus)
78{
79 free(bus->adapter);
80}
81
82static void free_config_busses(void)
83{
84 int i;
85
86 for (i = 0; i < sensors_config_busses_count; i++)
87 free_bus(&sensors_config_busses[i]);
88 free(sensors_config_busses);
89 sensors_config_busses = NULL;
90 sensors_config_busses_count = sensors_config_busses_max = 0;
91}
92
93static int parse_config(FILE *input, const char *name)
94{
95 int err;
96 char *name_copy;
97
98 if (name) {
99 /* Record configuration file name for error reporting */
100 name_copy = strdup(name);
101 if (!name_copy)
102 sensors_fatal_error(__func__, "Out of memory");
103 sensors_add_config_files(&name_copy);
104 } else
105 name_copy = NULL;
106
107 if (sensors_scanner_init(input, name_copy)) {
108 err = -SENSORS_ERR_PARSE;
109 goto exit_cleanup;
110 }
111 err = sensors_parse();
112 sensors_scanner_exit();
113 if (err) {
114 err = -SENSORS_ERR_PARSE;
115 goto exit_cleanup;
116 }
117
118 err = sensors_substitute_busses();
119
120exit_cleanup:
121 free_config_busses();
122 return err;
123}
124
125static int config_file_filter(const struct dirent *entry)
126{
127 return entry->d_name[0] != '.'; /* Skip hidden files */
128}
129
130static int add_config_from_dir(const char *dir)
131{
132 int count, res, i;
133 struct dirent **namelist;
134
135 count = scandir(dir, &namelist, config_file_filter, (int (*)(const struct dirent **, const struct dirent **))alphasort);
136 if (count < 0) {
137 /* Do not return an error if directory does not exist */
138 if (errno == ENOENT)
139 return 0;
140
141 sensors_parse_error_wfn(strerror(errno), NULL, 0);
142 return -SENSORS_ERR_PARSE;
143 }
144
145 for (res = 0, i = 0; !res && i < count; i++) {
146 int len;
147 char path[PATH_MAX];
148 FILE *input;
149 struct stat st;
150
151 len = snprintf(path, sizeof(path), "%s/%s", dir,
152 namelist[i]->d_name);
153 if (len < 0 || len >= (int)sizeof(path)) {
154 res = -SENSORS_ERR_PARSE;
155 continue;
156 }
157
158 /* Only accept regular files */
159 if (stat(path, &st) < 0 || !S_ISREG(st.st_mode))
160 continue;
161
162 input = fopen(path, "r");
163 if (input) {
164 res = parse_config(input, path);
165 fclose(input);
166 } else {
167 res = -SENSORS_ERR_PARSE;
168 sensors_parse_error_wfn(strerror(errno), path, 0);
169 }
170 }
171
172 /* Free memory allocated by scandir() */
173 for (i = 0; i < count; i++)
174 free(namelist[i]);
175 free(namelist);
176
177 return res;
178}
179
180int sensors_init(FILE *input)
181{
182 int res;
183
184 if (!sensors_init_sysfs())
185 return -SENSORS_ERR_KERNEL;
186 if ((res = sensors_read_sysfs_bus()) ||
187 (res = sensors_read_sysfs_chips()))
188 goto exit_cleanup;
189
190 if (input) {
191 res = parse_config(input, NULL);
192 if (res)
193 goto exit_cleanup;
194 } else {
195 const char* name;
196
197 /* No configuration provided, use default */
198 input = fopen(name = DEFAULT_CONFIG_FILE, "r");
199 if (!input && errno == ENOENT)
200 input = fopen(name = ALT_CONFIG_FILE, "r");
201 if (input) {
202 res = parse_config(input, name);
203 fclose(input);
204 if (res)
205 goto exit_cleanup;
206
207 } else if (errno != ENOENT) {
208 sensors_parse_error_wfn(strerror(errno), name, 0);
209 res = -SENSORS_ERR_PARSE;
210 goto exit_cleanup;
211 }
212
213 /* Also check for files in default directory */
214 res = add_config_from_dir(DEFAULT_CONFIG_DIR);
215 if (res)
216 goto exit_cleanup;
217 }
218
219 return 0;
220
221exit_cleanup:
222 sensors_cleanup();
223 return res;
224}
225
226static void free_chip_name(sensors_chip_name *name)
227{
228 free(name->prefix);
229 free(name->path);
230}
231
232static void free_chip_features(sensors_chip_features *features)
233{
234 int i;
235
236 for (i = 0; i < features->subfeature_count; i++)
237 free(features->subfeature[i].name);
238 free(features->subfeature);
239 for (i = 0; i < features->feature_count; i++)
240 free(features->feature[i].name);
241 free(features->feature);
242}
243
244static void free_label(sensors_label *label)
245{
246 free(label->name);
247 free(label->value);
248}
249
250void sensors_free_expr(sensors_expr *expr)
251{
252 if (expr->kind == sensors_kind_var)
253 free(expr->data.var);
254 else if (expr->kind == sensors_kind_sub) {
255 if (expr->data.subexpr.sub1)
256 sensors_free_expr(expr->data.subexpr.sub1);
257 if (expr->data.subexpr.sub2)
258 sensors_free_expr(expr->data.subexpr.sub2);
259 }
260 free(expr);
261}
262
263static void free_set(sensors_set *set)
264{
265 free(set->name);
266 sensors_free_expr(set->value);
267}
268
269static void free_compute(sensors_compute *compute)
270{
271 free(compute->name);
272 sensors_free_expr(compute->from_proc);
273 sensors_free_expr(compute->to_proc);
274}
275
276static void free_ignore(sensors_ignore *ignore)
277{
278 free(ignore->name);
279}
280
281static void free_chip(sensors_chip *chip)
282{
283 int i;
284
285 for (i = 0; i < chip->chips.fits_count; i++)
286 free_chip_name(&chip->chips.fits[i]);
287 free(chip->chips.fits);
288 chip->chips.fits_count = chip->chips.fits_max = 0;
289
290 for (i = 0; i < chip->labels_count; i++)
291 free_label(&chip->labels[i]);
292 free(chip->labels);
293 chip->labels_count = chip->labels_max = 0;
294
295 for (i = 0; i < chip->sets_count; i++)
296 free_set(&chip->sets[i]);
297 free(chip->sets);
298 chip->sets_count = chip->sets_max = 0;
299
300 for (i = 0; i < chip->computes_count; i++)
301 free_compute(&chip->computes[i]);
302 free(chip->computes);
303 chip->computes_count = chip->computes_max = 0;
304
305 for (i = 0; i < chip->ignores_count; i++)
306 free_ignore(&chip->ignores[i]);
307 free(chip->ignores);
308 chip->ignores_count = chip->ignores_max = 0;
309}
310
311void sensors_cleanup(void)
312{
313 int i;
314
315 for (i = 0; i < sensors_proc_chips_count; i++) {
316 free_chip_name(&sensors_proc_chips[i].chip);
317 free_chip_features(&sensors_proc_chips[i]);
318 }
319 free(sensors_proc_chips);
320 sensors_proc_chips = NULL;
321 sensors_proc_chips_count = sensors_proc_chips_max = 0;
322
323 for (i = 0; i < sensors_config_chips_count; i++)
324 free_chip(&sensors_config_chips[i]);
325 free(sensors_config_chips);
326 sensors_config_chips = NULL;
327 sensors_config_chips_count = sensors_config_chips_max = 0;
328 sensors_config_chips_subst = 0;
329
330 for (i = 0; i < sensors_proc_bus_count; i++)
331 free_bus(&sensors_proc_bus[i]);
332 free(sensors_proc_bus);
333 sensors_proc_bus = NULL;
334 sensors_proc_bus_count = sensors_proc_bus_max = 0;
335
336 for (i = 0; i < sensors_config_files_count; i++)
337 free(sensors_config_files[i]);
338 free(sensors_config_files);
339 sensors_config_files = NULL;
340 sensors_config_files_count = sensors_config_files_max = 0;
341}
diff --git a/daemon/libsensors/init.h b/daemon/libsensors/init.h
new file mode 100644
index 0000000..47006a6
--- /dev/null
+++ b/daemon/libsensors/init.h
@@ -0,0 +1,28 @@
1/*
2 init.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 MA 02110-1301 USA.
19*/
20
21#ifndef LIB_SENSORS_INIT_H
22#define LIB_SENSORS_INIT_H
23
24#include "data.h"
25
26void sensors_free_expr(sensors_expr *expr);
27
28#endif /* def LIB_SENSORS_INIT_H */
diff --git a/daemon/libsensors/scanner.h b/daemon/libsensors/scanner.h
new file mode 100644
index 0000000..4c41516
--- /dev/null
+++ b/daemon/libsensors/scanner.h
@@ -0,0 +1,32 @@
1/*
2 scanner.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 2006 Mark M. Hoffman <mhoffman@lightlink.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 MA 02110-1301 USA.
19*/
20
21/*** This file modified by ARM on Jan 23, 2013 to fix input defined but not used warning from conf-lex.c. ***/
22
23#ifndef LIB_SENSORS_SCANNER_H
24#define LIB_SENSORS_SCANNER_H
25
26int sensors_scanner_init(FILE *input, const char *filename);
27void sensors_scanner_exit(void);
28
29#define YY_NO_INPUT
30
31#endif
32
diff --git a/daemon/libsensors/sensors.h b/daemon/libsensors/sensors.h
new file mode 100644
index 0000000..7874d02
--- /dev/null
+++ b/daemon/libsensors/sensors.h
@@ -0,0 +1,311 @@
1/*
2 sensors.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007, 2010 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22/*** This file modified by ARM on Jan 23, 2013 to read non-scaled values. ***/
23
24#ifndef LIB_SENSORS_SENSORS_H
25#define LIB_SENSORS_SENSORS_H
26
27#include <stdio.h>
28#include <limits.h>
29
30/* Publicly accessible library functions */
31
32/* libsensors API version define, first digit is the major version (changed
33 when the API + ABI breaks), the third digit is incremented to track small
34 API additions like new flags / enum values. The second digit is for tracking
35 larger additions like new methods. */
36#define SENSORS_API_VERSION 0x432
37
38#define SENSORS_CHIP_NAME_PREFIX_ANY NULL
39#define SENSORS_CHIP_NAME_ADDR_ANY (-1)
40
41#define SENSORS_BUS_TYPE_ANY (-1)
42#define SENSORS_BUS_TYPE_I2C 0
43#define SENSORS_BUS_TYPE_ISA 1
44#define SENSORS_BUS_TYPE_PCI 2
45#define SENSORS_BUS_TYPE_SPI 3
46#define SENSORS_BUS_TYPE_VIRTUAL 4
47#define SENSORS_BUS_TYPE_ACPI 5
48#define SENSORS_BUS_TYPE_HID 6
49#define SENSORS_BUS_NR_ANY (-1)
50#define SENSORS_BUS_NR_IGNORE (-2)
51
52#ifdef __cplusplus
53extern "C" {
54#endif /* __cplusplus */
55
56extern const char *libsensors_version;
57
58extern int sensors_sysfs_no_scaling;
59
60typedef struct sensors_bus_id {
61 short type;
62 short nr;
63} sensors_bus_id;
64
65/* A chip name is encoded in this structure */
66typedef struct sensors_chip_name {
67 char *prefix;
68 sensors_bus_id bus;
69 int addr;
70 char *path;
71} sensors_chip_name;
72
73/* Load the configuration file and the detected chips list. If this
74 returns a value unequal to zero, you are in trouble; you can not
75 assume anything will be initialized properly. If you want to
76 reload the configuration file, call sensors_cleanup() below before
77 calling sensors_init() again. */
78int sensors_init(FILE *input);
79
80/* Clean-up function: You can't access anything after
81 this, until the next sensors_init() call! */
82void sensors_cleanup(void);
83
84/* Parse a chip name to the internal representation. Return 0 on success, <0
85 on error. */
86int sensors_parse_chip_name(const char *orig_name, sensors_chip_name *res);
87
88/* Free memory allocated for the internal representation of a chip name. */
89void sensors_free_chip_name(sensors_chip_name *chip);
90
91/* Print a chip name from its internal representation. Note that chip should
92 not contain wildcard values! Return the number of characters printed on
93 success (same as snprintf), <0 on error. */
94int sensors_snprintf_chip_name(char *str, size_t size,
95 const sensors_chip_name *chip);
96
97/* This function returns the adapter name of a bus,
98 as used within the sensors_chip_name structure. If it could not be found,
99 it returns NULL */
100const char *sensors_get_adapter_name(const sensors_bus_id *bus);
101
102typedef struct sensors_feature sensors_feature;
103
104/* Look up the label for a given feature. Note that chip should not
105 contain wildcard values! The returned string is newly allocated (free it
106 yourself). On failure, NULL is returned.
107 If no label exists for this feature, its name is returned itself. */
108char *sensors_get_label(const sensors_chip_name *name,
109 const sensors_feature *feature);
110
111/* Read the value of a subfeature of a certain chip. Note that chip should not
112 contain wildcard values! This function will return 0 on success, and <0
113 on failure. */
114int sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
115 double *value);
116
117/* Set the value of a subfeature of a certain chip. Note that chip should not
118 contain wildcard values! This function will return 0 on success, and <0
119 on failure. */
120int sensors_set_value(const sensors_chip_name *name, int subfeat_nr,
121 double value);
122
123/* Execute all set statements for this particular chip. The chip may contain
124 wildcards! This function will return 0 on success, and <0 on failure. */
125int sensors_do_chip_sets(const sensors_chip_name *name);
126
127/* This function returns all detected chips that match a given chip name,
128 one by one. If no chip name is provided, all detected chips are returned.
129 To start at the beginning of the list, use 0 for nr; NULL is returned if
130 we are at the end of the list. Do not try to change these chip names, as
131 they point to internal structures! */
132const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
133 *match, int *nr);
134
135/* These defines are used in the flags field of sensors_subfeature */
136#define SENSORS_MODE_R 1
137#define SENSORS_MODE_W 2
138#define SENSORS_COMPUTE_MAPPING 4
139
140typedef enum sensors_feature_type {
141 SENSORS_FEATURE_IN = 0x00,
142 SENSORS_FEATURE_FAN = 0x01,
143 SENSORS_FEATURE_TEMP = 0x02,
144 SENSORS_FEATURE_POWER = 0x03,
145 SENSORS_FEATURE_ENERGY = 0x04,
146 SENSORS_FEATURE_CURR = 0x05,
147 SENSORS_FEATURE_HUMIDITY = 0x06,
148 SENSORS_FEATURE_MAX_MAIN,
149 SENSORS_FEATURE_VID = 0x10,
150 SENSORS_FEATURE_INTRUSION = 0x11,
151 SENSORS_FEATURE_MAX_OTHER,
152 SENSORS_FEATURE_BEEP_ENABLE = 0x18,
153 SENSORS_FEATURE_UNKNOWN = INT_MAX,
154} sensors_feature_type;
155
156/* All the sensor types (in, fan, temp, vid) are a multiple of 0x100 apart,
157 and sensor subfeatures which have no compute mapping have bit 7 set. */
158typedef enum sensors_subfeature_type {
159 SENSORS_SUBFEATURE_IN_INPUT = SENSORS_FEATURE_IN << 8,
160 SENSORS_SUBFEATURE_IN_MIN,
161 SENSORS_SUBFEATURE_IN_MAX,
162 SENSORS_SUBFEATURE_IN_LCRIT,
163 SENSORS_SUBFEATURE_IN_CRIT,
164 SENSORS_SUBFEATURE_IN_AVERAGE,
165 SENSORS_SUBFEATURE_IN_LOWEST,
166 SENSORS_SUBFEATURE_IN_HIGHEST,
167 SENSORS_SUBFEATURE_IN_ALARM = (SENSORS_FEATURE_IN << 8) | 0x80,
168 SENSORS_SUBFEATURE_IN_MIN_ALARM,
169 SENSORS_SUBFEATURE_IN_MAX_ALARM,
170 SENSORS_SUBFEATURE_IN_BEEP,
171 SENSORS_SUBFEATURE_IN_LCRIT_ALARM,
172 SENSORS_SUBFEATURE_IN_CRIT_ALARM,
173
174 SENSORS_SUBFEATURE_FAN_INPUT = SENSORS_FEATURE_FAN << 8,
175 SENSORS_SUBFEATURE_FAN_MIN,
176 SENSORS_SUBFEATURE_FAN_MAX,
177 SENSORS_SUBFEATURE_FAN_ALARM = (SENSORS_FEATURE_FAN << 8) | 0x80,
178 SENSORS_SUBFEATURE_FAN_FAULT,
179 SENSORS_SUBFEATURE_FAN_DIV,
180 SENSORS_SUBFEATURE_FAN_BEEP,
181 SENSORS_SUBFEATURE_FAN_PULSES,
182 SENSORS_SUBFEATURE_FAN_MIN_ALARM,
183 SENSORS_SUBFEATURE_FAN_MAX_ALARM,
184
185 SENSORS_SUBFEATURE_TEMP_INPUT = SENSORS_FEATURE_TEMP << 8,
186 SENSORS_SUBFEATURE_TEMP_MAX,
187 SENSORS_SUBFEATURE_TEMP_MAX_HYST,
188 SENSORS_SUBFEATURE_TEMP_MIN,
189 SENSORS_SUBFEATURE_TEMP_CRIT,
190 SENSORS_SUBFEATURE_TEMP_CRIT_HYST,
191 SENSORS_SUBFEATURE_TEMP_LCRIT,
192 SENSORS_SUBFEATURE_TEMP_EMERGENCY,
193 SENSORS_SUBFEATURE_TEMP_EMERGENCY_HYST,
194 SENSORS_SUBFEATURE_TEMP_LOWEST,
195 SENSORS_SUBFEATURE_TEMP_HIGHEST,
196 SENSORS_SUBFEATURE_TEMP_ALARM = (SENSORS_FEATURE_TEMP << 8) | 0x80,
197 SENSORS_SUBFEATURE_TEMP_MAX_ALARM,
198 SENSORS_SUBFEATURE_TEMP_MIN_ALARM,
199 SENSORS_SUBFEATURE_TEMP_CRIT_ALARM,
200 SENSORS_SUBFEATURE_TEMP_FAULT,
201 SENSORS_SUBFEATURE_TEMP_TYPE,
202 SENSORS_SUBFEATURE_TEMP_OFFSET,
203 SENSORS_SUBFEATURE_TEMP_BEEP,
204 SENSORS_SUBFEATURE_TEMP_EMERGENCY_ALARM,
205 SENSORS_SUBFEATURE_TEMP_LCRIT_ALARM,
206
207 SENSORS_SUBFEATURE_POWER_AVERAGE = SENSORS_FEATURE_POWER << 8,
208 SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST,
209 SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST,
210 SENSORS_SUBFEATURE_POWER_INPUT,
211 SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST,
212 SENSORS_SUBFEATURE_POWER_INPUT_LOWEST,
213 SENSORS_SUBFEATURE_POWER_CAP,
214 SENSORS_SUBFEATURE_POWER_CAP_HYST,
215 SENSORS_SUBFEATURE_POWER_MAX,
216 SENSORS_SUBFEATURE_POWER_CRIT,
217 SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL = (SENSORS_FEATURE_POWER << 8) | 0x80,
218 SENSORS_SUBFEATURE_POWER_ALARM,
219 SENSORS_SUBFEATURE_POWER_CAP_ALARM,
220 SENSORS_SUBFEATURE_POWER_MAX_ALARM,
221 SENSORS_SUBFEATURE_POWER_CRIT_ALARM,
222
223 SENSORS_SUBFEATURE_ENERGY_INPUT = SENSORS_FEATURE_ENERGY << 8,
224
225 SENSORS_SUBFEATURE_CURR_INPUT = SENSORS_FEATURE_CURR << 8,
226 SENSORS_SUBFEATURE_CURR_MIN,
227 SENSORS_SUBFEATURE_CURR_MAX,
228 SENSORS_SUBFEATURE_CURR_LCRIT,
229 SENSORS_SUBFEATURE_CURR_CRIT,
230 SENSORS_SUBFEATURE_CURR_AVERAGE,
231 SENSORS_SUBFEATURE_CURR_LOWEST,
232 SENSORS_SUBFEATURE_CURR_HIGHEST,
233 SENSORS_SUBFEATURE_CURR_ALARM = (SENSORS_FEATURE_CURR << 8) | 0x80,
234 SENSORS_SUBFEATURE_CURR_MIN_ALARM,
235 SENSORS_SUBFEATURE_CURR_MAX_ALARM,
236 SENSORS_SUBFEATURE_CURR_BEEP,
237 SENSORS_SUBFEATURE_CURR_LCRIT_ALARM,
238 SENSORS_SUBFEATURE_CURR_CRIT_ALARM,
239
240 SENSORS_SUBFEATURE_HUMIDITY_INPUT = SENSORS_FEATURE_HUMIDITY << 8,
241
242 SENSORS_SUBFEATURE_VID = SENSORS_FEATURE_VID << 8,
243
244 SENSORS_SUBFEATURE_INTRUSION_ALARM = SENSORS_FEATURE_INTRUSION << 8,
245 SENSORS_SUBFEATURE_INTRUSION_BEEP,
246
247 SENSORS_SUBFEATURE_BEEP_ENABLE = SENSORS_FEATURE_BEEP_ENABLE << 8,
248
249 SENSORS_SUBFEATURE_UNKNOWN = INT_MAX,
250} sensors_subfeature_type;
251
252/* Data about a single chip feature (or category leader) */
253struct sensors_feature {
254 char *name;
255 int number;
256 sensors_feature_type type;
257 /* Members below are for libsensors internal use only */
258 int first_subfeature;
259 int padding1;
260};
261
262/* Data about a single chip subfeature:
263 name is the string name used to refer to this subfeature (in config files)
264 number is the internal subfeature number, used in many functions to refer
265 to this subfeature
266 type is the subfeature type
267 mapping is the number of a main feature this subfeature belongs to
268 (for example subfeatures fan1_input, fan1_min, fan1_div and fan1_alarm
269 are mapped to main feature fan1)
270 flags is a bitfield, its value is a combination of SENSORS_MODE_R (readable),
271 SENSORS_MODE_W (writable) and SENSORS_COMPUTE_MAPPING (affected by the
272 computation rules of the main feature) */
273typedef struct sensors_subfeature {
274 char *name;
275 int number;
276 sensors_subfeature_type type;
277 int mapping;
278 unsigned int flags;
279} sensors_subfeature;
280
281/* This returns all main features of a specific chip. nr is an internally
282 used variable. Set it to zero to start at the begin of the list. If no
283 more features are found NULL is returned.
284 Do not try to change the returned structure; you will corrupt internal
285 data structures. */
286const sensors_feature *
287sensors_get_features(const sensors_chip_name *name, int *nr);
288
289/* This returns all subfeatures of a given main feature. nr is an internally
290 used variable. Set it to zero to start at the begin of the list. If no
291 more features are found NULL is returned.
292 Do not try to change the returned structure; you will corrupt internal
293 data structures. */
294const sensors_subfeature *
295sensors_get_all_subfeatures(const sensors_chip_name *name,
296 const sensors_feature *feature, int *nr);
297
298/* This returns the subfeature of the given type for a given main feature,
299 if it exists, NULL otherwise.
300 Do not try to change the returned structure; you will corrupt internal
301 data structures. */
302const sensors_subfeature *
303sensors_get_subfeature(const sensors_chip_name *name,
304 const sensors_feature *feature,
305 sensors_subfeature_type type);
306
307#ifdef __cplusplus
308}
309#endif /* __cplusplus */
310
311#endif /* def LIB_SENSORS_ERROR_H */
diff --git a/daemon/libsensors/sysfs.c b/daemon/libsensors/sysfs.c
new file mode 100644
index 0000000..2b494c9
--- /dev/null
+++ b/daemon/libsensors/sysfs.c
@@ -0,0 +1,926 @@
1/*
2 sysfs.c - Part of libsensors, a library for reading Linux sensor data
3 Copyright (c) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
4 Copyright (C) 2007-2010 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22/*** This file modified by ARM on Jan 23, 2013 to improve performance by substituting calls to fread() with calls to read() and to read non-scaled values. ***/
23
24/* this define needed for strndup() */
25#define _GNU_SOURCE
26
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/vfs.h>
30#include <unistd.h>
31#include <string.h>
32#include <stdlib.h>
33#include <limits.h>
34#include <errno.h>
35#include <dirent.h>
36#include <fcntl.h>
37#include "data.h"
38#include "error.h"
39#include "access.h"
40#include "general.h"
41#include "sysfs.h"
42
43
44/****************************************************************************/
45
46#define ATTR_MAX 128
47#define SYSFS_MAGIC 0x62656572
48
49int sensors_sysfs_no_scaling;
50
51/*
52 * Read an attribute from sysfs
53 * Returns a pointer to a freshly allocated string; free it yourself.
54 * If the file doesn't exist or can't be read, NULL is returned.
55 */
56static char *sysfs_read_attr(const char *device, const char *attr)
57{
58 char path[NAME_MAX];
59 char buf[ATTR_MAX], *p;
60 FILE *f;
61
62 snprintf(path, NAME_MAX, "%s/%s", device, attr);
63
64 if (!(f = fopen(path, "r")))
65 return NULL;
66 p = fgets(buf, ATTR_MAX, f);
67 fclose(f);
68 if (!p)
69 return NULL;
70
71 /* Last byte is a '\n'; chop that off */
72 p = strndup(buf, strlen(buf) - 1);
73 if (!p)
74 sensors_fatal_error(__func__, "Out of memory");
75 return p;
76}
77
78/*
79 * Call an arbitrary function for each class device of the given class
80 * Returns 0 on success (all calls returned 0), a positive errno for
81 * local errors, or a negative error value if any call fails.
82 */
83static int sysfs_foreach_classdev(const char *class_name,
84 int (*func)(const char *, const char *))
85{
86 char path[NAME_MAX];
87 int path_off, ret;
88 DIR *dir;
89 struct dirent *ent;
90
91 path_off = snprintf(path, NAME_MAX, "%s/class/%s",
92 sensors_sysfs_mount, class_name);
93 if (!(dir = opendir(path)))
94 return errno;
95
96 ret = 0;
97 while (!ret && (ent = readdir(dir))) {
98 if (ent->d_name[0] == '.') /* skip hidden entries */
99 continue;
100
101 snprintf(path + path_off, NAME_MAX - path_off, "/%s",
102 ent->d_name);
103 ret = func(path, ent->d_name);
104 }
105
106 closedir(dir);
107 return ret;
108}
109
110/*
111 * Call an arbitrary function for each device of the given bus type
112 * Returns 0 on success (all calls returned 0), a positive errno for
113 * local errors, or a negative error value if any call fails.
114 */
115static int sysfs_foreach_busdev(const char *bus_type,
116 int (*func)(const char *, const char *))
117{
118 char path[NAME_MAX];
119 int path_off, ret;
120 DIR *dir;
121 struct dirent *ent;
122
123 path_off = snprintf(path, NAME_MAX, "%s/bus/%s/devices",
124 sensors_sysfs_mount, bus_type);
125 if (!(dir = opendir(path)))
126 return errno;
127
128 ret = 0;
129 while (!ret && (ent = readdir(dir))) {
130 if (ent->d_name[0] == '.') /* skip hidden entries */
131 continue;
132
133 snprintf(path + path_off, NAME_MAX - path_off, "/%s",
134 ent->d_name);
135 ret = func(path, ent->d_name);
136 }
137
138 closedir(dir);
139 return ret;
140}
141
142/****************************************************************************/
143
144char sensors_sysfs_mount[NAME_MAX];
145
146#define MAX_MAIN_SENSOR_TYPES (SENSORS_FEATURE_MAX_MAIN - SENSORS_FEATURE_IN)
147#define MAX_OTHER_SENSOR_TYPES (SENSORS_FEATURE_MAX_OTHER - SENSORS_FEATURE_VID)
148#define MAX_SENSORS_PER_TYPE 24
149/* max_subfeatures is now computed dynamically */
150#define FEATURE_SIZE (max_subfeatures * 2)
151#define FEATURE_TYPE_SIZE (MAX_SENSORS_PER_TYPE * FEATURE_SIZE)
152
153/*
154 * Room for all 7 main types (in, fan, temp, power, energy, current, humidity)
155 * and 2 other types (VID, intrusion) with all their subfeatures + misc features
156 */
157#define SUB_OFFSET_OTHER (MAX_MAIN_SENSOR_TYPES * FEATURE_TYPE_SIZE)
158#define SUB_OFFSET_MISC (SUB_OFFSET_OTHER + \
159 MAX_OTHER_SENSOR_TYPES * FEATURE_TYPE_SIZE)
160#define ALL_POSSIBLE_SUBFEATURES (SUB_OFFSET_MISC + 1)
161
162static
163int get_type_scaling(sensors_subfeature_type type)
164{
165 /* Multipliers for subfeatures */
166 switch (type & 0xFF80) {
167 case SENSORS_SUBFEATURE_IN_INPUT:
168 case SENSORS_SUBFEATURE_TEMP_INPUT:
169 case SENSORS_SUBFEATURE_CURR_INPUT:
170 case SENSORS_SUBFEATURE_HUMIDITY_INPUT:
171 return 1000;
172 case SENSORS_SUBFEATURE_FAN_INPUT:
173 return 1;
174 case SENSORS_SUBFEATURE_POWER_AVERAGE:
175 case SENSORS_SUBFEATURE_ENERGY_INPUT:
176 return 1000000;
177 }
178
179 /* Multipliers for second class subfeatures
180 that need their own multiplier */
181 switch (type) {
182 case SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL:
183 case SENSORS_SUBFEATURE_VID:
184 case SENSORS_SUBFEATURE_TEMP_OFFSET:
185 return 1000;
186 default:
187 return 1;
188 }
189}
190
191static
192char *get_feature_name(sensors_feature_type ftype, char *sfname)
193{
194 char *name, *underscore;
195
196 switch (ftype) {
197 case SENSORS_FEATURE_IN:
198 case SENSORS_FEATURE_FAN:
199 case SENSORS_FEATURE_TEMP:
200 case SENSORS_FEATURE_POWER:
201 case SENSORS_FEATURE_ENERGY:
202 case SENSORS_FEATURE_CURR:
203 case SENSORS_FEATURE_HUMIDITY:
204 case SENSORS_FEATURE_INTRUSION:
205 underscore = strchr(sfname, '_');
206 name = strndup(sfname, underscore - sfname);
207 if (!name)
208 sensors_fatal_error(__func__, "Out of memory");
209
210 break;
211 default:
212 name = strdup(sfname);
213 if (!name)
214 sensors_fatal_error(__func__, "Out of memory");
215 }
216
217 return name;
218}
219
220/* Static mappings for use by sensors_subfeature_get_type() */
221struct subfeature_type_match
222{
223 const char *name;
224 sensors_subfeature_type type;
225};
226
227struct feature_type_match
228{
229 const char *name;
230 const struct subfeature_type_match *submatches;
231};
232
233static const struct subfeature_type_match temp_matches[] = {
234 { "input", SENSORS_SUBFEATURE_TEMP_INPUT },
235 { "max", SENSORS_SUBFEATURE_TEMP_MAX },
236 { "max_hyst", SENSORS_SUBFEATURE_TEMP_MAX_HYST },
237 { "min", SENSORS_SUBFEATURE_TEMP_MIN },
238 { "crit", SENSORS_SUBFEATURE_TEMP_CRIT },
239 { "crit_hyst", SENSORS_SUBFEATURE_TEMP_CRIT_HYST },
240 { "lcrit", SENSORS_SUBFEATURE_TEMP_LCRIT },
241 { "emergency", SENSORS_SUBFEATURE_TEMP_EMERGENCY },
242 { "emergency_hyst", SENSORS_SUBFEATURE_TEMP_EMERGENCY_HYST },
243 { "lowest", SENSORS_SUBFEATURE_TEMP_LOWEST },
244 { "highest", SENSORS_SUBFEATURE_TEMP_HIGHEST },
245 { "alarm", SENSORS_SUBFEATURE_TEMP_ALARM },
246 { "min_alarm", SENSORS_SUBFEATURE_TEMP_MIN_ALARM },
247 { "max_alarm", SENSORS_SUBFEATURE_TEMP_MAX_ALARM },
248 { "crit_alarm", SENSORS_SUBFEATURE_TEMP_CRIT_ALARM },
249 { "emergency_alarm", SENSORS_SUBFEATURE_TEMP_EMERGENCY_ALARM },
250 { "lcrit_alarm", SENSORS_SUBFEATURE_TEMP_LCRIT_ALARM },
251 { "fault", SENSORS_SUBFEATURE_TEMP_FAULT },
252 { "type", SENSORS_SUBFEATURE_TEMP_TYPE },
253 { "offset", SENSORS_SUBFEATURE_TEMP_OFFSET },
254 { "beep", SENSORS_SUBFEATURE_TEMP_BEEP },
255 { NULL, 0 }
256};
257
258static const struct subfeature_type_match in_matches[] = {
259 { "input", SENSORS_SUBFEATURE_IN_INPUT },
260 { "min", SENSORS_SUBFEATURE_IN_MIN },
261 { "max", SENSORS_SUBFEATURE_IN_MAX },
262 { "lcrit", SENSORS_SUBFEATURE_IN_LCRIT },
263 { "crit", SENSORS_SUBFEATURE_IN_CRIT },
264 { "average", SENSORS_SUBFEATURE_IN_AVERAGE },
265 { "lowest", SENSORS_SUBFEATURE_IN_LOWEST },
266 { "highest", SENSORS_SUBFEATURE_IN_HIGHEST },
267 { "alarm", SENSORS_SUBFEATURE_IN_ALARM },
268 { "min_alarm", SENSORS_SUBFEATURE_IN_MIN_ALARM },
269 { "max_alarm", SENSORS_SUBFEATURE_IN_MAX_ALARM },
270 { "lcrit_alarm", SENSORS_SUBFEATURE_IN_LCRIT_ALARM },
271 { "crit_alarm", SENSORS_SUBFEATURE_IN_CRIT_ALARM },
272 { "beep", SENSORS_SUBFEATURE_IN_BEEP },
273 { NULL, 0 }
274};
275
276static const struct subfeature_type_match fan_matches[] = {
277 { "input", SENSORS_SUBFEATURE_FAN_INPUT },
278 { "min", SENSORS_SUBFEATURE_FAN_MIN },
279 { "max", SENSORS_SUBFEATURE_FAN_MAX },
280 { "div", SENSORS_SUBFEATURE_FAN_DIV },
281 { "pulses", SENSORS_SUBFEATURE_FAN_PULSES },
282 { "alarm", SENSORS_SUBFEATURE_FAN_ALARM },
283 { "min_alarm", SENSORS_SUBFEATURE_FAN_MIN_ALARM },
284 { "max_alarm", SENSORS_SUBFEATURE_FAN_MAX_ALARM },
285 { "fault", SENSORS_SUBFEATURE_FAN_FAULT },
286 { "beep", SENSORS_SUBFEATURE_FAN_BEEP },
287 { NULL, 0 }
288};
289
290static const struct subfeature_type_match power_matches[] = {
291 { "average", SENSORS_SUBFEATURE_POWER_AVERAGE },
292 { "average_highest", SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST },
293 { "average_lowest", SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST },
294 { "input", SENSORS_SUBFEATURE_POWER_INPUT },
295 { "input_highest", SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST },
296 { "input_lowest", SENSORS_SUBFEATURE_POWER_INPUT_LOWEST },
297 { "cap", SENSORS_SUBFEATURE_POWER_CAP },
298 { "cap_hyst", SENSORS_SUBFEATURE_POWER_CAP_HYST },
299 { "cap_alarm", SENSORS_SUBFEATURE_POWER_CAP_ALARM },
300 { "alarm", SENSORS_SUBFEATURE_POWER_ALARM },
301 { "max", SENSORS_SUBFEATURE_POWER_MAX },
302 { "max_alarm", SENSORS_SUBFEATURE_POWER_MAX_ALARM },
303 { "crit", SENSORS_SUBFEATURE_POWER_CRIT },
304 { "crit_alarm", SENSORS_SUBFEATURE_POWER_CRIT_ALARM },
305 { "average_interval", SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL },
306 { NULL, 0 }
307};
308
309static const struct subfeature_type_match energy_matches[] = {
310 { "input", SENSORS_SUBFEATURE_ENERGY_INPUT },
311 { NULL, 0 }
312};
313
314static const struct subfeature_type_match curr_matches[] = {
315 { "input", SENSORS_SUBFEATURE_CURR_INPUT },
316 { "min", SENSORS_SUBFEATURE_CURR_MIN },
317 { "max", SENSORS_SUBFEATURE_CURR_MAX },
318 { "lcrit", SENSORS_SUBFEATURE_CURR_LCRIT },
319 { "crit", SENSORS_SUBFEATURE_CURR_CRIT },
320 { "average", SENSORS_SUBFEATURE_CURR_AVERAGE },
321 { "lowest", SENSORS_SUBFEATURE_CURR_LOWEST },
322 { "highest", SENSORS_SUBFEATURE_CURR_HIGHEST },
323 { "alarm", SENSORS_SUBFEATURE_CURR_ALARM },
324 { "min_alarm", SENSORS_SUBFEATURE_CURR_MIN_ALARM },
325 { "max_alarm", SENSORS_SUBFEATURE_CURR_MAX_ALARM },
326 { "lcrit_alarm", SENSORS_SUBFEATURE_CURR_LCRIT_ALARM },
327 { "crit_alarm", SENSORS_SUBFEATURE_CURR_CRIT_ALARM },
328 { "beep", SENSORS_SUBFEATURE_CURR_BEEP },
329 { NULL, 0 }
330};
331
332static const struct subfeature_type_match humidity_matches[] = {
333 { "input", SENSORS_SUBFEATURE_HUMIDITY_INPUT },
334 { NULL, 0 }
335};
336
337static const struct subfeature_type_match cpu_matches[] = {
338 { "vid", SENSORS_SUBFEATURE_VID },
339 { NULL, 0 }
340};
341
342static const struct subfeature_type_match intrusion_matches[] = {
343 { "alarm", SENSORS_SUBFEATURE_INTRUSION_ALARM },
344 { "beep", SENSORS_SUBFEATURE_INTRUSION_BEEP },
345 { NULL, 0 }
346};
347static struct feature_type_match matches[] = {
348 { "temp%d%c", temp_matches },
349 { "in%d%c", in_matches },
350 { "fan%d%c", fan_matches },
351 { "cpu%d%c", cpu_matches },
352 { "power%d%c", power_matches },
353 { "curr%d%c", curr_matches },
354 { "energy%d%c", energy_matches },
355 { "intrusion%d%c", intrusion_matches },
356 { "humidity%d%c", humidity_matches },
357};
358
359/* Return the subfeature type and channel number based on the subfeature
360 name */
361static
362sensors_subfeature_type sensors_subfeature_get_type(const char *name, int *nr)
363{
364 char c;
365 int i, count;
366 const struct subfeature_type_match *submatches;
367
368 /* Special case */
369 if (!strcmp(name, "beep_enable")) {
370 *nr = 0;
371 return SENSORS_SUBFEATURE_BEEP_ENABLE;
372 }
373
374 for (i = 0; i < ARRAY_SIZE(matches); i++)
375 if ((count = sscanf(name, matches[i].name, nr, &c)))
376 break;
377
378 if (i == ARRAY_SIZE(matches) || count != 2 || c != '_')
379 return SENSORS_SUBFEATURE_UNKNOWN; /* no match */
380
381 submatches = matches[i].submatches;
382 name = strchr(name + 3, '_') + 1;
383 for (i = 0; submatches[i].name != NULL; i++)
384 if (!strcmp(name, submatches[i].name))
385 return submatches[i].type;
386
387 return SENSORS_SUBFEATURE_UNKNOWN;
388}
389
390static int sensors_compute_max(void)
391{
392 int i, j, max, offset;
393 const struct subfeature_type_match *submatches;
394 sensors_feature_type ftype;
395
396 max = 0;
397 for (i = 0; i < ARRAY_SIZE(matches); i++) {
398 submatches = matches[i].submatches;
399 for (j = 0; submatches[j].name != NULL; j++) {
400 ftype = submatches[j].type >> 8;
401
402 if (ftype < SENSORS_FEATURE_VID) {
403 offset = submatches[j].type & 0x7F;
404 if (offset >= max)
405 max = offset + 1;
406 } else {
407 offset = submatches[j].type & 0xFF;
408 if (offset >= max * 2)
409 max = ((offset + 1) + 1) / 2;
410 }
411 }
412 }
413
414 return max;
415}
416
417static int sensors_get_attr_mode(const char *device, const char *attr)
418{
419 char path[NAME_MAX];
420 struct stat st;
421 int mode = 0;
422
423 snprintf(path, NAME_MAX, "%s/%s", device, attr);
424 if (!stat(path, &st)) {
425 if (st.st_mode & S_IRUSR)
426 mode |= SENSORS_MODE_R;
427 if (st.st_mode & S_IWUSR)
428 mode |= SENSORS_MODE_W;
429 }
430 return mode;
431}
432
433static int sensors_read_dynamic_chip(sensors_chip_features *chip,
434 const char *dev_path)
435{
436 int i, fnum = 0, sfnum = 0, prev_slot;
437 static int max_subfeatures;
438 DIR *dir;
439 struct dirent *ent;
440 sensors_subfeature *all_subfeatures;
441 sensors_subfeature *dyn_subfeatures;
442 sensors_feature *dyn_features;
443 sensors_feature_type ftype;
444 sensors_subfeature_type sftype;
445
446 if (!(dir = opendir(dev_path)))
447 return -errno;
448
449 /* Dynamically figure out the max number of subfeatures */
450 if (!max_subfeatures)
451 max_subfeatures = sensors_compute_max();
452
453 /* We use a large sparse table at first to store all found
454 subfeatures, so that we can store them sorted at type and index
455 and then later create a dense sorted table. */
456 all_subfeatures = calloc(ALL_POSSIBLE_SUBFEATURES,
457 sizeof(sensors_subfeature));
458 if (!all_subfeatures)
459 sensors_fatal_error(__func__, "Out of memory");
460
461 while ((ent = readdir(dir))) {
462 char *name;
463 int nr;
464
465 /* Skip directories and symlinks */
466 if (ent->d_type != DT_REG)
467 continue;
468
469 name = ent->d_name;
470
471 sftype = sensors_subfeature_get_type(name, &nr);
472 if (sftype == SENSORS_SUBFEATURE_UNKNOWN)
473 continue;
474 ftype = sftype >> 8;
475
476 /* Adjust the channel number */
477 switch (ftype) {
478 case SENSORS_FEATURE_FAN:
479 case SENSORS_FEATURE_TEMP:
480 case SENSORS_FEATURE_POWER:
481 case SENSORS_FEATURE_ENERGY:
482 case SENSORS_FEATURE_CURR:
483 case SENSORS_FEATURE_HUMIDITY:
484 nr--;
485 break;
486 default:
487 break;
488 }
489
490 if (nr < 0 || nr >= MAX_SENSORS_PER_TYPE) {
491 /* More sensors of one type than MAX_SENSORS_PER_TYPE,
492 we have to ignore it */
493#ifdef DEBUG
494 sensors_fatal_error(__func__,
495 "Increase MAX_SENSORS_PER_TYPE!");
496#endif
497 continue;
498 }
499
500 /* "calculate" a place to store the subfeature in our sparse,
501 sorted table */
502 switch (ftype) {
503 case SENSORS_FEATURE_VID:
504 case SENSORS_FEATURE_INTRUSION:
505 i = SUB_OFFSET_OTHER +
506 (ftype - SENSORS_FEATURE_VID) * FEATURE_TYPE_SIZE +
507 nr * FEATURE_SIZE + (sftype & 0xFF);
508 break;
509 case SENSORS_FEATURE_BEEP_ENABLE:
510 i = SUB_OFFSET_MISC +
511 (ftype - SENSORS_FEATURE_BEEP_ENABLE);
512 break;
513 default:
514 i = ftype * FEATURE_TYPE_SIZE +
515 nr * FEATURE_SIZE +
516 ((sftype & 0x80) >> 7) * max_subfeatures +
517 (sftype & 0x7F);
518 }
519
520 if (all_subfeatures[i].name) {
521#ifdef DEBUG
522 sensors_fatal_error(__func__, "Duplicate subfeature");
523#endif
524 continue;
525 }
526
527 /* fill in the subfeature members */
528 all_subfeatures[i].type = sftype;
529 all_subfeatures[i].name = strdup(name);
530 if (!all_subfeatures[i].name)
531 sensors_fatal_error(__func__, "Out of memory");
532
533 /* Other and misc subfeatures are never scaled */
534 if (sftype < SENSORS_SUBFEATURE_VID && !(sftype & 0x80))
535 all_subfeatures[i].flags |= SENSORS_COMPUTE_MAPPING;
536 all_subfeatures[i].flags |= sensors_get_attr_mode(dev_path, name);
537
538 sfnum++;
539 }
540 closedir(dir);
541
542 if (!sfnum) { /* No subfeature */
543 chip->subfeature = NULL;
544 goto exit_free;
545 }
546
547 /* How many main features? */
548 prev_slot = -1;
549 for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
550 if (!all_subfeatures[i].name)
551 continue;
552
553 if (i >= SUB_OFFSET_MISC || i / FEATURE_SIZE != prev_slot) {
554 fnum++;
555 prev_slot = i / FEATURE_SIZE;
556 }
557 }
558
559 dyn_subfeatures = calloc(sfnum, sizeof(sensors_subfeature));
560 dyn_features = calloc(fnum, sizeof(sensors_feature));
561 if (!dyn_subfeatures || !dyn_features)
562 sensors_fatal_error(__func__, "Out of memory");
563
564 /* Copy from the sparse array to the compact array */
565 sfnum = 0;
566 fnum = -1;
567 prev_slot = -1;
568 for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
569 if (!all_subfeatures[i].name)
570 continue;
571
572 /* New main feature? */
573 if (i >= SUB_OFFSET_MISC || i / FEATURE_SIZE != prev_slot) {
574 ftype = all_subfeatures[i].type >> 8;
575 fnum++;
576 prev_slot = i / FEATURE_SIZE;
577
578 dyn_features[fnum].name = get_feature_name(ftype,
579 all_subfeatures[i].name);
580 dyn_features[fnum].number = fnum;
581 dyn_features[fnum].first_subfeature = sfnum;
582 dyn_features[fnum].type = ftype;
583 }
584
585 dyn_subfeatures[sfnum] = all_subfeatures[i];
586 dyn_subfeatures[sfnum].number = sfnum;
587 /* Back to the feature */
588 dyn_subfeatures[sfnum].mapping = fnum;
589
590 sfnum++;
591 }
592
593 chip->subfeature = dyn_subfeatures;
594 chip->subfeature_count = sfnum;
595 chip->feature = dyn_features;
596 chip->feature_count = ++fnum;
597
598exit_free:
599 free(all_subfeatures);
600 return 0;
601}
602
603/* returns !0 if sysfs filesystem was found, 0 otherwise */
604int sensors_init_sysfs(void)
605{
606 struct statfs statfsbuf;
607
608 snprintf(sensors_sysfs_mount, NAME_MAX, "%s", "/sys");
609 if (statfs(sensors_sysfs_mount, &statfsbuf) < 0
610 || statfsbuf.f_type != SYSFS_MAGIC)
611 return 0;
612
613 return 1;
614}
615
616/* returns: number of devices added (0 or 1) if successful, <0 otherwise */
617static int sensors_read_one_sysfs_chip(const char *dev_path,
618 const char *dev_name,
619 const char *hwmon_path)
620{
621 int domain, bus, slot, fn, vendor, product, id;
622 int err = -SENSORS_ERR_KERNEL;
623 char *bus_attr;
624 char bus_path[NAME_MAX];
625 char linkpath[NAME_MAX];
626 char subsys_path[NAME_MAX], *subsys;
627 int sub_len;
628 sensors_chip_features entry;
629
630 /* ignore any device without name attribute */
631 if (!(entry.chip.prefix = sysfs_read_attr(hwmon_path, "name")))
632 return 0;
633
634 entry.chip.path = strdup(hwmon_path);
635 if (!entry.chip.path)
636 sensors_fatal_error(__func__, "Out of memory");
637
638 if (dev_path == NULL) {
639 /* Virtual device */
640 entry.chip.bus.type = SENSORS_BUS_TYPE_VIRTUAL;
641 entry.chip.bus.nr = 0;
642 /* For now we assume that virtual devices are unique */
643 entry.chip.addr = 0;
644 goto done;
645 }
646
647 /* Find bus type */
648 snprintf(linkpath, NAME_MAX, "%s/subsystem", dev_path);
649 sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
650 if (sub_len < 0 && errno == ENOENT) {
651 /* Fallback to "bus" link for kernels <= 2.6.17 */
652 snprintf(linkpath, NAME_MAX, "%s/bus", dev_path);
653 sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
654 }
655 if (sub_len < 0) {
656 /* Older kernels (<= 2.6.11) have neither the subsystem
657 symlink nor the bus symlink */
658 if (errno == ENOENT)
659 subsys = NULL;
660 else
661 goto exit_free;
662 } else {
663 subsys_path[sub_len] = '\0';
664 subsys = strrchr(subsys_path, '/') + 1;
665 }
666
667 if ((!subsys || !strcmp(subsys, "i2c")) &&
668 sscanf(dev_name, "%hd-%x", &entry.chip.bus.nr,
669 &entry.chip.addr) == 2) {
670 /* find out if legacy ISA or not */
671 if (entry.chip.bus.nr == 9191) {
672 entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
673 entry.chip.bus.nr = 0;
674 } else {
675 entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
676 snprintf(bus_path, sizeof(bus_path),
677 "%s/class/i2c-adapter/i2c-%d/device",
678 sensors_sysfs_mount, entry.chip.bus.nr);
679
680 if ((bus_attr = sysfs_read_attr(bus_path, "name"))) {
681 if (!strncmp(bus_attr, "ISA ", 4)) {
682 entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
683 entry.chip.bus.nr = 0;
684 }
685
686 free(bus_attr);
687 }
688 }
689 } else
690 if ((!subsys || !strcmp(subsys, "spi")) &&
691 sscanf(dev_name, "spi%hd.%d", &entry.chip.bus.nr,
692 &entry.chip.addr) == 2) {
693 /* SPI */
694 entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
695 } else
696 if ((!subsys || !strcmp(subsys, "pci")) &&
697 sscanf(dev_name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
698 /* PCI */
699 entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
700 entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
701 entry.chip.bus.nr = 0;
702 } else
703 if ((!subsys || !strcmp(subsys, "platform") ||
704 !strcmp(subsys, "of_platform"))) {
705 /* must be new ISA (platform driver) */
706 if (sscanf(dev_name, "%*[a-z0-9_].%d", &entry.chip.addr) != 1)
707 entry.chip.addr = 0;
708 entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
709 entry.chip.bus.nr = 0;
710 } else if (subsys && !strcmp(subsys, "acpi")) {
711 entry.chip.bus.type = SENSORS_BUS_TYPE_ACPI;
712 /* For now we assume that acpi devices are unique */
713 entry.chip.bus.nr = 0;
714 entry.chip.addr = 0;
715 } else
716 if (subsys && !strcmp(subsys, "hid") &&
717 sscanf(dev_name, "%x:%x:%x.%x", &bus, &vendor, &product, &id) == 4) {
718 entry.chip.bus.type = SENSORS_BUS_TYPE_HID;
719 /* As of kernel 2.6.32, the hid device names don't look good */
720 entry.chip.bus.nr = bus;
721 entry.chip.addr = id;
722 } else {
723 /* Ignore unknown device */
724 err = 0;
725 goto exit_free;
726 }
727
728done:
729 if (sensors_read_dynamic_chip(&entry, hwmon_path) < 0)
730 goto exit_free;
731 if (!entry.subfeature) { /* No subfeature, discard chip */
732 err = 0;
733 goto exit_free;
734 }
735 sensors_add_proc_chips(&entry);
736
737 return 1;
738
739exit_free:
740 free(entry.chip.prefix);
741 free(entry.chip.path);
742 return err;
743}
744
745static int sensors_add_hwmon_device_compat(const char *path,
746 const char *dev_name)
747{
748 int err;
749
750 err = sensors_read_one_sysfs_chip(path, dev_name, path);
751 if (err < 0)
752 return err;
753 return 0;
754}
755
756/* returns 0 if successful, !0 otherwise */
757static int sensors_read_sysfs_chips_compat(void)
758{
759 int ret;
760
761 ret = sysfs_foreach_busdev("i2c", sensors_add_hwmon_device_compat);
762 if (ret && ret != ENOENT)
763 return -SENSORS_ERR_KERNEL;
764
765 return 0;
766}
767
768static int sensors_add_hwmon_device(const char *path, const char *classdev)
769{
770 char linkpath[NAME_MAX];
771 char device[NAME_MAX], *device_p;
772 int dev_len, err;
773 (void)classdev; /* hide warning */
774
775 snprintf(linkpath, NAME_MAX, "%s/device", path);
776 dev_len = readlink(linkpath, device, NAME_MAX - 1);
777 if (dev_len < 0) {
778 /* No device link? Treat as virtual */
779 err = sensors_read_one_sysfs_chip(NULL, NULL, path);
780 } else {
781 device[dev_len] = '\0';
782 device_p = strrchr(device, '/') + 1;
783
784 /* The attributes we want might be those of the hwmon class
785 device, or those of the device itself. */
786 err = sensors_read_one_sysfs_chip(linkpath, device_p, path);
787 if (err == 0)
788 err = sensors_read_one_sysfs_chip(linkpath, device_p,
789 linkpath);
790 }
791 if (err < 0)
792 return err;
793 return 0;
794}
795
796/* returns 0 if successful, !0 otherwise */
797int sensors_read_sysfs_chips(void)
798{
799 int ret;
800
801 ret = sysfs_foreach_classdev("hwmon", sensors_add_hwmon_device);
802 if (ret == ENOENT) {
803 /* compatibility function for kernel 2.6.n where n <= 13 */
804 return sensors_read_sysfs_chips_compat();
805 }
806
807 if (ret > 0)
808 ret = -SENSORS_ERR_KERNEL;
809 return ret;
810}
811
812/* returns 0 if successful, !0 otherwise */
813static int sensors_add_i2c_bus(const char *path, const char *classdev)
814{
815 sensors_bus entry;
816
817 if (sscanf(classdev, "i2c-%hd", &entry.bus.nr) != 1 ||
818 entry.bus.nr == 9191) /* legacy ISA */
819 return 0;
820 entry.bus.type = SENSORS_BUS_TYPE_I2C;
821
822 /* Get the adapter name from the classdev "name" attribute
823 * (Linux 2.6.20 and later). If it fails, fall back to
824 * the device "name" attribute (for older kernels). */
825 entry.adapter = sysfs_read_attr(path, "name");
826 if (!entry.adapter)
827 entry.adapter = sysfs_read_attr(path, "device/name");
828 if (entry.adapter)
829 sensors_add_proc_bus(&entry);
830
831 return 0;
832}
833
834/* returns 0 if successful, !0 otherwise */
835int sensors_read_sysfs_bus(void)
836{
837 int ret;
838
839 ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus);
840 if (ret == ENOENT)
841 ret = sysfs_foreach_busdev("i2c", sensors_add_i2c_bus);
842 if (ret && ret != ENOENT)
843 return -SENSORS_ERR_KERNEL;
844
845 return 0;
846}
847
848int sensors_read_sysfs_attr(const sensors_chip_name *name,
849 const sensors_subfeature *subfeature,
850 double *value)
851{
852 char n[NAME_MAX];
853 int f;
854
855 snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
856 if ((f = open(n, O_RDONLY)) != -1) {
857 int res, err = 0;
858 char buf[512];
859 int count;
860
861 errno = 0;
862 if ((count = read(f, buf, sizeof(buf) - 1)) == -1) {
863 if (errno == EIO)
864 err = -SENSORS_ERR_IO;
865 else
866 err = -SENSORS_ERR_ACCESS_R;
867 } else {
868 buf[count] = '\0';
869 errno = 0;
870 res = sscanf(buf, "%lf", value);
871 if (res == EOF && errno == EIO)
872 err = -SENSORS_ERR_IO;
873 else if (res != 1)
874 err = -SENSORS_ERR_ACCESS_R;
875 }
876 res = close(f);
877 if (err)
878 return err;
879
880 if (res != 0) {
881 if (errno == EIO)
882 return -SENSORS_ERR_IO;
883 else
884 return -SENSORS_ERR_ACCESS_R;
885 }
886 if (!sensors_sysfs_no_scaling)
887 *value /= get_type_scaling(subfeature->type);
888 } else
889 return -SENSORS_ERR_KERNEL;
890
891 return 0;
892}
893
894int sensors_write_sysfs_attr(const sensors_chip_name *name,
895 const sensors_subfeature *subfeature,
896 double value)
897{
898 char n[NAME_MAX];
899 FILE *f;
900
901 snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
902 if ((f = fopen(n, "w"))) {
903 int res, err = 0;
904
905 if (!sensors_sysfs_no_scaling)
906 value *= get_type_scaling(subfeature->type);
907 res = fprintf(f, "%d", (int) value);
908 if (res == -EIO)
909 err = -SENSORS_ERR_IO;
910 else if (res < 0)
911 err = -SENSORS_ERR_ACCESS_W;
912 res = fclose(f);
913 if (err)
914 return err;
915
916 if (res == EOF) {
917 if (errno == EIO)
918 return -SENSORS_ERR_IO;
919 else
920 return -SENSORS_ERR_ACCESS_W;
921 }
922 } else
923 return -SENSORS_ERR_KERNEL;
924
925 return 0;
926}
diff --git a/daemon/libsensors/sysfs.h b/daemon/libsensors/sysfs.h
new file mode 100644
index 0000000..38584af
--- /dev/null
+++ b/daemon/libsensors/sysfs.h
@@ -0,0 +1,43 @@
1/*
2 sysfs.h - part of libsensors, a library for reading Linux sensor data
3 Copyright (C) Mark M. Hoffman <mhoffman@lightlink.com>
4 Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#ifndef SENSORS_LIB_SYSFS_H
23#define SENSORS_LIB_SYSFS_H
24
25extern char sensors_sysfs_mount[];
26
27int sensors_init_sysfs(void);
28
29int sensors_read_sysfs_chips(void);
30
31int sensors_read_sysfs_bus(void);
32
33/* Read a value out of a sysfs attribute file */
34int sensors_read_sysfs_attr(const sensors_chip_name *name,
35 const sensors_subfeature *subfeature,
36 double *value);
37
38/* Write a value to a sysfs attribute file */
39int sensors_write_sysfs_attr(const sensors_chip_name *name,
40 const sensors_subfeature *subfeature,
41 double value);
42
43#endif /* !SENSORS_LIB_SYSFS_H */
diff --git a/daemon/libsensors/version.h b/daemon/libsensors/version.h
new file mode 100644
index 0000000..76ceb08
--- /dev/null
+++ b/daemon/libsensors/version.h
@@ -0,0 +1 @@
#define LM_VERSION "3.3.2"
diff --git a/daemon/main.cpp b/daemon/main.cpp
index 894bad7..a6ddfe2 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -1,15 +1,13 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <stdint.h>
10#include <stdlib.h> 9#include <stdlib.h>
11#include <signal.h> 10#include <signal.h>
12#include <ctype.h>
13#include <sys/wait.h> 11#include <sys/wait.h>
14#include <unistd.h> 12#include <unistd.h>
15#include <sys/syscall.h> 13#include <sys/syscall.h>
@@ -26,11 +24,12 @@
26#include "OlySocket.h" 24#include "OlySocket.h"
27#include "Logging.h" 25#include "Logging.h"
28#include "OlyUtility.h" 26#include "OlyUtility.h"
27#include "KMod.h"
29 28
30#define DEBUG false 29#define DEBUG false
31 30
32extern Child* child; 31extern Child* child;
33int shutdownFilesystem(); 32static int shutdownFilesystem();
34static pthread_mutex_t numSessions_mutex; 33static pthread_mutex_t numSessions_mutex;
35static int numSessions = 0; 34static int numSessions = 0;
36static OlySocket* socket = NULL; 35static OlySocket* socket = NULL;
@@ -52,7 +51,7 @@ void cleanUp() {
52} 51}
53 52
54// CTRL C Signal Handler 53// CTRL C Signal Handler
55void handler(int signum) { 54static void handler(int signum) {
56 logg->logMessage("Received signal %d, gator daemon exiting", signum); 55 logg->logMessage("Received signal %d, gator daemon exiting", signum);
57 56
58 // Case 1: both child and parent receive the signal 57 // Case 1: both child and parent receive the signal
@@ -90,7 +89,7 @@ void handler(int signum) {
90} 89}
91 90
92// Child exit Signal Handler 91// Child exit Signal Handler
93void child_exit(int signum) { 92static void child_exit(int signum) {
94 int status; 93 int status;
95 int pid = wait(&status); 94 int pid = wait(&status);
96 if (pid != -1) { 95 if (pid != -1) {
@@ -102,7 +101,7 @@ void child_exit(int signum) {
102} 101}
103 102
104// retval: -1 = failure; 0 = was already mounted; 1 = successfully mounted 103// retval: -1 = failure; 0 = was already mounted; 1 = successfully mounted
105int mountGatorFS() { 104static int mountGatorFS() {
106 // If already mounted, 105 // If already mounted,
107 if (access("/dev/gator/buffer", F_OK) == 0) { 106 if (access("/dev/gator/buffer", F_OK) == 0) {
108 return 0; 107 return 0;
@@ -117,7 +116,7 @@ int mountGatorFS() {
117 } 116 }
118} 117}
119 118
120bool init_module (const char * const location) { 119static bool init_module (const char * const location) {
121 bool ret(false); 120 bool ret(false);
122 const int fd = open(location, O_RDONLY); 121 const int fd = open(location, O_RDONLY);
123 if (fd >= 0) { 122 if (fd >= 0) {
@@ -137,7 +136,7 @@ bool init_module (const char * const location) {
137 return ret; 136 return ret;
138} 137}
139 138
140int setupFilesystem(char* module) { 139static int setupFilesystem(char* module) {
141 int retval; 140 int retval;
142 141
143 // Verify root permissions 142 // Verify root permissions
@@ -205,7 +204,7 @@ int setupFilesystem(char* module) {
205 return 0; 204 return 0;
206} 205}
207 206
208int shutdownFilesystem() { 207static int shutdownFilesystem() {
209 if (driverMountedAtStart == false) { 208 if (driverMountedAtStart == false) {
210 umount("/dev/gator"); 209 umount("/dev/gator");
211 } 210 }
@@ -221,7 +220,7 @@ int shutdownFilesystem() {
221 return 0; // success 220 return 0; // success
222} 221}
223 222
224struct cmdline_t parseCommandLine(int argc, char** argv) { 223static struct cmdline_t parseCommandLine(int argc, char** argv) {
225 struct cmdline_t cmdline; 224 struct cmdline_t cmdline;
226 cmdline.port = 8080; 225 cmdline.port = 8080;
227 cmdline.module = NULL; 226 cmdline.module = NULL;
@@ -302,10 +301,13 @@ int main(int argc, char** argv, char* envp[]) {
302 // e.g. it may not be the group leader when launched as 'sudo gatord' 301 // e.g. it may not be the group leader when launched as 'sudo gatord'
303 setsid(); 302 setsid();
304 303
305 gSessionData = new SessionData(); // Global data class
306 logg = new Logging(DEBUG); // Set up global thread-safe logging 304 logg = new Logging(DEBUG); // Set up global thread-safe logging
305 gSessionData = new SessionData(); // Global data class
307 util = new OlyUtility(); // Set up global utility class 306 util = new OlyUtility(); // Set up global utility class
308 307
308 // Initialize drivers
309 new KMod();
310
309 prctl(PR_SET_NAME, (unsigned long)&"gatord-main", 0, 0, 0); 311 prctl(PR_SET_NAME, (unsigned long)&"gatord-main", 0, 0, 0);
310 pthread_mutex_init(&numSessions_mutex, NULL); 312 pthread_mutex_init(&numSessions_mutex, NULL);
311 313
diff --git a/driver/Makefile b/driver/Makefile
index d22d29d..3af8b8d 100644
--- a/driver/Makefile
+++ b/driver/Makefile
@@ -58,5 +58,6 @@ all:
58 58
59clean: 59clean:
60 rm -f *.o .*.cmd gator_events.h modules.order Module.symvers gator.ko gator.mod.c 60 rm -f *.o .*.cmd gator_events.h modules.order Module.symvers gator.ko gator.mod.c
61 rm -rf .tmp_versions
61 62
62endif 63endif
diff --git a/driver/gator.h b/driver/gator.h
index 9a4617b..205cbcd 100644
--- a/driver/gator.h
+++ b/driver/gator.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,9 @@
18#define GATOR_PERF_PMU_SUPPORT GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && (!(defined(__arm__) || defined(__aarch64__)) || defined(CONFIG_HW_PERF_EVENTS)) 18#define GATOR_PERF_PMU_SUPPORT GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && (!(defined(__arm__) || defined(__aarch64__)) || defined(CONFIG_HW_PERF_EVENTS))
19#define GATOR_NO_PERF_SUPPORT (!(GATOR_PERF_SUPPORT)) 19#define GATOR_NO_PERF_SUPPORT (!(GATOR_PERF_SUPPORT))
20#define GATOR_CPU_FREQ_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ) 20#define GATOR_CPU_FREQ_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ)
21#define GATOR_IKS_SUPPORT defined(CONFIG_BL_SWITCHER)
22
23#define GATOR_LIVE 1
21 24
22// cpu ids 25// cpu ids
23#define ARM1136 0xb36 26#define ARM1136 0xb36
@@ -42,14 +45,15 @@
42#define MAXSIZE_CORE_NAME 32 45#define MAXSIZE_CORE_NAME 32
43 46
44struct gator_cpu { 47struct gator_cpu {
45 const int cpuid; 48 const int cpuid;
46 const char core_name[MAXSIZE_CORE_NAME]; 49 const char core_name[MAXSIZE_CORE_NAME];
47 const char * const pmnc_name; 50 const char * const pmu_name;
48 const int pmnc_counters; 51 const char * const pmnc_name;
49 const int ccnt; 52 const int pmnc_counters;
50}; 53};
51 54
52extern struct gator_cpu gator_cpus[]; 55const struct gator_cpu *gator_find_cpu_by_cpuid(const u32 cpuid);
56const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name);
53 57
54/****************************************************************************** 58/******************************************************************************
55 * Filesystem 59 * Filesystem
@@ -98,10 +102,10 @@ struct gator_interface {
98 int (*create_files)(struct super_block *sb, struct dentry *root); 102 int (*create_files)(struct super_block *sb, struct dentry *root);
99 int (*start)(void); 103 int (*start)(void);
100 void (*stop)(void); // Complementary function to start 104 void (*stop)(void); // Complementary function to start
101 int (*online)(int **buffer); 105 int (*online)(int **buffer, bool migrate);
102 int (*offline)(int **buffer); 106 int (*offline)(int **buffer, bool migrate);
103 void (*online_dispatch)(int cpu); // called in process context but may not be running on core 'cpu' 107 void (*online_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu'
104 void (*offline_dispatch)(int cpu); // called in process context but may not be running on core 'cpu' 108 void (*offline_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu'
105 int (*read)(int **buffer); 109 int (*read)(int **buffer);
106 int (*read64)(long long **buffer); 110 int (*read64)(long long **buffer);
107 struct list_head list; 111 struct list_head list;
@@ -118,4 +122,21 @@ u32 gator_cpuid(void);
118 122
119void gator_backtrace_handler(struct pt_regs *const regs); 123void gator_backtrace_handler(struct pt_regs *const regs);
120 124
125#if !GATOR_IKS_SUPPORT
126
127#define get_physical_cpu() smp_processor_id()
128#define lcpu_to_pcpu(lcpu) lcpu
129#define pcpu_to_lcpu(pcpu) pcpu
130
131#else
132
133#define get_physical_cpu() lcpu_to_pcpu(get_logical_cpu())
134int lcpu_to_pcpu(const int lcpu);
135int pcpu_to_lcpu(const int pcpu);
136
137#endif
138
139#define get_logical_cpu() smp_processor_id()
140#define on_primary_core() (get_logical_cpu() == 0)
141
121#endif // GATOR_H_ 142#endif // GATOR_H_
diff --git a/driver/gator_annotate.c b/driver/gator_annotate.c
index 42f9951..ad9f309 100644
--- a/driver/gator_annotate.c
+++ b/driver/gator_annotate.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -50,6 +50,7 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
50 return -EINVAL; 50 return -EINVAL;
51 } 51 }
52 52
53 retry:
53 // synchronize between cores and with collect_annotations 54 // synchronize between cores and with collect_annotations
54 spin_lock(&annotate_lock); 55 spin_lock(&annotate_lock);
55 56
@@ -74,17 +75,18 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
74 size = count < available ? count : available; 75 size = count < available ? count : available;
75 76
76 if (size <= 0) { 77 if (size <= 0) {
77 // Buffer is full but don't return an error. Instead return 0 so the 78 // Buffer is full, wait until space is available
78 // caller knows nothing was written and they can try again. 79 spin_unlock(&annotate_lock);
79 size = 0; 80 wait_event_interruptible(gator_annotate_wait, buffer_bytes_available(cpu, ANNOTATE_BUF) > header_size || !collect_annotations);
80 goto annotate_write_out; 81 goto retry;
81 } 82 }
82 83
83 // synchronize shared variables annotateBuf and annotatePos 84 // synchronize shared variables annotateBuf and annotatePos
84 if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF]) { 85 if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF]) {
85 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, smp_processor_id()); 86 u64 time = gator_get_time();
87 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu());
86 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid); 88 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid);
87 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, gator_get_time()); 89 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, time);
88 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, size); 90 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, size);
89 91
90 // determine the sizes to capture, length1 + length2 will equal size 92 // determine the sizes to capture, length1 + length2 will equal size
@@ -108,7 +110,7 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
108 } 110 }
109 111
110 // Check and commit; commit is set to occur once buffer is 3/4 full 112 // Check and commit; commit is set to occur once buffer is 3/4 full
111 buffer_check(cpu, ANNOTATE_BUF); 113 buffer_check(cpu, ANNOTATE_BUF, time);
112 } 114 }
113 115
114annotate_write_out: 116annotate_write_out:
@@ -129,14 +131,14 @@ static int annotate_release(struct inode *inode, struct file *file)
129 131
130 if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) { 132 if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) {
131 uint32_t pid = current->pid; 133 uint32_t pid = current->pid;
132 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, smp_processor_id()); 134 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu());
133 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid); 135 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid);
134 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time 136 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time
135 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size 137 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size
136 } 138 }
137 139
138 // Check and commit; commit is set to occur once buffer is 3/4 full 140 // Check and commit; commit is set to occur once buffer is 3/4 full
139 buffer_check(cpu, ANNOTATE_BUF); 141 buffer_check(cpu, ANNOTATE_BUF, gator_get_time());
140 142
141 spin_unlock(&annotate_lock); 143 spin_unlock(&annotate_lock);
142 144
@@ -164,5 +166,6 @@ static void gator_annotate_stop(void)
164 // the spinlock here will ensure that when this function exits, we are not in the middle of an annotation 166 // the spinlock here will ensure that when this function exits, we are not in the middle of an annotation
165 spin_lock(&annotate_lock); 167 spin_lock(&annotate_lock);
166 collect_annotations = false; 168 collect_annotations = false;
169 wake_up(&gator_annotate_wait);
167 spin_unlock(&annotate_lock); 170 spin_unlock(&annotate_lock);
168} 171}
diff --git a/driver/gator_annotate_kernel.c b/driver/gator_annotate_kernel.c
index 67d2d6c..4715f64 100644
--- a/driver/gator_annotate_kernel.c
+++ b/driver/gator_annotate_kernel.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_backtrace.c b/driver/gator_backtrace.c
index e6125b3..94f01e6 100644
--- a/driver/gator_backtrace.c
+++ b/driver/gator_backtrace.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -11,8 +11,17 @@
11 * EABI backtrace stores {fp,lr} on the stack. 11 * EABI backtrace stores {fp,lr} on the stack.
12 */ 12 */
13struct frame_tail_eabi { 13struct frame_tail_eabi {
14 unsigned long fp; // points to prev_lr 14 union {
15 unsigned long lr; 15 struct {
16 unsigned long fp; // points to prev_lr
17 unsigned long lr;
18 };
19 // Used to read 32 bit fp/lr from a 64 bit kernel
20 struct {
21 u32 fp_32;
22 u32 lr_32;
23 };
24 };
16}; 25};
17 26
18static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth) 27static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth)
@@ -20,18 +29,20 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
20#if defined(__arm__) || defined(__aarch64__) 29#if defined(__arm__) || defined(__aarch64__)
21 struct frame_tail_eabi *tail; 30 struct frame_tail_eabi *tail;
22 struct frame_tail_eabi *next; 31 struct frame_tail_eabi *next;
23 struct frame_tail_eabi *ptrtail;
24 struct frame_tail_eabi buftail; 32 struct frame_tail_eabi buftail;
25#if defined(__arm__) 33#if defined(__arm__)
34 const bool is_compat = false;
26 unsigned long fp = regs->ARM_fp; 35 unsigned long fp = regs->ARM_fp;
27 unsigned long sp = regs->ARM_sp; 36 unsigned long sp = regs->ARM_sp;
28 unsigned long lr = regs->ARM_lr; 37 unsigned long lr = regs->ARM_lr;
29 const int frame_offset = 4; 38 const int frame_offset = 4;
30#else 39#else
31 unsigned long fp = regs->regs[29]; 40 // Is userspace aarch32 (32 bit)
32 unsigned long sp = regs->sp; 41 const bool is_compat = compat_user_mode(regs);
33 unsigned long lr = regs->regs[30]; 42 unsigned long fp = (is_compat ? regs->regs[11] : regs->regs[29]);
34 const int frame_offset = 0; 43 unsigned long sp = (is_compat ? regs->compat_sp : regs->sp);
44 unsigned long lr = (is_compat ? regs->compat_lr : regs->regs[30]);
45 const int frame_offset = (is_compat ? 4 : 0);
35#endif 46#endif
36 int is_user_mode = user_mode(regs); 47 int is_user_mode = user_mode(regs);
37 48
@@ -55,15 +66,14 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
55 return; 66 return;
56 if (__copy_from_user_inatomic(&buftail, tail, sizeof(struct frame_tail_eabi))) 67 if (__copy_from_user_inatomic(&buftail, tail, sizeof(struct frame_tail_eabi)))
57 return; 68 return;
58 ptrtail = &buftail;
59 69
60 lr = ptrtail[0].lr; 70 lr = (is_compat ? buftail.lr_32 : buftail.lr);
61 gator_add_trace(cpu, lr); 71 gator_add_trace(cpu, lr);
62 72
63 /* frame pointers should progress back up the stack, towards higher addresses */ 73 /* frame pointers should progress back up the stack, towards higher addresses */
64 next = (struct frame_tail_eabi *)(lr - frame_offset); 74 next = (struct frame_tail_eabi *)(lr - frame_offset);
65 if (tail >= next || lr == 0) { 75 if (tail >= next || lr == 0) {
66 fp = ptrtail[0].fp; 76 fp = (is_compat ? buftail.fp_32 : buftail.fp);
67 next = (struct frame_tail_eabi *)(fp - frame_offset); 77 next = (struct frame_tail_eabi *)(fp - frame_offset);
68 /* check tail is valid */ 78 /* check tail is valid */
69 if (tail >= next || fp == 0) { 79 if (tail >= next || fp == 0) {
@@ -79,16 +89,17 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
79#if defined(__arm__) || defined(__aarch64__) 89#if defined(__arm__) || defined(__aarch64__)
80static int report_trace(struct stackframe *frame, void *d) 90static int report_trace(struct stackframe *frame, void *d)
81{ 91{
82 struct module *mod; 92 unsigned int *depth = d, cookie = NO_COOKIE, cpu = get_physical_cpu();
83 unsigned int *depth = d, cookie = NO_COOKIE, cpu = smp_processor_id();
84 unsigned long addr = frame->pc; 93 unsigned long addr = frame->pc;
85 94
86 if (*depth) { 95 if (*depth) {
87 mod = __module_address(addr); 96#if defined(MODULE)
97 struct module *mod = __module_address(addr);
88 if (mod) { 98 if (mod) {
89 cookie = get_cookie(cpu, current, mod->name, false); 99 cookie = get_cookie(cpu, current, mod->name, false);
90 addr = addr - (unsigned long)mod->module_core; 100 addr = addr - (unsigned long)mod->module_core;
91 } 101 }
102#endif
92 marshal_backtrace(addr & ~1, cookie); 103 marshal_backtrace(addr & ~1, cookie);
93 (*depth)--; 104 (*depth)--;
94 } 105 }
diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c
index bb401bb..c332187 100644
--- a/driver/gator_cookies.c
+++ b/driver/gator_cookies.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -61,7 +61,7 @@ static uint32_t gator_chksum_crc32(const char *data)
61static uint32_t cookiemap_exists(uint64_t key) 61static uint32_t cookiemap_exists(uint64_t key)
62{ 62{
63 unsigned long x, flags, retval = 0; 63 unsigned long x, flags, retval = 0;
64 int cpu = smp_processor_id(); 64 int cpu = get_physical_cpu();
65 uint32_t cookiecode = cookiemap_code(key); 65 uint32_t cookiecode = cookiemap_code(key);
66 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]); 66 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
67 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]); 67 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
@@ -93,7 +93,7 @@ static uint32_t cookiemap_exists(uint64_t key)
93 */ 93 */
94static void cookiemap_add(uint64_t key, uint32_t value) 94static void cookiemap_add(uint64_t key, uint32_t value)
95{ 95{
96 int cpu = smp_processor_id(); 96 int cpu = get_physical_cpu();
97 int cookiecode = cookiemap_code(key); 97 int cookiecode = cookiemap_code(key);
98 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]); 98 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
99 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]); 99 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
@@ -124,7 +124,7 @@ static void wq_cookie_handler(struct work_struct *unused)
124{ 124{
125 struct task_struct *task; 125 struct task_struct *task;
126 char *text; 126 char *text;
127 int cpu = smp_processor_id(); 127 int cpu = get_physical_cpu();
128 unsigned int commit; 128 unsigned int commit;
129 129
130 mutex_lock(&start_mutex); 130 mutex_lock(&start_mutex);
diff --git a/driver/gator_events.sh b/driver/gator_events.sh
index 5467dd6..5467dd6 100644..100755
--- a/driver/gator_events.sh
+++ b/driver/gator_events.sh
diff --git a/driver/gator_events_armv6.c b/driver/gator_events_armv6.c
index ee36dd0..4f1bca6 100644
--- a/driver/gator_events_armv6.c
+++ b/driver/gator_events_armv6.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -93,7 +93,7 @@ int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
93 return 0; 93 return 0;
94} 94}
95 95
96static int gator_events_armv6_online(int **buffer) 96static int gator_events_armv6_online(int **buffer, bool migrate)
97{ 97{
98 unsigned int cnt, len = 0, cpu = smp_processor_id(); 98 unsigned int cnt, len = 0, cpu = smp_processor_id();
99 u32 pmnc; 99 u32 pmnc;
@@ -141,7 +141,7 @@ static int gator_events_armv6_online(int **buffer)
141 return len; 141 return len;
142} 142}
143 143
144static int gator_events_armv6_offline(int **buffer) 144static int gator_events_armv6_offline(int **buffer, bool migrate)
145{ 145{
146 unsigned int cnt; 146 unsigned int cnt;
147 147
diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c
index 212b17b..58f2956 100644
--- a/driver/gator_events_armv7.c
+++ b/driver/gator_events_armv7.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -159,7 +159,7 @@ static int gator_events_armv7_create_files(struct super_block *sb, struct dentry
159 return 0; 159 return 0;
160} 160}
161 161
162static int gator_events_armv7_online(int **buffer) 162static int gator_events_armv7_online(int **buffer, bool migrate)
163{ 163{
164 unsigned int cnt, len = 0, cpu = smp_processor_id(); 164 unsigned int cnt, len = 0, cpu = smp_processor_id();
165 165
@@ -214,7 +214,7 @@ static int gator_events_armv7_online(int **buffer)
214 return len; 214 return len;
215} 215}
216 216
217static int gator_events_armv7_offline(int **buffer) 217static int gator_events_armv7_offline(int **buffer, bool migrate)
218{ 218{
219 // disable all counters, including PMCCNTR; overflow IRQs will not be signaled 219 // disable all counters, including PMCCNTR; overflow IRQs will not be signaled
220 armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); 220 armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
diff --git a/driver/gator_events_block.c b/driver/gator_events_block.c
index f512b13..56c6a67 100644
--- a/driver/gator_events_block.c
+++ b/driver/gator_events_block.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -30,7 +30,6 @@ static int blockGet[BLOCK_TOTAL * 4];
30 30
31GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq)) 31GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq))
32{ 32{
33 unsigned long flags;
34 int write, size; 33 int write, size;
35 34
36 if (!rq) 35 if (!rq)
@@ -42,9 +41,6 @@ GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct r
42 if (!size) 41 if (!size)
43 return; 42 return;
44 43
45 // disable interrupts to synchronize with gator_events_block_read()
46 // spinlocks not needed since percpu buffers are used
47 local_irq_save(flags);
48 if (write) { 44 if (write) {
49 if (block_rq_wr_enabled) { 45 if (block_rq_wr_enabled) {
50 atomic_add(size, &blockCnt[BLOCK_RQ_WR]); 46 atomic_add(size, &blockCnt[BLOCK_RQ_WR]);
@@ -54,7 +50,6 @@ GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct r
54 atomic_add(size, &blockCnt[BLOCK_RQ_RD]); 50 atomic_add(size, &blockCnt[BLOCK_RQ_RD]);
55 } 51 }
56 } 52 }
57 local_irq_restore(flags);
58} 53}
59 54
60static int gator_events_block_create_files(struct super_block *sb, struct dentry *root) 55static int gator_events_block_create_files(struct super_block *sb, struct dentry *root)
@@ -111,7 +106,7 @@ static int gator_events_block_read(int **buffer)
111{ 106{
112 int len, value, data = 0; 107 int len, value, data = 0;
113 108
114 if (smp_processor_id() != 0) { 109 if (!on_primary_core()) {
115 return 0; 110 return 0;
116 } 111 }
117 112
diff --git a/driver/gator_events_irq.c b/driver/gator_events_irq.c
index 1221372..b4df7fa 100644
--- a/driver/gator_events_irq.c
+++ b/driver/gator_events_irq.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -18,19 +18,13 @@ static ulong hardirq_enabled;
18static ulong softirq_enabled; 18static ulong softirq_enabled;
19static ulong hardirq_key; 19static ulong hardirq_key;
20static ulong softirq_key; 20static ulong softirq_key;
21static DEFINE_PER_CPU(int[TOTALIRQ], irqCnt); 21static DEFINE_PER_CPU(atomic_t[TOTALIRQ], irqCnt);
22static DEFINE_PER_CPU(int[TOTALIRQ * 2], irqGet); 22static DEFINE_PER_CPU(int[TOTALIRQ * 2], irqGet);
23 23
24GATOR_DEFINE_PROBE(irq_handler_exit, 24GATOR_DEFINE_PROBE(irq_handler_exit,
25 TP_PROTO(int irq, struct irqaction *action, int ret)) 25 TP_PROTO(int irq, struct irqaction *action, int ret))
26{ 26{
27 unsigned long flags; 27 atomic_inc(&per_cpu(irqCnt, get_physical_cpu())[HARDIRQ]);
28
29 // disable interrupts to synchronize with gator_events_irq_read()
30 // spinlocks not needed since percpu buffers are used
31 local_irq_save(flags);
32 per_cpu(irqCnt, smp_processor_id())[HARDIRQ]++;
33 local_irq_restore(flags);
34} 28}
35 29
36#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) 30#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
@@ -39,13 +33,7 @@ GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(struct softirq_action *h, struct softi
39GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr)) 33GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr))
40#endif 34#endif
41{ 35{
42 unsigned long flags; 36 atomic_inc(&per_cpu(irqCnt, get_physical_cpu())[SOFTIRQ]);
43
44 // disable interrupts to synchronize with gator_events_irq_read()
45 // spinlocks not needed since percpu buffers are used
46 local_irq_save(flags);
47 per_cpu(irqCnt, smp_processor_id())[SOFTIRQ]++;
48 local_irq_restore(flags);
49} 37}
50 38
51static int gator_events_irq_create_files(struct super_block *sb, struct dentry *root) 39static int gator_events_irq_create_files(struct super_block *sb, struct dentry *root)
@@ -71,24 +59,19 @@ static int gator_events_irq_create_files(struct super_block *sb, struct dentry *
71 return 0; 59 return 0;
72} 60}
73 61
74static int gator_events_irq_online(int **buffer) 62static int gator_events_irq_online(int **buffer, bool migrate)
75{ 63{
76 int len = 0, cpu = smp_processor_id(); 64 int len = 0, cpu = get_physical_cpu();
77 unsigned long flags; // not necessary as we are in interrupt context anyway, but doesn't hurt
78 65
79 // synchronization with the irq_exit functions is not necessary as the values are being reset 66 // synchronization with the irq_exit functions is not necessary as the values are being reset
80 if (hardirq_enabled) { 67 if (hardirq_enabled) {
81 local_irq_save(flags); 68 atomic_set(&per_cpu(irqCnt, cpu)[HARDIRQ], 0);
82 per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
83 local_irq_restore(flags);
84 per_cpu(irqGet, cpu)[len++] = hardirq_key; 69 per_cpu(irqGet, cpu)[len++] = hardirq_key;
85 per_cpu(irqGet, cpu)[len++] = 0; 70 per_cpu(irqGet, cpu)[len++] = 0;
86 } 71 }
87 72
88 if (softirq_enabled) { 73 if (softirq_enabled) {
89 local_irq_save(flags); 74 atomic_set(&per_cpu(irqCnt, cpu)[SOFTIRQ], 0);
90 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
91 local_irq_restore(flags);
92 per_cpu(irqGet, cpu)[len++] = softirq_key; 75 per_cpu(irqGet, cpu)[len++] = softirq_key;
93 per_cpu(irqGet, cpu)[len++] = 0; 76 per_cpu(irqGet, cpu)[len++] = 0;
94 } 77 }
@@ -136,26 +119,21 @@ static void gator_events_irq_stop(void)
136 119
137static int gator_events_irq_read(int **buffer) 120static int gator_events_irq_read(int **buffer)
138{ 121{
139 unsigned long flags; // not necessary as we are in interrupt context anyway, but doesn't hurt
140 int len, value; 122 int len, value;
141 int cpu = smp_processor_id(); 123 int cpu = get_physical_cpu();
142 124
143 len = 0; 125 len = 0;
144 if (hardirq_enabled) { 126 if (hardirq_enabled) {
145 local_irq_save(flags); 127 value = atomic_read(&per_cpu(irqCnt, cpu)[HARDIRQ]);
146 value = per_cpu(irqCnt, cpu)[HARDIRQ]; 128 atomic_sub(value, &per_cpu(irqCnt, cpu)[HARDIRQ]);
147 per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
148 local_irq_restore(flags);
149 129
150 per_cpu(irqGet, cpu)[len++] = hardirq_key; 130 per_cpu(irqGet, cpu)[len++] = hardirq_key;
151 per_cpu(irqGet, cpu)[len++] = value; 131 per_cpu(irqGet, cpu)[len++] = value;
152 } 132 }
153 133
154 if (softirq_enabled) { 134 if (softirq_enabled) {
155 local_irq_save(flags); 135 value = atomic_read(&per_cpu(irqCnt, cpu)[SOFTIRQ]);
156 value = per_cpu(irqCnt, cpu)[SOFTIRQ]; 136 atomic_sub(value, &per_cpu(irqCnt, cpu)[SOFTIRQ]);
157 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
158 local_irq_restore(flags);
159 137
160 per_cpu(irqGet, cpu)[len++] = softirq_key; 138 per_cpu(irqGet, cpu)[len++] = softirq_key;
161 per_cpu(irqGet, cpu)[len++] = value; 139 per_cpu(irqGet, cpu)[len++] = value;
diff --git a/driver/gator_events_l2c-310.c b/driver/gator_events_l2c-310.c
index 197af04..52472c7 100644
--- a/driver/gator_events_l2c-310.c
+++ b/driver/gator_events_l2c-310.c
@@ -1,7 +1,7 @@
1/** 1/**
2 * l2c310 (L2 Cache Controller) event counters for gator 2 * l2c310 (L2 Cache Controller) event counters for gator
3 * 3 *
4 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 4 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
@@ -10,6 +10,7 @@
10 10
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/io.h> 12#include <linux/io.h>
13#include <linux/module.h>
13#include <asm/hardware/cache-l2x0.h> 14#include <asm/hardware/cache-l2x0.h>
14 15
15#include "gator.h" 16#include "gator.h"
@@ -95,7 +96,7 @@ static int gator_events_l2c310_read(int **buffer)
95 int i; 96 int i;
96 int len = 0; 97 int len = 0;
97 98
98 if (smp_processor_id()) 99 if (!on_primary_core())
99 return 0; 100 return 0;
100 101
101 for (i = 0; i < L2C310_COUNTERS_NUM; i++) { 102 for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
@@ -122,20 +123,48 @@ static struct gator_interface gator_events_l2c310_interface = {
122 .read = gator_events_l2c310_read, 123 .read = gator_events_l2c310_read,
123}; 124};
124 125
125static void __maybe_unused gator_events_l2c310_probe(unsigned long phys) 126#define L2C310_ADDR_PROBE (~0)
127
128MODULE_PARM_DESC(l2c310_addr, "L2C310 physical base address (0 to disable)");
129static unsigned long l2c310_addr = L2C310_ADDR_PROBE;
130module_param(l2c310_addr, ulong, 0444);
131
132static void __iomem *gator_events_l2c310_probe(void)
126{ 133{
127 if (l2c310_base) 134 phys_addr_t variants[] = {
128 return; 135#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_S5PV310)
136 0x10502000,
137#endif
138#if defined(CONFIG_ARCH_OMAP4)
139 0x48242000,
140#endif
141#if defined(CONFIG_ARCH_TEGRA)
142 0x50043000,
143#endif
144#if defined(CONFIG_ARCH_U8500)
145 0xa0412000,
146#endif
147#if defined(CONFIG_ARCH_VEXPRESS)
148 0x1e00a000, // A9x4 core tile (HBI-0191)
149 0x2c0f0000, // New memory map tiles
150#endif
151 };
152 int i;
129 153
130 l2c310_base = ioremap(phys, SZ_4K); 154 for (i = 0; i < ARRAY_SIZE(variants); i++) {
131 if (l2c310_base) { 155 void __iomem *base = ioremap(variants[i], SZ_4K);
132 u32 cache_id = readl(l2c310_base + L2X0_CACHE_ID);
133 156
134 if ((cache_id & 0xff0003c0) != 0x410000c0) { 157 if (base) {
135 iounmap(l2c310_base); 158 u32 cache_id = readl(base + L2X0_CACHE_ID);
136 l2c310_base = NULL; 159
160 if ((cache_id & 0xff0003c0) == 0x410000c0)
161 return base;
162
163 iounmap(base);
137 } 164 }
138 } 165 }
166
167 return NULL;
139} 168}
140 169
141int gator_events_l2c310_init(void) 170int gator_events_l2c310_init(void)
@@ -145,24 +174,11 @@ int gator_events_l2c310_init(void)
145 if (gator_cpuid() != CORTEX_A5 && gator_cpuid() != CORTEX_A9) 174 if (gator_cpuid() != CORTEX_A5 && gator_cpuid() != CORTEX_A9)
146 return -1; 175 return -1;
147 176
148#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_S5PV310) 177 if (l2c310_addr == L2C310_ADDR_PROBE)
149 gator_events_l2c310_probe(0x10502000); 178 l2c310_base = gator_events_l2c310_probe();
150#endif 179 else if (l2c310_addr)
151#if defined(CONFIG_ARCH_OMAP4) 180 l2c310_base = ioremap(l2c310_addr, SZ_4K);
152 gator_events_l2c310_probe(0x48242000); 181
153#endif
154#if defined(CONFIG_ARCH_TEGRA)
155 gator_events_l2c310_probe(0x50043000);
156#endif
157#if defined(CONFIG_ARCH_U8500)
158 gator_events_l2c310_probe(0xa0412000);
159#endif
160#if defined(CONFIG_ARCH_VEXPRESS)
161 // A9x4 core tile (HBI-0191)
162 gator_events_l2c310_probe(0x1e00a000);
163 // New memory map tiles
164 gator_events_l2c310_probe(0x2c0f0000);
165#endif
166 if (!l2c310_base) 182 if (!l2c310_base)
167 return -1; 183 return -1;
168 184
diff --git a/driver/gator_events_mali_400.c b/driver/gator_events_mali_400.c
index 4888b54..38c97d1 100644
--- a/driver/gator_events_mali_400.c
+++ b/driver/gator_events_mali_400.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -17,14 +17,6 @@
17#include "gator_events_mali_common.h" 17#include "gator_events_mali_common.h"
18#include "gator_events_mali_400.h" 18#include "gator_events_mali_400.h"
19 19
20#if !defined(GATOR_MALI_INTERFACE_STYLE)
21/*
22 * At the moment, we only have users with the old style interface, so
23 * make our life easier by making it the default...
24 */
25#define GATOR_MALI_INTERFACE_STYLE (2)
26#endif
27
28/* 20/*
29 * There are (currently) three different variants of the comms between gator and Mali: 21 * There are (currently) three different variants of the comms between gator and Mali:
30 * 1 (deprecated): No software counter support 22 * 1 (deprecated): No software counter support
@@ -638,7 +630,7 @@ static int read(int **buffer)
638{ 630{
639 int cnt, len = 0; 631 int cnt, len = 0;
640 632
641 if (smp_processor_id()) 633 if (!on_primary_core())
642 return 0; 634 return 0;
643 635
644 // Read the L2 C0 and C1 here. 636 // Read the L2 C0 and C1 here.
diff --git a/driver/gator_events_mali_400.h b/driver/gator_events_mali_400.h
index a09757e..43aec49 100644
--- a/driver/gator_events_mali_400.h
+++ b/driver/gator_events_mali_400.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_mali_common.c b/driver/gator_events_mali_common.c
index 2186eee..22a517d 100644
--- a/driver/gator_events_mali_common.c
+++ b/driver/gator_events_mali_common.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_mali_common.h b/driver/gator_events_mali_common.h
index 8e33edf..27eaacc 100644
--- a/driver/gator_events_mali_common.h
+++ b/driver/gator_events_mali_common.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_mali_t6xx.c b/driver/gator_events_mali_t6xx.c
index 1b3a53d..2576a99 100644
--- a/driver/gator_events_mali_t6xx.c
+++ b/driver/gator_events_mali_t6xx.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -411,7 +411,7 @@ static int read(int **buffer)
411 long sample_interval_us = 0; 411 long sample_interval_us = 0;
412 struct timespec read_timestamp; 412 struct timespec read_timestamp;
413 413
414 if (smp_processor_id() != 0) { 414 if (!on_primary_core()) {
415 return 0; 415 return 0;
416 } 416 }
417 417
diff --git a/driver/gator_events_mali_t6xx_hw.c b/driver/gator_events_mali_t6xx_hw.c
index 72498c8..fb2e15c 100644
--- a/driver/gator_events_mali_t6xx_hw.c
+++ b/driver/gator_events_mali_t6xx_hw.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -608,7 +608,7 @@ static int read(int **buffer)
608 static u32 prev_time_s = 0; 608 static u32 prev_time_s = 0;
609 static s32 next_read_time_ns = 0; 609 static s32 next_read_time_ns = 0;
610 610
611 if (smp_processor_id() != 0) { 611 if (!on_primary_core()) {
612 return 0; 612 return 0;
613 } 613 }
614 614
diff --git a/driver/gator_events_mali_t6xx_hw_test.c b/driver/gator_events_mali_t6xx_hw_test.c
index eb77110..efb32dd 100644
--- a/driver/gator_events_mali_t6xx_hw_test.c
+++ b/driver/gator_events_mali_t6xx_hw_test.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_events_meminfo.c b/driver/gator_events_meminfo.c
index fd063b2..c1e360d 100644
--- a/driver/gator_events_meminfo.c
+++ b/driver/gator_events_meminfo.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -198,7 +198,7 @@ static int gator_events_meminfo_read(long long **buffer)
198{ 198{
199 static unsigned int last_mem_event = 0; 199 static unsigned int last_mem_event = 0;
200 200
201 if (smp_processor_id() || !meminfo_global_enabled) 201 if (!on_primary_core() || !meminfo_global_enabled)
202 return 0; 202 return 0;
203 203
204 if (last_mem_event != mem_event) { 204 if (last_mem_event != mem_event) {
diff --git a/driver/gator_events_mmaped.c b/driver/gator_events_mmaped.c
index c4cb44f..0027564 100644
--- a/driver/gator_events_mmaped.c
+++ b/driver/gator_events_mmaped.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Example events provider 2 * Example events provider
3 * 3 *
4 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 4 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
@@ -141,7 +141,7 @@ static int mmaped_simulate(int counter, int delta_in_us)
141 break; 141 break;
142 case 2: /* PWM signal */ 142 case 2: /* PWM signal */
143 { 143 {
144 static int t, dc, x; 144 static int dc, x, t = 0;
145 145
146 t += delta_in_us; 146 t += delta_in_us;
147 if (t > 1000000) 147 if (t > 1000000)
@@ -170,7 +170,7 @@ static int gator_events_mmaped_read(int **buffer)
170#endif 170#endif
171 171
172 /* System wide counters - read from one core only */ 172 /* System wide counters - read from one core only */
173 if (smp_processor_id()) 173 if (!on_primary_core())
174 return 0; 174 return 0;
175 175
176#ifndef TODO 176#ifndef TODO
diff --git a/driver/gator_events_net.c b/driver/gator_events_net.c
index b6ce06a..80cdee4 100644
--- a/driver/gator_events_net.c
+++ b/driver/gator_events_net.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -117,7 +117,7 @@ static int gator_events_net_read(int **buffer)
117 int len, rx_delta, tx_delta; 117 int len, rx_delta, tx_delta;
118 static int last_rx_delta = 0, last_tx_delta = 0; 118 static int last_rx_delta = 0, last_tx_delta = 0;
119 119
120 if (smp_processor_id() != 0) 120 if (!on_primary_core())
121 return 0; 121 return 0;
122 122
123 if (!netrx_enabled && !nettx_enabled) 123 if (!netrx_enabled && !nettx_enabled)
diff --git a/driver/gator_events_perf_pmu.c b/driver/gator_events_perf_pmu.c
index ce3a40f..34a6bc7 100644
--- a/driver/gator_events_perf_pmu.c
+++ b/driver/gator_events_perf_pmu.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -13,49 +13,74 @@
13// gator_events_armvX.c is used for Linux 2.6.x 13// gator_events_armvX.c is used for Linux 2.6.x
14#if GATOR_PERF_PMU_SUPPORT 14#if GATOR_PERF_PMU_SUPPORT
15 15
16static const char *pmnc_name; 16extern bool event_based_sampling;
17int pmnc_counters;
18int ccnt = 0;
19 17
20#define CNTMAX (6+1) 18#define CNTMAX 16
19#define CCI_400 4
20// + 1 for the cci-400 cycles counter
21#define UCCNT (CCI_400 + 1)
21 22
22static DEFINE_MUTEX(perf_mutex); 23struct gator_attr {
24 char name[40];
25 unsigned long enabled;
26 unsigned long type;
27 unsigned long event;
28 unsigned long count;
29 unsigned long key;
30};
23 31
24unsigned long pmnc_enabled[CNTMAX]; 32static struct gator_attr attrs[CNTMAX];
25unsigned long pmnc_event[CNTMAX]; 33static int attr_count;
26unsigned long pmnc_count[CNTMAX]; 34static struct gator_attr uc_attrs[UCCNT];
27unsigned long pmnc_key[CNTMAX]; 35static int uc_attr_count;
36
37struct gator_event {
38 int curr;
39 int prev;
40 int prev_delta;
41 bool zero;
42 struct perf_event *pevent;
43 struct perf_event_attr *pevent_attr;
44};
28 45
29static DEFINE_PER_CPU(int[CNTMAX], perfCurr); 46static DEFINE_PER_CPU(struct gator_event[CNTMAX], events);
30static DEFINE_PER_CPU(int[CNTMAX], perfPrev); 47static struct gator_event uc_events[UCCNT];
31static DEFINE_PER_CPU(int[CNTMAX], perfPrevDelta); 48static DEFINE_PER_CPU(int[(CNTMAX + UCCNT)*2], perf_cnt);
32static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
33static DEFINE_PER_CPU(struct perf_event *[CNTMAX], pevent);
34static DEFINE_PER_CPU(struct perf_event_attr *[CNTMAX], pevent_attr);
35 49
36static void gator_events_perf_pmu_stop(void); 50static void gator_events_perf_pmu_stop(void);
37 51
38static int gator_events_perf_pmu_create_files(struct super_block *sb, struct dentry *root) 52static int __create_files(struct super_block *sb, struct dentry *root, struct gator_attr *const attr)
39{ 53{
40 struct dentry *dir; 54 struct dentry *dir;
41 int i;
42 55
43 for (i = 0; i < pmnc_counters; i++) { 56 if (attr->name[0] == '\0') {
44 char buf[40]; 57 return 0;
45 if (i == 0) { 58 }
46 snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name); 59 dir = gatorfs_mkdir(sb, root, attr->name);
47 } else { 60 if (!dir) {
48 snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1); 61 return -1;
49 } 62 }
50 dir = gatorfs_mkdir(sb, root, buf); 63 gatorfs_create_ulong(sb, dir, "enabled", &attr->enabled);
51 if (!dir) { 64 gatorfs_create_ulong(sb, dir, "count", &attr->count);
65 gatorfs_create_ro_ulong(sb, dir, "key", &attr->key);
66 gatorfs_create_ulong(sb, dir, "event", &attr->event);
67
68 return 0;
69}
70
71static int gator_events_perf_pmu_create_files(struct super_block *sb, struct dentry *root)
72{
73 int cnt;
74
75 for (cnt = 0; cnt < attr_count; cnt++) {
76 if (__create_files(sb, root, &attrs[cnt]) != 0) {
52 return -1; 77 return -1;
53 } 78 }
54 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]); 79 }
55 gatorfs_create_ulong(sb, dir, "count", &pmnc_count[i]); 80
56 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]); 81 for (cnt = 0; cnt < uc_attr_count; cnt++) {
57 if (i > 0) { 82 if (__create_files(sb, root, &uc_attrs[cnt]) != 0) {
58 gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]); 83 return -1;
59 } 84 }
60 } 85 }
61 86
@@ -80,177 +105,268 @@ static void dummy_handler(struct perf_event *event, struct perf_sample_data *dat
80// Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll 105// Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll
81} 106}
82 107
83static int gator_events_perf_pmu_online(int **buffer) 108static int gator_events_perf_pmu_read(int **buffer);
109
110static int gator_events_perf_pmu_online(int **buffer, bool migrate)
84{ 111{
85 int cnt, len = 0, cpu = smp_processor_id(); 112 return gator_events_perf_pmu_read(buffer);
113}
86 114
87 // read the counters and toss the invalid data, return zero instead 115static void __online_dispatch(int cpu, bool migrate, struct gator_attr *const attr, struct gator_event *const event)
88 for (cnt = 0; cnt < pmnc_counters; cnt++) { 116{
89 struct perf_event *ev = per_cpu(pevent, cpu)[cnt]; 117 perf_overflow_handler_t handler;
90 if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) { 118
91 ev->pmu->read(ev); 119 event->zero = true;
92 per_cpu(perfPrev, cpu)[cnt] = per_cpu(perfCurr, cpu)[cnt] = local64_read(&ev->count); 120
93 per_cpu(perfPrevDelta, cpu)[cnt] = 0; 121 if (event->pevent != NULL || event->pevent_attr == 0 || migrate) {
94 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; 122 return;
95 per_cpu(perfCnt, cpu)[len++] = 0;
96 }
97 } 123 }
98 124
99 if (buffer) 125 if (attr->count > 0) {
100 *buffer = per_cpu(perfCnt, cpu); 126 handler = ebs_overflow_handler;
127 } else {
128 handler = dummy_handler;
129 }
101 130
102 return len; 131#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
132 event->pevent = perf_event_create_kernel_counter(event->pevent_attr, cpu, 0, handler);
133#else
134 event->pevent = perf_event_create_kernel_counter(event->pevent_attr, cpu, 0, handler, 0);
135#endif
136 if (IS_ERR(event->pevent)) {
137 pr_debug("gator: unable to online a counter on cpu %d\n", cpu);
138 event->pevent = NULL;
139 return;
140 }
141
142 if (event->pevent->state != PERF_EVENT_STATE_ACTIVE) {
143 pr_debug("gator: inactive counter on cpu %d\n", cpu);
144 perf_event_release_kernel(event->pevent);
145 event->pevent = NULL;
146 return;
147 }
103} 148}
104 149
105static void gator_events_perf_pmu_online_dispatch(int cpu) 150static void gator_events_perf_pmu_online_dispatch(int cpu, bool migrate)
106{ 151{
107 int cnt; 152 int cnt;
108 perf_overflow_handler_t handler;
109 153
110 for (cnt = 0; cnt < pmnc_counters; cnt++) { 154 cpu = pcpu_to_lcpu(cpu);
111 if (per_cpu(pevent, cpu)[cnt] != NULL || per_cpu(pevent_attr, cpu)[cnt] == 0)
112 continue;
113 155
114 if (pmnc_count[cnt] > 0) { 156 for (cnt = 0; cnt < attr_count; cnt++) {
115 handler = ebs_overflow_handler; 157 __online_dispatch(cpu, migrate, &attrs[cnt], &per_cpu(events, cpu)[cnt]);
116 } else { 158 }
117 handler = dummy_handler;
118 }
119 159
120#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) 160 if (cpu == 0) {
121 per_cpu(pevent, cpu)[cnt] = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu)[cnt], cpu, 0, handler); 161 for (cnt = 0; cnt < uc_attr_count; cnt++) {
122#else 162 __online_dispatch(cpu, migrate, &uc_attrs[cnt], &uc_events[cnt]);
123 per_cpu(pevent, cpu)[cnt] = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu)[cnt], cpu, 0, handler, 0);
124#endif
125 if (IS_ERR(per_cpu(pevent, cpu)[cnt])) {
126 pr_debug("gator: unable to online a counter on cpu %d\n", cpu);
127 per_cpu(pevent, cpu)[cnt] = NULL;
128 continue;
129 } 163 }
164 }
165}
130 166
131 if (per_cpu(pevent, cpu)[cnt]->state != PERF_EVENT_STATE_ACTIVE) { 167static void __offline_dispatch(int cpu, struct gator_event *const event)
132 pr_debug("gator: inactive counter on cpu %d\n", cpu); 168{
133 perf_event_release_kernel(per_cpu(pevent, cpu)[cnt]); 169 struct perf_event *pe = NULL;
134 per_cpu(pevent, cpu)[cnt] = NULL; 170
135 continue; 171 if (event->pevent) {
136 } 172 pe = event->pevent;
173 event->pevent = NULL;
174 }
175
176 if (pe) {
177 perf_event_release_kernel(pe);
137 } 178 }
138} 179}
139 180
140static void gator_events_perf_pmu_offline_dispatch(int cpu) 181static void gator_events_perf_pmu_offline_dispatch(int cpu, bool migrate)
141{ 182{
142 int cnt; 183 int cnt;
143 struct perf_event *pe;
144 184
145 for (cnt = 0; cnt < pmnc_counters; cnt++) { 185 if (migrate) {
146 pe = NULL; 186 return;
147 mutex_lock(&perf_mutex); 187 }
148 if (per_cpu(pevent, cpu)[cnt]) { 188 cpu = pcpu_to_lcpu(cpu);
149 pe = per_cpu(pevent, cpu)[cnt]; 189
150 per_cpu(pevent, cpu)[cnt] = NULL; 190 for (cnt = 0; cnt < attr_count; cnt++) {
191 __offline_dispatch(cpu, &per_cpu(events, cpu)[cnt]);
192 }
193
194 if (cpu == 0) {
195 for (cnt = 0; cnt < uc_attr_count; cnt++) {
196 __offline_dispatch(cpu, &uc_events[cnt]);
151 } 197 }
152 mutex_unlock(&perf_mutex); 198 }
199}
153 200
154 if (pe) { 201static int __check_ebs(struct gator_attr *const attr)
155 perf_event_release_kernel(pe); 202{
203 if (attr->count > 0) {
204 if (!event_based_sampling) {
205 event_based_sampling = true;
206 } else {
207 printk(KERN_WARNING "gator: Only one ebs counter is allowed\n");
208 return -1;
156 } 209 }
157 } 210 }
211
212 return 0;
213}
214
215static int __start(struct gator_attr *const attr, struct gator_event *const event)
216{
217 u32 size = sizeof(struct perf_event_attr);
218
219 event->pevent = NULL;
220 if (!attr->enabled) { // Skip disabled counters
221 return 0;
222 }
223
224 event->prev = 0;
225 event->curr = 0;
226 event->prev_delta = 0;
227 event->pevent_attr = kmalloc(size, GFP_KERNEL);
228 if (!event->pevent_attr) {
229 gator_events_perf_pmu_stop();
230 return -1;
231 }
232
233 memset(event->pevent_attr, 0, size);
234 event->pevent_attr->type = attr->type;
235 event->pevent_attr->size = size;
236 event->pevent_attr->config = attr->event;
237 event->pevent_attr->sample_period = attr->count;
238 event->pevent_attr->pinned = 1;
239
240 return 0;
158} 241}
159 242
160static int gator_events_perf_pmu_start(void) 243static int gator_events_perf_pmu_start(void)
161{ 244{
162 int cnt, cpu; 245 int cnt, cpu;
163 u32 size = sizeof(struct perf_event_attr); 246
164 int found_ebs = false; 247 event_based_sampling = false;
165 248 for (cnt = 0; cnt < attr_count; cnt++) {
166 for (cnt = 0; cnt < pmnc_counters; cnt++) { 249 if (__check_ebs(&attrs[cnt]) != 0) {
167 if (pmnc_count[cnt] > 0) { 250 return -1;
168 if (!found_ebs) { 251 }
169 found_ebs = true; 252 }
170 } else { 253
171 // Only one ebs counter is allowed 254 for (cnt = 0; cnt < uc_attr_count; cnt++) {
172 return -1; 255 if (__check_ebs(&uc_attrs[cnt]) != 0) {
173 } 256 return -1;
174 } 257 }
175 } 258 }
176 259
177 for_each_present_cpu(cpu) { 260 for_each_present_cpu(cpu) {
178 for (cnt = 0; cnt < pmnc_counters; cnt++) { 261 for (cnt = 0; cnt < attr_count; cnt++) {
179 per_cpu(pevent, cpu)[cnt] = NULL; 262 if (__start(&attrs[cnt], &per_cpu(events, cpu)[cnt]) != 0) {
180 if (!pmnc_enabled[cnt]) // Skip disabled counters
181 continue;
182
183 per_cpu(perfPrev, cpu)[cnt] = 0;
184 per_cpu(perfCurr, cpu)[cnt] = 0;
185 per_cpu(perfPrevDelta, cpu)[cnt] = 0;
186 per_cpu(pevent_attr, cpu)[cnt] = kmalloc(size, GFP_KERNEL);
187 if (!per_cpu(pevent_attr, cpu)[cnt]) {
188 gator_events_perf_pmu_stop();
189 return -1; 263 return -1;
190 } 264 }
265 }
266 }
191 267
192 memset(per_cpu(pevent_attr, cpu)[cnt], 0, size); 268 for (cnt = 0; cnt < uc_attr_count; cnt++) {
193 per_cpu(pevent_attr, cpu)[cnt]->type = PERF_TYPE_RAW; 269 if (__start(&uc_attrs[cnt], &uc_events[cnt]) != 0) {
194 per_cpu(pevent_attr, cpu)[cnt]->size = size; 270 return -1;
195 per_cpu(pevent_attr, cpu)[cnt]->config = pmnc_event[cnt];
196 per_cpu(pevent_attr, cpu)[cnt]->sample_period = pmnc_count[cnt];
197 per_cpu(pevent_attr, cpu)[cnt]->pinned = 1;
198
199 // handle special case for ccnt
200 if (cnt == ccnt) {
201 per_cpu(pevent_attr, cpu)[cnt]->type = PERF_TYPE_HARDWARE;
202 per_cpu(pevent_attr, cpu)[cnt]->config = PERF_COUNT_HW_CPU_CYCLES;
203 }
204 } 271 }
205 } 272 }
206 273
207 return 0; 274 return 0;
208} 275}
209 276
277static void __event_stop(struct gator_event *const event)
278{
279 if (event->pevent_attr) {
280 kfree(event->pevent_attr);
281 event->pevent_attr = NULL;
282 }
283}
284
285static void __attr_stop(struct gator_attr *const attr)
286{
287 attr->enabled = 0;
288 attr->event = 0;
289 attr->count = 0;
290}
291
210static void gator_events_perf_pmu_stop(void) 292static void gator_events_perf_pmu_stop(void)
211{ 293{
212 unsigned int cnt, cpu; 294 unsigned int cnt, cpu;
213 295
214 for_each_present_cpu(cpu) { 296 for_each_present_cpu(cpu) {
215 for (cnt = 0; cnt < pmnc_counters; cnt++) { 297 for (cnt = 0; cnt < attr_count; cnt++) {
216 if (per_cpu(pevent_attr, cpu)[cnt]) { 298 __event_stop(&per_cpu(events, cpu)[cnt]);
217 kfree(per_cpu(pevent_attr, cpu)[cnt]);
218 per_cpu(pevent_attr, cpu)[cnt] = NULL;
219 }
220 } 299 }
221 } 300 }
222 301
223 for (cnt = 0; cnt < pmnc_counters; cnt++) { 302 for (cnt = 0; cnt < uc_attr_count; cnt++) {
224 pmnc_enabled[cnt] = 0; 303 __event_stop(&uc_events[cnt]);
225 pmnc_event[cnt] = 0; 304 }
226 pmnc_count[cnt] = 0; 305
306 for (cnt = 0; cnt < attr_count; cnt++) {
307 __attr_stop(&attrs[cnt]);
308 }
309
310 for (cnt = 0; cnt < uc_attr_count; cnt++) {
311 __attr_stop(&uc_attrs[cnt]);
227 } 312 }
228} 313}
229 314
230static int gator_events_perf_pmu_read(int **buffer) 315static void __read(int *const len, int cpu, struct gator_attr *const attr, struct gator_event *const event)
231{ 316{
232 int cnt, delta, len = 0; 317 int delta;
233 int cpu = smp_processor_id(); 318
234 319 struct perf_event *const ev = event->pevent;
235 for (cnt = 0; cnt < pmnc_counters; cnt++) { 320 if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
236 struct perf_event *ev = per_cpu(pevent, cpu)[cnt]; 321 /* After creating the perf counter in __online_dispatch, there
237 if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) { 322 * is a race condition between gator_events_perf_pmu_online and
323 * gator_events_perf_pmu_read. So have
324 * gator_events_perf_pmu_online call gator_events_perf_pmu_read
325 * and in __read check to see if it's the first call after
326 * __online_dispatch and if so, run the online code.
327 */
328 if (event->zero) {
329 ev->pmu->read(ev);
330 event->prev = event->curr = local64_read(&ev->count);
331 event->prev_delta = 0;
332 per_cpu(perf_cnt, cpu)[(*len)++] = attr->key;
333 per_cpu(perf_cnt, cpu)[(*len)++] = 0;
334 event->zero = false;
335 } else {
238 ev->pmu->read(ev); 336 ev->pmu->read(ev);
239 per_cpu(perfCurr, cpu)[cnt] = local64_read(&ev->count); 337 event->curr = local64_read(&ev->count);
240 delta = per_cpu(perfCurr, cpu)[cnt] - per_cpu(perfPrev, cpu)[cnt]; 338 delta = event->curr - event->prev;
241 if (delta != 0 || delta != per_cpu(perfPrevDelta, cpu)[cnt]) { 339 if (delta != 0 || delta != event->prev_delta) {
242 per_cpu(perfPrevDelta, cpu)[cnt] = delta; 340 event->prev_delta = delta;
243 per_cpu(perfPrev, cpu)[cnt] = per_cpu(perfCurr, cpu)[cnt]; 341 event->prev = event->curr;
244 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; 342 per_cpu(perf_cnt, cpu)[(*len)++] = attr->key;
245 if (delta < 0) 343 if (delta < 0) {
246 delta *= -1; 344 delta *= -1;
247 per_cpu(perfCnt, cpu)[len++] = delta; 345 }
346 per_cpu(perf_cnt, cpu)[(*len)++] = delta;
248 } 347 }
249 } 348 }
250 } 349 }
350}
251 351
252 if (buffer) 352static int gator_events_perf_pmu_read(int **buffer)
253 *buffer = per_cpu(perfCnt, cpu); 353{
354 int cnt, len = 0;
355 const int cpu = get_logical_cpu();
356
357 for (cnt = 0; cnt < attr_count; cnt++) {
358 __read(&len, cpu, &attrs[cnt], &per_cpu(events, cpu)[cnt]);
359 }
360
361 if (cpu == 0) {
362 for (cnt = 0; cnt < uc_attr_count; cnt++) {
363 __read(&len, cpu, &uc_attrs[cnt], &uc_events[cnt]);
364 }
365 }
366
367 if (buffer) {
368 *buffer = per_cpu(perf_cnt, cpu);
369 }
254 370
255 return len; 371 return len;
256} 372}
@@ -265,30 +381,116 @@ static struct gator_interface gator_events_perf_pmu_interface = {
265 .read = gator_events_perf_pmu_read, 381 .read = gator_events_perf_pmu_read,
266}; 382};
267 383
384static void __attr_init(struct gator_attr *const attr)
385{
386 attr->name[0] = '\0';
387 attr->enabled = 0;
388 attr->type = 0;
389 attr->event = 0;
390 attr->count = 0;
391 attr->key = gator_events_get_key();
392}
393
394static void gator_events_perf_pmu_cci_init(const int type)
395{
396 int cnt;
397
398 strncpy(uc_attrs[uc_attr_count].name, "cci-400_ccnt", sizeof(uc_attrs[uc_attr_count].name));
399 uc_attrs[uc_attr_count].type = type;
400 ++uc_attr_count;
401
402 for (cnt = 0; cnt < CCI_400; ++cnt, ++uc_attr_count) {
403 struct gator_attr *const attr = &uc_attrs[uc_attr_count];
404 snprintf(attr->name, sizeof(attr->name), "cci-400_cnt%d", cnt);
405 attr->type = type;
406 }
407}
408
409static void gator_events_perf_pmu_cpu_init(const struct gator_cpu *const gator_cpu, const int type)
410{
411 int cnt;
412
413 snprintf(attrs[attr_count].name, sizeof(attrs[attr_count].name), "%s_ccnt", gator_cpu->pmnc_name);
414 attrs[attr_count].type = type;
415 ++attr_count;
416
417 for (cnt = 0; cnt < gator_cpu->pmnc_counters; ++cnt, ++attr_count) {
418 struct gator_attr *const attr = &attrs[attr_count];
419 snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", gator_cpu->pmnc_name, cnt);
420 attr->type = type;
421 }
422}
423
268int gator_events_perf_pmu_init(void) 424int gator_events_perf_pmu_init(void)
269{ 425{
270 unsigned int cnt; 426 struct perf_event_attr pea;
271 const u32 cpuid = gator_cpuid(); 427 struct perf_event *pe;
272 428 const struct gator_cpu *gator_cpu;
273 for (cnt = 0; gator_cpus[cnt].cpuid != 0; ++cnt) { 429 int type;
274 if (gator_cpus[cnt].cpuid == cpuid) { 430 int cpu;
275 pmnc_name = gator_cpus[cnt].pmnc_name; 431 int cnt;
276 pmnc_counters = gator_cpus[cnt].pmnc_counters; 432 bool found_cpu = false;
277 ccnt = gator_cpus[cnt].ccnt; 433
434 for (cnt = 0; cnt < CNTMAX; cnt++) {
435 __attr_init(&attrs[cnt]);
436 }
437 for (cnt = 0; cnt < UCCNT; cnt++) {
438 __attr_init(&uc_attrs[cnt]);
439 }
440
441 memset(&pea, 0, sizeof(pea));
442 pea.size = sizeof(pea);
443 pea.config = 0xFF;
444 attr_count = 0;
445 uc_attr_count = 0;
446 for (type = PERF_TYPE_MAX; type < 0x20; ++type) {
447 pea.type = type;
448
449 // A particular PMU may work on some but not all cores, so try on each core
450 pe = NULL;
451 for_each_present_cpu(cpu) {
452#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
453 pe = perf_event_create_kernel_counter(&pea, cpu, 0, dummy_handler);
454#else
455 pe = perf_event_create_kernel_counter(&pea, cpu, 0, dummy_handler, 0);
456#endif
457 if (!IS_ERR(pe)) {
458 break;
459 }
460 }
461 // Assume that valid PMUs are contigious
462 if (IS_ERR(pe)) {
278 break; 463 break;
279 } 464 }
465
466 if (pe->pmu != NULL && type == pe->pmu->type) {
467 if (strcmp("CCI", pe->pmu->name) == 0) {
468 gator_events_perf_pmu_cci_init(type);
469 } else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) {
470 found_cpu = true;
471 gator_events_perf_pmu_cpu_init(gator_cpu, type);
472 }
473 }
474
475 perf_event_release_kernel(pe);
280 } 476 }
281 if (gator_cpus[cnt].cpuid == 0) { 477
282 return -1; 478 if (!found_cpu) {
479 const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(gator_cpuid());
480 if (gator_cpu == NULL) {
481 return -1;
482 }
483 gator_events_perf_pmu_cpu_init(gator_cpu, PERF_TYPE_RAW);
283 } 484 }
284 485
285 pmnc_counters++; // CNT[n] + CCNT 486 if (attr_count > CNTMAX) {
487 printk(KERN_ERR "gator: Too many perf counters\n");
488 return -1;
489 }
286 490
287 for (cnt = 0; cnt < CNTMAX; cnt++) { 491 if (uc_attr_count > UCCNT) {
288 pmnc_enabled[cnt] = 0; 492 printk(KERN_ERR "gator: Too many perf uncore counters\n");
289 pmnc_event[cnt] = 0; 493 return -1;
290 pmnc_count[cnt] = 0;
291 pmnc_key[cnt] = gator_events_get_key();
292 } 494 }
293 495
294 return gator_events_install(&gator_events_perf_pmu_interface); 496 return gator_events_install(&gator_events_perf_pmu_interface);
diff --git a/driver/gator_events_sched.c b/driver/gator_events_sched.c
index ba6744d..461a051 100644
--- a/driver/gator_events_sched.c
+++ b/driver/gator_events_sched.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -29,7 +29,7 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_
29 // disable interrupts to synchronize with gator_events_sched_read() 29 // disable interrupts to synchronize with gator_events_sched_read()
30 // spinlocks not needed since percpu buffers are used 30 // spinlocks not needed since percpu buffers are used
31 local_irq_save(flags); 31 local_irq_save(flags);
32 per_cpu(schedCnt, smp_processor_id())[SCHED_SWITCH]++; 32 per_cpu(schedCnt, get_physical_cpu())[SCHED_SWITCH]++;
33 local_irq_restore(flags); 33 local_irq_restore(flags);
34} 34}
35 35
@@ -78,7 +78,7 @@ static int gator_events_sched_read(int **buffer)
78{ 78{
79 unsigned long flags; 79 unsigned long flags;
80 int len, value; 80 int len, value;
81 int cpu = smp_processor_id(); 81 int cpu = get_physical_cpu();
82 82
83 len = 0; 83 len = 0;
84 if (sched_switch_enabled) { 84 if (sched_switch_enabled) {
diff --git a/driver/gator_events_scorpion.c b/driver/gator_events_scorpion.c
index 5ffc63a..aaf306a 100644
--- a/driver/gator_events_scorpion.c
+++ b/driver/gator_events_scorpion.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -524,7 +524,7 @@ static int gator_events_scorpion_create_files(struct super_block *sb, struct den
524 return 0; 524 return 0;
525} 525}
526 526
527static int gator_events_scorpion_online(int **buffer) 527static int gator_events_scorpion_online(int **buffer, bool migrate)
528{ 528{
529 unsigned int cnt, len = 0, cpu = smp_processor_id(); 529 unsigned int cnt, len = 0, cpu = smp_processor_id();
530 530
@@ -581,7 +581,7 @@ static int gator_events_scorpion_online(int **buffer)
581 return len; 581 return len;
582} 582}
583 583
584static int gator_events_scorpion_offline(int **buffer) 584static int gator_events_scorpion_offline(int **buffer, bool migrate)
585{ 585{
586 scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E); 586 scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
587 return 0; 587 return 0;
diff --git a/driver/gator_fs.c b/driver/gator_fs.c
index 9ff118b..fe6f83d 100644
--- a/driver/gator_fs.c
+++ b/driver/gator_fs.c
@@ -53,6 +53,15 @@ ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count,
53 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen); 53 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
54} 54}
55 55
56ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff_t *offset)
57{
58 char tmpbuf[TMPBUFSIZE];
59 size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%llu\n", val);
60 if (maxlen > TMPBUFSIZE)
61 maxlen = TMPBUFSIZE;
62 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
63}
64
56int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count) 65int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
57{ 66{
58 char tmpbuf[TMPBUFSIZE]; 67 char tmpbuf[TMPBUFSIZE];
@@ -75,12 +84,40 @@ int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t c
75 return 0; 84 return 0;
76} 85}
77 86
87int gatorfs_u64_from_user(u64 *val, char const __user *buf, size_t count)
88{
89 char tmpbuf[TMPBUFSIZE];
90 unsigned long flags;
91
92 if (!count)
93 return 0;
94
95 if (count > TMPBUFSIZE - 1)
96 return -EINVAL;
97
98 memset(tmpbuf, 0x0, TMPBUFSIZE);
99
100 if (copy_from_user(tmpbuf, buf, count))
101 return -EFAULT;
102
103 spin_lock_irqsave(&gatorfs_lock, flags);
104 *val = simple_strtoull(tmpbuf, NULL, 0);
105 spin_unlock_irqrestore(&gatorfs_lock, flags);
106 return 0;
107}
108
78static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) 109static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
79{ 110{
80 unsigned long *val = file->private_data; 111 unsigned long *val = file->private_data;
81 return gatorfs_ulong_to_user(*val, buf, count, offset); 112 return gatorfs_ulong_to_user(*val, buf, count, offset);
82} 113}
83 114
115static ssize_t u64_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
116{
117 u64 *val = file->private_data;
118 return gatorfs_u64_to_user(*val, buf, count, offset);
119}
120
84static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset) 121static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
85{ 122{
86 unsigned long *value = file->private_data; 123 unsigned long *value = file->private_data;
@@ -96,6 +133,21 @@ static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_
96 return count; 133 return count;
97} 134}
98 135
136static ssize_t u64_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
137{
138 u64 *value = file->private_data;
139 int retval;
140
141 if (*offset)
142 return -EINVAL;
143
144 retval = gatorfs_u64_from_user(value, buf, count);
145
146 if (retval)
147 return retval;
148 return count;
149}
150
99static int default_open(struct inode *inode, struct file *filp) 151static int default_open(struct inode *inode, struct file *filp)
100{ 152{
101 if (inode->i_private) 153 if (inode->i_private)
@@ -109,11 +161,22 @@ static const struct file_operations ulong_fops = {
109 .open = default_open, 161 .open = default_open,
110}; 162};
111 163
164static const struct file_operations u64_fops = {
165 .read = u64_read_file,
166 .write = u64_write_file,
167 .open = default_open,
168};
169
112static const struct file_operations ulong_ro_fops = { 170static const struct file_operations ulong_ro_fops = {
113 .read = ulong_read_file, 171 .read = ulong_read_file,
114 .open = default_open, 172 .open = default_open,
115}; 173};
116 174
175static const struct file_operations u64_ro_fops = {
176 .read = u64_read_file,
177 .open = default_open,
178};
179
117static struct dentry *__gatorfs_create_file(struct super_block *sb, 180static struct dentry *__gatorfs_create_file(struct super_block *sb,
118 struct dentry *root, 181 struct dentry *root,
119 char const *name, 182 char const *name,
@@ -148,6 +211,18 @@ int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
148 return 0; 211 return 0;
149} 212}
150 213
214int gatorfs_create_u64(struct super_block *sb, struct dentry *root,
215 char const *name, u64 *val)
216{
217 struct dentry *d = __gatorfs_create_file(sb, root, name,
218 &u64_fops, 0644);
219 if (!d)
220 return -EFAULT;
221
222 d->d_inode->i_private = val;
223 return 0;
224}
225
151int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root, 226int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
152 char const *name, unsigned long *val) 227 char const *name, unsigned long *val)
153{ 228{
@@ -160,6 +235,18 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
160 return 0; 235 return 0;
161} 236}
162 237
238int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root,
239 char const *name, u64 * val)
240{
241 struct dentry *d =
242 __gatorfs_create_file(sb, root, name, &u64_ro_fops, 0444);
243 if (!d)
244 return -EFAULT;
245
246 d->d_inode->i_private = val;
247 return 0;
248}
249
163static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) 250static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
164{ 251{
165 atomic_t *val = file->private_data; 252 atomic_t *val = file->private_data;
diff --git a/driver/gator_hrtimer_gator.c b/driver/gator_hrtimer_gator.c
index 846fba4..8c35d49 100644
--- a/driver/gator_hrtimer_gator.c
+++ b/driver/gator_hrtimer_gator.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -15,8 +15,8 @@ void (*callback)(void);
15DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer); 15DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
16DEFINE_PER_CPU(int, hrtimer_is_active); 16DEFINE_PER_CPU(int, hrtimer_is_active);
17static ktime_t profiling_interval; 17static ktime_t profiling_interval;
18static void gator_hrtimer_online(int cpu); 18static void gator_hrtimer_online(void);
19static void gator_hrtimer_offline(int cpu); 19static void gator_hrtimer_offline(void);
20 20
21static enum hrtimer_restart gator_hrtimer_notify(struct hrtimer *hrtimer) 21static enum hrtimer_restart gator_hrtimer_notify(struct hrtimer *hrtimer)
22{ 22{
@@ -25,43 +25,28 @@ static enum hrtimer_restart gator_hrtimer_notify(struct hrtimer *hrtimer)
25 return HRTIMER_RESTART; 25 return HRTIMER_RESTART;
26} 26}
27 27
28static void gator_hrtimer_switch_cpus_online(void *unused) 28static void gator_hrtimer_online(void)
29{
30 gator_hrtimer_online(smp_processor_id());
31}
32
33static void gator_hrtimer_online(int cpu)
34{ 29{
30 int cpu = get_logical_cpu();
35 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); 31 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
36 32
37 if (cpu != smp_processor_id()) {
38 smp_call_function_single(cpu, gator_hrtimer_switch_cpus_online, NULL, 1);
39 return;
40 }
41
42 if (per_cpu(hrtimer_is_active, cpu) || profiling_interval.tv64 == 0) 33 if (per_cpu(hrtimer_is_active, cpu) || profiling_interval.tv64 == 0)
43 return; 34 return;
44 35
45 per_cpu(hrtimer_is_active, cpu) = 1; 36 per_cpu(hrtimer_is_active, cpu) = 1;
46 hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 37 hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
47 hrtimer->function = gator_hrtimer_notify; 38 hrtimer->function = gator_hrtimer_notify;
39#ifdef CONFIG_PREEMPT_RT_BASE
40 hrtimer->irqsafe = 1;
41#endif
48 hrtimer_start(hrtimer, profiling_interval, HRTIMER_MODE_REL_PINNED); 42 hrtimer_start(hrtimer, profiling_interval, HRTIMER_MODE_REL_PINNED);
49} 43}
50 44
51static void gator_hrtimer_switch_cpus_offline(void *unused) 45static void gator_hrtimer_offline(void)
52{
53 gator_hrtimer_offline(smp_processor_id());
54}
55
56static void gator_hrtimer_offline(int cpu)
57{ 46{
47 int cpu = get_logical_cpu();
58 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); 48 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
59 49
60 if (cpu != smp_processor_id()) {
61 smp_call_function_single(cpu, gator_hrtimer_switch_cpus_offline, NULL, 1);
62 return;
63 }
64
65 if (!per_cpu(hrtimer_is_active, cpu)) 50 if (!per_cpu(hrtimer_is_active, cpu))
66 return; 51 return;
67 52
diff --git a/driver/gator_hrtimer_perf.c b/driver/gator_hrtimer_perf.c
index 7c0333f..7b95399 100644
--- a/driver/gator_hrtimer_perf.c
+++ b/driver/gator_hrtimer_perf.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_iks.c b/driver/gator_iks.c
new file mode 100644
index 0000000..6f45c54
--- /dev/null
+++ b/driver/gator_iks.c
@@ -0,0 +1,144 @@
1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#if GATOR_IKS_SUPPORT
11
12#include <linux/of.h>
13#include <asm/bL_switcher.h>
14#include <asm/smp_plat.h>
15#include <trace/events/power_cpu_migrate.h>
16
17static int mpidr_cpuids[NR_CPUS];
18static int __lcpu_to_pcpu[NR_CPUS];
19
20static void calc_first_cluster_size(void)
21{
22 int len;
23 const u32 *val;
24 struct device_node *cn = NULL;
25 int mpidr_cpuids_count = 0;
26
27 // Zero is a valid cpuid, so initialize the array to 0xff's
28 memset(&mpidr_cpuids, 0xff, sizeof(mpidr_cpuids));
29
30 while ((cn = of_find_node_by_type(cn, "cpu"))) {
31 BUG_ON(mpidr_cpuids_count >= NR_CPUS);
32
33 val = of_get_property(cn, "reg", &len);
34 if (!val || len != 4) {
35 pr_err("%s missing reg property\n", cn->full_name);
36 continue;
37 }
38
39 mpidr_cpuids[mpidr_cpuids_count] = be32_to_cpup(val);
40 ++mpidr_cpuids_count;
41 }
42
43 BUG_ON(mpidr_cpuids_count != nr_cpu_ids);
44}
45
46static int linearize_mpidr(int mpidr)
47{
48 int i;
49 for (i = 0; i < nr_cpu_ids; ++i) {
50 if (mpidr_cpuids[i] == mpidr) {
51 return i;
52 }
53 }
54
55 BUG();
56}
57
58int lcpu_to_pcpu(const int lcpu)
59{
60 int pcpu;
61 BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0);
62 pcpu = __lcpu_to_pcpu[lcpu];
63 BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0);
64 return pcpu;
65}
66
67int pcpu_to_lcpu(const int pcpu)
68{
69 int lcpu;
70 BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0);
71 for (lcpu = 0; lcpu < nr_cpu_ids; ++lcpu) {
72 if (__lcpu_to_pcpu[lcpu] == pcpu) {
73 BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0);
74 return lcpu;
75 }
76 }
77 BUG();
78}
79
80static void gator_update_cpu_mapping(u32 cpu_hwid)
81{
82 int lcpu = smp_processor_id();
83 int pcpu = linearize_mpidr(cpu_hwid & MPIDR_HWID_BITMASK);
84 BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0);
85 BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0);
86 __lcpu_to_pcpu[lcpu] = pcpu;
87}
88
89GATOR_DEFINE_PROBE(cpu_migrate_begin, TP_PROTO(u64 timestamp, u32 cpu_hwid))
90{
91 const int cpu = get_physical_cpu();
92
93 gator_timer_offline((void *)1);
94 gator_timer_offline_dispatch(cpu, true);
95}
96
97GATOR_DEFINE_PROBE(cpu_migrate_finish, TP_PROTO(u64 timestamp, u32 cpu_hwid))
98{
99 int cpu;
100
101 gator_update_cpu_mapping(cpu_hwid);
102
103 // get_physical_cpu must be called after gator_update_cpu_mapping
104 cpu = get_physical_cpu();
105 gator_timer_online_dispatch(cpu, true);
106 gator_timer_online((void *)1);
107}
108
109GATOR_DEFINE_PROBE(cpu_migrate_current, TP_PROTO(u64 timestamp, u32 cpu_hwid))
110{
111 gator_update_cpu_mapping(cpu_hwid);
112}
113
114static int gator_migrate_start(void)
115{
116 int retval = 0;
117 if (retval == 0)
118 retval = GATOR_REGISTER_TRACE(cpu_migrate_begin);
119 if (retval == 0)
120 retval = GATOR_REGISTER_TRACE(cpu_migrate_finish);
121 if (retval == 0)
122 retval = GATOR_REGISTER_TRACE(cpu_migrate_current);
123 if (retval == 0) {
124 // Initialize the logical to physical cpu mapping
125 memset(&__lcpu_to_pcpu, 0xff, sizeof(__lcpu_to_pcpu));
126 bL_switcher_trace_trigger();
127 }
128 return retval;
129}
130
131static void gator_migrate_stop(void)
132{
133 GATOR_UNREGISTER_TRACE(cpu_migrate_current);
134 GATOR_UNREGISTER_TRACE(cpu_migrate_finish);
135 GATOR_UNREGISTER_TRACE(cpu_migrate_begin);
136}
137
138#else
139
140#define calc_first_cluster_size()
141#define gator_migrate_start() 0
142#define gator_migrate_stop()
143
144#endif
diff --git a/driver/gator_main.c b/driver/gator_main.c
index 8c35caa..3e62b59 100644
--- a/driver/gator_main.c
+++ b/driver/gator_main.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -7,7 +7,8 @@
7 * 7 *
8 */ 8 */
9 9
10static unsigned long gator_protocol_version = 12; 10// This version must match the gator daemon version
11static unsigned long gator_protocol_version = 13;
11 12
12#include <linux/slab.h> 13#include <linux/slab.h>
13#include <linux/cpu.h> 14#include <linux/cpu.h>
@@ -20,6 +21,7 @@ static unsigned long gator_protocol_version = 12;
20#include <linux/suspend.h> 21#include <linux/suspend.h>
21#include <linux/module.h> 22#include <linux/module.h>
22#include <linux/perf_event.h> 23#include <linux/perf_event.h>
24#include <linux/utsname.h>
23#include <asm/stacktrace.h> 25#include <asm/stacktrace.h>
24#include <asm/uaccess.h> 26#include <asm/uaccess.h>
25 27
@@ -48,9 +50,9 @@ static unsigned long gator_protocol_version = 12;
48 50
49#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT)) 51#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT))
50#ifndef CONFIG_PERF_EVENTS 52#ifndef CONFIG_PERF_EVENTS
51#warning gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters 53#error gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
52#elif !defined CONFIG_HW_PERF_EVENTS 54#elif !defined CONFIG_HW_PERF_EVENTS
53#warning gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters 55#error gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
54#endif 56#endif
55#endif 57#endif
56 58
@@ -92,9 +94,14 @@ static unsigned long gator_protocol_version = 12;
92#define MESSAGE_SCHED_SWITCH 1 94#define MESSAGE_SCHED_SWITCH 1
93#define MESSAGE_SCHED_EXIT 2 95#define MESSAGE_SCHED_EXIT 2
94 96
97#define MESSAGE_IDLE_ENTER 1
98#define MESSAGE_IDLE_EXIT 2
99
95#define MAXSIZE_PACK32 5 100#define MAXSIZE_PACK32 5
96#define MAXSIZE_PACK64 10 101#define MAXSIZE_PACK64 10
97 102
103#define FRAME_HEADER_SIZE 3
104
98#if defined(__arm__) 105#if defined(__arm__)
99#define PC_REG regs->ARM_pc 106#define PC_REG regs->ARM_pc
100#elif defined(__aarch64__) 107#elif defined(__aarch64__)
@@ -123,23 +130,35 @@ static unsigned long gator_cpu_cores;
123// Size of the largest buffer. Effectively constant, set in gator_op_create_files 130// Size of the largest buffer. Effectively constant, set in gator_op_create_files
124static unsigned long userspace_buffer_size; 131static unsigned long userspace_buffer_size;
125static unsigned long gator_backtrace_depth; 132static unsigned long gator_backtrace_depth;
133// How often to commit the buffers for live in nanoseconds
134static u64 gator_live_rate;
126 135
127static unsigned long gator_started; 136static unsigned long gator_started;
128static uint64_t monotonic_started; 137static u64 gator_monotonic_started;
129static unsigned long gator_buffer_opened; 138static unsigned long gator_buffer_opened;
130static unsigned long gator_timer_count; 139static unsigned long gator_timer_count;
131static unsigned long gator_response_type; 140static unsigned long gator_response_type;
132static DEFINE_MUTEX(start_mutex); 141static DEFINE_MUTEX(start_mutex);
133static DEFINE_MUTEX(gator_buffer_mutex); 142static DEFINE_MUTEX(gator_buffer_mutex);
134 143
144bool event_based_sampling;
145
135static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait); 146static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
147static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait);
136static struct timer_list gator_buffer_wake_up_timer; 148static struct timer_list gator_buffer_wake_up_timer;
137static LIST_HEAD(gator_events); 149static LIST_HEAD(gator_events);
138 150
151static DEFINE_PER_CPU(u64, last_timestamp);
152
153static bool printed_monotonic_warning;
154
155static bool sent_core_name[NR_CPUS];
156
139/****************************************************************************** 157/******************************************************************************
140 * Prototypes 158 * Prototypes
141 ******************************************************************************/ 159 ******************************************************************************/
142static void buffer_check(int cpu, int buftype); 160static void buffer_check(int cpu, int buftype, u64 time);
161static void gator_commit_buffer(int cpu, int buftype, u64 time);
143static int buffer_bytes_available(int cpu, int buftype); 162static int buffer_bytes_available(int cpu, int buftype);
144static bool buffer_check_space(int cpu, int buftype, int bytes); 163static bool buffer_check_space(int cpu, int buftype, int bytes);
145static int contiguous_space_available(int cpu, int bufytpe); 164static int contiguous_space_available(int cpu, int bufytpe);
@@ -149,7 +168,7 @@ static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int le
149static void gator_buffer_write_string(int cpu, int buftype, const char *x); 168static void gator_buffer_write_string(int cpu, int buftype, const char *x);
150static void gator_add_trace(int cpu, unsigned long address); 169static void gator_add_trace(int cpu, unsigned long address);
151static void gator_add_sample(int cpu, struct pt_regs *const regs); 170static void gator_add_sample(int cpu, struct pt_regs *const regs);
152static uint64_t gator_get_time(void); 171static u64 gator_get_time(void);
153 172
154// Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup. 173// Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup.
155static uint32_t gator_buffer_size[NUM_GATOR_BUFS]; 174static uint32_t gator_buffer_size[NUM_GATOR_BUFS];
@@ -167,6 +186,11 @@ static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], buffer_space_available);
167// The buffer. Allocated in gator_op_setup 186// The buffer. Allocated in gator_op_setup
168static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer); 187static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer);
169 188
189#if GATOR_LIVE
190// The time after which the buffer should be committed for live display
191static DEFINE_PER_CPU(u64, gator_buffer_commit_time);
192#endif
193
170/****************************************************************************** 194/******************************************************************************
171 * Application Includes 195 * Application Includes
172 ******************************************************************************/ 196 ******************************************************************************/
@@ -186,83 +210,85 @@ static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer);
186 * Misc 210 * Misc
187 ******************************************************************************/ 211 ******************************************************************************/
188 212
189struct gator_cpu gator_cpus[] = { 213const struct gator_cpu gator_cpus[] = {
190 { 214 {
191 .cpuid = ARM1136, 215 .cpuid = ARM1136,
192 .core_name = "ARM1136", 216 .core_name = "ARM1136",
193 .pmnc_name = "ARM_ARM11", 217 .pmnc_name = "ARM_ARM11",
194 .pmnc_counters = 3, 218 .pmnc_counters = 3,
195 .ccnt = 2,
196 }, 219 },
197 { 220 {
198 .cpuid = ARM1156, 221 .cpuid = ARM1156,
199 .core_name = "ARM1156", 222 .core_name = "ARM1156",
200 .pmnc_name = "ARM_ARM11", 223 .pmnc_name = "ARM_ARM11",
201 .pmnc_counters = 3, 224 .pmnc_counters = 3,
202 .ccnt = 2,
203 }, 225 },
204 { 226 {
205 .cpuid = ARM1176, 227 .cpuid = ARM1176,
206 .core_name = "ARM1176", 228 .core_name = "ARM1176",
207 .pmnc_name = "ARM_ARM11", 229 .pmnc_name = "ARM_ARM11",
208 .pmnc_counters = 3, 230 .pmnc_counters = 3,
209 .ccnt = 2,
210 }, 231 },
211 { 232 {
212 .cpuid = ARM11MPCORE, 233 .cpuid = ARM11MPCORE,
213 .core_name = "ARM11MPCore", 234 .core_name = "ARM11MPCore",
214 .pmnc_name = "ARM_ARM11MPCore", 235 .pmnc_name = "ARM_ARM11MPCore",
215 .pmnc_counters = 3, 236 .pmnc_counters = 3,
216 }, 237 },
217 { 238 {
218 .cpuid = CORTEX_A5, 239 .cpuid = CORTEX_A5,
219 .core_name = "Cortex-A5", 240 .core_name = "Cortex-A5",
241 .pmu_name = "ARMv7_Cortex_A5",
220 .pmnc_name = "ARM_Cortex-A5", 242 .pmnc_name = "ARM_Cortex-A5",
221 .pmnc_counters = 2, 243 .pmnc_counters = 2,
222 }, 244 },
223 { 245 {
224 .cpuid = CORTEX_A7, 246 .cpuid = CORTEX_A7,
225 .core_name = "Cortex-A7", 247 .core_name = "Cortex-A7",
248 .pmu_name = "ARMv7_Cortex_A7",
226 .pmnc_name = "ARM_Cortex-A7", 249 .pmnc_name = "ARM_Cortex-A7",
227 .pmnc_counters = 4, 250 .pmnc_counters = 4,
228 }, 251 },
229 { 252 {
230 .cpuid = CORTEX_A8, 253 .cpuid = CORTEX_A8,
231 .core_name = "Cortex-A8", 254 .core_name = "Cortex-A8",
255 .pmu_name = "ARMv7_Cortex_A8",
232 .pmnc_name = "ARM_Cortex-A8", 256 .pmnc_name = "ARM_Cortex-A8",
233 .pmnc_counters = 4, 257 .pmnc_counters = 4,
234 }, 258 },
235 { 259 {
236 .cpuid = CORTEX_A9, 260 .cpuid = CORTEX_A9,
237 .core_name = "Cortex-A9", 261 .core_name = "Cortex-A9",
262 .pmu_name = "ARMv7_Cortex_A9",
238 .pmnc_name = "ARM_Cortex-A9", 263 .pmnc_name = "ARM_Cortex-A9",
239 .pmnc_counters = 6, 264 .pmnc_counters = 6,
240 }, 265 },
241 { 266 {
242 .cpuid = CORTEX_A15, 267 .cpuid = CORTEX_A15,
243 .core_name = "Cortex-A15", 268 .core_name = "Cortex-A15",
269 .pmu_name = "ARMv7_Cortex_A15",
244 .pmnc_name = "ARM_Cortex-A15", 270 .pmnc_name = "ARM_Cortex-A15",
245 .pmnc_counters = 6, 271 .pmnc_counters = 6,
246 }, 272 },
247 { 273 {
248 .cpuid = SCORPION, 274 .cpuid = SCORPION,
249 .core_name = "Scorpion", 275 .core_name = "Scorpion",
250 .pmnc_name = "Scorpion", 276 .pmnc_name = "Scorpion",
251 .pmnc_counters = 4, 277 .pmnc_counters = 4,
252 }, 278 },
253 { 279 {
254 .cpuid = SCORPIONMP, 280 .cpuid = SCORPIONMP,
255 .core_name = "ScorpionMP", 281 .core_name = "ScorpionMP",
256 .pmnc_name = "ScorpionMP", 282 .pmnc_name = "ScorpionMP",
257 .pmnc_counters = 4, 283 .pmnc_counters = 4,
258 }, 284 },
259 { 285 {
260 .cpuid = KRAITSIM, 286 .cpuid = KRAITSIM,
261 .core_name = "KraitSIM", 287 .core_name = "KraitSIM",
262 .pmnc_name = "Krait", 288 .pmnc_name = "Krait",
263 .pmnc_counters = 4, 289 .pmnc_counters = 4,
264 }, 290 },
265 { 291 {
266 .cpuid = KRAIT, 292 .cpuid = KRAIT,
267 .core_name = "Krait", 293 .core_name = "Krait",
268 .pmnc_name = "Krait", 294 .pmnc_name = "Krait",
@@ -274,19 +300,19 @@ struct gator_cpu gator_cpus[] = {
274 .pmnc_name = "Krait", 300 .pmnc_name = "Krait",
275 .pmnc_counters = 4, 301 .pmnc_counters = 4,
276 }, 302 },
277 { 303 {
278 .cpuid = CORTEX_A53, 304 .cpuid = CORTEX_A53,
279 .core_name = "Cortex-A53", 305 .core_name = "Cortex-A53",
280 .pmnc_name = "ARM_Cortex-A53", 306 .pmnc_name = "ARM_Cortex-A53",
281 .pmnc_counters = 6, 307 .pmnc_counters = 6,
282 }, 308 },
283 { 309 {
284 .cpuid = CORTEX_A57, 310 .cpuid = CORTEX_A57,
285 .core_name = "Cortex-A57", 311 .core_name = "Cortex-A57",
286 .pmnc_name = "ARM_Cortex-A57", 312 .pmnc_name = "ARM_Cortex-A57",
287 .pmnc_counters = 6, 313 .pmnc_counters = 6,
288 }, 314 },
289 { 315 {
290 .cpuid = AARCH64, 316 .cpuid = AARCH64,
291 .core_name = "AArch64", 317 .core_name = "AArch64",
292 .pmnc_name = "ARM_AArch64", 318 .pmnc_name = "ARM_AArch64",
@@ -298,9 +324,37 @@ struct gator_cpu gator_cpus[] = {
298 .pmnc_name = "Other", 324 .pmnc_name = "Other",
299 .pmnc_counters = 6, 325 .pmnc_counters = 6,
300 }, 326 },
301 {} 327 {}
302}; 328};
303 329
330const struct gator_cpu *gator_find_cpu_by_cpuid(const u32 cpuid)
331{
332 int i;
333
334 for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
335 const struct gator_cpu *const gator_cpu = &gator_cpus[i];
336 if (gator_cpu->cpuid == cpuid) {
337 return gator_cpu;
338 }
339 }
340
341 return NULL;
342}
343
344const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name)
345{
346 int i;
347
348 for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
349 const struct gator_cpu *const gator_cpu = &gator_cpus[i];
350 if (gator_cpu->pmu_name != NULL && strcmp(gator_cpu->pmu_name, name) == 0) {
351 return gator_cpu;
352 }
353 }
354
355 return NULL;
356}
357
304u32 gator_cpuid(void) 358u32 gator_cpuid(void)
305{ 359{
306#if defined(__arm__) || defined(__aarch64__) 360#if defined(__arm__) || defined(__aarch64__)
@@ -408,7 +462,7 @@ static void gator_buffer_write_string(int cpu, int buftype, const char *x)
408 gator_buffer_write_bytes(cpu, buftype, x, len); 462 gator_buffer_write_bytes(cpu, buftype, x, len);
409} 463}
410 464
411static void gator_commit_buffer(int cpu, int buftype) 465static void gator_commit_buffer(int cpu, int buftype, u64 time)
412{ 466{
413 int type_length, commit, length, byte; 467 int type_length, commit, length, byte;
414 468
@@ -423,25 +477,40 @@ static void gator_commit_buffer(int cpu, int buftype)
423 length += gator_buffer_size[buftype]; 477 length += gator_buffer_size[buftype];
424 } 478 }
425 length = length - type_length - sizeof(int); 479 length = length - type_length - sizeof(int);
480
481 if (length <= FRAME_HEADER_SIZE) {
482 // Nothing to write, only the frame header is present
483 return;
484 }
485
426 for (byte = 0; byte < sizeof(int); byte++) { 486 for (byte = 0; byte < sizeof(int); byte++) {
427 per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF; 487 per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
428 } 488 }
429 489
430 per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype]; 490 per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
491
492#if GATOR_LIVE
493 if (gator_live_rate > 0) {
494 while (time > per_cpu(gator_buffer_commit_time, cpu)) {
495 per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
496 }
497 }
498#endif
499
431 marshal_frame(cpu, buftype); 500 marshal_frame(cpu, buftype);
432 501
433 // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater 502 // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
434 mod_timer(&gator_buffer_wake_up_timer, jiffies + 1); 503 mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
435} 504}
436 505
437static void buffer_check(int cpu, int buftype) 506static void buffer_check(int cpu, int buftype, u64 time)
438{ 507{
439 int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype]; 508 int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype];
440 if (filled < 0) { 509 if (filled < 0) {
441 filled += gator_buffer_size[buftype]; 510 filled += gator_buffer_size[buftype];
442 } 511 }
443 if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) { 512 if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
444 gator_commit_buffer(cpu, buftype); 513 gator_commit_buffer(cpu, buftype, time);
445 } 514 }
446} 515}
447 516
@@ -496,7 +565,7 @@ static void gator_timer_interrupt(void)
496 565
497void gator_backtrace_handler(struct pt_regs *const regs) 566void gator_backtrace_handler(struct pt_regs *const regs)
498{ 567{
499 int cpu = smp_processor_id(); 568 int cpu = get_physical_cpu();
500 569
501 // Output backtrace 570 // Output backtrace
502 gator_add_sample(cpu, regs); 571 gator_add_sample(cpu, regs);
@@ -510,40 +579,48 @@ void gator_backtrace_handler(struct pt_regs *const regs)
510static int gator_running; 579static int gator_running;
511 580
512// This function runs in interrupt context and on the appropriate core 581// This function runs in interrupt context and on the appropriate core
513static void gator_timer_offline(void *unused) 582static void gator_timer_offline(void *migrate)
514{ 583{
515 struct gator_interface *gi; 584 struct gator_interface *gi;
516 int i, len, cpu = smp_processor_id(); 585 int i, len, cpu = get_physical_cpu();
517 int *buffer; 586 int *buffer;
587 u64 time;
518 588
519 gator_trace_sched_offline(); 589 gator_trace_sched_offline();
520 gator_trace_power_offline(); 590 gator_trace_power_offline();
521 591
522 gator_hrtimer_offline(cpu); 592 if (!migrate) {
593 gator_hrtimer_offline();
594 }
523 595
524 // Offline any events and output counters 596 // Offline any events and output counters
597 time = gator_get_time();
525 if (marshal_event_header()) { 598 if (marshal_event_header()) {
526 list_for_each_entry(gi, &gator_events, list) { 599 list_for_each_entry(gi, &gator_events, list) {
527 if (gi->offline) { 600 if (gi->offline) {
528 len = gi->offline(&buffer); 601 len = gi->offline(&buffer, migrate);
529 marshal_event(len, buffer); 602 marshal_event(len, buffer);
530 } 603 }
531 } 604 }
605 // Only check after writing all counters so that time and corresponding counters appear in the same frame
606 buffer_check(cpu, BLOCK_COUNTER_BUF, time);
532 } 607 }
533 608
534 // Flush all buffers on this core 609 // Flush all buffers on this core
535 for (i = 0; i < NUM_GATOR_BUFS; i++) 610 for (i = 0; i < NUM_GATOR_BUFS; i++)
536 gator_commit_buffer(cpu, i); 611 gator_commit_buffer(cpu, i, time);
537} 612}
538 613
539// This function runs in process context and may be running on a core other than core 'cpu' 614// This function runs in interrupt context and may be running on a core other than core 'cpu'
540static void gator_timer_offline_dispatch(int cpu) 615static void gator_timer_offline_dispatch(int cpu, bool migrate)
541{ 616{
542 struct gator_interface *gi; 617 struct gator_interface *gi;
543 618
544 list_for_each_entry(gi, &gator_events, list) 619 list_for_each_entry(gi, &gator_events, list) {
545 if (gi->offline_dispatch) 620 if (gi->offline_dispatch) {
546 gi->offline_dispatch(cpu); 621 gi->offline_dispatch(cpu, migrate);
622 }
623 }
547} 624}
548 625
549static void gator_timer_stop(void) 626static void gator_timer_stop(void)
@@ -553,7 +630,7 @@ static void gator_timer_stop(void)
553 if (gator_running) { 630 if (gator_running) {
554 on_each_cpu(gator_timer_offline, NULL, 1); 631 on_each_cpu(gator_timer_offline, NULL, 1);
555 for_each_online_cpu(cpu) { 632 for_each_online_cpu(cpu) {
556 gator_timer_offline_dispatch(cpu); 633 gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false);
557 } 634 }
558 635
559 gator_running = 0; 636 gator_running = 0;
@@ -562,10 +639,10 @@ static void gator_timer_stop(void)
562} 639}
563 640
564// This function runs in interrupt context and on the appropriate core 641// This function runs in interrupt context and on the appropriate core
565static void gator_timer_online(void *unused) 642static void gator_timer_online(void *migrate)
566{ 643{
567 struct gator_interface *gi; 644 struct gator_interface *gi;
568 int len, cpu = smp_processor_id(); 645 int len, cpu = get_physical_cpu();
569 int *buffer; 646 int *buffer;
570 647
571 gator_trace_power_online(); 648 gator_trace_power_online();
@@ -574,39 +651,48 @@ static void gator_timer_online(void *unused)
574 if (marshal_event_header()) { 651 if (marshal_event_header()) {
575 list_for_each_entry(gi, &gator_events, list) { 652 list_for_each_entry(gi, &gator_events, list) {
576 if (gi->online) { 653 if (gi->online) {
577 len = gi->online(&buffer); 654 len = gi->online(&buffer, migrate);
578 marshal_event(len, buffer); 655 marshal_event(len, buffer);
579 } 656 }
580 } 657 }
658 // Only check after writing all counters so that time and corresponding counters appear in the same frame
659 buffer_check(cpu, BLOCK_COUNTER_BUF, gator_get_time());
660 }
661
662 if (!migrate) {
663 gator_hrtimer_online();
581 } 664 }
582 665
583 gator_hrtimer_online(cpu);
584#if defined(__arm__) || defined(__aarch64__) 666#if defined(__arm__) || defined(__aarch64__)
585 { 667 if (!sent_core_name[cpu]) {
586 const char *core_name = "Unknown"; 668 const char *core_name = NULL;
587 const u32 cpuid = gator_cpuid(); 669 const u32 cpuid = gator_cpuid();
588 int i; 670 const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(cpuid);
589 671 char core_name_buf[32];
590 for (i = 0; gator_cpus[i].cpuid != 0; ++i) { 672
591 if (gator_cpus[i].cpuid == cpuid) { 673 if (gator_cpu != NULL) {
592 core_name = gator_cpus[i].core_name; 674 core_name = gator_cpu->core_name;
593 break; 675 } else {
594 } 676 snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.3x)", cpuid);
677 core_name = core_name_buf;
595 } 678 }
596 679
597 marshal_core_name(core_name); 680 marshal_core_name(cpuid, core_name);
681 sent_core_name[cpu] = true;
598 } 682 }
599#endif 683#endif
600} 684}
601 685
602// This function runs in interrupt context and may be running on a core other than core 'cpu' 686// This function runs in interrupt context and may be running on a core other than core 'cpu'
603static void gator_timer_online_dispatch(int cpu) 687static void gator_timer_online_dispatch(int cpu, bool migrate)
604{ 688{
605 struct gator_interface *gi; 689 struct gator_interface *gi;
606 690
607 list_for_each_entry(gi, &gator_events, list) 691 list_for_each_entry(gi, &gator_events, list) {
608 if (gi->online_dispatch) 692 if (gi->online_dispatch) {
609 gi->online_dispatch(cpu); 693 gi->online_dispatch(cpu, migrate);
694 }
695 }
610} 696}
611 697
612int gator_timer_start(unsigned long sample_rate) 698int gator_timer_start(unsigned long sample_rate)
@@ -620,45 +706,72 @@ int gator_timer_start(unsigned long sample_rate)
620 706
621 gator_running = 1; 707 gator_running = 1;
622 708
709 // event based sampling trumps hr timer based sampling
710 if (event_based_sampling) {
711 sample_rate = 0;
712 }
713
623 if (gator_hrtimer_init(sample_rate, gator_timer_interrupt) == -1) 714 if (gator_hrtimer_init(sample_rate, gator_timer_interrupt) == -1)
624 return -1; 715 return -1;
625 716
626 for_each_online_cpu(cpu) { 717 for_each_online_cpu(cpu) {
627 gator_timer_online_dispatch(cpu); 718 gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false);
628 } 719 }
629 on_each_cpu(gator_timer_online, NULL, 1); 720 on_each_cpu(gator_timer_online, NULL, 1);
630 721
631 return 0; 722 return 0;
632} 723}
633 724
634static uint64_t gator_get_time(void) 725static u64 gator_get_time(void)
635{ 726{
636 struct timespec ts; 727 struct timespec ts;
637 uint64_t timestamp; 728 u64 timestamp;
729 u64 prev_timestamp;
730 u64 delta;
731 int cpu = smp_processor_id();
638 732
639 //getnstimeofday(&ts); 733 // Match clock_gettime(CLOCK_MONOTONIC_RAW, &ts) from userspace
640 do_posix_clock_monotonic_gettime(&ts); 734 getrawmonotonic(&ts);
641 timestamp = timespec_to_ns(&ts) - monotonic_started; 735 timestamp = timespec_to_ns(&ts);
642 736
643 return timestamp; 737 // getrawmonotonic is not monotonic on all systems. Detect and attempt to correct these cases.
738 // up to 0.5ms delta has been seen on some systems, which can skew Streamline data when viewing at high resolution.
739 prev_timestamp = per_cpu(last_timestamp, cpu);
740 if (prev_timestamp <= timestamp) {
741 per_cpu(last_timestamp, cpu) = timestamp;
742 } else {
743 delta = prev_timestamp - timestamp;
744 // Log the error once
745 if (!printed_monotonic_warning && delta > 500000) {
746 printk(KERN_ERR "%s: getrawmonotonic is not monotonic cpu: %i delta: %lli\nSkew in Streamline data may be present at the fine zoom levels\n", __FUNCTION__, cpu, delta);
747 printed_monotonic_warning = true;
748 } else {
749 pr_debug("%s: getrawmonotonic is not monotonic cpu: %i delta: %lli\n", __FUNCTION__, cpu, delta);
750 }
751 timestamp = prev_timestamp;
752 }
753
754 return timestamp - gator_monotonic_started;
644} 755}
645 756
646/****************************************************************************** 757/******************************************************************************
647 * cpu hotplug and pm notifiers 758 * cpu hotplug and pm notifiers
648 ******************************************************************************/ 759 ******************************************************************************/
760#include "gator_iks.c"
761
649static int __cpuinit gator_hotcpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) 762static int __cpuinit gator_hotcpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
650{ 763{
651 long cpu = (long)hcpu; 764 int cpu = lcpu_to_pcpu((long)hcpu);
652 765
653 switch (action) { 766 switch (action) {
654 case CPU_DOWN_PREPARE: 767 case CPU_DOWN_PREPARE:
655 case CPU_DOWN_PREPARE_FROZEN: 768 case CPU_DOWN_PREPARE_FROZEN:
656 smp_call_function_single(cpu, gator_timer_offline, NULL, 1); 769 smp_call_function_single(cpu, gator_timer_offline, NULL, 1);
657 gator_timer_offline_dispatch(cpu); 770 gator_timer_offline_dispatch(cpu, false);
658 break; 771 break;
659 case CPU_ONLINE: 772 case CPU_ONLINE:
660 case CPU_ONLINE_FROZEN: 773 case CPU_ONLINE_FROZEN:
661 gator_timer_online_dispatch(cpu); 774 gator_timer_online_dispatch(cpu, false);
662 smp_call_function_single(cpu, gator_timer_online, NULL, 1); 775 smp_call_function_single(cpu, gator_timer_online, NULL, 1);
663 break; 776 break;
664 } 777 }
@@ -683,13 +796,13 @@ static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void
683 unregister_scheduler_tracepoints(); 796 unregister_scheduler_tracepoints();
684 on_each_cpu(gator_timer_offline, NULL, 1); 797 on_each_cpu(gator_timer_offline, NULL, 1);
685 for_each_online_cpu(cpu) { 798 for_each_online_cpu(cpu) {
686 gator_timer_offline_dispatch(cpu); 799 gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false);
687 } 800 }
688 break; 801 break;
689 case PM_POST_HIBERNATION: 802 case PM_POST_HIBERNATION:
690 case PM_POST_SUSPEND: 803 case PM_POST_SUSPEND:
691 for_each_online_cpu(cpu) { 804 for_each_online_cpu(cpu) {
692 gator_timer_online_dispatch(cpu); 805 gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false);
693 } 806 }
694 on_each_cpu(gator_timer_online, NULL, 1); 807 on_each_cpu(gator_timer_online, NULL, 1);
695 register_scheduler_tracepoints(); 808 register_scheduler_tracepoints();
@@ -724,15 +837,33 @@ static void gator_notifier_stop(void)
724 ******************************************************************************/ 837 ******************************************************************************/
725static void gator_summary(void) 838static void gator_summary(void)
726{ 839{
727 uint64_t timestamp; 840 u64 timestamp, uptime;
728 struct timespec uptime_ts; 841 struct timespec ts;
842 char uname_buf[512];
843 void (*m2b)(struct timespec *ts);
844 unsigned long flags;
729 845
730 timestamp = gator_get_time(); 846 snprintf(uname_buf, sizeof(uname_buf), "%s %s %s %s %s GNU/Linux", utsname()->sysname, utsname()->nodename, utsname()->release, utsname()->version, utsname()->machine);
731 847
732 do_posix_clock_monotonic_gettime(&uptime_ts); 848 getnstimeofday(&ts);
733 monotonic_started = timespec_to_ns(&uptime_ts); 849 timestamp = timespec_to_ns(&ts);
734 850
735 marshal_summary(timestamp, monotonic_started); 851 do_posix_clock_monotonic_gettime(&ts);
852 // monotonic_to_bootbased is not defined for some versions of Android
853 m2b = symbol_get(monotonic_to_bootbased);
854 if (m2b) {
855 m2b(&ts);
856 }
857 uptime = timespec_to_ns(&ts);
858
859 // Disable interrupts as gator_get_time calls smp_processor_id to verify time is monotonic
860 local_irq_save(flags);
861 // Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started
862 gator_monotonic_started = 0;
863 gator_monotonic_started = gator_get_time();
864 local_irq_restore(flags);
865
866 marshal_summary(timestamp, uptime, uname_buf);
736} 867}
737 868
738int gator_events_install(struct gator_interface *interface) 869int gator_events_install(struct gator_interface *interface)
@@ -747,13 +878,17 @@ int gator_events_get_key(void)
747 // key of zero is reserved as a timestamp 878 // key of zero is reserved as a timestamp
748 static int key = 1; 879 static int key = 1;
749 880
750 return key++; 881 const int ret = key;
882 key += 2;
883 return ret;
751} 884}
752 885
753static int gator_init(void) 886static int gator_init(void)
754{ 887{
755 int i; 888 int i;
756 889
890 calc_first_cluster_size();
891
757 // events sources (gator_events.h, generated by gator_events.sh) 892 // events sources (gator_events.h, generated by gator_events.sh)
758 for (i = 0; i < ARRAY_SIZE(gator_events_list); i++) 893 for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
759 if (gator_events_list[i]) 894 if (gator_events_list[i])
@@ -778,14 +913,19 @@ static int gator_start(void)
778 unsigned long cpu, i; 913 unsigned long cpu, i;
779 struct gator_interface *gi; 914 struct gator_interface *gi;
780 915
916 if (gator_migrate_start())
917 goto migrate_failure;
918
781 // Initialize the buffer with the frame type and core 919 // Initialize the buffer with the frame type and core
782 for_each_present_cpu(cpu) { 920 for_each_present_cpu(cpu) {
783 for (i = 0; i < NUM_GATOR_BUFS; i++) { 921 for (i = 0; i < NUM_GATOR_BUFS; i++) {
784 marshal_frame(cpu, i); 922 marshal_frame(cpu, i);
785 } 923 }
924 per_cpu(last_timestamp, cpu) = 0;
786 } 925 }
926 printed_monotonic_warning = false;
787 927
788 // Capture the start time 928 // Capture the start time
789 gator_summary(); 929 gator_summary();
790 930
791 // start all events 931 // start all events
@@ -838,9 +978,11 @@ annotate_failure:
838cookies_failure: 978cookies_failure:
839 // stop all events 979 // stop all events
840 list_for_each_entry(gi, &gator_events, list) 980 list_for_each_entry(gi, &gator_events, list)
841 if (gi->stop) 981 if (gi->stop)
842 gi->stop(); 982 gi->stop();
843events_failure: 983events_failure:
984 gator_migrate_stop();
985migrate_failure:
844 986
845 return -1; 987 return -1;
846} 988}
@@ -860,8 +1002,10 @@ static void gator_stop(void)
860 1002
861 // stop all events 1003 // stop all events
862 list_for_each_entry(gi, &gator_events, list) 1004 list_for_each_entry(gi, &gator_events, list)
863 if (gi->stop) 1005 if (gi->stop)
864 gi->stop(); 1006 gi->stop();
1007
1008 gator_migrate_stop();
865} 1009}
866 1010
867/****************************************************************************** 1011/******************************************************************************
@@ -915,6 +1059,9 @@ static int gator_op_setup(void)
915 per_cpu(gator_buffer_write, cpu)[i] = 0; 1059 per_cpu(gator_buffer_write, cpu)[i] = 0;
916 per_cpu(gator_buffer_commit, cpu)[i] = 0; 1060 per_cpu(gator_buffer_commit, cpu)[i] = 0;
917 per_cpu(buffer_space_available, cpu)[i] = true; 1061 per_cpu(buffer_space_available, cpu)[i] = true;
1062#if GATOR_LIVE
1063 per_cpu(gator_buffer_commit_time, cpu) = gator_live_rate;
1064#endif
918 1065
919 // Annotation is a special case that only uses a single buffer 1066 // Annotation is a special case that only uses a single buffer
920 if (cpu > 0 && i == ANNOTATE_BUF) { 1067 if (cpu > 0 && i == ANNOTATE_BUF) {
@@ -963,6 +1110,7 @@ static void gator_op_stop(void)
963 mutex_lock(&gator_buffer_mutex); 1110 mutex_lock(&gator_buffer_mutex);
964 1111
965 gator_started = 0; 1112 gator_started = 0;
1113 gator_monotonic_started = 0;
966 cookies_release(); 1114 cookies_release();
967 wake_up(&gator_buffer_wait); 1115 wake_up(&gator_buffer_wait);
968 1116
@@ -987,10 +1135,15 @@ static void gator_shutdown(void)
987 per_cpu(gator_buffer_write, cpu)[i] = 0; 1135 per_cpu(gator_buffer_write, cpu)[i] = 0;
988 per_cpu(gator_buffer_commit, cpu)[i] = 0; 1136 per_cpu(gator_buffer_commit, cpu)[i] = 0;
989 per_cpu(buffer_space_available, cpu)[i] = true; 1137 per_cpu(buffer_space_available, cpu)[i] = true;
1138#if GATOR_LIVE
1139 per_cpu(gator_buffer_commit_time, cpu) = 0;
1140#endif
990 } 1141 }
991 mutex_unlock(&gator_buffer_mutex); 1142 mutex_unlock(&gator_buffer_mutex);
992 } 1143 }
993 1144
1145 memset(&sent_core_name, 0, sizeof(sent_core_name));
1146
994 mutex_unlock(&start_mutex); 1147 mutex_unlock(&start_mutex);
995} 1148}
996 1149
@@ -1143,6 +1296,11 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
1143 /* kick just in case we've lost an SMP event */ 1296 /* kick just in case we've lost an SMP event */
1144 wake_up(&gator_buffer_wait); 1297 wake_up(&gator_buffer_wait);
1145 1298
1299 // Wake up annotate_write if more space is available
1300 if (buftype == ANNOTATE_BUF) {
1301 wake_up(&gator_annotate_wait);
1302 }
1303
1146out: 1304out:
1147 mutex_unlock(&gator_buffer_mutex); 1305 mutex_unlock(&gator_buffer_mutex);
1148 return retval; 1306 return retval;
@@ -1196,6 +1354,7 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
1196 } 1354 }
1197 userspace_buffer_size = BACKTRACE_BUFFER_SIZE; 1355 userspace_buffer_size = BACKTRACE_BUFFER_SIZE;
1198 gator_response_type = 1; 1356 gator_response_type = 1;
1357 gator_live_rate = 0;
1199 1358
1200 gatorfs_create_file(sb, root, "enable", &enable_fops); 1359 gatorfs_create_file(sb, root, "enable", &enable_fops);
1201 gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops); 1360 gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops);
@@ -1205,6 +1364,8 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
1205 gatorfs_create_ulong(sb, root, "tick", &gator_timer_count); 1364 gatorfs_create_ulong(sb, root, "tick", &gator_timer_count);
1206 gatorfs_create_ulong(sb, root, "response_type", &gator_response_type); 1365 gatorfs_create_ulong(sb, root, "response_type", &gator_response_type);
1207 gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version); 1366 gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version);
1367 gatorfs_create_ro_u64(sb, root, "started", &gator_monotonic_started);
1368 gatorfs_create_u64(sb, root, "live_rate", &gator_live_rate);
1208 1369
1209 // Annotate interface 1370 // Annotate interface
1210 gator_annotate_create_files(sb, root); 1371 gator_annotate_create_files(sb, root);
@@ -1212,8 +1373,8 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
1212 // Linux Events 1373 // Linux Events
1213 dir = gatorfs_mkdir(sb, root, "events"); 1374 dir = gatorfs_mkdir(sb, root, "events");
1214 list_for_each_entry(gi, &gator_events, list) 1375 list_for_each_entry(gi, &gator_events, list)
1215 if (gi->create_files) 1376 if (gi->create_files)
1216 gi->create_files(sb, dir); 1377 gi->create_files(sb, dir);
1217 1378
1218 // Power interface 1379 // Power interface
1219 gator_trace_power_create_files(sb, dir); 1380 gator_trace_power_create_files(sb, dir);
diff --git a/driver/gator_marshaling.c b/driver/gator_marshaling.c
index b2efdd2..627b441 100644
--- a/driver/gator_marshaling.c
+++ b/driver/gator_marshaling.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2012. All rights reserved. 2 * Copyright (C) ARM Limited 2012-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -7,50 +7,72 @@
7 * 7 *
8 */ 8 */
9 9
10static void marshal_summary(long long timestamp, long long uptime) 10#define NEWLINE_CANARY \
11 /* Unix */ \
12 "1\n" \
13 /* Windows */ \
14 "2\r\n" \
15 /* Mac OS */ \
16 "3\r" \
17 /* RISC OS */ \
18 "4\n\r" \
19 /* Add another character so the length isn't 0x0a bytes */ \
20 "5"
21
22static void marshal_summary(long long timestamp, long long uptime, const char * uname)
11{ 23{
24 unsigned long flags;
12 int cpu = 0; 25 int cpu = 0;
26
27 local_irq_save(flags);
28 gator_buffer_write_string(cpu, SUMMARY_BUF, NEWLINE_CANARY);
13 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, timestamp); 29 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, timestamp);
14 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, uptime); 30 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, uptime);
15 buffer_check(cpu, SUMMARY_BUF); 31 gator_buffer_write_string(cpu, SUMMARY_BUF, uname);
32 // Commit the buffer now so it can be one of the first frames read by Streamline
33 gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
34 local_irq_restore(flags);
16} 35}
17 36
18static bool marshal_cookie_header(const char *text) 37static bool marshal_cookie_header(const char *text)
19{ 38{
20 int cpu = smp_processor_id(); 39 int cpu = get_physical_cpu();
21 return buffer_check_space(cpu, NAME_BUF, strlen(text) + 3 * MAXSIZE_PACK32); 40 return buffer_check_space(cpu, NAME_BUF, strlen(text) + 3 * MAXSIZE_PACK32);
22} 41}
23 42
24static void marshal_cookie(int cookie, const char *text) 43static void marshal_cookie(int cookie, const char *text)
25{ 44{
26 int cpu = smp_processor_id(); 45 int cpu = get_physical_cpu();
27 // buffer_check_space already called by marshal_cookie_header 46 // buffer_check_space already called by marshal_cookie_header
28 gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_COOKIE); 47 gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_COOKIE);
29 gator_buffer_write_packed_int(cpu, NAME_BUF, cookie); 48 gator_buffer_write_packed_int(cpu, NAME_BUF, cookie);
30 gator_buffer_write_string(cpu, NAME_BUF, text); 49 gator_buffer_write_string(cpu, NAME_BUF, text);
31 buffer_check(cpu, NAME_BUF); 50 buffer_check(cpu, NAME_BUF, gator_get_time());
32} 51}
33 52
34static void marshal_thread_name(int pid, char *name) 53static void marshal_thread_name(int pid, char *name)
35{ 54{
36 unsigned long flags, cpu; 55 unsigned long flags, cpu;
56 u64 time;
37 local_irq_save(flags); 57 local_irq_save(flags);
38 cpu = smp_processor_id(); 58 cpu = get_physical_cpu();
59 time = gator_get_time();
39 if (buffer_check_space(cpu, NAME_BUF, TASK_COMM_LEN + 3 * MAXSIZE_PACK32 + MAXSIZE_PACK64)) { 60 if (buffer_check_space(cpu, NAME_BUF, TASK_COMM_LEN + 3 * MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
40 gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_THREAD_NAME); 61 gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_THREAD_NAME);
41 gator_buffer_write_packed_int64(cpu, NAME_BUF, gator_get_time()); 62 gator_buffer_write_packed_int64(cpu, NAME_BUF, time);
42 gator_buffer_write_packed_int(cpu, NAME_BUF, pid); 63 gator_buffer_write_packed_int(cpu, NAME_BUF, pid);
43 gator_buffer_write_string(cpu, NAME_BUF, name); 64 gator_buffer_write_string(cpu, NAME_BUF, name);
44 } 65 }
45 buffer_check(cpu, NAME_BUF); 66 buffer_check(cpu, NAME_BUF, time);
46 local_irq_restore(flags); 67 local_irq_restore(flags);
47} 68}
48 69
49static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inKernel) 70static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inKernel)
50{ 71{
51 int cpu = smp_processor_id(); 72 int cpu = get_physical_cpu();
73 u64 time = gator_get_time();
52 if (buffer_check_space(cpu, BACKTRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32 + gator_backtrace_depth * 2 * MAXSIZE_PACK32)) { 74 if (buffer_check_space(cpu, BACKTRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32 + gator_backtrace_depth * 2 * MAXSIZE_PACK32)) {
53 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, gator_get_time()); 75 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, time);
54 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, exec_cookie); 76 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, exec_cookie);
55 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, tgid); 77 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, tgid);
56 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, pid); 78 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, pid);
@@ -59,30 +81,30 @@ static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inK
59 } 81 }
60 82
61 // Check and commit; commit is set to occur once buffer is 3/4 full 83 // Check and commit; commit is set to occur once buffer is 3/4 full
62 buffer_check(cpu, BACKTRACE_BUF); 84 buffer_check(cpu, BACKTRACE_BUF, time);
63 85
64 return false; 86 return false;
65} 87}
66 88
67static void marshal_backtrace(unsigned long address, int cookie) 89static void marshal_backtrace(unsigned long address, int cookie)
68{ 90{
69 int cpu = smp_processor_id(); 91 int cpu = get_physical_cpu();
70 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie); 92 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie);
71 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, address); 93 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, address);
72} 94}
73 95
74static void marshal_backtrace_footer(void) 96static void marshal_backtrace_footer(void)
75{ 97{
76 int cpu = smp_processor_id(); 98 int cpu = get_physical_cpu();
77 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_END_BACKTRACE); 99 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_END_BACKTRACE);
78 100
79 // Check and commit; commit is set to occur once buffer is 3/4 full 101 // Check and commit; commit is set to occur once buffer is 3/4 full
80 buffer_check(cpu, BACKTRACE_BUF); 102 buffer_check(cpu, BACKTRACE_BUF, gator_get_time());
81} 103}
82 104
83static bool marshal_event_header(void) 105static bool marshal_event_header(void)
84{ 106{
85 unsigned long flags, cpu = smp_processor_id(); 107 unsigned long flags, cpu = get_physical_cpu();
86 bool retval = false; 108 bool retval = false;
87 109
88 local_irq_save(flags); 110 local_irq_save(flags);
@@ -91,8 +113,6 @@ static bool marshal_event_header(void)
91 gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, gator_get_time()); 113 gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, gator_get_time());
92 retval = true; 114 retval = true;
93 } 115 }
94 // Check and commit; commit is set to occur once buffer is 3/4 full
95 buffer_check(cpu, BLOCK_COUNTER_BUF);
96 local_irq_restore(flags); 116 local_irq_restore(flags);
97 117
98 return retval; 118 return retval;
@@ -100,7 +120,7 @@ static bool marshal_event_header(void)
100 120
101static void marshal_event(int len, int *buffer) 121static void marshal_event(int len, int *buffer)
102{ 122{
103 unsigned long i, flags, cpu = smp_processor_id(); 123 unsigned long i, flags, cpu = get_physical_cpu();
104 124
105 if (len <= 0) 125 if (len <= 0)
106 return; 126 return;
@@ -120,14 +140,12 @@ static void marshal_event(int len, int *buffer)
120 gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i]); 140 gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i]);
121 gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i + 1]); 141 gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i + 1]);
122 } 142 }
123 // Check and commit; commit is set to occur once buffer is 3/4 full
124 buffer_check(cpu, BLOCK_COUNTER_BUF);
125 local_irq_restore(flags); 143 local_irq_restore(flags);
126} 144}
127 145
128static void marshal_event64(int len, long long *buffer64) 146static void marshal_event64(int len, long long *buffer64)
129{ 147{
130 unsigned long i, flags, cpu = smp_processor_id(); 148 unsigned long i, flags, cpu = get_physical_cpu();
131 149
132 if (len <= 0) 150 if (len <= 0)
133 return; 151 return;
@@ -147,8 +165,6 @@ static void marshal_event64(int len, long long *buffer64)
147 gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i]); 165 gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i]);
148 gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i + 1]); 166 gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i + 1]);
149 } 167 }
150 // Check and commit; commit is set to occur once buffer is 3/4 full
151 buffer_check(cpu, BLOCK_COUNTER_BUF);
152 local_irq_restore(flags); 168 local_irq_restore(flags);
153} 169}
154 170
@@ -156,97 +172,107 @@ static void marshal_event64(int len, long long *buffer64)
156static void marshal_event_single(int core, int key, int value) 172static void marshal_event_single(int core, int key, int value)
157{ 173{
158 unsigned long flags, cpu; 174 unsigned long flags, cpu;
175 u64 time;
159 176
160 local_irq_save(flags); 177 local_irq_save(flags);
161 cpu = smp_processor_id(); 178 cpu = get_physical_cpu();
179 time = gator_get_time();
162 if (buffer_check_space(cpu, COUNTER_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) { 180 if (buffer_check_space(cpu, COUNTER_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) {
163 gator_buffer_write_packed_int64(cpu, COUNTER_BUF, gator_get_time()); 181 gator_buffer_write_packed_int64(cpu, COUNTER_BUF, time);
164 gator_buffer_write_packed_int(cpu, COUNTER_BUF, core); 182 gator_buffer_write_packed_int(cpu, COUNTER_BUF, core);
165 gator_buffer_write_packed_int(cpu, COUNTER_BUF, key); 183 gator_buffer_write_packed_int(cpu, COUNTER_BUF, key);
166 gator_buffer_write_packed_int(cpu, COUNTER_BUF, value); 184 gator_buffer_write_packed_int(cpu, COUNTER_BUF, value);
167 } 185 }
168 // Check and commit; commit is set to occur once buffer is 3/4 full 186 // Check and commit; commit is set to occur once buffer is 3/4 full
169 buffer_check(cpu, COUNTER_BUF); 187 buffer_check(cpu, COUNTER_BUF, time);
170 local_irq_restore(flags); 188 local_irq_restore(flags);
171} 189}
172#endif 190#endif
173 191
174static void marshal_sched_gpu_start(int unit, int core, int tgid, int pid) 192static void marshal_sched_gpu_start(int unit, int core, int tgid, int pid)
175{ 193{
176 unsigned long cpu = smp_processor_id(), flags; 194 unsigned long cpu = get_physical_cpu(), flags;
195 u64 time;
177 196
178 if (!per_cpu(gator_buffer, cpu)[GPU_TRACE_BUF]) 197 if (!per_cpu(gator_buffer, cpu)[GPU_TRACE_BUF])
179 return; 198 return;
180 199
181 local_irq_save(flags); 200 local_irq_save(flags);
201 time = gator_get_time();
182 if (buffer_check_space(cpu, GPU_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { 202 if (buffer_check_space(cpu, GPU_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) {
183 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, MESSAGE_GPU_START); 203 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, MESSAGE_GPU_START);
184 gator_buffer_write_packed_int64(cpu, GPU_TRACE_BUF, gator_get_time()); 204 gator_buffer_write_packed_int64(cpu, GPU_TRACE_BUF, time);
185 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit); 205 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit);
186 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core); 206 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core);
187 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, tgid); 207 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, tgid);
188 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, pid); 208 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, pid);
189 } 209 }
190 // Check and commit; commit is set to occur once buffer is 3/4 full 210 // Check and commit; commit is set to occur once buffer is 3/4 full
191 buffer_check(cpu, GPU_TRACE_BUF); 211 buffer_check(cpu, GPU_TRACE_BUF, time);
192 local_irq_restore(flags); 212 local_irq_restore(flags);
193} 213}
194 214
195static void marshal_sched_gpu_stop(int unit, int core) 215static void marshal_sched_gpu_stop(int unit, int core)
196{ 216{
197 unsigned long cpu = smp_processor_id(), flags; 217 unsigned long cpu = get_physical_cpu(), flags;
218 u64 time;
198 219
199 if (!per_cpu(gator_buffer, cpu)[GPU_TRACE_BUF]) 220 if (!per_cpu(gator_buffer, cpu)[GPU_TRACE_BUF])
200 return; 221 return;
201 222
202 local_irq_save(flags); 223 local_irq_save(flags);
224 time = gator_get_time();
203 if (buffer_check_space(cpu, GPU_TRACE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) { 225 if (buffer_check_space(cpu, GPU_TRACE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) {
204 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, MESSAGE_GPU_STOP); 226 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, MESSAGE_GPU_STOP);
205 gator_buffer_write_packed_int64(cpu, GPU_TRACE_BUF, gator_get_time()); 227 gator_buffer_write_packed_int64(cpu, GPU_TRACE_BUF, time);
206 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit); 228 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit);
207 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core); 229 gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core);
208 } 230 }
209 // Check and commit; commit is set to occur once buffer is 3/4 full 231 // Check and commit; commit is set to occur once buffer is 3/4 full
210 buffer_check(cpu, GPU_TRACE_BUF); 232 buffer_check(cpu, GPU_TRACE_BUF, time);
211 local_irq_restore(flags); 233 local_irq_restore(flags);
212} 234}
213 235
214static void marshal_sched_trace_switch(int tgid, int pid, int cookie, int state) 236static void marshal_sched_trace_switch(int tgid, int pid, int cookie, int state)
215{ 237{
216 unsigned long cpu = smp_processor_id(), flags; 238 unsigned long cpu = get_physical_cpu(), flags;
239 u64 time;
217 240
218 if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF]) 241 if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF])
219 return; 242 return;
220 243
221 local_irq_save(flags); 244 local_irq_save(flags);
245 time = gator_get_time();
222 if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { 246 if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) {
223 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_SWITCH); 247 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_SWITCH);
224 gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, gator_get_time()); 248 gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time);
225 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, tgid); 249 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, tgid);
226 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid); 250 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid);
227 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie); 251 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie);
228 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, state); 252 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, state);
229 } 253 }
230 // Check and commit; commit is set to occur once buffer is 3/4 full 254 // Check and commit; commit is set to occur once buffer is 3/4 full
231 buffer_check(cpu, SCHED_TRACE_BUF); 255 buffer_check(cpu, SCHED_TRACE_BUF, time);
232 local_irq_restore(flags); 256 local_irq_restore(flags);
233} 257}
234 258
235static void marshal_sched_trace_exit(int tgid, int pid) 259static void marshal_sched_trace_exit(int tgid, int pid)
236{ 260{
237 unsigned long cpu = smp_processor_id(), flags; 261 unsigned long cpu = get_physical_cpu(), flags;
262 u64 time;
238 263
239 if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF]) 264 if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF])
240 return; 265 return;
241 266
242 local_irq_save(flags); 267 local_irq_save(flags);
268 time = gator_get_time();
243 if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) { 269 if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
244 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_EXIT); 270 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_EXIT);
245 gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, gator_get_time()); 271 gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time);
246 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid); 272 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid);
247 } 273 }
248 // Check and commit; commit is set to occur once buffer is 3/4 full 274 // Check and commit; commit is set to occur once buffer is 3/4 full
249 buffer_check(cpu, SCHED_TRACE_BUF); 275 buffer_check(cpu, SCHED_TRACE_BUF, time);
250 local_irq_restore(flags); 276 local_irq_restore(flags);
251} 277}
252 278
@@ -254,16 +280,18 @@ static void marshal_sched_trace_exit(int tgid, int pid)
254static void marshal_idle(int core, int state) 280static void marshal_idle(int core, int state)
255{ 281{
256 unsigned long flags, cpu; 282 unsigned long flags, cpu;
283 u64 time;
257 284
258 local_irq_save(flags); 285 local_irq_save(flags);
259 cpu = smp_processor_id(); 286 cpu = get_physical_cpu();
287 time = gator_get_time();
260 if (buffer_check_space(cpu, IDLE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) { 288 if (buffer_check_space(cpu, IDLE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
261 gator_buffer_write_packed_int(cpu, IDLE_BUF, state); 289 gator_buffer_write_packed_int(cpu, IDLE_BUF, state);
262 gator_buffer_write_packed_int64(cpu, IDLE_BUF, gator_get_time()); 290 gator_buffer_write_packed_int64(cpu, IDLE_BUF, time);
263 gator_buffer_write_packed_int(cpu, IDLE_BUF, core); 291 gator_buffer_write_packed_int(cpu, IDLE_BUF, core);
264 } 292 }
265 // Check and commit; commit is set to occur once buffer is 3/4 full 293 // Check and commit; commit is set to occur once buffer is 3/4 full
266 buffer_check(cpu, IDLE_BUF); 294 buffer_check(cpu, IDLE_BUF, time);
267 local_irq_restore(flags); 295 local_irq_restore(flags);
268} 296}
269#endif 297#endif
@@ -323,16 +351,17 @@ static void marshal_frame(int cpu, int buftype)
323} 351}
324 352
325#if defined(__arm__) || defined(__aarch64__) 353#if defined(__arm__) || defined(__aarch64__)
326static void marshal_core_name(const char *name) 354static void marshal_core_name(const int cpuid, const char *name)
327{ 355{
328 int cpu = smp_processor_id(); 356 int cpu = get_physical_cpu();
329 unsigned long flags; 357 unsigned long flags;
330 local_irq_save(flags); 358 local_irq_save(flags);
331 if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK32 + MAXSIZE_CORE_NAME)) { 359 if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK32 + MAXSIZE_CORE_NAME)) {
332 gator_buffer_write_packed_int(cpu, NAME_BUF, HRTIMER_CORE_NAME); 360 gator_buffer_write_packed_int(cpu, NAME_BUF, HRTIMER_CORE_NAME);
361 gator_buffer_write_packed_int(cpu, NAME_BUF, cpuid);
333 gator_buffer_write_string(cpu, NAME_BUF, name); 362 gator_buffer_write_string(cpu, NAME_BUF, name);
334 } 363 }
335 buffer_check(cpu, NAME_BUF); 364 buffer_check(cpu, NAME_BUF, gator_get_time());
336 local_irq_restore(flags); 365 local_irq_restore(flags);
337} 366}
338#endif 367#endif
diff --git a/driver/gator_pack.c b/driver/gator_pack.c
index 119746b..2bddcbe 100644
--- a/driver/gator_pack.c
+++ b/driver/gator_pack.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_trace_gpu.c b/driver/gator_trace_gpu.c
index 9fc488b..c94f6a0 100644
--- a/driver/gator_trace_gpu.c
+++ b/driver/gator_trace_gpu.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -32,14 +32,72 @@ static int mali_timeline_trace_registered;
32static int mali_job_slots_trace_registered; 32static int mali_job_slots_trace_registered;
33static int gpu_trace_registered; 33static int gpu_trace_registered;
34 34
35#define GPU_UNIT_NONE 0 35enum {
36#define GPU_UNIT_VP 1 36 GPU_UNIT_NONE = 0,
37#define GPU_UNIT_FP 2 37 GPU_UNIT_VP,
38#define GPU_UNIT_CL 3 38 GPU_UNIT_FP,
39 GPU_UNIT_CL,
40 NUMBER_OF_GPU_UNITS
41};
39 42
40#define MALI_400 (0x0b07) 43#define MALI_400 (0x0b07)
41#define MALI_T6xx (0x0056) 44#define MALI_T6xx (0x0056)
42 45
46struct mali_gpu_job {
47 int count;
48 int last_core;
49 int last_tgid;
50 int last_pid;
51};
52
53#define NUMBER_OF_GPU_CORES 16
54static struct mali_gpu_job mali_gpu_jobs[NUMBER_OF_GPU_UNITS][NUMBER_OF_GPU_CORES];
55static DEFINE_SPINLOCK(mali_gpu_jobs_lock);
56
57static void mali_gpu_enqueue(int unit, int core, int tgid, int pid)
58{
59 int count;
60
61 spin_lock(&mali_gpu_jobs_lock);
62 count = mali_gpu_jobs[unit][core].count;
63 BUG_ON(count < 0);
64 ++mali_gpu_jobs[unit][core].count;
65 if (count) {
66 mali_gpu_jobs[unit][core].last_core = core;
67 mali_gpu_jobs[unit][core].last_tgid = tgid;
68 mali_gpu_jobs[unit][core].last_pid = pid;
69 }
70 spin_unlock(&mali_gpu_jobs_lock);
71
72 if (!count) {
73 marshal_sched_gpu_start(unit, core, tgid, pid);
74 }
75}
76
77static void mali_gpu_stop(int unit, int core)
78{
79 int count;
80 int last_core = 0;
81 int last_tgid = 0;
82 int last_pid = 0;
83
84 spin_lock(&mali_gpu_jobs_lock);
85 --mali_gpu_jobs[unit][core].count;
86 count = mali_gpu_jobs[unit][core].count;
87 BUG_ON(count < 0);
88 if (count) {
89 last_core = mali_gpu_jobs[unit][core].last_core;
90 last_tgid = mali_gpu_jobs[unit][core].last_tgid;
91 last_pid = mali_gpu_jobs[unit][core].last_pid;
92 }
93 spin_unlock(&mali_gpu_jobs_lock);
94
95 marshal_sched_gpu_stop(unit, core);
96 if (count) {
97 marshal_sched_gpu_start(unit, last_core, last_tgid, last_pid);
98 }
99}
100
43#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx) 101#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
44#include "gator_events_mali_400.h" 102#include "gator_events_mali_400.h"
45 103
@@ -80,18 +138,18 @@ GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned
80 case EVENT_TYPE_START: 138 case EVENT_TYPE_START:
81 if (component == EVENT_CHANNEL_VP0) { 139 if (component == EVENT_CHANNEL_VP0) {
82 /* tgid = d0; pid = d1; */ 140 /* tgid = d0; pid = d1; */
83 marshal_sched_gpu_start(GPU_UNIT_VP, 0, d0, d1); 141 mali_gpu_enqueue(GPU_UNIT_VP, 0, d0, d1);
84 } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) { 142 } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
85 /* tgid = d0; pid = d1; */ 143 /* tgid = d0; pid = d1; */
86 marshal_sched_gpu_start(GPU_UNIT_FP, component - EVENT_CHANNEL_FP0, d0, d1); 144 mali_gpu_enqueue(GPU_UNIT_FP, component - EVENT_CHANNEL_FP0, d0, d1);
87 } 145 }
88 break; 146 break;
89 147
90 case EVENT_TYPE_STOP: 148 case EVENT_TYPE_STOP:
91 if (component == EVENT_CHANNEL_VP0) { 149 if (component == EVENT_CHANNEL_VP0) {
92 marshal_sched_gpu_stop(GPU_UNIT_VP, 0); 150 mali_gpu_stop(GPU_UNIT_VP, 0);
93 } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) { 151 } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
94 marshal_sched_gpu_stop(GPU_UNIT_FP, component - EVENT_CHANNEL_FP0); 152 mali_gpu_stop(GPU_UNIT_FP, component - EVENT_CHANNEL_FP0);
95 } 153 }
96 break; 154 break;
97 155
@@ -136,16 +194,16 @@ GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigne
136 if (unit != GPU_UNIT_NONE) { 194 if (unit != GPU_UNIT_NONE) {
137 switch (state) { 195 switch (state) {
138 case EVENT_TYPE_START: 196 case EVENT_TYPE_START:
139 marshal_sched_gpu_start(unit, 0, tgid, (pid != 0 ? pid : tgid)); 197 mali_gpu_enqueue(unit, 0, tgid, (pid != 0 ? pid : tgid));
140 break; 198 break;
141 case EVENT_TYPE_STOP: 199 case EVENT_TYPE_STOP:
142 marshal_sched_gpu_stop(unit, 0); 200 mali_gpu_stop(unit, 0);
143 break; 201 break;
144 default: 202 default:
145 /* 203 /*
146 * Some jobs can be soft-stopped, so ensure that this terminates the activity trace. 204 * Some jobs can be soft-stopped, so ensure that this terminates the activity trace.
147 */ 205 */
148 marshal_sched_gpu_stop(unit, 0); 206 mali_gpu_stop(unit, 0);
149 } 207 }
150 } 208 }
151} 209}
@@ -153,12 +211,12 @@ GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigne
153 211
154GATOR_DEFINE_PROBE(gpu_activity_start, TP_PROTO(int gpu_unit, int gpu_core, struct task_struct *p)) 212GATOR_DEFINE_PROBE(gpu_activity_start, TP_PROTO(int gpu_unit, int gpu_core, struct task_struct *p))
155{ 213{
156 marshal_sched_gpu_start(gpu_unit, gpu_core, (int)p->tgid, (int)p->pid); 214 mali_gpu_enqueue(gpu_unit, gpu_core, (int)p->tgid, (int)p->pid);
157} 215}
158 216
159GATOR_DEFINE_PROBE(gpu_activity_stop, TP_PROTO(int gpu_unit, int gpu_core)) 217GATOR_DEFINE_PROBE(gpu_activity_stop, TP_PROTO(int gpu_unit, int gpu_core))
160{ 218{
161 marshal_sched_gpu_stop(gpu_unit, gpu_core); 219 mali_gpu_stop(gpu_unit, gpu_core);
162} 220}
163 221
164int gator_trace_gpu_start(void) 222int gator_trace_gpu_start(void)
diff --git a/driver/gator_trace_gpu.h b/driver/gator_trace_gpu.h
index efb47c6..bb0f42d 100644
--- a/driver/gator_trace_gpu.h
+++ b/driver/gator_trace_gpu.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/driver/gator_trace_power.c b/driver/gator_trace_power.c
index 79fa13c..272e056 100644
--- a/driver/gator_trace_power.c
+++ b/driver/gator_trace_power.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -38,14 +38,27 @@ static ulong power_cpu_key[POWER_TOTAL];
38static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root) 38static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root)
39{ 39{
40 struct dentry *dir; 40 struct dentry *dir;
41 int cpu;
42 bool found_nonzero_freq = false;
43
44 // Even if CONFIG_CPU_FREQ is defined, it still may not be used. Check
45 // for non-zero values from cpufreq_quick_get
46 for_each_online_cpu(cpu) {
47 if (cpufreq_quick_get(cpu) > 0) {
48 found_nonzero_freq = true;
49 break;
50 }
51 }
41 52
42 // cpu_frequency 53 if (found_nonzero_freq) {
43 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_freq"); 54 // cpu_frequency
44 if (!dir) { 55 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_freq");
45 return -1; 56 if (!dir) {
57 return -1;
58 }
59 gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_FREQ]);
60 gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_FREQ]);
46 } 61 }
47 gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_FREQ]);
48 gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_FREQ]);
49 62
50 // cpu_idle 63 // cpu_idle
51 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_idle"); 64 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_idle");
@@ -61,13 +74,14 @@ static int gator_trace_power_create_files(struct super_block *sb, struct dentry
61// 'cpu' may not equal smp_processor_id(), i.e. may not be running on the core that is having the freq/idle state change 74// 'cpu' may not equal smp_processor_id(), i.e. may not be running on the core that is having the freq/idle state change
62GATOR_DEFINE_PROBE(cpu_frequency, TP_PROTO(unsigned int frequency, unsigned int cpu)) 75GATOR_DEFINE_PROBE(cpu_frequency, TP_PROTO(unsigned int frequency, unsigned int cpu))
63{ 76{
77 cpu = lcpu_to_pcpu(cpu);
64 marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], frequency * 1000); 78 marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], frequency * 1000);
65} 79}
66 80
67#define WFI_EXIT 2
68#define WFI_ENTER 1
69GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu)) 81GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu))
70{ 82{
83 cpu = lcpu_to_pcpu(cpu);
84
71 if (state == per_cpu(idle_prev_state, cpu)) { 85 if (state == per_cpu(idle_prev_state, cpu)) {
72 return; 86 return;
73 } 87 }
@@ -75,10 +89,10 @@ GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu))
75 if (implements_wfi()) { 89 if (implements_wfi()) {
76 if (state == PWR_EVENT_EXIT) { 90 if (state == PWR_EVENT_EXIT) {
77 // transition from wfi to non-wfi 91 // transition from wfi to non-wfi
78 marshal_idle(cpu, WFI_EXIT); 92 marshal_idle(cpu, MESSAGE_IDLE_EXIT);
79 } else { 93 } else {
80 // transition from non-wfi to wfi 94 // transition from non-wfi to wfi
81 marshal_idle(cpu, WFI_ENTER); 95 marshal_idle(cpu, MESSAGE_IDLE_ENTER);
82 } 96 }
83 } 97 }
84 98
@@ -92,16 +106,17 @@ GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu))
92 106
93static void gator_trace_power_online(void) 107static void gator_trace_power_online(void)
94{ 108{
95 int cpu = smp_processor_id(); 109 int pcpu = get_physical_cpu();
110 int lcpu = get_logical_cpu();
96 if (power_cpu_enabled[POWER_CPU_FREQ]) { 111 if (power_cpu_enabled[POWER_CPU_FREQ]) {
97 marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], cpufreq_quick_get(cpu) * 1000); 112 marshal_event_single(pcpu, power_cpu_key[POWER_CPU_FREQ], cpufreq_quick_get(lcpu) * 1000);
98 } 113 }
99} 114}
100 115
101static void gator_trace_power_offline(void) 116static void gator_trace_power_offline(void)
102{ 117{
103 // Set frequency to zero on an offline 118 // Set frequency to zero on an offline
104 int cpu = smp_processor_id(); 119 int cpu = get_physical_cpu();
105 if (power_cpu_enabled[POWER_CPU_FREQ]) { 120 if (power_cpu_enabled[POWER_CPU_FREQ]) {
106 marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], 0); 121 marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], 0);
107 } 122 }
diff --git a/driver/gator_trace_sched.c b/driver/gator_trace_sched.c
index d0336f9..eb989b5 100644
--- a/driver/gator_trace_sched.c
+++ b/driver/gator_trace_sched.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -23,14 +23,13 @@ enum {
23 STATE_WAIT_ON_OTHER = 0, 23 STATE_WAIT_ON_OTHER = 0,
24 STATE_CONTENTION, 24 STATE_CONTENTION,
25 STATE_WAIT_ON_IO, 25 STATE_WAIT_ON_IO,
26 STATE_WAIT_ON_MUTEX,
27}; 26};
28 27
29void emit_pid_name(struct task_struct *task) 28void emit_pid_name(struct task_struct *task)
30{ 29{
31 bool found = false; 30 bool found = false;
32 char taskcomm[TASK_COMM_LEN + 3]; 31 char taskcomm[TASK_COMM_LEN + 3];
33 unsigned long x, cpu = smp_processor_id(); 32 unsigned long x, cpu = get_physical_cpu();
34 uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]); 33 uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]);
35 uint64_t value; 34 uint64_t value;
36 35
@@ -66,9 +65,10 @@ void emit_pid_name(struct task_struct *task)
66 65
67static void collect_counters(void) 66static void collect_counters(void)
68{ 67{
69 int *buffer, len; 68 int *buffer, len, cpu = get_physical_cpu();
70 long long *buffer64; 69 long long *buffer64;
71 struct gator_interface *gi; 70 struct gator_interface *gi;
71 u64 time;
72 72
73 if (marshal_event_header()) { 73 if (marshal_event_header()) {
74 list_for_each_entry(gi, &gator_events, list) { 74 list_for_each_entry(gi, &gator_events, list) {
@@ -80,13 +80,27 @@ static void collect_counters(void)
80 marshal_event64(len, buffer64); 80 marshal_event64(len, buffer64);
81 } 81 }
82 } 82 }
83 // Only check after writing all counters so that time and corresponding counters appear in the same frame
84 time = gator_get_time();
85 buffer_check(cpu, BLOCK_COUNTER_BUF, time);
86
87#if GATOR_LIVE
88 // Commit buffers on timeout
89 if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) {
90 static const int buftypes[] = { COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF };
91 int i;
92 for (i = 0; i < sizeof(buftypes)/sizeof(buftypes[0]); ++i) {
93 gator_commit_buffer(cpu, buftypes[i], time);
94 }
95 }
96#endif
83 } 97 }
84} 98}
85 99
86static void probe_sched_write(int type, struct task_struct *task, struct task_struct *old_task) 100static void probe_sched_write(int type, struct task_struct *task, struct task_struct *old_task)
87{ 101{
88 int cookie = 0, state = 0; 102 int cookie = 0, state = 0;
89 int cpu = smp_processor_id(); 103 int cpu = get_physical_cpu();
90 int tgid = task->tgid; 104 int tgid = task->tgid;
91 int pid = task->pid; 105 int pid = task->pid;
92 106
@@ -98,10 +112,6 @@ static void probe_sched_write(int type, struct task_struct *task, struct task_st
98 state = STATE_CONTENTION; 112 state = STATE_CONTENTION;
99 } else if (old_task->in_iowait) { 113 } else if (old_task->in_iowait) {
100 state = STATE_WAIT_ON_IO; 114 state = STATE_WAIT_ON_IO;
101#ifdef CONFIG_DEBUG_MUTEXES
102 } else if (old_task->blocked_on) {
103 state = STATE_WAIT_ON_MUTEX;
104#endif
105 } else { 115 } else {
106 state = STATE_WAIT_ON_OTHER; 116 state = STATE_WAIT_ON_OTHER;
107 } 117 }