diff options
author | Jon Medhurst | 2014-08-01 07:32:58 -0500 |
---|---|---|
committer | Jon Medhurst | 2014-08-01 07:33:21 -0500 |
commit | bc8a84cf0b138a2951679581453da7bd93003db6 (patch) | |
tree | b94eb00f90c24063053d99bea588fbbd493076ef | |
parent | ba783f1443773505231ac2808c9a3716c3c2f3ae (diff) | |
download | arm-ds5-gator-DS-5.19-ti.tar.gz arm-ds5-gator-DS-5.19-ti.tar.xz arm-ds5-gator-DS-5.19-ti.zip |
gator: Version 5.19DS-5.19-tiDS-5.19
Signed-off-by: Jon Medhurst <tixy@linaro.org>
On branch master
Changes not staged for commit:
modified: README_Streamline.txt
no changes added to commit (use "git add" and/or "git commit -a")
Signed-off-by: Jon Medhurst <tixy@linaro.org>
87 files changed, 2281 insertions, 1057 deletions
diff --git a/README_Streamline.txt b/README_Streamline.txt index df3f923..54791c0 100755 --- a/README_Streamline.txt +++ b/README_Streamline.txt | |||
@@ -2,7 +2,7 @@ | |||
2 | *** Purpose *** | 2 | *** Purpose *** |
3 | 3 | ||
4 | Instructions on setting up ARM Streamline on the target. | 4 | Instructions on setting up ARM Streamline on the target. |
5 | The gator driver and gator daemon are required to run on the ARM Linux target in order for ARM Streamline to operate. A new early access feature allows the gator daemon can run without the gator driver by using userspace APIs with reduced functionality when using Linux 3.12 or later. | 5 | The gator driver and gator daemon are required to run on the ARM Linux target in order for ARM Streamline to operate. A new early access feature allows the gator daemon can run without the gator driver by using userspace APIs with reduced functionality when using Linux 3.4 or later. |
6 | The driver should be built as a module and the daemon must run with root permissions on the target. | 6 | The driver should be built as a module and the daemon must run with root permissions on the target. |
7 | 7 | ||
8 | *** Introduction *** | 8 | *** Introduction *** |
@@ -14,7 +14,7 @@ A Linux development environment with cross compiling tools is most likely requir | |||
14 | -First, check if the kernel has the proper configuration options (see below). Profiling cannot occur using a kernel that is not configured properly, a new kernel must be created. See if /proc/config.gz exists on the target. | 14 | -First, check if the kernel has the proper configuration options (see below). Profiling cannot occur using a kernel that is not configured properly, a new kernel must be created. See if /proc/config.gz exists on the target. |
15 | -Second, given a properly configured kernel, check if the filesystem contains the kernel source/headers, which can be used to re-create the gator driver. These files may be located in different areas, but common locations are /lib/modules/ and /usr/src. | 15 | -Second, given a properly configured kernel, check if the filesystem contains the kernel source/headers, which can be used to re-create the gator driver. These files may be located in different areas, but common locations are /lib/modules/ and /usr/src. |
16 | -If the kernel is not properly configured or sources/headers are not available, the developer is on their own and kernel creation is beyond the scope of this document. Note: It is possible for a module to work when compiled against a similar kernel source code, though this is not guaranteed to work due to differences in kernel structures, exported symbols and incompatible configuration parameters. | 16 | -If the kernel is not properly configured or sources/headers are not available, the developer is on their own and kernel creation is beyond the scope of this document. Note: It is possible for a module to work when compiled against a similar kernel source code, though this is not guaranteed to work due to differences in kernel structures, exported symbols and incompatible configuration parameters. |
17 | -If the target is running Linux 3.12 or later the kernel driver is not required and userspace APIs will be used instead. | 17 | -If the target is running Linux 3.4 or later the kernel driver is not required and userspace APIs will be used instead. |
18 | 18 | ||
19 | *** Kernel configuration *** | 19 | *** Kernel configuration *** |
20 | 20 | ||
@@ -59,8 +59,7 @@ If a device tree is used it must include the pmu bindings, see Documentation/dev | |||
59 | *** Building the gator module *** | 59 | *** Building the gator module *** |
60 | 60 | ||
61 | To create the gator.ko module, | 61 | To create the gator.ko module, |
62 | cd /path/to/gator/driver-src | 62 | tar xzf /path/to/DS-5/arm/gator/driver-src/gator-driver.tar.gz |
63 | tar xzf gator-driver.tar.gz | ||
64 | cd gator-driver | 63 | cd gator-driver |
65 | make -C <kernel_build_dir> M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules | 64 | make -C <kernel_build_dir> M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules |
66 | for example when using the linaro-toolchain-binaries | 65 | for example when using the linaro-toolchain-binaries |
@@ -78,10 +77,14 @@ Edit Kconfig in the kernel drivers folder and add this before the last endmenu | |||
78 | source "drivers/gator/Kconfig" | 77 | source "drivers/gator/Kconfig" |
79 | You can now select gator when using menuconfig while configuring the kernel and rebuild as directed | 78 | You can now select gator when using menuconfig while configuring the kernel and rebuild as directed |
80 | 79 | ||
80 | *** Use the prebuilt gator daemon *** | ||
81 | |||
82 | A prebuilt gator daemon is provided at /path/to/DS-5/arm/gator/gatord. This gator daemon should work in most cases so building the gator daemon is only required if the prebuilt gator daemon doesn't work. | ||
83 | To improve portablility gatord is statically compiled against musl libc from http://www.musl-libc.org/releases/musl-1.0.2.tar.gz instead of glibc. The gator daemon will work correctly with either glibc or musl. | ||
84 | |||
81 | *** Building the gator daemon *** | 85 | *** Building the gator daemon *** |
82 | 86 | ||
83 | cd /path/to/gator/daemon-src | 87 | tar -xzf /path/to/DS-5/arm/gator/daemon-src/gator-daemon.tar.gz |
84 | tar -xzf gator-daemon.tar.gz (may need to issue with 'sudo') | ||
85 | For Linux targets, | 88 | For Linux targets, |
86 | cd gator-daemon | 89 | cd gator-daemon |
87 | make CROSS_COMPILE=<...> # For ARMv7 targets | 90 | make CROSS_COMPILE=<...> # For ARMv7 targets |
@@ -105,7 +108,7 @@ gator.ko must be located in the same directory as gatord on the target or the lo | |||
105 | With root privileges, run the daemon | 108 | With root privileges, run the daemon |
106 | sudo ./gatord & | 109 | sudo ./gatord & |
107 | Note: gatord requires libstdc++.so.6 which is usually supplied by the Linux distribution on the target. A copy of libstdc++.so.6 is available in the DS-5 Linux example distribution. | 110 | Note: gatord requires libstdc++.so.6 which is usually supplied by the Linux distribution on the target. A copy of libstdc++.so.6 is available in the DS-5 Linux example distribution. |
108 | If gator.ko is not loaded and is not in the same directory as gatord when using Linux 3.12 or later, gatord can run without gator.ko by using userspace APIs. Not all features are supported by userspace gator. If /dev/gator/version does not exist after starting gatord it is running userspace gator. | 111 | If gator.ko is not loaded and is not in the same directory as gatord when using Linux 3.4 or later, gatord can run without gator.ko by using userspace APIs. Not all features are supported by userspace gator. If /dev/gator/version does not exist after starting gatord it is running userspace gator. |
109 | 112 | ||
110 | *** Customizing the l2c-310 Counter *** | 113 | *** Customizing the l2c-310 Counter *** |
111 | 114 | ||
@@ -123,7 +126,7 @@ CCN-504 is disabled by default. To enable CCN-504, insmod gator module with the | |||
123 | Recommended compiler settings: | 126 | Recommended compiler settings: |
124 | "-g": Debug information, such as line numbers, needed for best analysis results. | 127 | "-g": Debug information, such as line numbers, needed for best analysis results. |
125 | "-fno-inline": Speed improvement when processing the image files and most accurate analysis results. | 128 | "-fno-inline": Speed improvement when processing the image files and most accurate analysis results. |
126 | "-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). | 129 | "-fno-omit-frame-pointer": ARM EABI frame pointers allow recording of the call stack with each sample taken when in ARM state (i.e. not -mthumb). |
127 | "-marm": This option is required if your compiler is configured with --with-mode=thumb, otherwise call stack unwinding will not work. | 130 | "-marm": This option is required if your compiler is configured with --with-mode=thumb, otherwise call stack unwinding will not work. |
128 | 131 | ||
129 | *** Hardfloat EABI *** | 132 | *** Hardfloat EABI *** |
@@ -132,6 +135,35 @@ To compile for non-hardfloat targets it is necessary to add options '-marm -marc | |||
132 | The armv5t_mtx filesystem is provided as part of the "DS-5 Linux Example Distribution" package which can be downloaded from the DS-5 Downloads page. | 135 | The armv5t_mtx filesystem is provided as part of the "DS-5 Linux Example Distribution" package which can be downloaded from the DS-5 Downloads page. |
133 | Attempting to run an incompatible binary often results in the confusing error message "No such file or directory" when clearly the file exists. | 136 | Attempting to run an incompatible binary often results in the confusing error message "No such file or directory" when clearly the file exists. |
134 | 137 | ||
138 | *** Mali GPU *** | ||
139 | |||
140 | Streamline supports Mali-400, 450, T6xx, and T7xx series GPUs with hardware activity charts, hardware & software counters and an optional 'film strip' showing periodic framebuffer snapshots. Support is chosen at build time and only one type of GPU (and version of driver) is supported at once. For best results build gator in-tree at .../drivers/gator and use the menuconfig options. Details of what these mean or how to build out of tree below. | ||
141 | |||
142 | Mali-4xx: | ||
143 | ___To add Mali-4xx support to gator___ | ||
144 | GATOR_WITH_MALI_SUPPORT=MALI_4xx # Set by CONFIG_GATOR_MALI_4XXMP | ||
145 | CONFIG_GATOR_MALI_PATH=".../path/to/Mali_DDK_kernel_files/src/devicedrv/mali" # gator source needs to #include "linux/mali_linux_trace.h" | ||
146 | GATOR_MALI_INTERFACE_STYLE=<3|4> # 3=Mali-400 DDK >= r3p0-04rel0 and < r3p2-01rel3 | ||
147 | # 4=Mali-400 DDK >= r3p2-01rel3 | ||
148 | # (default of 4 set in gator-driver/gator_events_mali_4xx.c) | ||
149 | ___To add the corresponding support to Mali___ | ||
150 | Userspace needs MALI_TIMELINE_PROFILING_ENABLED=1 MALI_FRAMEBUFFER_DUMP_ENABLED=1 MALI_SW_COUNTERS_ENABLED=1 | ||
151 | Kernel driver needs USING_PROFILING=1 # Sets CONFIG_MALI400_PROFILING=y | ||
152 | See the DDK integration guide for more details (the above are the default in later driver versions) | ||
153 | |||
154 | Mali-T6xx/T7xx: | ||
155 | ___To add Mali-T6xx support to gator___ | ||
156 | GATOR_WITH_MALI_SUPPORT=MALI_T6xx # Set by CONFIG_GATOR_MALI_T6XX | ||
157 | DDK_DIR=".../path/to/Mali_DDK_kernel_files" # gator source needs access to headers under .../kernel/drivers/gpu/arm/... | ||
158 | # (default of . suitable for in-tree builds) | ||
159 | ___To add the corresponding support to Mali___ | ||
160 | Userspace (scons) needs gator=1 | ||
161 | Kernel driver needs CONFIG_MALI_GATOR_SUPPORT=y | ||
162 | See the DDK integration guide for more details | ||
163 | |||
164 | *** Polling /dev, /sys and /proc files *** | ||
165 | Gator supports reading arbitrary /dev, /sys and /proc files 10 times a second. It will either interpret the file contents as a number or use a POSIX extended regex to extract the number, see events-Filesystem.xml for examples. | ||
166 | |||
135 | *** Bugs *** | 167 | *** Bugs *** |
136 | 168 | ||
137 | There is a bug in some Linux kernels where perf misidentifies the CPU type. To see if you are affected by this, run ls /sys/bus/event_source/devices/ and verify the listed processor type matches what is expected. For example, an A9 should show the following. | 169 | There is a bug in some Linux kernels where perf misidentifies the CPU type. To see if you are affected by this, run ls /sys/bus/event_source/devices/ and verify the listed processor type matches what is expected. For example, an A9 should show the following. |
@@ -139,7 +171,7 @@ There is a bug in some Linux kernels where perf misidentifies the CPU type. To s | |||
139 | ARMv7_Cortex_A9 breakpoint software tracepoint | 171 | ARMv7_Cortex_A9 breakpoint software tracepoint |
140 | To work around the issue try upgrading to a later kernel or comment out the gator_events_perf_pmu_cpu_init(gator_cpu, type); call in gator_events_perf_pmu.c | 172 | To work around the issue try upgrading to a later kernel or comment out the gator_events_perf_pmu_cpu_init(gator_cpu, type); call in gator_events_perf_pmu.c |
141 | 173 | ||
142 | There is a bug in some Linux kernels where an Oops may occurs when using userspace gator and a core is offlined. The fix was merged into mainline in 3.14-rc5, see http://git.kernel.org/tip/e3703f8cdfcf39c25c4338c3ad8e68891cca3731, and as been backported to older kernels. | 174 | There is a bug in some Linux kernels where an Oops may occur when using userspace gator and a core is offlined. The fix was merged into mainline in 3.14-rc5, see http://git.kernel.org/tip/e3703f8cdfcf39c25c4338c3ad8e68891cca3731, and as been backported to older kernels. |
143 | 175 | ||
144 | If you see this error when using SELinux, ex: Android 4.4 or later | 176 | If you see this error when using SELinux, ex: Android 4.4 or later |
145 | # ./gatord | 177 | # ./gatord |
@@ -172,3 +204,4 @@ update-rc.d rungator.sh defaults | |||
172 | *** GPL License *** | 204 | *** GPL License *** |
173 | 205 | ||
174 | For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz. | 206 | For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz. |
207 | The prebuilt gatord uses musl from http://www.musl-libc.org/releases/musl-1.0.2.tar.gz for musl license information see the COPYRIGHT file in the musl tar file. | ||
diff --git a/daemon/Android.mk b/daemon/Android.mk index 045d028..44c069c 100644 --- a/daemon/Android.mk +++ b/daemon/Android.mk | |||
@@ -3,7 +3,7 @@ include $(CLEAR_VARS) | |||
3 | 3 | ||
4 | XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h) | 4 | XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h) |
5 | 5 | ||
6 | LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -DETCDIR=\"/etc\" -Ilibsensors | 6 | LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -pthread -DETCDIR=\"/etc\" -Ilibsensors |
7 | 7 | ||
8 | LOCAL_SRC_FILES := \ | 8 | LOCAL_SRC_FILES := \ |
9 | Buffer.cpp \ | 9 | Buffer.cpp \ |
@@ -15,12 +15,14 @@ LOCAL_SRC_FILES := \ | |||
15 | DynBuf.cpp \ | 15 | DynBuf.cpp \ |
16 | EventsXML.cpp \ | 16 | EventsXML.cpp \ |
17 | ExternalSource.cpp \ | 17 | ExternalSource.cpp \ |
18 | FSDriver.cpp \ | ||
18 | Fifo.cpp \ | 19 | Fifo.cpp \ |
19 | Hwmon.cpp \ | 20 | Hwmon.cpp \ |
20 | KMod.cpp \ | 21 | KMod.cpp \ |
21 | LocalCapture.cpp \ | 22 | LocalCapture.cpp \ |
22 | Logging.cpp \ | 23 | Logging.cpp \ |
23 | main.cpp \ | 24 | main.cpp \ |
25 | MaliVideoDriver.cpp \ | ||
24 | Monitor.cpp \ | 26 | Monitor.cpp \ |
25 | OlySocket.cpp \ | 27 | OlySocket.cpp \ |
26 | OlyUtility.cpp \ | 28 | OlyUtility.cpp \ |
@@ -55,7 +57,7 @@ LOCAL_SRC_FILES := \ | |||
55 | mxml/mxml-set.c \ | 57 | mxml/mxml-set.c \ |
56 | mxml/mxml-string.c | 58 | mxml/mxml-string.c |
57 | 59 | ||
58 | LOCAL_C_INCLUDES := $(LOCAL_PATH) | 60 | LOCAL_C_INCLUDES := $(LOCAL_PATH) |
59 | 61 | ||
60 | LOCAL_MODULE := gatord | 62 | LOCAL_MODULE := gatord |
61 | LOCAL_MODULE_TAGS := optional | 63 | LOCAL_MODULE_TAGS := optional |
diff --git a/daemon/Application.mk b/daemon/Application.mk new file mode 100644 index 0000000..631ba54 --- /dev/null +++ b/daemon/Application.mk | |||
@@ -0,0 +1 @@ | |||
APP_PLATFORM := android-8 | |||
diff --git a/daemon/Buffer.cpp b/daemon/Buffer.cpp index 93557da..dd19f7f 100644 --- a/daemon/Buffer.cpp +++ b/daemon/Buffer.cpp | |||
@@ -15,11 +15,12 @@ | |||
15 | #define mask (mSize - 1) | 15 | #define mask (mSize - 1) |
16 | 16 | ||
17 | enum { | 17 | enum { |
18 | CODE_PEA = 1, | 18 | CODE_PEA = 1, |
19 | CODE_KEYS = 2, | 19 | CODE_KEYS = 2, |
20 | CODE_FORMAT = 3, | 20 | CODE_FORMAT = 3, |
21 | CODE_MAPS = 4, | 21 | CODE_MAPS = 4, |
22 | CODE_COMM = 5, | 22 | CODE_COMM = 5, |
23 | CODE_KEYS_OLD = 6, | ||
23 | }; | 24 | }; |
24 | 25 | ||
25 | // Summary Frame Messages | 26 | // Summary Frame Messages |
@@ -167,7 +168,7 @@ void Buffer::check(const uint64_t time) { | |||
167 | } | 168 | } |
168 | } | 169 | } |
169 | 170 | ||
170 | void Buffer::packInt(int32_t x) { | 171 | void Buffer::packInt(char *const buf, const int size, int &writePos, int32_t x) { |
171 | int packedBytes = 0; | 172 | int packedBytes = 0; |
172 | int more = true; | 173 | int more = true; |
173 | while (more) { | 174 | while (more) { |
@@ -181,11 +182,15 @@ void Buffer::packInt(int32_t x) { | |||
181 | b |= 0x80; | 182 | b |= 0x80; |
182 | } | 183 | } |
183 | 184 | ||
184 | mBuf[(mWritePos + packedBytes) & mask] = b; | 185 | buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b; |
185 | packedBytes++; | 186 | packedBytes++; |
186 | } | 187 | } |
187 | 188 | ||
188 | mWritePos = (mWritePos + packedBytes) & mask; | 189 | writePos = (writePos + packedBytes) & /*mask*/(size - 1); |
190 | } | ||
191 | |||
192 | void Buffer::packInt(int32_t x) { | ||
193 | packInt(mBuf, mSize, mWritePos, x); | ||
189 | } | 194 | } |
190 | 195 | ||
191 | void Buffer::packInt64(int64_t x) { | 196 | void Buffer::packInt64(int64_t x) { |
@@ -320,6 +325,21 @@ void Buffer::keys(const int count, const __u64 *const ids, const int *const keys | |||
320 | check(1); | 325 | check(1); |
321 | } | 326 | } |
322 | 327 | ||
328 | void Buffer::keysOld(const int keyCount, const int *const keys, const int bytes, const char *const buf) { | ||
329 | if (checkSpace((2 + keyCount) * MAXSIZE_PACK32 + bytes)) { | ||
330 | packInt(CODE_KEYS_OLD); | ||
331 | packInt(keyCount); | ||
332 | for (int i = 0; i < keyCount; ++i) { | ||
333 | packInt(keys[i]); | ||
334 | } | ||
335 | writeBytes(buf, bytes); | ||
336 | } else { | ||
337 | logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs"); | ||
338 | handleException(); | ||
339 | } | ||
340 | check(1); | ||
341 | } | ||
342 | |||
323 | void Buffer::format(const int length, const char *const format) { | 343 | void Buffer::format(const int length, const char *const format) { |
324 | if (checkSpace(MAXSIZE_PACK32 + length + 1)) { | 344 | if (checkSpace(MAXSIZE_PACK32 + length + 1)) { |
325 | packInt(CODE_FORMAT); | 345 | packInt(CODE_FORMAT); |
diff --git a/daemon/Buffer.h b/daemon/Buffer.h index 5023777..2de1b97 100644 --- a/daemon/Buffer.h +++ b/daemon/Buffer.h | |||
@@ -54,6 +54,7 @@ public: | |||
54 | // Perf Attrs messages | 54 | // Perf Attrs messages |
55 | void pea(const struct perf_event_attr *const pea, int key); | 55 | void pea(const struct perf_event_attr *const pea, int key); |
56 | void keys(const int count, const __u64 *const ids, const int *const keys); | 56 | void keys(const int count, const __u64 *const ids, const int *const keys); |
57 | void keysOld(const int keyCount, const int *const keys, const int bytes, const char *const buf); | ||
57 | void format(const int length, const char *const format); | 58 | void format(const int length, const char *const format); |
58 | void maps(const int pid, const int tid, const char *const maps); | 59 | void maps(const int pid, const int tid, const char *const maps); |
59 | void comm(const int pid, const int tid, const char *const image, const char *const comm); | 60 | void comm(const int pid, const int tid, const char *const image, const char *const comm); |
@@ -64,6 +65,11 @@ public: | |||
64 | // Prefer a new member to using these functions if possible | 65 | // Prefer a new member to using these functions if possible |
65 | char *getWritePos() { return mBuf + mWritePos; } | 66 | char *getWritePos() { return mBuf + mWritePos; } |
66 | void advanceWrite(int bytes) { mWritePos = (mWritePos + bytes) & /*mask*/(mSize - 1); } | 67 | void advanceWrite(int bytes) { mWritePos = (mWritePos + bytes) & /*mask*/(mSize - 1); } |
68 | static void packInt(char *const buf, const int size, int &writePos, int32_t x); | ||
69 | void packInt(int32_t x); | ||
70 | void packInt64(int64_t x); | ||
71 | void writeBytes(const void *const data, size_t count); | ||
72 | void writeString(const char *const str); | ||
67 | 73 | ||
68 | static void writeLEInt(unsigned char *buf, int v) { | 74 | static void writeLEInt(unsigned char *buf, int v) { |
69 | buf[0] = (v >> 0) & 0xFF; | 75 | buf[0] = (v >> 0) & 0xFF; |
@@ -76,11 +82,6 @@ private: | |||
76 | bool commitReady() const; | 82 | bool commitReady() const; |
77 | bool checkSpace(int bytes); | 83 | bool checkSpace(int bytes); |
78 | 84 | ||
79 | void packInt(int32_t x); | ||
80 | void packInt64(int64_t x); | ||
81 | void writeBytes(const void *const data, size_t count); | ||
82 | void writeString(const char *const str); | ||
83 | |||
84 | const int32_t mCore; | 85 | const int32_t mCore; |
85 | const int32_t mBufType; | 86 | const int32_t mBufType; |
86 | const int mSize; | 87 | const int mSize; |
diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp index cf79b72..4a11415 100644 --- a/daemon/CapturedXML.cpp +++ b/daemon/CapturedXML.cpp | |||
@@ -33,7 +33,7 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) { | |||
33 | captured = mxmlNewElement(xml, "captured"); | 33 | captured = mxmlNewElement(xml, "captured"); |
34 | mxmlElementSetAttr(captured, "version", "1"); | 34 | mxmlElementSetAttr(captured, "version", "1"); |
35 | if (gSessionData->perf.isSetup()) { | 35 | if (gSessionData->perf.isSetup()) { |
36 | mxmlElementSetAttr(captured, "type", "Perf"); | 36 | mxmlElementSetAttr(captured, "type", "Perf"); |
37 | } | 37 | } |
38 | mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION); | 38 | mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION); |
39 | if (includeTime) { // Send the following only after the capture is complete | 39 | if (includeTime) { // Send the following only after the capture is complete |
@@ -66,10 +66,15 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) { | |||
66 | mxml_node_t *const node = mxmlNewElement(counters, "counter"); | 66 | mxml_node_t *const node = mxmlNewElement(counters, "counter"); |
67 | mxmlElementSetAttrf(node, "key", "0x%x", counter.getKey()); | 67 | mxmlElementSetAttrf(node, "key", "0x%x", counter.getKey()); |
68 | mxmlElementSetAttr(node, "type", counter.getType()); | 68 | mxmlElementSetAttr(node, "type", counter.getType()); |
69 | mxmlElementSetAttrf(node, "event", "0x%x", counter.getEvent()); | 69 | if (counter.getEvent() != -1) { |
70 | mxmlElementSetAttrf(node, "event", "0x%x", counter.getEvent()); | ||
71 | } | ||
70 | if (counter.getCount() > 0) { | 72 | if (counter.getCount() > 0) { |
71 | mxmlElementSetAttrf(node, "count", "%d", counter.getCount()); | 73 | mxmlElementSetAttrf(node, "count", "%d", counter.getCount()); |
72 | } | 74 | } |
75 | if (counter.getCores() > 0) { | ||
76 | mxmlElementSetAttrf(node, "cores", "%d", counter.getCores()); | ||
77 | } | ||
73 | } | 78 | } |
74 | } | 79 | } |
75 | 80 | ||
@@ -89,7 +94,7 @@ void CapturedXML::write(char* path) { | |||
89 | 94 | ||
90 | // Set full path | 95 | // Set full path |
91 | snprintf(file, PATH_MAX, "%s/captured.xml", path); | 96 | snprintf(file, PATH_MAX, "%s/captured.xml", path); |
92 | 97 | ||
93 | char* xml = getXML(true); | 98 | char* xml = getXML(true); |
94 | if (util->writeToDisk(file, xml) < 0) { | 99 | if (util->writeToDisk(file, xml) < 0) { |
95 | logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); | 100 | logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); |
diff --git a/daemon/CapturedXML.h b/daemon/CapturedXML.h index efc1e52..ed08c44 100644 --- a/daemon/CapturedXML.h +++ b/daemon/CapturedXML.h | |||
@@ -23,4 +23,4 @@ private: | |||
23 | 23 | ||
24 | const char * mxmlWhitespaceCB(mxml_node_t *node, int where); | 24 | const char * mxmlWhitespaceCB(mxml_node_t *node, int where); |
25 | 25 | ||
26 | #endif //__CAPTURED_XML_H__ | 26 | #endif //__CAPTURED_XML_H__ |
diff --git a/daemon/Child.cpp b/daemon/Child.cpp index ca33561..1901ecc 100644 --- a/daemon/Child.cpp +++ b/daemon/Child.cpp | |||
@@ -26,13 +26,13 @@ | |||
26 | #include "Driver.h" | 26 | #include "Driver.h" |
27 | #include "PerfSource.h" | 27 | #include "PerfSource.h" |
28 | #include "DriverSource.h" | 28 | #include "DriverSource.h" |
29 | #include "UserSpaceSource.h" | ||
30 | #include "ExternalSource.h" | 29 | #include "ExternalSource.h" |
30 | #include "UserSpaceSource.h" | ||
31 | 31 | ||
32 | static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads | 32 | static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads |
33 | static Source *primarySource = NULL; | 33 | static Source *primarySource = NULL; |
34 | static Source *userSpaceSource = NULL; | ||
35 | static Source *externalSource = NULL; | 34 | static Source *externalSource = NULL; |
35 | static Source *userSpaceSource = NULL; | ||
36 | static Sender* sender = NULL; // Shared by Child.cpp and spawned threads | 36 | static Sender* sender = NULL; // Shared by Child.cpp and spawned threads |
37 | Child* child = NULL; // shared by Child.cpp and main.cpp | 37 | Child* child = NULL; // shared by Child.cpp and main.cpp |
38 | 38 | ||
@@ -147,16 +147,16 @@ static void *senderThread(void *) { | |||
147 | prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0); | 147 | prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0); |
148 | sem_wait(&haltPipeline); | 148 | sem_wait(&haltPipeline); |
149 | 149 | ||
150 | while (!primarySource->isDone() || (userSpaceSource != NULL && !userSpaceSource->isDone()) || (externalSource != NULL && !externalSource->isDone())) { | 150 | while (!primarySource->isDone() || |
151 | !externalSource->isDone() || | ||
152 | (userSpaceSource != NULL && !userSpaceSource->isDone())) { | ||
151 | sem_wait(&senderSem); | 153 | sem_wait(&senderSem); |
152 | 154 | ||
153 | primarySource->write(sender); | 155 | primarySource->write(sender); |
156 | externalSource->write(sender); | ||
154 | if (userSpaceSource != NULL) { | 157 | if (userSpaceSource != NULL) { |
155 | userSpaceSource->write(sender); | 158 | userSpaceSource->write(sender); |
156 | } | 159 | } |
157 | if (externalSource != NULL) { | ||
158 | externalSource->write(sender); | ||
159 | } | ||
160 | } | 160 | } |
161 | 161 | ||
162 | // write end-of-capture sequence | 162 | // write end-of-capture sequence |
@@ -202,6 +202,10 @@ void Child::initialization() { | |||
202 | void Child::endSession() { | 202 | void Child::endSession() { |
203 | gSessionData->mSessionIsActive = false; | 203 | gSessionData->mSessionIsActive = false; |
204 | primarySource->interrupt(); | 204 | primarySource->interrupt(); |
205 | externalSource->interrupt(); | ||
206 | if (userSpaceSource != NULL) { | ||
207 | userSpaceSource->interrupt(); | ||
208 | } | ||
205 | sem_post(&haltPipeline); | 209 | sem_post(&haltPipeline); |
206 | } | 210 | } |
207 | 211 | ||
@@ -227,9 +231,9 @@ void Child::run() { | |||
227 | 231 | ||
228 | // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated | 232 | // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated |
229 | if (!gSessionData->perf.isSetup()) { | 233 | if (!gSessionData->perf.isSetup()) { |
230 | primarySource = new DriverSource(&senderSem, &startProfile); | 234 | primarySource = new DriverSource(&senderSem, &startProfile); |
231 | } else { | 235 | } else { |
232 | primarySource = new PerfSource(&senderSem, &startProfile); | 236 | primarySource = new PerfSource(&senderSem, &startProfile); |
233 | } | 237 | } |
234 | 238 | ||
235 | // Initialize all drivers | 239 | // Initialize all drivers |
@@ -280,11 +284,18 @@ void Child::run() { | |||
280 | thread_creation_success = false; | 284 | thread_creation_success = false; |
281 | } else if (socket && pthread_create(&stopThreadID, NULL, stopThread, NULL)) { | 285 | } else if (socket && pthread_create(&stopThreadID, NULL, stopThread, NULL)) { |
282 | thread_creation_success = false; | 286 | thread_creation_success = false; |
283 | } else if (pthread_create(&senderThreadID, NULL, senderThread, NULL)){ | 287 | } else if (pthread_create(&senderThreadID, NULL, senderThread, NULL)) { |
284 | thread_creation_success = false; | 288 | thread_creation_success = false; |
285 | } | 289 | } |
286 | 290 | ||
287 | if (gSessionData->hwmon.countersEnabled()) { | 291 | externalSource = new ExternalSource(&senderSem); |
292 | if (!externalSource->prepare()) { | ||
293 | logg->logError(__FILE__, __LINE__, "Unable to prepare for capture"); | ||
294 | handleException(); | ||
295 | } | ||
296 | externalSource->start(); | ||
297 | |||
298 | if (gSessionData->hwmon.countersEnabled() || gSessionData->fsDriver.countersEnabled()) { | ||
288 | userSpaceSource = new UserSpaceSource(&senderSem); | 299 | userSpaceSource = new UserSpaceSource(&senderSem); |
289 | if (!userSpaceSource->prepare()) { | 300 | if (!userSpaceSource->prepare()) { |
290 | logg->logError(__FILE__, __LINE__, "Unable to prepare for capture"); | 301 | logg->logError(__FILE__, __LINE__, "Unable to prepare for capture"); |
@@ -292,14 +303,6 @@ void Child::run() { | |||
292 | } | 303 | } |
293 | userSpaceSource->start(); | 304 | userSpaceSource->start(); |
294 | } | 305 | } |
295 | if (access("/tmp/gator", F_OK) == 0) { | ||
296 | externalSource = new ExternalSource(&senderSem); | ||
297 | if (!externalSource->prepare()) { | ||
298 | logg->logError(__FILE__, __LINE__, "Unable to prepare for capture"); | ||
299 | handleException(); | ||
300 | } | ||
301 | externalSource->start(); | ||
302 | } | ||
303 | 306 | ||
304 | if (!thread_creation_success) { | 307 | if (!thread_creation_success) { |
305 | logg->logError(__FILE__, __LINE__, "Failed to create gator threads"); | 308 | logg->logError(__FILE__, __LINE__, "Failed to create gator threads"); |
@@ -312,12 +315,10 @@ void Child::run() { | |||
312 | // Start profiling | 315 | // Start profiling |
313 | primarySource->run(); | 316 | primarySource->run(); |
314 | 317 | ||
315 | if (externalSource != NULL) { | ||
316 | externalSource->join(); | ||
317 | } | ||
318 | if (userSpaceSource != NULL) { | 318 | if (userSpaceSource != NULL) { |
319 | userSpaceSource->join(); | 319 | userSpaceSource->join(); |
320 | } | 320 | } |
321 | externalSource->join(); | ||
321 | 322 | ||
322 | // Wait for the other threads to exit | 323 | // Wait for the other threads to exit |
323 | pthread_join(senderThreadID, NULL); | 324 | pthread_join(senderThreadID, NULL); |
@@ -337,8 +338,8 @@ void Child::run() { | |||
337 | 338 | ||
338 | logg->logMessage("Profiling ended."); | 339 | logg->logMessage("Profiling ended."); |
339 | 340 | ||
340 | delete externalSource; | ||
341 | delete userSpaceSource; | 341 | delete userSpaceSource; |
342 | delete externalSource; | ||
342 | delete primarySource; | 343 | delete primarySource; |
343 | delete sender; | 344 | delete sender; |
344 | delete localCapture; | 345 | delete localCapture; |
diff --git a/daemon/Child.h b/daemon/Child.h index 9e206d7..a306a77 100644 --- a/daemon/Child.h +++ b/daemon/Child.h | |||
@@ -30,4 +30,4 @@ private: | |||
30 | Child &operator=(const Child &); | 30 | Child &operator=(const Child &); |
31 | }; | 31 | }; |
32 | 32 | ||
33 | #endif //__CHILD_H__ | 33 | #endif //__CHILD_H__ |
diff --git a/daemon/ConfigurationXML.cpp b/daemon/ConfigurationXML.cpp index fd479f2..6590dd3 100644 --- a/daemon/ConfigurationXML.cpp +++ b/daemon/ConfigurationXML.cpp | |||
@@ -21,12 +21,13 @@ static const char* ATTR_COUNTER = "counter"; | |||
21 | static const char* ATTR_REVISION = "revision"; | 21 | static const char* ATTR_REVISION = "revision"; |
22 | static const char* ATTR_EVENT = "event"; | 22 | static const char* ATTR_EVENT = "event"; |
23 | static const char* ATTR_COUNT = "count"; | 23 | static const char* ATTR_COUNT = "count"; |
24 | static const char* ATTR_CORES = "cores"; | ||
24 | 25 | ||
25 | ConfigurationXML::ConfigurationXML() { | 26 | ConfigurationXML::ConfigurationXML() { |
26 | const char * configuration_xml; | 27 | const char * configuration_xml; |
27 | unsigned int configuration_xml_len; | 28 | unsigned int configuration_xml_len; |
28 | getDefaultConfigurationXml(configuration_xml, configuration_xml_len); | 29 | getDefaultConfigurationXml(configuration_xml, configuration_xml_len); |
29 | 30 | ||
30 | char path[PATH_MAX]; | 31 | char path[PATH_MAX]; |
31 | 32 | ||
32 | getPath(path); | 33 | getPath(path); |
@@ -53,7 +54,7 @@ ConfigurationXML::ConfigurationXML() { | |||
53 | 54 | ||
54 | break; | 55 | break; |
55 | } | 56 | } |
56 | 57 | ||
57 | validate(); | 58 | validate(); |
58 | } | 59 | } |
59 | 60 | ||
@@ -82,7 +83,7 @@ int ConfigurationXML::parse(const char* configurationXML) { | |||
82 | node = mxmlGetFirstChild(tree); | 83 | node = mxmlGetFirstChild(tree); |
83 | while (node && mxmlGetType(node) != MXML_ELEMENT) | 84 | while (node && mxmlGetType(node) != MXML_ELEMENT) |
84 | node = mxmlWalkNext(node, tree, MXML_NO_DESCEND); | 85 | node = mxmlWalkNext(node, tree, MXML_NO_DESCEND); |
85 | 86 | ||
86 | ret = configurationsTag(node); | 87 | ret = configurationsTag(node); |
87 | 88 | ||
88 | node = mxmlGetFirstChild(node); | 89 | node = mxmlGetFirstChild(node); |
@@ -127,7 +128,7 @@ void ConfigurationXML::validate(void) { | |||
127 | #define CONFIGURATION_REVISION 3 | 128 | #define CONFIGURATION_REVISION 3 |
128 | int ConfigurationXML::configurationsTag(mxml_node_t *node) { | 129 | int ConfigurationXML::configurationsTag(mxml_node_t *node) { |
129 | const char* revision_string; | 130 | const char* revision_string; |
130 | 131 | ||
131 | revision_string = mxmlElementGetAttr(node, ATTR_REVISION); | 132 | revision_string = mxmlElementGetAttr(node, ATTR_REVISION); |
132 | if (!revision_string) { | 133 | if (!revision_string) { |
133 | return 1; //revision issue; | 134 | return 1; //revision issue; |
@@ -158,6 +159,7 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) { | |||
158 | if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER)); | 159 | if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER)); |
159 | if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16)); | 160 | if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16)); |
160 | if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10)); | 161 | if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10)); |
162 | if (mxmlElementGetAttr(node, ATTR_CORES)) counter.setCores(strtol(mxmlElementGetAttr(node, ATTR_CORES), NULL, 10)); | ||
161 | if (counter.getCount() > 0) { | 163 | if (counter.getCount() > 0) { |
162 | gSessionData->mIsEBS = true; | 164 | gSessionData->mIsEBS = true; |
163 | } | 165 | } |
diff --git a/daemon/Counter.h b/daemon/Counter.h index 6891745..5202aa0 100644 --- a/daemon/Counter.h +++ b/daemon/Counter.h | |||
@@ -27,6 +27,7 @@ public: | |||
27 | mEnabled = false; | 27 | mEnabled = false; |
28 | mEvent = -1; | 28 | mEvent = -1; |
29 | mCount = 0; | 29 | mCount = 0; |
30 | mCores = -1; | ||
30 | mKey = 0; | 31 | mKey = 0; |
31 | mDriver = NULL; | 32 | mDriver = NULL; |
32 | } | 33 | } |
@@ -35,6 +36,7 @@ public: | |||
35 | void setEnabled(const bool enabled) { mEnabled = enabled; } | 36 | void setEnabled(const bool enabled) { mEnabled = enabled; } |
36 | void setEvent(const int event) { mEvent = event; } | 37 | void setEvent(const int event) { mEvent = event; } |
37 | void setCount(const int count) { mCount = count; } | 38 | void setCount(const int count) { mCount = count; } |
39 | void setCores(const int cores) { mCores = cores; } | ||
38 | void setKey(const int key) { mKey = key; } | 40 | void setKey(const int key) { mKey = key; } |
39 | void setDriver(Driver *const driver) { mDriver = driver; } | 41 | void setDriver(Driver *const driver) { mDriver = driver; } |
40 | 42 | ||
@@ -42,6 +44,7 @@ public: | |||
42 | bool isEnabled() const { return mEnabled; } | 44 | bool isEnabled() const { return mEnabled; } |
43 | int getEvent() const { return mEvent; } | 45 | int getEvent() const { return mEvent; } |
44 | int getCount() const { return mCount; } | 46 | int getCount() const { return mCount; } |
47 | int getCores() const { return mCores; } | ||
45 | int getKey() const { return mKey; } | 48 | int getKey() const { return mKey; } |
46 | Driver *getDriver() const { return mDriver; } | 49 | Driver *getDriver() const { return mDriver; } |
47 | 50 | ||
@@ -54,6 +57,7 @@ private: | |||
54 | bool mEnabled; | 57 | bool mEnabled; |
55 | int mEvent; | 58 | int mEvent; |
56 | int mCount; | 59 | int mCount; |
60 | int mCores; | ||
57 | int mKey; | 61 | int mKey; |
58 | Driver *mDriver; | 62 | Driver *mDriver; |
59 | }; | 63 | }; |
diff --git a/daemon/DriverSource.cpp b/daemon/DriverSource.cpp index f78ec6b..11d3095 100644 --- a/daemon/DriverSource.cpp +++ b/daemon/DriverSource.cpp | |||
@@ -12,19 +12,24 @@ | |||
12 | 12 | ||
13 | #include <fcntl.h> | 13 | #include <fcntl.h> |
14 | #include <inttypes.h> | 14 | #include <inttypes.h> |
15 | #include <sys/prctl.h> | ||
15 | #include <unistd.h> | 16 | #include <unistd.h> |
16 | 17 | ||
18 | #include "Buffer.h" | ||
17 | #include "Child.h" | 19 | #include "Child.h" |
20 | #include "DynBuf.h" | ||
18 | #include "Fifo.h" | 21 | #include "Fifo.h" |
19 | #include "Logging.h" | 22 | #include "Logging.h" |
23 | #include "Proc.h" | ||
20 | #include "Sender.h" | 24 | #include "Sender.h" |
21 | #include "SessionData.h" | 25 | #include "SessionData.h" |
22 | 26 | ||
23 | extern Child *child; | 27 | extern Child *child; |
24 | 28 | ||
25 | DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) { | 29 | DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL), mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) { |
26 | int driver_version = 0; | 30 | int driver_version = 0; |
27 | 31 | ||
32 | mBuffer = new Buffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem); | ||
28 | if (readIntDriver("/dev/gator/version", &driver_version) == -1) { | 33 | if (readIntDriver("/dev/gator/version", &driver_version) == -1) { |
29 | logg->logError(__FILE__, __LINE__, "Error reading gator driver version"); | 34 | logg->logError(__FILE__, __LINE__, "Error reading gator driver version"); |
30 | handleException(); | 35 | handleException(); |
@@ -43,7 +48,7 @@ DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mFifo(NULL), | |||
43 | handleException(); | 48 | handleException(); |
44 | } else { | 49 | } else { |
45 | // Release version mismatch | 50 | // Release version mismatch |
46 | logg->logError(__FILE__, __LINE__, | 51 | logg->logError(__FILE__, __LINE__, |
47 | "gator driver version \"%d\" is different than gator daemon version \"%d\".\n" | 52 | "gator driver version \"%d\" is different than gator daemon version \"%d\".\n" |
48 | ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION); | 53 | ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION); |
49 | handleException(); | 54 | handleException(); |
@@ -87,6 +92,28 @@ bool DriverSource::prepare() { | |||
87 | return true; | 92 | return true; |
88 | } | 93 | } |
89 | 94 | ||
95 | void DriverSource::bootstrapThread() { | ||
96 | prctl(PR_SET_NAME, (unsigned long)&"gatord-bootstrap", 0, 0, 0); | ||
97 | |||
98 | DynBuf printb; | ||
99 | DynBuf b1; | ||
100 | DynBuf b2; | ||
101 | DynBuf b3; | ||
102 | |||
103 | if (!readProc(mBuffer, false, &printb, &b1, &b2, &b3)) { | ||
104 | logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__); | ||
105 | handleException(); | ||
106 | } | ||
107 | |||
108 | mBuffer->commit(1); | ||
109 | mBuffer->setDone(); | ||
110 | } | ||
111 | |||
112 | void *DriverSource::bootstrapThreadStatic(void *arg) { | ||
113 | static_cast<DriverSource *>(arg)->bootstrapThread(); | ||
114 | return NULL; | ||
115 | } | ||
116 | |||
90 | void DriverSource::run() { | 117 | void DriverSource::run() { |
91 | // Get the initial pointer to the collect buffer | 118 | // Get the initial pointer to the collect buffer |
92 | char *collectBuffer = mFifo->start(); | 119 | char *collectBuffer = mFifo->start(); |
@@ -138,6 +165,12 @@ void DriverSource::run() { | |||
138 | 165 | ||
139 | sem_post(mStartProfile); | 166 | sem_post(mStartProfile); |
140 | 167 | ||
168 | pthread_t bootstrapThreadID; | ||
169 | if (pthread_create(&bootstrapThreadID, NULL, bootstrapThreadStatic, this) != 0) { | ||
170 | logg->logError(__FILE__, __LINE__, "Unable to start the gator_bootstrap thread"); | ||
171 | handleException(); | ||
172 | } | ||
173 | |||
141 | // Collect Data | 174 | // Collect Data |
142 | do { | 175 | do { |
143 | // This command will stall until data is received from the driver | 176 | // This command will stall until data is received from the driver |
@@ -164,6 +197,8 @@ void DriverSource::run() { | |||
164 | } while (bytesCollected > 0); | 197 | } while (bytesCollected > 0); |
165 | 198 | ||
166 | logg->logMessage("Exit collect data loop"); | 199 | logg->logMessage("Exit collect data loop"); |
200 | |||
201 | pthread_join(bootstrapThreadID, NULL); | ||
167 | } | 202 | } |
168 | 203 | ||
169 | void DriverSource::interrupt() { | 204 | void DriverSource::interrupt() { |
@@ -174,7 +209,7 @@ void DriverSource::interrupt() { | |||
174 | } | 209 | } |
175 | 210 | ||
176 | bool DriverSource::isDone() { | 211 | bool DriverSource::isDone() { |
177 | return mLength <= 0; | 212 | return mLength <= 0 && (mBuffer == NULL || mBuffer->isDone()); |
178 | } | 213 | } |
179 | 214 | ||
180 | void DriverSource::write(Sender *sender) { | 215 | void DriverSource::write(Sender *sender) { |
@@ -182,6 +217,16 @@ void DriverSource::write(Sender *sender) { | |||
182 | if (data != NULL) { | 217 | if (data != NULL) { |
183 | sender->writeData(data, mLength, RESPONSE_APC_DATA); | 218 | sender->writeData(data, mLength, RESPONSE_APC_DATA); |
184 | mFifo->release(); | 219 | mFifo->release(); |
220 | // Assume the summary packet is in the first block received from the driver | ||
221 | gSessionData->mSentSummary = true; | ||
222 | } | ||
223 | if (mBuffer != NULL && !mBuffer->isDone()) { | ||
224 | mBuffer->write(sender); | ||
225 | if (mBuffer->isDone()) { | ||
226 | Buffer *buf = mBuffer; | ||
227 | mBuffer = NULL; | ||
228 | delete buf; | ||
229 | } | ||
185 | } | 230 | } |
186 | } | 231 | } |
187 | 232 | ||
@@ -227,7 +272,7 @@ int DriverSource::readInt64Driver(const char *fullpath, int64_t *value) { | |||
227 | char *endptr; | 272 | char *endptr; |
228 | errno = 0; | 273 | errno = 0; |
229 | *value = strtoll(data, &endptr, 10); | 274 | *value = strtoll(data, &endptr, 10); |
230 | if (errno != 0 || *endptr != '\n') { | 275 | if (errno != 0 || (*endptr != '\n' && *endptr != '\0')) { |
231 | logg->logMessage("Invalid value in file %s", fullpath); | 276 | logg->logMessage("Invalid value in file %s", fullpath); |
232 | return -1; | 277 | return -1; |
233 | } | 278 | } |
diff --git a/daemon/DriverSource.h b/daemon/DriverSource.h index dcf1078..ec27b08 100644 --- a/daemon/DriverSource.h +++ b/daemon/DriverSource.h | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | #include "Source.h" | 15 | #include "Source.h" |
16 | 16 | ||
17 | class Buffer; | ||
17 | class Fifo; | 18 | class Fifo; |
18 | 19 | ||
19 | class DriverSource : public Source { | 20 | class DriverSource : public Source { |
@@ -37,6 +38,10 @@ public: | |||
37 | static int writeReadDriver(const char *path, int64_t *value); | 38 | static int writeReadDriver(const char *path, int64_t *value); |
38 | 39 | ||
39 | private: | 40 | private: |
41 | static void *bootstrapThreadStatic(void *arg); | ||
42 | void bootstrapThread(); | ||
43 | |||
44 | Buffer *mBuffer; | ||
40 | Fifo *mFifo; | 45 | Fifo *mFifo; |
41 | sem_t *const mSenderSem; | 46 | sem_t *const mSenderSem; |
42 | sem_t *const mStartProfile; | 47 | sem_t *const mStartProfile; |
diff --git a/daemon/EventsXML.cpp b/daemon/EventsXML.cpp index a07a046..cf0192e 100644 --- a/daemon/EventsXML.cpp +++ b/daemon/EventsXML.cpp | |||
@@ -13,7 +13,7 @@ | |||
13 | #include "OlyUtility.h" | 13 | #include "OlyUtility.h" |
14 | #include "SessionData.h" | 14 | #include "SessionData.h" |
15 | 15 | ||
16 | char* EventsXML::getXML() { | 16 | mxml_node_t *EventsXML::getTree() { |
17 | #include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len | 17 | #include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len |
18 | char path[PATH_MAX]; | 18 | char path[PATH_MAX]; |
19 | mxml_node_t *xml; | 19 | mxml_node_t *xml; |
@@ -38,6 +38,12 @@ char* EventsXML::getXML() { | |||
38 | xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK); | 38 | xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK); |
39 | } | 39 | } |
40 | 40 | ||
41 | return xml; | ||
42 | } | ||
43 | |||
44 | char *EventsXML::getXML() { | ||
45 | mxml_node_t *xml = getTree(); | ||
46 | |||
41 | // Add dynamic events from the drivers | 47 | // Add dynamic events from the drivers |
42 | mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND); | 48 | mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND); |
43 | if (!events) { | 49 | if (!events) { |
@@ -48,19 +54,19 @@ char* EventsXML::getXML() { | |||
48 | driver->writeEvents(events); | 54 | driver->writeEvents(events); |
49 | } | 55 | } |
50 | 56 | ||
51 | char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB); | 57 | char *string = mxmlSaveAllocString(xml, mxmlWhitespaceCB); |
52 | mxmlDelete(xml); | 58 | mxmlDelete(xml); |
53 | 59 | ||
54 | return string; | 60 | return string; |
55 | } | 61 | } |
56 | 62 | ||
57 | void EventsXML::write(const char* path) { | 63 | void EventsXML::write(const char *path) { |
58 | char file[PATH_MAX]; | 64 | char file[PATH_MAX]; |
59 | 65 | ||
60 | // Set full path | 66 | // Set full path |
61 | snprintf(file, PATH_MAX, "%s/events.xml", path); | 67 | snprintf(file, PATH_MAX, "%s/events.xml", path); |
62 | 68 | ||
63 | char* buf = getXML(); | 69 | char *buf = getXML(); |
64 | if (util->writeToDisk(file, buf) < 0) { | 70 | if (util->writeToDisk(file, buf) < 0) { |
65 | logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); | 71 | logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); |
66 | handleException(); | 72 | handleException(); |
diff --git a/daemon/EventsXML.h b/daemon/EventsXML.h index 6cd1560..ff7a02f 100644 --- a/daemon/EventsXML.h +++ b/daemon/EventsXML.h | |||
@@ -9,9 +9,12 @@ | |||
9 | #ifndef EVENTS_XML | 9 | #ifndef EVENTS_XML |
10 | #define EVENTS_XML | 10 | #define EVENTS_XML |
11 | 11 | ||
12 | #include "mxml/mxml.h" | ||
13 | |||
12 | class EventsXML { | 14 | class EventsXML { |
13 | public: | 15 | public: |
14 | char* getXML(); | 16 | mxml_node_t *getTree(); |
17 | char *getXML(); | ||
15 | void write(const char* path); | 18 | void write(const char* path); |
16 | }; | 19 | }; |
17 | 20 | ||
diff --git a/daemon/ExternalSource.cpp b/daemon/ExternalSource.cpp index fe5824b..b6ec301 100644 --- a/daemon/ExternalSource.cpp +++ b/daemon/ExternalSource.cpp | |||
@@ -8,41 +8,195 @@ | |||
8 | 8 | ||
9 | #include "ExternalSource.h" | 9 | #include "ExternalSource.h" |
10 | 10 | ||
11 | #include <fcntl.h> | ||
11 | #include <sys/prctl.h> | 12 | #include <sys/prctl.h> |
13 | #include <unistd.h> | ||
12 | 14 | ||
13 | #include "Logging.h" | 15 | #include "Logging.h" |
14 | #include "OlySocket.h" | 16 | #include "OlySocket.h" |
15 | #include "SessionData.h" | 17 | #include "SessionData.h" |
16 | 18 | ||
17 | ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 1024, senderSem), mSock("/tmp/gator") { | 19 | static const char MALI_VIDEO[] = "\0mali-video"; |
20 | static const char MALI_VIDEO_STARTUP[] = "\0mali-video-startup"; | ||
21 | static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n"; | ||
22 | |||
23 | static bool setNonblock(const int fd) { | ||
24 | int flags; | ||
25 | |||
26 | flags = fcntl(fd, F_GETFL); | ||
27 | if (flags < 0) { | ||
28 | logg->logMessage("fcntl getfl failed"); | ||
29 | return false; | ||
30 | } | ||
31 | |||
32 | if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) { | ||
33 | logg->logMessage("fcntl setfl failed"); | ||
34 | return false; | ||
35 | } | ||
36 | |||
37 | return true; | ||
38 | } | ||
39 | |||
40 | ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mInterruptFd(-1), mMveUds(-1) { | ||
41 | sem_init(&mBufferSem, 0, 0); | ||
18 | } | 42 | } |
19 | 43 | ||
20 | ExternalSource::~ExternalSource() { | 44 | ExternalSource::~ExternalSource() { |
21 | } | 45 | } |
22 | 46 | ||
47 | void ExternalSource::waitFor(const uint64_t currTime, const int bytes) { | ||
48 | while (mBuffer.bytesAvailable() <= bytes) { | ||
49 | mBuffer.check(currTime); | ||
50 | sem_wait(&mBufferSem); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | void ExternalSource::configureConnection(const int fd, const char *const handshake, size_t size) { | ||
55 | if (!setNonblock(fd)) { | ||
56 | logg->logError(__FILE__, __LINE__, "Unable to set nonblock on fh"); | ||
57 | handleException(); | ||
58 | } | ||
59 | |||
60 | if (!mMonitor.add(fd)) { | ||
61 | logg->logError(__FILE__, __LINE__, "Unable to add fh to monitor"); | ||
62 | handleException(); | ||
63 | } | ||
64 | |||
65 | // Write the handshake to the circular buffer | ||
66 | waitFor(1, Buffer::MAXSIZE_PACK32 + 4 + size - 1); | ||
67 | mBuffer.packInt(fd); | ||
68 | mBuffer.writeLEInt((unsigned char *)mBuffer.getWritePos(), size - 1); | ||
69 | mBuffer.advanceWrite(4); | ||
70 | mBuffer.writeBytes(handshake, size - 1); | ||
71 | } | ||
72 | |||
73 | bool ExternalSource::connectMve() { | ||
74 | if (!gSessionData->maliVideo.countersEnabled()) { | ||
75 | return true; | ||
76 | } | ||
77 | |||
78 | mMveUds = OlySocket::connect(MALI_VIDEO, sizeof(MALI_VIDEO)); | ||
79 | if (mMveUds < 0) { | ||
80 | return false; | ||
81 | } | ||
82 | |||
83 | if (!gSessionData->maliVideo.start(mMveUds)) { | ||
84 | return false; | ||
85 | } | ||
86 | |||
87 | configureConnection(mMveUds, MALI_VIDEO_V1, sizeof(MALI_VIDEO_V1)); | ||
88 | |||
89 | return true; | ||
90 | } | ||
91 | |||
23 | bool ExternalSource::prepare() { | 92 | bool ExternalSource::prepare() { |
93 | if (!mMonitor.init() || !setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd())) { | ||
94 | return false; | ||
95 | } | ||
96 | |||
97 | connectMve(); | ||
98 | |||
24 | return true; | 99 | return true; |
25 | } | 100 | } |
26 | 101 | ||
27 | void ExternalSource::run() { | 102 | void ExternalSource::run() { |
28 | prctl(PR_SET_NAME, (unsigned long)&"gatord-uds", 0, 0, 0); | 103 | int pipefd[2]; |
104 | |||
105 | prctl(PR_SET_NAME, (unsigned long)&"gatord-external", 0, 0, 0); | ||
106 | |||
107 | if (pipe(pipefd) != 0) { | ||
108 | logg->logError(__FILE__, __LINE__, "pipe failed"); | ||
109 | handleException(); | ||
110 | } | ||
111 | mInterruptFd = pipefd[1]; | ||
112 | |||
113 | if (!mMonitor.add(pipefd[0])) { | ||
114 | logg->logError(__FILE__, __LINE__, "Monitor::add failed"); | ||
115 | handleException(); | ||
116 | } | ||
29 | 117 | ||
30 | while (gSessionData->mSessionIsActive) { | 118 | while (gSessionData->mSessionIsActive) { |
31 | // Will be aborted when the socket is closed at the end of the capture | 119 | struct epoll_event events[16]; |
32 | int length = mSock.receive(mBuffer.getWritePos(), mBuffer.contiguousSpaceAvailable()); | 120 | // Clear any pending sem posts |
33 | if (length <= 0) { | 121 | while (sem_trywait(&mBufferSem) == 0); |
34 | break; | 122 | int ready = mMonitor.wait(events, ARRAY_LENGTH(events), -1); |
123 | if (ready < 0) { | ||
124 | logg->logError(__FILE__, __LINE__, "Monitor::wait failed"); | ||
125 | handleException(); | ||
35 | } | 126 | } |
36 | 127 | ||
37 | mBuffer.advanceWrite(length); | 128 | const uint64_t currTime = getTime(); |
38 | mBuffer.check(0); | 129 | |
130 | for (int i = 0; i < ready; ++i) { | ||
131 | const int fd = events[i].data.fd; | ||
132 | if (fd == mMveStartupUds.getFd()) { | ||
133 | // Mali Video Engine says it's alive | ||
134 | int client = mMveStartupUds.acceptConnection(); | ||
135 | // Don't read from this connection, establish a new connection to Mali-V500 | ||
136 | close(client); | ||
137 | if (!connectMve()) { | ||
138 | logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali video connection"); | ||
139 | handleException(); | ||
140 | } | ||
141 | } else if (fd == pipefd[0]) { | ||
142 | // Means interrupt has been called and mSessionIsActive should be reread | ||
143 | } else { | ||
144 | while (true) { | ||
145 | waitFor(currTime, Buffer::MAXSIZE_PACK32 + 4); | ||
146 | |||
147 | mBuffer.packInt(fd); | ||
148 | char *const bytesPos = mBuffer.getWritePos(); | ||
149 | mBuffer.advanceWrite(4); | ||
150 | const int contiguous = mBuffer.contiguousSpaceAvailable(); | ||
151 | const int bytes = read(fd, mBuffer.getWritePos(), contiguous); | ||
152 | if (bytes < 0) { | ||
153 | if (errno == EAGAIN) { | ||
154 | // Nothing left to read, and Buffer convention dictates that writePos can't go backwards | ||
155 | mBuffer.writeLEInt((unsigned char *)bytesPos, 0); | ||
156 | break; | ||
157 | } | ||
158 | // Something else failed, close the socket | ||
159 | mBuffer.writeLEInt((unsigned char *)bytesPos, -1); | ||
160 | close(fd); | ||
161 | break; | ||
162 | } else if (bytes == 0) { | ||
163 | // The other side is closed | ||
164 | mBuffer.writeLEInt((unsigned char *)bytesPos, -1); | ||
165 | close(fd); | ||
166 | break; | ||
167 | } | ||
168 | |||
169 | mBuffer.writeLEInt((unsigned char *)bytesPos, bytes); | ||
170 | mBuffer.advanceWrite(bytes); | ||
171 | |||
172 | // Short reads also mean nothing is left to read | ||
173 | if (bytes < contiguous) { | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | // Only call mBufferCheck once per iteration | ||
181 | mBuffer.check(currTime); | ||
39 | } | 182 | } |
40 | 183 | ||
41 | mBuffer.setDone(); | 184 | mBuffer.setDone(); |
185 | |||
186 | mInterruptFd = -1; | ||
187 | close(pipefd[0]); | ||
188 | close(pipefd[1]); | ||
42 | } | 189 | } |
43 | 190 | ||
44 | void ExternalSource::interrupt() { | 191 | void ExternalSource::interrupt() { |
45 | // Do nothing | 192 | if (mInterruptFd >= 0) { |
193 | int8_t c = 0; | ||
194 | // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread | ||
195 | if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) { | ||
196 | logg->logError(__FILE__, __LINE__, "write failed"); | ||
197 | handleException(); | ||
198 | } | ||
199 | } | ||
46 | } | 200 | } |
47 | 201 | ||
48 | bool ExternalSource::isDone() { | 202 | bool ExternalSource::isDone() { |
@@ -50,7 +204,12 @@ bool ExternalSource::isDone() { | |||
50 | } | 204 | } |
51 | 205 | ||
52 | void ExternalSource::write(Sender *sender) { | 206 | void ExternalSource::write(Sender *sender) { |
207 | // Don't send external data until the summary packet is sent so that monotonic delta is available | ||
208 | if (!gSessionData->mSentSummary) { | ||
209 | return; | ||
210 | } | ||
53 | if (!mBuffer.isDone()) { | 211 | if (!mBuffer.isDone()) { |
54 | mBuffer.write(sender); | 212 | mBuffer.write(sender); |
213 | sem_post(&mBufferSem); | ||
55 | } | 214 | } |
56 | } | 215 | } |
diff --git a/daemon/ExternalSource.h b/daemon/ExternalSource.h index 2052bdf..2e7ed27 100644 --- a/daemon/ExternalSource.h +++ b/daemon/ExternalSource.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <semaphore.h> | 12 | #include <semaphore.h> |
13 | 13 | ||
14 | #include "Buffer.h" | 14 | #include "Buffer.h" |
15 | #include "Monitor.h" | ||
15 | #include "OlySocket.h" | 16 | #include "OlySocket.h" |
16 | #include "Source.h" | 17 | #include "Source.h" |
17 | 18 | ||
@@ -29,8 +30,16 @@ public: | |||
29 | void write(Sender *sender); | 30 | void write(Sender *sender); |
30 | 31 | ||
31 | private: | 32 | private: |
33 | void waitFor(const uint64_t currTime, const int bytes); | ||
34 | void configureConnection(const int fd, const char *const handshake, size_t size); | ||
35 | bool connectMve(); | ||
36 | |||
37 | sem_t mBufferSem; | ||
32 | Buffer mBuffer; | 38 | Buffer mBuffer; |
33 | OlySocket mSock; | 39 | Monitor mMonitor; |
40 | OlyServerSocket mMveStartupUds; | ||
41 | int mInterruptFd; | ||
42 | int mMveUds; | ||
34 | 43 | ||
35 | // Intentionally unimplemented | 44 | // Intentionally unimplemented |
36 | ExternalSource(const ExternalSource &); | 45 | ExternalSource(const ExternalSource &); |
diff --git a/daemon/FSDriver.cpp b/daemon/FSDriver.cpp new file mode 100644 index 0000000..40c8df1 --- /dev/null +++ b/daemon/FSDriver.cpp | |||
@@ -0,0 +1,212 @@ | |||
1 | /** | ||
2 | * Copyright (C) ARM Limited 2014. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include "FSDriver.h" | ||
10 | |||
11 | #include <fcntl.h> | ||
12 | #include <regex.h> | ||
13 | #include <sys/stat.h> | ||
14 | #include <sys/types.h> | ||
15 | #include <unistd.h> | ||
16 | |||
17 | #include "Buffer.h" | ||
18 | #include "Counter.h" | ||
19 | #include "DriverSource.h" | ||
20 | #include "Logging.h" | ||
21 | #include "SessionData.h" | ||
22 | |||
23 | class FSCounter { | ||
24 | public: | ||
25 | FSCounter(FSCounter *next, char *name, const char *regex); | ||
26 | ~FSCounter(); | ||
27 | |||
28 | FSCounter *getNext() const { return next; } | ||
29 | int getKey() const { return key; } | ||
30 | bool isEnabled() const { return enabled; } | ||
31 | void setEnabled(const bool enabled) { this->enabled = enabled; } | ||
32 | const char *getName() const { return name; } | ||
33 | int64_t read(); | ||
34 | |||
35 | private: | ||
36 | FSCounter *const next; | ||
37 | regex_t reg; | ||
38 | char *name; | ||
39 | const int key; | ||
40 | int enabled : 1, | ||
41 | useRegex : 1; | ||
42 | |||
43 | // Intentionally unimplemented | ||
44 | FSCounter(const FSCounter &); | ||
45 | FSCounter &operator=(const FSCounter &); | ||
46 | }; | ||
47 | |||
48 | FSCounter::FSCounter(FSCounter *next, char *name, const char *regex) : next(next), name(name), key(getEventKey()), enabled(false), useRegex(regex != NULL) { | ||
49 | if (useRegex) { | ||
50 | int result = regcomp(®, regex, REG_EXTENDED); | ||
51 | if (result != 0) { | ||
52 | char buf[128]; | ||
53 | regerror(result, ®, buf, sizeof(buf)); | ||
54 | logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf); | ||
55 | handleException(); | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | |||
60 | FSCounter::~FSCounter() { | ||
61 | free(name); | ||
62 | if (useRegex) { | ||
63 | regfree(®); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | int64_t FSCounter::read() { | ||
68 | int64_t value; | ||
69 | if (useRegex) { | ||
70 | char buf[4096]; | ||
71 | size_t pos = 0; | ||
72 | const int fd = open(name, O_RDONLY); | ||
73 | if (fd < 0) { | ||
74 | goto fail; | ||
75 | } | ||
76 | while (pos < sizeof(buf) - 1) { | ||
77 | const ssize_t bytes = ::read(fd, buf + pos, sizeof(buf) - pos - 1); | ||
78 | if (bytes < 0) { | ||
79 | goto fail; | ||
80 | } else if (bytes == 0) { | ||
81 | break; | ||
82 | } | ||
83 | pos += bytes; | ||
84 | } | ||
85 | close(fd); | ||
86 | buf[pos] = '\0'; | ||
87 | |||
88 | regmatch_t match[2]; | ||
89 | int result = regexec(®, buf, 2, match, 0); | ||
90 | if (result != 0) { | ||
91 | regerror(result, ®, buf, sizeof(buf)); | ||
92 | logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", name, buf); | ||
93 | handleException(); | ||
94 | } | ||
95 | |||
96 | if (match[1].rm_so < 0) { | ||
97 | logg->logError(__FILE__, __LINE__, "Parsing %s failed", name); | ||
98 | handleException(); | ||
99 | } | ||
100 | char *endptr; | ||
101 | errno = 0; | ||
102 | value = strtoll(buf + match[1].rm_so, &endptr, 0); | ||
103 | if (errno != 0) { | ||
104 | logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", name, strerror(errno)); | ||
105 | handleException(); | ||
106 | } | ||
107 | } else { | ||
108 | if (DriverSource::readInt64Driver(name, &value) != 0) { | ||
109 | goto fail; | ||
110 | } | ||
111 | } | ||
112 | return value; | ||
113 | |||
114 | fail: | ||
115 | logg->logError(__FILE__, __LINE__, "Unable to read %s", name); | ||
116 | handleException(); | ||
117 | } | ||
118 | |||
119 | FSDriver::FSDriver() : counters(NULL) { | ||
120 | } | ||
121 | |||
122 | FSDriver::~FSDriver() { | ||
123 | while (counters != NULL) { | ||
124 | FSCounter * counter = counters; | ||
125 | counters = counter->getNext(); | ||
126 | delete counter; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | void FSDriver::setup(mxml_node_t *const xml) { | ||
131 | // fs driver does not currently work with perf | ||
132 | if (gSessionData->perf.isSetup()) { | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | mxml_node_t *node = xml; | ||
137 | while (true) { | ||
138 | node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND); | ||
139 | if (node == NULL) { | ||
140 | break; | ||
141 | } | ||
142 | const char *counter = mxmlElementGetAttr(node, "counter"); | ||
143 | if ((counter != NULL) && (counter[0] == '/')) { | ||
144 | const char *regex = mxmlElementGetAttr(node, "regex"); | ||
145 | counters = new FSCounter(counters, strdup(counter), regex); | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | FSCounter *FSDriver::findCounter(const Counter &counter) const { | ||
151 | for (FSCounter * fsCounter = counters; fsCounter != NULL; fsCounter = fsCounter->getNext()) { | ||
152 | if (strcmp(fsCounter->getName(), counter.getType()) == 0) { | ||
153 | return fsCounter; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | bool FSDriver::claimCounter(const Counter &counter) const { | ||
161 | return findCounter(counter) != NULL; | ||
162 | } | ||
163 | |||
164 | bool FSDriver::countersEnabled() const { | ||
165 | for (FSCounter *counter = counters; counter != NULL; counter = counter->getNext()) { | ||
166 | if (counter->isEnabled()) { | ||
167 | return true; | ||
168 | } | ||
169 | } | ||
170 | return false; | ||
171 | } | ||
172 | |||
173 | void FSDriver::resetCounters() { | ||
174 | for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) { | ||
175 | counter->setEnabled(false); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | void FSDriver::setupCounter(Counter &counter) { | ||
180 | FSCounter *const fsCounter = findCounter(counter); | ||
181 | if (fsCounter == NULL) { | ||
182 | counter.setEnabled(false); | ||
183 | return; | ||
184 | } | ||
185 | fsCounter->setEnabled(true); | ||
186 | counter.setKey(fsCounter->getKey()); | ||
187 | } | ||
188 | |||
189 | int FSDriver::writeCounters(mxml_node_t *root) const { | ||
190 | int count = 0; | ||
191 | for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) { | ||
192 | if (access(counter->getName(), R_OK) == 0) { | ||
193 | mxml_node_t *node = mxmlNewElement(root, "counter"); | ||
194 | mxmlElementSetAttr(node, "name", counter->getName()); | ||
195 | ++count; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | return count; | ||
200 | } | ||
201 | |||
202 | void FSDriver::start() { | ||
203 | } | ||
204 | |||
205 | void FSDriver::read(Buffer * const buffer) { | ||
206 | for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) { | ||
207 | if (!counter->isEnabled()) { | ||
208 | continue; | ||
209 | } | ||
210 | buffer->event(counter->getKey(), counter->read()); | ||
211 | } | ||
212 | } | ||
diff --git a/daemon/FSDriver.h b/daemon/FSDriver.h new file mode 100644 index 0000000..ef39553 --- /dev/null +++ b/daemon/FSDriver.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /** | ||
2 | * Copyright (C) ARM Limited 2014. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef FSDRIVER_H | ||
10 | #define FSDRIVER_H | ||
11 | |||
12 | #include "Driver.h" | ||
13 | |||
14 | class Buffer; | ||
15 | class FSCounter; | ||
16 | |||
17 | class FSDriver : public Driver { | ||
18 | public: | ||
19 | FSDriver(); | ||
20 | ~FSDriver(); | ||
21 | |||
22 | void setup(mxml_node_t *const xml); | ||
23 | |||
24 | bool claimCounter(const Counter &counter) const; | ||
25 | bool countersEnabled() const; | ||
26 | void resetCounters(); | ||
27 | void setupCounter(Counter &counter); | ||
28 | |||
29 | int writeCounters(mxml_node_t *root) const; | ||
30 | |||
31 | void start(); | ||
32 | void read(Buffer * buffer); | ||
33 | |||
34 | private: | ||
35 | FSCounter *findCounter(const Counter &counter) const; | ||
36 | |||
37 | FSCounter *counters; | ||
38 | |||
39 | // Intentionally unimplemented | ||
40 | FSDriver(const FSDriver &); | ||
41 | FSDriver &operator=(const FSDriver &); | ||
42 | }; | ||
43 | |||
44 | #endif // FSDRIVER_H | ||
diff --git a/daemon/Fifo.h b/daemon/Fifo.h index 7dd7426..bdda3f5 100644 --- a/daemon/Fifo.h +++ b/daemon/Fifo.h | |||
@@ -45,4 +45,4 @@ private: | |||
45 | Fifo &operator=(const Fifo &); | 45 | Fifo &operator=(const Fifo &); |
46 | }; | 46 | }; |
47 | 47 | ||
48 | #endif //__FIFO_H__ | 48 | #endif //__FIFO_H__ |
diff --git a/daemon/Hwmon.cpp b/daemon/Hwmon.cpp index 778f307..e444247 100644 --- a/daemon/Hwmon.cpp +++ b/daemon/Hwmon.cpp | |||
@@ -28,6 +28,7 @@ public: | |||
28 | const char *getTitle() const { return title; } | 28 | const char *getTitle() const { return title; } |
29 | bool isDuplicate() const { return duplicate; } | 29 | bool isDuplicate() const { return duplicate; } |
30 | const char *getDisplay() const { return display; } | 30 | const char *getDisplay() const { return display; } |
31 | const char *getCounterClass() const { return counter_class; } | ||
31 | const char *getUnit() const { return unit; } | 32 | const char *getUnit() const { return unit; } |
32 | int getModifier() const { return modifier; } | 33 | int getModifier() const { return modifier; } |
33 | 34 | ||
@@ -58,6 +59,7 @@ private: | |||
58 | char *label; | 59 | char *label; |
59 | const char *title; | 60 | const char *title; |
60 | const char *display; | 61 | const char *display; |
62 | const char *counter_class; | ||
61 | const char *unit; | 63 | const char *unit; |
62 | int modifier; | 64 | int modifier; |
63 | double previous_value; | 65 | double previous_value; |
@@ -87,7 +89,8 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co | |||
87 | case SENSORS_FEATURE_IN: | 89 | case SENSORS_FEATURE_IN: |
88 | title = "Voltage"; | 90 | title = "Voltage"; |
89 | input = SENSORS_SUBFEATURE_IN_INPUT; | 91 | input = SENSORS_SUBFEATURE_IN_INPUT; |
90 | display = "average"; | 92 | display = "maximum"; |
93 | counter_class = "absolute"; | ||
91 | unit = "V"; | 94 | unit = "V"; |
92 | modifier = 1000; | 95 | modifier = 1000; |
93 | monotonic = false; | 96 | monotonic = false; |
@@ -96,6 +99,7 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co | |||
96 | title = "Fan"; | 99 | title = "Fan"; |
97 | input = SENSORS_SUBFEATURE_FAN_INPUT; | 100 | input = SENSORS_SUBFEATURE_FAN_INPUT; |
98 | display = "average"; | 101 | display = "average"; |
102 | counter_class = "absolute"; | ||
99 | unit = "RPM"; | 103 | unit = "RPM"; |
100 | modifier = 1; | 104 | modifier = 1; |
101 | monotonic = false; | 105 | monotonic = false; |
@@ -104,6 +108,7 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co | |||
104 | title = "Temperature"; | 108 | title = "Temperature"; |
105 | input = SENSORS_SUBFEATURE_TEMP_INPUT; | 109 | input = SENSORS_SUBFEATURE_TEMP_INPUT; |
106 | display = "maximum"; | 110 | display = "maximum"; |
111 | counter_class = "absolute"; | ||
107 | unit = "°C"; | 112 | unit = "°C"; |
108 | modifier = 1000; | 113 | modifier = 1000; |
109 | monotonic = false; | 114 | monotonic = false; |
@@ -111,7 +116,8 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co | |||
111 | case SENSORS_FEATURE_POWER: | 116 | case SENSORS_FEATURE_POWER: |
112 | title = "Power"; | 117 | title = "Power"; |
113 | input = SENSORS_SUBFEATURE_POWER_INPUT; | 118 | input = SENSORS_SUBFEATURE_POWER_INPUT; |
114 | display = "average"; | 119 | display = "maximum"; |
120 | counter_class = "absolute"; | ||
115 | unit = "W"; | 121 | unit = "W"; |
116 | modifier = 1000000; | 122 | modifier = 1000000; |
117 | monotonic = false; | 123 | monotonic = false; |
@@ -120,6 +126,7 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co | |||
120 | title = "Energy"; | 126 | title = "Energy"; |
121 | input = SENSORS_SUBFEATURE_ENERGY_INPUT; | 127 | input = SENSORS_SUBFEATURE_ENERGY_INPUT; |
122 | display = "accumulate"; | 128 | display = "accumulate"; |
129 | counter_class = "delta"; | ||
123 | unit = "J"; | 130 | unit = "J"; |
124 | modifier = 1000000; | 131 | modifier = 1000000; |
125 | monotonic = true; | 132 | monotonic = true; |
@@ -127,7 +134,8 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co | |||
127 | case SENSORS_FEATURE_CURR: | 134 | case SENSORS_FEATURE_CURR: |
128 | title = "Current"; | 135 | title = "Current"; |
129 | input = SENSORS_SUBFEATURE_CURR_INPUT; | 136 | input = SENSORS_SUBFEATURE_CURR_INPUT; |
130 | display = "average"; | 137 | display = "maximum"; |
138 | counter_class = "absolute"; | ||
131 | unit = "A"; | 139 | unit = "A"; |
132 | modifier = 1000; | 140 | modifier = 1000; |
133 | monotonic = false; | 141 | monotonic = false; |
@@ -136,6 +144,7 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co | |||
136 | title = "Humidity"; | 144 | title = "Humidity"; |
137 | input = SENSORS_SUBFEATURE_HUMIDITY_INPUT; | 145 | input = SENSORS_SUBFEATURE_HUMIDITY_INPUT; |
138 | display = "average"; | 146 | display = "average"; |
147 | counter_class = "absolute"; | ||
139 | unit = "%"; | 148 | unit = "%"; |
140 | modifier = 1000; | 149 | modifier = 1000; |
141 | monotonic = false; | 150 | monotonic = false; |
@@ -311,6 +320,7 @@ void Hwmon::writeEvents(mxml_node_t *root) const { | |||
311 | mxmlElementSetAttr(node, "name", counter->getLabel()); | 320 | mxmlElementSetAttr(node, "name", counter->getLabel()); |
312 | } | 321 | } |
313 | mxmlElementSetAttr(node, "display", counter->getDisplay()); | 322 | mxmlElementSetAttr(node, "display", counter->getDisplay()); |
323 | mxmlElementSetAttr(node, "class", counter->getCounterClass()); | ||
314 | mxmlElementSetAttr(node, "units", counter->getUnit()); | 324 | mxmlElementSetAttr(node, "units", counter->getUnit()); |
315 | if (counter->getModifier() != 1) { | 325 | if (counter->getModifier() != 1) { |
316 | mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier()); | 326 | mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier()); |
diff --git a/daemon/KMod.cpp b/daemon/KMod.cpp index 9300002..73e123d 100644 --- a/daemon/KMod.cpp +++ b/daemon/KMod.cpp | |||
@@ -58,10 +58,15 @@ void KMod::setupCounter(Counter &counter) { | |||
58 | return; | 58 | return; |
59 | } | 59 | } |
60 | 60 | ||
61 | int value = 0; | ||
61 | snprintf(text, sizeof(text), "%s/key", base); | 62 | snprintf(text, sizeof(text), "%s/key", base); |
62 | int key = 0; | 63 | DriverSource::readIntDriver(text, &value); |
63 | DriverSource::readIntDriver(text, &key); | 64 | counter.setKey(value); |
64 | counter.setKey(key); | 65 | |
66 | snprintf(text, sizeof(text), "%s/cores", base); | ||
67 | if (DriverSource::readIntDriver(text, &value) == 0) { | ||
68 | counter.setCores(value); | ||
69 | } | ||
65 | 70 | ||
66 | snprintf(text, sizeof(text), "%s/event", base); | 71 | snprintf(text, sizeof(text), "%s/event", base); |
67 | DriverSource::writeDriver(text, counter.getEvent()); | 72 | DriverSource::writeDriver(text, counter.getEvent()); |
diff --git a/daemon/LocalCapture.h b/daemon/LocalCapture.h index aadecce..b1e7219 100644 --- a/daemon/LocalCapture.h +++ b/daemon/LocalCapture.h | |||
@@ -23,4 +23,4 @@ private: | |||
23 | int removeDirAndAllContents(char* path); | 23 | int removeDirAndAllContents(char* path); |
24 | }; | 24 | }; |
25 | 25 | ||
26 | #endif //__LOCAL_CAPTURE_H__ | 26 | #endif //__LOCAL_CAPTURE_H__ |
diff --git a/daemon/Logging.h b/daemon/Logging.h index 6ae3280..4934bb0 100644 --- a/daemon/Logging.h +++ b/daemon/Logging.h | |||
@@ -33,4 +33,4 @@ extern Logging* logg; | |||
33 | 33 | ||
34 | extern void handleException() __attribute__ ((noreturn)); | 34 | extern void handleException() __attribute__ ((noreturn)); |
35 | 35 | ||
36 | #endif //__LOGGING_H__ | 36 | #endif //__LOGGING_H__ |
diff --git a/daemon/Makefile b/daemon/Makefile index 24ee940..2ed49fd 100644 --- a/daemon/Makefile +++ b/daemon/Makefile | |||
@@ -8,14 +8,14 @@ | |||
8 | # targets run 'make SOFTFLOAT=1 SYSROOT=/path/to/sysroot', see | 8 | # targets run 'make SOFTFLOAT=1 SYSROOT=/path/to/sysroot', see |
9 | # README_Streamline.txt for more details | 9 | # README_Streamline.txt for more details |
10 | 10 | ||
11 | CPP = $(CROSS_COMPILE)g++ | 11 | CC = $(CROSS_COMPILE)gcc |
12 | GCC = $(CROSS_COMPILE)gcc | 12 | CXX = $(CROSS_COMPILE)g++ |
13 | 13 | ||
14 | # -mthumb-interwork is required for interworking to ARM or Thumb stdlibc | 14 | # -mthumb-interwork is required for interworking to ARM or Thumb stdlibc |
15 | CFLAGS += -mthumb-interwork | 15 | CPPFLAGS += -mthumb-interwork |
16 | 16 | ||
17 | ifeq ($(SOFTFLOAT),1) | 17 | ifeq ($(SOFTFLOAT),1) |
18 | CFLAGS += -marm -march=armv4t -mfloat-abi=soft | 18 | CPPFLAGS += -marm -march=armv4t -mfloat-abi=soft |
19 | LDFLAGS += -marm -march=armv4t -mfloat-abi=soft | 19 | LDFLAGS += -marm -march=armv4t -mfloat-abi=soft |
20 | endif | 20 | endif |
21 | ifneq ($(SYSROOT),) | 21 | ifneq ($(SYSROOT),) |
diff --git a/daemon/Makefile_aarch64 b/daemon/Makefile_aarch64 index 10b4b4a..efd1fa0 100644 --- a/daemon/Makefile_aarch64 +++ b/daemon/Makefile_aarch64 | |||
@@ -4,12 +4,9 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | # Uncomment and define CROSS_COMPILE if it is not already defined | 6 | # Uncomment and define CROSS_COMPILE if it is not already defined |
7 | # CROSS_COMPILE=/path/to/cross-compiler/arm-linux-gnueabihf- | 7 | # CROSS_COMPILE=/path/to/cross-compiler/aarch64-linux-gnu- |
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 | 8 | ||
12 | CPP = $(CROSS_COMPILE)g++ | 9 | CC = $(CROSS_COMPILE)gcc |
13 | GCC = $(CROSS_COMPILE)gcc | 10 | CXX = $(CROSS_COMPILE)g++ |
14 | 11 | ||
15 | include common.mk | 12 | include common.mk |
diff --git a/daemon/MaliVideoDriver.cpp b/daemon/MaliVideoDriver.cpp new file mode 100644 index 0000000..18b413b --- /dev/null +++ b/daemon/MaliVideoDriver.cpp | |||
@@ -0,0 +1,253 @@ | |||
1 | /** | ||
2 | * Copyright (C) ARM Limited 2014. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include "MaliVideoDriver.h" | ||
10 | |||
11 | #include <unistd.h> | ||
12 | |||
13 | #include "Buffer.h" | ||
14 | #include "Counter.h" | ||
15 | #include "Logging.h" | ||
16 | #include "SessionData.h" | ||
17 | |||
18 | // From instr/src/mve_instr_comm_protocol.h | ||
19 | typedef enum mve_instr_configuration_type { | ||
20 | MVE_INSTR_RAW = 1 << 0, | ||
21 | MVE_INSTR_COUNTERS = 1 << 1, | ||
22 | MVE_INSTR_EVENTS = 1 << 2, | ||
23 | MVE_INSTR_ACTIVITIES = 1 << 3, | ||
24 | |||
25 | // Raw always pushed regardless | ||
26 | MVE_INSTR_PULL = 1 << 12, | ||
27 | // Raw always unpacked regardless | ||
28 | MVE_INSTR_PACKED_COMM = 1 << 13, | ||
29 | // Don’t send ACKt response | ||
30 | MVE_INSTR_NO_AUTO_ACK = 1 << 14, | ||
31 | } mve_instr_configuration_type_t; | ||
32 | |||
33 | static const char COUNTER[] = "ARM_Mali-V500_cnt"; | ||
34 | static const char EVENT[] = "ARM_Mali-V500_evn"; | ||
35 | static const char ACTIVITY[] = "ARM_Mali-V500_act"; | ||
36 | |||
37 | class MaliVideoCounter { | ||
38 | public: | ||
39 | MaliVideoCounter(MaliVideoCounter *next, const char *name, const MaliVideoCounterType type, const int id) : mNext(next), mName(name), mType(type), mId(id), mKey(getEventKey()), mEnabled(false) { | ||
40 | } | ||
41 | |||
42 | ~MaliVideoCounter() { | ||
43 | delete mName; | ||
44 | } | ||
45 | |||
46 | MaliVideoCounter *getNext() const { return mNext; } | ||
47 | const char *getName() const { return mName; } | ||
48 | MaliVideoCounterType getType() const { return mType; } | ||
49 | int getId() const { return mId; } | ||
50 | int getKey() const { return mKey; } | ||
51 | bool isEnabled() const { return mEnabled; } | ||
52 | void setEnabled(const bool enabled) { mEnabled = enabled; } | ||
53 | |||
54 | private: | ||
55 | MaliVideoCounter *const mNext; | ||
56 | const char *const mName; | ||
57 | const MaliVideoCounterType mType; | ||
58 | // Mali Video id | ||
59 | const int mId; | ||
60 | // Streamline key | ||
61 | const int mKey; | ||
62 | bool mEnabled; | ||
63 | }; | ||
64 | |||
65 | MaliVideoDriver::MaliVideoDriver() : mCounters(NULL), mActivityCount(0) { | ||
66 | } | ||
67 | |||
68 | MaliVideoDriver::~MaliVideoDriver() { | ||
69 | while (mCounters != NULL) { | ||
70 | MaliVideoCounter *counter = mCounters; | ||
71 | mCounters = counter->getNext(); | ||
72 | delete counter; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | void MaliVideoDriver::setup(mxml_node_t *const xml) { | ||
77 | // hwmon does not currently work with perf | ||
78 | if (gSessionData->perf.isSetup()) { | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | mxml_node_t *node = xml; | ||
83 | while (true) { | ||
84 | node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND); | ||
85 | if (node == NULL) { | ||
86 | break; | ||
87 | } | ||
88 | const char *counter = mxmlElementGetAttr(node, "counter"); | ||
89 | if (counter == NULL) { | ||
90 | // Ignore | ||
91 | } else if (strncmp(counter, COUNTER, sizeof(COUNTER) - 1) == 0) { | ||
92 | const int i = strtol(counter + sizeof(COUNTER) - 1, NULL, 10); | ||
93 | mCounters = new MaliVideoCounter(mCounters, strdup(counter), MVCT_COUNTER, i); | ||
94 | } else if (strncmp(counter, EVENT, sizeof(EVENT) - 1) == 0) { | ||
95 | const int i = strtol(counter + sizeof(EVENT) - 1, NULL, 10); | ||
96 | mCounters = new MaliVideoCounter(mCounters, strdup(counter), MVCT_EVENT, i); | ||
97 | } else if (strcmp(counter, ACTIVITY) == 0) { | ||
98 | mCounters = new MaliVideoCounter(mCounters, strdup(ACTIVITY), MVCT_ACTIVITY, 0); | ||
99 | mActivityCount = 0; | ||
100 | while (true) { | ||
101 | char buf[32]; | ||
102 | snprintf(buf, sizeof(buf), "activity%i", mActivityCount + 1); | ||
103 | if (mxmlElementGetAttr(node, buf) == NULL) { | ||
104 | break; | ||
105 | } | ||
106 | ++mActivityCount; | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | MaliVideoCounter *MaliVideoDriver::findCounter(const Counter &counter) const { | ||
113 | for (MaliVideoCounter *maliVideoCounter = mCounters; maliVideoCounter != NULL; maliVideoCounter = maliVideoCounter->getNext()) { | ||
114 | if (strcmp(maliVideoCounter->getName(), counter.getType()) == 0) { | ||
115 | return maliVideoCounter; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | return NULL; | ||
120 | } | ||
121 | |||
122 | bool MaliVideoDriver::claimCounter(const Counter &counter) const { | ||
123 | return findCounter(counter) != NULL; | ||
124 | } | ||
125 | |||
126 | bool MaliVideoDriver::countersEnabled() const { | ||
127 | for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { | ||
128 | if (counter->isEnabled()) { | ||
129 | return true; | ||
130 | } | ||
131 | } | ||
132 | return false; | ||
133 | } | ||
134 | |||
135 | void MaliVideoDriver::resetCounters() { | ||
136 | for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { | ||
137 | counter->setEnabled(false); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | void MaliVideoDriver::setupCounter(Counter &counter) { | ||
142 | MaliVideoCounter *const maliVideoCounter = findCounter(counter); | ||
143 | if (maliVideoCounter == NULL) { | ||
144 | counter.setEnabled(false); | ||
145 | return; | ||
146 | } | ||
147 | maliVideoCounter->setEnabled(true); | ||
148 | counter.setKey(maliVideoCounter->getKey()); | ||
149 | } | ||
150 | |||
151 | int MaliVideoDriver::writeCounters(mxml_node_t *root) const { | ||
152 | if (access("/dev/mv500", F_OK) != 0) { | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | int count = 0; | ||
157 | for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { | ||
158 | mxml_node_t *node = mxmlNewElement(root, "counter"); | ||
159 | mxmlElementSetAttr(node, "name", counter->getName()); | ||
160 | ++count; | ||
161 | } | ||
162 | |||
163 | return count; | ||
164 | } | ||
165 | |||
166 | void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos) { | ||
167 | // size | ||
168 | int numEnabled = 0; | ||
169 | for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { | ||
170 | if (counter->isEnabled() && (counter->getType() == type)) { | ||
171 | ++numEnabled; | ||
172 | } | ||
173 | } | ||
174 | Buffer::packInt(buf, bufsize, pos, numEnabled*sizeof(uint32_t)); | ||
175 | for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { | ||
176 | if (counter->isEnabled() && (counter->getType() == type)) { | ||
177 | Buffer::packInt(buf, bufsize, pos, counter->getId()); | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | bool MaliVideoDriver::start(const int mveUds) { | ||
183 | char buf[256]; | ||
184 | int pos = 0; | ||
185 | |||
186 | // code - MVE_INSTR_STARTUP | ||
187 | buf[pos++] = 'C'; | ||
188 | buf[pos++] = 'L'; | ||
189 | buf[pos++] = 'N'; | ||
190 | buf[pos++] = 'T'; | ||
191 | // size | ||
192 | Buffer::packInt(buf, sizeof(buf), pos, sizeof(uint32_t)); | ||
193 | // client_version_number | ||
194 | Buffer::packInt(buf, sizeof(buf), pos, 1); | ||
195 | |||
196 | // code - MVE_INSTR_CONFIGURE | ||
197 | buf[pos++] = 'C'; | ||
198 | buf[pos++] = 'N'; | ||
199 | buf[pos++] = 'F'; | ||
200 | buf[pos++] = 'G'; | ||
201 | // size | ||
202 | Buffer::packInt(buf, sizeof(buf), pos, 5*sizeof(uint32_t)); | ||
203 | // configuration | ||
204 | Buffer::packInt(buf, sizeof(buf), pos, MVE_INSTR_COUNTERS | MVE_INSTR_EVENTS | MVE_INSTR_ACTIVITIES | MVE_INSTR_PACKED_COMM); | ||
205 | // communication_protocol_version | ||
206 | Buffer::packInt(buf, sizeof(buf), pos, 1); | ||
207 | // data_protocol_version | ||
208 | Buffer::packInt(buf, sizeof(buf), pos, 1); | ||
209 | // sample_rate - convert samples/second to ms/sample | ||
210 | Buffer::packInt(buf, sizeof(buf), pos, 1000/gSessionData->mSampleRate); | ||
211 | // live_rate - convert ns/flush to ms/flush | ||
212 | Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mLiveRate/1000000); | ||
213 | |||
214 | // code - MVE_INSTR_ENABLE_COUNTERS | ||
215 | buf[pos++] = 'C'; | ||
216 | buf[pos++] = 'F'; | ||
217 | buf[pos++] = 'G'; | ||
218 | buf[pos++] = 'c'; | ||
219 | marshalEnable(MVCT_COUNTER, buf, sizeof(buf), pos); | ||
220 | |||
221 | // code - MVE_INSTR_ENABLE_EVENTS | ||
222 | buf[pos++] = 'C'; | ||
223 | buf[pos++] = 'F'; | ||
224 | buf[pos++] = 'G'; | ||
225 | buf[pos++] = 'e'; | ||
226 | marshalEnable(MVCT_EVENT, buf, sizeof(buf), pos); | ||
227 | |||
228 | /* | ||
229 | // code - MVE_INSTR_ENABLE_ACTIVITIES | ||
230 | buf[pos++] = 'C'; | ||
231 | buf[pos++] = 'F'; | ||
232 | buf[pos++] = 'G'; | ||
233 | buf[pos++] = 'a'; | ||
234 | // size | ||
235 | Buffer::packInt(buf, sizeof(buf), pos, mActivityCount*sizeof(uint32_t)); | ||
236 | for (int i = 0; i < mActivityCount; ++i) { | ||
237 | // activity_id | ||
238 | Buffer::packInt(buf, sizeof(buf), pos, i); | ||
239 | } | ||
240 | */ | ||
241 | |||
242 | int written = 0; | ||
243 | while (written < pos) { | ||
244 | size_t bytes = ::write(mveUds, buf + written, pos - written); | ||
245 | if (bytes <= 0) { | ||
246 | logg->logMessage("%s(%s:%i): write failed", __FUNCTION__, __FILE__, __LINE__); | ||
247 | return false; | ||
248 | } | ||
249 | written += bytes; | ||
250 | } | ||
251 | |||
252 | return true; | ||
253 | } | ||
diff --git a/daemon/MaliVideoDriver.h b/daemon/MaliVideoDriver.h new file mode 100644 index 0000000..00cb808 --- /dev/null +++ b/daemon/MaliVideoDriver.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /** | ||
2 | * Copyright (C) ARM Limited 2014. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef MALIVIDEODRIVER_H | ||
10 | #define MALIVIDEODRIVER_H | ||
11 | |||
12 | #include "Driver.h" | ||
13 | |||
14 | class MaliVideoCounter; | ||
15 | |||
16 | enum MaliVideoCounterType { | ||
17 | MVCT_COUNTER, | ||
18 | MVCT_EVENT, | ||
19 | MVCT_ACTIVITY, | ||
20 | }; | ||
21 | |||
22 | class MaliVideoDriver : public Driver { | ||
23 | public: | ||
24 | MaliVideoDriver(); | ||
25 | ~MaliVideoDriver(); | ||
26 | |||
27 | void setup(mxml_node_t *const xml); | ||
28 | |||
29 | bool claimCounter(const Counter &counter) const; | ||
30 | bool countersEnabled() const; | ||
31 | void resetCounters(); | ||
32 | void setupCounter(Counter &counter); | ||
33 | |||
34 | int writeCounters(mxml_node_t *root) const; | ||
35 | |||
36 | bool start(const int mveUds); | ||
37 | |||
38 | private: | ||
39 | MaliVideoCounter *findCounter(const Counter &counter) const; | ||
40 | void marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos); | ||
41 | |||
42 | MaliVideoCounter *mCounters; | ||
43 | int mActivityCount; | ||
44 | |||
45 | // Intentionally unimplemented | ||
46 | MaliVideoDriver(const MaliVideoDriver &); | ||
47 | MaliVideoDriver &operator=(const MaliVideoDriver &); | ||
48 | }; | ||
49 | |||
50 | #endif // MALIVIDEODRIVER_H | ||
diff --git a/daemon/Monitor.cpp b/daemon/Monitor.cpp index 90d5c47..b34a15f 100644 --- a/daemon/Monitor.cpp +++ b/daemon/Monitor.cpp | |||
@@ -18,8 +18,15 @@ Monitor::Monitor() : mFd(-1) { | |||
18 | } | 18 | } |
19 | 19 | ||
20 | Monitor::~Monitor() { | 20 | Monitor::~Monitor() { |
21 | if (mFd >= -1) { | 21 | if (mFd >= 0) { |
22 | close(mFd); | 22 | ::close(mFd); |
23 | } | ||
24 | } | ||
25 | |||
26 | void Monitor::close() { | ||
27 | if (mFd >= 0) { | ||
28 | ::close(mFd); | ||
29 | mFd = -1; | ||
23 | } | 30 | } |
24 | } | 31 | } |
25 | 32 | ||
diff --git a/daemon/Monitor.h b/daemon/Monitor.h index 6e268b6..7194e0e 100644 --- a/daemon/Monitor.h +++ b/daemon/Monitor.h | |||
@@ -16,6 +16,7 @@ public: | |||
16 | Monitor(); | 16 | Monitor(); |
17 | ~Monitor(); | 17 | ~Monitor(); |
18 | 18 | ||
19 | void close(); | ||
19 | bool init(); | 20 | bool init(); |
20 | bool add(const int fd); | 21 | bool add(const int fd); |
21 | int wait(struct epoll_event *const events, int maxevents, int timeout); | 22 | int wait(struct epoll_event *const events, int maxevents, int timeout); |
diff --git a/daemon/OlySocket.cpp b/daemon/OlySocket.cpp index 26e4768..28774e3 100644 --- a/daemon/OlySocket.cpp +++ b/daemon/OlySocket.cpp | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "OlySocket.h" | 9 | #include "OlySocket.h" |
10 | 10 | ||
11 | #include <stdio.h> | 11 | #include <stdio.h> |
12 | #include <string.h> | ||
12 | #ifdef WIN32 | 13 | #ifdef WIN32 |
13 | #include <Winsock2.h> | 14 | #include <Winsock2.h> |
14 | #include <ws2tcpip.h> | 15 | #include <ws2tcpip.h> |
@@ -43,16 +44,18 @@ OlyServerSocket::OlyServerSocket(int port) { | |||
43 | createServerSocket(port); | 44 | createServerSocket(port); |
44 | } | 45 | } |
45 | 46 | ||
46 | OlySocket::OlySocket(int port, const char* host) { | ||
47 | createClientSocket(host, port); | ||
48 | } | ||
49 | |||
50 | OlySocket::OlySocket(int socketID) : mSocketID(socketID) { | 47 | OlySocket::OlySocket(int socketID) : mSocketID(socketID) { |
51 | } | 48 | } |
52 | 49 | ||
53 | #ifndef WIN32 | 50 | #ifndef WIN32 |
54 | 51 | ||
55 | OlyServerSocket::OlyServerSocket(const char* path) { | 52 | #define MIN(A, B) ({ \ |
53 | const __typeof__(A) __a = A; \ | ||
54 | const __typeof__(B) __b = B; \ | ||
55 | __a > __b ? __b : __a; \ | ||
56 | }) | ||
57 | |||
58 | OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize) { | ||
56 | // Create socket | 59 | // Create socket |
57 | mFDServer = socket(PF_UNIX, SOCK_STREAM, 0); | 60 | mFDServer = socket(PF_UNIX, SOCK_STREAM, 0); |
58 | if (mFDServer < 0) { | 61 | if (mFDServer < 0) { |
@@ -60,13 +63,11 @@ OlyServerSocket::OlyServerSocket(const char* path) { | |||
60 | handleException(); | 63 | handleException(); |
61 | } | 64 | } |
62 | 65 | ||
63 | unlink(path); | ||
64 | |||
65 | // Create sockaddr_in structure, ensuring non-populated fields are zero | 66 | // Create sockaddr_in structure, ensuring non-populated fields are zero |
66 | struct sockaddr_un sockaddr; | 67 | struct sockaddr_un sockaddr; |
67 | memset((void*)&sockaddr, 0, sizeof(sockaddr)); | 68 | memset((void*)&sockaddr, 0, sizeof(sockaddr)); |
68 | sockaddr.sun_family = AF_UNIX; | 69 | sockaddr.sun_family = AF_UNIX; |
69 | strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1); | 70 | memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path))); |
70 | sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0'; | 71 | sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0'; |
71 | 72 | ||
72 | // Bind the socket to an address | 73 | // Bind the socket to an address |
@@ -82,24 +83,25 @@ OlyServerSocket::OlyServerSocket(const char* path) { | |||
82 | } | 83 | } |
83 | } | 84 | } |
84 | 85 | ||
85 | OlySocket::OlySocket(const char* path) { | 86 | int OlySocket::connect(const char* path, const size_t pathSize) { |
86 | mSocketID = socket(PF_UNIX, SOCK_STREAM, 0); | 87 | int fd = socket(PF_UNIX, SOCK_STREAM, 0); |
87 | if (mSocketID < 0) { | 88 | if (fd < 0) { |
88 | return; | 89 | return -1; |
89 | } | 90 | } |
90 | 91 | ||
91 | // Create sockaddr_in structure, ensuring non-populated fields are zero | 92 | // Create sockaddr_in structure, ensuring non-populated fields are zero |
92 | struct sockaddr_un sockaddr; | 93 | struct sockaddr_un sockaddr; |
93 | memset((void*)&sockaddr, 0, sizeof(sockaddr)); | 94 | memset((void*)&sockaddr, 0, sizeof(sockaddr)); |
94 | sockaddr.sun_family = AF_UNIX; | 95 | sockaddr.sun_family = AF_UNIX; |
95 | strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1); | 96 | memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path))); |
96 | sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0'; | 97 | sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0'; |
97 | 98 | ||
98 | if (connect(mSocketID, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { | 99 | if (::connect(fd, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { |
99 | close(mSocketID); | 100 | close(fd); |
100 | mSocketID = -1; | 101 | return -1; |
101 | return; | ||
102 | } | 102 | } |
103 | |||
104 | return fd; | ||
103 | } | 105 | } |
104 | 106 | ||
105 | #endif | 107 | #endif |
@@ -137,47 +139,6 @@ void OlyServerSocket::closeServerSocket() { | |||
137 | mFDServer = 0; | 139 | mFDServer = 0; |
138 | } | 140 | } |
139 | 141 | ||
140 | void OlySocket::createClientSocket(const char* hostname, int portno) { | ||
141 | #ifdef WIN32 | ||
142 | // TODO: Implement for Windows | ||
143 | #else | ||
144 | char buf[32]; | ||
145 | struct addrinfo hints, *res, *res0; | ||
146 | |||
147 | snprintf(buf, sizeof(buf), "%d", portno); | ||
148 | mSocketID = -1; | ||
149 | memset((void*)&hints, 0, sizeof(hints)); | ||
150 | hints.ai_family = PF_UNSPEC; | ||
151 | hints.ai_socktype = SOCK_STREAM; | ||
152 | |||
153 | if (getaddrinfo(hostname, buf, &hints, &res0)) { | ||
154 | logg->logError(__FILE__, __LINE__, "Client socket failed to get address info for %s", hostname); | ||
155 | handleException(); | ||
156 | } | ||
157 | for (res=res0; res!=NULL; res = res->ai_next) { | ||
158 | if ( res->ai_family != PF_INET || res->ai_socktype != SOCK_STREAM ) { | ||
159 | continue; | ||
160 | } | ||
161 | mSocketID = socket(res->ai_family, res->ai_socktype, res->ai_protocol); | ||
162 | if (mSocketID < 0) { | ||
163 | continue; | ||
164 | } | ||
165 | if (connect(mSocketID, res->ai_addr, res->ai_addrlen) < 0) { | ||
166 | close(mSocketID); | ||
167 | mSocketID = -1; | ||
168 | } | ||
169 | if (mSocketID > 0) { | ||
170 | break; | ||
171 | } | ||
172 | } | ||
173 | freeaddrinfo(res0); | ||
174 | if (mSocketID <= 0) { | ||
175 | logg->logError(__FILE__, __LINE__, "Could not connect to client socket. Ensure ARM Streamline is running."); | ||
176 | handleException(); | ||
177 | } | ||
178 | #endif | ||
179 | } | ||
180 | |||
181 | void OlyServerSocket::createServerSocket(int port) { | 142 | void OlyServerSocket::createServerSocket(int port) { |
182 | int family = AF_INET6; | 143 | int family = AF_INET6; |
183 | 144 | ||
diff --git a/daemon/OlySocket.h b/daemon/OlySocket.h index eab786b..20c67cc 100644 --- a/daemon/OlySocket.h +++ b/daemon/OlySocket.h | |||
@@ -9,13 +9,15 @@ | |||
9 | #ifndef __OLY_SOCKET_H__ | 9 | #ifndef __OLY_SOCKET_H__ |
10 | #define __OLY_SOCKET_H__ | 10 | #define __OLY_SOCKET_H__ |
11 | 11 | ||
12 | #include <stddef.h> | ||
13 | |||
12 | class OlySocket { | 14 | class OlySocket { |
13 | public: | 15 | public: |
14 | OlySocket(int port, const char* hostname); | ||
15 | OlySocket(int socketID); | ||
16 | #ifndef WIN32 | 16 | #ifndef WIN32 |
17 | OlySocket(const char* path); | 17 | static int connect(const char* path, const size_t pathSize); |
18 | #endif | 18 | #endif |
19 | |||
20 | OlySocket(int socketID); | ||
19 | ~OlySocket(); | 21 | ~OlySocket(); |
20 | 22 | ||
21 | void closeSocket(); | 23 | void closeSocket(); |
@@ -29,21 +31,21 @@ public: | |||
29 | 31 | ||
30 | private: | 32 | private: |
31 | int mSocketID; | 33 | int mSocketID; |
32 | |||
33 | void createClientSocket(const char* hostname, int port); | ||
34 | }; | 34 | }; |
35 | 35 | ||
36 | class OlyServerSocket { | 36 | class OlyServerSocket { |
37 | public: | 37 | public: |
38 | OlyServerSocket(int port); | 38 | OlyServerSocket(int port); |
39 | #ifndef WIN32 | 39 | #ifndef WIN32 |
40 | OlyServerSocket(const char* path); | 40 | OlyServerSocket(const char* path, const size_t pathSize); |
41 | #endif | 41 | #endif |
42 | ~OlyServerSocket(); | 42 | ~OlyServerSocket(); |
43 | 43 | ||
44 | int acceptConnection(); | 44 | int acceptConnection(); |
45 | void closeServerSocket(); | 45 | void closeServerSocket(); |
46 | 46 | ||
47 | int getFd() { return mFDServer; } | ||
48 | |||
47 | private: | 49 | private: |
48 | int mFDServer; | 50 | int mFDServer; |
49 | 51 | ||
diff --git a/daemon/PerfDriver.cpp b/daemon/PerfDriver.cpp index 8e25c22..ac97a07 100644 --- a/daemon/PerfDriver.cpp +++ b/daemon/PerfDriver.cpp | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <dirent.h> | 11 | #include <dirent.h> |
12 | #include <sys/utsname.h> | 12 | #include <sys/utsname.h> |
13 | #include <time.h> | 13 | #include <time.h> |
14 | #include <unistd.h> | ||
14 | 15 | ||
15 | #include "Buffer.h" | 16 | #include "Buffer.h" |
16 | #include "Config.h" | 17 | #include "Config.h" |
@@ -30,7 +31,7 @@ | |||
30 | struct gator_cpu { | 31 | struct gator_cpu { |
31 | const int cpuid; | 32 | const int cpuid; |
32 | // Human readable name | 33 | // Human readable name |
33 | const char core_name[32]; | 34 | const char *const core_name; |
34 | // gatorfs event and Perf PMU name | 35 | // gatorfs event and Perf PMU name |
35 | const char *const pmnc_name; | 36 | const char *const pmnc_name; |
36 | const int pmnc_counters; | 37 | const int pmnc_counters; |
@@ -62,9 +63,20 @@ static const struct gator_cpu gator_cpus[] = { | |||
62 | static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-"; | 63 | static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-"; |
63 | static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_"; | 64 | static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_"; |
64 | 65 | ||
66 | struct uncore_counter { | ||
67 | // gatorfs event and Perf PMU name | ||
68 | const char *const name; | ||
69 | const int count; | ||
70 | }; | ||
71 | |||
72 | static const struct uncore_counter uncore_counters[] = { | ||
73 | { "CCI_400", 4 }, | ||
74 | { "CCI_400-r1", 4 }, | ||
75 | }; | ||
76 | |||
65 | class PerfCounter { | 77 | class PerfCounter { |
66 | public: | 78 | public: |
67 | PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false) {} | 79 | PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config, bool perCpu) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false), mPerCpu(perCpu) {} |
68 | ~PerfCounter() { | 80 | ~PerfCounter() { |
69 | delete [] mName; | 81 | delete [] mName; |
70 | } | 82 | } |
@@ -79,6 +91,7 @@ public: | |||
79 | void setConfig(const uint64_t config) { mConfig = config; } | 91 | void setConfig(const uint64_t config) { mConfig = config; } |
80 | bool isEnabled() const { return mEnabled; } | 92 | bool isEnabled() const { return mEnabled; } |
81 | void setEnabled(const bool enabled) { mEnabled = enabled; } | 93 | void setEnabled(const bool enabled) { mEnabled = enabled; } |
94 | bool isPerCpu() const { return mPerCpu; } | ||
82 | 95 | ||
83 | private: | 96 | private: |
84 | PerfCounter *const mNext; | 97 | PerfCounter *const mNext; |
@@ -87,10 +100,11 @@ private: | |||
87 | int mCount; | 100 | int mCount; |
88 | const int mKey; | 101 | const int mKey; |
89 | uint64_t mConfig; | 102 | uint64_t mConfig; |
90 | bool mEnabled; | 103 | int mEnabled : 1, |
104 | mPerCpu : 1; | ||
91 | }; | 105 | }; |
92 | 106 | ||
93 | PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false) { | 107 | PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false), mLegacySupport(false) { |
94 | } | 108 | } |
95 | 109 | ||
96 | PerfDriver::~PerfDriver() { | 110 | PerfDriver::~PerfDriver() { |
@@ -105,13 +119,27 @@ void PerfDriver::addCpuCounters(const char *const counterName, const int type, c | |||
105 | int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; | 119 | int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; |
106 | char *name = new char[len]; | 120 | char *name = new char[len]; |
107 | snprintf(name, len, "%s_ccnt", counterName); | 121 | snprintf(name, len, "%s_ccnt", counterName); |
108 | mCounters = new PerfCounter(mCounters, name, type, -1); | 122 | mCounters = new PerfCounter(mCounters, name, type, -1, true); |
109 | 123 | ||
110 | for (int j = 0; j < numCounters; ++j) { | 124 | for (int j = 0; j < numCounters; ++j) { |
111 | len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1; | 125 | len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1; |
112 | name = new char[len]; | 126 | name = new char[len]; |
113 | snprintf(name, len, "%s_cnt%d", counterName, j); | 127 | snprintf(name, len, "%s_cnt%d", counterName, j); |
114 | mCounters = new PerfCounter(mCounters, name, type, -1); | 128 | mCounters = new PerfCounter(mCounters, name, type, -1, true); |
129 | } | ||
130 | } | ||
131 | |||
132 | void PerfDriver::addUncoreCounters(const char *const counterName, const int type, const int numCounters) { | ||
133 | int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; | ||
134 | char *name = new char[len]; | ||
135 | snprintf(name, len, "%s_ccnt", counterName); | ||
136 | mCounters = new PerfCounter(mCounters, name, type, -1, false); | ||
137 | |||
138 | for (int j = 0; j < numCounters; ++j) { | ||
139 | len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1; | ||
140 | name = new char[len]; | ||
141 | snprintf(name, len, "%s_cnt%d", counterName, j); | ||
142 | mCounters = new PerfCounter(mCounters, name, type, -1, false); | ||
115 | } | 143 | } |
116 | } | 144 | } |
117 | 145 | ||
@@ -139,10 +167,16 @@ bool PerfDriver::setup() { | |||
139 | } | 167 | } |
140 | } | 168 | } |
141 | 169 | ||
142 | if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0)) { | 170 | if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 4, 0)) { |
143 | logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__); | 171 | logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__); |
144 | return false; | 172 | return false; |
145 | } | 173 | } |
174 | mLegacySupport = KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0); | ||
175 | |||
176 | if (access(EVENTS_PATH, R_OK) != 0) { | ||
177 | logg->logMessage("%s(%s:%i): " EVENTS_PATH " does not exist, is CONFIG_TRACING enabled?", __FUNCTION__, __FILE__, __LINE__); | ||
178 | return false; | ||
179 | } | ||
146 | 180 | ||
147 | // Add supported PMUs | 181 | // Add supported PMUs |
148 | bool foundCpu = false; | 182 | bool foundCpu = false; |
@@ -174,6 +208,21 @@ bool PerfDriver::setup() { | |||
174 | foundCpu = true; | 208 | foundCpu = true; |
175 | addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters); | 209 | addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters); |
176 | } | 210 | } |
211 | |||
212 | for (int i = 0; i < ARRAY_LENGTH(uncore_counters); ++i) { | ||
213 | if (strcmp(dirent->d_name, uncore_counters[i].name) != 0) { | ||
214 | continue; | ||
215 | } | ||
216 | |||
217 | int type; | ||
218 | char buf[256]; | ||
219 | snprintf(buf, sizeof(buf), PERF_DEVICES "/%s/type", dirent->d_name); | ||
220 | if (DriverSource::readIntDriver(buf, &type) != 0) { | ||
221 | continue; | ||
222 | } | ||
223 | |||
224 | addUncoreCounters(uncore_counters[i].name, type, uncore_counters[i].count); | ||
225 | } | ||
177 | } | 226 | } |
178 | closedir(dir); | 227 | closedir(dir); |
179 | 228 | ||
@@ -203,12 +252,12 @@ bool PerfDriver::setup() { | |||
203 | 252 | ||
204 | id = getTracepointId("irq/softirq_exit", &printb); | 253 | id = getTracepointId("irq/softirq_exit", &printb); |
205 | if (id >= 0) { | 254 | if (id >= 0) { |
206 | mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id); | 255 | mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, true); |
207 | } | 256 | } |
208 | 257 | ||
209 | id = getTracepointId("irq/irq_handler_exit", &printb); | 258 | id = getTracepointId("irq/irq_handler_exit", &printb); |
210 | if (id >= 0) { | 259 | if (id >= 0) { |
211 | mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id); | 260 | mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, true); |
212 | } | 261 | } |
213 | 262 | ||
214 | //Linux_block_rq_wr | 263 | //Linux_block_rq_wr |
@@ -218,7 +267,7 @@ bool PerfDriver::setup() { | |||
218 | 267 | ||
219 | id = getTracepointId(SCHED_SWITCH, &printb); | 268 | id = getTracepointId(SCHED_SWITCH, &printb); |
220 | if (id >= 0) { | 269 | if (id >= 0) { |
221 | mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id); | 270 | mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, true); |
222 | } | 271 | } |
223 | 272 | ||
224 | //Linux_meminfo_memused | 273 | //Linux_meminfo_memused |
@@ -227,7 +276,7 @@ bool PerfDriver::setup() { | |||
227 | //Linux_power_cpu_freq | 276 | //Linux_power_cpu_freq |
228 | //Linux_power_cpu_idle | 277 | //Linux_power_cpu_idle |
229 | 278 | ||
230 | mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1); | 279 | mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1, false); |
231 | 280 | ||
232 | //Linux_cpu_wait_io | 281 | //Linux_cpu_wait_io |
233 | 282 | ||
@@ -252,15 +301,16 @@ bool PerfDriver::summary(Buffer *const buffer) { | |||
252 | } | 301 | } |
253 | const int64_t timestamp = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec; | 302 | const int64_t timestamp = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec; |
254 | 303 | ||
255 | if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { | 304 | const int64_t uptime = getTime(); |
256 | logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__); | ||
257 | return false; | ||
258 | } | ||
259 | const int64_t uptime = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec; | ||
260 | 305 | ||
261 | buffer->summary(timestamp, uptime, 0, buf); | 306 | buffer->summary(timestamp, uptime, 0, buf); |
262 | 307 | ||
263 | for (int i = 0; i < gSessionData->mCores; ++i) { | 308 | for (int i = 0; i < gSessionData->mCores; ++i) { |
309 | // Don't send information on a cpu we know nothing about | ||
310 | if (gSessionData->mCpuIds[i] == -1) { | ||
311 | continue; | ||
312 | } | ||
313 | |||
264 | int j; | 314 | int j; |
265 | for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) { | 315 | for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) { |
266 | if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) { | 316 | if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) { |
@@ -270,7 +320,11 @@ bool PerfDriver::summary(Buffer *const buffer) { | |||
270 | if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) { | 320 | if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) { |
271 | buffer->coreName(i, gSessionData->mCpuIds[i], gator_cpus[j].core_name); | 321 | buffer->coreName(i, gSessionData->mCpuIds[i], gator_cpus[j].core_name); |
272 | } else { | 322 | } else { |
273 | snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]); | 323 | if (gSessionData->mCpuIds[i] == -1) { |
324 | snprintf(buf, sizeof(buf), "Unknown"); | ||
325 | } else { | ||
326 | snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]); | ||
327 | } | ||
274 | buffer->coreName(i, gSessionData->mCpuIds[i], buf); | 328 | buffer->coreName(i, gSessionData->mCpuIds[i], buf); |
275 | } | 329 | } |
276 | } | 330 | } |
@@ -326,10 +380,10 @@ int PerfDriver::writeCounters(mxml_node_t *root) const { | |||
326 | return count; | 380 | return count; |
327 | } | 381 | } |
328 | 382 | ||
329 | bool PerfDriver::enable(PerfGroup *group, Buffer *const buffer) const { | 383 | bool PerfDriver::enable(PerfGroup *const group, Buffer *const buffer) const { |
330 | for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { | 384 | for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { |
331 | if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) { | 385 | if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) { |
332 | if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), 0, 0)) { | 386 | if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0, counter->isPerCpu() ? PERF_GROUP_PER_CPU : 0)) { |
333 | logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__); | 387 | logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__); |
334 | return false; | 388 | return false; |
335 | } | 389 | } |
diff --git a/daemon/PerfDriver.h b/daemon/PerfDriver.h index 3181b74..2cae575 100644 --- a/daemon/PerfDriver.h +++ b/daemon/PerfDriver.h | |||
@@ -27,6 +27,8 @@ public: | |||
27 | PerfDriver(); | 27 | PerfDriver(); |
28 | ~PerfDriver(); | 28 | ~PerfDriver(); |
29 | 29 | ||
30 | bool getLegacySupport() const { return mLegacySupport; } | ||
31 | |||
30 | bool setup(); | 32 | bool setup(); |
31 | bool summary(Buffer *const buffer); | 33 | bool summary(Buffer *const buffer); |
32 | bool isSetup() const { return mIsSetup; } | 34 | bool isSetup() const { return mIsSetup; } |
@@ -37,16 +39,18 @@ public: | |||
37 | 39 | ||
38 | int writeCounters(mxml_node_t *root) const; | 40 | int writeCounters(mxml_node_t *root) const; |
39 | 41 | ||
40 | bool enable(PerfGroup *group, Buffer *const buffer) const; | 42 | bool enable(PerfGroup *const group, Buffer *const buffer) const; |
41 | 43 | ||
42 | static long long getTracepointId(const char *const name, DynBuf *const printb); | 44 | static long long getTracepointId(const char *const name, DynBuf *const printb); |
43 | 45 | ||
44 | private: | 46 | private: |
45 | PerfCounter *findCounter(const Counter &counter) const; | 47 | PerfCounter *findCounter(const Counter &counter) const; |
46 | void addCpuCounters(const char *const counterName, const int type, const int numCounters); | 48 | void addCpuCounters(const char *const counterName, const int type, const int numCounters); |
49 | void addUncoreCounters(const char *const counterName, const int type, const int numCounters); | ||
47 | 50 | ||
48 | PerfCounter *mCounters; | 51 | PerfCounter *mCounters; |
49 | bool mIsSetup; | 52 | bool mIsSetup; |
53 | bool mLegacySupport; | ||
50 | 54 | ||
51 | // Intentionally undefined | 55 | // Intentionally undefined |
52 | PerfDriver(const PerfDriver &); | 56 | PerfDriver(const PerfDriver &); |
diff --git a/daemon/PerfGroup.cpp b/daemon/PerfGroup.cpp index faf5fca..2a0239f 100644 --- a/daemon/PerfGroup.cpp +++ b/daemon/PerfGroup.cpp | |||
@@ -23,7 +23,9 @@ | |||
23 | #define DEFAULT_PEA_ARGS(pea, additionalSampleType) \ | 23 | #define DEFAULT_PEA_ARGS(pea, additionalSampleType) \ |
24 | pea.size = sizeof(pea); \ | 24 | pea.size = sizeof(pea); \ |
25 | /* Emit time, read_format below, group leader id, and raw tracepoint info */ \ | 25 | /* Emit time, read_format below, group leader id, and raw tracepoint info */ \ |
26 | pea.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER | additionalSampleType; \ | 26 | pea.sample_type = (gSessionData->perf.getLegacySupport() \ |
27 | ? PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_ID \ | ||
28 | : PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER ) | additionalSampleType; \ | ||
27 | /* Emit emit value in group format */ \ | 29 | /* Emit emit value in group format */ \ |
28 | pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP; \ | 30 | pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP; \ |
29 | /* start out disabled */ \ | 31 | /* start out disabled */ \ |
@@ -39,6 +41,7 @@ static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t p | |||
39 | 41 | ||
40 | PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) { | 42 | PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) { |
41 | memset(&mAttrs, 0, sizeof(mAttrs)); | 43 | memset(&mAttrs, 0, sizeof(mAttrs)); |
44 | memset(&mPerCpu, 0, sizeof(mPerCpu)); | ||
42 | memset(&mKeys, -1, sizeof(mKeys)); | 45 | memset(&mKeys, -1, sizeof(mKeys)); |
43 | memset(&mFds, -1, sizeof(mFds)); | 46 | memset(&mFds, -1, sizeof(mFds)); |
44 | } | 47 | } |
@@ -75,6 +78,7 @@ bool PerfGroup::add(Buffer *const buffer, const int key, const __u32 type, const | |||
75 | mAttrs[i].freq = (flags & PERF_GROUP_FREQ ? 1 : 0); | 78 | mAttrs[i].freq = (flags & PERF_GROUP_FREQ ? 1 : 0); |
76 | mAttrs[i].task = (flags & PERF_GROUP_TASK ? 1 : 0); | 79 | mAttrs[i].task = (flags & PERF_GROUP_TASK ? 1 : 0); |
77 | mAttrs[i].sample_id_all = (flags & PERF_GROUP_SAMPLE_ID_ALL ? 1 : 0); | 80 | mAttrs[i].sample_id_all = (flags & PERF_GROUP_SAMPLE_ID_ALL ? 1 : 0); |
81 | mPerCpu[i] = (flags & PERF_GROUP_PER_CPU); | ||
78 | 82 | ||
79 | mKeys[i] = key; | 83 | mKeys[i] = key; |
80 | 84 | ||
@@ -91,13 +95,17 @@ bool PerfGroup::prepareCPU(const int cpu) { | |||
91 | continue; | 95 | continue; |
92 | } | 96 | } |
93 | 97 | ||
98 | if ((cpu != 0) && !mPerCpu[i]) { | ||
99 | continue; | ||
100 | } | ||
101 | |||
94 | const int offset = i * gSessionData->mCores; | 102 | const int offset = i * gSessionData->mCores; |
95 | if (mFds[cpu + offset] >= 0) { | 103 | if (mFds[cpu + offset] >= 0) { |
96 | logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__); | 104 | logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__); |
97 | return false; | 105 | return false; |
98 | } | 106 | } |
99 | 107 | ||
100 | logg->logMessage("%s(%s:%i): perf_event_open cpu: %i type: %lli config: %lli sample: %lli sample_type: %lli", __FUNCTION__, __FILE__, __LINE__, cpu, (long long)mAttrs[i].type, (long long)mAttrs[i].config, (long long)mAttrs[i].sample_period, (long long)mAttrs[i].sample_type); | 108 | logg->logMessage("%s(%s:%i): perf_event_open cpu: %i type: %lli config: %lli sample: %lli sample_type: 0x%llx pinned: %i mmap: %i comm: %i freq: %i task: %i sample_id_all: %i", __FUNCTION__, __FILE__, __LINE__, cpu, (long long)mAttrs[i].type, (long long)mAttrs[i].config, (long long)mAttrs[i].sample_period, (long long)mAttrs[i].sample_type, mAttrs[i].pinned, mAttrs[i].mmap, mAttrs[i].comm, mAttrs[i].freq, mAttrs[i].task, mAttrs[i].sample_id_all); |
101 | mFds[cpu + offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, i == 0 ? -1 : mFds[cpu], i == 0 ? 0 : PERF_FLAG_FD_OUTPUT); | 109 | mFds[cpu + offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, i == 0 ? -1 : mFds[cpu], i == 0 ? 0 : PERF_FLAG_FD_OUTPUT); |
102 | if (mFds[cpu + offset] < 0) { | 110 | if (mFds[cpu + offset] < 0) { |
103 | logg->logMessage("%s(%s:%i): failed %s", __FUNCTION__, __FILE__, __LINE__, strerror(errno)); | 111 | logg->logMessage("%s(%s:%i): failed %s", __FUNCTION__, __FILE__, __LINE__, strerror(errno)); |
@@ -125,7 +133,9 @@ int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer, | |||
125 | } | 133 | } |
126 | 134 | ||
127 | coreKeys[idCount] = mKeys[i]; | 135 | coreKeys[idCount] = mKeys[i]; |
128 | if (ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0) { | 136 | if (!gSessionData->perf.getLegacySupport() && ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0 && |
137 | // Workaround for running 32-bit gatord on 64-bit systems, kernel patch in the works | ||
138 | ioctl(fd, (PERF_EVENT_IOC_ID & ~IOCSIZE_MASK) | (8 << _IOC_SIZESHIFT), &ids[idCount]) != 0) { | ||
129 | logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__); | 139 | logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__); |
130 | return false; | 140 | return false; |
131 | } | 141 | } |
@@ -137,7 +147,17 @@ int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer, | |||
137 | return false; | 147 | return false; |
138 | } | 148 | } |
139 | 149 | ||
140 | buffer->keys(idCount, ids, coreKeys); | 150 | if (!gSessionData->perf.getLegacySupport()) { |
151 | buffer->keys(idCount, ids, coreKeys); | ||
152 | } else { | ||
153 | char buf[1024]; | ||
154 | ssize_t bytes = read(mFds[cpu], buf, sizeof(buf)); | ||
155 | if (bytes < 0) { | ||
156 | logg->logMessage("read failed"); | ||
157 | return false; | ||
158 | } | ||
159 | buffer->keysOld(idCount, coreKeys, bytes, buf); | ||
160 | } | ||
141 | 161 | ||
142 | if (start) { | 162 | if (start) { |
143 | for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) { | 163 | for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) { |
diff --git a/daemon/PerfGroup.h b/daemon/PerfGroup.h index af496d4..3f1e2bb 100644 --- a/daemon/PerfGroup.h +++ b/daemon/PerfGroup.h | |||
@@ -24,6 +24,7 @@ enum PerfGroupFlags { | |||
24 | PERF_GROUP_FREQ = 1 << 2, | 24 | PERF_GROUP_FREQ = 1 << 2, |
25 | PERF_GROUP_TASK = 1 << 3, | 25 | PERF_GROUP_TASK = 1 << 3, |
26 | PERF_GROUP_SAMPLE_ID_ALL = 1 << 4, | 26 | PERF_GROUP_SAMPLE_ID_ALL = 1 << 4, |
27 | PERF_GROUP_PER_CPU = 1 << 5, | ||
27 | }; | 28 | }; |
28 | 29 | ||
29 | class PerfGroup { | 30 | class PerfGroup { |
@@ -43,6 +44,7 @@ public: | |||
43 | private: | 44 | private: |
44 | // +1 for the group leader | 45 | // +1 for the group leader |
45 | struct perf_event_attr mAttrs[MAX_PERFORMANCE_COUNTERS + 1]; | 46 | struct perf_event_attr mAttrs[MAX_PERFORMANCE_COUNTERS + 1]; |
47 | bool mPerCpu[MAX_PERFORMANCE_COUNTERS + 1]; | ||
46 | int mKeys[MAX_PERFORMANCE_COUNTERS + 1]; | 48 | int mKeys[MAX_PERFORMANCE_COUNTERS + 1]; |
47 | int mFds[NR_CPUS * (MAX_PERFORMANCE_COUNTERS + 1)]; | 49 | int mFds[NR_CPUS * (MAX_PERFORMANCE_COUNTERS + 1)]; |
48 | PerfBuffer *const mPb; | 50 | PerfBuffer *const mPb; |
diff --git a/daemon/PerfSource.cpp b/daemon/PerfSource.cpp index 1f1cb19..ecfaa66 100644 --- a/daemon/PerfSource.cpp +++ b/daemon/PerfSource.cpp | |||
@@ -37,7 +37,7 @@ static bool sendTracepointFormat(Buffer *const buffer, const char *const name, D | |||
37 | return true; | 37 | return true; |
38 | } | 38 | } |
39 | 39 | ||
40 | PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(0, FRAME_PERF_ATTRS, 1024*1024, senderSem), mCountersBuf(), mCountersGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) { | 40 | PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem), mCountersBuf(), mCountersGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) { |
41 | long l = sysconf(_SC_PAGE_SIZE); | 41 | long l = sysconf(_SC_PAGE_SIZE); |
42 | if (l < 0) { | 42 | if (l < 0) { |
43 | logg->logError(__FILE__, __LINE__, "Unable to obtain the page size"); | 43 | logg->logError(__FILE__, __LINE__, "Unable to obtain the page size"); |
@@ -74,6 +74,9 @@ bool PerfSource::prepare() { | |||
74 | DynBuf b3; | 74 | DynBuf b3; |
75 | long long schedSwitchId; | 75 | long long schedSwitchId; |
76 | 76 | ||
77 | // Reread cpuinfo since cores may have changed since startup | ||
78 | gSessionData->readCpuInfo(); | ||
79 | |||
77 | if (0 | 80 | if (0 |
78 | || !mMonitor.init() | 81 | || !mMonitor.init() |
79 | || !mUEvent.init() | 82 | || !mUEvent.init() |
@@ -83,14 +86,14 @@ bool PerfSource::prepare() { | |||
83 | || !sendTracepointFormat(&mBuffer, SCHED_SWITCH, &printb, &b1) | 86 | || !sendTracepointFormat(&mBuffer, SCHED_SWITCH, &printb, &b1) |
84 | 87 | ||
85 | // Only want RAW but not IP on sched_switch and don't want TID on SAMPLE_ID | 88 | // Only want RAW but not IP on sched_switch and don't want TID on SAMPLE_ID |
86 | || !mCountersGroup.add(&mBuffer, 100/**/, PERF_TYPE_TRACEPOINT, schedSwitchId, 1, PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL) | 89 | || !mCountersGroup.add(&mBuffer, 100/**/, PERF_TYPE_TRACEPOINT, schedSwitchId, 1, PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL | PERF_GROUP_PER_CPU) |
87 | 90 | ||
88 | // Only want TID and IP but not RAW on timer | 91 | // Only want TID and IP but not RAW on timer |
89 | || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(&mBuffer, 99/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, 0)) | 92 | || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(&mBuffer, 99/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, PERF_GROUP_PER_CPU)) |
90 | 93 | ||
91 | || !gSessionData->perf.enable(&mCountersGroup, &mBuffer) | 94 | || !gSessionData->perf.enable(&mCountersGroup, &mBuffer) |
92 | || 0) { | 95 | || 0) { |
93 | logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.12 or later?", __FUNCTION__, __FILE__, __LINE__); | 96 | logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.4 or later?", __FUNCTION__, __FILE__, __LINE__); |
94 | return false; | 97 | return false; |
95 | } | 98 | } |
96 | 99 | ||
@@ -134,7 +137,7 @@ bool PerfSource::prepare() { | |||
134 | return false; | 137 | return false; |
135 | } | 138 | } |
136 | 139 | ||
137 | if (!readProc(&mBuffer, &printb, &b1, &b2, &b3)) { | 140 | if (!readProc(&mBuffer, true, &printb, &b1, &b2, &b3)) { |
138 | logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__); | 141 | logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__); |
139 | return false; | 142 | return false; |
140 | } | 143 | } |
@@ -260,6 +263,7 @@ bool PerfSource::isDone () { | |||
260 | void PerfSource::write (Sender *sender) { | 263 | void PerfSource::write (Sender *sender) { |
261 | if (!mSummary.isDone()) { | 264 | if (!mSummary.isDone()) { |
262 | mSummary.write(sender); | 265 | mSummary.write(sender); |
266 | gSessionData->mSentSummary = true; | ||
263 | } | 267 | } |
264 | if (!mBuffer.isDone()) { | 268 | if (!mBuffer.isDone()) { |
265 | mBuffer.write(sender); | 269 | mBuffer.write(sender); |
diff --git a/daemon/Proc.cpp b/daemon/Proc.cpp index e0b9e22..9f01770 100644 --- a/daemon/Proc.cpp +++ b/daemon/Proc.cpp | |||
@@ -57,14 +57,57 @@ static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf | |||
57 | return true; | 57 | return true; |
58 | } | 58 | } |
59 | 59 | ||
60 | static bool readProcTask(Buffer *const buffer, const int pid, const char *const image, DynBuf *const printb, DynBuf *const b) { | 60 | static const char *readProcExe(DynBuf *const printb, const int pid, const int tid, DynBuf *const b) { |
61 | if (tid == -1 ? !printb->printf("/proc/%i/exe", pid) | ||
62 | : !printb->printf("/proc/%i/task/%i/exe", pid, tid)) { | ||
63 | logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); | ||
64 | return NULL; | ||
65 | } | ||
66 | |||
67 | const int err = b->readlink(printb->getBuf()); | ||
68 | const char *image; | ||
69 | if (err == 0) { | ||
70 | image = strrchr(b->getBuf(), '/'); | ||
71 | if (image == NULL) { | ||
72 | image = b->getBuf(); | ||
73 | } else { | ||
74 | ++image; | ||
75 | } | ||
76 | } else if (err == -ENOENT) { | ||
77 | // readlink /proc/[pid]/exe returns ENOENT for kernel threads | ||
78 | image = "\0"; | ||
79 | } else { | ||
80 | logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__); | ||
81 | return NULL; | ||
82 | } | ||
83 | |||
84 | // Android apps are run by app_process but the cmdline is changed to reference the actual app name | ||
85 | if (strcmp(image, "app_process") != 0) { | ||
86 | return image; | ||
87 | } | ||
88 | |||
89 | if (tid == -1 ? !printb->printf("/proc/%i/cmdline", pid) | ||
90 | : !printb->printf("/proc/%i/task/%i/cmdline", pid, tid)) { | ||
91 | logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); | ||
92 | return NULL; | ||
93 | } | ||
94 | |||
95 | if (!b->read(printb->getBuf())) { | ||
96 | logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__); | ||
97 | return NULL; | ||
98 | } | ||
99 | |||
100 | return b->getBuf(); | ||
101 | } | ||
102 | |||
103 | static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) { | ||
61 | bool result = false; | 104 | bool result = false; |
62 | 105 | ||
63 | if (!b->printf("/proc/%i/task", pid)) { | 106 | if (!b1->printf("/proc/%i/task", pid)) { |
64 | logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); | 107 | logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); |
65 | return result; | 108 | return result; |
66 | } | 109 | } |
67 | DIR *task = opendir(b->getBuf()); | 110 | DIR *task = opendir(b1->getBuf()); |
68 | if (task == NULL) { | 111 | if (task == NULL) { |
69 | logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__); | 112 | logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__); |
70 | return result; | 113 | return result; |
@@ -84,11 +127,17 @@ static bool readProcTask(Buffer *const buffer, const int pid, const char *const | |||
84 | goto fail; | 127 | goto fail; |
85 | } | 128 | } |
86 | ProcStat ps; | 129 | ProcStat ps; |
87 | if (!readProcStat(&ps, printb->getBuf(), b)) { | 130 | if (!readProcStat(&ps, printb->getBuf(), b1)) { |
88 | logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__); | 131 | logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__); |
89 | goto fail; | 132 | goto fail; |
90 | } | 133 | } |
91 | 134 | ||
135 | const char *const image = readProcExe(printb, pid, tid, b2); | ||
136 | if (image == NULL) { | ||
137 | logg->logMessage("%s(%s:%i): readImage failed", __FUNCTION__, __FILE__, __LINE__); | ||
138 | goto fail; | ||
139 | } | ||
140 | |||
92 | buffer->comm(pid, tid, image, ps.comm); | 141 | buffer->comm(pid, tid, image, ps.comm); |
93 | } | 142 | } |
94 | 143 | ||
@@ -100,7 +149,7 @@ static bool readProcTask(Buffer *const buffer, const int pid, const char *const | |||
100 | return result; | 149 | return result; |
101 | } | 150 | } |
102 | 151 | ||
103 | bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) { | 152 | bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) { |
104 | bool result = false; | 153 | bool result = false; |
105 | 154 | ||
106 | DIR *proc = opendir("/proc"); | 155 | DIR *proc = opendir("/proc"); |
@@ -128,42 +177,29 @@ bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynB | |||
128 | goto fail; | 177 | goto fail; |
129 | } | 178 | } |
130 | 179 | ||
131 | if (!printb->printf("/proc/%i/exe", pid)) { | 180 | if (sendMaps) { |
132 | logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); | 181 | if (!printb->printf("/proc/%i/maps", pid)) { |
133 | goto fail; | 182 | logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); |
134 | } | 183 | goto fail; |
135 | const int err = b1->readlink(printb->getBuf()); | 184 | } |
136 | const char *image; | 185 | if (!b2->read(printb->getBuf())) { |
137 | if (err == 0) { | 186 | logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__); |
138 | image = strrchr(b1->getBuf(), '/'); | 187 | // This is not a fatal error - the process just doesn't exist any more |
139 | if (image == NULL) { | 188 | continue; |
140 | image = b1->getBuf(); | ||
141 | } else { | ||
142 | ++image; | ||
143 | } | 189 | } |
144 | } else if (err == -ENOENT) { | ||
145 | // readlink /proc/[pid]/exe returns ENOENT for kernel threads | ||
146 | image = "\0"; | ||
147 | } else { | ||
148 | logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__); | ||
149 | goto fail; | ||
150 | } | ||
151 | 190 | ||
152 | if (!printb->printf("/proc/%i/maps", pid)) { | 191 | buffer->maps(pid, pid, b2->getBuf()); |
153 | logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); | ||
154 | goto fail; | ||
155 | } | 192 | } |
156 | if (!b2->read(printb->getBuf())) { | ||
157 | logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__); | ||
158 | // This is not a fatal error - the process just doesn't exist any more | ||
159 | continue; | ||
160 | } | ||
161 | |||
162 | buffer->maps(pid, pid, b2->getBuf()); | ||
163 | if (ps.numThreads <= 1) { | 193 | if (ps.numThreads <= 1) { |
194 | const char *const image = readProcExe(printb, pid, -1, b1); | ||
195 | if (image == NULL) { | ||
196 | logg->logMessage("%s(%s:%i): readImage failed", __FUNCTION__, __FILE__, __LINE__); | ||
197 | goto fail; | ||
198 | } | ||
199 | |||
164 | buffer->comm(pid, pid, image, ps.comm); | 200 | buffer->comm(pid, pid, image, ps.comm); |
165 | } else { | 201 | } else { |
166 | if (!readProcTask(buffer, pid, image, printb, b3)) { | 202 | if (!readProcTask(buffer, pid, printb, b1, b3)) { |
167 | logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__); | 203 | logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__); |
168 | goto fail; | 204 | goto fail; |
169 | } | 205 | } |
diff --git a/daemon/Proc.h b/daemon/Proc.h index 057b610..31c2eec 100644 --- a/daemon/Proc.h +++ b/daemon/Proc.h | |||
@@ -12,6 +12,6 @@ | |||
12 | class Buffer; | 12 | class Buffer; |
13 | class DynBuf; | 13 | class DynBuf; |
14 | 14 | ||
15 | bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3); | 15 | bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3); |
16 | 16 | ||
17 | #endif // PROC_H | 17 | #endif // PROC_H |
diff --git a/daemon/Sender.h b/daemon/Sender.h index 4c359db..33b6cc3 100644 --- a/daemon/Sender.h +++ b/daemon/Sender.h | |||
@@ -39,4 +39,4 @@ private: | |||
39 | Sender &operator=(const Sender &); | 39 | Sender &operator=(const Sender &); |
40 | }; | 40 | }; |
41 | 41 | ||
42 | #endif //__SENDER_H__ | 42 | #endif //__SENDER_H__ |
diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp index c169299..14d995f 100644 --- a/daemon/SessionData.cpp +++ b/daemon/SessionData.cpp | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "SessionData.h" | 9 | #include "SessionData.h" |
10 | 10 | ||
11 | #include <string.h> | 11 | #include <string.h> |
12 | #include <sys/mman.h> | ||
12 | 13 | ||
13 | #include "SessionXML.h" | 14 | #include "SessionXML.h" |
14 | #include "Logging.h" | 15 | #include "Logging.h" |
@@ -27,6 +28,15 @@ void SessionData::initialize() { | |||
27 | mSessionIsActive = false; | 28 | mSessionIsActive = false; |
28 | mLocalCapture = false; | 29 | mLocalCapture = false; |
29 | mOneShot = false; | 30 | mOneShot = false; |
31 | mSentSummary = false; | ||
32 | const size_t cpuIdSize = sizeof(int)*NR_CPUS; | ||
33 | // Share mCpuIds across all instances of gatord | ||
34 | mCpuIds = (int *)mmap(NULL, cpuIdSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); | ||
35 | if (mCpuIds == MAP_FAILED) { | ||
36 | logg->logError(__FILE__, __LINE__, "Unable to mmap shared memory for cpuids"); | ||
37 | handleException(); | ||
38 | } | ||
39 | memset(mCpuIds, -1, cpuIdSize); | ||
30 | readCpuInfo(); | 40 | readCpuInfo(); |
31 | mConfigurationXMLPath = NULL; | 41 | mConfigurationXMLPath = NULL; |
32 | mSessionXMLPath = NULL; | 42 | mSessionXMLPath = NULL; |
@@ -91,10 +101,9 @@ void SessionData::parseSessionXML(char* xmlString) { | |||
91 | void SessionData::readCpuInfo() { | 101 | void SessionData::readCpuInfo() { |
92 | char temp[256]; // arbitrarily large amount | 102 | char temp[256]; // arbitrarily large amount |
93 | strcpy(mCoreName, "unknown"); | 103 | strcpy(mCoreName, "unknown"); |
94 | memset(&mCpuIds, -1, sizeof(mCpuIds)); | ||
95 | mMaxCpuId = -1; | 104 | mMaxCpuId = -1; |
96 | 105 | ||
97 | FILE* f = fopen("/proc/cpuinfo", "r"); | 106 | FILE* f = fopen("/proc/cpuinfo", "r"); |
98 | if (f == NULL) { | 107 | if (f == NULL) { |
99 | logg->logMessage("Error opening /proc/cpuinfo\n" | 108 | logg->logMessage("Error opening /proc/cpuinfo\n" |
100 | "The core name in the captured xml file will be 'unknown'."); | 109 | "The core name in the captured xml file will be 'unknown'."); |
@@ -102,10 +111,18 @@ void SessionData::readCpuInfo() { | |||
102 | } | 111 | } |
103 | 112 | ||
104 | bool foundCoreName = false; | 113 | bool foundCoreName = false; |
105 | int processor = 0; | 114 | int processor = -1; |
106 | while (fgets(temp, sizeof(temp), f)) { | 115 | while (fgets(temp, sizeof(temp), f)) { |
107 | if (strlen(temp) > 0) { | 116 | const size_t len = strlen(temp); |
108 | temp[strlen(temp) - 1] = 0; // Replace the line feed with a null | 117 | |
118 | if (len == 1) { | ||
119 | // New section, clear the processor. Streamline will not know the cpus if the pre Linux 3.8 format of cpuinfo is encountered but also that no incorrect information will be transmitted. | ||
120 | processor = -1; | ||
121 | continue; | ||
122 | } | ||
123 | |||
124 | if (len > 0) { | ||
125 | temp[len - 1] = '\0'; // Replace the line feed with a null | ||
109 | } | 126 | } |
110 | 127 | ||
111 | const bool foundHardware = strstr(temp, "Hardware") != 0; | 128 | const bool foundHardware = strstr(temp, "Hardware") != 0; |
@@ -127,10 +144,15 @@ void SessionData::readCpuInfo() { | |||
127 | } | 144 | } |
128 | 145 | ||
129 | if (foundCPUPart) { | 146 | if (foundCPUPart) { |
130 | mCpuIds[processor] = strtol(position, NULL, 0); | 147 | const int cpuId = strtol(position, NULL, 0); |
131 | // If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId | 148 | // If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId |
132 | if (mCpuIds[processor] > mMaxCpuId) { | 149 | if (cpuId > mMaxCpuId) { |
133 | mMaxCpuId = mCpuIds[processor]; | 150 | mMaxCpuId = cpuId; |
151 | } | ||
152 | if (processor >= NR_CPUS) { | ||
153 | logg->logMessage("Too many processors, please increase NR_CPUS"); | ||
154 | } else if (processor >= 0) { | ||
155 | mCpuIds[processor] = cpuId; | ||
134 | } | 156 | } |
135 | } | 157 | } |
136 | 158 | ||
@@ -142,10 +164,23 @@ void SessionData::readCpuInfo() { | |||
142 | 164 | ||
143 | if (!foundCoreName) { | 165 | if (!foundCoreName) { |
144 | logg->logMessage("Could not determine core name from /proc/cpuinfo\n" | 166 | logg->logMessage("Could not determine core name from /proc/cpuinfo\n" |
145 | "The core name in the captured xml file will be 'unknown'."); | 167 | "The core name in the captured xml file will be 'unknown'."); |
146 | } | 168 | } |
147 | fclose(f); | 169 | fclose(f); |
148 | } | 170 | } |
171 | |||
172 | uint64_t getTime() { | ||
173 | struct timespec ts; | ||
174 | #ifndef CLOCK_MONOTONIC_RAW | ||
175 | // Android doesn't have this defined but it was added in Linux 2.6.28 | ||
176 | #define CLOCK_MONOTONIC_RAW 4 | ||
177 | #endif | ||
178 | if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) { | ||
179 | logg->logError(__FILE__, __LINE__, "Failed to get uptime"); | ||
180 | handleException(); | ||
181 | } | ||
182 | return (NS_PER_S*ts.tv_sec + ts.tv_nsec); | ||
183 | } | ||
149 | 184 | ||
150 | int getEventKey() { | 185 | int getEventKey() { |
151 | // key 0 is reserved as a timestamp | 186 | // key 0 is reserved as a timestamp |
diff --git a/daemon/SessionData.h b/daemon/SessionData.h index ea34240..835082d 100644 --- a/daemon/SessionData.h +++ b/daemon/SessionData.h | |||
@@ -13,12 +13,16 @@ | |||
13 | 13 | ||
14 | #include "Config.h" | 14 | #include "Config.h" |
15 | #include "Counter.h" | 15 | #include "Counter.h" |
16 | #include "FSDriver.h" | ||
16 | #include "Hwmon.h" | 17 | #include "Hwmon.h" |
18 | #include "MaliVideoDriver.h" | ||
17 | #include "PerfDriver.h" | 19 | #include "PerfDriver.h" |
18 | 20 | ||
19 | #define PROTOCOL_VERSION 18 | 21 | #define PROTOCOL_VERSION 19 |
20 | #define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions | 22 | #define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions |
21 | 23 | ||
24 | #define NS_PER_S ((uint64_t)1000000000) | ||
25 | |||
22 | struct ImageLinkList { | 26 | struct ImageLinkList { |
23 | char* path; | 27 | char* path; |
24 | struct ImageLinkList *next; | 28 | struct ImageLinkList *next; |
@@ -32,9 +36,12 @@ public: | |||
32 | ~SessionData(); | 36 | ~SessionData(); |
33 | void initialize(); | 37 | void initialize(); |
34 | void parseSessionXML(char* xmlString); | 38 | void parseSessionXML(char* xmlString); |
39 | void readCpuInfo(); | ||
35 | 40 | ||
36 | Hwmon hwmon; | 41 | Hwmon hwmon; |
42 | FSDriver fsDriver; | ||
37 | PerfDriver perf; | 43 | PerfDriver perf; |
44 | MaliVideoDriver maliVideo; | ||
38 | 45 | ||
39 | char mCoreName[MAX_STRING_LEN]; | 46 | char mCoreName[MAX_STRING_LEN]; |
40 | struct ImageLinkList *mImages; | 47 | struct ImageLinkList *mImages; |
@@ -49,7 +56,8 @@ public: | |||
49 | bool mLocalCapture; | 56 | bool mLocalCapture; |
50 | bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled | 57 | bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled |
51 | bool mIsEBS; | 58 | bool mIsEBS; |
52 | 59 | bool mSentSummary; | |
60 | |||
53 | int mBacktraceDepth; | 61 | int mBacktraceDepth; |
54 | int mTotalBufferSize; // number of MB to use for the entire collection buffer | 62 | int mTotalBufferSize; // number of MB to use for the entire collection buffer |
55 | int mSampleRate; | 63 | int mSampleRate; |
@@ -57,7 +65,7 @@ public: | |||
57 | int mDuration; | 65 | int mDuration; |
58 | int mCores; | 66 | int mCores; |
59 | int mPageSize; | 67 | int mPageSize; |
60 | int mCpuIds[NR_CPUS]; | 68 | int *mCpuIds; |
61 | int mMaxCpuId; | 69 | int mMaxCpuId; |
62 | 70 | ||
63 | // PMU Counters | 71 | // PMU Counters |
@@ -65,8 +73,6 @@ public: | |||
65 | Counter mCounters[MAX_PERFORMANCE_COUNTERS]; | 73 | Counter mCounters[MAX_PERFORMANCE_COUNTERS]; |
66 | 74 | ||
67 | private: | 75 | private: |
68 | void readCpuInfo(); | ||
69 | |||
70 | // Intentionally unimplemented | 76 | // Intentionally unimplemented |
71 | SessionData(const SessionData &); | 77 | SessionData(const SessionData &); |
72 | SessionData &operator=(const SessionData &); | 78 | SessionData &operator=(const SessionData &); |
@@ -74,6 +80,7 @@ private: | |||
74 | 80 | ||
75 | extern SessionData* gSessionData; | 81 | extern SessionData* gSessionData; |
76 | 82 | ||
83 | uint64_t getTime(); | ||
77 | int getEventKey(); | 84 | int getEventKey(); |
78 | 85 | ||
79 | #endif // SESSION_DATA_H | 86 | #endif // SESSION_DATA_H |
diff --git a/daemon/SessionXML.cpp b/daemon/SessionXML.cpp index 55b2f92..8cdc940 100644 --- a/daemon/SessionXML.cpp +++ b/daemon/SessionXML.cpp | |||
@@ -17,15 +17,15 @@ | |||
17 | #include "SessionData.h" | 17 | #include "SessionData.h" |
18 | 18 | ||
19 | static const char* TAG_SESSION = "session"; | 19 | static const char* TAG_SESSION = "session"; |
20 | static const char* TAG_IMAGE = "image"; | 20 | static const char* TAG_IMAGE = "image"; |
21 | 21 | ||
22 | static const char* ATTR_VERSION = "version"; | 22 | static const char* ATTR_VERSION = "version"; |
23 | static const char* ATTR_CALL_STACK_UNWINDING = "call_stack_unwinding"; | 23 | static const char* ATTR_CALL_STACK_UNWINDING = "call_stack_unwinding"; |
24 | static const char* ATTR_BUFFER_MODE = "buffer_mode"; | 24 | static const char* ATTR_BUFFER_MODE = "buffer_mode"; |
25 | static const char* ATTR_SAMPLE_RATE = "sample_rate"; | 25 | static const char* ATTR_SAMPLE_RATE = "sample_rate"; |
26 | static const char* ATTR_DURATION = "duration"; | 26 | static const char* ATTR_DURATION = "duration"; |
27 | static const char* ATTR_PATH = "path"; | 27 | static const char* ATTR_PATH = "path"; |
28 | static const char* ATTR_LIVE_RATE = "live_rate"; | 28 | static const char* ATTR_LIVE_RATE = "live_rate"; |
29 | 29 | ||
30 | SessionXML::SessionXML(const char *str) { | 30 | SessionXML::SessionXML(const char *str) { |
31 | parameters.buffer_mode[0] = 0; | 31 | parameters.buffer_mode[0] = 0; |
diff --git a/daemon/StreamlineSetup.cpp b/daemon/StreamlineSetup.cpp index caa665e..2b61eae 100644 --- a/daemon/StreamlineSetup.cpp +++ b/daemon/StreamlineSetup.cpp | |||
@@ -266,7 +266,7 @@ void StreamlineSetup::writeConfiguration(char* xml) { | |||
266 | { ConfigurationXML configuration; } | 266 | { ConfigurationXML configuration; } |
267 | 267 | ||
268 | if (gSessionData->mCounterOverflow > 0) { | 268 | if (gSessionData->mCounterOverflow > 0) { |
269 | logg->logError(__FILE__, __LINE__, "Only %i performance counters counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow); | 269 | logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow); |
270 | handleException(); | 270 | handleException(); |
271 | } | 271 | } |
272 | } | 272 | } |
diff --git a/daemon/StreamlineSetup.h b/daemon/StreamlineSetup.h index 74bb197..b380f46 100644 --- a/daemon/StreamlineSetup.h +++ b/daemon/StreamlineSetup.h | |||
@@ -21,7 +21,7 @@ enum { | |||
21 | COMMAND_APC_START = 2, | 21 | COMMAND_APC_START = 2, |
22 | COMMAND_APC_STOP = 3, | 22 | COMMAND_APC_STOP = 3, |
23 | COMMAND_DISCONNECT = 4, | 23 | COMMAND_DISCONNECT = 4, |
24 | COMMAND_PING = 5 | 24 | COMMAND_PING = 5 |
25 | }; | 25 | }; |
26 | 26 | ||
27 | class StreamlineSetup { | 27 | class StreamlineSetup { |
@@ -47,4 +47,4 @@ private: | |||
47 | StreamlineSetup &operator=(const StreamlineSetup &); | 47 | StreamlineSetup &operator=(const StreamlineSetup &); |
48 | }; | 48 | }; |
49 | 49 | ||
50 | #endif //__STREAMLINE_SETUP_H__ | 50 | #endif //__STREAMLINE_SETUP_H__ |
diff --git a/daemon/UEvent.cpp b/daemon/UEvent.cpp index d977cd0..54d4575 100644 --- a/daemon/UEvent.cpp +++ b/daemon/UEvent.cpp | |||
@@ -8,12 +8,12 @@ | |||
8 | 8 | ||
9 | #include "UEvent.h" | 9 | #include "UEvent.h" |
10 | 10 | ||
11 | #include <sys/socket.h> | ||
12 | #include <linux/netlink.h> | ||
13 | #include <string.h> | 11 | #include <string.h> |
14 | 12 | #include <sys/socket.h> | |
15 | #include <unistd.h> | 13 | #include <unistd.h> |
16 | 14 | ||
15 | #include <linux/netlink.h> | ||
16 | |||
17 | #include "Logging.h" | 17 | #include "Logging.h" |
18 | 18 | ||
19 | static const char EMPTY[] = ""; | 19 | static const char EMPTY[] = ""; |
diff --git a/daemon/UserSpaceSource.cpp b/daemon/UserSpaceSource.cpp index debe696..8c328e0 100644 --- a/daemon/UserSpaceSource.cpp +++ b/daemon/UserSpaceSource.cpp | |||
@@ -16,7 +16,6 @@ | |||
16 | #include "Logging.h" | 16 | #include "Logging.h" |
17 | #include "SessionData.h" | 17 | #include "SessionData.h" |
18 | 18 | ||
19 | #define NS_PER_S ((uint64_t)1000000000) | ||
20 | #define NS_PER_US 1000 | 19 | #define NS_PER_US 1000 |
21 | 20 | ||
22 | extern Child *child; | 21 | extern Child *child; |
@@ -35,6 +34,7 @@ void UserSpaceSource::run() { | |||
35 | prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0); | 34 | prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0); |
36 | 35 | ||
37 | gSessionData->hwmon.start(); | 36 | gSessionData->hwmon.start(); |
37 | gSessionData->fsDriver.start(); | ||
38 | 38 | ||
39 | int64_t monotonic_started = 0; | 39 | int64_t monotonic_started = 0; |
40 | while (monotonic_started <= 0) { | 40 | while (monotonic_started <= 0) { |
@@ -48,16 +48,7 @@ void UserSpaceSource::run() { | |||
48 | 48 | ||
49 | uint64_t next_time = 0; | 49 | uint64_t next_time = 0; |
50 | while (gSessionData->mSessionIsActive) { | 50 | while (gSessionData->mSessionIsActive) { |
51 | struct timespec ts; | 51 | const uint64_t curr_time = getTime() - monotonic_started; |
52 | #ifndef CLOCK_MONOTONIC_RAW | ||
53 | // Android doesn't have this defined but it was added in Linux 2.6.28 | ||
54 | #define CLOCK_MONOTONIC_RAW 4 | ||
55 | #endif | ||
56 | if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) { | ||
57 | logg->logError(__FILE__, __LINE__, "Failed to get uptime"); | ||
58 | handleException(); | ||
59 | } | ||
60 | const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started; | ||
61 | // Sample ten times a second ignoring gSessionData->mSampleRate | 52 | // Sample ten times a second ignoring gSessionData->mSampleRate |
62 | next_time += NS_PER_S/10;//gSessionData->mSampleRate; | 53 | next_time += NS_PER_S/10;//gSessionData->mSampleRate; |
63 | if (next_time < curr_time) { | 54 | if (next_time < curr_time) { |
@@ -67,6 +58,7 @@ void UserSpaceSource::run() { | |||
67 | 58 | ||
68 | if (mBuffer.eventHeader(curr_time)) { | 59 | if (mBuffer.eventHeader(curr_time)) { |
69 | gSessionData->hwmon.read(&mBuffer); | 60 | gSessionData->hwmon.read(&mBuffer); |
61 | gSessionData->fsDriver.read(&mBuffer); | ||
70 | // Only check after writing all counters so that time and corresponding counters appear in the same frame | 62 | // Only check after writing all counters so that time and corresponding counters appear in the same frame |
71 | mBuffer.check(curr_time); | 63 | mBuffer.check(curr_time); |
72 | } | 64 | } |
diff --git a/daemon/UserSpaceSource.h b/daemon/UserSpaceSource.h index fb5889d..9b36660 100644 --- a/daemon/UserSpaceSource.h +++ b/daemon/UserSpaceSource.h | |||
@@ -14,7 +14,7 @@ | |||
14 | #include "Buffer.h" | 14 | #include "Buffer.h" |
15 | #include "Source.h" | 15 | #include "Source.h" |
16 | 16 | ||
17 | // User space counters - currently just hwmon | 17 | // User space counters |
18 | class UserSpaceSource : public Source { | 18 | class UserSpaceSource : public Source { |
19 | public: | 19 | public: |
20 | UserSpaceSource(sem_t *senderSem); | 20 | UserSpaceSource(sem_t *senderSem); |
diff --git a/daemon/c++.cpp b/daemon/c++.cpp new file mode 100644 index 0000000..6041e5e --- /dev/null +++ b/daemon/c++.cpp | |||
@@ -0,0 +1,40 @@ | |||
1 | /** | ||
2 | * Minimal set of C++ functions so that libstdc++ is not required | ||
3 | * | ||
4 | * Copyright (C) ARM Limited 2010-2014. All rights reserved. | ||
5 | * | ||
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 | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <stdio.h> | ||
12 | #include <stdlib.h> | ||
13 | |||
14 | void operator delete(void *ptr) { | ||
15 | if (ptr != NULL) { | ||
16 | free(ptr); | ||
17 | } | ||
18 | } | ||
19 | |||
20 | void operator delete[](void *ptr) { | ||
21 | operator delete(ptr); | ||
22 | } | ||
23 | |||
24 | void *operator new(size_t size) { | ||
25 | void *ptr = malloc(size == 0 ? 1 : size); | ||
26 | if (ptr == NULL) { | ||
27 | abort(); | ||
28 | } | ||
29 | return ptr; | ||
30 | } | ||
31 | |||
32 | void *operator new[](size_t size) { | ||
33 | return operator new(size); | ||
34 | } | ||
35 | |||
36 | extern "C" | ||
37 | void __cxa_pure_virtual() { | ||
38 | printf("pure virtual method called\n"); | ||
39 | abort(); | ||
40 | } | ||
diff --git a/daemon/common.mk b/daemon/common.mk index d9dc146..769a92e 100644 --- a/daemon/common.mk +++ b/daemon/common.mk | |||
@@ -5,16 +5,17 @@ | |||
5 | # -Werror treats warnings as errors | 5 | # -Werror treats warnings as errors |
6 | # -std=c++0x is the planned new c++ standard | 6 | # -std=c++0x is the planned new c++ standard |
7 | # -std=c++98 is the 1998 c++ standard | 7 | # -std=c++98 is the 1998 c++ standard |
8 | CFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors | 8 | CPPFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors |
9 | CXXFLAGS += -fno-rtti -Wextra # -Weffc++ | 9 | CXXFLAGS += -fno-rtti -Wextra # -Weffc++ |
10 | ifeq ($(WERROR),1) | 10 | ifeq ($(WERROR),1) |
11 | CFLAGS += -Werror | 11 | CPPFLAGS += -Werror |
12 | endif | 12 | endif |
13 | # -s strips the binary of debug info | 13 | # -s strips the binary of debug info |
14 | LDFLAGS += -s | 14 | LDFLAGS += -s |
15 | LDLIBS += -lrt -lm -pthread | ||
15 | TARGET = gatord | 16 | TARGET = gatord |
16 | C_SRC = $(wildcard mxml/*.c) $(wildcard libsensors/*.c) | 17 | C_SRC = $(wildcard mxml/*.c) $(wildcard libsensors/*.c) |
17 | CPP_SRC = $(wildcard *.cpp) | 18 | CXX_SRC = $(wildcard *.cpp) |
18 | 19 | ||
19 | all: $(TARGET) | 20 | all: $(TARGET) |
20 | 21 | ||
@@ -35,14 +36,15 @@ libsensors/conf-parse.c: ; | |||
35 | ./escape $< > $@ | 36 | ./escape $< > $@ |
36 | 37 | ||
37 | %.o: %.c | 38 | %.o: %.c |
38 | $(GCC) -c $(CFLAGS) -o $@ $< | 39 | $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< |
39 | 40 | ||
40 | %.o: %.cpp | 41 | %.o: %.cpp |
41 | $(CPP) -c $(CFLAGS) $(CXXFLAGS) -o $@ $< | 42 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< |
42 | 43 | ||
43 | $(TARGET): $(CPP_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o) | 44 | $(TARGET): $(CXX_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o) |
44 | $(CPP) $(LDFLAGS) -o $@ $^ -lrt -pthread | 45 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ |
45 | 46 | ||
47 | # Intentionally ignore CC as a native binary is required | ||
46 | escape: escape.c | 48 | escape: escape.c |
47 | gcc $^ -o $@ | 49 | gcc $^ -o $@ |
48 | 50 | ||
diff --git a/daemon/defaults.xml b/daemon/defaults.xml index 5bf096c..39a0f65 100644 --- a/daemon/defaults.xml +++ b/daemon/defaults.xml | |||
@@ -58,5 +58,10 @@ | |||
58 | <configuration counter="Linux_meminfo_memused"/> | 58 | <configuration counter="Linux_meminfo_memused"/> |
59 | <configuration counter="Linux_meminfo_memfree"/> | 59 | <configuration counter="Linux_meminfo_memfree"/> |
60 | <configuration counter="Linux_power_cpu_freq"/> | 60 | <configuration counter="Linux_power_cpu_freq"/> |
61 | <configuration counter="ARM_Mali-4xx_fragment"/> | ||
62 | <configuration counter="ARM_Mali-4xx_vertex"/> | ||
63 | <configuration counter="ARM_Mali-T6xx_fragment" cores="1"/> | ||
64 | <configuration counter="ARM_Mali-T6xx_vertex" cores="1"/> | ||
65 | <configuration counter="ARM_Mali-T6xx_opencl" cores="1"/> | ||
61 | <configuration counter="L2C-310_cnt0" event="0x1"/> | 66 | <configuration counter="L2C-310_cnt0" event="0x1"/> |
62 | </configurations> | 67 | </configurations> |
diff --git a/daemon/escape.c b/daemon/escape.c index c54aa1c..2b0863a 100644 --- a/daemon/escape.c +++ b/daemon/escape.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * The Makefile in the daemon folder builds and executes 'escape' | 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 | 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 | 12 | * these genereated xml files are then #included and built as part of the gatord binary |
diff --git a/daemon/events-CCI-400.xml b/daemon/events-CCI-400.xml index 4fa7711..20002ef 100644 --- a/daemon/events-CCI-400.xml +++ b/daemon/events-CCI-400.xml | |||
@@ -1,7 +1,6 @@ | |||
1 | <counter_set name="cci-400_cnt" count="4"/> | 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"> | 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 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> | 3 | <event counter="CCI_400_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> |
4 | |||
5 | <option_set name="Slave"> | 4 | <option_set name="Slave"> |
6 | <option event_delta="0x00" name="S0" description="Slave interface 0"/> | 5 | <option event_delta="0x00" name="S0" description="Slave interface 0"/> |
7 | <option event_delta="0x20" name="S1" description="Slave interface 1"/> | 6 | <option event_delta="0x20" name="S1" description="Slave interface 1"/> |
@@ -9,7 +8,6 @@ | |||
9 | <option event_delta="0x60" name="S3" description="Slave interface 3"/> | 8 | <option event_delta="0x60" name="S3" description="Slave interface 3"/> |
10 | <option event_delta="0x80" name="S4" description="Slave interface 4"/> | 9 | <option event_delta="0x80" name="S4" description="Slave interface 4"/> |
11 | </option_set> | 10 | </option_set> |
12 | |||
13 | <event event="0x00" option_set="Slave" title="CCI-400" name="Read: any" description="Read request handshake: any"/> | 11 | <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"/> | 12 | <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"/> | 13 | <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"/> |
@@ -30,13 +28,11 @@ | |||
30 | <event event="0x11" option_set="Slave" title="CCI-400" name="Write: WriteLineUnique" description="Write request handshake: WriteLineUnique"/> | 28 | <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"/> | 29 | <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"/> | 30 | <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"> | 31 | <option_set name="Master"> |
35 | <option event_delta="0xa0" name="M0" description="Master interface 0"/> | 32 | <option event_delta="0xa0" name="M0" description="Master interface 0"/> |
36 | <option event_delta="0xc0" name="M1" description="Master interface 1"/> | 33 | <option event_delta="0xc0" name="M1" description="Master interface 1"/> |
37 | <option event_delta="0xe0" name="M2" description="Master interface 2"/> | 34 | <option event_delta="0xe0" name="M2" description="Master interface 2"/> |
38 | </option_set> | 35 | </option_set> |
39 | |||
40 | <event event="0x14" option_set="Master" title="CCI-400" name="Retry fetch" description="RETRY of speculative fetch transaction"/> | 36 | <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"/> | 37 | <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"/> | 38 | <event event="0x16" option_set="Master" title="CCI-400" name="Read stall: ID hazard" description="Read request stall cycle because of an ID hazard"/> |
@@ -45,11 +41,9 @@ | |||
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"/> | 41 | <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"/> | 42 | <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> | 43 | </category> |
48 | 44 | <counter_set name="CCI_400-r1_cnt" count="4"/> | |
49 | <counter_set name="cci-400-r1_cnt" count="4"/> | 45 | <category name="CCI-400" counter_set="CCI_400-r1_cnt" per_cpu="no" supports_event_based_sampling="yes"> |
50 | <category name="CCI-400" counter_set="cci-400-r1_cnt" per_cpu="no" supports_event_based_sampling="yes"> | 46 | <event counter="CCI_400-r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> |
51 | <event counter="cci-400-r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> | ||
52 | |||
53 | <option_set name="Slave"> | 47 | <option_set name="Slave"> |
54 | <option event_delta="0x00" name="S0" description="Slave interface 0"/> | 48 | <option event_delta="0x00" name="S0" description="Slave interface 0"/> |
55 | <option event_delta="0x20" name="S1" description="Slave interface 1"/> | 49 | <option event_delta="0x20" name="S1" description="Slave interface 1"/> |
@@ -57,7 +51,6 @@ | |||
57 | <option event_delta="0x60" name="S3" description="Slave interface 3"/> | 51 | <option event_delta="0x60" name="S3" description="Slave interface 3"/> |
58 | <option event_delta="0x80" name="S4" description="Slave interface 4"/> | 52 | <option event_delta="0x80" name="S4" description="Slave interface 4"/> |
59 | </option_set> | 53 | </option_set> |
60 | |||
61 | <event event="0x00" option_set="Slave" title="CCI-400" name="Read: any" description="Read request handshake: any"/> | 54 | <event event="0x00" option_set="Slave" title="CCI-400" name="Read: any" description="Read request handshake: any"/> |
62 | <event event="0x01" option_set="Slave" title="CCI-400" name="Read: transaction" description="Read request handshake: device transaction"/> | 55 | <event event="0x01" option_set="Slave" title="CCI-400" name="Read: transaction" description="Read request handshake: device transaction"/> |
63 | <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"/> | 56 | <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"/> |
@@ -79,13 +72,11 @@ | |||
79 | <event event="0x12" option_set="Slave" title="CCI-400" name="Write: Evict" description="Write request handshake: Evict"/> | 72 | <event event="0x12" option_set="Slave" title="CCI-400" name="Write: Evict" description="Write request handshake: Evict"/> |
80 | <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"/> | 73 | <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"/> |
81 | <event event="0x14" option_set="Slave" title="CCI-400" name="Read stall: slave hazard" description="Read request stall cycle because of a slave interface ID hazard"/> | 74 | <event event="0x14" option_set="Slave" title="CCI-400" name="Read stall: slave hazard" description="Read request stall cycle because of a slave interface ID hazard"/> |
82 | |||
83 | <option_set name="Master"> | 75 | <option_set name="Master"> |
84 | <option event_delta="0xa0" name="M0" description="Master interface 0"/> | 76 | <option event_delta="0xa0" name="M0" description="Master interface 0"/> |
85 | <option event_delta="0xc0" name="M1" description="Master interface 1"/> | 77 | <option event_delta="0xc0" name="M1" description="Master interface 1"/> |
86 | <option event_delta="0xe0" name="M2" description="Master interface 2"/> | 78 | <option event_delta="0xe0" name="M2" description="Master interface 2"/> |
87 | </option_set> | 79 | </option_set> |
88 | |||
89 | <event event="0x00" option_set="Master" title="CCI-400" name="Retry fetch" description="RETRY of speculative fetch transaction"/> | 80 | <event event="0x00" option_set="Master" title="CCI-400" name="Retry fetch" description="RETRY of speculative fetch transaction"/> |
90 | <event event="0x01" option_set="Master" title="CCI-400" name="Read stall: address hazard" description="Stall cycle because of an address hazard. A read or write invalidation is stalled because of an outstanding transaction to an overlapping address"/> | 81 | <event event="0x01" option_set="Master" title="CCI-400" name="Read stall: address hazard" description="Stall cycle because of an address hazard. A read or write invalidation is stalled because of an outstanding transaction to an overlapping address"/> |
91 | <event event="0x02" option_set="Master" title="CCI-400" name="Read stall: ID hazard" description="Read request stall cycle because of a master interface ID hazard"/> | 82 | <event event="0x02" option_set="Master" title="CCI-400" name="Read stall: ID hazard" description="Read request stall cycle because of a master interface ID hazard"/> |
diff --git a/daemon/events-CCN-504.xml b/daemon/events-CCN-504.xml index cfabf65..6ef3e64 100644 --- a/daemon/events-CCN-504.xml +++ b/daemon/events-CCN-504.xml | |||
@@ -1,7 +1,6 @@ | |||
1 | <counter_set name="CCN-504_cnt" count="4"/> | 1 | <counter_set name="CCN-504_cnt" count="4"/> |
2 | <category name="CCN-504" counter_set="CCN-504_cnt"> | 2 | <category name="CCN-504" counter_set="CCN-504_cnt"> |
3 | <event counter="CCN-504_ccnt" title="CCN-504 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> | 3 | <event counter="CCN-504_ccnt" title="CCN-504 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/> |
4 | |||
5 | <option_set name="XP_Region"> | 4 | <option_set name="XP_Region"> |
6 | <option event_delta="0x400000" name="XP 0" description="Crosspoint 0"/> | 5 | <option event_delta="0x400000" name="XP 0" description="Crosspoint 0"/> |
7 | <option event_delta="0x410000" name="XP 1" description="Crosspoint 1"/> | 6 | <option event_delta="0x410000" name="XP 1" description="Crosspoint 1"/> |
@@ -15,7 +14,6 @@ | |||
15 | <option event_delta="0x490000" name="XP 9" description="Crosspoint 9"/> | 14 | <option event_delta="0x490000" name="XP 9" description="Crosspoint 9"/> |
16 | <option event_delta="0x4A0000" name="XP 10" description="Crosspoint 10"/> | 15 | <option event_delta="0x4A0000" name="XP 10" description="Crosspoint 10"/> |
17 | </option_set> | 16 | </option_set> |
18 | |||
19 | <event event="0x0801" option_set="XP_Region" title="CCN-504" name="Bus 0: REQ: H-bit" description="Bus 0: REQ: Set H-bit, signaled when this XP sets the H-bit."/> | 17 | <event event="0x0801" option_set="XP_Region" title="CCN-504" name="Bus 0: REQ: H-bit" description="Bus 0: REQ: Set H-bit, signaled when this XP sets the H-bit."/> |
20 | <event event="0x0802" option_set="XP_Region" title="CCN-504" name="Bus 0: REQ: S-bit" description="Bus 0: REQ: Set S-bit, signaled when this XP sets the S-bit."/> | 18 | <event event="0x0802" option_set="XP_Region" title="CCN-504" name="Bus 0: REQ: S-bit" description="Bus 0: REQ: Set S-bit, signaled when this XP sets the S-bit."/> |
21 | <event event="0x0803" option_set="XP_Region" title="CCN-504" name="Bus 0: REQ: P-Cnt" description="Bus 0: REQ: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/> | 19 | <event event="0x0803" option_set="XP_Region" title="CCN-504" name="Bus 0: REQ: P-Cnt" description="Bus 0: REQ: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/> |
@@ -56,7 +54,6 @@ | |||
56 | <event event="0x087A" option_set="XP_Region" title="CCN-504" name="Bus 1: DATB: S-bit" description="Bus 1: DATB: Set S-bit, signaled when this XP sets the S-bit."/> | 54 | <event event="0x087A" option_set="XP_Region" title="CCN-504" name="Bus 1: DATB: S-bit" description="Bus 1: DATB: Set S-bit, signaled when this XP sets the S-bit."/> |
57 | <event event="0x087B" option_set="XP_Region" title="CCN-504" name="Bus 1: DATB: P-Cnt" description="Bus 1: DATB: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/> | 55 | <event event="0x087B" option_set="XP_Region" title="CCN-504" name="Bus 1: DATB: P-Cnt" description="Bus 1: DATB: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/> |
58 | <event event="0x087C" option_set="XP_Region" title="CCN-504" name="Bus 1: DATB: TknV" description="Bus 1: DATB: No TknV, signaled when this XP transmits a valid packet."/> | 56 | <event event="0x087C" option_set="XP_Region" title="CCN-504" name="Bus 1: DATB: TknV" description="Bus 1: DATB: No TknV, signaled when this XP transmits a valid packet."/> |
59 | |||
60 | <option_set name="HN-F_Region"> | 57 | <option_set name="HN-F_Region"> |
61 | <option event_delta="0x200000" name="HN-F 3" description="Fully-coherent Home Node 3"/> | 58 | <option event_delta="0x200000" name="HN-F 3" description="Fully-coherent Home Node 3"/> |
62 | <option event_delta="0x210000" name="HN-F 5" description="Fully-coherent Home Node 5"/> | 59 | <option event_delta="0x210000" name="HN-F 5" description="Fully-coherent Home Node 5"/> |
@@ -67,7 +64,6 @@ | |||
67 | <option event_delta="0x260000" name="HN-F 17" description="Fully-coherent Home Node 17"/> | 64 | <option event_delta="0x260000" name="HN-F 17" description="Fully-coherent Home Node 17"/> |
68 | <option event_delta="0x270000" name="HN-F 18" description="Fully-coherent Home Node 18"/> | 65 | <option event_delta="0x270000" name="HN-F 18" description="Fully-coherent Home Node 18"/> |
69 | </option_set> | 66 | </option_set> |
70 | |||
71 | <event event="0x0401" option_set="HN-F_Region" title="CCN-504" name="Cache Miss" description="Counts the total cache misses. This is the first time lookup result, and is high priority."/> | 67 | <event event="0x0401" option_set="HN-F_Region" title="CCN-504" name="Cache Miss" description="Counts the total cache misses. This is the first time lookup result, and is high priority."/> |
72 | <event event="0x0402" option_set="HN-F_Region" title="CCN-504" name="L3 SF Cache Access" description="Counts the number of cache accesses. This is the first time access, and is high priority."/> | 68 | <event event="0x0402" option_set="HN-F_Region" title="CCN-504" name="L3 SF Cache Access" description="Counts the number of cache accesses. This is the first time access, and is high priority."/> |
73 | <event event="0x0403" option_set="HN-F_Region" title="CCN-504" name="Cache Fill" description="Counts the total allocations in the HN L3 cache, and all cache line allocations to the L3 cache."/> | 69 | <event event="0x0403" option_set="HN-F_Region" title="CCN-504" name="Cache Fill" description="Counts the total allocations in the HN L3 cache, and all cache line allocations to the L3 cache."/> |
@@ -82,7 +78,6 @@ | |||
82 | <event event="0x040C" option_set="HN-F_Region" title="CCN-504" name="MC Retries" description="Counts the number of transactions retried by the memory controller."/> | 78 | <event event="0x040C" option_set="HN-F_Region" title="CCN-504" name="MC Retries" description="Counts the number of transactions retried by the memory controller."/> |
83 | <event event="0x040D" option_set="HN-F_Region" title="CCN-504" name="MC Reqs" description="Counts the number of requests to the memory controller."/> | 79 | <event event="0x040D" option_set="HN-F_Region" title="CCN-504" name="MC Reqs" description="Counts the number of requests to the memory controller."/> |
84 | <event event="0x040E" option_set="HN-F_Region" title="CCN-504" name="QOS HH Retry" description="Counts the number of times a highest-priority QoS class was retried at the HN-F."/> | 80 | <event event="0x040E" option_set="HN-F_Region" title="CCN-504" name="QOS HH Retry" description="Counts the number of times a highest-priority QoS class was retried at the HN-F."/> |
85 | |||
86 | <option_set name="RN-I_Region"> | 81 | <option_set name="RN-I_Region"> |
87 | <option event_delta="0x800000" name="RN-I 0" description="I/O-coherent Requesting Node 0"/> | 82 | <option event_delta="0x800000" name="RN-I 0" description="I/O-coherent Requesting Node 0"/> |
88 | <option event_delta="0x820000" name="RN-I 2" description="I/O-coherent Requesting Node 2"/> | 83 | <option event_delta="0x820000" name="RN-I 2" description="I/O-coherent Requesting Node 2"/> |
@@ -91,7 +86,6 @@ | |||
91 | <option event_delta="0x900000" name="RN-I 16" description="I/O-coherent Requesting Node 16"/> | 86 | <option event_delta="0x900000" name="RN-I 16" description="I/O-coherent Requesting Node 16"/> |
92 | <option event_delta="0x940000" name="RN-I 20" description="I/O-coherent Requesting Node 20"/> | 87 | <option event_delta="0x940000" name="RN-I 20" description="I/O-coherent Requesting Node 20"/> |
93 | </option_set> | 88 | </option_set> |
94 | |||
95 | <event event="0x1601" option_set="RN-I_Region" title="CCN-504" name="S0 RDataBeats" description="S0 RDataBeats."/> | 89 | <event event="0x1601" option_set="RN-I_Region" title="CCN-504" name="S0 RDataBeats" description="S0 RDataBeats."/> |
96 | <event event="0x1602" option_set="RN-I_Region" title="CCN-504" name="S1 RDataBeats" description="S1 RDataBeats."/> | 90 | <event event="0x1602" option_set="RN-I_Region" title="CCN-504" name="S1 RDataBeats" description="S1 RDataBeats."/> |
97 | <event event="0x1603" option_set="RN-I_Region" title="CCN-504" name="S2 RDataBeats" description="S2 RDataBeats."/> | 91 | <event event="0x1603" option_set="RN-I_Region" title="CCN-504" name="S2 RDataBeats" description="S2 RDataBeats."/> |
@@ -102,14 +96,12 @@ | |||
102 | <event event="0x1608" option_set="RN-I_Region" title="CCN-504" name="RRT full" description="RRT full."/> | 96 | <event event="0x1608" option_set="RN-I_Region" title="CCN-504" name="RRT full" description="RRT full."/> |
103 | <event event="0x1609" option_set="RN-I_Region" title="CCN-504" name="WRT full" description="WRT full."/> | 97 | <event event="0x1609" option_set="RN-I_Region" title="CCN-504" name="WRT full" description="WRT full."/> |
104 | <event event="0x160A" option_set="RN-I_Region" title="CCN-504" name="Replayed TXREQ Flits" description="Replayed TXREQ Flits."/> | 98 | <event event="0x160A" option_set="RN-I_Region" title="CCN-504" name="Replayed TXREQ Flits" description="Replayed TXREQ Flits."/> |
105 | |||
106 | <option_set name="SBAS_Region"> | 99 | <option_set name="SBAS_Region"> |
107 | <option event_delta="0x810000" name="SBAS 1" description="ACE master to CHI protocol bridge 1"/> | 100 | <option event_delta="0x810000" name="SBAS 1" description="ACE master to CHI protocol bridge 1"/> |
108 | <option event_delta="0x890000" name="SBAS 9" description="ACE master to CHI protocol bridge 9"/> | 101 | <option event_delta="0x890000" name="SBAS 9" description="ACE master to CHI protocol bridge 9"/> |
109 | <option event_delta="0x8B0000" name="SBAS 11" description="ACE master to CHI protocol bridge 11"/> | 102 | <option event_delta="0x8B0000" name="SBAS 11" description="ACE master to CHI protocol bridge 11"/> |
110 | <option event_delta="0x930000" name="SBAS 19" description="ACE master to CHI protocol bridge 19"/> | 103 | <option event_delta="0x930000" name="SBAS 19" description="ACE master to CHI protocol bridge 19"/> |
111 | </option_set> | 104 | </option_set> |
112 | |||
113 | <event event="0x1001" option_set="SBAS_Region" title="CCN-504" name="S0 RDataBeats" description="S0 RDataBeats."/> | 105 | <event event="0x1001" option_set="SBAS_Region" title="CCN-504" name="S0 RDataBeats" description="S0 RDataBeats."/> |
114 | <event event="0x1004" option_set="SBAS_Region" title="CCN-504" name="RXDAT Flits received" description="RXDAT Flits received."/> | 106 | <event event="0x1004" option_set="SBAS_Region" title="CCN-504" name="RXDAT Flits received" description="RXDAT Flits received."/> |
115 | <event event="0x1005" option_set="SBAS_Region" title="CCN-504" name="TXDAT Flits sent" description="TXDAT Flits sent."/> | 107 | <event event="0x1005" option_set="SBAS_Region" title="CCN-504" name="TXDAT Flits sent" description="TXDAT Flits sent."/> |
@@ -118,5 +110,4 @@ | |||
118 | <event event="0x1008" option_set="SBAS_Region" title="CCN-504" name="RRT full" description="RRT full."/> | 110 | <event event="0x1008" option_set="SBAS_Region" title="CCN-504" name="RRT full" description="RRT full."/> |
119 | <event event="0x1009" option_set="SBAS_Region" title="CCN-504" name="WRT full" description="WRT full."/> | 111 | <event event="0x1009" option_set="SBAS_Region" title="CCN-504" name="WRT full" description="WRT full."/> |
120 | <event event="0x100A" option_set="SBAS_Region" title="CCN-504" name="Replayed TXREQ Flits" description="Replayed TXREQ Flits."/> | 112 | <event event="0x100A" option_set="SBAS_Region" title="CCN-504" name="Replayed TXREQ Flits" description="Replayed TXREQ Flits."/> |
121 | |||
122 | </category> | 113 | </category> |
diff --git a/daemon/events-Cortex-A53.xml b/daemon/events-Cortex-A53.xml index 577dcd9..5ba1790 100644 --- a/daemon/events-Cortex-A53.xml +++ b/daemon/events-Cortex-A53.xml | |||
@@ -1,171 +1,87 @@ | |||
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 --> | ||
4 | <event counter="ARM_Cortex-A53_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> | 3 | <event counter="ARM_Cortex-A53_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> |
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"/> | 4 | <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 --> | ||
8 | <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"/> |
9 | <!-- 0x02 L1I_TLB_REFILL - Level 1 instruction TLB refill --> | ||
10 | <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"/> |
11 | <!-- 0x03 L1D_CACHE_REFILL - Level 1 data cache refill --> | ||
12 | <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/> | 7 | <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/> |
13 | <!-- 0x04 L1D_CACHE - Level 1 data cache access --> | ||
14 | <event event="0x04" title="Cache" name="Data access" 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"/> | 8 | <event event="0x04" title="Cache" name="Data access" 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"/> |
15 | <!-- 0x05 L1D_TLB_REFILL - Level 1 data TLB refill --> | ||
16 | <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/> | 9 | <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/> |
17 | <!-- 0x08 INST_RETIRED - Instruction architecturally executed --> | ||
18 | <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/> | 10 | <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/> |
19 | <!-- 0x09 EXC_TAKEN - Exception taken --> | ||
20 | <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/> | 11 | <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/> |
21 | <!-- 0x0A EXC_RETURN - Instruction architecturally executed (condition check pass) - Exception return --> | ||
22 | <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/> | 12 | <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/> |
23 | <!-- 0x0B CID_WRITE_RETIRED - Instruction architecturally executed (condition check pass) - Write to CONTEXTIDR --> | ||
24 | <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/> | 13 | <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/> |
25 | <!-- 0x10 BR_MIS_PRED - Mispredicted or not predicted branch speculatively executed --> | ||
26 | <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/> | 14 | <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/> |
27 | <!-- 0x12 BR_PRED - Predictable branch speculatively executed --> | ||
28 | <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"/> | 15 | <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"/> |
29 | <!-- 0x13 MEM_ACCESS - Data memory access --> | ||
30 | <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/> | 16 | <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/> |
31 | <!-- 0x14 L1I_CACHE - Level 1 instruction cache access --> | ||
32 | <event event="0x14" title="Cache" name="L1 inst access" description="Level 1 instruction cache access"/> | 17 | <event event="0x14" title="Cache" name="L1 inst access" description="Level 1 instruction cache access"/> |
33 | <!-- 0x15 L1D_CACHE_WB - Level 1 data cache Write-Back --> | ||
34 | <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/> | 18 | <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/> |
35 | <!-- 0x16 L2D_CACHE - Level 2 data cache access --> | ||
36 | <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"/> |
37 | <!-- 0x17 L2D_CACHE_REFILL - Level 2 data cache refill --> | ||
38 | <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"/> |
39 | <!-- 0x18 L2D_CACHE_WB - Level 2 data cache Write-Back --> | ||
40 | <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"/> |
41 | <!-- 0x19 BUS_ACCESS - Bus access --> | ||
42 | <event event="0x19" title="Bus" name="Access" description="Bus access"/> | 22 | <event event="0x19" title="Bus" name="Access" description="Bus access"/> |
43 | <!-- 0x1A MEMORY_ERROR - Local memory error --> | ||
44 | <event event="0x1A" title="Memory" name="Error" description="Local memory error"/> | 23 | <event event="0x1A" title="Memory" name="Error" description="Local memory error"/> |
45 | <!-- 0x1B INST_SPEC - Operation speculatively executed --> | ||
46 | <event event="0x1B" title="Instruction" name="Speculative" description="Operation speculatively executed"/> | 24 | <event event="0x1B" title="Instruction" name="Speculative" description="Operation speculatively executed"/> |
47 | <!-- 0x1C TTBR_WRITE_RETIRED - Instruction architecturally executed (condition check pass) - Write to translation table base --> | ||
48 | <event event="0x1C" title="Memory" name="Translation table" description="Instruction architecturally executed (condition check pass) - Write to translation table base"/> | 25 | <event event="0x1C" title="Memory" name="Translation table" description="Instruction architecturally executed (condition check pass) - Write to translation table base"/> |
49 | <!-- 0x1D BUS_CYCLES - Bus cycle --> | ||
50 | <event event="0x1D" title="Bus" name="Cycle" description="Bus cycle"/> | 26 | <event event="0x1D" title="Bus" name="Cycle" description="Bus cycle"/> |
51 | <!-- 0x1E CHAIN - Odd performance counter chain mode --> | ||
52 | <event event="0x1E" title="Counter chain" name="Odd Performance" description="Odd performance counter chain mode"/> | 27 | <event event="0x1E" title="Counter chain" name="Odd Performance" description="Odd performance counter chain mode"/> |
53 | <!-- 0x40 L1D_CACHE_LD - Level 1 data cache access - Read --> | ||
54 | <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/> | 28 | <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/> |
55 | <!-- 0x41 L1D_CACHE_ST - Level 1 data cache access - Write --> | ||
56 | <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/> | 29 | <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/> |
57 | <!-- 0x42 L1D_CACHE_REFILL_LD - Level 1 data cache refill - Read --> | ||
58 | <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/> | 30 | <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/> |
59 | <!-- 0x43 L1D_CACHE_REFILL_ST - Level 1 data cache refill - Write --> | ||
60 | <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/> | 31 | <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/> |
61 | <!-- 0x46 L1D_CACHE_WB_VICTIM - Level 1 data cache Write-back - Victim --> | ||
62 | <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-back - Victim"/> | 32 | <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-back - Victim"/> |
63 | <!-- 0x47 L1D_CACHE_WB_CLEAN - Level 1 data cache Write-back - Cleaning and coherency --> | ||
64 | <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-back - Cleaning and coherency"/> | 33 | <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-back - Cleaning and coherency"/> |
65 | <!-- 0x48 L1D_CACHE_INVAL - Level 1 data cache invalidate --> | ||
66 | <event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/> | 34 | <event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/> |
67 | <!-- 0x4C L1D_TLB_REFILL_LD - Level 1 data TLB refill - Read --> | ||
68 | <event event="0x4C" title="Cache" name="L1 data refill read" description="Level 1 data TLB refill - Read"/> | 35 | <event event="0x4C" title="Cache" name="L1 data refill read" description="Level 1 data TLB refill - Read"/> |
69 | <!-- 0x4D L1D_TLB_REFILL_ST - Level 1 data TLB refill - Write --> | ||
70 | <event event="0x4D" title="Cache" name="L1 data refill write" description="Level 1 data TLB refill - Write"/> | 36 | <event event="0x4D" title="Cache" name="L1 data refill write" description="Level 1 data TLB refill - Write"/> |
71 | <!-- 0x50 L2D_CACHE_LD - Level 2 data cache access - Read --> | ||
72 | <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/> | 37 | <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/> |
73 | <!-- 0x51 L2D_CACHE_ST - Level 2 data cache access - Write --> | ||
74 | <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/> | 38 | <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/> |
75 | <!-- 0x52 L2D_CACHE_REFILL_LD - Level 2 data cache refill - Read --> | ||
76 | <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/> | 39 | <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/> |
77 | <!-- 0x53 L2D_CACHE_REFILL_ST - Level 2 data cache refill - Write --> | ||
78 | <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/> | 40 | <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/> |
79 | <!-- 0x56 L2D_CACHE_WB_VICTIM - Level 2 data cache Write-back - Victim --> | ||
80 | <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-back - Victim"/> | 41 | <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-back - Victim"/> |
81 | <!-- 0x57 L2D_CACHE_WB_CLEAN - Level 2 data cache Write-back - Cleaning and coherency --> | ||
82 | <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-back - Cleaning and coherency"/> | 42 | <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-back - Cleaning and coherency"/> |
83 | <!-- 0x58 L2D_CACHE_INVAL - Level 2 data cache invalidate --> | ||
84 | <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/> | 43 | <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/> |
85 | <!-- 0x60 BUS_ACCESS_LD - Bus access - Read --> | ||
86 | <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/> | 44 | <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/> |
87 | <!-- 0x61 BUS_ACCESS_ST - Bus access - Write --> | ||
88 | <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/> | 45 | <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/> |
89 | <!-- 0x62 BUS_ACCESS_SHARED - Bus access - Normal --> | ||
90 | <event event="0x62" title="Bus" name="Access shared" description="Bus access - Normal"/> | 46 | <event event="0x62" title="Bus" name="Access shared" description="Bus access - Normal"/> |
91 | <!-- 0x63 BUS_ACCESS_NOT_SHARED - Bus access - Not normal --> | ||
92 | <event event="0x63" title="Bus" name="Access not shared" description="Bus access - Not normal"/> | 47 | <event event="0x63" title="Bus" name="Access not shared" description="Bus access - Not normal"/> |
93 | <!-- 0x64 BUS_ACCESS_NORMAL - Bus access - Normal --> | ||
94 | <event event="0x64" title="Bus" name="Access normal" description="Bus access - Normal"/> |