aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrew Richardson <drew.richardson@arm.com>2014-10-22 12:00:00 -0700
committerDrew Richardson <drew.richardson@arm.com>2014-12-19 15:59:12 -0800
commitecc3d86ea62f7be7defa303d1d14b8506ec63e75 (patch)
tree4a0c3fb31869e2eca869f3eb2d35c6d1391ecd68
parent6a98fbff8b9f8a23045efdea51784b479cefac7f (diff)
gator: Version 5.205.20
Signed-off-by: Drew Richardson <drew.richardson@arm.com>
-rw-r--r--README_Streamline.txt44
-rw-r--r--daemon/Android.mk17
-rw-r--r--daemon/AnnotateListener.cpp69
-rw-r--r--daemon/AnnotateListener.h31
-rw-r--r--daemon/Application.mk2
-rw-r--r--daemon/Buffer.cpp201
-rw-r--r--daemon/Buffer.h38
-rw-r--r--daemon/CCNDriver.cpp295
-rw-r--r--daemon/CCNDriver.h43
-rw-r--r--daemon/CPUFreqDriver.cpp58
-rw-r--r--daemon/CPUFreqDriver.h34
-rw-r--r--daemon/CapturedXML.cpp17
-rw-r--r--daemon/CapturedXML.h4
-rw-r--r--daemon/Child.cpp82
-rw-r--r--daemon/Child.h4
-rw-r--r--daemon/Command.cpp172
-rw-r--r--daemon/Command.h14
-rw-r--r--daemon/Config.h13
-rw-r--r--daemon/DiskIODriver.cpp125
-rw-r--r--daemon/DiskIODriver.h39
-rw-r--r--daemon/Driver.cpp81
-rw-r--r--daemon/Driver.h76
-rw-r--r--daemon/DriverSource.cpp19
-rw-r--r--daemon/DynBuf.cpp2
-rw-r--r--daemon/EventsXML.cpp2
-rw-r--r--daemon/ExternalSource.cpp87
-rw-r--r--daemon/ExternalSource.h8
-rw-r--r--daemon/FSDriver.cpp140
-rw-r--r--daemon/FSDriver.h19
-rw-r--r--daemon/Fifo.cpp5
-rw-r--r--daemon/Fifo.h10
-rw-r--r--daemon/FtraceDriver.cpp118
-rw-r--r--daemon/FtraceDriver.h31
-rw-r--r--daemon/FtraceSource.cpp158
-rw-r--r--daemon/FtraceSource.h43
-rw-r--r--daemon/Hwmon.h45
-rw-r--r--daemon/HwmonDriver.cpp (renamed from daemon/Hwmon.cpp)213
-rw-r--r--daemon/HwmonDriver.h31
-rw-r--r--daemon/KMod.cpp9
-rw-r--r--daemon/KMod.h7
-rw-r--r--daemon/LocalCapture.h4
-rw-r--r--daemon/Logging.cpp18
-rw-r--r--daemon/Logging.h12
-rw-r--r--daemon/Makefile5
-rw-r--r--daemon/MaliVideoDriver.cpp148
-rw-r--r--daemon/MaliVideoDriver.h17
-rw-r--r--daemon/MemInfoDriver.cpp93
-rw-r--r--daemon/MemInfoDriver.h37
-rw-r--r--daemon/Monitor.cpp14
-rw-r--r--daemon/NetDriver.cpp129
-rw-r--r--daemon/NetDriver.h39
-rw-r--r--daemon/OlySocket.cpp54
-rw-r--r--daemon/OlySocket.h9
-rw-r--r--daemon/PerfBuffer.cpp65
-rw-r--r--daemon/PerfBuffer.h4
-rw-r--r--daemon/PerfDriver.cpp194
-rw-r--r--daemon/PerfDriver.h15
-rw-r--r--daemon/PerfGroup.cpp66
-rw-r--r--daemon/PerfGroup.h14
-rw-r--r--daemon/PerfSource.cpp306
-rw-r--r--daemon/PerfSource.h3
-rw-r--r--daemon/Proc.cpp137
-rw-r--r--daemon/Proc.h6
-rw-r--r--daemon/Sender.cpp7
-rw-r--r--daemon/Sender.h4
-rw-r--r--daemon/SessionData.cpp91
-rw-r--r--daemon/SessionData.h44
-rw-r--r--daemon/SessionXML.cpp40
-rw-r--r--daemon/SessionXML.h12
-rw-r--r--daemon/Setup.cpp232
-rw-r--r--daemon/Setup.h18
-rw-r--r--daemon/StreamlineSetup.h4
-rw-r--r--daemon/UEvent.cpp3
-rw-r--r--daemon/UserSpaceSource.cpp23
-rw-r--r--daemon/defaults.xml27
-rw-r--r--daemon/events-Cortex-A17.xml (renamed from daemon/events-Cortex-A12.xml)8
-rw-r--r--daemon/events-Filesystem.xml12
-rw-r--r--daemon/events-Linux.xml11
-rw-r--r--daemon/events-Mali-T60x_hw.xml2
-rw-r--r--daemon/events-Mali-T62x_hw.xml2
-rw-r--r--daemon/events-Mali-T72x_hw.xml4
-rw-r--r--daemon/events-Mali-T76x_hw.xml2
-rw-r--r--daemon/events-Mali-V500.xml55
-rw-r--r--daemon/events-ftrace.xml7
-rw-r--r--daemon/main.cpp95
-rw-r--r--daemon/mxml/config.h10
-rw-r--r--daemon/mxml/mxml-attr.c19
-rw-r--r--daemon/mxml/mxml-entity.c19
-rw-r--r--daemon/mxml/mxml-file.c104
-rw-r--r--daemon/mxml/mxml-get.c27
-rw-r--r--daemon/mxml/mxml-index.c11
-rw-r--r--daemon/mxml/mxml-node.c31
-rw-r--r--daemon/mxml/mxml-private.c42
-rw-r--r--daemon/mxml/mxml-private.h8
-rw-r--r--daemon/mxml/mxml-search.c17
-rw-r--r--daemon/mxml/mxml-set.c20
-rw-r--r--daemon/mxml/mxml-string.c21
-rw-r--r--daemon/mxml/mxml.h17
-rw-r--r--driver/Makefile6
-rw-r--r--driver/gator.h37
-rw-r--r--driver/gator_annotate.c67
-rw-r--r--driver/gator_annotate_kernel.c30
-rw-r--r--driver/gator_backtrace.c66
-rw-r--r--driver/gator_buffer.c71
-rw-r--r--driver/gator_buffer_write.c19
-rw-r--r--driver/gator_cookies.c67
-rw-r--r--driver/gator_events_armv6.c47
-rw-r--r--driver/gator_events_armv7.c90
-rw-r--r--driver/gator_events_block.c29
-rw-r--r--driver/gator_events_ccn-504.c346
-rw-r--r--driver/gator_events_irq.c14
-rw-r--r--driver/gator_events_l2c-310.c6
-rw-r--r--driver/gator_events_mali_4xx.c171
-rw-r--r--driver/gator_events_mali_common.c21
-rw-r--r--driver/gator_events_mali_common.h17
-rw-r--r--driver/gator_events_mali_midgard.c95
-rw-r--r--driver/gator_events_mali_midgard_hw.c311
-rw-r--r--driver/gator_events_mali_midgard_hw_test.c8
-rw-r--r--driver/gator_events_meminfo.c197
-rw-r--r--driver/gator_events_mmapped.c6
-rw-r--r--driver/gator_events_net.c22
-rw-r--r--driver/gator_events_perf_pmu.c207
-rw-r--r--driver/gator_events_sched.c14
-rw-r--r--driver/gator_events_scorpion.c81
-rw-r--r--driver/gator_events_threads.c115
-rw-r--r--driver/gator_fs.c9
-rw-r--r--driver/gator_hrtimer_gator.c8
-rw-r--r--driver/gator_iks.c22
-rw-r--r--driver/gator_main.c345
-rw-r--r--driver/gator_marshaling.c73
-rw-r--r--driver/gator_trace_gpu.c74
-rw-r--r--driver/gator_trace_power.c61
-rw-r--r--driver/gator_trace_sched.c104
-rw-r--r--driver/mali/mali_mjollnir_profiling_gator_api.h192
-rw-r--r--driver/mali/mali_utgard_profiling_gator_api.h214
135 files changed, 4942 insertions, 3164 deletions
diff --git a/README_Streamline.txt b/README_Streamline.txt
index 54791c0..7b108d4 100644
--- a/README_Streamline.txt
+++ b/README_Streamline.txt
@@ -2,7 +2,7 @@
*** Purpose ***
Instructions on setting up ARM Streamline on the target.
-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.
+A target agent (gator) is required to run on the ARM Linux target in order for ARM Streamline to operate. Gator may run in kernel space or user space mode, though user space gator requires Linux 3.4 or later and contains reduced functionality. Furthermore, user space gator is a beta release, see the bugs section in this readme for a list of known issues.
The driver should be built as a module and the daemon must run with root permissions on the target.
*** Introduction ***
@@ -35,13 +35,14 @@ menuconfig options (depending on the kernel version, the location of these confi
- [*] Tracers
- [*] Trace process context switches and events (#)
-(#) The "Trace process context switches and events" is not the only option that enables tracing (CONFIG_GENERIC_TRACER or CONFIG_TRACING) and may not be visible in menuconfig as an option if other trace configurations are enabled. Other trace configurations being enabled is sufficient to turn on tracing.
+(#) The "Trace process context switches and events" is not the only option that enables tracing (CONFIG_GENERIC_TRACER or CONFIG_TRACING as well as CONFIG_CONTEXT_SWITCH_TRACER) and may not be visible in menuconfig as an option if other trace configurations are enabled. Other trace configurations being enabled is sufficient to turn on tracing.
The configuration options:
CONFIG_GENERIC_TRACER or CONFIG_TRACING
+CONFIG_CONTEXT_SWITCH_TRACER
CONFIG_PROFILING
CONFIG_HIGH_RES_TIMERS
-CONFIG_LOCAL_TIMERS (for SMP systems)
+CONFIG_LOCAL_TIMERS (for SMP systems and kernel versions before 3.12)
CONFIG_PERF_EVENTS and CONFIG_HW_PERF_EVENTS (kernel versions 3.0 and greater)
CONFIG_DEBUG_INFO (optional, used for analyzing the kernel)
CONFIG_CPU_FREQ (optional, provides frequency setting of the CPU)
@@ -90,7 +91,7 @@ For Linux targets,
make CROSS_COMPILE=<...> # For ARMv7 targets
make -f Makefile_aarch64 CROSS_COMPILE=<...> # For ARMv8 targets
gatord should now be created
-For Android targets (install the android ndk, see developer.android.com)
+For Android targets (install the Android NDK appropriate for your target (ndk32 for 32-bit targets and ndk64 for 64-bit targets), see developer.android.com)
mv gator-daemon jni
ndk-build
or execute /path/to/ndk/ndk-build if the ndk is not on your path
@@ -98,6 +99,7 @@ For Android targets (install the android ndk, see developer.android.com)
If you get an error like the following, upgrade to a more recent version of the android ndk
jni/PerfGroup.cpp: In function 'int sys_perf_event_open(perf_event_attr*, pid_t, int, int, long unsigned int)':
jni/PerfGroup.cpp:36:17: error: '__NR_perf_event_open' was not declared in this scope
+ To build gatord for aarch64 edit jni/Application.mk and replace armeabi-v7a with arm64-v8a. To build for ARM11 jni/Application.mk and replace armeabi-v7a with armeabi.
*** Running gator ***
@@ -117,9 +119,15 @@ The l2c-310 counter in gator_events_l2c-310.c contains hard coded offsets where
Further, the l2c-310 counter can be disabled by providing an offset of zero, ex:
insmod gator.ko l2c310_addr=0
-*** CCN-504 ***
+*** Perf PMU support ***
-CCN-504 is disabled by default. To enable CCN-504, insmod gator module with the ccn504_addr=<addr> parameter where addr is the base address of the CCN-504 configuration register space (PERIPHBASE), ex: insmod gator.ko ccn504_addr=0x2E000000.
+To check the perf PMUs support by your kernel, run
+ ls /sys/bus/event_source/devices/
+If you see something like ARMv7_Cortex_A## this indicates A## support. If you see CCI_400 this indicates CCI-400 support. If you see ccn, it indicates CCN support.
+
+*** CCN ***
+
+CCN requires a perf driver to work. The necessary perf driver has been merged into Linux 3.17 but can be backported to previous versions (see https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/diff/?id=a33b0daab73a0e08cc04459dd44b0121a8e8f81b and later bugfixes)
*** Compiling an application or shared library ***
@@ -127,7 +135,7 @@ Recommended compiler settings:
"-g": Debug information, such as line numbers, needed for best analysis results.
"-fno-inline": Speed improvement when processing the image files and most accurate analysis results.
"-fno-omit-frame-pointer": ARM EABI frame pointers allow recording of the call stack with each sample taken when in ARM state (i.e. not -mthumb).
- "-marm": This option is required if your compiler is configured with --with-mode=thumb, otherwise call stack unwinding will not work.
+ "-marm": This option is required for ARMv7 and earlier if your compiler is configured with --with-mode=thumb, otherwise call stack unwinding will not work.
*** Hardfloat EABI ***
Binary applications built for the soft or softfp ABI are not compatible on a hardfloat system. All soft/softfp applications need to be rebuilt for hardfloat. To see if your ARM compiler supports hardfloat, run "gcc -v" and look for --with-float=hard.
@@ -153,7 +161,7 @@ Mali-4xx:
Mali-T6xx/T7xx:
___To add Mali-T6xx support to gator___
- GATOR_WITH_MALI_SUPPORT=MALI_T6xx # Set by CONFIG_GATOR_MALI_T6XX
+ GATOR_WITH_MALI_SUPPORT=MALI_MIDGARD # Set by CONFIG_GATOR_MALI_MIDGARD
DDK_DIR=".../path/to/Mali_DDK_kernel_files" # gator source needs access to headers under .../kernel/drivers/gpu/arm/...
# (default of . suitable for in-tree builds)
___To add the corresponding support to Mali___
@@ -166,20 +174,22 @@ Gator supports reading arbitrary /dev, /sys and /proc files 10 times a second. I
*** Bugs ***
+User space gator is in beta release with known issues. Please note that based on the kernel version and target configuration, the data presented may be incorrect and unexpected behavior can occur including crashing the target kernel. If you experience any of these issues, please use kernel space gator.
+
+There is a bug in some Linux kernels where an Oops may occur when a core is offlined (user space gator only). The fix was merged into mainline in 3.14-rc5, see http://git.kernel.org/tip/e3703f8cdfcf39c25c4338c3ad8e68891cca3731, and has been backported to older kernels (3.4.83, 3.10.33, 3.12.14 and 3.13.6).
+
+"CPU PMU: CPUx reading wrong counter -1" in dmesg (user space gator only). To work around, update to the latest Linux kernel or use kernel space gator.
+
+Scheduler switch resolutions are on exact millisecond boundaries (user space gator only). To work around, update to the latest Linux kernel or use kernel space gator.
+
There is a bug in some Linux kernels where perf misidentifies the CPU type. To see if you are affected by this, run ls /sys/bus/event_source/devices/ and verify the listed processor type matches what is expected. For example, an A9 should show the following.
# ls /sys/bus/event_source/devices/
ARMv7_Cortex_A9 breakpoint software tracepoint
To work around the issue try upgrading to a later kernel or comment out the gator_events_perf_pmu_cpu_init(gator_cpu, type); call in gator_events_perf_pmu.c
-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.
-
-If you see this error when using SELinux, ex: Android 4.4 or later
- # ./gatord
- Unable to load (insmod) gator.ko driver:
- >>> gator.ko must be built against the current kernel version & configuration
- >>> See dmesg for more details
- # dmesg
- ...
+If you see one of these errors when using SELinux, ex: Android 4.4 or later
+ "Unable to mount the gator filesystem needed for profiling" or "Unable to load (insmod) gator.ko driver"
+with the following dmesg output,
<7>[ 6745.475110] SELinux: initialized (dev gatorfs, type gatorfs), not configured for labeling
<5>[ 6745.477434] type=1400 audit(1393005053.336:10): avc: denied { mount } for pid=1996 comm="gatord-main" name="/" dev="gatorfs" ino=8733 scontext=u:r:shell:s0 tcontext=u:object_r:unlabeled:s0 tclass=filesystem
disable SELinux so that gatorfs can be mounted by running
diff --git a/daemon/Android.mk b/daemon/Android.mk
index 44c069c..970ac69 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -3,13 +3,16 @@ include $(CLEAR_VARS)
XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h)
-LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -pthread -DETCDIR=\"/etc\" -Ilibsensors
-
LOCAL_SRC_FILES := \
+ AnnotateListener.cpp \
Buffer.cpp \
+ CCNDriver.cpp \
+ CPUFreqDriver.cpp \
CapturedXML.cpp \
Child.cpp \
+ Command.cpp \
ConfigurationXML.cpp \
+ DiskIODriver.cpp \
Driver.cpp \
DriverSource.cpp \
DynBuf.cpp \
@@ -17,13 +20,17 @@ LOCAL_SRC_FILES := \
ExternalSource.cpp \
FSDriver.cpp \
Fifo.cpp \
- Hwmon.cpp \
+ FtraceDriver.cpp \
+ FtraceSource.cpp \
+ HwmonDriver.cpp \
KMod.cpp \
LocalCapture.cpp \
Logging.cpp \
main.cpp \
MaliVideoDriver.cpp \
+ MemInfoDriver.cpp\
Monitor.cpp \
+ NetDriver.cpp \
OlySocket.cpp \
OlyUtility.cpp \
PerfBuffer.cpp \
@@ -34,6 +41,7 @@ LOCAL_SRC_FILES := \
Sender.cpp \
SessionData.cpp \
SessionXML.cpp \
+ Setup.cpp \
Source.cpp \
StreamlineSetup.cpp \
UEvent.cpp \
@@ -57,6 +65,9 @@ LOCAL_SRC_FILES := \
mxml/mxml-set.c \
mxml/mxml-string.c
+LOCAL_CFLAGS += -Wall -O3 -fno-exceptions -pthread -DETCDIR=\"/etc\" -Ilibsensors -fPIE
+LOCAL_LDFLAGS += -fPIE -pie
+
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_MODULE := gatord
diff --git a/daemon/AnnotateListener.cpp b/daemon/AnnotateListener.cpp
new file mode 100644
index 0000000..50110b4
--- /dev/null
+++ b/daemon/AnnotateListener.cpp
@@ -0,0 +1,69 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "AnnotateListener.h"
+
+#include <unistd.h>
+
+#include "OlySocket.h"
+
+struct AnnotateClient {
+ AnnotateClient *next;
+ int fd;
+};
+
+AnnotateListener::AnnotateListener() : mClients(NULL), mSock(NULL) {
+}
+
+AnnotateListener::~AnnotateListener() {
+ close();
+ delete mSock;
+}
+
+void AnnotateListener::setup() {
+ mSock = new OlyServerSocket(8082);
+}
+
+int AnnotateListener::getFd() {
+ return mSock->getFd();
+}
+
+void AnnotateListener::handle() {
+ AnnotateClient *const client = new AnnotateClient();
+ client->fd = mSock->acceptConnection();
+ client->next = mClients;
+ mClients = client;
+}
+
+void AnnotateListener::close() {
+ mSock->closeServerSocket();
+ while (mClients != NULL) {
+ ::close(mClients->fd);
+ AnnotateClient *next = mClients->next;
+ delete mClients;
+ mClients = next;
+ }
+}
+
+void AnnotateListener::signal() {
+ const char ch = 0;
+ AnnotateClient **ptr = &mClients;
+ AnnotateClient *client = mClients;
+ while (client != NULL) {
+ if (write(client->fd, &ch, sizeof(ch)) != 1) {
+ ::close(client->fd);
+ AnnotateClient *next = client->next;
+ delete client;
+ *ptr = next;
+ client = next;
+ continue;
+ }
+ ptr = &client->next;
+ client = client->next;
+ }
+}
diff --git a/daemon/AnnotateListener.h b/daemon/AnnotateListener.h
new file mode 100644
index 0000000..cdefef1
--- /dev/null
+++ b/daemon/AnnotateListener.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+class AnnotateClient;
+class OlyServerSocket;
+
+class AnnotateListener {
+public:
+ AnnotateListener();
+ ~AnnotateListener();
+
+ void setup();
+ int getFd();
+
+ void handle();
+ void close();
+ void signal();
+
+private:
+ AnnotateClient *mClients;
+ OlyServerSocket *mSock;
+
+ // Intentionally unimplemented
+ AnnotateListener(const AnnotateListener &);
+ AnnotateListener &operator=(const AnnotateListener &);
+};
diff --git a/daemon/Application.mk b/daemon/Application.mk
index 631ba54..3ada471 100644
--- a/daemon/Application.mk
+++ b/daemon/Application.mk
@@ -1 +1,3 @@
APP_PLATFORM := android-8
+# Replace armeabi-v7a with arm64-v8a to build an arm64 gatord or with armeabi to build an ARM11 gatord
+APP_ABI := armeabi-v7a
diff --git a/daemon/Buffer.cpp b/daemon/Buffer.cpp
index d7c4c7d..8fa6280 100644
--- a/daemon/Buffer.cpp
+++ b/daemon/Buffer.cpp
@@ -15,12 +15,15 @@
#define mask (mSize - 1)
enum {
- CODE_PEA = 1,
- CODE_KEYS = 2,
- CODE_FORMAT = 3,
- CODE_MAPS = 4,
- CODE_COMM = 5,
- CODE_KEYS_OLD = 6,
+ CODE_PEA = 1,
+ CODE_KEYS = 2,
+ CODE_FORMAT = 3,
+ CODE_MAPS = 4,
+ CODE_COMM = 5,
+ CODE_KEYS_OLD = 6,
+ CODE_ONLINE_CPU = 7,
+ CODE_OFFLINE_CPU = 8,
+ CODE_KALLSYMS = 9,
};
// Summary Frame Messages
@@ -42,16 +45,18 @@ enum {
/* Add another character so the length isn't 0x0a bytes */ \
"5"
-Buffer::Buffer(const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : mCore(core), mBufType(buftype), mSize(size), mReadPos(0), mWritePos(0), mCommitPos(0), mAvailable(true), mIsDone(false), mBuf(new char[mSize]), mCommitTime(gSessionData->mLiveRate), mReaderSem(readerSem) {
+Buffer::Buffer(const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : mBuf(new char[size]), mReaderSem(readerSem), mCommitTime(gSessionData->mLiveRate), mSize(size), mReadPos(0), mWritePos(0), mCommitPos(0), mAvailable(true), mIsDone(false), mCore(core), mBufType(buftype) {
if ((mSize & mask) != 0) {
logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
handleException();
}
+ sem_init(&mWriterSem, 0, 0);
frame();
}
Buffer::~Buffer() {
delete [] mBuf;
+ sem_destroy(&mWriterSem);
}
void Buffer::write(Sender *const sender) {
@@ -86,6 +91,9 @@ void Buffer::write(Sender *const sender) {
}
mReadPos = commitPos;
+
+ // send a notification that space is available
+ sem_post(&mWriterSem);
}
bool Buffer::commitReady() const {
@@ -197,7 +205,7 @@ void Buffer::packInt(int32_t x) {
packInt(mBuf, mSize, mWritePos, x);
}
-void Buffer::packInt64(int64_t x) {
+void Buffer::packInt64(char *const buf, const int size, int &writePos, int64_t x) {
int packedBytes = 0;
int more = true;
while (more) {
@@ -211,11 +219,15 @@ void Buffer::packInt64(int64_t x) {
b |= 0x80;
}
- mBuf[(mWritePos + packedBytes) & mask] = b;
+ buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
packedBytes++;
}
- mWritePos = (mWritePos + packedBytes) & mask;
+ writePos = (writePos + packedBytes) & /*mask*/(size - 1);
+}
+
+void Buffer::packInt64(int64_t x) {
+ packInt64(mBuf, mSize, mWritePos, x);
}
void Buffer::writeBytes(const void *const data, size_t count) {
@@ -240,10 +252,12 @@ void Buffer::frame() {
// Reserve space for the length
mWritePos += sizeof(int32_t);
packInt(mBufType);
- packInt(mCore);
+ if ((mBufType == FRAME_BLOCK_COUNTER) || (mBufType == FRAME_PERF_ATTRS) || (mBufType == FRAME_PERF)) {
+ packInt(mCore);
+ }
}
-void Buffer::summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
+void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
packInt(MESSAGE_SUMMARY);
writeString(NEWLINE_CANARY);
packInt64(timestamp);
@@ -252,23 +266,24 @@ void Buffer::summary(const int64_t timestamp, const int64_t uptime, const int64_
writeString("uname");
writeString(uname);
writeString("");
- check(1);
+ check(currTime);
}
-void Buffer::coreName(const int core, const int cpuid, const char *const name) {
+void Buffer::coreName(const uint64_t currTime, const int core, const int cpuid, const char *const name) {
if (checkSpace(3 * MAXSIZE_PACK32 + 0x100)) {
packInt(MESSAGE_CORE_NAME);
packInt(core);
packInt(cpuid);
writeString(name);
}
- check(1);
+ check(currTime);
}
bool Buffer::eventHeader(const uint64_t curr_time) {
bool retval = false;
if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
- packInt(0); // key of zero indicates a timestamp
+ // key of zero indicates a timestamp
+ packInt(0);
packInt64(curr_time);
retval = true;
}
@@ -279,7 +294,8 @@ bool Buffer::eventHeader(const uint64_t curr_time) {
bool Buffer::eventTid(const int tid) {
bool retval = false;
if (checkSpace(2 * MAXSIZE_PACK32)) {
- packInt(1); // key of 1 indicates a tid
+ // key of 1 indicates a tid
+ packInt(1);
packInt(tid);
retval = true;
}
@@ -287,102 +303,119 @@ bool Buffer::eventTid(const int tid) {
return retval;
}
-void Buffer::event(const int32_t key, const int32_t value) {
+void Buffer::event(const int key, const int32_t value) {
if (checkSpace(2 * MAXSIZE_PACK32)) {
packInt(key);
packInt(value);
}
}
-void Buffer::event64(const int64_t key, const int64_t value) {
- if (checkSpace(2 * MAXSIZE_PACK64)) {
- packInt64(key);
+void Buffer::event64(const int key, const int64_t value) {
+ if (checkSpace(MAXSIZE_PACK64 + MAXSIZE_PACK32)) {
+ packInt(key);
packInt64(value);
}
}
-void Buffer::pea(const struct perf_event_attr *const pea, int key) {
- if (checkSpace(2 * MAXSIZE_PACK32 + pea->size)) {
- packInt(CODE_PEA);
- writeBytes(pea, pea->size);
- packInt(key);
- } else {
- logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
- handleException();
+void Buffer::pea(const uint64_t currTime, const struct perf_event_attr *const pea, int key) {
+ while (!checkSpace(2 * MAXSIZE_PACK32 + pea->size)) {
+ sem_wait(&mWriterSem);
}
- // Don't know the real perf time so use 1 as it will work for now
- check(1);
+ packInt(CODE_PEA);
+ writeBytes(pea, pea->size);
+ packInt(key);
+ check(currTime);
}
-void Buffer::keys(const int count, const __u64 *const ids, const int *const keys) {
- if (checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) {
- packInt(CODE_KEYS);
- packInt(count);
- for (int i = 0; i < count; ++i) {
- packInt64(ids[i]);
- packInt(keys[i]);
- }
- } else {
- logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
- handleException();
+void Buffer::keys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys) {
+ while (!checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) {
+ sem_wait(&mWriterSem);
}
- check(1);
+ packInt(CODE_KEYS);
+ packInt(count);
+ for (int i = 0; i < count; ++i) {
+ packInt64(ids[i]);
+ packInt(keys[i]);
+ }
+ check(currTime);
}
-void Buffer::keysOld(const int keyCount, const int *const keys, const int bytes, const char *const buf) {
- if (checkSpace((2 + keyCount) * MAXSIZE_PACK32 + bytes)) {
- packInt(CODE_KEYS_OLD);
- packInt(keyCount);
- for (int i = 0; i < keyCount; ++i) {
- packInt(keys[i]);
- }
- writeBytes(buf, bytes);
- } else {
- logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
- handleException();
+void Buffer::keysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf) {
+ while (!checkSpace((2 + keyCount) * MAXSIZE_PACK32 + bytes)) {
+ sem_wait(&mWriterSem);
}
- check(1);
+ packInt(CODE_KEYS_OLD);
+ packInt(keyCount);
+ for (int i = 0; i < keyCount; ++i) {
+ packInt(keys[i]);
+ }
+ writeBytes(buf, bytes);
+ check(currTime);
}
-void Buffer::format(const int length, const char *const format) {
- if (checkSpace(MAXSIZE_PACK32 + length + 1)) {
- packInt(CODE_FORMAT);
- writeBytes(format, length + 1);
- } else {
- logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
- handleException();
+void Buffer::format(const uint64_t currTime, const int length, const char *const format) {
+ while (!checkSpace(MAXSIZE_PACK32 + length + 1)) {
+ sem_wait(&mWriterSem);
}
- check(1);
+ packInt(CODE_FORMAT);
+ writeBytes(format, length + 1);
+ check(currTime);
}
-void Buffer::maps(const int pid, const int tid, const char *const maps) {
+void Buffer::maps(const uint64_t currTime, const int pid, const int tid, const char *const maps) {
const int mapsLen = strlen(maps) + 1;
- if (checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) {
- packInt(CODE_MAPS);
- packInt(pid);
- packInt(tid);
- writeBytes(maps, mapsLen);
- } else {
- logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
- handleException();
+ while (!checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) {
+ sem_wait(&mWriterSem);
}
- check(1);
+ packInt(CODE_MAPS);
+ packInt(pid);
+ packInt(tid);
+ writeBytes(maps, mapsLen);
+ check(currTime);
}
-void Buffer::comm(const int pid, const int tid, const char *const image, const char *const comm) {
+void Buffer::comm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm) {
const int imageLen = strlen(image) + 1;
const int commLen = strlen(comm) + 1;
- if (checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) {
- packInt(CODE_COMM);
- packInt(pid);
- packInt(tid);
- writeBytes(image, imageLen);
- writeBytes(comm, commLen);
- } else {
- logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
- handleException();
+ while (!checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) {
+ sem_wait(&mWriterSem);
+ }
+ packInt(CODE_COMM);
+ packInt(pid);
+ packInt(tid);
+ writeBytes(image, imageLen);
+ writeBytes(comm, commLen);
+ check(currTime);
+}
+
+void Buffer::onlineCPU(const uint64_t currTime, const uint64_t time, const int cpu) {
+ while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
+ sem_wait(&mWriterSem);
+ }
+ packInt(CODE_ONLINE_CPU);
+ packInt64(time);
+ packInt(cpu);
+ check(currTime);
+}
+
+void Buffer::offlineCPU(const uint64_t currTime, const uint64_t time, const int cpu) {
+ while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
+ sem_wait(&mWriterSem);
+ }
+ packInt(CODE_OFFLINE_CPU);
+ packInt64(time);
+ packInt(cpu);
+ check(currTime);
+}
+
+void Buffer::kallsyms(const uint64_t currTime, const char *const kallsyms) {
+ const int kallsymsLen = strlen(kallsyms) + 1;
+ while (!checkSpace(3 * MAXSIZE_PACK32 + kallsymsLen)) {
+ sem_wait(&mWriterSem);
}
- check(1);
+ packInt(CODE_KALLSYMS);
+ writeBytes(kallsyms, kallsymsLen);
+ check(currTime);
}
void Buffer::setDone() {
diff --git a/daemon/Buffer.h b/daemon/Buffer.h
index 2de1b97..6cffd8e 100644
--- a/daemon/Buffer.h
+++ b/daemon/Buffer.h
@@ -39,25 +39,26 @@ public:
void commit(const uint64_t time);
void check(const uint64_t time);
- void frame();
-
// Summary messages
- void summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname);
- void coreName(const int core, const int cpuid, const char *const name);
+ void summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname);
+ void coreName(const uint64_t currTime, const int core, const int cpuid, const char *const name);
// Block Counter messages
bool eventHeader(uint64_t curr_time);
bool eventTid(int tid);
- void event(int32_t key, int32_t value);
- void event64(int64_t key, int64_t value);
+ void event(int key, int32_t value);
+ void event64(int key, int64_t value);
// Perf Attrs messages
- void pea(const struct perf_event_attr *const pea, int key);
- void keys(const int count, const __u64 *const ids, const int *const keys);
- void keysOld(const int keyCount, const int *const keys, const int bytes, const char *const buf);
- void format(const int length, const char *const format);
- void maps(const int pid, const int tid, const char *const maps);
- void comm(const int pid, const int tid, const char *const image, const char *const comm);
+ void pea(const uint64_t currTime, const struct perf_event_attr *const pea, int key);
+ void keys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys);
+ void keysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf);
+ void format(const uint64_t currTime, const int length, const char *const format);
+ void maps(const uint64_t currTime, const int pid, const int tid, const char *const maps);
+ void comm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm);
+ void onlineCPU(const uint64_t currTime, const uint64_t time, const int cpu);
+ void offlineCPU(const uint64_t currTime, const uint64_t time, const int cpu);
+ void kallsyms(const uint64_t currTime, const char *const kallsyms);
void setDone();
bool isDone() const;
@@ -67,6 +68,7 @@ public:
void advanceWrite(int bytes) { mWritePos = (mWritePos + bytes) & /*mask*/(mSize - 1); }
static void packInt(char *const buf, const int size, int &writePos, int32_t x);
void packInt(int32_t x);
+ static void packInt64(char *const buf, const int size, int &writePos, int64_t x);
void packInt64(int64_t x);
void writeBytes(const void *const data, size_t count);
void writeString(const char *const str);
@@ -79,20 +81,22 @@ public:
}
private:
+ void frame();
bool commitReady() const;
bool checkSpace(int bytes);
- const int32_t mCore;
- const int32_t mBufType;
+ char *const mBuf;
+ sem_t *const mReaderSem;
+ uint64_t mCommitTime;
+ sem_t mWriterSem;
const int mSize;
int mReadPos;
int mWritePos;
int mCommitPos;
bool mAvailable;
bool mIsDone;
- char *const mBuf;
- uint64_t mCommitTime;
- sem_t *const mReaderSem;
+ const int32_t mCore;
+ const int32_t mBufType;
// Intentionally unimplemented
Buffer(const Buffer &);
diff --git a/daemon/CCNDriver.cpp b/daemon/CCNDriver.cpp
new file mode 100644
index 0000000..dd1a2b1
--- /dev/null
+++ b/daemon/CCNDriver.cpp
@@ -0,0 +1,295 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "CCNDriver.h"
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "k/perf_event.h"
+
+#include "Config.h"
+#include "DriverSource.h"
+#include "Logging.h"
+
+static const char TAG_CATEGORY[] = "category";
+static const char TAG_COUNTER_SET[] = "counter_set";
+static const char TAG_EVENT[] = "event";
+static const char TAG_OPTION[] = "option";
+static const char TAG_OPTION_SET[] = "option_set";
+
+static const char ATTR_AVERAGE_SELECTION[] = "average_selection";
+static const char ATTR_COUNTER[] = "counter";
+static const char ATTR_COUNTER_SET[] = "counter_set";
+static const char ATTR_COUNT[] = "count";
+static const char ATTR_DESCRIPTION[] = "description";
+static const char ATTR_DISPLAY[] = "display";
+static const char ATTR_EVENT[] = "event";
+static const char ATTR_EVENT_DELTA[] = "event_delta";
+static const char ATTR_NAME[] = "name";
+static const char ATTR_OPTION_SET[] = "option_set";
+static const char ATTR_TITLE[] = "title";
+static const char ATTR_UNITS[] = "units";
+
+static const char XP_REGION[] = "XP_Region";
+static const char HNF_REGION[] = "HN-F_Region";
+static const char RNI_REGION[] = "RN-I_Region";
+static const char SBAS_REGION[] = "SBAS_Region";
+static const char CCN_5XX[] = "CCN-5xx";
+#define ARM_CCN_5XX "ARM_CCN_5XX_"
+
+static const char *const VC_TYPES[] = { "REQ", "RSP", "SNP", "DAT" };
+static const char *const XP_EVENT_NAMES[] = { NULL, "H-bit", "S-bit", "P-Cnt", "TknV" };
+static const char *const XP_EVENT_DESCRIPTIONS[] = { NULL, "Set H-bit, signaled when this XP sets the H-bit.", "Set S-bit, signaled when this XP sets the S-bit.", "Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC.", "No TknV, signaled when this XP transmits a valid packet." };
+static const char *const HNF_EVENT_NAMES[] = { NULL, "Cache Miss", "L3 SF Cache Access", "Cache Fill", "POCQ Retry", "POCQ Reqs Recvd", "SF Hit", "SF Evictions", "Snoops Sent", "Snoops Broadcast", "L3 Eviction", "L3 Fill Invalid Way", "MC Retries", "MC Reqs", "QOS HH Retry" };
+static const char *const HNF_EVENT_DESCRIPTIONS[] = { NULL, "Counts the total cache misses. This is the first time lookup result, and is high priority.", "Counts the number of cache accesses. This is the first time access, and is high priority.", "Counts the total allocations in the HN L3 cache, and all cache line allocations to the L3 cache.", "Counts the number of requests that have been retried.", "Counts the number of requests received by HN.", "Counts the number of snoop filter hits.", "Counts the number of snoop filter evictions. Cache invalidations are initiated.", "Counts the number of snoops sent. Does not differentiate between broadcast or directed snoops.", "Counts the number of snoop broadcasts sent.", "Counts the number of L3 evictions.", "Counts the number of L3 fills to an invalid way.", "Counts the number of transactions retried by the memory controller.", "Counts the number of requests to the memory controller.", "Counts the number of times a highest-priority QoS class was retried at the HN-F." };
+static const char *const RNI_EVENT_NAMES[] = { NULL, "S0 RDataBeats", "S1 RDataBeats", "S2 RDataBeats", "RXDAT Flits received", "TXDAT Flits sent", "Total TXREQ Flits sent", "Retried TXREQ Flits sent", "RRT full", "WRT full", "Replayed TXREQ Flits" };
+static const char *const RNI_EVENT_DESCRIPTIONS[] = { NULL, "S0 RDataBeats.", "S1 RDataBeats.", "S2 RDataBeats.", "RXDAT Flits received.", "TXDAT Flits sent.", "Total TXREQ Flits sent.", "Retried TXREQ Flits sent.", "RRT full.", "WRT full.", "Replayed TXREQ Flits." };
+static const char *const SBAS_EVENT_NAMES[] = { NULL, "S0 RDataBeats", NULL, NULL, "RXDAT Flits received", "TXDAT Flits sent", "Total TXREQ Flits sent", "Retried TXREQ Flits sent", "RRT full", "WRT full", "Replayed TXREQ Flits" };
+static const char *const SBAS_EVENT_DESCRIPTIONS[] = { NULL, "S0 RDataBeats.", NULL, NULL, "RXDAT Flits received.", "TXDAT Flits sent.", "Total TXREQ Flits sent.", "Retried TXREQ Flits sent.", "RRT full.", "WRT full.", "Replayed TXREQ Flits." };
+
+// This class is used only to poll for CCN-5xx configuration and emit events XML for it. All other operations are handled by PerfDriver
+
+static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t pid, const int cpu, const int group_fd, const unsigned long flags) {
+ return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
+}
+
+static unsigned int getConfig(unsigned int node, unsigned int type, unsigned int event, unsigned int port, unsigned int vc) {
+ return
+ ((node & 0xff) << 0) |
+ ((type & 0xff) << 8) |
+ ((event & 0xff) << 16) |
+ ((port & 0x03) << 24) |
+ ((vc & 0x07) << 26) |
+ 0;
+}
+
+static bool perfPoll(struct perf_event_attr *const pea) {
+ int fd = sys_perf_event_open(pea, -1, 0, -1, 0);
+ if (fd < 0) {
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+CCNDriver::CCNDriver() : mNodeTypes(NULL), mXpCount(0) {
+}
+
+CCNDriver::~CCNDriver() {
+ delete mNodeTypes;
+}
+
+bool CCNDriver::claimCounter(const Counter &) const {
+ // Handled by PerfDriver
+ return false;
+}
+
+void CCNDriver::resetCounters() {
+ // Handled by PerfDriver
+}
+
+void CCNDriver::setupCounter(Counter &) {
+ // Handled by PerfDriver
+}
+
+void CCNDriver::readEvents(mxml_node_t *const) {
+ struct stat st;
+ if (stat("/sys/bus/event_source/devices/ccn", &st) != 0) {
+ // Not found
+ return;
+ }
+
+ int type;
+ if (DriverSource::readIntDriver("/sys/bus/event_source/devices/ccn/type", &type) != 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to read CCN-5xx type");
+ handleException();
+ }
+
+ // Detect number of xps
+ struct perf_event_attr pea;
+ memset(&pea, 0, sizeof(pea));
+ pea.type = type;
+ pea.size = sizeof(pea);
+
+ mXpCount = 1;
+ while (true) {
+ pea.config = getConfig(0, 0x08, 1, 0, 1) | mXpCount;
+ if (!perfPoll(&pea)) {
+ break;
+ }
+ mXpCount *= 2;
+ };
+ {
+ int lower = mXpCount/2 + 1;
+ while (lower < mXpCount) {
+ int mid = (lower + mXpCount)/2;
+ pea.config = getConfig(0, 0x08, 1, 0, 1) | mid;
+ if (perfPoll(&pea)) {
+ lower = mid + 1;
+ } else {
+ mXpCount = mid;
+ }
+ }
+ }
+
+ mNodeTypes = new NodeType[2*mXpCount];
+
+ // Detect node types
+ for (int i = 0; i < 2*mXpCount; ++i) {
+ pea.config = getConfig(0, 0x04, 1, 0, 0) | i;
+ if (perfPoll(&pea)) {
+ mNodeTypes[i] = NT_HNF;
+ continue;
+ }
+
+ pea.config = getConfig(0, 0x16, 1, 0, 0) | i;
+ if (perfPoll(&pea)) {
+ mNodeTypes[i] = NT_RNI;
+ continue;
+ }
+
+ pea.config = getConfig(0, 0x10, 1, 0, 0) | i;
+ if (perfPoll(&pea)) {
+ mNodeTypes[i] = NT_SBAS;
+ continue;
+ }
+
+ mNodeTypes[i] = NT_UNKNOWN;
+ }
+}
+
+int CCNDriver::writeCounters(mxml_node_t *const) const {
+ // Handled by PerfDriver
+ return 0;
+}
+
+void CCNDriver::writeEvents(mxml_node_t *const root) const {
+ mxml_node_t *const counter_set = mxmlNewElement(root, TAG_COUNTER_SET);
+ mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX "cnt");
+ mxmlElementSetAttr(counter_set, ATTR_COUNT, "8");
+
+ mxml_node_t *const category = mxmlNewElement(root, TAG_CATEGORY);
+ mxmlElementSetAttr(category, ATTR_NAME, CCN_5XX);
+ mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX "cnt");
+
+ mxml_node_t *const clock_event = mxmlNewElement(category, TAG_EVENT);
+ mxmlElementSetAttr(clock_event, ATTR_COUNTER, ARM_CCN_5XX "ccnt");
+ mxmlElementSetAttr(clock_event, ATTR_EVENT, "0xff00");
+ mxmlElementSetAttr(clock_event, ATTR_TITLE, "CCN-5xx Clock");
+ mxmlElementSetAttr(clock_event, ATTR_NAME, "Cycles");
+ mxmlElementSetAttr(clock_event, ATTR_DISPLAY, "hertz");
+ mxmlElementSetAttr(clock_event, ATTR_UNITS, "Hz");
+ mxmlElementSetAttr(clock_event, ATTR_AVERAGE_SELECTION, "yes");
+ mxmlElementSetAttr(clock_event, ATTR_DESCRIPTION, "The number of core clock cycles");
+
+ mxml_node_t *const xp_option_set = mxmlNewElement(category, TAG_OPTION_SET);
+ mxmlElementSetAttr(xp_option_set, ATTR_NAME, XP_REGION);
+
+ for (int i = 0; i < mXpCount; ++i) {
+ mxml_node_t *const option = mxmlNewElement(xp_option_set, TAG_OPTION);
+ mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
+ mxmlElementSetAttrf(option, ATTR_NAME, "XP %i", i);
+ mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "Crosspoint %i", i);
+ }
+
+ for (int vc = 0; vc < ARRAY_LENGTH(VC_TYPES); ++vc) {
+ if (VC_TYPES[vc] == NULL) {
+ continue;
+ }
+ for (int bus = 0; bus < 2; ++bus) {
+ for (int eventId = 0; eventId < ARRAY_LENGTH(XP_EVENT_NAMES); ++eventId) {
+ if (XP_EVENT_NAMES[eventId] == NULL) {
+ continue;
+ }
+ mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
+ mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x08, eventId, bus, vc));
+ mxmlElementSetAttr(event, ATTR_OPTION_SET, XP_REGION);
+ mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
+ mxmlElementSetAttrf(event, ATTR_NAME, "Bus %i: %s: %s", bus, VC_TYPES[vc], XP_EVENT_NAMES[eventId]);
+ mxmlElementSetAttrf(event, ATTR_DESCRIPTION, "Bus %i: %s: %s", bus, VC_TYPES[vc], XP_EVENT_DESCRIPTIONS[eventId]);
+ }
+ }
+ }
+
+ mxml_node_t *const hnf_option_set = mxmlNewElement(category, TAG_OPTION_SET);
+ mxmlElementSetAttr(hnf_option_set, ATTR_NAME, HNF_REGION);
+
+ for (int eventId = 0; eventId < ARRAY_LENGTH(HNF_EVENT_NAMES); ++eventId) {
+ if (HNF_EVENT_NAMES[eventId] == NULL) {
+ continue;
+ }
+ mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
+ mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x04, eventId, 0, 0));
+ mxmlElementSetAttr(event, ATTR_OPTION_SET, HNF_REGION);
+ mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
+ mxmlElementSetAttr(event, ATTR_NAME, HNF_EVENT_NAMES[eventId]);
+ mxmlElementSetAttr(event, ATTR_DESCRIPTION, HNF_EVENT_DESCRIPTIONS[eventId]);
+ }
+
+ mxml_node_t *const rni_option_set = mxmlNewElement(category, TAG_OPTION_SET);
+ mxmlElementSetAttr(rni_option_set, ATTR_NAME, RNI_REGION);
+
+ for (int eventId = 0; eventId < ARRAY_LENGTH(RNI_EVENT_NAMES); ++eventId) {
+ if (RNI_EVENT_NAMES[eventId] == NULL) {
+ continue;
+ }
+ mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
+ mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x16, eventId, 0, 0));
+ mxmlElementSetAttr(event, ATTR_OPTION_SET, RNI_REGION);
+ mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
+ mxmlElementSetAttr(event, ATTR_NAME, RNI_EVENT_NAMES[eventId]);
+ mxmlElementSetAttr(event, ATTR_DESCRIPTION, RNI_EVENT_DESCRIPTIONS[eventId]);
+ }
+
+ mxml_node_t *const sbas_option_set = mxmlNewElement(category, TAG_OPTION_SET);
+ mxmlElementSetAttr(sbas_option_set, ATTR_NAME, SBAS_REGION);
+
+ for (int eventId = 0; eventId < ARRAY_LENGTH(SBAS_EVENT_NAMES); ++eventId) {
+ if (SBAS_EVENT_NAMES[eventId] == NULL) {
+ continue;
+ }
+ mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
+ mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x10, eventId, 0, 0));
+ mxmlElementSetAttr(event, ATTR_OPTION_SET, SBAS_REGION);
+ mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
+ mxmlElementSetAttr(event, ATTR_NAME, SBAS_EVENT_NAMES[eventId]);
+ mxmlElementSetAttr(event, ATTR_DESCRIPTION, SBAS_EVENT_DESCRIPTIONS[eventId]);
+ }
+
+ for (int i = 0; i < 2*mXpCount; ++i) {
+ switch (mNodeTypes[i]) {
+ case NT_HNF: {
+ mxml_node_t *const option = mxmlNewElement(hnf_option_set, TAG_OPTION);
+ mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
+ mxmlElementSetAttrf(option, ATTR_NAME, "HN-F %i", i);
+ mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "Fully-coherent Home Node %i", i);
+ break;
+ }
+ case NT_RNI: {
+ mxml_node_t *const option = mxmlNewElement(rni_option_set, TAG_OPTION);
+ mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
+ mxmlElementSetAttrf(option, ATTR_NAME, "RN-I %i", i);
+ mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "I/O-coherent Requesting Node %i", i);
+ break;
+ }
+ case NT_SBAS: {
+ mxml_node_t *const option = mxmlNewElement(sbas_option_set, TAG_OPTION);
+ mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
+ mxmlElementSetAttrf(option, ATTR_NAME, "SBAS %i", i);
+ mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "ACE master to CHI protocol bridge %i", i);
+ break;
+ }
+ default:
+ continue;
+ }
+ }
+}
diff --git a/daemon/CCNDriver.h b/daemon/CCNDriver.h
new file mode 100644
index 0000000..fb4c717
--- /dev/null
+++ b/daemon/CCNDriver.h
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef CCNDRIVER_H
+#define CCNDRIVER_H
+
+#include "Driver.h"
+
+class CCNDriver : public Driver {
+public:
+ CCNDriver();
+ ~CCNDriver();
+
+ bool claimCounter(const Counter &counter) const;
+ void resetCounters();
+ void setupCounter(Counter &counter);
+
+ void readEvents(mxml_node_t *const);
+ int writeCounters(mxml_node_t *const root) const;
+ void writeEvents(mxml_node_t *const) const;
+
+private:
+ enum NodeType {
+ NT_UNKNOWN,
+ NT_HNF,
+ NT_RNI,
+ NT_SBAS,
+ };
+
+ NodeType *mNodeTypes;
+ int mXpCount;
+
+ // Intentionally unimplemented
+ CCNDriver(const CCNDriver &);
+ CCNDriver &operator=(const CCNDriver &);
+};
+
+#endif // CCNDRIVER_H
diff --git a/daemon/CPUFreqDriver.cpp b/daemon/CPUFreqDriver.cpp
new file mode 100644
index 0000000..41f9d6f
--- /dev/null
+++ b/daemon/CPUFreqDriver.cpp
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "CPUFreqDriver.h"
+
+#include "Buffer.h"
+#include "DriverSource.h"
+#include "Logging.h"
+#include "SessionData.h"
+
+CPUFreqDriver::CPUFreqDriver() : mPrev() {
+}
+
+CPUFreqDriver::~CPUFreqDriver() {
+}
+
+void CPUFreqDriver::readEvents(mxml_node_t *const) {
+ // Only for use with perf
+ if (!gSessionData->perf.isSetup()) {
+ return;
+ }
+
+ setCounters(new DriverCounter(getCounters(), strdup("Linux_power_cpu_freq")));
+}
+
+void CPUFreqDriver::read(Buffer *const buffer) {
+ char buf[64];
+ const DriverCounter *const counter = getCounters();
+ if ((counter == NULL) || !counter->isEnabled()) {
+ return;
+ }
+
+ const int key = getCounters()->getKey();
+ bool resetCores = false;
+ for (int i = 0; i < gSessionData->mCores; ++i) {
+ snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%i/cpufreq/cpuinfo_cur_freq", i);
+ int64_t freq;
+ if (DriverSource::readInt64Driver(buf, &freq) != 0) {
+ freq = 0;
+ }
+ if (mPrev[i] != freq) {
+ mPrev[i] = freq;
+ // Change cores
+ buffer->event64(2, i);
+ resetCores = true;
+ buffer->event64(key, 1000*freq);
+ }
+ }
+ if (resetCores) {
+ // Revert cores, UserSpaceSource is all on core 0
+ buffer->event64(2, 0);
+ }
+}
diff --git a/daemon/CPUFreqDriver.h b/daemon/CPUFreqDriver.h
new file mode 100644
index 0000000..ad8c9aa
--- /dev/null
+++ b/daemon/CPUFreqDriver.h
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef CPUFREQDRIVER_H
+#define CPUFREQDRIVER_H
+
+#include "Config.h"
+#include "Driver.h"
+
+class CPUFreqDriver : public PolledDriver {
+private:
+ typedef PolledDriver super;
+
+public:
+ CPUFreqDriver();
+ ~CPUFreqDriver();
+
+ void readEvents(mxml_node_t *const root);
+ void read(Buffer *const buffer);
+
+private:
+ int64_t mPrev[NR_CPUS];
+
+ // Intentionally unimplemented
+ CPUFreqDriver(const CPUFreqDriver &);
+ CPUFreqDriver &operator=(const CPUFreqDriver &);
+};
+
+#endif // CPUFREQDRIVER_H
diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp
index 4a11415..0b5802c 100644
--- a/daemon/CapturedXML.cpp
+++ b/daemon/CapturedXML.cpp
@@ -34,6 +34,7 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
mxmlElementSetAttr(captured, "version", "1");
if (gSessionData->perf.isSetup()) {
mxmlElementSetAttr(captured, "type", "Perf");
+ mxmlElementSetAttr(captured, "perf_beta", "yes");
}
mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION);
if (includeTime) { // Send the following only after the capture is complete
@@ -113,32 +114,32 @@ const char * mxmlWhitespaceCB(mxml_node_t *node, int loc) {
if (loc == MXML_WS_BEFORE_OPEN) {
// Single indentation
if (!strcmp(name, "target") || !strcmp(name, "counters"))
- return("\n ");
+ return "\n ";
// Double indentation
if (!strcmp(name, "counter"))
- return("\n ");
+ return "\n ";
// Avoid a carriage return on the first line of the xml file
if (!strncmp(name, "?xml", 4))
- return(NULL);
+ return NULL;
// Default - no indentation
- return("\n");
+ return "\n";
}
if (loc == MXML_WS_BEFORE_CLOSE) {
// No indentation
if (!strcmp(name, "captured"))
- return("\n");
+ return "\n";
// Single indentation
if (!strcmp(name, "counters"))
- return("\n ");
+ return "\n ";
// Default - no carriage return
- return(NULL);
+ return NULL;
}
- return(NULL);
+ return NULL;
}
diff --git a/daemon/CapturedXML.h b/daemon/CapturedXML.h
index ed08c44..b704f6e 100644
--- a/daemon/CapturedXML.h
+++ b/daemon/CapturedXML.h
@@ -6,8 +6,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __CAPTURED_XML_H__
-#define __CAPTURED_XML_H__
+#ifndef __CAPTURED_XML_H__
+#define __CAPTURED_XML_H__
#include "mxml/mxml.h"
diff --git a/daemon/Child.cpp b/daemon/Child.cpp
index 1901ecc..6b5bbb3 100644
--- a/daemon/Child.cpp
+++ b/daemon/Child.cpp
@@ -14,25 +14,28 @@
#include <unistd.h>
#include <sys/prctl.h>
-#include "Logging.h"
#include "CapturedXML.h"
-#include "SessionData.h"
-#include "LocalCapture.h"
-#include "Sender.h"
-#include "OlyUtility.h"
-#include "OlySocket.h"
-#include "StreamlineSetup.h"
+#include "Command.h"
#include "ConfigurationXML.h"
#include "Driver.h"
-#include "PerfSource.h"
#include "DriverSource.h"
#include "ExternalSource.h"
+#include "FtraceSource.h"
+#include "LocalCapture.h"
+#include "Logging.h"
+#include "OlySocket.h"
+#include "OlyUtility.h"
+#include "PerfSource.h"
+#include "Sender.h"
+#include "SessionData.h"
+#include "StreamlineSetup.h"
#include "UserSpaceSource.h"
static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads
static Source *primarySource = NULL;
static Source *externalSource = NULL;
static Source *userSpaceSource = NULL;
+static Source *ftraceSource = NULL;
static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
Child* child = NULL; // shared by Child.cpp and main.cpp
@@ -149,7 +152,8 @@ static void *senderThread(void *) {
while (!primarySource->isDone() ||
!externalSource->isDone() ||
- (userSpaceSource != NULL && !userSpaceSource->isDone())) {
+ (userSpaceSource != NULL && !userSpaceSource->isDone()) ||
+ (ftraceSource != NULL && !ftraceSource->isDone())) {
sem_wait(&senderSem);
primarySource->write(sender);
@@ -157,6 +161,9 @@ static void *senderThread(void *) {
if (userSpaceSource != NULL) {
userSpaceSource->write(sender);
}
+ if (ftraceSource != NULL) {
+ ftraceSource->write(sender);
+ }
}
// write end-of-capture sequence
@@ -206,6 +213,9 @@ void Child::endSession() {
if (userSpaceSource != NULL) {
userSpaceSource->interrupt();
}
+ if (ftraceSource != NULL) {
+ ftraceSource->interrupt();
+ }
sem_post(&haltPipeline);
}
@@ -269,15 +279,32 @@ void Child::run() {
free(xmlString);
}
+ if (gSessionData->kmod.isMaliCapture() && (gSessionData->mSampleRate == 0)) {
+ logg->logError(__FILE__, __LINE__, "Mali counters are not supported with Sample Rate: None.");
+ handleException();
+ }
+
// Must be after session XML is parsed
if (!primarySource->prepare()) {
- logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
+ if (gSessionData->perf.isSetup()) {
+ logg->logError(__FILE__, __LINE__, "Unable to prepare gator driver for capture");
+ } else {
+ logg->logError(__FILE__, __LINE__, "Unable to communicate with the perf API, please ensure that CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER are enabled. Please refer to README_Streamline.txt for more information.");
+ }
handleException();
}
// Sender thread shall be halted until it is signaled for one shot mode
sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
+ // Must be initialized before senderThread is started as senderThread checks externalSource
+ externalSource = new ExternalSource(&senderSem);
+ if (!externalSource->prepare()) {
+ logg->logError(__FILE__, __LINE__, "Unable to prepare external source for capture");
+ handleException();
+ }
+ externalSource->start();
+
// Create the duration, stop, and sender threads
bool thread_creation_success = true;
if (gSessionData->mDuration > 0 && pthread_create(&durationThreadID, NULL, durationThread, NULL)) {
@@ -288,22 +315,37 @@ void Child::run() {
thread_creation_success = false;
}
- externalSource = new ExternalSource(&senderSem);
- if (!externalSource->prepare()) {
- logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
- handleException();
+ bool startUSSource = false;
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
+ if (gSessionData->usDrivers[i]->countersEnabled()) {
+ startUSSource = true;
+ }
}
- externalSource->start();
-
- if (gSessionData->hwmon.countersEnabled() || gSessionData->fsDriver.countersEnabled()) {
+ if (startUSSource) {
userSpaceSource = new UserSpaceSource(&senderSem);
if (!userSpaceSource->prepare()) {
- logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
+ logg->logError(__FILE__, __LINE__, "Unable to prepare userspace source for capture");
handleException();
}
userSpaceSource->start();
}
+ if (gSessionData->ftraceDriver.countersEnabled()) {
+ ftraceSource = new FtraceSource(&senderSem);
+ if (!ftraceSource->prepare()) {
+ logg->logError(__FILE__, __LINE__, "Unable to prepare userspace source for capture");
+ handleException();
+ }
+ ftraceSource->start();
+ }
+
+ if (gSessionData->mAllowCommands && (gSessionData->mCaptureCommand != NULL)) {
+ pthread_t thread;
+ if (pthread_create(&thread, NULL, commandThread, NULL)) {
+ thread_creation_success = false;
+ }
+ }
+
if (!thread_creation_success) {
logg->logError(__FILE__, __LINE__, "Failed to create gator threads");
handleException();
@@ -315,6 +357,9 @@ void Child::run() {
// Start profiling
primarySource->run();
+ if (ftraceSource != NULL) {
+ ftraceSource->join();
+ }
if (userSpaceSource != NULL) {
userSpaceSource->join();
}
@@ -338,6 +383,7 @@ void Child::run() {
logg->logMessage("Profiling ended.");
+ delete ftraceSource;
delete userSpaceSource;
delete externalSource;
delete primarySource;
diff --git a/daemon/Child.h b/daemon/Child.h
index a306a77..cc78202 100644
--- a/daemon/Child.h
+++ b/daemon/Child.h
@@ -6,8 +6,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __CHILD_H__
-#define __CHILD_H__
+#ifndef __CHILD_H__
+#define __CHILD_H__
class OlySocket;
diff --git a/daemon/Command.cpp b/daemon/Command.cpp
new file mode 100644
index 0000000..28d73cf
--- /dev/null
+++ b/daemon/Command.cpp
@@ -0,0 +1,172 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "Command.h"
+
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "Logging.h"
+#include "SessionData.h"
+
+static int getUid(const char *const name, char *const shPath, const char *const tmpDir) {
+ // Lookups may fail when using a different libc or a statically compiled executable
+ char gatorTemp[32];
+ snprintf(gatorTemp, sizeof(gatorTemp), "%s/gator_temp", tmpDir);
+
+ const int fd = open(gatorTemp, 600, O_CREAT | O_CLOEXEC);
+ if (fd < 0) {
+ return -1;
+ }
+ close(fd);
+
+ char cmd[128];
+ snprintf(cmd, sizeof(cmd), "chown %s %s || rm %s", name, gatorTemp, gatorTemp);
+
+ const int pid = fork();
+ if (pid < 0) {
+ logg->logError(__FILE__, __LINE__, "fork failed");
+ handleException();
+ }
+ if (pid == 0) {
+ char cargv1[] = "-c";
+ char *cargv[] = {
+ shPath,
+ cargv1,
+ cmd,
+ NULL,
+ };
+
+ execv(cargv[0], cargv);
+ exit(-1);
+ }
+ while ((waitpid(pid, NULL, 0) < 0) && (errno == EINTR));
+
+ struct stat st;
+ int result = -1;
+ if (stat(gatorTemp, &st) == 0) {
+ result = st.st_uid;
+ }
+ unlink(gatorTemp);
+ return result;
+}
+
+static int getUid(const char *const name) {
+ // Look up the username
+ struct passwd *const user = getpwnam(name);
+ if (user != NULL) {
+ return user->pw_uid;
+ }
+
+
+ // Are we on Linux
+ char cargv0l[] = "/bin/sh";
+ if ((access(cargv0l, X_OK) == 0) && (access("/tmp", W_OK) == 0)) {
+ return getUid(name, cargv0l, "/tmp");
+ }
+
+ // Are we on android
+ char cargv0a[] = "/system/bin/sh";
+ if ((access(cargv0a, X_OK) == 0) && (access("/data", W_OK) == 0)) {
+ return getUid(name, cargv0a, "/data");
+ }
+
+ return -1;
+}
+
+void *commandThread(void *) {
+ prctl(PR_SET_NAME, (unsigned long)&"gatord-command", 0, 0, 0);
+
+ const char *const name = gSessionData->mCaptureUser == NULL ? "nobody" : gSessionData->mCaptureUser;
+ const int uid = getUid(name);
+ if (uid < 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to lookup the user %s, please double check that the user exists", name);
+ handleException();
+ }
+
+ sleep(3);
+
+ char buf[128];
+ int pipefd[2];
+ if (pipe_cloexec(pipefd) != 0) {
+ logg->logError(__FILE__, __LINE__, "pipe failed");
+ handleException();
+ }
+
+ const int pid = fork();
+ if (pid < 0) {
+ logg->logError(__FILE__, __LINE__, "fork failed");
+ handleException();
+ }
+ if (pid == 0) {
+ char cargv0l[] = "/bin/sh";
+ char cargv0a[] = "/system/bin/sh";
+ char cargv1[] = "-c";
+ char *cargv[] = {
+ cargv0l,
+ cargv1,
+ gSessionData->mCaptureCommand,
+ NULL,
+ };
+
+ buf[0] = '\0';
+ close(pipefd[0]);
+
+ // Gator runs at a high priority, reset the priority to the default
+ if (setpriority(PRIO_PROCESS, syscall(__NR_gettid), 0) == -1) {
+ snprintf(buf, sizeof(buf), "setpriority failed");
+ goto fail_exit;
+ }
+
+ if (setuid(uid) != 0) {
+ snprintf(buf, sizeof(buf), "setuid failed");
+ goto fail_exit;
+ }
+
+ {
+ const char *const path = gSessionData->mCaptureWorkingDir == NULL ? "/" : gSessionData->mCaptureWorkingDir;
+ if (chdir(path) != 0) {
+ snprintf(buf, sizeof(buf), "Unable to cd to %s, please verify the directory exists and is accessable to %s", path, name);
+ goto fail_exit;
+ }
+ }
+
+ execv(cargv[0], cargv);
+ cargv[0] = cargv0a;
+ execv(cargv[0], cargv);
+ snprintf(buf, sizeof(buf), "execv failed");
+
+ fail_exit:
+ if (buf[0] != '\0') {
+ const ssize_t bytes = write(pipefd[1], buf, sizeof(buf));
+ // Can't do anything if this fails
+ (void)bytes;
+ }
+
+ exit(-1);
+ }
+
+ close(pipefd[1]);
+ const ssize_t bytes = read(pipefd[0], buf, sizeof(buf));
+ if (bytes > 0) {
+ logg->logError(__FILE__, __LINE__, buf);
+ handleException();
+ }
+ close(pipefd[0]);
+
+ return NULL;
+}
diff --git a/daemon/Command.h b/daemon/Command.h
new file mode 100644
index 0000000..17244b7
--- /dev/null
+++ b/daemon/Command.h
@@ -0,0 +1,14 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+void *commandThread(void *);
+
+#endif // COMMAND_H
diff --git a/daemon/Config.h b/daemon/Config.h
index 6f5e2aa..bee383a 100644
--- a/daemon/Config.h
+++ b/daemon/Config.h
@@ -10,8 +10,19 @@
#define CONFIG_H
#define ARRAY_LENGTH(A) static_cast<int>(sizeof(A)/sizeof((A)[0]))
+#define ACCESS_ONCE(x) (*(volatile typeof(x)*)&(x))
#define MAX_PERFORMANCE_COUNTERS 50
-#define NR_CPUS 16
+#define NR_CPUS 32
+
+template<typename T>
+static inline T min(const T a, const T b) {
+ return (a < b ? a : b);
+}
+
+template<typename T>
+static inline T max(const T a, const T b) {
+ return (a > b ? a : b);
+}
#endif // CONFIG_H
diff --git a/daemon/DiskIODriver.cpp b/daemon/DiskIODriver.cpp
new file mode 100644
index 0000000..5deb0f3
--- /dev/null
+++ b/daemon/DiskIODriver.cpp
@@ -0,0 +1,125 @@
+/**
+ * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+// Define to get format macros from inttypes.h
+#define __STDC_FORMAT_MACROS
+
+#include "DiskIODriver.h"
+
+#include <inttypes.h>
+
+#include "Logging.h"
+#include "SessionData.h"
+
+class DiskIOCounter : public DriverCounter {
+public:
+ DiskIOCounter(DriverCounter *next, char *const name, int64_t *const value);
+ ~DiskIOCounter();
+
+ int64_t read();
+
+private:
+ int64_t *const mValue;
+ int64_t mPrev;
+
+ // Intentionally unimplemented
+ DiskIOCounter(const DiskIOCounter &);
+ DiskIOCounter &operator=(const DiskIOCounter &);
+};
+
+DiskIOCounter::DiskIOCounter(DriverCounter *next, char *const name, int64_t *const value) : DriverCounter(next, name), mValue(value), mPrev(0) {
+}
+
+DiskIOCounter::~DiskIOCounter() {
+}
+
+int64_t DiskIOCounter::read() {
+ int64_t result = *mValue - mPrev;
+ mPrev = *mValue;
+ // Kernel assumes a sector is 512 bytes
+ return result << 9;
+}
+
+DiskIODriver::DiskIODriver() : mBuf(), mReadBytes(0), mWriteBytes(0) {
+}
+
+DiskIODriver::~DiskIODriver() {
+}
+
+void DiskIODriver::readEvents(mxml_node_t *const) {
+ // Only for use with perf
+ if (!gSessionData->perf.isSetup()) {
+ return;
+ }
+
+ setCounters(new DiskIOCounter(getCounters(), strdup("Linux_block_rq_rd"), &mReadBytes));
+ setCounters(new DiskIOCounter(getCounters(), strdup("Linux_block_rq_wr"), &mWriteBytes));
+}
+
+void DiskIODriver::doRead() {
+ if (!countersEnabled()) {
+ return;
+ }
+
+ if (!mBuf.read("/proc/diskstats")) {
+ logg->logError(__FILE__, __LINE__, "Unable to read /proc/diskstats");
+ handleException();
+ }
+
+ mReadBytes = 0;
+ mWriteBytes = 0;
+
+ char *lastName = NULL;
+ int lastNameLen = -1;
+ char *start = mBuf.getBuf();
+ while (*start != '\0') {
+ char *end = strchr(start, '\n');
+ if (end != NULL) {
+ *end = '\0';
+ }
+
+ int nameStart = -1;
+ int nameEnd = -1;
+ int64_t readBytes = -1;
+ int64_t writeBytes = -1;
+ const int count = sscanf(start, "%*d %*d %n%*s%n %*u %*u %" SCNu64 " %*u %*u %*u %" SCNu64, &nameStart, &nameEnd, &readBytes, &writeBytes);
+ if (count != 2) {
+ logg->logError(__FILE__, __LINE__, "Unable to parse /proc/diskstats");
+ handleException();
+ }
+
+ // Skip partitions which are identified if the name is a substring of the last non-partition
+ if ((lastName == NULL) || (strncmp(lastName, start + nameStart, lastNameLen) != 0)) {
+ lastName = start + nameStart;
+ lastNameLen = nameEnd - nameStart;
+ mReadBytes += readBytes;
+ mWriteBytes += writeBytes;
+ }
+
+ if (end == NULL) {
+ break;
+ }
+ start = end + 1;
+ }
+}
+
+void DiskIODriver::start() {
+ doRead();
+ // Initialize previous values
+ for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ counter->read();
+ }
+}
+
+void DiskIODriver::read(Buffer *const buffer) {
+ doRead();
+ super::read(buffer);
+}
diff --git a/daemon/DiskIODriver.h b/daemon/DiskIODriver.h
new file mode 100644
index 0000000..d0db18c
--- /dev/null
+++ b/daemon/DiskIODriver.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef DISKIODRIVER_H
+#define DISKIODRIVER_H
+
+#include "Driver.h"
+#include "DynBuf.h"
+
+class DiskIODriver : public PolledDriver {
+private:
+ typedef PolledDriver super;
+
+public:
+ DiskIODriver();
+ ~DiskIODriver();
+
+ void readEvents(mxml_node_t *const root);
+ void start();
+ void read(Buffer *const buffer);
+
+private:
+ void doRead();
+
+ DynBuf mBuf;
+ int64_t mReadBytes;
+ int64_t mWriteBytes;
+
+ // Intentionally unimplemented
+ DiskIODriver(const DiskIODriver &);
+ DiskIODriver &operator=(const DiskIODriver &);
+};
+
+#endif // DISKIODRIVER_H
diff --git a/daemon/Driver.cpp b/daemon/Driver.cpp
index 09e0401..275da31 100644
--- a/daemon/Driver.cpp
+++ b/daemon/Driver.cpp
@@ -8,8 +8,89 @@
#include "Driver.h"
+#include "Buffer.h"
+#include "SessionData.h"
+
+DriverCounter::DriverCounter(DriverCounter *const next, const char *const name) : mNext(next), mName(name), mKey(getEventKey()), mEnabled(false) {
+}
+
+DriverCounter::~DriverCounter() {
+ delete mName;
+}
+
Driver *Driver::head = NULL;
Driver::Driver() : next(head) {
head = this;
}
+
+SimpleDriver::~SimpleDriver() {
+ DriverCounter *counters = mCounters;
+ while (counters != NULL) {
+ DriverCounter *counter = counters;
+ counters = counter->getNext();
+ delete counter;
+ }
+}
+
+DriverCounter *SimpleDriver::findCounter(const Counter &counter) const {
+ for (DriverCounter *driverCounter = mCounters; driverCounter != NULL; driverCounter = driverCounter->getNext()) {
+ if (strcmp(driverCounter->getName(), counter.getType()) == 0) {
+ return driverCounter;
+ }
+ }
+
+ return NULL;
+}
+
+bool SimpleDriver::claimCounter(const Counter &counter) const {
+ return findCounter(counter) != NULL;
+}
+
+bool SimpleDriver::countersEnabled() const {
+ for (DriverCounter *counter = mCounters; counter != NULL; counter = counter->getNext()) {
+ if (counter->isEnabled()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void SimpleDriver::resetCounters() {
+ for (DriverCounter *counter = mCounters; counter != NULL; counter = counter->getNext()) {
+ counter->setEnabled(false);
+ }
+}
+
+void SimpleDriver::setupCounter(Counter &counter) {
+ DriverCounter *const driverCounter = findCounter(counter);
+ if (driverCounter == NULL) {
+ counter.setEnabled(false);
+ return;
+ }
+ driverCounter->setEnabled(true);
+ counter.setKey(driverCounter->getKey());
+}
+
+int SimpleDriver::writeCounters(mxml_node_t *root) const {
+ int count = 0;
+ for (DriverCounter *counter = mCounters; counter != NULL; counter = counter->getNext()) {
+ mxml_node_t *node = mxmlNewElement(root, "counter");
+ mxmlElementSetAttr(node, "name", counter->getName());
+ ++count;
+ }
+
+ return count;
+}
+
+PolledDriver::~PolledDriver() {
+}
+
+void PolledDriver::read(Buffer *const buffer) {
+ for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ buffer->event64(counter->getKey(), counter->read());
+ }
+}
diff --git a/daemon/Driver.h b/daemon/Driver.h
index e5ed7b6..72870e3 100644
--- a/daemon/Driver.h
+++ b/daemon/Driver.h
@@ -9,10 +9,36 @@
#ifndef DRIVER_H
#define DRIVER_H
+#include <stdint.h>
+
#include "mxml/mxml.h"
+class Buffer;
class Counter;
+class DriverCounter {
+public:
+ DriverCounter(DriverCounter *const next, const char *const name);
+ virtual ~DriverCounter();
+
+ DriverCounter *getNext() const { return mNext; }
+ const char *getName() const { return mName; }
+ int getKey() const { return mKey; }
+ bool isEnabled() const { return mEnabled; }
+ void setEnabled(const bool enabled) { mEnabled = enabled; }
+ virtual int64_t read() { return -1; }
+
+private:
+ DriverCounter *const mNext;
+ const char *const mName;
+ const int mKey;
+ bool mEnabled;
+
+ // Intentionally unimplemented
+ DriverCounter(const DriverCounter &);
+ DriverCounter &operator=(const DriverCounter &);
+};
+
class Driver {
public:
static Driver *getHead() { return head; }
@@ -26,15 +52,17 @@ public:
// Enables and prepares the counter for capture
virtual void setupCounter(Counter &counter) = 0;
+ // Performs any actions needed for setup or based on eventsXML
+ virtual void readEvents(mxml_node_t *const) {}
// Emits available counters
- virtual int writeCounters(mxml_node_t *root) const = 0;
+ virtual int writeCounters(mxml_node_t *const root) const = 0;
// Emits possible dynamically generated events/counters
- virtual void writeEvents(mxml_node_t *) const {}
+ virtual void writeEvents(mxml_node_t *const) const {}
Driver *getNext() const { return next; }
protected:
- Driver ();
+ Driver();
private:
static Driver *head;
@@ -45,4 +73,46 @@ private:
Driver &operator=(const Driver &);
};
+class SimpleDriver : public Driver {
+public:
+ virtual ~SimpleDriver();
+
+ bool claimCounter(const Counter &counter) const;
+ bool countersEnabled() const;
+ void resetCounters();
+ void setupCounter(Counter &counter);
+ int writeCounters(mxml_node_t *root) const;
+
+protected:
+ SimpleDriver() : mCounters(NULL) {}
+
+ DriverCounter *getCounters() const { return mCounters; }
+ void setCounters(DriverCounter *const counter) { mCounters = counter; }
+
+ DriverCounter *findCounter(const Counter &counter) const;
+
+private:
+ DriverCounter *mCounters;
+
+ // Intentionally unimplemented
+ SimpleDriver(const SimpleDriver &);
+ SimpleDriver &operator=(const SimpleDriver &);
+};
+
+class PolledDriver : public SimpleDriver {
+public:
+ virtual ~PolledDriver();
+
+ virtual void start() {}
+ virtual void read(Buffer *const buffer);
+
+protected:
+ PolledDriver() {}
+
+private:
+ // Intentionally unimplemented
+ PolledDriver(const PolledDriver &);
+ PolledDriver &operator=(const PolledDriver &);
+};
+
#endif // DRIVER_H
diff --git a/daemon/DriverSource.cpp b/daemon/DriverSource.cpp
index 11d3095..7f299b6 100644
--- a/daemon/DriverSource.cpp
+++ b/daemon/DriverSource.cpp
@@ -6,6 +6,7 @@
* published by the Free Software Foundation.
*/
+// Define to get format macros from inttypes.h
#define __STDC_FORMAT_MACROS
#include "DriverSource.h"
@@ -93,19 +94,19 @@ bool DriverSource::prepare() {
}
void DriverSource::bootstrapThread() {
- prctl(PR_SET_NAME, (unsigned long)&"gatord-bootstrap", 0, 0, 0);
+ prctl(PR_SET_NAME, (unsigned long)&"gatord-proc", 0, 0, 0);
DynBuf printb;
DynBuf b1;
DynBuf b2;
- DynBuf b3;
+ const uint64_t currTime = getTime();
- if (!readProc(mBuffer, false, &printb, &b1, &b2, &b3)) {
- logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__);
+ if (!readProcComms(currTime, mBuffer, &printb, &b1, &b2)) {
+ logg->logError(__FILE__, __LINE__, "readProcComms failed");
handleException();
}
- mBuffer->commit(1);
+ mBuffer->commit(currTime);
mBuffer->setDone();
}
@@ -128,7 +129,7 @@ void DriverSource::run() {
}
// open the buffer which calls userspace_buffer_open() in the driver
- mBufferFD = open("/dev/gator/buffer", O_RDONLY);
+ mBufferFD = open("/dev/gator/buffer", O_RDONLY | O_CLOEXEC);
if (mBufferFD < 0) {
logg->logError(__FILE__, __LINE__, "The gator driver did not set up properly. Please view the linux console or dmesg log for more information on the failure.");
handleException();
@@ -232,7 +233,7 @@ void DriverSource::write(Sender *sender) {
int DriverSource::readIntDriver(const char *fullpath, int *value) {
char data[40]; // Sufficiently large to hold any integer
- const int fd = open(fullpath, O_RDONLY);
+ const int fd = open(fullpath, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
return -1;
}
@@ -257,7 +258,7 @@ int DriverSource::readIntDriver(const char *fullpath, int *value) {
int DriverSource::readInt64Driver(const char *fullpath, int64_t *value) {
char data[40]; // Sufficiently large to hold any integer
- const int fd = open(fullpath, O_RDONLY);
+ const int fd = open(fullpath, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
return -1;
}
@@ -281,7 +282,7 @@ int DriverSource::readInt64Driver(const char *fullpath, int64_t *value) {
}
int DriverSource::writeDriver(const char *fullpath, const char *data) {
- int fd = open(fullpath, O_WRONLY);
+ int fd = open(fullpath, O_WRONLY | O_CLOEXEC);
if (fd < 0) {
return -1;
}
diff --git a/daemon/DynBuf.cpp b/daemon/DynBuf.cpp
index 6f92b33..df20713 100644
--- a/daemon/DynBuf.cpp
+++ b/daemon/DynBuf.cpp
@@ -40,7 +40,7 @@ int DynBuf::resize(const size_t minCapacity) {
bool DynBuf::read(const char *const path) {
int result = false;
- const int fd = open(path, O_RDONLY);
+ const int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
return false;
diff --git a/daemon/EventsXML.cpp b/daemon/EventsXML.cpp
index cf0192e..d905bba 100644
--- a/daemon/EventsXML.cpp
+++ b/daemon/EventsXML.cpp
@@ -47,7 +47,7 @@ char *EventsXML::getXML() {
// Add dynamic events from the drivers
mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
if (!events) {
- logg->logMessage("Unable to find <events> node in the events.xml");
+ logg->logError(__FILE__, __LINE__, "Unable to find <events> node in the events.xml");
handleException();
}
for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
diff --git a/daemon/ExternalSource.cpp b/daemon/ExternalSource.cpp
index b6ec301..8f5e6b6 100644
--- a/daemon/ExternalSource.cpp
+++ b/daemon/ExternalSource.cpp
@@ -19,6 +19,9 @@
static const char MALI_VIDEO[] = "\0mali-video";
static const char MALI_VIDEO_STARTUP[] = "\0mali-video-startup";
static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n";
+static const char MALI_GRAPHICS[] = "\0mali_thirdparty_server";
+static const char MALI_GRAPHICS_STARTUP[] = "\0mali_thirdparty_client";
+static const char MALI_GRAPHICS_V1[] = "MALI_GRAPHICS 1\n";
static bool setNonblock(const int fd) {
int flags;
@@ -37,16 +40,15 @@ static bool setNonblock(const int fd) {
return true;
}
-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) {
+ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mAnnotate(8083), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) {
sem_init(&mBufferSem, 0, 0);
}
ExternalSource::~ExternalSource() {
}
-void ExternalSource::waitFor(const uint64_t currTime, const int bytes) {
+void ExternalSource::waitFor(const int bytes) {
while (mBuffer.bytesAvailable() <= bytes) {
- mBuffer.check(currTime);
sem_wait(&mBufferSem);
}
}
@@ -63,11 +65,21 @@ void ExternalSource::configureConnection(const int fd, const char *const handsha
}
// Write the handshake to the circular buffer
- waitFor(1, Buffer::MAXSIZE_PACK32 + 4 + size - 1);
+ waitFor(Buffer::MAXSIZE_PACK32 + size - 1);
mBuffer.packInt(fd);
- mBuffer.writeLEInt((unsigned char *)mBuffer.getWritePos(), size - 1);
- mBuffer.advanceWrite(4);
mBuffer.writeBytes(handshake, size - 1);
+ mBuffer.commit(1);
+}
+
+bool ExternalSource::connectMali() {
+ mMaliUds = OlySocket::connect(MALI_GRAPHICS, sizeof(MALI_GRAPHICS));
+ if (mMaliUds < 0) {
+ return false;
+ }
+
+ configureConnection(mMaliUds, MALI_GRAPHICS_V1, sizeof(MALI_GRAPHICS_V1));
+
+ return true;
}
bool ExternalSource::connectMve() {
@@ -90,10 +102,15 @@ bool ExternalSource::connectMve() {
}
bool ExternalSource::prepare() {
- if (!mMonitor.init() || !setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd())) {
+ if (!mMonitor.init() ||
+ !setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd()) ||
+ !setNonblock(mMaliStartupUds.getFd()) || !mMonitor.add(mMaliStartupUds.getFd()) ||
+ !setNonblock(mAnnotate.getFd()) || !mMonitor.add(mAnnotate.getFd()) ||
+ false) {
return false;
}
+ connectMali();
connectMve();
return true;
@@ -104,7 +121,7 @@ void ExternalSource::run() {
prctl(PR_SET_NAME, (unsigned long)&"gatord-external", 0, 0, 0);
- if (pipe(pipefd) != 0) {
+ if (pipe_cloexec(pipefd) != 0) {
logg->logError(__FILE__, __LINE__, "pipe failed");
handleException();
}
@@ -115,6 +132,9 @@ void ExternalSource::run() {
handleException();
}
+ // Notify annotate clients to retry connecting to gatord
+ gSessionData->annotateListener.signal();
+
while (gSessionData->mSessionIsActive) {
struct epoll_event events[16];
// Clear any pending sem posts
@@ -138,36 +158,60 @@ void ExternalSource::run() {
logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali video connection");
handleException();
}
+ } else if (fd == mMaliStartupUds.getFd()) {
+ // Mali Graphics says it's alive
+ int client = mMaliStartupUds.acceptConnection();
+ // Don't read from this connection, establish a new connection to Mali Graphics
+ close(client);
+ if (!connectMali()) {
+ logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali graphics connection");
+ handleException();
+ }
+ } else if (fd == mAnnotate.getFd()) {
+ int client = mAnnotate.acceptConnection();
+ if (!setNonblock(client) || !mMonitor.add(client)) {
+ logg->logError(__FILE__, __LINE__, "Unable to set socket options on incoming annotation connection");
+ handleException();
+ }
} else if (fd == pipefd[0]) {
// Means interrupt has been called and mSessionIsActive should be reread
} else {
- while (true) {
- waitFor(currTime, Buffer::MAXSIZE_PACK32 + 4);
-
+ /* This can result in some starvation if there are multiple
+ * threads which are annotating heavily, but it is not
+ * recommended that threads annotate that much as it can also
+ * starve out the gator data.
+ */
+ while (gSessionData->mSessionIsActive) {
+ // Wait until there is enough room for the fd, two headers and two ints
+ waitFor(7*Buffer::MAXSIZE_PACK32 + 2*sizeof(uint32_t));
mBuffer.packInt(fd);
- char *const bytesPos = mBuffer.getWritePos();
- mBuffer.advanceWrite(4);
const int contiguous = mBuffer.contiguousSpaceAvailable();
const int bytes = read(fd, mBuffer.getWritePos(), contiguous);
if (bytes < 0) {
if (errno == EAGAIN) {
- // Nothing left to read, and Buffer convention dictates that writePos can't go backwards
- mBuffer.writeLEInt((unsigned char *)bytesPos, 0);
+ // Nothing left to read
+ mBuffer.commit(currTime);
break;
}
// Something else failed, close the socket
- mBuffer.writeLEInt((unsigned char *)bytesPos, -1);
+ mBuffer.commit(currTime);
+ mBuffer.packInt(-1);
+ mBuffer.packInt(fd);
+ mBuffer.commit(currTime);
close(fd);
break;
} else if (bytes == 0) {
// The other side is closed
- mBuffer.writeLEInt((unsigned char *)bytesPos, -1);
+ mBuffer.commit(currTime);
+ mBuffer.packInt(-1);
+ mBuffer.packInt(fd);
+ mBuffer.commit(currTime);
close(fd);
break;
}
- mBuffer.writeLEInt((unsigned char *)bytesPos, bytes);
mBuffer.advanceWrite(bytes);
+ mBuffer.commit(currTime);
// Short reads also mean nothing is left to read
if (bytes < contiguous) {
@@ -176,13 +220,14 @@ void ExternalSource::run() {
}
}
}
-
- // Only call mBufferCheck once per iteration
- mBuffer.check(currTime);
}
mBuffer.setDone();
+ if (mMveUds >= 0) {
+ gSessionData->maliVideo.stop(mMveUds);
+ }
+
mInterruptFd = -1;
close(pipefd[0]);
close(pipefd[1]);
diff --git a/daemon/ExternalSource.h b/daemon/ExternalSource.h
index 2e7ed27..919e75e 100644
--- a/daemon/ExternalSource.h
+++ b/daemon/ExternalSource.h
@@ -16,7 +16,7 @@
#include "OlySocket.h"
#include "Source.h"
-// Unix domain socket counters from external sources like graphics drivers
+// Counters from external sources like graphics drivers and annotations
class ExternalSource : public Source {
public:
ExternalSource(sem_t *senderSem);
@@ -30,15 +30,19 @@ public:
void write(Sender *sender);
private:
- void waitFor(const uint64_t currTime, const int bytes);
+ void waitFor(const int bytes);
void configureConnection(const int fd, const char *const handshake, size_t size);
+ bool connectMali();
bool connectMve();
sem_t mBufferSem;
Buffer mBuffer;
Monitor mMonitor;
OlyServerSocket mMveStartupUds;
+ OlyServerSocket mMaliStartupUds;
+ OlyServerSocket mAnnotate;
int mInterruptFd;
+ int mMaliUds;
int mMveUds;
// Intentionally unimplemented
diff --git a/daemon/FSDriver.cpp b/daemon/FSDriver.cpp
index 40c8df1..dd8eb80 100644
--- a/daemon/FSDriver.cpp
+++ b/daemon/FSDriver.cpp
@@ -14,43 +14,34 @@
#include <sys/types.h>
#include <unistd.h>
-#include "Buffer.h"
-#include "Counter.h"
#include "DriverSource.h"
#include "Logging.h"
-#include "SessionData.h"
-class FSCounter {
+class FSCounter : public DriverCounter {
public:
- FSCounter(FSCounter *next, char *name, const char *regex);
+ FSCounter(DriverCounter *next, char *name, char *path, const char *regex);
~FSCounter();
- FSCounter *getNext() const { return next; }
- int getKey() const { return key; }
- bool isEnabled() const { return enabled; }
- void setEnabled(const bool enabled) { this->enabled = enabled; }
- const char *getName() const { return name; }
+ const char *getPath() const { return mPath; }
+
int64_t read();
private:
- FSCounter *const next;
- regex_t reg;
- char *name;
- const int key;
- int enabled : 1,
- useRegex : 1;
+ char *const mPath;
+ regex_t mReg;
+ bool mUseRegex;
// Intentionally unimplemented
FSCounter(const FSCounter &);
FSCounter &operator=(const FSCounter &);
};
-FSCounter::FSCounter(FSCounter *next, char *name, const char *regex) : next(next), name(name), key(getEventKey()), enabled(false), useRegex(regex != NULL) {
- if (useRegex) {
- int result = regcomp(&reg, regex, REG_EXTENDED);
+FSCounter::FSCounter(DriverCounter *next, char *name, char *path, const char *regex) : DriverCounter(next, name), mPath(path), mUseRegex(regex != NULL) {
+ if (mUseRegex) {
+ int result = regcomp(&mReg, regex, REG_EXTENDED);
if (result != 0) {
char buf[128];
- regerror(result, &reg, buf, sizeof(buf));
+ regerror(result, &mReg, buf, sizeof(buf));
logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf);
handleException();
}
@@ -58,18 +49,18 @@ FSCounter::FSCounter(FSCounter *next, char *name, const char *regex) : next(next
}
FSCounter::~FSCounter() {
- free(name);
- if (useRegex) {
- regfree(&reg);
+ free(mPath);
+ if (mUseRegex) {
+ regfree(&mReg);
}
}
int64_t FSCounter::read() {
int64_t value;
- if (useRegex) {
+ if (mUseRegex) {
char buf[4096];
size_t pos = 0;
- const int fd = open(name, O_RDONLY);
+ const int fd = open(mPath, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
goto fail;
}
@@ -86,53 +77,43 @@ int64_t FSCounter::read() {
buf[pos] = '\0';
regmatch_t match[2];
- int result = regexec(&reg, buf, 2, match, 0);
+ int result = regexec(&mReg, buf, 2, match, 0);
if (result != 0) {
- regerror(result, &reg, buf, sizeof(buf));
- logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", name, buf);
+ regerror(result, &mReg, buf, sizeof(buf));
+ logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", mPath, buf);
handleException();
}
if (match[1].rm_so < 0) {
- logg->logError(__FILE__, __LINE__, "Parsing %s failed", name);
+ logg->logError(__FILE__, __LINE__, "Parsing %s failed", mPath);
handleException();
}
- char *endptr;
+
errno = 0;
- value = strtoll(buf + match[1].rm_so, &endptr, 0);
+ value = strtoll(buf + match[1].rm_so, NULL, 0);
if (errno != 0) {
- logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", name, strerror(errno));
+ logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", mPath, strerror(errno));
handleException();
}
} else {
- if (DriverSource::readInt64Driver(name, &value) != 0) {
+ if (DriverSource::readInt64Driver(mPath, &value) != 0) {
goto fail;
}
}
return value;
fail:
- logg->logError(__FILE__, __LINE__, "Unable to read %s", name);
+ logg->logError(__FILE__, __LINE__, "Unable to read %s", mPath);
handleException();
}
-FSDriver::FSDriver() : counters(NULL) {
+FSDriver::FSDriver() {
}
FSDriver::~FSDriver() {
- while (counters != NULL) {
- FSCounter * counter = counters;
- counters = counter->getNext();
- delete counter;
- }
}
-void FSDriver::setup(mxml_node_t *const xml) {
- // fs driver does not currently work with perf
- if (gSessionData->perf.isSetup()) {
- return;
- }
-
+void FSDriver::readEvents(mxml_node_t *const xml) {
mxml_node_t *node = xml;
while (true) {
node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
@@ -140,56 +121,33 @@ void FSDriver::setup(mxml_node_t *const xml) {
break;
}
const char *counter = mxmlElementGetAttr(node, "counter");
- if ((counter != NULL) && (counter[0] == '/')) {
- const char *regex = mxmlElementGetAttr(node, "regex");
- counters = new FSCounter(counters, strdup(counter), regex);
+ if (counter == NULL) {
+ continue;
}
- }
-}
-FSCounter *FSDriver::findCounter(const Counter &counter) const {
- for (FSCounter * fsCounter = counters; fsCounter != NULL; fsCounter = fsCounter->getNext()) {
- if (strcmp(fsCounter->getName(), counter.getType()) == 0) {
- return fsCounter;
+ if (counter[0] == '/') {
+ logg->logError(__FILE__, __LINE__, "Old style filesystem counter (%s) detected, please create a new unique counter value and move the filename into the path attribute, see events-Filesystem.xml for examples", counter);
+ handleException();
}
- }
-
- return NULL;
-}
-bool FSDriver::claimCounter(const Counter &counter) const {
- return findCounter(counter) != NULL;
-}
-
-bool FSDriver::countersEnabled() const {
- for (FSCounter *counter = counters; counter != NULL; counter = counter->getNext()) {
- if (counter->isEnabled()) {
- return true;
+ if (strncmp(counter, "filesystem_", 11) != 0) {
+ continue;
}
- }
- return false;
-}
-void FSDriver::resetCounters() {
- for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
- counter->setEnabled(false);
- }
-}
-
-void FSDriver::setupCounter(Counter &counter) {
- FSCounter *const fsCounter = findCounter(counter);
- if (fsCounter == NULL) {
- counter.setEnabled(false);
- return;
+ const char *path = mxmlElementGetAttr(node, "path");
+ if (path == NULL) {
+ logg->logError(__FILE__, __LINE__, "The filesystem counter %s is missing the required path attribute", counter);
+ handleException();
+ }
+ const char *regex = mxmlElementGetAttr(node, "regex");
+ setCounters(new FSCounter(getCounters(), strdup(counter), strdup(path), regex));
}
- fsCounter->setEnabled(true);
- counter.setKey(fsCounter->getKey());
}
int FSDriver::writeCounters(mxml_node_t *root) const {
int count = 0;
- for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
- if (access(counter->getName(), R_OK) == 0) {
+ for (FSCounter *counter = static_cast<FSCounter *>(getCounters()); counter != NULL; counter = static_cast<FSCounter *>(counter->getNext())) {
+ if (access(counter->getPath(), R_OK) == 0) {
mxml_node_t *node = mxmlNewElement(root, "counter");
mxmlElementSetAttr(node, "name", counter->getName());
++count;
@@ -198,15 +156,3 @@ int FSDriver::writeCounters(mxml_node_t *root) const {
return count;
}
-
-void FSDriver::start() {
-}
-
-void FSDriver::read(Buffer * const buffer) {
- for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
- if (!counter->isEnabled()) {
- continue;
- }
- buffer->event(counter->getKey(), counter->read());
- }
-}
diff --git a/daemon/FSDriver.h b/daemon/FSDriver.h
index ef39553..a7dc8b4 100644
--- a/daemon/FSDriver.h
+++ b/daemon/FSDriver.h
@@ -11,31 +11,16 @@
#include "Driver.h"
-class Buffer;
-class FSCounter;
-
-class FSDriver : public Driver {
+class FSDriver : public PolledDriver {
public:
FSDriver();
~FSDriver();
- void setup(mxml_node_t *const xml);
-
- bool claimCounter(const Counter &counter) const;
- bool countersEnabled() const;
- void resetCounters();
- void setupCounter(Counter &counter);
+ void readEvents(mxml_node_t *const xml);
int writeCounters(mxml_node_t *root) const;
- void start();
- void read(Buffer * buffer);
-
private:
- FSCounter *findCounter(const Counter &counter) const;
-
- FSCounter *counters;
-
// Intentionally unimplemented
FSDriver(const FSDriver &);
FSDriver &operator=(const FSDriver &);
diff --git a/daemon/Fifo.cpp b/daemon/Fifo.cpp
index f672e92..41275fd 100644
--- a/daemon/Fifo.cpp
+++ b/daemon/Fifo.cpp
@@ -9,9 +9,6 @@
#include "Fifo.h"
#include <stdlib.h>
-#ifdef WIN32
-#define valloc malloc
-#endif
#include "Logging.h"
@@ -23,7 +20,7 @@ Fifo::Fifo(int singleBufferSize, int bufferSize, sem_t* readerSem) {
mWrapThreshold = bufferSize;
mSingleBufferSize = singleBufferSize;
mReaderSem = readerSem;
- mBuffer = (char*)valloc(bufferSize + singleBufferSize);
+ mBuffer = (char*)malloc(bufferSize + singleBufferSize);
mEnd = false;
if (mBuffer == NULL) {
diff --git a/daemon/Fifo.h b/daemon/Fifo.h
index bdda3f5..21c8d85 100644
--- a/daemon/Fifo.h
+++ b/daemon/Fifo.h
@@ -6,8 +6,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __FIFO_H__
-#define __FIFO_H__
+#ifndef __FIFO_H__
+#define __FIFO_H__
#ifdef WIN32
#include <windows.h>
@@ -35,10 +35,10 @@ public:
private:
int mSingleBufferSize, mWrite, mRead, mReadCommit, mRaggedEnd, mWrapThreshold;
- sem_t mWaitForSpaceSem;
+ sem_t mWaitForSpaceSem;
sem_t* mReaderSem;
- char* mBuffer;
- bool mEnd;
+ char* mBuffer;
+ bool mEnd;
// Intentionally unimplemented
Fifo(const Fifo &);
diff --git a/daemon/FtraceDriver.cpp b/daemon/FtraceDriver.cpp
new file mode 100644
index 0000000..b156f1c
--- /dev/null
+++ b/daemon/FtraceDriver.cpp
@@ -0,0 +1,118 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "FtraceDriver.h"
+
+#include <regex.h>
+
+#include "Logging.h"
+
+class FtraceCounter : public DriverCounter {
+public:
+ FtraceCounter(DriverCounter *next, char *name, const char *regex);
+ ~FtraceCounter();
+
+ int read(const char *const line, int64_t *values);
+
+private:
+ regex_t reg;
+
+ // Intentionally unimplemented
+ FtraceCounter(const FtraceCounter &);
+ FtraceCounter &operator=(const FtraceCounter &);
+};
+
+FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex) : DriverCounter(next, name) {
+ int result = regcomp(&reg, regex, REG_EXTENDED);
+ if (result != 0) {
+ char buf[128];
+ regerror(result, &reg, buf, sizeof(buf));
+ logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf);
+ handleException();
+ }
+}
+
+FtraceCounter::~FtraceCounter() {
+ regfree(&reg);
+}
+
+int FtraceCounter::read(const char *const line, int64_t *values) {
+ regmatch_t match[2];
+ int result = regexec(&reg, line, 2, match, 0);
+ if (result != 0) {
+ // No match
+ return 0;
+ }
+
+ if (match[1].rm_so < 0) {
+ logg->logError(__FILE__, __LINE__, "Parsing %s failed", getName());
+ handleException();
+ }
+
+ errno = 0;
+ int64_t value = strtoll(line + match[1].rm_so, NULL, 0);
+ if (errno != 0) {
+ logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", getName(), strerror(errno));
+ handleException();
+ }
+
+ values[0] = getKey();
+ values[1] = value;
+
+ return 1;
+}
+
+FtraceDriver::FtraceDriver() : mValues(NULL) {
+}
+
+FtraceDriver::~FtraceDriver() {
+ delete [] mValues;
+}
+
+void FtraceDriver::readEvents(mxml_node_t *const xml) {
+ mxml_node_t *node = xml;
+ int count = 0;
+ while (true) {
+ node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
+ if (node == NULL) {
+ break;
+ }
+ const char *counter = mxmlElementGetAttr(node, "counter");
+ if (counter == NULL) {
+ continue;
+ }
+
+ if (strncmp(counter, "ftrace_", 7) != 0) {
+ continue;
+ }
+
+ const char *regex = mxmlElementGetAttr(node, "regex");
+ if (regex == NULL) {
+ logg->logError(__FILE__, __LINE__, "The regex counter %s is missing the required regex attribute", counter);
+ handleException();
+ }
+ setCounters(new FtraceCounter(getCounters(), strdup(counter), regex));
+ ++count;
+ }
+
+ mValues = new int64_t[2*count];
+}
+
+int FtraceDriver::read(const char *line, int64_t **buf) {
+ int count = 0;
+
+ for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ count += counter->read(line, mValues + 2*count);
+ }
+
+ *buf = mValues;
+ return count;
+}
diff --git a/daemon/FtraceDriver.h b/daemon/FtraceDriver.h
new file mode 100644
index 0000000..5f958be
--- /dev/null
+++ b/daemon/FtraceDriver.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FTRACEDRIVER_H
+#define FTRACEDRIVER_H
+
+#include "Driver.h"
+
+class FtraceDriver : public SimpleDriver {
+public:
+ FtraceDriver();
+ ~FtraceDriver();
+
+ void readEvents(mxml_node_t *const xml);
+
+ int read(const char *line, int64_t **buf);
+
+private:
+ int64_t *mValues;
+
+ // Intentionally unimplemented
+ FtraceDriver(const FtraceDriver &);
+ FtraceDriver &operator=(const FtraceDriver &);
+};
+
+#endif // FTRACEDRIVER_H
diff --git a/daemon/FtraceSource.cpp b/daemon/FtraceSource.cpp
new file mode 100644
index 0000000..5216333
--- /dev/null
+++ b/daemon/FtraceSource.cpp
@@ -0,0 +1,158 @@
+/**
+ * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "FtraceSource.h"
+
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "DriverSource.h"
+#include "Logging.h"
+#include "SessionData.h"
+
+static void handler(int signum)
+{
+ (void)signum;
+};
+
+FtraceSource::FtraceSource(sem_t *senderSem) : mFtraceFh(NULL), mBuffer(0, FRAME_BLOCK_COUNTER, 128*1024, senderSem), mTid(-1), mTracingOn(0) {
+}
+
+FtraceSource::~FtraceSource() {
+}
+
+bool FtraceSource::prepare() {
+ {
+ struct sigaction act;
+ act.sa_handler = handler;
+ act.sa_flags = (int)SA_RESETHAND;
+ if (sigaction(SIGUSR1, &act, NULL) != 0) {
+ logg->logError(__FILE__, __LINE__, "sigaction failed: %s\n", strerror(errno));
+ handleException();
+ }
+ }
+
+ if (DriverSource::readIntDriver("/sys/kernel/debug/tracing/tracing_on", &mTracingOn)) {
+ logg->logError(__FILE__, __LINE__, "Unable to read if ftrace is enabled");
+ handleException();
+ }
+
+ if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "0") != 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to turn ftrace off before truncating the buffer");
+ handleException();
+ }
+
+ {
+ int fd;
+ fd = open("/sys/kernel/debug/tracing/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
+ if (fd < 0) {
+ logg->logError(__FILE__, __LINE__, "Unable truncate ftrace buffer: %s", strerror(errno));
+ handleException();
+ }
+ close(fd);
+ }
+
+ if (DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "perf") != 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
+ handleException();
+ }
+
+ mFtraceFh = fopen_cloexec("/sys/kernel/debug/tracing/trace_pipe", "rb");
+ if (mFtraceFh == NULL) {
+ logg->logError(__FILE__, __LINE__, "Unable to open trace_pipe");
+ handleException();
+ }
+
+ return true;
+}
+
+void FtraceSource::run() {
+ prctl(PR_SET_NAME, (unsigned long)&"gatord-ftrace", 0, 0, 0);
+ mTid = syscall(__NR_gettid);
+
+ if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "1") != 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to turn ftrace on");
+ handleException();
+ }
+
+ while (gSessionData->mSessionIsActive) {
+ char buf[1<<12];
+
+ if (fgets(buf, sizeof(buf), mFtraceFh) == NULL) {
+ if (errno == EINTR) {
+ // Interrupted by interrupt - likely user request to terminate
+ break;
+ }
+ logg->logError(__FILE__, __LINE__, "Unable read trace data: %s", strerror(errno));
+ handleException();
+ }
+
+ const uint64_t currTime = getTime();
+
+ char *const colon = strstr(buf, ": ");
+ if (colon == NULL) {
+ logg->logError(__FILE__, __LINE__, "Unable find colon: %s", buf);
+ handleException();
+ }
+ *colon = '\0';
+
+ char *const space = strrchr(buf, ' ');
+ if (space == NULL) {
+ logg->logError(__FILE__, __LINE__, "Unable find space: %s", buf);
+ handleException();
+ }
+ *colon = ':';
+
+ int64_t *data = NULL;
+ int count = gSessionData->ftraceDriver.read(colon + 2, &data);
+ if (count > 0) {
+ errno = 0;
+ const long long time = strtod(space, NULL) * 1000000000;
+ if (errno != 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to parse time: %s", strerror(errno));
+ handleException();
+ }
+ mBuffer.event64(-1, time);
+
+ for (int i = 0; i < count; ++i) {
+ mBuffer.event64(data[2*i + 0], data[2*i + 1]);
+ }
+
+ mBuffer.check(currTime);
+ }
+
+ }
+
+ mBuffer.setDone();
+
+ DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", mTracingOn);
+ fclose(mFtraceFh);
+ DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "local");
+}
+
+void FtraceSource::interrupt() {
+ // Closing the underlying file handle does not result in the read on the ftrace file handle to return, so send a signal to the thread
+ syscall(__NR_tgkill, getpid(), mTid, SIGUSR1);
+}
+
+bool FtraceSource::isDone() {
+ return mBuffer.isDone();
+}
+
+void FtraceSource::write(Sender *sender) {
+ // Don't send ftrace data until the summary packet is sent so that monotonic delta is available
+ if (!gSessionData->mSentSummary) {
+ return;
+ }
+ if (!mBuffer.isDone()) {
+ mBuffer.write(sender);
+ }
+}
diff --git a/daemon/FtraceSource.h b/daemon/FtraceSource.h
new file mode 100644
index 0000000..2391b88
--- /dev/null
+++ b/daemon/FtraceSource.h
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FTRACESOURCE_H
+#define FTRACESOURCE_H
+
+#include <semaphore.h>
+#include <stdio.h>
+
+#include "Buffer.h"
+#include "Source.h"
+
+class FtraceSource : public Source {
+public:
+ FtraceSource(sem_t *senderSem);
+ ~FtraceSource();
+
+ bool prepare();
+ void run();
+ void interrupt();
+
+ bool isDone();
+ void write(Sender *sender);
+
+private:
+ void waitFor(const int bytes);
+
+ FILE *mFtraceFh;
+ Buffer mBuffer;
+ int mTid;
+ int mTracingOn;
+
+ // Intentionally unimplemented
+ FtraceSource(const FtraceSource &);
+ FtraceSource &operator=(const FtraceSource &);
+};
+
+#endif // FTRACESOURCE_H
diff --git a/daemon/Hwmon.h b/daemon/Hwmon.h
deleted file mode 100644
index a22a360..0000000
--- a/daemon/Hwmon.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef HWMON_H
-#define HWMON_H
-
-#include "Driver.h"
-
-class Buffer;
-class HwmonCounter;
-
-class Hwmon : public Driver {
-public:
- Hwmon();
- ~Hwmon();
-
- void setup();
-
- bool claimCounter(const Counter &counter) const;
- bool countersEnabled() const;
- void resetCounters();
- void setupCounter(Counter &counter);
-
- int writeCounters(mxml_node_t *root) const;
- void writeEvents(mxml_node_t *root) const;
-
- void start();
- void read(Buffer * buffer);
-
-private:
- HwmonCounter *findCounter(const Counter &counter) const;
-
- HwmonCounter *counters;
-
- // Intentionally unimplemented
- Hwmon(const Hwmon &);
- Hwmon &operator=(const Hwmon &);
-};
-
-#endif // HWMON_H
diff --git a/daemon/Hwmon.cpp b/daemon/HwmonDriver.cpp
index e444247..9d161ae 100644
--- a/daemon/Hwmon.cpp
+++ b/daemon/HwmonDriver.cpp
@@ -6,24 +6,33 @@
* published by the Free Software Foundation.
*/
-#include "Hwmon.h"
+#include "HwmonDriver.h"
#include "libsensors/sensors.h"
-#include "Buffer.h"
-#include "Counter.h"
#include "Logging.h"
-#include "SessionData.h"
-class HwmonCounter {
+// feature->type to input map
+static sensors_subfeature_type getInput(const sensors_feature_type type) {
+ switch (type) {
+ case SENSORS_FEATURE_IN: return SENSORS_SUBFEATURE_IN_INPUT;
+ case SENSORS_FEATURE_FAN: return SENSORS_SUBFEATURE_FAN_INPUT;
+ case SENSORS_FEATURE_TEMP: return SENSORS_SUBFEATURE_TEMP_INPUT;
+ case SENSORS_FEATURE_POWER: return SENSORS_SUBFEATURE_POWER_INPUT;
+ case SENSORS_FEATURE_ENERGY: return SENSORS_SUBFEATURE_ENERGY_INPUT;
+ case SENSORS_FEATURE_CURR: return SENSORS_SUBFEATURE_CURR_INPUT;
+ case SENSORS_FEATURE_HUMIDITY: return SENSORS_SUBFEATURE_HUMIDITY_INPUT;
+ default:
+ logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", type);
+ handleException();
+ }
+};
+
+class HwmonCounter : public DriverCounter {
public:
- HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature);
+ HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature);
~HwmonCounter();
- HwmonCounter *getNext() const { return next; }
- int getKey() const { return key; }
- bool isEnabled() const { return enabled; }
- const char *getName() const { return name; }
const char *getLabel() const { return label; }
const char *getTitle() const { return title; }
bool isDuplicate() const { return duplicate; }
@@ -32,63 +41,34 @@ public:
const char *getUnit() const { return unit; }
int getModifier() const { return modifier; }
- void setEnabled(const bool enabled) {
- this->enabled = enabled;
- // canRead will clear enabled if the counter is not readable
- canRead();
- }
-
- double read();
- bool canRead();
+ int64_t read();
private:
void init(const sensors_chip_name *chip, const sensors_feature *feature);
- HwmonCounter *const next;
- const int key;
- int polled : 1,
- readable : 1,
- enabled : 1,
- monotonic: 1,
- duplicate : 1;
-
const sensors_chip_name *chip;
const sensors_feature *feature;
-
- char *name;
char *label;
const char *title;
const char *display;
const char *counter_class;
const char *unit;
- int modifier;
double previous_value;
-
- sensors_subfeature_type input;
+ int modifier;
+ int monotonic: 1,
+ duplicate : 1;
// Intentionally unimplemented
HwmonCounter(const HwmonCounter &);
HwmonCounter &operator=(const HwmonCounter &);
};
-HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(getEventKey()), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) {
-
- int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
- char *chip_name = new char[len];
- sensors_snprintf_chip_name(chip_name, len, chip);
-
- len = snprintf(NULL, 0, "hwmon_%s_%d", chip_name, feature->number) + 1;
- name = new char[len];
- snprintf(name, len, "hwmon_%s_%d", chip_name, feature->number);
-
- delete [] chip_name;
-
+HwmonCounter::HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature) : DriverCounter(next, name), chip(chip), feature(feature), duplicate(false) {
label = sensors_get_label(chip, feature);
switch (feature->type) {
case SENSORS_FEATURE_IN:
title = "Voltage";
- input = SENSORS_SUBFEATURE_IN_INPUT;
display = "maximum";
counter_class = "absolute";
unit = "V";
@@ -97,7 +77,6 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co
break;
case SENSORS_FEATURE_FAN:
title = "Fan";
- input = SENSORS_SUBFEATURE_FAN_INPUT;
display = "average";
counter_class = "absolute";
unit = "RPM";
@@ -106,7 +85,6 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co
break;
case SENSORS_FEATURE_TEMP:
title = "Temperature";
- input = SENSORS_SUBFEATURE_TEMP_INPUT;
display = "maximum";
counter_class = "absolute";
unit = "°C";
@@ -115,7 +93,6 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co
break;
case SENSORS_FEATURE_POWER:
title = "Power";
- input = SENSORS_SUBFEATURE_POWER_INPUT;
display = "maximum";
counter_class = "absolute";
unit = "W";
@@ -124,7 +101,6 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co
break;
case SENSORS_FEATURE_ENERGY:
title = "Energy";
- input = SENSORS_SUBFEATURE_ENERGY_INPUT;
display = "accumulate";
counter_class = "delta";
unit = "J";
@@ -133,7 +109,6 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co
break;
case SENSORS_FEATURE_CURR:
title = "Current";
- input = SENSORS_SUBFEATURE_CURR_INPUT;
display = "maximum";
counter_class = "absolute";
unit = "A";
@@ -142,7 +117,6 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co
break;
case SENSORS_FEATURE_HUMIDITY:
title = "Humidity";
- input = SENSORS_SUBFEATURE_HUMIDITY_INPUT;
display = "average";
counter_class = "absolute";
unit = "%";
@@ -154,7 +128,7 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co
handleException();
}
- for (HwmonCounter * counter = next; counter != NULL; counter = counter->getNext()) {
+ for (HwmonCounter * counter = static_cast<HwmonCounter *>(next); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) {
if (strcmp(label, counter->getLabel()) == 0 && strcmp(title, counter->getTitle()) == 0) {
duplicate = true;
counter->duplicate = true;
@@ -165,16 +139,15 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co
HwmonCounter::~HwmonCounter() {
free((void *)label);
- delete [] name;
}
-double HwmonCounter::read() {
+int64_t HwmonCounter::read() {
double value;
double result;
const sensors_subfeature *subfeature;
- // Keep in sync with canRead
- subfeature = sensors_get_subfeature(chip, feature, input);
+ // Keep in sync with the read check in HwmonDriver::readEvents
+ subfeature = sensors_get_subfeature(chip, feature, getInput(feature->type));
if (!subfeature) {
logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label);
handleException();
@@ -191,46 +164,14 @@ double HwmonCounter::read() {
return result;
}
-bool HwmonCounter::canRead() {
- if (!polled) {
- double value;
- const sensors_subfeature *subfeature;
- bool result = true;
-
- subfeature = sensors_get_subfeature(chip, feature, input);
- if (!subfeature) {
- result = false;
- } else {
- result = sensors_get_value(chip, subfeature->number, &value) == 0;
- }
-
- polled = true;
- readable = result;
- }
-
- enabled &= readable;
-
- return readable;
-}
-
-Hwmon::Hwmon() : counters(NULL) {
+HwmonDriver::HwmonDriver() {
}
-Hwmon::~Hwmon() {
- while (counters != NULL) {
- HwmonCounter * counter = counters;
- counters = counter->getNext();
- delete counter;
- }
+HwmonDriver::~HwmonDriver() {
sensors_cleanup();
}
-void Hwmon::setup() {
- // hwmon does not currently work with perf
- if (gSessionData->perf.isSetup()) {
- return;
- }
-
+void HwmonDriver::readEvents(mxml_node_t *const) {
int err = sensors_init(NULL);
if (err) {
logg->logMessage("Failed to initialize libsensors! (%d)", err);
@@ -244,73 +185,34 @@ void Hwmon::setup() {
int feature_nr = 0;
const sensors_feature *feature;
while ((feature = sensors_get_features(chip, &feature_nr))) {
- counters = new HwmonCounter(counters, chip, feature);
+ // Keep in sync with HwmonCounter::read
+ // Can this counter be read?
+ double value;
+ const sensors_subfeature *const subfeature = sensors_get_subfeature(chip, feature, getInput(feature->type));
+ if ((subfeature == NULL) || (sensors_get_value(chip, subfeature->number, &value) != 0)) {
+ continue;
+ }
+
+ // Get the name of the counter
+ int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
+ char *chip_name = new char[len];
+ sensors_snprintf_chip_name(chip_name, len, chip);
+ len = snprintf(NULL, 0, "hwmon_%s_%d_%d", chip_name, chip_nr, feature->number) + 1;
+ char *const name = new char[len];
+ snprintf(name, len, "hwmon_%s_%d_%d", chip_name, chip_nr, feature->number);
+ delete [] chip_name;
+
+ setCounters(new HwmonCounter(getCounters(), name, chip, feature));
}
}
}
-HwmonCounter *Hwmon::findCounter(const Counter &counter) const {
- for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) {
- if (hwmonCounter->canRead() && strcmp(hwmonCounter->getName(), counter.getType()) == 0) {
- return hwmonCounter;
- }
- }
-
- return NULL;
-}
-
-bool Hwmon::claimCounter(const Counter &counter) const {
- return findCounter(counter) != NULL;
-}
-
-bool Hwmon::countersEnabled() const {
- for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
- if (counter->isEnabled()) {
- return true;
- }
- }
- return false;
-}
-
-void Hwmon::resetCounters() {
- for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
- counter->setEnabled(false);
- }
-}
-
-void Hwmon::setupCounter(Counter &counter) {
- HwmonCounter *const hwmonCounter = findCounter(counter);
- if (hwmonCounter == NULL) {
- counter.setEnabled(false);
- return;
- }
- hwmonCounter->setEnabled(true);
- counter.setKey(hwmonCounter->getKey());
-}
-
-int Hwmon::writeCounters(mxml_node_t *root) const {
- int count = 0;
- for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
- if (!counter->canRead()) {
- continue;
- }
- mxml_node_t *node = mxmlNewElement(root, "counter");
- mxmlElementSetAttr(node, "name", counter->getName());
- ++count;
- }
-
- return count;
-}
-
-void Hwmon::writeEvents(mxml_node_t *root) const {
+void HwmonDriver::writeEvents(mxml_node_t *root) const {
root = mxmlNewElement(root, "category");
mxmlElementSetAttr(root, "name", "hwmon");
char buf[1024];
- for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
- if (!counter->canRead()) {
- continue;
- }
+ for (HwmonCounter *counter = static_cast<HwmonCounter *>(getCounters()); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) {
mxml_node_t *node = mxmlNewElement(root, "event");
mxmlElementSetAttr(node, "counter", counter->getName());
mxmlElementSetAttr(node, "title", counter->getTitle());
@@ -333,20 +235,11 @@ void Hwmon::writeEvents(mxml_node_t *root) const {
}
}
-void Hwmon::start() {
- for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
+void HwmonDriver::start() {
+ for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
if (!counter->isEnabled()) {
continue;
}
counter->read();
}
}
-
-void Hwmon::read(Buffer * const buffer) {
- for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
- if (!counter->isEnabled()) {
- continue;
- }
- buffer->event(counter->getKey(), counter->read());
- }
-}
diff --git a/daemon/HwmonDriver.h b/daemon/HwmonDriver.h
new file mode 100644
index 0000000..f28d825
--- /dev/null
+++ b/daemon/HwmonDriver.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef HWMONDRIVER_H
+#define HWMONDRIVER_H
+
+#include "Driver.h"
+
+class HwmonDriver : public PolledDriver {
+public:
+ HwmonDriver();
+ ~HwmonDriver();
+
+ void readEvents(mxml_node_t *const root);
+
+ void writeEvents(mxml_node_t *root) const;
+
+ void start();
+
+private:
+ // Intentionally unimplemented
+ HwmonDriver(const HwmonDriver &);
+ HwmonDriver &operator=(const HwmonDriver &);
+};
+
+#endif // HWMONDRIVER_H
diff --git a/daemon/KMod.cpp b/daemon/KMod.cpp
index 73e123d..fe9dc6a 100644
--- a/daemon/KMod.cpp
+++ b/daemon/KMod.cpp
@@ -16,6 +16,7 @@
#include "Counter.h"
#include "DriverSource.h"
#include "Logging.h"
+#include "SessionData.h"
// Claim all the counters in /dev/gator/events
bool KMod::claimCounter(const Counter &counter) const {
@@ -46,11 +47,19 @@ void KMod::resetCounters() {
}
}
+static const char ARM_MALI_MIDGARD[] = "ARM_Mali-Midgard_";
+static const char ARM_MALI_T[] = "ARM_Mali-T";
+
void KMod::setupCounter(Counter &counter) {
char base[128];
char text[128];
snprintf(base, sizeof(base), "/dev/gator/events/%s", counter.getType());
+ if ((strncmp(counter.getType(), ARM_MALI_MIDGARD, sizeof(ARM_MALI_MIDGARD) - 1) == 0 ||
+ strncmp(counter.getType(), ARM_MALI_T, sizeof(ARM_MALI_T) - 1) == 0)) {
+ mIsMaliCapture = true;
+ }
+
snprintf(text, sizeof(text), "%s/enabled", base);
int enabled = true;
if (DriverSource::writeReadDriver(text, &enabled) || !enabled) {
diff --git a/daemon/KMod.h b/daemon/KMod.h
index fb7fc8a..900a60e 100644
--- a/daemon/KMod.h
+++ b/daemon/KMod.h
@@ -14,7 +14,7 @@
// Driver for the gator kernel module
class KMod : public Driver {
public:
- KMod() {}
+ KMod() : mIsMaliCapture(false) {}
~KMod() {}
bool claimCounter(const Counter &counter) const;
@@ -22,6 +22,11 @@ public:
void setupCounter(Counter &counter);
int writeCounters(mxml_node_t *root) const;
+
+ bool isMaliCapture() const { return mIsMaliCapture; }
+
+private:
+ bool mIsMaliCapture;
};
#endif // KMOD_H
diff --git a/daemon/LocalCapture.h b/daemon/LocalCapture.h
index b1e7219..25d281f 100644
--- a/daemon/LocalCapture.h
+++ b/daemon/LocalCapture.h
@@ -6,8 +6,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __LOCAL_CAPTURE_H__
-#define __LOCAL_CAPTURE_H__
+#ifndef __LOCAL_CAPTURE_H__
+#define __LOCAL_CAPTURE_H__
struct ImageLinkList;
diff --git a/daemon/Logging.cpp b/daemon/Logging.cpp
index b8d3178..41ffa1a 100644
--- a/daemon/Logging.cpp
+++ b/daemon/Logging.cpp
@@ -14,15 +14,15 @@
#include <string.h>
#ifdef WIN32
-#define MUTEX_INIT() mLoggingMutex = CreateMutex(NULL, false, NULL);
-#define MUTEX_LOCK() WaitForSingleObject(mLoggingMutex, 0xFFFFFFFF);
-#define MUTEX_UNLOCK() ReleaseMutex(mLoggingMutex);
-#define snprintf _snprintf
+#define MUTEX_INIT() mLoggingMutex = CreateMutex(NULL, false, NULL);
+#define MUTEX_LOCK() WaitForSingleObject(mLoggingMutex, 0xFFFFFFFF);
+#define MUTEX_UNLOCK() ReleaseMutex(mLoggingMutex);
+#define snprintf _snprintf
#else
#include <pthread.h>
-#define MUTEX_INIT() pthread_mutex_init(&mLoggingMutex, NULL)
-#define MUTEX_LOCK() pthread_mutex_lock(&mLoggingMutex)
-#define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex)
+#define MUTEX_INIT() pthread_mutex_init(&mLoggingMutex, NULL)
+#define MUTEX_LOCK() pthread_mutex_lock(&mLoggingMutex)
+#define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex)
#endif
// Global thread-safe logging
@@ -40,7 +40,7 @@ Logging::~Logging() {
}
void Logging::logError(const char* file, int line, const char* fmt, ...) {
- va_list args;
+ va_list args;
MUTEX_LOCK();
if (mDebug) {
@@ -61,7 +61,7 @@ void Logging::logError(const char* file, int line, const char* fmt, ...) {
void Logging::logMessage(const char* fmt, ...) {
if (mDebug) {
- va_list args;
+ va_list args;
MUTEX_LOCK();
strcpy(mLogBuf, "INFO: ");
diff --git a/daemon/Logging.h b/daemon/Logging.h
index 4934bb0..09e93ff 100644
--- a/daemon/Logging.h
+++ b/daemon/Logging.h
@@ -6,8 +6,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __LOGGING_H__
-#define __LOGGING_H__
+#ifndef __LOGGING_H__
+#define __LOGGING_H__
#include <pthread.h>
@@ -23,10 +23,10 @@ public:
char* getLastMessage() {return mLogBuf;}
private:
- char mErrBuf[4096]; // Arbitrarily large buffer to hold a string
- char mLogBuf[4096]; // Arbitrarily large buffer to hold a string
- bool mDebug;
- pthread_mutex_t mLoggingMutex;
+ char mErrBuf[4096]; // Arbitrarily large buffer to hold a string
+ char mLogBuf[4096]; // Arbitrarily large buffer to hold a string
+ bool mDebug;
+ pthread_mutex_t mLoggingMutex;
};
extern Logging* logg;
diff --git a/daemon/Makefile b/daemon/Makefile
index 2ed49fd..27531b4 100644
--- a/daemon/Makefile
+++ b/daemon/Makefile
@@ -11,11 +11,8 @@
CC = $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
-# -mthumb-interwork is required for interworking to ARM or Thumb stdlibc
-CPPFLAGS += -mthumb-interwork
-
ifeq ($(SOFTFLOAT),1)
- CPPFLAGS += -marm -march=armv4t -mfloat-abi=soft
+ CPPFLAGS += -marm -mthumb-interwork -march=armv4t -mfloat-abi=soft
LDFLAGS += -marm -march=armv4t -mfloat-abi=soft
endif
ifneq ($(SYSROOT),)
diff --git a/daemon/MaliVideoDriver.cpp b/daemon/MaliVideoDriver.cpp
index 18b413b..5eef264 100644
--- a/daemon/MaliVideoDriver.cpp
+++ b/daemon/MaliVideoDriver.cpp
@@ -34,51 +34,30 @@ static const char COUNTER[] = "ARM_Mali-V500_cnt";
static const char EVENT[] = "ARM_Mali-V500_evn";
static const char ACTIVITY[] = "ARM_Mali-V500_act";
-class MaliVideoCounter {
+class MaliVideoCounter : public DriverCounter {
public:
- MaliVideoCounter(MaliVideoCounter *next, const char *name, const MaliVideoCounterType type, const int id) : mNext(next), mName(name), mType(type), mId(id), mKey(getEventKey()), mEnabled(false) {
+ MaliVideoCounter(DriverCounter *next, const char *name, const MaliVideoCounterType type, const int id) : DriverCounter(next, name), mType(type), mId(id) {
}
~MaliVideoCounter() {
- delete mName;
}
- MaliVideoCounter *getNext() const { return mNext; }
- const char *getName() const { return mName; }
MaliVideoCounterType getType() const { return mType; }
int getId() const { return mId; }
- int getKey() const { return mKey; }
- bool isEnabled() const { return mEnabled; }
- void setEnabled(const bool enabled) { mEnabled = enabled; }
private:
- MaliVideoCounter *const mNext;
- const char *const mName;
const MaliVideoCounterType mType;
// Mali Video id
const int mId;
- // Streamline key
- const int mKey;
- bool mEnabled;
};
-MaliVideoDriver::MaliVideoDriver() : mCounters(NULL), mActivityCount(0) {
+MaliVideoDriver::MaliVideoDriver() {
}
MaliVideoDriver::~MaliVideoDriver() {
- while (mCounters != NULL) {
- MaliVideoCounter *counter = mCounters;
- mCounters = counter->getNext();
- delete counter;
- }
}
-void MaliVideoDriver::setup(mxml_node_t *const xml) {
- // hwmon does not currently work with perf
- if (gSessionData->perf.isSetup()) {
- return;
- }
-
+void MaliVideoDriver::readEvents(mxml_node_t *const xml) {
mxml_node_t *node = xml;
while (true) {
node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
@@ -90,62 +69,15 @@ void MaliVideoDriver::setup(mxml_node_t *const xml) {
// Ignore
} else if (strncmp(counter, COUNTER, sizeof(COUNTER) - 1) == 0) {
const int i = strtol(counter + sizeof(COUNTER) - 1, NULL, 10);
- mCounters = new MaliVideoCounter(mCounters, strdup(counter), MVCT_COUNTER, i);
+ setCounters(new MaliVideoCounter(getCounters(), strdup(counter), MVCT_COUNTER, i));
} else if (strncmp(counter, EVENT, sizeof(EVENT) - 1) == 0) {
const int i = strtol(counter + sizeof(EVENT) - 1, NULL, 10);
- mCounters = new MaliVideoCounter(mCounters, strdup(counter), MVCT_EVENT, i);
- } else if (strcmp(counter, ACTIVITY) == 0) {
- mCounters = new MaliVideoCounter(mCounters, strdup(ACTIVITY), MVCT_ACTIVITY, 0);
- mActivityCount = 0;
- while (true) {
- char buf[32];
- snprintf(buf, sizeof(buf), "activity%i", mActivityCount + 1);
- if (mxmlElementGetAttr(node, buf) == NULL) {
- break;
- }
- ++mActivityCount;
- }
- }
- }
-}
-
-MaliVideoCounter *MaliVideoDriver::findCounter(const Counter &counter) const {
- for (MaliVideoCounter *maliVideoCounter = mCounters; maliVideoCounter != NULL; maliVideoCounter = maliVideoCounter->getNext()) {
- if (strcmp(maliVideoCounter->getName(), counter.getType()) == 0) {
- return maliVideoCounter;
- }
- }
-
- return NULL;
-}
-
-bool MaliVideoDriver::claimCounter(const Counter &counter) const {
- return findCounter(counter) != NULL;
-}
-
-bool MaliVideoDriver::countersEnabled() const {
- for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
- if (counter->isEnabled()) {
- return true;
+ setCounters(new MaliVideoCounter(getCounters(), strdup(counter), MVCT_EVENT, i));
+ } else if (strncmp(counter, ACTIVITY, sizeof(ACTIVITY) - 1) == 0) {
+ const int i = strtol(counter + sizeof(ACTIVITY) - 1, NULL, 10);
+ setCounters(new MaliVideoCounter(getCounters(), strdup(counter), MVCT_ACTIVITY, i));
}
}
- return false;
-}
-
-void MaliVideoDriver::resetCounters() {
- for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
- counter->setEnabled(false);
- }
-}
-
-void MaliVideoDriver::setupCounter(Counter &counter) {
- MaliVideoCounter *const maliVideoCounter = findCounter(counter);
- if (maliVideoCounter == NULL) {
- counter.setEnabled(false);
- return;
- }
- maliVideoCounter->setEnabled(true);
- counter.setKey(maliVideoCounter->getKey());
}
int MaliVideoDriver::writeCounters(mxml_node_t *root) const {
@@ -153,32 +85,39 @@ int MaliVideoDriver::writeCounters(mxml_node_t *root) const {
return 0;
}
- int count = 0;
- for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
- mxml_node_t *node = mxmlNewElement(root, "counter");
- mxmlElementSetAttr(node, "name", counter->getName());
- ++count;
- }
-
- return count;
+ return super::writeCounters(root);
}
void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos) {
// size
int numEnabled = 0;
- for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
+ for (MaliVideoCounter *counter = static_cast<MaliVideoCounter *>(getCounters()); counter != NULL; counter = static_cast<MaliVideoCounter *>(counter->getNext())) {
if (counter->isEnabled() && (counter->getType() == type)) {
++numEnabled;
}
}
Buffer::packInt(buf, bufsize, pos, numEnabled*sizeof(uint32_t));
- for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
+ for (MaliVideoCounter *counter = static_cast<MaliVideoCounter *>(getCounters()); counter != NULL; counter = static_cast<MaliVideoCounter *>(counter->getNext())) {
if (counter->isEnabled() && (counter->getType() == type)) {
Buffer::packInt(buf, bufsize, pos, counter->getId());
}
}
}
+static bool writeAll(const int mveUds, const char *const buf, const int pos) {
+ int written = 0;
+ while (written < pos) {
+ size_t bytes = ::write(mveUds, buf + written, pos - written);
+ if (bytes <= 0) {
+ logg->logMessage("%s(%s:%i): write failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+ written += bytes;
+ }
+
+ return true;
+}
+
bool MaliVideoDriver::start(const int mveUds) {
char buf[256];
int pos = 0;
@@ -225,29 +164,28 @@ bool MaliVideoDriver::start(const int mveUds) {
buf[pos++] = 'e';
marshalEnable(MVCT_EVENT, buf, sizeof(buf), pos);
- /*
// code - MVE_INSTR_ENABLE_ACTIVITIES
buf[pos++] = 'C';
buf[pos++] = 'F';
buf[pos++] = 'G';
buf[pos++] = 'a';
- // size
- Buffer::packInt(buf, sizeof(buf), pos, mActivityCount*sizeof(uint32_t));
- for (int i = 0; i < mActivityCount; ++i) {
- // activity_id
- Buffer::packInt(buf, sizeof(buf), pos, i);
- }
- */
+ marshalEnable(MVCT_ACTIVITY, buf, sizeof(buf), pos);
- int written = 0;
- while (written < pos) {
- size_t bytes = ::write(mveUds, buf + written, pos - written);
- if (bytes <= 0) {
- logg->logMessage("%s(%s:%i): write failed", __FUNCTION__, __FILE__, __LINE__);
- return false;
- }
- written += bytes;
- }
+ return writeAll(mveUds, buf, pos);
+}
- return true;
+void MaliVideoDriver::stop(const int mveUds) {
+ char buf[8];
+ int pos = 0;
+
+ // code - MVE_INSTR_STOP
+ buf[pos++] = 'S';
+ buf[pos++] = 'T';
+ buf[pos++] = 'O';
+ buf[pos++] = 'P';
+ marshalEnable(MVCT_COUNTER, buf, sizeof(buf), pos);
+
+ writeAll(mveUds, buf, pos);
+
+ close(mveUds);
}
diff --git a/daemon/MaliVideoDriver.h b/daemon/MaliVideoDriver.h
index 00cb808..204a57a 100644
--- a/daemon/MaliVideoDriver.h
+++ b/daemon/MaliVideoDriver.h
@@ -19,29 +19,24 @@ enum MaliVideoCounterType {
MVCT_ACTIVITY,
};
-class MaliVideoDriver : public Driver {
+class MaliVideoDriver : public SimpleDriver {
+private:
+ typedef SimpleDriver super;
+
public:
MaliVideoDriver();
~MaliVideoDriver();
- void setup(mxml_node_t *const xml);
-
- bool claimCounter(const Counter &counter) const;
- bool countersEnabled() const;
- void resetCounters();
- void setupCounter(Counter &counter);
+ void readEvents(mxml_node_t *const root);
int writeCounters(mxml_node_t *root) const;
bool start(const int mveUds);
+ void stop(const int mveUds);
private:
- MaliVideoCounter *findCounter(const Counter &counter) const;
void marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos);
- MaliVideoCounter *mCounters;
- int mActivityCount;
-
// Intentionally unimplemented
MaliVideoDriver(const MaliVideoDriver &);
MaliVideoDriver &operator=(const MaliVideoDriver &);
diff --git a/daemon/MemInfoDriver.cpp b/daemon/MemInfoDriver.cpp
new file mode 100644
index 0000000..cce15c1
--- /dev/null
+++ b/daemon/MemInfoDriver.cpp
@@ -0,0 +1,93 @@
+/**
+ * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "MemInfoDriver.h"
+
+#include "Logging.h"
+#include "SessionData.h"
+
+class MemInfoCounter : public DriverCounter {
+public:
+ MemInfoCounter(DriverCounter *next, char *const name, int64_t *const value);
+ ~MemInfoCounter();
+
+ int64_t read();
+
+private:
+ int64_t *const mValue;
+
+ // Intentionally unimplemented
+ MemInfoCounter(const MemInfoCounter &);
+ MemInfoCounter &operator=(const MemInfoCounter &);
+};
+
+MemInfoCounter::MemInfoCounter(DriverCounter *next, char *const name, int64_t *const value) : DriverCounter(next, name), mValue(value) {
+}
+
+MemInfoCounter::~MemInfoCounter() {
+}
+
+int64_t MemInfoCounter::read() {
+ return *mValue;
+}
+
+MemInfoDriver::MemInfoDriver() : mBuf(), mMemUsed(0), mMemFree(0), mBuffers(0) {
+}
+
+MemInfoDriver::~MemInfoDriver() {
+}
+
+void MemInfoDriver::readEvents(mxml_node_t *const) {
+ // Only for use with perf
+ if (!gSessionData->perf.isSetup()) {
+ return;
+ }
+
+ setCounters(new MemInfoCounter(getCounters(), strdup("Linux_meminfo_memused2"), &mMemUsed));
+ setCounters(new MemInfoCounter(getCounters(), strdup("Linux_meminfo_memfree"), &mMemFree));
+ setCounters(new MemInfoCounter(getCounters(), strdup("Linux_meminfo_bufferram"), &mBuffers));
+}
+
+void MemInfoDriver::read(Buffer *const buffer) {
+ if (!countersEnabled()) {
+ return;
+ }
+
+ if (!mBuf.read("/proc/meminfo")) {
+ logg->logError(__FILE__, __LINE__, "Failed to read /proc/meminfo");
+ handleException();
+ }
+
+ char *key = mBuf.getBuf();
+ char *colon;
+ int64_t memTotal = 0;
+ while ((colon = strchr(key, ':')) != NULL) {
+ char *end = strchr(colon + 1, '\n');
+ if (end != NULL) {
+ *end = '\0';
+ }
+ *colon = '\0';
+
+ if (strcmp(key, "MemTotal") == 0) {
+ memTotal = strtoll(colon + 1, NULL, 10) << 10;
+ } else if (strcmp(key, "MemFree") == 0) {
+ mMemFree = strtoll(colon + 1, NULL, 10) << 10;
+ } else if (strcmp(key, "Buffers") == 0) {
+ mBuffers = strtoll(colon + 1, NULL, 10) << 10;
+ }
+
+ if (end == NULL) {
+ break;
+ }
+ key = end + 1;
+ }
+
+ mMemUsed = memTotal - mMemFree;
+
+ super::read(buffer);
+}
diff --git a/daemon/MemInfoDriver.h b/daemon/MemInfoDriver.h
new file mode 100644
index 0000000..eb1b041
--- /dev/null
+++ b/daemon/MemInfoDriver.h
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MEMINFODRIVER_H
+#define MEMINFODRIVER_H
+
+#include "Driver.h"
+#include "DynBuf.h"
+
+class MemInfoDriver : public PolledDriver {
+private:
+ typedef PolledDriver super;
+
+public:
+ MemInfoDriver();
+ ~MemInfoDriver();
+
+ void readEvents(mxml_node_t *const root);
+ void read(Buffer *const buffer);
+
+private:
+ DynBuf mBuf;
+ int64_t mMemUsed;
+ int64_t mMemFree;
+ int64_t mBuffers;
+
+ // Intentionally unimplemented
+ MemInfoDriver(const MemInfoDriver &);
+ MemInfoDriver &operator=(const MemInfoDriver &);
+};
+
+#endif // MEMINFODRIVER_H
diff --git a/daemon/Monitor.cpp b/daemon/Monitor.cpp
index b34a15f..74f22ee 100644
--- a/daemon/Monitor.cpp
+++ b/daemon/Monitor.cpp
@@ -9,6 +9,7 @@
#include "Monitor.h"
#include <errno.h>
+#include <fcntl.h>
#include <string.h>
#include <unistd.h>
@@ -31,12 +32,25 @@ void Monitor::close() {
}
bool Monitor::init() {
+#ifdef EPOLL_CLOEXEC
+ mFd = epoll_create1(EPOLL_CLOEXEC);
+#else
mFd = epoll_create(16);
+#endif
if (mFd < 0) {
logg->logMessage("%s(%s:%i): epoll_create1 failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
+#ifndef EPOLL_CLOEXEC
+ int fdf = fcntl(mFd, F_GETFD);
+ if ((fdf == -1) || (fcntl(mFd, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
+ logg->logMessage("%s(%s:%i): fcntl failed", __FUNCTION__, __FILE__, __LINE__);
+ ::close(mFd);
+ return -1;
+ }
+#endif
+
return true;
}
diff --git a/daemon/NetDriver.cpp b/daemon/NetDriver.cpp
new file mode 100644
index 0000000..e75c069
--- /dev/null
+++ b/daemon/NetDriver.cpp
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+// Define to get format macros from inttypes.h
+#define __STDC_FORMAT_MACROS
+
+#include "NetDriver.h"
+
+#include <inttypes.h>
+
+#include "Logging.h"
+#include "SessionData.h"
+
+class NetCounter : public DriverCounter {
+public:
+ NetCounter(DriverCounter *next, char *const name, int64_t *const value);
+ ~NetCounter();
+
+ int64_t read();
+
+private:
+ int64_t *const mValue;
+ int64_t mPrev;
+
+ // Intentionally unimplemented
+ NetCounter(const NetCounter &);
+ NetCounter &operator=(const NetCounter &);
+};
+
+NetCounter::NetCounter(DriverCounter *next, char *const name, int64_t *const value) : DriverCounter(next, name), mValue(value), mPrev(0) {
+}
+
+NetCounter::~NetCounter() {
+}
+
+int64_t NetCounter::read() {
+ int64_t result = *mValue - mPrev;
+ mPrev = *mValue;
+ return result;
+}
+
+NetDriver::NetDriver() : mBuf(), mReceiveBytes(0), mTransmitBytes(0) {
+}
+
+NetDriver::~NetDriver() {
+}
+
+void NetDriver::readEvents(mxml_node_t *const) {
+ // Only for use with perf
+ if (!gSessionData->perf.isSetup()) {
+ return;
+ }
+
+ setCounters(new NetCounter(getCounters(), strdup("Linux_net_rx"), &mReceiveBytes));
+ setCounters(new NetCounter(getCounters(), strdup("Linux_net_tx"), &mTransmitBytes));
+}
+
+bool NetDriver::doRead() {
+ if (!countersEnabled()) {
+ return true;
+ }
+
+ if (!mBuf.read("/proc/net/dev")) {
+ return false;
+ }
+
+ // Skip the header
+ char *key;
+ if (((key = strchr(mBuf.getBuf(), '\n')) == NULL) ||
+ ((key = strchr(key + 1, '\n')) == NULL)) {
+ return false;
+ }
+ key = key + 1;
+
+ mReceiveBytes = 0;
+ mTransmitBytes = 0;
+
+ char *colon;
+ while ((colon = strchr(key, ':')) != NULL) {
+ char *end = strchr(colon + 1, '\n');
+ if (end != NULL) {
+ *end = '\0';
+ }
+ *colon = '\0';
+
+ int64_t receiveBytes;
+ int64_t transmitBytes;
+ const int count = sscanf(colon + 1, " %" SCNu64 " %*u %*u %*u %*u %*u %*u %*u %" SCNu64, &receiveBytes, &transmitBytes);
+ if (count != 2) {
+ return false;
+ }
+ mReceiveBytes += receiveBytes;
+ mTransmitBytes += transmitBytes;
+
+ if (end == NULL) {
+ break;
+ }
+ key = end + 1;
+ }
+
+ return true;
+}
+
+void NetDriver::start() {
+ if (!doRead()) {
+ logg->logError(__FILE__, __LINE__, "Unable to read network stats");
+ handleException();
+ }
+ // Initialize previous values
+ for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ counter->read();
+ }
+}
+
+void NetDriver::read(Buffer *const buffer) {
+ if (!doRead()) {
+ logg->logError(__FILE__, __LINE__, "Unable to read network stats");
+ handleException();
+ }
+ super::read(buffer);
+}
diff --git a/daemon/NetDriver.h b/daemon/NetDriver.h
new file mode 100644
index 0000000..50ff850
--- /dev/null
+++ b/daemon/NetDriver.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef NETDRIVER_H
+#define NETDRIVER_H
+
+#include "Driver.h"
+#include "DynBuf.h"
+
+class NetDriver : public PolledDriver {
+private:
+ typedef PolledDriver super;
+
+public:
+ NetDriver();
+ ~NetDriver();
+
+ void readEvents(mxml_node_t *const root);
+ void start();
+ void read(Buffer *const buffer);
+
+private:
+ bool doRead();
+
+ DynBuf mBuf;
+ int64_t mReceiveBytes;
+ int64_t mTransmitBytes;
+
+ // Intentionally unimplemented
+ NetDriver(const NetDriver &);
+ NetDriver &operator=(const NetDriver &);
+};
+
+#endif // NETDRIVER_H
diff --git a/daemon/OlySocket.cpp b/daemon/OlySocket.cpp
index 28774e3..aa0ce49 100644
--- a/daemon/OlySocket.cpp
+++ b/daemon/OlySocket.cpp
@@ -15,10 +15,10 @@
#include <ws2tcpip.h>
#else
#include <netinet/in.h>
-#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <netdb.h>
+#include <fcntl.h>
#endif
#include "Logging.h"
@@ -32,6 +32,48 @@
#define SHUTDOWN_RX_TX SHUT_RDWR
#endif
+int socket_cloexec(int domain, int type, int protocol) {
+#ifdef SOCK_CLOEXEC
+ return socket(domain, type | SOCK_CLOEXEC, protocol);
+#else
+ int sock = socket(domain, type, protocol);
+#ifdef FD_CLOEXEC
+ if (sock < 0) {
+ return -1;
+ }
+ int fdf = fcntl(sock, F_GETFD);
+ if ((fdf == -1) || (fcntl(sock, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
+ close(sock);
+ return -1;
+ }
+#endif
+ return sock;
+#endif
+}
+
+int accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+ int sock;
+#ifdef SOCK_CLOEXEC
+ sock = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
+ if (sock >= 0) {
+ return sock;
+ }
+ // accept4 with SOCK_CLOEXEC may not work on all kernels, so fallback
+#endif
+ sock = accept(sockfd, addr, addrlen);
+#ifdef FD_CLOEXEC
+ if (sock < 0) {
+ return -1;
+ }
+ int fdf = fcntl(sock, F_GETFD);
+ if ((fdf == -1) || (fcntl(sock, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
+ close(sock);
+ return -1;
+ }
+#endif
+ return sock;
+}
+
OlyServerSocket::OlyServerSocket(int port) {
#ifdef WIN32
WSADATA wsaData;
@@ -57,7 +99,7 @@ OlySocket::OlySocket(int socketID) : mSocketID(socketID) {
OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize) {
// Create socket
- mFDServer = socket(PF_UNIX, SOCK_STREAM, 0);
+ mFDServer = socket_cloexec(PF_UNIX, SOCK_STREAM, 0);
if (mFDServer < 0) {
logg->logError(__FILE__, __LINE__, "Error creating server socket");
handleException();
@@ -84,7 +126,7 @@ OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize) {
}
int OlySocket::connect(const char* path, const size_t pathSize) {
- int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ int fd = socket_cloexec(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
return -1;
}
@@ -143,10 +185,10 @@ void OlyServerSocket::createServerSocket(int port) {
int family = AF_INET6;
// Create socket
- mFDServer = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ mFDServer = socket_cloexec(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (mFDServer < 0) {
family = AF_INET;
- mFDServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ mFDServer = socket_cloexec(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (mFDServer < 0) {
logg->logError(__FILE__, __LINE__, "Error creating server socket");
handleException();
@@ -190,7 +232,7 @@ int OlyServerSocket::acceptConnection() {
}
// Accept a connection, note that this call blocks until a client connects
- socketID = accept(mFDServer, NULL, NULL);
+ socketID = accept_cloexec(mFDServer, NULL, NULL);
if (socketID < 0) {
logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
handleException();
diff --git a/daemon/OlySocket.h b/daemon/OlySocket.h
index 20c67cc..6b53b01 100644
--- a/daemon/OlySocket.h
+++ b/daemon/OlySocket.h
@@ -11,6 +11,12 @@
#include <stddef.h>
+#ifdef WIN32
+typedef socklen_t int;
+#else
+#include <sys/socket.h>
+#endif
+
class OlySocket {
public:
#ifndef WIN32
@@ -52,4 +58,7 @@ private:
void createServerSocket(int port);
};
+int socket_cloexec(int domain, int type, int protocol);
+int accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+
#endif //__OLY_SOCKET_H__
diff --git a/daemon/PerfBuffer.cpp b/daemon/PerfBuffer.cpp
index 5fad583..f127c99 100644
--- a/daemon/PerfBuffer.cpp
+++ b/daemon/PerfBuffer.cpp
@@ -20,6 +20,7 @@ PerfBuffer::PerfBuffer() {
for (int cpu = 0; cpu < ARRAY_LENGTH(mBuf); ++cpu) {
mBuf[cpu] = MAP_FAILED;
mDiscard[cpu] = false;
+ mFds[cpu] = -1;
}
}
@@ -31,8 +32,8 @@ PerfBuffer::~PerfBuffer() {
}
}
-bool PerfBuffer::useFd(const int cpu, const int fd, const int groupFd) {
- if (fd == groupFd) {
+bool PerfBuffer::useFd(const int cpu, const int fd) {
+ if (mFds[cpu] < 0) {
if (mBuf[cpu] != MAP_FAILED) {
logg->logMessage("%s(%s:%i): cpu %i already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__, cpu);
return false;
@@ -44,6 +45,7 @@ bool PerfBuffer::useFd(const int cpu, const int fd, const int groupFd) {
logg->logMessage("%s(%s:%i): mmap failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
+ mFds[cpu] = fd;
// Check the version
struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
@@ -57,7 +59,7 @@ bool PerfBuffer::useFd(const int cpu, const int fd, const int groupFd) {
return false;
}
- if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, groupFd) < 0) {
+ if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, mFds[cpu]) < 0) {
logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
@@ -89,6 +91,41 @@ bool PerfBuffer::isEmpty() {
return true;
}
+static void compressAndSend(const int cpu, const __u64 head, __u64 tail, const uint8_t *const b, Sender *const sender) {
+ // Pick a big size but something smaller than the chunkSize in Sender::writeData which is 100k
+ char buf[1<<16];
+ int writePos = 0;
+ const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
+
+ while (head > tail) {
+ writePos = 0;
+ if (!gSessionData->mLocalCapture) {
+ buf[writePos++] = RESPONSE_APC_DATA;
+ }
+ // Reserve space for size
+ writePos += sizeof(uint32_t);
+ Buffer::packInt(buf, sizeof(buf), writePos, FRAME_PERF);
+ Buffer::packInt(buf, sizeof(buf), writePos, cpu);
+
+ while (head > tail) {
+ const int count = reinterpret_cast<const struct perf_event_header *>(b + (tail & BUF_MASK))->size/sizeof(uint64_t);
+ // Can this whole message be written as Streamline assumes events are not split between frames
+ if (sizeof(buf) <= writePos + count*Buffer::MAXSIZE_PACK64) {
+ break;
+ }
+ for (int i = 0; i < count; ++i) {
+ // Must account for message size
+ Buffer::packInt64(buf, sizeof(buf), writePos, *reinterpret_cast<const uint64_t *>(b + (tail & BUF_MASK)));
+ tail += sizeof(uint64_t);
+ }
+ }
+
+ // Write size
+ Buffer::writeLEInt(reinterpret_cast<unsigned char *>(buf + typeLength), writePos - typeLength - sizeof(uint32_t));
+ sender->writeData(buf, writePos, RESPONSE_APC_DATA);
+ }
+}
+
bool PerfBuffer::send(Sender *const sender) {
for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
if (mBuf[cpu] == MAP_FAILED) {
@@ -102,26 +139,7 @@ bool PerfBuffer::send(Sender *const sender) {
if (head > tail) {
const uint8_t *const b = static_cast<uint8_t *>(mBuf[cpu]) + gSessionData->mPageSize;
- const int offset = gSessionData->mLocalCapture ? 1 : 0;
- unsigned char header[7];
- header[0] = RESPONSE_APC_DATA;
- Buffer::writeLEInt(header + 1, head - tail + sizeof(header) - 5);
- // Should use real packing functions
- header[5] = FRAME_PERF;
- header[6] = cpu;
-
- // Write header
- sender->writeData(reinterpret_cast<const char *>(&header) + offset, sizeof(header) - offset, RESPONSE_APC_DATA);
-
- // Write data
- if ((head & ~BUF_MASK) == (tail & ~BUF_MASK)) {
- // Not wrapped
- sender->writeData(reinterpret_cast<const char *>(b + (tail & BUF_MASK)), head - tail, RESPONSE_APC_DATA);
- } else {
- // Wrapped
- sender->writeData(reinterpret_cast<const char *>(b + (tail & BUF_MASK)), BUF_SIZE - (tail & BUF_MASK), RESPONSE_APC_DATA);
- sender->writeData(reinterpret_cast<const char *>(b), head & BUF_MASK, RESPONSE_APC_DATA);
- }
+ compressAndSend(cpu, head, tail, b, sender);
// Update tail with the data read
pemp->data_tail = head;
@@ -131,6 +149,7 @@ bool PerfBuffer::send(Sender *const sender) {
munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
mBuf[cpu] = MAP_FAILED;
mDiscard[cpu] = false;
+ mFds[cpu] = -1;
logg->logMessage("%s(%s:%i): Unmaped cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
}
}
diff --git a/daemon/PerfBuffer.h b/daemon/PerfBuffer.h
index 278a3b9..25a1062 100644
--- a/daemon/PerfBuffer.h
+++ b/daemon/PerfBuffer.h
@@ -21,7 +21,7 @@ public:
PerfBuffer();
~PerfBuffer();
- bool useFd(const int cpu, const int fd, const int groupFd);
+ bool useFd(const int cpu, const int fd);
void discard(const int cpu);
bool isEmpty();
bool send(Sender *const sender);
@@ -30,6 +30,8 @@ private:
void *mBuf[NR_CPUS];
// After the buffer is flushed it should be unmaped
bool mDiscard[NR_CPUS];
+ // fd that corresponds to the mBuf
+ int mFds[NR_CPUS];
// Intentionally undefined
PerfBuffer(const PerfBuffer &);
diff --git a/daemon/PerfDriver.cpp b/daemon/PerfDriver.cpp
index ac97a07..ee90284 100644
--- a/daemon/PerfDriver.cpp
+++ b/daemon/PerfDriver.cpp
@@ -22,6 +22,7 @@
#include "Logging.h"
#include "PerfGroup.h"
#include "SessionData.h"
+#include "Setup.h"
#define PERF_DEVICES "/sys/bus/event_source/devices"
@@ -47,7 +48,6 @@ static const struct gator_cpu gator_cpus[] = {
{ 0xc07, "Cortex-A7", "ARMv7_Cortex_A7", 4 },
{ 0xc08, "Cortex-A8", "ARMv7_Cortex_A8", 4 },
{ 0xc09, "Cortex-A9", "ARMv7_Cortex_A9", 6 },
- { 0xc0d, "Cortex-A12", "ARMv7_Cortex_A12", 6 },
{ 0xc0f, "Cortex-A15", "ARMv7_Cortex_A15", 6 },
{ 0xc0e, "Cortex-A17", "ARMv7_Cortex_A17", 6 },
{ 0x00f, "Scorpion", "Scorpion", 4 },
@@ -64,68 +64,57 @@ static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_";
struct uncore_counter {
- // gatorfs event and Perf PMU name
- const char *const name;
+ // Perf PMU name
+ const char *const perfName;
+ // gatorfs event name
+ const char *const gatorName;
const int count;
};
static const struct uncore_counter uncore_counters[] = {
- { "CCI_400", 4 },
- { "CCI_400-r1", 4 },
+ { "CCI_400", "CCI_400", 4 },
+ { "CCI_400-r1", "CCI_400-r1", 4 },
+ { "ccn", "ARM_CCN_5XX", 8 },
};
-class PerfCounter {
+class PerfCounter : public DriverCounter {
public:
- 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) {}
+ PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, bool perCpu) : DriverCounter(next, name), mType(type), mCount(0), mConfig(config), mPerCpu(perCpu) {}
+
~PerfCounter() {
- delete [] mName;
}
- PerfCounter *getNext() const { return mNext; }
- const char *getName() const { return mName; }
uint32_t getType() const { return mType; }
int getCount() const { return mCount; }
void setCount(const int count) { mCount = count; }
- int getKey() const { return mKey; }
uint64_t getConfig() const { return mConfig; }
void setConfig(const uint64_t config) { mConfig = config; }
- bool isEnabled() const { return mEnabled; }
- void setEnabled(const bool enabled) { mEnabled = enabled; }
bool isPerCpu() const { return mPerCpu; }
private:
- PerfCounter *const mNext;
- const char *const mName;
const uint32_t mType;
int mCount;
- const int mKey;
uint64_t mConfig;
- int mEnabled : 1,
- mPerCpu : 1;
+ bool mPerCpu;
};
-PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false), mLegacySupport(false) {
+PerfDriver::PerfDriver() : mIsSetup(false), mLegacySupport(false) {
}
PerfDriver::~PerfDriver() {
- while (mCounters != NULL) {
- PerfCounter *counter = mCounters;
- mCounters = counter->getNext();
- delete counter;
- }
}
void PerfDriver::addCpuCounters(const char *const counterName, const int type, const int numCounters) {
int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
char *name = new char[len];
snprintf(name, len, "%s_ccnt", counterName);
- mCounters = new PerfCounter(mCounters, name, type, -1, true);
+ setCounters(new PerfCounter(getCounters(), name, type, -1, true));
for (int j = 0; j < numCounters; ++j) {
len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
name = new char[len];
snprintf(name, len, "%s_cnt%d", counterName, j);
- mCounters = new PerfCounter(mCounters, name, type, -1, true);
+ setCounters(new PerfCounter(getCounters(), name, type, -1, true));
}
}
@@ -133,40 +122,24 @@ void PerfDriver::addUncoreCounters(const char *const counterName, const int type
int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
char *name = new char[len];
snprintf(name, len, "%s_ccnt", counterName);
- mCounters = new PerfCounter(mCounters, name, type, -1, false);
+ setCounters(new PerfCounter(getCounters(), name, type, -1, false));
for (int j = 0; j < numCounters; ++j) {
len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
name = new char[len];
snprintf(name, len, "%s_cnt%d", counterName, j);
- mCounters = new PerfCounter(mCounters, name, type, -1, false);
+ setCounters(new PerfCounter(getCounters(), name, type, -1, false));
}
}
-// From include/generated/uapi/linux/version.h
-#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-
bool PerfDriver::setup() {
// Check the kernel version
- struct utsname utsname;
- if (uname(&utsname) != 0) {
- logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
+ int release[3];
+ if (!getLinuxVersion(release)) {
+ logg->logMessage("%s(%s:%i): getLinuxVersion failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
- int release[3] = { 0, 0, 0 };
- int part = 0;
- char *ch = utsname.release;
- while (*ch >= '0' && *ch <= '9' && part < ARRAY_LENGTH(release)) {
- release[part] = 10*release[part] + *ch - '0';
-
- ++ch;
- if (*ch == '.') {
- ++part;
- ++ch;
- }
- }
-
if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 4, 0)) {
logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__);
return false;
@@ -174,7 +147,7 @@ bool PerfDriver::setup() {
mLegacySupport = KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0);
if (access(EVENTS_PATH, R_OK) != 0) {
- logg->logMessage("%s(%s:%i): " EVENTS_PATH " does not exist, is CONFIG_TRACING enabled?", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("%s(%s:%i): " EVENTS_PATH " does not exist, is CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER enabled?", __FUNCTION__, __FILE__, __LINE__);
return false;
}
@@ -189,12 +162,14 @@ bool PerfDriver::setup() {
struct dirent *dirent;
while ((dirent = readdir(dir)) != NULL) {
for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
+ const struct gator_cpu *const gator_cpu = &gator_cpus[i];
+
// Do the names match exactly?
- if (strcmp(dirent->d_name, gator_cpus[i].pmnc_name) != 0 &&
- // Do these names match but have the old vs new prefix?
- (strncmp(dirent->d_name, OLD_PMU_PREFIX, sizeof(OLD_PMU_PREFIX) - 1) != 0 ||
- strncmp(gator_cpus[i].pmnc_name, NEW_PMU_PREFIX, sizeof(NEW_PMU_PREFIX) - 1) != 0 ||
- strcmp(dirent->d_name + sizeof(OLD_PMU_PREFIX) - 1, gator_cpus[i].pmnc_name + sizeof(NEW_PMU_PREFIX) - 1) != 0)) {
+ if (strcasecmp(gator_cpu->pmnc_name, dirent->d_name) != 0 &&
+ // Do these names match but have the old vs new prefix?
+ ((strncasecmp(dirent->d_name, OLD_PMU_PREFIX, sizeof(OLD_PMU_PREFIX) - 1) != 0 ||
+ strncasecmp(gator_cpu->pmnc_name, NEW_PMU_PREFIX, sizeof(NEW_PMU_PREFIX) - 1) != 0 ||
+ strcasecmp(dirent->d_name + sizeof(OLD_PMU_PREFIX) - 1, gator_cpu->pmnc_name + sizeof(NEW_PMU_PREFIX) - 1) != 0))) {
continue;
}
@@ -206,11 +181,12 @@ bool PerfDriver::setup() {
}
foundCpu = true;
- addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters);
+ logg->logMessage("Adding cpu counters for %s", gator_cpu->pmnc_name);
+ addCpuCounters(gator_cpu->pmnc_name, type, gator_cpu->pmnc_counters);
}
for (int i = 0; i < ARRAY_LENGTH(uncore_counters); ++i) {
- if (strcmp(dirent->d_name, uncore_counters[i].name) != 0) {
+ if (strcmp(dirent->d_name, uncore_counters[i].perfName) != 0) {
continue;
}
@@ -221,7 +197,8 @@ bool PerfDriver::setup() {
continue;
}
- addUncoreCounters(uncore_counters[i].name, type, uncore_counters[i].count);
+ logg->logMessage("Adding uncore counters for %s", uncore_counters[i].gatorName);
+ addUncoreCounters(uncore_counters[i].gatorName, type, uncore_counters[i].count);
}
}
closedir(dir);
@@ -234,6 +211,7 @@ bool PerfDriver::setup() {
}
foundCpu = true;
+ logg->logMessage("Adding cpu counters (based on cpuid) for %s", gator_cpus[i].pmnc_name);
addCpuCounters(gator_cpus[i].pmnc_name, PERF_TYPE_RAW, gator_cpus[i].pmnc_counters);
}
}
@@ -252,31 +230,20 @@ bool PerfDriver::setup() {
id = getTracepointId("irq/softirq_exit", &printb);
if (id >= 0) {
- mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, true);
+ setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, true));
}
id = getTracepointId("irq/irq_handler_exit", &printb);
if (id >= 0) {
- mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, true);
+ setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, true));
}
- //Linux_block_rq_wr
- //Linux_block_rq_rd
- //Linux_net_rx
- //Linux_net_tx
-
id = getTracepointId(SCHED_SWITCH, &printb);
if (id >= 0) {
- mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, true);
+ setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, true));
}
- //Linux_meminfo_memused
- //Linux_meminfo_memfree
- //Linux_meminfo_bufferram
- //Linux_power_cpu_freq
- //Linux_power_cpu_idle
-
- mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1, false);
+ setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, false));
//Linux_cpu_wait_io
@@ -299,62 +266,48 @@ bool PerfDriver::summary(Buffer *const buffer) {
logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
- const int64_t timestamp = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec;
+ const int64_t timestamp = (int64_t)ts.tv_sec * NS_PER_S + ts.tv_nsec;
- const int64_t uptime = getTime();
+ const uint64_t monotonicStarted = getTime();
+ gSessionData->mMonotonicStarted = monotonicStarted;
- buffer->summary(timestamp, uptime, 0, buf);
+ buffer->summary(monotonicStarted, timestamp, monotonicStarted, monotonicStarted, buf);
for (int i = 0; i < gSessionData->mCores; ++i) {
- // Don't send information on a cpu we know nothing about
- if (gSessionData->mCpuIds[i] == -1) {
- continue;
- }
-
- int j;
- for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) {
- if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) {
- break;
- }
- }
- if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) {
- buffer->coreName(i, gSessionData->mCpuIds[i], gator_cpus[j].core_name);
- } else {
- if (gSessionData->mCpuIds[i] == -1) {
- snprintf(buf, sizeof(buf), "Unknown");
- } else {
- snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]);
- }
- buffer->coreName(i, gSessionData->mCpuIds[i], buf);
- }
+ coreName(monotonicStarted, buffer, i);
}
- buffer->commit(1);
+ buffer->commit(monotonicStarted);
return true;
}
-PerfCounter *PerfDriver::findCounter(const Counter &counter) const {
- for (PerfCounter * perfCounter = mCounters; perfCounter != NULL; perfCounter = perfCounter->getNext()) {
- if (strcmp(perfCounter->getName(), counter.getType()) == 0) {
- return perfCounter;
- }
+void PerfDriver::coreName(const uint32_t startTime, Buffer *const buffer, const int cpu) {
+ // Don't send information on a cpu we know nothing about
+ if (gSessionData->mCpuIds[cpu] == -1) {
+ return;
}
- return NULL;
-}
-
-bool PerfDriver::claimCounter(const Counter &counter) const {
- return findCounter(counter) != NULL;
-}
-
-void PerfDriver::resetCounters() {
- for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
- counter->setEnabled(false);
+ int j;
+ for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) {
+ if (gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
+ break;
+ }
+ }
+ if (gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
+ buffer->coreName(startTime, cpu, gSessionData->mCpuIds[cpu], gator_cpus[j].core_name);
+ } else {
+ char buf[32];
+ if (gSessionData->mCpuIds[cpu] == -1) {
+ snprintf(buf, sizeof(buf), "Unknown");
+ } else {
+ snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[cpu]);
+ }
+ buffer->coreName(startTime, cpu, gSessionData->mCpuIds[cpu], buf);
}
}
void PerfDriver::setupCounter(Counter &counter) {
- PerfCounter *const perfCounter = findCounter(counter);
+ PerfCounter *const perfCounter = static_cast<PerfCounter *>(findCounter(counter));
if (perfCounter == NULL) {
counter.setEnabled(false);
return;
@@ -369,21 +322,10 @@ void PerfDriver::setupCounter(Counter &counter) {
counter.setKey(perfCounter->getKey());
}
-int PerfDriver::writeCounters(mxml_node_t *root) const {
- int count = 0;
- for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
- mxml_node_t *node = mxmlNewElement(root, "counter");
- mxmlElementSetAttr(node, "name", counter->getName());
- ++count;
- }
-
- return count;
-}
-
-bool PerfDriver::enable(PerfGroup *const group, Buffer *const buffer) const {
- for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
+bool PerfDriver::enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const {
+ for (PerfCounter *counter = static_cast<PerfCounter *>(getCounters()); counter != NULL; counter = static_cast<PerfCounter *>(counter->getNext())) {
if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
- 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)) {
+ if (!group->add(currTime, 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)) {
logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
diff --git a/daemon/PerfDriver.h b/daemon/PerfDriver.h
index 2cae575..846203a 100644
--- a/daemon/PerfDriver.h
+++ b/daemon/PerfDriver.h
@@ -9,6 +9,8 @@
#ifndef PERFDRIVER_H
#define PERFDRIVER_H
+#include <stdint.h>
+
#include "Driver.h"
// If debugfs is not mounted at /sys/kernel/debug, update DEBUGFS_PATH
@@ -16,13 +18,13 @@
#define EVENTS_PATH DEBUGFS_PATH "/tracing/events"
#define SCHED_SWITCH "sched/sched_switch"
+#define CPU_IDLE "power/cpu_idle"
class Buffer;
class DynBuf;
-class PerfCounter;
class PerfGroup;
-class PerfDriver : public Driver {
+class PerfDriver : public SimpleDriver {
public:
PerfDriver();
~PerfDriver();
@@ -31,24 +33,19 @@ public:
bool setup();
bool summary(Buffer *const buffer);
+ void coreName(const uint32_t startTime, Buffer *const buffer, const int cpu);
bool isSetup() const { return mIsSetup; }
- bool claimCounter(const Counter &counter) const;
- void resetCounters();
void setupCounter(Counter &counter);
- int writeCounters(mxml_node_t *root) const;
-
- bool enable(PerfGroup *const group, Buffer *const buffer) const;
+ bool enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const;
static long long getTracepointId(const char *const name, DynBuf *const printb);
private:
- PerfCounter *findCounter(const Counter &counter) const;
void addCpuCounters(const char *const counterName, const int type, const int numCounters);
void addUncoreCounters(const char *const counterName, const int type, const int numCounters);
- PerfCounter *mCounters;
bool mIsSetup;
bool mLegacySupport;
diff --git a/daemon/PerfGroup.cpp b/daemon/PerfGroup.cpp
index 2a0239f..4fd960a 100644
--- a/daemon/PerfGroup.cpp
+++ b/daemon/PerfGroup.cpp
@@ -9,6 +9,7 @@
#include "PerfGroup.h"
#include <errno.h>
+#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
@@ -33,10 +34,19 @@
/* have a sampling interrupt happen when we cross the wakeup_watermark boundary */ \
pea.watermark = 1; \
/* Be conservative in flush size as only one buffer set is monitored */ \
- pea.wakeup_watermark = 3 * BUF_SIZE / 4
+ pea.wakeup_watermark = BUF_SIZE / 2
static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t pid, const int cpu, const int group_fd, const unsigned long flags) {
- return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
+ int fd = syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
+ if (fd < 0) {
+ return -1;
+ }
+ int fdf = fcntl(fd, F_GETFD);
+ if ((fdf == -1) || (fcntl(fd, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
+ close(fd);
+ return -1;
+ }
+ return fd;
}
PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) {
@@ -54,7 +64,7 @@ PerfGroup::~PerfGroup() {
}
}
-bool PerfGroup::add(Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) {
+bool PerfGroup::add(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) {
int i;
for (i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
if (mKeys[i] < 0) {
@@ -82,12 +92,12 @@ bool PerfGroup::add(Buffer *const buffer, const int key, const __u32 type, const
mKeys[i] = key;
- buffer->pea(&mAttrs[i], key);
+ buffer->pea(currTime, &mAttrs[i], key);
return true;
}
-bool PerfGroup::prepareCPU(const int cpu) {
+int PerfGroup::prepareCPU(const int cpu, Monitor *const monitor) {
logg->logMessage("%s(%s:%i): Onlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
@@ -102,26 +112,35 @@ bool PerfGroup::prepareCPU(const int cpu) {
const int offset = i * gSessionData->mCores;
if (mFds[cpu + offset] >= 0) {
logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
- return false;
+ return PG_FAILURE;
}
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);
mFds[cpu + offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, i == 0 ? -1 : mFds[cpu], i == 0 ? 0 : PERF_FLAG_FD_OUTPUT);
if (mFds[cpu + offset] < 0) {
logg->logMessage("%s(%s:%i): failed %s", __FUNCTION__, __FILE__, __LINE__, strerror(errno));
+ if (errno == ENODEV) {
+ return PG_CPU_OFFLINE;
+ }
continue;
}
- if (!mPb->useFd(cpu, mFds[cpu + offset], mFds[cpu])) {
+ if (!mPb->useFd(cpu, mFds[cpu + offset])) {
logg->logMessage("%s(%s:%i): PerfBuffer::useFd failed", __FUNCTION__, __FILE__, __LINE__);
- return false;
+ return PG_FAILURE;
+ }
+
+
+ if (!monitor->add(mFds[cpu + offset])) {
+ logg->logMessage("%s(%s:%i): Monitor::add failed", __FUNCTION__, __FILE__, __LINE__);
+ return PG_FAILURE;
}
}
- return true;
+ return PG_SUCCESS;
}
-int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor) {
+int PerfGroup::onlineCPU(const uint64_t currTime, const int cpu, const bool start, Buffer *const buffer) {
__u64 ids[ARRAY_LENGTH(mKeys)];
int coreKeys[ARRAY_LENGTH(mKeys)];
int idCount = 0;
@@ -137,38 +156,37 @@ int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer,
// Workaround for running 32-bit gatord on 64-bit systems, kernel patch in the works
ioctl(fd, (PERF_EVENT_IOC_ID & ~IOCSIZE_MASK) | (8 << _IOC_SIZESHIFT), &ids[idCount]) != 0) {
logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
- return false;
+ return 0;
}
++idCount;
}
- if (!monitor->add(mFds[cpu])) {
- logg->logMessage("%s(%s:%i): Monitor::add failed", __FUNCTION__, __FILE__, __LINE__);
- return false;
- }
-
if (!gSessionData->perf.getLegacySupport()) {
- buffer->keys(idCount, ids, coreKeys);
+ buffer->keys(currTime, idCount, ids, coreKeys);
} else {
char buf[1024];
ssize_t bytes = read(mFds[cpu], buf, sizeof(buf));
if (bytes < 0) {
logg->logMessage("read failed");
- return false;
+ return 0;
}
- buffer->keysOld(idCount, coreKeys, bytes, buf);
+ buffer->keysOld(currTime, idCount, coreKeys, bytes, buf);
}
if (start) {
for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
int offset = i * gSessionData->mCores + cpu;
- if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_ENABLE) < 0) {
+ if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_ENABLE, 0) < 0) {
logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
- return false;
+ return 0;
}
}
}
+ if (idCount == 0) {
+ logg->logMessage("%s(%s:%i): no events came online", __FUNCTION__, __FILE__, __LINE__);
+ }
+
return idCount;
}
@@ -177,7 +195,7 @@ bool PerfGroup::offlineCPU(const int cpu) {
for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
int offset = i * gSessionData->mCores + cpu;
- if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_DISABLE) < 0) {
+ if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_DISABLE, 0) < 0) {
logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
@@ -203,7 +221,7 @@ bool PerfGroup::offlineCPU(const int cpu) {
bool PerfGroup::start() {
for (int pos = 0; pos < ARRAY_LENGTH(mFds); ++pos) {
- if (mFds[pos] >= 0 && ioctl(mFds[pos], PERF_EVENT_IOC_ENABLE) < 0) {
+ if (mFds[pos] >= 0 && ioctl(mFds[pos], PERF_EVENT_IOC_ENABLE, 0) < 0) {
logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
goto fail;
}
@@ -220,7 +238,7 @@ bool PerfGroup::start() {
void PerfGroup::stop() {
for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
if (mFds[pos] >= 0) {
- ioctl(mFds[pos], PERF_EVENT_IOC_DISABLE);
+ ioctl(mFds[pos], PERF_EVENT_IOC_DISABLE, 0);
}
}
}
diff --git a/daemon/PerfGroup.h b/daemon/PerfGroup.h
index 3f1e2bb..f7b3d72 100644
--- a/daemon/PerfGroup.h
+++ b/daemon/PerfGroup.h
@@ -9,6 +9,8 @@
#ifndef PERF_GROUP
#define PERF_GROUP
+#include <stdint.h>
+
// Use a snapshot of perf_event.h as it may be more recent than what is on the target and if not newer features won't be supported anyways
#include "k/perf_event.h"
@@ -27,16 +29,22 @@ enum PerfGroupFlags {
PERF_GROUP_PER_CPU = 1 << 5,
};
+enum {
+ PG_SUCCESS = 0,
+ PG_FAILURE,
+ PG_CPU_OFFLINE,
+};
+
class PerfGroup {
public:
PerfGroup(PerfBuffer *const pb);
~PerfGroup();
- bool add(Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags);
+ bool add(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags);
// Safe to call concurrently
- bool prepareCPU(const int cpu);
+ int prepareCPU(const int cpu, Monitor *const monitor);
// Not safe to call concurrently. Returns the number of events enabled
- int onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor);
+ int onlineCPU(const uint64_t currTime, const int cpu, const bool start, Buffer *const buffer);
bool offlineCPU(int cpu);
bool start();
void stop();
diff --git a/daemon/PerfSource.cpp b/daemon/PerfSource.cpp
index ecfaa66..193b778 100644
--- a/daemon/PerfSource.cpp
+++ b/daemon/PerfSource.cpp
@@ -8,8 +8,14 @@
#include "PerfSource.h"
+#include <dirent.h>
#include <errno.h>
+#include <signal.h>
#include <string.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
#include <unistd.h>
#include "Child.h"
@@ -19,11 +25,13 @@
#include "Proc.h"
#include "SessionData.h"
-#define MS_PER_US 1000000
+#ifndef SCHED_RESET_ON_FORK
+#define SCHED_RESET_ON_FORK 0x40000000
+#endif
extern Child *child;
-static bool sendTracepointFormat(Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
+static bool sendTracepointFormat(const uint64_t currTime, Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
return false;
@@ -32,47 +40,112 @@ static bool sendTracepointFormat(Buffer *const buffer, const char *const name, D
logg->logMessage("%s(%s:%i): DynBuf::read failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
- buffer->format(b->getLength(), b->getBuf());
+ buffer->format(currTime, b->getLength(), b->getBuf());
return true;
}
-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) {
- long l = sysconf(_SC_PAGE_SIZE);
- if (l < 0) {
- logg->logError(__FILE__, __LINE__, "Unable to obtain the page size");
+static void *syncFunc(void *arg)
+{
+ struct timespec ts;
+ int64_t nextTime = gSessionData->mMonotonicStarted;
+ int err;
+ (void)arg;
+
+ prctl(PR_SET_NAME, (unsigned long)&"gatord-sync", 0, 0, 0);
+
+ // Mask all signals so that this thread will not be woken up
+ {
+ sigset_t set;
+ if (sigfillset(&set) != 0) {
+ logg->logError(__FILE__, __LINE__, "sigfillset failed");
+ handleException();
+ }
+ if ((err = pthread_sigmask(SIG_SETMASK, &set, NULL)) != 0) {
+ logg->logError(__FILE__, __LINE__, "pthread_sigmask failed");
+ handleException();
+ }
+ }
+
+ for (;;) {
+ if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
+ logg->logError(__FILE__, __LINE__, "clock_gettime failed");
+ handleException();
+ }
+ const int64_t currTime = ts.tv_sec * NS_PER_S + ts.tv_nsec;
+
+ // Wake up once a second
+ nextTime += NS_PER_S;
+
+ // Always sleep more than 1 ms, hopefully things will line up better next time
+ const int64_t sleepTime = max(nextTime - currTime, (int64_t)(NS_PER_MS + 1));
+ ts.tv_sec = sleepTime/NS_PER_S;
+ ts.tv_nsec = sleepTime % NS_PER_S;
+
+ err = nanosleep(&ts, NULL);
+ if (err != 0) {
+ fprintf(stderr, "clock_nanosleep failed: %s\n", strerror(err));
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+static long getMaxCoreNum() {
+ DIR *dir = opendir("/sys/devices/system/cpu");
+ if (dir == NULL) {
+ logg->logError(__FILE__, __LINE__, "Unable to determine the number of cores on the target, opendir failed");
handleException();
}
- gSessionData->mPageSize = static_cast<int>(l);
- l = sysconf(_SC_NPROCESSORS_CONF);
- if (l < 0) {
- logg->logError(__FILE__, __LINE__, "Unable to obtain the number of cores");
+ long maxCoreNum = -1;
+ struct dirent *dirent;
+ while ((dirent = readdir(dir)) != NULL) {
+ if (strncmp(dirent->d_name, "cpu", 3) == 0) {
+ char *endptr;
+ errno = 0;
+ long coreNum = strtol(dirent->d_name + 3, &endptr, 10);
+ if ((errno == 0) && (*endptr == '\0') && (coreNum >= maxCoreNum)) {
+ maxCoreNum = coreNum + 1;
+ }
+ }
+ }
+ closedir(dir);
+
+ if (maxCoreNum < 1) {
+ logg->logError(__FILE__, __LINE__, "Unable to determine the number of cores on the target, no cpu# directories found");
handleException();
}
- gSessionData->mCores = static_cast<int>(l);
-}
-PerfSource::~PerfSource() {
+ if (maxCoreNum >= NR_CPUS) {
+ logg->logError(__FILE__, __LINE__, "Too many cores on the target, please increase NR_CPUS in Config.h");
+ handleException();
+ }
+
+ return maxCoreNum;
}
-struct PrepareParallelArgs {
- PerfGroup *pg;
- int cpu;
-};
+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), mIdleGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) {
+ long l = sysconf(_SC_PAGE_SIZE);
+ if (l < 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to obtain the page size");
+ handleException();
+ }
+ gSessionData->mPageSize = static_cast<int>(l);
+ gSessionData->mCores = static_cast<int>(getMaxCoreNum());
+}
-void *prepareParallel(void *arg) {
- const PrepareParallelArgs *const args = (PrepareParallelArgs *)arg;
- args->pg->prepareCPU(args->cpu);
- return NULL;
+PerfSource::~PerfSource() {
}
bool PerfSource::prepare() {
DynBuf printb;
DynBuf b1;
- DynBuf b2;
- DynBuf b3;
long long schedSwitchId;
+ long long cpuIdleId;
+
+ const uint64_t currTime = getTime();
// Reread cpuinfo since cores may have changed since startup
gSessionData->readCpuInfo();
@@ -83,76 +156,146 @@ bool PerfSource::prepare() {
|| !mMonitor.add(mUEvent.getFd())
|| (schedSwitchId = PerfDriver::getTracepointId(SCHED_SWITCH, &printb)) < 0
- || !sendTracepointFormat(&mBuffer, SCHED_SWITCH, &printb, &b1)
+ || !sendTracepointFormat(currTime, &mBuffer, SCHED_SWITCH, &printb, &b1)
+
+ || (cpuIdleId = PerfDriver::getTracepointId(CPU_IDLE, &printb)) < 0
+ || !sendTracepointFormat(currTime, &mBuffer, CPU_IDLE, &printb, &b1)
// Only want RAW but not IP on sched_switch and don't want TID on SAMPLE_ID
- || !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)
+ || !mCountersGroup.add(currTime, &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)
+ || !mIdleGroup.add(currTime, &mBuffer, 101/**/, PERF_TYPE_TRACEPOINT, cpuIdleId, 1, PERF_SAMPLE_RAW, PERF_GROUP_PER_CPU)
// Only want TID and IP but not RAW on timer
- || (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))
+ || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(currTime, &mBuffer, 102/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, PERF_GROUP_PER_CPU))
- || !gSessionData->perf.enable(&mCountersGroup, &mBuffer)
+ || !gSessionData->perf.enable(currTime, &mCountersGroup, &mBuffer)
|| 0) {
logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.4 or later?", __FUNCTION__, __FILE__, __LINE__);
return false;
}
- if (!gSessionData->perf.summary(&mSummary)) {
- logg->logMessage("%s(%s:%i): PerfDriver::summary failed", __FUNCTION__, __FILE__, __LINE__);
- return false;
- }
-
- {
- // Run prepareCPU in parallel as perf_event_open can take more than 1 sec in some cases
- pthread_t threads[NR_CPUS];
- PrepareParallelArgs args[NR_CPUS];
- for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
- args[cpu].pg = &mCountersGroup;
- args[cpu].cpu = cpu;
- if (pthread_create(&threads[cpu], NULL, prepareParallel, &args[cpu]) != 0) {
- logg->logMessage("%s(%s:%i): pthread_create failed", __FUNCTION__, __FILE__, __LINE__);
- return false;
- }
+ for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+ const int result = mCountersGroup.prepareCPU(cpu, &mMonitor);
+ if ((result != PG_SUCCESS) && (result != PG_CPU_OFFLINE)) {
+ logg->logError(__FILE__, __LINE__, "PerfGroup::prepareCPU on mCountersGroup failed");
+ handleException();
}
- for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
- if (pthread_join(threads[cpu], NULL) != 0) {
- logg->logMessage("%s(%s:%i): pthread_join failed", __FUNCTION__, __FILE__, __LINE__);
- return false;
- }
+ }
+ for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+ const int result = mIdleGroup.prepareCPU(cpu, &mMonitor);
+ if ((result != PG_SUCCESS) && (result != PG_CPU_OFFLINE)) {
+ logg->logError(__FILE__, __LINE__, "PerfGroup::prepareCPU on mIdleGroup failed");
+ handleException();
}
}
int numEvents = 0;
for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
- numEvents += mCountersGroup.onlineCPU(cpu, false, &mBuffer, &mMonitor);
+ numEvents += mCountersGroup.onlineCPU(currTime, cpu, false, &mBuffer);
+ }
+ for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+ numEvents += mIdleGroup.onlineCPU(currTime, cpu, false, &mBuffer);
}
if (numEvents <= 0) {
logg->logMessage("%s(%s:%i): PerfGroup::onlineCPU failed on all cores", __FUNCTION__, __FILE__, __LINE__);
return false;
}
- // Start events before reading proc to avoid race conditions
- if (!mCountersGroup.start()) {
- logg->logMessage("%s(%s:%i): PerfGroup::start failed", __FUNCTION__, __FILE__, __LINE__);
- return false;
+ // Send the summary right before the start so that the monotonic delta is close to the start time
+ if (!gSessionData->perf.summary(&mSummary)) {
+ logg->logError(__FILE__, __LINE__, "PerfDriver::summary failed", __FUNCTION__, __FILE__, __LINE__);
+ handleException();
}
- if (!readProc(&mBuffer, true, &printb, &b1, &b2, &b3)) {
- logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__);
- return false;
+ // Start the timer thread to used to sync perf and monotonic raw times
+ pthread_t syncThread;
+ if (pthread_create(&syncThread, NULL, syncFunc, NULL)) {
+ logg->logError(__FILE__, __LINE__, "pthread_create failed", __FUNCTION__, __FILE__, __LINE__);
+ handleException();
+ }
+ struct sched_param param;
+ param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+ if (pthread_setschedparam(syncThread, SCHED_FIFO | SCHED_RESET_ON_FORK, &param) != 0) {
+ logg->logError(__FILE__, __LINE__, "pthread_setschedparam failed");
+ handleException();
}
- mBuffer.commit(1);
+ mBuffer.commit(currTime);
return true;
}
+struct ProcThreadArgs {
+ Buffer *mBuffer;
+ uint64_t mCurrTime;
+ bool mIsDone;
+};
+
+void *procFunc(void *arg) {
+ DynBuf printb;
+ DynBuf b;
+ const ProcThreadArgs *const args = (ProcThreadArgs *)arg;
+
+ prctl(PR_SET_NAME, (unsigned long)&"gatord-proc", 0, 0, 0);
+
+ // Gator runs at a high priority, reset the priority to the default
+ if (setpriority(PRIO_PROCESS, syscall(__NR_gettid), 0) == -1) {
+ logg->logError(__FILE__, __LINE__, "setpriority failed");
+ handleException();
+ }
+
+ if (!readProcMaps(args->mCurrTime, args->mBuffer, &printb, &b)) {
+ logg->logError(__FILE__, __LINE__, "readProcMaps failed");
+ handleException();
+ }
+ args->mBuffer->commit(args->mCurrTime);
+
+ if (!readKallsyms(args->mCurrTime, args->mBuffer, &args->mIsDone)) {
+ logg->logError(__FILE__, __LINE__, "readKallsyms failed");
+ handleException();
+ }
+ args->mBuffer->commit(args->mCurrTime);
+
+ return NULL;
+}
+
static const char CPU_DEVPATH[] = "/devices/system/cpu/cpu";
void PerfSource::run() {
int pipefd[2];
+ pthread_t procThread;
+ ProcThreadArgs procThreadArgs;
+
+ {
+ DynBuf printb;
+ DynBuf b1;
+ DynBuf b2;
- if (pipe(pipefd) != 0) {
+ const uint64_t currTime = getTime();
+
+ // Start events before reading proc to avoid race conditions
+ if (!mCountersGroup.start() || !mIdleGroup.start()) {
+ logg->logError(__FILE__, __LINE__, "PerfGroup::start failed", __FUNCTION__, __FILE__, __LINE__);
+ handleException();
+ }
+
+ if (!readProcComms(currTime, &mBuffer, &printb, &b1, &b2)) {
+ logg->logError(__FILE__, __LINE__, "readProcComms failed");
+ handleException();
+ }
+ mBuffer.commit(currTime);
+
+ // Postpone reading kallsyms as on android adb gets too backed up and data is lost
+ procThreadArgs.mBuffer = &mBuffer;
+ procThreadArgs.mCurrTime = currTime;
+ procThreadArgs.mIsDone = false;
+ if (pthread_create(&procThread, NULL, procFunc, &procThreadArgs)) {
+ logg->logError(__FILE__, __LINE__, "pthread_create failed", __FUNCTION__, __FILE__, __LINE__);
+ handleException();
+ }
+ }
+
+ if (pipe_cloexec(pipefd) != 0) {
logg->logError(__FILE__, __LINE__, "pipe failed");
handleException();
}
@@ -165,7 +308,7 @@ void PerfSource::run() {
int timeout = -1;
if (gSessionData->mLiveRate > 0) {
- timeout = gSessionData->mLiveRate/MS_PER_US;
+ timeout = gSessionData->mLiveRate/NS_PER_MS;
}
sem_post(mStartProfile);
@@ -178,10 +321,11 @@ void PerfSource::run() {
logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
handleException();
}
+ const uint64_t currTime = getTime();
for (int i = 0; i < ready; ++i) {
if (events[i].data.fd == mUEvent.getFd()) {
- if (!handleUEvent()) {
+ if (!handleUEvent(currTime)) {
logg->logError(__FILE__, __LINE__, "PerfSource::handleUEvent failed");
handleException();
}
@@ -200,6 +344,9 @@ void PerfSource::run() {
}
}
+ procThreadArgs.mIsDone = true;
+ pthread_join(procThread, NULL);
+ mIdleGroup.stop();
mCountersGroup.stop();
mBuffer.setDone();
mIsDone = true;
@@ -212,7 +359,7 @@ void PerfSource::run() {
close(pipefd[1]);
}
-bool PerfSource::handleUEvent() {
+bool PerfSource::handleUEvent(const uint64_t currTime) {
UEventResult result;
if (!mUEvent.read(&result)) {
logg->logMessage("%s(%s:%i): UEvent::Read failed", __FUNCTION__, __FILE__, __LINE__);
@@ -231,14 +378,41 @@ bool PerfSource::handleUEvent() {
logg->logMessage("%s(%s:%i): strtol failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
+
+ if (cpu >= gSessionData->mCores) {
+ logg->logError(__FILE__, __LINE__, "Only %i cores are expected but core %i reports %s", gSessionData->mCores, cpu, result.mAction);
+ handleException();
+ }
+
if (strcmp(result.mAction, "online") == 0) {
+ mBuffer.onlineCPU(currTime, currTime - gSessionData->mMonotonicStarted, cpu);
// Only call onlineCPU if prepareCPU succeeded
- const bool result = mCountersGroup.prepareCPU(cpu) &&
- mCountersGroup.onlineCPU(cpu, true, &mBuffer, &mMonitor);
- mBuffer.commit(1);
+ bool result = false;
+ int err = mCountersGroup.prepareCPU(cpu, &mMonitor);
+ if (err == PG_CPU_OFFLINE) {
+ result = true;
+ } else if (err == PG_SUCCESS) {
+ if (mCountersGroup.onlineCPU(currTime, cpu, true, &mBuffer)) {
+ err = mIdleGroup.prepareCPU(cpu, &mMonitor);
+ if (err == PG_CPU_OFFLINE) {
+ result = true;
+ } else if (err == PG_SUCCESS) {
+ if (mIdleGroup.onlineCPU(currTime, cpu, true, &mBuffer)) {
+ result = true;
+ }
+ }
+ }
+ }
+ mBuffer.commit(currTime);
+
+ gSessionData->readCpuInfo();
+ gSessionData->perf.coreName(currTime, &mSummary, cpu);
+ mSummary.commit(currTime);
return result;
} else if (strcmp(result.mAction, "offline") == 0) {
- return mCountersGroup.offlineCPU(cpu);
+ const bool result = mCountersGroup.offlineCPU(cpu) && mIdleGroup.offlineCPU(cpu);
+ mBuffer.offlineCPU(currTime, currTime - gSessionData->mMonotonicStarted, cpu);
+ return result;
}
}
diff --git a/daemon/PerfSource.h b/daemon/PerfSource.h
index 3f471c8..ce1eafe 100644
--- a/daemon/PerfSource.h
+++ b/daemon/PerfSource.h
@@ -33,12 +33,13 @@ public:
void write(Sender *sender);
private:
- bool handleUEvent();
+ bool handleUEvent(const uint64_t currTime);
Buffer mSummary;
Buffer mBuffer;
PerfBuffer mCountersBuf;
PerfGroup mCountersGroup;
+ PerfGroup mIdleGroup;
Monitor mMonitor;
UEvent mUEvent;
sem_t *const mSenderSem;
diff --git a/daemon/Proc.cpp b/daemon/Proc.cpp
index 9f01770..e6b26b1 100644
--- a/daemon/Proc.cpp
+++ b/daemon/Proc.cpp
@@ -10,13 +10,16 @@
#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "Buffer.h"
#include "DynBuf.h"
#include "Logging.h"
+#include "SessionData.h"
struct ProcStat {
// From linux-dev/include/linux/sched.h
@@ -57,6 +60,8 @@ static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf
return true;
}
+static const char APP_PROCESS[] = "app_process";
+
static const char *readProcExe(DynBuf *const printb, const int pid, const int tid, DynBuf *const b) {
if (tid == -1 ? !printb->printf("/proc/%i/exe", pid)
: !printb->printf("/proc/%i/task/%i/exe", pid, tid)) {
@@ -82,7 +87,8 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti
}
// Android apps are run by app_process but the cmdline is changed to reference the actual app name
- if (strcmp(image, "app_process") != 0) {
+ // On 64-bit android app_process can be app_process32 or app_process64
+ if (strncmp(image, APP_PROCESS, sizeof(APP_PROCESS) - 1) != 0) {
return image;
}
@@ -100,7 +106,7 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti
return b->getBuf();
}
-static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) {
+static bool readProcTask(const uint64_t currTime, Buffer *const buffer, const int pid, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) {
bool result = false;
if (!b1->printf("/proc/%i/task", pid)) {
@@ -110,7 +116,8 @@ static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const prin
DIR *task = opendir(b1->getBuf());
if (task == NULL) {
logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
- return result;
+ // This is not a fatal error - the thread just doesn't exist any more
+ return true;
}
struct dirent *dirent;
@@ -138,7 +145,7 @@ static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const prin
goto fail;
}
- buffer->comm(pid, tid, image, ps.comm);
+ buffer->comm(currTime, pid, tid, image, ps.comm);
}
result = true;
@@ -149,7 +156,7 @@ static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const prin
return result;
}
-bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) {
+bool readProcComms(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) {
bool result = false;
DIR *proc = opendir("/proc");
@@ -177,19 +184,6 @@ bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf
goto fail;
}
- if (sendMaps) {
- if (!printb->printf("/proc/%i/maps", pid)) {
- logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
- goto fail;
- }
- if (!b2->read(printb->getBuf())) {
- logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__);
- // This is not a fatal error - the process just doesn't exist any more
- continue;
- }
-
- buffer->maps(pid, pid, b2->getBuf());
- }
if (ps.numThreads <= 1) {
const char *const image = readProcExe(printb, pid, -1, b1);
if (image == NULL) {
@@ -197,9 +191,9 @@ bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf
goto fail;
}
- buffer->comm(pid, pid, image, ps.comm);
+ buffer->comm(currTime, pid, pid, image, ps.comm);
} else {
- if (!readProcTask(buffer, pid, printb, b1, b3)) {
+ if (!readProcTask(currTime, buffer, pid, printb, b1, b2)) {
logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__);
goto fail;
}
@@ -213,3 +207,106 @@ bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf
return result;
}
+
+bool readProcMaps(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b) {
+ bool result = false;
+
+ DIR *proc = opendir("/proc");
+ if (proc == NULL) {
+ logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
+ return result;
+ }
+
+ struct dirent *dirent;
+ while ((dirent = readdir(proc)) != NULL) {
+ char *endptr;
+ const int pid = strtol(dirent->d_name, &endptr, 10);
+ if (*endptr != '\0') {
+ // Ignore proc items that are not integers like ., cpuinfo, etc...
+ continue;
+ }
+
+ if (!printb->printf("/proc/%i/maps", pid)) {
+ logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ goto fail;
+ }
+ if (!b->read(printb->getBuf())) {
+ logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__);
+ // This is not a fatal error - the process just doesn't exist any more
+ continue;
+ }
+
+ buffer->maps(currTime, pid, pid, b->getBuf());
+ }
+
+ result = true;
+
+ fail:
+ closedir(proc);
+
+ return result;
+}
+
+bool readKallsyms(const uint64_t currTime, Buffer *const buffer, const bool *const isDone) {
+ int fd = ::open("/proc/kallsyms", O_RDONLY | O_CLOEXEC);
+
+ if (fd < 0) {
+ logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
+ return true;
+ };
+
+ char buf[1<<12];
+ ssize_t pos = 0;
+ while (gSessionData->mSessionIsActive && !ACCESS_ONCE(*isDone)) {
+ // Assert there is still space in the buffer
+ if (sizeof(buf) - pos - 1 == 0) {
+ logg->logError(__FILE__, __LINE__, "no space left in buffer");
+ handleException();
+ }
+
+ {
+ // -1 to reserve space for \0
+ const ssize_t bytes = ::read(fd, buf + pos, sizeof(buf) - pos - 1);
+ if (bytes < 0) {
+ logg->logError(__FILE__, __LINE__, "read failed", __FUNCTION__, __FILE__, __LINE__);
+ handleException();
+ }
+ if (bytes == 0) {
+ // Assert the buffer is empty
+ if (pos != 0) {
+ logg->logError(__FILE__, __LINE__, "buffer not empty on eof");
+ handleException();
+ }
+ break;
+ }
+ pos += bytes;
+ }
+
+ ssize_t newline;
+ // Find the last '\n'
+ for (newline = pos - 1; newline >= 0; --newline) {
+ if (buf[newline] == '\n') {
+ const char was = buf[newline + 1];
+ buf[newline + 1] = '\0';
+ buffer->kallsyms(currTime, buf);
+ // Sleep 3 ms to avoid sending out too much data too quickly
+ usleep(3000);
+ buf[0] = was;
+ // Assert the memory regions do not overlap
+ if (pos - newline >= newline + 1) {
+ logg->logError(__FILE__, __LINE__, "memcpy src and dst overlap");
+ handleException();
+ }
+ if (pos - newline - 2 > 0) {
+ memcpy(buf + 1, buf + newline + 2, pos - newline - 2);
+ }
+ pos -= newline + 1;
+ break;
+ }
+ }
+ }
+
+ close(fd);
+
+ return true;
+}
diff --git a/daemon/Proc.h b/daemon/Proc.h
index 31c2eec..2a1a7cb 100644
--- a/daemon/Proc.h
+++ b/daemon/Proc.h
@@ -9,9 +9,13 @@
#ifndef PROC_H
#define PROC_H
+#include <stdint.h>
+
class Buffer;
class DynBuf;
-bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3);
+bool readProcComms(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2);
+bool readProcMaps(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b);
+bool readKallsyms(const uint64_t currTime, Buffer *const buffer, const bool *const isDone);
#endif // PROC_H
diff --git a/daemon/Sender.cpp b/daemon/Sender.cpp
index 3a981a6..8a54a66 100644
--- a/daemon/Sender.cpp
+++ b/daemon/Sender.cpp
@@ -65,18 +65,13 @@ void Sender::createDataFile(char* apcDir) {
mDataFileName = (char*)malloc(strlen(apcDir) + 12);
sprintf(mDataFileName, "%s/0000000000", apcDir);
- mDataFile = fopen(mDataFileName, "wb");
+ mDataFile = fopen_cloexec(mDataFileName, "wb");
if (!mDataFile) {
logg->logError(__FILE__, __LINE__, "Failed to open binary file: %s", mDataFileName);
handleException();
}
}
-template<typename T>
-inline T min(const T a, const T b) {
- return (a < b ? a : b);
-}
-
void Sender::writeData(const char* data, int length, int type) {
if (length < 0 || (data == NULL && length > 0)) {
return;
diff --git a/daemon/Sender.h b/daemon/Sender.h
index 33b6cc3..5aa9117 100644
--- a/daemon/Sender.h
+++ b/daemon/Sender.h
@@ -6,8 +6,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __SENDER_H__
-#define __SENDER_H__
+#ifndef __SENDER_H__
+#define __SENDER_H__
#include <stdio.h>
#include <pthread.h>
diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp
index 14d995f..0e65d78 100644
--- a/daemon/SessionData.cpp
+++ b/daemon/SessionData.cpp
@@ -8,15 +8,31 @@
#include "SessionData.h"
+#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
+#include <unistd.h>
-#include "SessionXML.h"
+#include "CPUFreqDriver.h"
+#include "DiskIODriver.h"
+#include "FSDriver.h"
+#include "HwmonDriver.h"
#include "Logging.h"
+#include "MemInfoDriver.h"
+#include "NetDriver.h"
+#include "SessionXML.h"
+
+#define CORE_NAME_UNKNOWN "unknown"
SessionData* gSessionData = NULL;
SessionData::SessionData() {
+ usDrivers[0] = new HwmonDriver();
+ usDrivers[1] = new FSDriver();
+ usDrivers[2] = new MemInfoDriver();
+ usDrivers[3] = new NetDriver();
+ usDrivers[4] = new CPUFreqDriver();
+ usDrivers[5] = new DiskIODriver();
initialize();
}
@@ -29,6 +45,7 @@ void SessionData::initialize() {
mLocalCapture = false;
mOneShot = false;
mSentSummary = false;
+ mAllowCommands = false;
const size_t cpuIdSize = sizeof(int)*NR_CPUS;
// Share mCpuIds across all instances of gatord
mCpuIds = (int *)mmap(NULL, cpuIdSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
@@ -37,15 +54,22 @@ void SessionData::initialize() {
handleException();
}
memset(mCpuIds, -1, cpuIdSize);
+ strcpy(mCoreName, CORE_NAME_UNKNOWN);
+ readModel();
readCpuInfo();
+ mImages = NULL;
mConfigurationXMLPath = NULL;
mSessionXMLPath = NULL;
mEventsXMLPath = NULL;
mTargetPath = NULL;
mAPCDir = NULL;
+ mCaptureWorkingDir = NULL;
+ mCaptureCommand = NULL;
+ mCaptureUser = NULL;
mSampleRate = 0;
mLiveRate = 0;
mDuration = 0;
+ mMonotonicStarted = -1;
mBacktraceDepth = 0;
mTotalBufferSize = 0;
// sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
@@ -71,7 +95,6 @@ void SessionData::parseSessionXML(char* xmlString) {
handleException();
}
mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0;
- mDuration = session.parameters.duration;
// Determine buffer size (in MB) based on buffer mode
mOneShot = true;
@@ -89,21 +112,38 @@ void SessionData::parseSessionXML(char* xmlString) {
handleException();
}
- mImages = session.parameters.images;
// Convert milli- to nanoseconds
mLiveRate = session.parameters.live_rate * (int64_t)1000000;
if (mLiveRate > 0 && mLocalCapture) {
logg->logMessage("Local capture is not compatable with live, disabling live");
mLiveRate = 0;
}
+
+ if (!mAllowCommands && (mCaptureCommand != NULL)) {
+ logg->logError(__FILE__, __LINE__, "Running a command during a capture is not currently allowed. Please restart gatord with the -a flag.");
+ handleException();
+ }
+}
+
+void SessionData::readModel() {
+ FILE *fh = fopen("/proc/device-tree/model", "rb");
+ if (fh == NULL) {
+ return;
+ }
+
+ char buf[256];
+ if (fgets(buf, sizeof(buf), fh) != NULL) {
+ strcpy(mCoreName, buf);
+ }
+
+ fclose(fh);
}
void SessionData::readCpuInfo() {
char temp[256]; // arbitrarily large amount
- strcpy(mCoreName, "unknown");
mMaxCpuId = -1;
- FILE* f = fopen("/proc/cpuinfo", "r");
+ FILE *f = fopen("/proc/cpuinfo", "r");
if (f == NULL) {
logg->logMessage("Error opening /proc/cpuinfo\n"
"The core name in the captured xml file will be 'unknown'.");
@@ -122,7 +162,8 @@ void SessionData::readCpuInfo() {
}
if (len > 0) {
- temp[len - 1] = '\0'; // Replace the line feed with a null
+ // Replace the line feed with a null
+ temp[len - 1] = '\0';
}
const bool foundHardware = strstr(temp, "Hardware") != 0;
@@ -137,7 +178,7 @@ void SessionData::readCpuInfo() {
}
position += 2;
- if (foundHardware) {
+ if (foundHardware && (strcmp(mCoreName, CORE_NAME_UNKNOWN) == 0)) {
strncpy(mCoreName, position, sizeof(mCoreName));
mCoreName[sizeof(mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
foundCoreName = true;
@@ -171,10 +212,6 @@ void SessionData::readCpuInfo() {
uint64_t getTime() {
struct timespec ts;
-#ifndef CLOCK_MONOTONIC_RAW
- // Android doesn't have this defined but it was added in Linux 2.6.28
-#define CLOCK_MONOTONIC_RAW 4
-#endif
if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
logg->logError(__FILE__, __LINE__, "Failed to get uptime");
handleException();
@@ -185,10 +222,40 @@ uint64_t getTime() {
int getEventKey() {
// key 0 is reserved as a timestamp
// key 1 is reserved as the marker for thread specific counters
+ // key 2 is reserved as the marker for core
// Odd keys are assigned by the driver, even keys by the daemon
- static int key = 2;
+ static int key = 4;
const int ret = key;
key += 2;
return ret;
}
+
+int pipe_cloexec(int pipefd[2]) {
+ if (pipe(pipefd) != 0) {
+ return -1;
+ }
+
+ int fdf;
+ if (((fdf = fcntl(pipefd[0], F_GETFD)) == -1) || (fcntl(pipefd[0], F_SETFD, fdf | FD_CLOEXEC) != 0) ||
+ ((fdf = fcntl(pipefd[1], F_GETFD)) == -1) || (fcntl(pipefd[1], F_SETFD, fdf | FD_CLOEXEC) != 0)) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return -1;
+ }
+ return 0;
+}
+
+FILE *fopen_cloexec(const char *path, const char *mode) {
+ FILE *fh = fopen(path, mode);
+ if (fh == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fh);
+ int fdf = fcntl(fd, F_GETFD);
+ if ((fdf == -1) || (fcntl(fd, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
+ fclose(fh);
+ return NULL;
+ }
+ return fh;
+}
diff --git a/daemon/SessionData.h b/daemon/SessionData.h
index 835082d..ed282af 100644
--- a/daemon/SessionData.h
+++ b/daemon/SessionData.h
@@ -11,17 +11,21 @@
#include <stdint.h>
+#include "AnnotateListener.h"
#include "Config.h"
#include "Counter.h"
-#include "FSDriver.h"
-#include "Hwmon.h"
+#include "FtraceDriver.h"
+#include "KMod.h"
#include "MaliVideoDriver.h"
#include "PerfDriver.h"
-#define PROTOCOL_VERSION 19
-#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions
+#define PROTOCOL_VERSION 20
+// Differentiates development versions (timestamp) from release versions
+#define PROTOCOL_DEV 1000
-#define NS_PER_S ((uint64_t)1000000000)
+#define NS_PER_S 1000000000LL
+#define NS_PER_MS 1000000LL
+#define NS_PER_US 1000LL
struct ImageLinkList {
char* path;
@@ -36,30 +40,40 @@ public:
~SessionData();
void initialize();
void parseSessionXML(char* xmlString);
+ void readModel();
void readCpuInfo();
- Hwmon hwmon;
- FSDriver fsDriver;
+ PolledDriver *usDrivers[6];
+ KMod kmod;
PerfDriver perf;
MaliVideoDriver maliVideo;
+ FtraceDriver ftraceDriver;
+ AnnotateListener annotateListener;
char mCoreName[MAX_STRING_LEN];
struct ImageLinkList *mImages;
- char* mConfigurationXMLPath;
- char* mSessionXMLPath;
- char* mEventsXMLPath;
- char* mTargetPath;
- char* mAPCDir;
+ char *mConfigurationXMLPath;
+ char *mSessionXMLPath;
+ char *mEventsXMLPath;
+ char *mTargetPath;
+ char *mAPCDir;
+ char *mCaptureWorkingDir;
+ char *mCaptureCommand;
+ char *mCaptureUser;
bool mWaitingOnCommand;
bool mSessionIsActive;
bool mLocalCapture;
- bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled
+ // halt processing of the driver data until profiling is complete or the buffer is filled
+ bool mOneShot;
bool mIsEBS;
bool mSentSummary;
+ bool mAllowCommands;
+ int64_t mMonotonicStarted;
int mBacktraceDepth;
- int mTotalBufferSize; // number of MB to use for the entire collection buffer
+ // number of MB to use for the entire collection buffer
+ int mTotalBufferSize;
int mSampleRate;
int64_t mLiveRate;
int mDuration;
@@ -82,5 +96,7 @@ extern SessionData* gSessionData;
uint64_t getTime();
int getEventKey();
+int pipe_cloexec(int pipefd[2]);
+FILE *fopen_cloexec(const char *path, const char *mode);
#endif // SESSION_DATA_H
diff --git a/daemon/SessionXML.cpp b/daemon/SessionXML.cpp
index 8cdc940..dea4c8f 100644
--- a/daemon/SessionXML.cpp
+++ b/daemon/SessionXML.cpp
@@ -16,33 +16,30 @@
#include "OlyUtility.h"
#include "SessionData.h"
-static const char* TAG_SESSION = "session";
-static const char* TAG_IMAGE = "image";
-
-static const char* ATTR_VERSION = "version";
-static const char* ATTR_CALL_STACK_UNWINDING = "call_stack_unwinding";
-static const char* ATTR_BUFFER_MODE = "buffer_mode";
-static const char* ATTR_SAMPLE_RATE = "sample_rate";
-static const char* ATTR_DURATION = "duration";
-static const char* ATTR_PATH = "path";
-static const char* ATTR_LIVE_RATE = "live_rate";
+static const char *TAG_SESSION = "session";
+static const char *TAG_IMAGE = "image";
+
+static const char *ATTR_VERSION = "version";
+static const char *ATTR_CALL_STACK_UNWINDING = "call_stack_unwinding";
+static const char *ATTR_BUFFER_MODE = "buffer_mode";
+static const char *ATTR_SAMPLE_RATE = "sample_rate";
+static const char *ATTR_DURATION = "duration";
+static const char *ATTR_PATH = "path";
+static const char *ATTR_LIVE_RATE = "live_rate";
+static const char *ATTR_CAPTURE_WORKING_DIR = "capture_working_dir";
+static const char *ATTR_CAPTURE_COMMAND = "capture_command";
+static const char *ATTR_CAPTURE_USER = "capture_user";
SessionXML::SessionXML(const char *str) {
parameters.buffer_mode[0] = 0;
parameters.sample_rate[0] = 0;
- parameters.duration = 0;
parameters.call_stack_unwinding = false;
parameters.live_rate = 0;
- parameters.images = NULL;
- mPath = 0;
- mSessionXML = (const char *)str;
+ mSessionXML = str;
logg->logMessage(mSessionXML);
}
SessionXML::~SessionXML() {
- if (mPath != 0) {
- free((char *)mSessionXML);
- }
}
void SessionXML::parse() {
@@ -79,10 +76,13 @@ void SessionXML::sessionTag(mxml_node_t *tree, mxml_node_t *node) {
strncpy(parameters.sample_rate, mxmlElementGetAttr(node, ATTR_SAMPLE_RATE), sizeof(parameters.sample_rate));
parameters.sample_rate[sizeof(parameters.sample_rate) - 1] = 0; // strncpy does not guarantee a null-terminated string
}
+ if (mxmlElementGetAttr(node, ATTR_CAPTURE_WORKING_DIR)) gSessionData->mCaptureWorkingDir = strdup(mxmlElementGetAttr(node, ATTR_CAPTURE_WORKING_DIR));
+ if (mxmlElementGetAttr(node, ATTR_CAPTURE_COMMAND)) gSessionData->mCaptureCommand = strdup(mxmlElementGetAttr(node, ATTR_CAPTURE_COMMAND));
+ if (mxmlElementGetAttr(node, ATTR_CAPTURE_USER)) gSessionData->mCaptureUser = strdup(mxmlElementGetAttr(node, ATTR_CAPTURE_USER));
// integers/bools
parameters.call_stack_unwinding = util->stringToBool(mxmlElementGetAttr(node, ATTR_CALL_STACK_UNWINDING), false);
- if (mxmlElementGetAttr(node, ATTR_DURATION)) parameters.duration = strtol(mxmlElementGetAttr(node, ATTR_DURATION), NULL, 10);
+ if (mxmlElementGetAttr(node, ATTR_DURATION)) gSessionData->mDuration = strtol(mxmlElementGetAttr(node, ATTR_DURATION), NULL, 10);
if (mxmlElementGetAttr(node, ATTR_LIVE_RATE)) parameters.live_rate = strtol(mxmlElementGetAttr(node, ATTR_LIVE_RATE), NULL, 10);
// parse subtags
@@ -106,6 +106,6 @@ void SessionXML::sessionImage(mxml_node_t *node) {
image = (struct ImageLinkList *)malloc(sizeof(struct ImageLinkList));
image->path = (char*)malloc(length + 1);
image->path = strdup(mxmlElementGetAttr(node, ATTR_PATH));
- image->next = parameters.images;
- parameters.images = image;
+ image->next = gSessionData->mImages;
+ gSessionData->mImages = image;
}
diff --git a/daemon/SessionXML.h b/daemon/SessionXML.h
index e146094..5396574 100644
--- a/daemon/SessionXML.h
+++ b/daemon/SessionXML.h
@@ -14,12 +14,13 @@
struct ImageLinkList;
struct ConfigParameters {
- char buffer_mode[64]; // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size
- char sample_rate[64]; // capture mode, "high", "normal", or "low"
- int duration; // length of profile in seconds
- bool call_stack_unwinding; // whether stack unwinding is performed
+ // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size
+ char buffer_mode[64];
+ // capture mode, "high", "normal", or "low"
+ char sample_rate[64];
+ // whether stack unwinding is performed
+ bool call_stack_unwinding;
int live_rate;
- struct ImageLinkList *images; // linked list of image strings
};
class SessionXML {
@@ -30,7 +31,6 @@ public:
ConfigParameters parameters;
private:
const char *mSessionXML;
- const char *mPath;
void sessionTag(mxml_node_t *tree, mxml_node_t *node);
void sessionImage(mxml_node_t *node);
diff --git a/daemon/Setup.cpp b/daemon/Setup.cpp
new file mode 100644
index 0000000..d4ce032
--- /dev/null
+++ b/daemon/Setup.cpp
@@ -0,0 +1,232 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "Setup.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "Config.h"
+#include "DynBuf.h"
+#include "Logging.h"
+
+bool getLinuxVersion(int version[3]) {
+ // Check the kernel version
+ struct utsname utsname;
+ if (uname(&utsname) != 0) {
+ logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
+ return false;
+ }
+
+ version[0] = 0;
+ version[1] = 0;
+ version[2] = 0;
+
+ int part = 0;
+ char *ch = utsname.release;
+ while (*ch >= '0' && *ch <= '9' && part < 3) {
+ version[part] = 10*version[part] + *ch - '0';
+
+ ++ch;
+ if (*ch == '.') {
+ ++part;
+ ++ch;
+ }
+ }
+
+ return true;
+}
+
+static int pgrep_gator(DynBuf *const printb) {
+ DynBuf b;
+
+ DIR *proc = opendir("/proc");
+ if (proc == NULL) {
+ logg->logError(__FILE__, __LINE__, "gator: error: opendir failed");
+ handleException();
+ }
+
+ int self = getpid();
+
+ struct dirent *dirent;
+ while ((dirent = readdir(proc)) != NULL) {
+ char *endptr;
+ const int pid = strtol(dirent->d_name, &endptr, 10);
+ if (*endptr != '\0' || (pid == self)) {
+ // Ignore proc items that are not integers like ., cpuinfo, etc...
+ continue;
+ }
+
+ if (!printb->printf("/proc/%i/stat", pid)) {
+ logg->logError(__FILE__, __LINE__, "gator: error: DynBuf::printf failed");
+ handleException();
+ }
+
+ if (!b.read(printb->getBuf())) {
+ // This is not a fatal error - the thread just doesn't exist any more
+ continue;
+ }
+
+ char *comm = strchr(b.getBuf(), '(');
+ if (comm == NULL) {
+ logg->logError(__FILE__, __LINE__, "gator: error: parsing stat begin failed");
+ handleException();
+ }
+ ++comm;
+ char *const str = strrchr(comm, ')');
+ if (str == NULL) {
+ logg->logError(__FILE__, __LINE__, "gator: error: parsing stat end failed");
+ handleException();
+ }
+ *str = '\0';
+
+ if (strncmp(comm, "gator", 5) == 0) {
+ // Assume there is only one gator process
+ return pid;
+ }
+ }
+
+ closedir(proc);
+
+ return -1;
+}
+
+int update(const char *const gatorPath) {
+ printf("gator: starting\n");
+
+ int version[3];
+ if (!getLinuxVersion(version)) {
+ logg->logError(__FILE__, __LINE__, "gator: error: getLinuxVersion failed");
+ handleException();
+ }
+
+ if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(2, 6, 32)) {
+ logg->logError(__FILE__, __LINE__, "gator: error: Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
+ handleException();
+ }
+
+ if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(3, 4, 0)) {
+ logg->logError(__FILE__, __LINE__, "gator: error: Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device.");
+ handleException();
+ }
+
+ if (access("/sys/module/gator", F_OK) == 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: Streamline has detected that the gator kernel module is loaded on your device. Please build an updated version of gator.ko and gatord and install them on your device.");
+ handleException();
+ }
+
+ if (geteuid() != 0) {
+ printf("gator: trying sudo\n");
+ execlp("sudo", "sudo", gatorPath, "-u", NULL);
+ // Streamline will provide the password if needed
+
+ printf("gator: trying su\n");
+ char buf[1<<10];
+ snprintf(buf, sizeof(buf), "%s -u", gatorPath);
+ execlp("su", "su", "-", "-c", buf, NULL);
+ // Streamline will provide the password if needed
+
+ logg->logError(__FILE__, __LINE__, "gator: error: Streamline was unable to sudo to root on your device. Please double check passwords, ensure sudo or su work with this user or try a different username.");
+ handleException();
+ }
+ printf("gator: now root\n");
+
+ // setenforce 0 not needed for userspace gator
+
+ // Kill existing gator
+ DynBuf gatorStatPath;
+ int gator_main = pgrep_gator(&gatorStatPath);
+ if (gator_main > 0) {
+ if (kill(gator_main, SIGTERM) != 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: kill SIGTERM failed");
+ handleException();
+ }
+ for (int i = 0; ; ++i) {
+ if (access(gatorStatPath.getBuf(), F_OK) != 0) {
+ break;
+ }
+ if (i == 5) {
+ if (kill(gator_main, SIGKILL) != 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: kill SIGKILL failed");
+ handleException();
+ }
+ } else if (i >= 10) {
+ logg->logError(__FILE__, __LINE__, "gator: error: unable to kill running gator");
+ handleException();
+ }
+ sleep(1);
+ }
+ }
+ printf("gator: no gatord running\n");
+
+ rename("gatord", "gatord.old");
+ rename("gator.ko", "gator.ko.old");
+
+ // Rename gatord.YYYYMMDDHHMMSSMMMM to gatord
+ char *newGatorPath = strdup(gatorPath);
+ char *dot = strrchr(newGatorPath, '.');
+ if (dot != NULL) {
+ *dot = '\0';
+ if (rename(gatorPath, newGatorPath) != 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: rename failed");
+ handleException();
+ }
+ }
+
+ // Fork and start gatord (redirect stdout and stderr)
+ int child = fork();
+ if (child < 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: fork failed");
+ handleException();
+ } else if (child == 0) {
+ int inFd = open("/dev/null", O_RDONLY | O_CLOEXEC);
+ if (inFd < 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: open of /dev/null failed");
+ handleException();
+ }
+ int outFd = open("gatord.out", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
+ if (outFd < 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: open of gatord.out failed");
+ handleException();
+ }
+ int errFd = open("gatord.err", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
+ if (errFd < 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: open of gatord.err failed");
+ handleException();
+ }
+ if (dup2(inFd, STDIN_FILENO) < 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stdin failed");
+ handleException();
+ }
+ if (dup2(outFd, STDOUT_FILENO) < 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stdout failed");
+ handleException();
+ }
+ if (dup2(errFd, STDERR_FILENO) < 0) {
+ logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stderr failed");
+ handleException();
+ }
+ execlp(newGatorPath, newGatorPath, "-a", NULL);
+ logg->logError(__FILE__, __LINE__, "gator: error: execlp failed");
+ handleException();
+ }
+
+ printf("gator: done\n");
+
+ return 0;
+}
diff --git a/daemon/Setup.h b/daemon/Setup.h
new file mode 100644
index 0000000..280d611
--- /dev/null
+++ b/daemon/Setup.h
@@ -0,0 +1,18 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SETUP_H
+#define SETUP_H
+
+// From include/generated/uapi/linux/version.h
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
+bool getLinuxVersion(int version[3]);
+int update(const char *const gatorPath);
+
+#endif // SETUP_H
diff --git a/daemon/StreamlineSetup.h b/daemon/StreamlineSetup.h
index b380f46..623e14f 100644
--- a/daemon/StreamlineSetup.h
+++ b/daemon/StreamlineSetup.h
@@ -6,8 +6,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __STREAMLINE_SETUP_H__
-#define __STREAMLINE_SETUP_H__
+#ifndef __STREAMLINE_SETUP_H__
+#define __STREAMLINE_SETUP_H__
#include <stdint.h>
#include <string.h>
diff --git a/daemon/UEvent.cpp b/daemon/UEvent.cpp
index 54d4575..f94a995 100644
--- a/daemon/UEvent.cpp
+++ b/daemon/UEvent.cpp
@@ -15,6 +15,7 @@
#include <linux/netlink.h>
#include "Logging.h"
+#include "OlySocket.h"
static const char EMPTY[] = "";
static const char ACTION[] = "ACTION=";
@@ -31,7 +32,7 @@ UEvent::~UEvent() {
}
bool UEvent::init() {
- mFd = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
+ mFd = socket_cloexec(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
if (mFd < 0) {
logg->logMessage("%s(%s:%i): socket failed", __FUNCTION__, __FILE__, __LINE__);
return false;
diff --git a/daemon/UserSpaceSource.cpp b/daemon/UserSpaceSource.cpp
index 8c328e0..4a9b22f 100644
--- a/daemon/UserSpaceSource.cpp
+++ b/daemon/UserSpaceSource.cpp
@@ -16,8 +16,6 @@
#include "Logging.h"
#include "SessionData.h"
-#define NS_PER_US 1000
-
extern Child *child;
UserSpaceSource::UserSpaceSource(sem_t *senderSem) : mBuffer(0, FRAME_BLOCK_COUNTER, gSessionData->mTotalBufferSize*1024*1024, senderSem) {
@@ -33,16 +31,22 @@ bool UserSpaceSource::prepare() {
void UserSpaceSource::run() {
prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
- gSessionData->hwmon.start();
- gSessionData->fsDriver.start();
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
+ gSessionData->usDrivers[i]->start();
+ }
int64_t monotonic_started = 0;
while (monotonic_started <= 0) {
usleep(10);
- if (DriverSource::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
- logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
- handleException();
+ if (gSessionData->perf.isSetup()) {
+ monotonic_started = gSessionData->mMonotonicStarted;
+ } else {
+ if (DriverSource::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
+ logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
+ handleException();
+ }
+ gSessionData->mMonotonicStarted = monotonic_started;
}
}
@@ -57,8 +61,9 @@ void UserSpaceSource::run() {
}
if (mBuffer.eventHeader(curr_time)) {
- gSessionData->hwmon.read(&mBuffer);
- gSessionData->fsDriver.read(&mBuffer);
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
+ gSessionData->usDrivers[i]->read(&mBuffer);
+ }
// Only check after writing all counters so that time and corresponding counters appear in the same frame
mBuffer.check(curr_time);
}
diff --git a/daemon/defaults.xml b/daemon/defaults.xml
index 815b582..086eca1 100644
--- a/daemon/defaults.xml
+++ b/daemon/defaults.xml
@@ -24,16 +24,16 @@
<configuration counter="ARMv7_Cortex_A9_cnt2" event="0x07"/>
<configuration counter="ARMv7_Cortex_A9_cnt3" event="0x03"/>
<configuration counter="ARMv7_Cortex_A9_cnt4" event="0x04"/>
- <configuration counter="ARMv7_Cortex_A12_ccnt" event="0xff"/>
- <configuration counter="ARMv7_Cortex_A12_cnt0" event="0x08"/>
- <configuration counter="ARMv7_Cortex_A12_cnt1" event="0x16"/>
- <configuration counter="ARMv7_Cortex_A12_cnt2" event="0x10"/>
- <configuration counter="ARMv7_Cortex_A12_cnt3" event="0x19"/>
<configuration counter="ARMv7_Cortex_A15_ccnt" event="0xff"/>
<configuration counter="ARMv7_Cortex_A15_cnt0" event="0x8"/>
<configuration counter="ARMv7_Cortex_A15_cnt1" event="0x16"/>
<configuration counter="ARMv7_Cortex_A15_cnt2" event="0x10"/>
<configuration counter="ARMv7_Cortex_A15_cnt3" event="0x19"/>
+ <configuration counter="ARMv7_Cortex_A17_ccnt" event="0xff"/>
+ <configuration counter="ARMv7_Cortex_A17_cnt0" event="0x08"/>
+ <configuration counter="ARMv7_Cortex_A17_cnt1" event="0x16"/>
+ <configuration counter="ARMv7_Cortex_A17_cnt2" event="0x10"/>
+ <configuration counter="ARMv7_Cortex_A17_cnt3" event="0x19"/>
<configuration counter="ARM_Cortex-A53_ccnt" event="0x11"/>
<configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/>
<configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/>
@@ -56,6 +56,7 @@
<configuration counter="Linux_block_rq_wr"/>
<configuration counter="Linux_block_rq_rd"/>
<configuration counter="Linux_meminfo_memused"/>
+ <configuration counter="Linux_meminfo_memused2"/>
<configuration counter="Linux_meminfo_memfree"/>
<configuration counter="Linux_power_cpu_freq"/>
<configuration counter="ARM_Mali-4xx_fragment"/>
@@ -63,5 +64,21 @@
<configuration counter="ARM_Mali-Midgard_fragment" cores="1"/>
<configuration counter="ARM_Mali-Midgard_vertex" cores="1"/>
<configuration counter="ARM_Mali-Midgard_opencl" cores="1"/>
+ <configuration counter="ARM_Mali-T60x_GPU_ACTIVE"/>
+ <configuration counter="ARM_Mali-T60x_JS0_ACTIVE"/>
+ <configuration counter="ARM_Mali-T60x_JS1_ACTIVE"/>
+ <configuration counter="ARM_Mali-T60x_JS2_ACTIVE"/>
+ <configuration counter="ARM_Mali-T62x_GPU_ACTIVE"/>
+ <configuration counter="ARM_Mali-T62x_JS0_ACTIVE"/>
+ <configuration counter="ARM_Mali-T62x_JS1_ACTIVE"/>
+ <configuration counter="ARM_Mali-T62x_JS2_ACTIVE"/>
+ <configuration counter="ARM_Mali-T72x_GPU_ACTIVE"/>
+ <configuration counter="ARM_Mali-T72x_JS0_ACTIVE"/>
+ <configuration counter="ARM_Mali-T72x_JS1_ACTIVE"/>
+ <configuration counter="ARM_Mali-T72x_JS2_ACTIVE"/>
+ <configuration counter="ARM_Mali-T76x_GPU_ACTIVE"/>
+ <configuration counter="ARM_Mali-T76x_JS0_ACTIVE"/>
+ <configuration counter="ARM_Mali-T76x_JS1_ACTIVE"/>
+ <configuration counter="ARM_Mali-T76x_JS2_ACTIVE"/>
<configuration counter="L2C-310_cnt0" event="0x1"/>
</configurations>
diff --git a/daemon/events-Cortex-A12.xml b/daemon/events-Cortex-A17.xml
index 9c04354..4dd08c1 100644
--- a/daemon/events-Cortex-A12.xml
+++ b/daemon/events-Cortex-A17.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARMv7_Cortex_A12_cnt" count="6"/>
- <category name="Cortex-A12" counter_set="ARMv7_Cortex_A12_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARMv7_Cortex_A12_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv7_Cortex_A17_cnt" count="6"/>
+ <category name="Cortex-A17" counter_set="ARMv7_Cortex_A17_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv7_Cortex_A17_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
<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"/>
@@ -62,7 +62,7 @@
<event event="0xc2" title="Cache" name="4 Ways Read" description="Number of set of 4 ways read in the instruction cache - Tag RAM"/>
<event event="0xc3" title="Cache" name="Ways Read" description="Number of ways read in the instruction cache - Data RAM"/>
<event event="0xc4" title="Cache" name="BATC Read" description="Number of ways read in the instruction BTAC RAM"/>
- <event event="0xca" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local Cortex-A12 cluster, rather than accessing the L2 cache or issuing an external read. It increments on each transaction, rather than on each beat of data"/>
+ <event event="0xca" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local Cortex-A17 cluster, rather than accessing the L2 cache or issuing an external read. It increments on each transaction, rather than on each beat of data"/>
<event event="0xd3" title="Slots" name="Load-Store Unit" description="Duration during which all slots in the Load-Store Unit are busy"/>
<event event="0xd8" title="Slots" name="Load-Store Issue Queue" description="Duration during which all slots in the Load-Store Issue queue are busy"/>
<event event="0xd9" title="Slots" name="Data Processing Issue Queue" description="Duration during which all slots in the Data Processing issue queue are busy"/>
diff --git a/daemon/events-Filesystem.xml b/daemon/events-Filesystem.xml
index 5feeb90..9ef61dd 100644
--- a/daemon/events-Filesystem.xml
+++ b/daemon/events-Filesystem.xml
@@ -1,11 +1,11 @@
<category name="Filesystem">
- <!-- counter attributes must be unique -->
+ <!-- counter attribute must start with filesystem_ and be unique -->
<!-- regex item in () is the value shown -->
- <!-- these counters are not compatible with userspace gator, i.e. gator.ko must be loaded -->
<!--
- <event counter="/sys/devices/system/cpu/cpu1/online" title="online" name="cpu 1" class="absolute" description="If cpu 1 is online"/>
- <event counter="/proc/self/loginuid" title="loginuid" name="loginuid" class="absolute" description="loginuid"/>
- <event counter="/proc/self/stat" title="stat" name="rss" class="absolute" regex="-?[0-9]+ \(.*\) . -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ (-?[0-9]+)" units="pages" description="resident set size"/>
- <event counter="/proc/stat" title="proc-stat" name="processes" class="absolute" regex="processes ([0-9]+)" description="Number of processes and threads created"/>
+ <event counter="filesystem_cpu1_online" path="/sys/devices/system/cpu/cpu1/online" title="online" name="cpu 1" class="absolute" description="If cpu 1 is online"/>
+ <event counter="filesystem_loginuid" path="/proc/self/loginuid" title="loginuid" name="loginuid" class="absolute" description="loginuid"/>
+ <event counter="filesystem_gatord_rss" path="/proc/self/stat" title="stat" name="rss" class="absolute" regex="-?[0-9]+ \(.*\) . -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ (-?[0-9]+)" units="pages" description="resident set size"/>
+ <event counter="filesystem_processes" path="/proc/stat" title="proc-stat" name="processes" class="absolute" regex="processes ([0-9]+)" description="Number of processes and threads created"/>
+ <event counter="filesystem_context_switches" path="/proc/stat" title="proc-stat" name="context switches" class="absolute" regex="ctxt ([0-9]+)" description="Number of processes and threads created"/>
-->
</category>
diff --git a/daemon/events-Linux.xml b/daemon/events-Linux.xml
index c306dd6..62a7018 100644
--- a/daemon/events-Linux.xml
+++ b/daemon/events-Linux.xml
@@ -1,16 +1,17 @@
<category name="Linux">
<event counter="Linux_irq_softirq" title="Interrupts" name="SoftIRQ" per_cpu="yes" description="Linux SoftIRQ taken"/>
<event counter="Linux_irq_irq" title="Interrupts" name="IRQ" per_cpu="yes" description="Linux IRQ taken"/>
- <event counter="Linux_block_rq_wr" title="Disk IO" name="Write" units="B" description="Disk IO Bytes Written"/>
- <event counter="Linux_block_rq_rd" title="Disk IO" name="Read" units="B" description="Disk IO Bytes Read"/>
+ <event counter="Linux_block_rq_wr" title="Disk I/O" name="Write" units="B" description="Disk I/O Bytes Written"/>
+ <event counter="Linux_block_rq_rd" title="Disk I/O" name="Read" units="B" description="Disk I/O Bytes Read"/>
<event counter="Linux_net_rx" title="Network" name="Receive" units="B" description="Receive network traffic, including effect from Streamline"/>
<event counter="Linux_net_tx" title="Network" name="Transmit" units="B" description="Transmit network traffic, including effect from Streamline"/>
<event counter="Linux_sched_switch" title="Scheduler" name="Switch" per_cpu="yes" description="Context switch events"/>
<event counter="Linux_meminfo_memused" title="Memory" name="Used" class="absolute" units="B" proc="yes" description="Total used memory size. Note: a process' used memory includes shared memory that may be counted more than once (equivalent to RES from top). Kernel threads are not filterable."/>
+ <event counter="Linux_meminfo_memused2" title="Memory" name="Used" class="absolute" units="B" description="Total used memory size"/>
<event counter="Linux_meminfo_memfree" title="Memory" name="Free" class="absolute" display="minimum" units="B" description="Available memory size"/>
<event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" class="absolute" units="B" description="Memory used by OS disk buffers"/>
<event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" class="absolute" units="Hz" series_composition="overlay" average_cores="yes" description="Frequency setting of the CPU"/>
- <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" class="absolute" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/>
- <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" color="0x003c96fb" description="Thread waiting on contended resource"/>
- <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" color="0x00b30000" description="Thread waiting on I/O resource"/>
+ <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" color="0x003c96fb" description="One or more threads are runnable but waiting due to CPU contention"/>
+ <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" color="0x00b30000" description="One or more threads are blocked on an I/O resource"/>
+ <event counter="Linux_power_cpu" title="CPU Status" name="Activity" class="activity" activity1="Off" activity_color1="0x0000ff00" activity2="WFI" activity_color2="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" description="CPU Status"/>
</category>
diff --git a/daemon/events-Mali-T60x_hw.xml b/daemon/events-Mali-T60x_hw.xml
index 95e9b5a..50797e6 100644
--- a/daemon/events-Mali-T60x_hw.xml
+++ b/daemon/events-Mali-T60x_hw.xml
@@ -102,5 +102,7 @@
<event counter="ARM_Mali-T60x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
<event counter="ARM_Mali-T60x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
<event counter="ARM_Mali-T60x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+ <event counter="ARM_Mali-T60x_L2_READ_LOOKUP" title="Mali L2 Cache" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T60x_L2_WRITE_LOOKUP" title="Mali L2 Cache" name="L2 write lookups" description="Number of writes into the L2 cache"/>
</category>
diff --git a/daemon/events-Mali-T62x_hw.xml b/daemon/events-Mali-T62x_hw.xml
index dbffd93..6ecc53c 100644
--- a/daemon/events-Mali-T62x_hw.xml
+++ b/daemon/events-Mali-T62x_hw.xml
@@ -103,5 +103,7 @@
<event counter="ARM_Mali-T62x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
<event counter="ARM_Mali-T62x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
<event counter="ARM_Mali-T62x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+ <event counter="ARM_Mali-T62x_L2_READ_LOOKUP" title="Mali L2 Cache" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T62x_L2_WRITE_LOOKUP" title="Mali L2 Cache" name="L2 write lookups" description="Number of writes into the L2 cache"/>
</category>
diff --git a/daemon/events-Mali-T72x_hw.xml b/daemon/events-Mali-T72x_hw.xml
index a0c14ad..5587534 100644
--- a/daemon/events-Mali-T72x_hw.xml
+++ b/daemon/events-Mali-T72x_hw.xml
@@ -1,7 +1,7 @@
<category name="Mali Job Manager" per_cpu="no">
- <event counter="ARM_Mali-T72_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles GPU active"/>
+ <event counter="ARM_Mali-T72x_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles GPU active"/>
<event counter="ARM_Mali-T72x_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles GPU interrupt pending"/>
<event counter="ARM_Mali-T72x_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) active"/>
<event counter="ARM_Mali-T72x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
@@ -89,5 +89,7 @@
<event counter="ARM_Mali-T72x_L2_WRITE_HIT" title="Mali L2 Cache" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
<event counter="ARM_Mali-T72x_L2_EXT_AR_STALL" title="Mali L2 Cache" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
<event counter="ARM_Mali-T72x_L2_EXT_W_STALL" title="Mali L2 Cache" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T72x_L2_READ_LOOKUP" title="Mali L2 Cache" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T72x_L2_WRITE_LOOKUP" title="Mali L2 Cache" name="L2 write lookups" description="Number of writes into the L2 cache"/>
</category>
diff --git a/daemon/events-Mali-T76x_hw.xml b/daemon/events-Mali-T76x_hw.xml
index 182bb69..be74c5a 100644
--- a/daemon/events-Mali-T76x_hw.xml
+++ b/daemon/events-Mali-T76x_hw.xml
@@ -103,4 +103,6 @@
<event counter="ARM_Mali-T76x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
<event counter="ARM_Mali-T76x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
<event counter="ARM_Mali-T76x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+ <event counter="ARM_Mali-T76x_L2_READ_LOOKUP" title="Mali L2 Cache" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T76x_L2_WRITE_LOOKUP" title="Mali L2 Cache" name="L2 write lookups" description="Number of writes into the L2 cache"/>
</category>
diff --git a/daemon/events-Mali-V500.xml b/daemon/events-Mali-V500.xml
index d2751e7..89bc7f4 100644
--- a/daemon/events-Mali-V500.xml
+++ b/daemon/events-Mali-V500.xml
@@ -1,29 +1,30 @@
<category name="Mali-V500">
- <event counter="ARM_Mali-V500_cnt0" title="Mali Video Engine" name="Samples" class="absolute" description="The number of times we have taken a sample"/>
- <event counter="ARM_Mali-V500_cnt1" title="Mali Video Engine" name="Queued input-buffers" class="absolute" description="The number of input-buffers that has been queued for consumption by the MVE"/>
- <event counter="ARM_Mali-V500_cnt2" title="Mali Video Engine" name="Consumed input-buffers" class="absolute" description="The number of input-buffers that has been consumed by the MVE and returned to the application"/>
- <event counter="ARM_Mali-V500_cnt3" title="Mali Video Engine" name="Queued output-buffers" class="absolute" description="The number of output-buffers that has been queued for usage by the MVE"/>
- <event counter="ARM_Mali-V500_cnt4" title="Mali Video Engine" name="Consumed output-buffers" class="absolute" description="The number of output-buffers that has been consumed by the MVE and returned to the application"/>
- <event counter="ARM_Mali-V500_cnt5" title="Mali Video Engine" name="Created Sessions" class="absolute" description="The number of created sessions throughout the lifetime of the process"/>
- <event counter="ARM_Mali-V500_cnt6" title="Mali Video Engine" name="Active Sessions" description="The number of currently existing sessions"/>
- <event counter="ARM_Mali-V500_cnt7" title="Mali Video Engine" name="Processed Frames" class="absolute" description="The number of processed frames. A processed frame is one where the encode or decode is complete for that particular frame. Frames can be processed out of order so this is not the same as the number of output-buffers returned"/>
- <event counter="ARM_Mali-V500_cnt8" title="Mali Video Engine" name="Input Flushes Requested" class="absolute" description="The number of requested flushes of the input queue"/>
- <event counter="ARM_Mali-V500_cnt9" title="Mali Video Engine" name="Input Flushes Complete" class="absolute" description="The number of completed flushes of the input queue"/>
- <event counter="ARM_Mali-V500_cnt10" title="Mali Video Engine" name="Output Flushes Requested" class="absolute" description="The number of requested flushes of the output queue"/>
- <event counter="ARM_Mali-V500_cnt11" title="Mali Video Engine" name="Output Flushes Complete" class="absolute" description="The number of completed flushes of the output queue"/>
- <event counter="ARM_Mali-V500_cnt12" title="Mali Video Engine" name="Queued Output Buffers (current)" description="The number of output-buffers that are currently queued for usage by the MVE"/>
- <event counter="ARM_Mali-V500_cnt13" title="Mali Video Engine" name="Queued Input Buffers (current)" description="The number of input-buffers that are currently queued for consumption by the MVE"/>
- <event counter="ARM_Mali-V500_cnt14" title="Mali Video Engine" name="Output Queue Flushes" description="The number of pending flushes for the MVE output-queue"/>
- <event counter="ARM_Mali-V500_cnt15" title="Mali Video Engine" name="Input Queue Flushes" description="The number of pending flushes for the MVE input-queue"/>
- <event counter="ARM_Mali-V500_cnt16" title="Mali Video Engine" name="Errors encountered" class="absolute" description="The number of errors encountered"/>
- <event counter="ARM_Mali-V500_cnt17" title="Mali Video Engine" name="Bits consumed" class="absolute" description="The number of bits consumed during decode"/>
- <event counter="ARM_Mali-V500_cnt18" title="Mali Video Engine" name="AFBC bandwidth" class="absolute" description="The amount of AFBC-encoded bytes read or written"/>
- <event counter="ARM_Mali-V500_cnt19" title="Mali Video Engine" name="Bandwidth (read)" class="absolute" description="The amount of bytes read over the AXI bus"/>
- <event counter="ARM_Mali-V500_cnt20" title="Mali Video Engine" name="Bandwidth (write)" class="absolute" description="The amount of bytes written over the AXI bus"/>
- <event counter="ARM_Mali-V500_evn0" title="Mali Video Engine" name="Session created" description="Generated when a session has been created"/>
- <event counter="ARM_Mali-V500_evn1" title="Mali Video Engine" name="Session destroyed" description="Generated when a session has been destroyed"/>
- <event counter="ARM_Mali-V500_evn2" title="Mali Video Engine" name="Frame Processed" description="Generated when the MVE has finished processing a frame"/>
- <event counter="ARM_Mali-V500_evn3" title="Mali Video Engine" name="Output buffer received" description="Generated when an an output buffer is returned to us from the MVE"/>
- <event counter="ARM_Mali-V500_evn4" title="Mali Video Engine" name="Input buffer received" description="Generated when we an input buffer is returned to us from the MVE"/>
- <!--event counter="ARM_Mali-V500_act" title="VPU" name="Activity" class="activity" activity1="Parsed" activity_color1="0x000000ff" activity2="Piped" activity_color2="0x0000ff00" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" cores="8" description="Mali-V500 Activity"/-->
+ <event counter="ARM_Mali-V500_cnt0" title="MVE-V500 Stats" name="Samples" class="absolute" description="The number of times we have taken a sample"/>
+ <event counter="ARM_Mali-V500_cnt1" title="MVE-V500 Input Totals" name="Queued input-buffers" class="absolute" description="The number of input-buffers that has been queued for consumption by the MVE"/>
+ <event counter="ARM_Mali-V500_cnt2" title="MVE-V500 Input Totals" name="Consumed input-buffers" class="absolute" description="The number of input-buffers that has been consumed by the MVE and returned to the application"/>
+ <event counter="ARM_Mali-V500_cnt3" title="MVE-V500 Output Totals" name="Queued output-buffers" class="absolute" description="The number of output-buffers that has been queued for usage by the MVE"/>
+ <event counter="ARM_Mali-V500_cnt4" title="MVE-V500 Output Totals" name="Consumed output-buffers" class="absolute" description="The number of output-buffers that has been consumed by the MVE and returned to the application"/>
+ <event counter="ARM_Mali-V500_cnt5" title="MVE-V500 Stats" name="Created Sessions" class="absolute" description="The number of created sessions throughout the lifetime of the process"/>
+ <event counter="ARM_Mali-V500_cnt6" title="MVE-V500 Sessions" name="Active Sessions" description="The number of currently existing sessions"/>
+ <event counter="ARM_Mali-V500_cnt7" title="MVE-V500 Stats" name="Processed Frames" class="absolute" description="The number of processed frames. A processed frame is one where the encode or decode is complete for that particular frame. Frames can be processed out of order so this is not the same as the number of output-buffers returned"/>
+ <event counter="ARM_Mali-V500_cnt8" title="MVE-V500 Input Totals" name="Input Flushes Requested" class="absolute" description="The number of requested flushes of the input queue"/>
+ <event counter="ARM_Mali-V500_cnt9" title="MVE-V500 Input Totals" name="Input Flushes Complete" class="absolute" description="The number of completed flushes of the input queue"/>
+ <event counter="ARM_Mali-V500_cnt10" title="MVE-V500 Output Totals" name="Output Flushes Requested" class="absolute" description="The number of requested flushes of the output queue"/>
+ <event counter="ARM_Mali-V500_cnt11" title="MVE-V500 Output Totals" name="Output Flushes Complete" class="absolute" description="The number of completed flushes of the output queue"/>
+ <event counter="ARM_Mali-V500_cnt12" title="MVE-V500 Output" name="Queued Output Buffers (current)" description="The number of output-buffers that are currently queued for usage by the MVE"/>
+ <event counter="ARM_Mali-V500_cnt13" title="MVE-V500 Input" name="Queued Input Buffers (current)" description="The number of input-buffers that are currently queued for consumption by the MVE"/>
+ <event counter="ARM_Mali-V500_cnt14" title="MVE-V500 Output" name="Output Queue Flushes" description="The number of pending flushes for the MVE output-queue"/>
+ <event counter="ARM_Mali-V500_cnt15" title="MVE-V500 Input" name="Input Queue Flushes" description="The number of pending flushes for the MVE input-queue"/>
+ <event counter="ARM_Mali-V500_cnt16" title="MVE-V500 Stats" name="Errors encountered" class="absolute" description="The number of errors encountered"/>
+ <event counter="ARM_Mali-V500_cnt17" title="MVE-V500 Bandwidth" name="Bits consumed" class="absolute" description="The number of bits consumed during decode"/>
+ <event counter="ARM_Mali-V500_cnt18" title="MVE-V500 Bandwidth" name="AFBC bandwidth" class="absolute" description="The amount of AFBC-encoded bytes read or written"/>
+ <event counter="ARM_Mali-V500_cnt19" title="MVE-V500 Bandwidth" name="Bandwidth (read)" class="absolute" description="The amount of bytes read over the AXI bus"/>
+ <event counter="ARM_Mali-V500_cnt20" title="MVE-V500 Bandwidth" name="Bandwidth (write)" class="absolute" description="The amount of bytes written over the AXI bus"/>
+ <event counter="ARM_Mali-V500_evn0" title="MVE-V500 Sessions" name="Session created" description="Generated when a session has been created"/>
+ <event counter="ARM_Mali-V500_evn1" title="MVE-V500 Sessions" name="Session destroyed" description="Generated when a session has been destroyed"/>
+ <event counter="ARM_Mali-V500_evn2" title="MVE-V500 Frames" name="Frame Processed" description="Generated when the MVE has finished processing a frame"/>
+ <event counter="ARM_Mali-V500_evn3" title="MVE-V500 Output" name="Output buffer received" description="Generated when an an output buffer is returned to us from the MVE"/>
+ <event counter="ARM_Mali-V500_evn4" title="MVE-V500 Input" name="Input buffer received" description="Generated when we an input buffer is returned to us from the MVE"/>
+ <event counter="ARM_Mali-V500_act0" title="MVE-V500 Parsed" name="Activity" class="activity" activity1="activity" activity_color1="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" cores="8" description="Mali-V500 Activity"/>
+ <event counter="ARM_Mali-V500_act1" title="MVE-V500 Piped" name="Activity" class="activity" activity1="activity" activity_color1="0x0000ff00" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" cores="8" description="Mali-V500 Activity"/>
</category>
diff --git a/daemon/events-ftrace.xml b/daemon/events-ftrace.xml
new file mode 100644
index 0000000..33ab7aa
--- /dev/null
+++ b/daemon/events-ftrace.xml
@@ -0,0 +1,7 @@
+ <category name="Ftrace">
+ <!-- counter attribute must start with ftrace_ and be unique -->
+ <!-- regex item in () is the value shown -->
+ <!--
+ <event counter="ftrace_trace_marker_numbers" title="ftrace" name="trace_marker" class="absolute" regex="([0-9]+)" description="Numbers written to /sys/kernel/debug/tracing/trace_marker, ex: echo 42 > /sys/kernel/debug/tracing/trace_marker"/>
+ -->
+ </category>
diff --git a/daemon/main.cpp b/daemon/main.cpp
index 2998c70..fbce1e1 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -19,16 +19,15 @@
#include <sys/wait.h>
#include <unistd.h>
+#include "CCNDriver.h"
#include "Child.h"
#include "EventsXML.h"
-#include "KMod.h"
#include "Logging.h"
#include "Monitor.h"
#include "OlySocket.h"
#include "OlyUtility.h"
#include "SessionData.h"
-
-#define DEBUG false
+#include "Setup.h"
extern Child* child;
static int shutdownFilesystem();
@@ -40,8 +39,9 @@ static bool driverRunningAtStart = false;
static bool driverMountedAtStart = false;
struct cmdline_t {
+ char *module;
int port;
- char* module;
+ bool update;
};
#define DEFAULT_PORT 8080
@@ -105,7 +105,6 @@ static void child_exit(int) {
}
}
-static const int UDP_ANS_PORT = 30000;
static const int UDP_REQ_PORT = 30001;
typedef struct {
@@ -125,11 +124,10 @@ static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0,
class UdpListener {
public:
- UdpListener() : mDstAns(), mReq(-1), mAns(-1) {}
+ UdpListener() : mDstAns(), mReq(-1) {}
void setup(int port) {
mReq = udpPort(UDP_REQ_PORT);
- mAns = udpPort(UDP_ANS_PORT);
// Format the answer buffer
memset(&mDstAns, 0, sizeof(mDstAns));
@@ -161,16 +159,13 @@ public:
logg->logError(__FILE__, __LINE__, "recvfrom failed");
handleException();
} else if ((read == 12) && (memcmp(buf, DST_REQ, sizeof(DST_REQ)) == 0)) {
- if (sendto(mAns, &mDstAns, sizeof(mDstAns), 0, (struct sockaddr *)&sockaddr, addrlen) != sizeof(mDstAns)) {
- logg->logError(__FILE__, __LINE__, "sendto failed");
- handleException();
- }
+ // Don't care if sendto fails - gatord shouldn't exit because of it and Streamline will retry
+ sendto(mReq, &mDstAns, sizeof(mDstAns), 0, (struct sockaddr *)&sockaddr, addrlen);
}
}
void close() {
::close(mReq);
- ::close(mAns);
}
private:
@@ -180,10 +175,10 @@ private:
int on;
int family = AF_INET6;
- s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ s = socket_cloexec(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1) {
family = AF_INET;
- s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ s = socket_cloexec(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1) {
logg->logError(__FILE__, __LINE__, "socket failed");
handleException();
@@ -210,7 +205,6 @@ private:
RVIConfigureInfo mDstAns;
int mReq;
- int mAns;
};
static UdpListener udpListener;
@@ -233,7 +227,7 @@ static int mountGatorFS() {
static bool init_module (const char * const location) {
bool ret(false);
- const int fd = open(location, O_RDONLY);
+ const int fd = open(location, O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
struct stat st;
if (fstat(fd, &st) == 0) {
@@ -332,10 +326,26 @@ static int shutdownFilesystem() {
return 0; // success
}
+static const char OPTSTRING[] = "hvudap:s:c:e:m:o:";
+
+static bool hasDebugFlag(int argc, char** argv) {
+ int c;
+
+ optind = 1;
+ while ((c = getopt(argc, argv, OPTSTRING)) != -1) {
+ if (c == 'd') {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static struct cmdline_t parseCommandLine(int argc, char** argv) {
struct cmdline_t cmdline;
cmdline.port = DEFAULT_PORT;
cmdline.module = NULL;
+ cmdline.update = false;
char version_string[256]; // arbitrary length to hold the version information
int c;
@@ -346,11 +356,15 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) {
snprintf(version_string, sizeof(version_string), "Streamline gatord development version %d", PROTOCOL_VERSION);
}
- while ((c = getopt(argc, argv, "hvp:s:c:e:m:o:")) != -1) {
- switch(c) {
+ optind = 1;
+ while ((c = getopt(argc, argv, OPTSTRING)) != -1) {
+ switch (c) {
case 'c':
gSessionData->mConfigurationXMLPath = optarg;
break;
+ case 'd':
+ // Already handled
+ break;
case 'e':
gSessionData->mEventsXMLPath = optarg;
break;
@@ -366,6 +380,12 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) {
case 'o':
gSessionData->mTargetPath = optarg;
break;
+ case 'u':
+ cmdline.update = true;
+ break;
+ case 'a':
+ gSessionData->mAllowCommands = true;
+ break;
case 'h':
case '?':
logg->logError(__FILE__, __LINE__,
@@ -375,9 +395,11 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) {
"-h this help page\n"
"-m module path and filename of gator.ko\n"
"-p port_number port upon which the server listens; default is 8080\n"
- "-s session_xml path and filename of a session xml used for local capture\n"
+ "-s session_xml path and filename of a session.xml used for local capture\n"
"-o apc_dir path and name of the output for a local capture\n"
"-v version information\n"
+ "-d enable debug messages\n"
+ "-a allow the user user to provide a command to run at the start of a capture"
, version_string);
handleException();
break;
@@ -407,7 +429,7 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) {
return cmdline;
}
-void handleClient() {
+static void handleClient() {
OlySocket client(sock->acceptConnection());
int pid = fork();
@@ -452,12 +474,15 @@ int main(int argc, char** argv) {
// e.g. it may not be the group leader when launched as 'sudo gatord'
setsid();
- logg = new Logging(DEBUG); // Set up global thread-safe logging
- gSessionData = new SessionData(); // Global data class
- util = new OlyUtility(); // Set up global utility class
+ // Set up global thread-safe logging
+ logg = new Logging(hasDebugFlag(argc, argv));
+ // Global data class
+ gSessionData = new SessionData();
+ // Set up global utility class
+ util = new OlyUtility();
// Initialize drivers
- new KMod();
+ new CCNDriver();
prctl(PR_SET_NAME, (unsigned long)&"gatord-main", 0, 0, 0);
pthread_mutex_init(&numSessions_mutex, NULL);
@@ -474,6 +499,10 @@ int main(int argc, char** argv) {
// Parse the command line parameters
struct cmdline_t cmdline = parseCommandLine(argc, argv);
+ if (cmdline.update) {
+ return update(argv[0]);
+ }
+
// Verify root permissions
uid_t euid = geteuid();
if (euid) {
@@ -490,17 +519,18 @@ int main(int argc, char** argv) {
" >>> gator.ko should be co-located with gatord in the same directory\n"
" >>> OR insmod gator.ko prior to launching gatord\n"
" >>> OR specify the location of gator.ko on the command line\n"
- " >>> OR run Linux 3.4 or later with perf (CONFIG_PERF_EVENTS and CONFIG_HW_PERF_EVENTS) and tracing (CONFIG_TRACING) support to collect data via userspace only");
+ " >>> OR run Linux 3.4 or later with perf (CONFIG_PERF_EVENTS and CONFIG_HW_PERF_EVENTS) and tracing (CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER) support to collect data via userspace only");
handleException();
}
}
- gSessionData->hwmon.setup();
{
EventsXML eventsXML;
mxml_node_t *xml = eventsXML.getTree();
- gSessionData->fsDriver.setup(xml);
- gSessionData->maliVideo.setup(xml);
+ // Initialize all drivers
+ for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
+ driver->readEvents(xml);
+ }
mxmlDelete(xml);
}
@@ -517,9 +547,14 @@ int main(int argc, char** argv) {
child->run();
delete child;
} else {
+ gSessionData->annotateListener.setup();
sock = new OlyServerSocket(cmdline.port);
udpListener.setup(cmdline.port);
- if (!monitor.init() || !monitor.add(sock->getFd()) || !monitor.add(udpListener.getReq())) {
+ if (!monitor.init() ||
+ !monitor.add(sock->getFd()) ||
+ !monitor.add(udpListener.getReq()) ||
+ !monitor.add(gSessionData->annotateListener.getFd()) ||
+ false) {
logg->logError(__FILE__, __LINE__, "Monitor setup failed");
handleException();
}
@@ -537,6 +572,8 @@ int main(int argc, char** argv) {
handleClient();
} else if (events[i].data.fd == udpListener.getReq()) {
udpListener.handle();
+ } else if (events[i].data.fd == gSessionData->annotateListener.getFd()) {
+ gSessionData->annotateListener.handle();
}
}
}
diff --git a/daemon/mxml/config.h b/daemon/mxml/config.h
index 1f59ba3..ad6df1d 100644
--- a/daemon/mxml/config.h
+++ b/daemon/mxml/config.h
@@ -1,10 +1,10 @@
/* config.h. Generated from config.h.in by configure. */
/*
- * "$Id: config.h.in 408 2010-09-19 05:26:46Z mike $"
+ * "$Id: config.h.in 451 2014-01-04 21:50:06Z msweet $"
*
* Configuration file for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2003-2010 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -12,7 +12,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -30,7 +30,7 @@
* Version number...
*/
-#define MXML_VERSION "Mini-XML v2.7"
+#define MXML_VERSION "Mini-XML v2.8"
/*
@@ -92,5 +92,5 @@ extern int _mxml_vsnprintf(char *, size_t, const char *, va_list);
# endif /* !HAVE_VSNPRINTF */
/*
- * End of "$Id: config.h.in 408 2010-09-19 05:26:46Z mike $".
+ * End of "$Id: config.h.in 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/daemon/mxml/mxml-attr.c b/daemon/mxml/mxml-attr.c
index c9950f5..8e89cc1 100644
--- a/daemon/mxml/mxml-attr.c
+++ b/daemon/mxml/mxml-attr.c
@@ -1,9 +1,9 @@
/*
- * "$Id: mxml-attr.c 408 2010-09-19 05:26:46Z mike $"
+ * "$Id: mxml-attr.c 451 2014-01-04 21:50:06Z msweet $"
*
* Attribute support code for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2003-2010 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -11,15 +11,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
- *
- * Contents:
- *
- * mxmlElementDeleteAttr() - Delete an attribute.
- * mxmlElementGetAttr() - Get an attribute.
- * mxmlElementSetAttr() - Set an attribute.
- * mxmlElementSetAttrf() - Set an attribute with a formatted value.
- * mxml_set_attr() - Set or add an attribute name/value pair.
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -90,6 +82,9 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */
memmove(attr, attr + 1, i * sizeof(mxml_attr_t));
node->value.element.num_attrs --;
+
+ if (node->value.element.num_attrs == 0)
+ free(node->value.element.attrs);
return;
}
}
@@ -315,5 +310,5 @@ mxml_set_attr(mxml_node_t *node, /* I - Element node */
/*
- * End of "$Id: mxml-attr.c 408 2010-09-19 05:26:46Z mike $".
+ * End of "$Id: mxml-attr.c 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/daemon/mxml/mxml-entity.c b/daemon/mxml/mxml-entity.c
index c5c9f61..0d11df6 100644
--- a/daemon/mxml/mxml-entity.c
+++ b/daemon/mxml/mxml-entity.c
@@ -1,10 +1,10 @@
/*
- * "$Id: mxml-entity.c 408 2010-09-19 05:26:46Z mike $"
+ * "$Id: mxml-entity.c 451 2014-01-04 21:50:06Z msweet $"
*
* Character entity support code for Mini-XML, a small XML-like
* file parsing library.
*
- * Copyright 2003-2010 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -12,18 +12,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
- *
- * Contents:
- *
- * mxmlEntityAddCallback() - Add a callback to convert entities to
- * Unicode.
- * mxmlEntityGetName() - Get the name that corresponds to the
- * character value.
- * mxmlEntityGetValue() - Get the character corresponding to a named
- * entity.
- * mxmlEntityRemoveCallback() - Remove a callback.
- * _mxml_entity_cb() - Lookup standard (X)HTML entities.
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -456,5 +445,5 @@ _mxml_entity_cb(const char *name) /* I - Entity name */
/*
- * End of "$Id: mxml-entity.c 408 2010-09-19 05:26:46Z mike $".
+ * End of "$Id: mxml-entity.c 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/daemon/mxml/mxml-file.c b/daemon/mxml/mxml-file.c
index 7860ee5..3812c25 100644
--- a/daemon/mxml/mxml-file.c
+++ b/daemon/mxml/mxml-file.c
@@ -1,9 +1,9 @@
/*
- * "$Id: mxml-file.c 438 2011-03-24 05:47:51Z mike $"
+ * "$Id: mxml-file.c 455 2014-01-05 03:28:03Z msweet $"
*
* File loading code for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2003-2011 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -11,44 +11,11 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
- *
- * Contents:
- *
- * mxmlLoadFd() - Load a file descriptor into an XML node tree.
- * mxmlLoadFile() - Load a file into an XML node tree.
- * mxmlLoadString() - Load a string into an XML node tree.
- * mxmlSaveAllocString() - Save an XML tree to an allocated string.
- * mxmlSaveFd() - Save an XML tree to a file descriptor.
- * mxmlSaveFile() - Save an XML tree to a file.
- * mxmlSaveString() - Save an XML node tree to a string.
- * mxmlSAXLoadFd() - Load a file descriptor into an XML node tree
- * using a SAX callback.
- * mxmlSAXLoadFile() - Load a file into an XML node tree
- * using a SAX callback.
- * mxmlSAXLoadString() - Load a string into an XML node tree
- * using a SAX callback.
- * mxmlSetCustomHandlers() - Set the handling functions for custom data.
- * mxmlSetErrorCallback() - Set the error message callback.
- * mxmlSetWrapMargin() - Set the wrap margin when saving XML data.
- * mxml_add_char() - Add a character to a buffer, expanding as needed.
- * mxml_fd_getc() - Read a character from a file descriptor.
- * mxml_fd_putc() - Write a character to a file descriptor.
- * mxml_fd_read() - Read a buffer of data from a file descriptor.
- * mxml_fd_write() - Write a buffer of data to a file descriptor.
- * mxml_file_getc() - Get a character from a file.
- * mxml_file_putc() - Write a character to a file.
- * mxml_get_entity() - Get the character corresponding to an entity...
- * mxml_load_data() - Load data into an XML node tree.
- * mxml_parse_element() - Parse an element for any attributes...
- * mxml_string_getc() - Get a character from a string.
- * mxml_string_putc() - Write a character to a string.
- * mxml_write_name() - Write a name string.
- * mxml_write_node() - Save an XML node to a file.
- * mxml_write_string() - Write a string, escaping & and < as needed.
- * mxml_write_ws() - Do whitespace callback...
+ * http://www.msweet.org/projects.php/Mini-XML
*/
+/*** This file modified by ARM on 25 Aug 2014 to avoid pointer overflow when checking if the write position is beyond the end of the buffer in mxmlSaveString and mxml_string_putc ***/
+
/*
* Include necessary headers...
*/
@@ -128,7 +95,7 @@ static int mxml_write_node(mxml_node_t *node, void *p,
_mxml_global_t *global);
static int mxml_write_string(const char *s, void *p,
_mxml_putc_cb_t putc_cb);
-static int mxml_write_ws(mxml_node_t *node, void *p,
+static int mxml_write_ws(mxml_node_t *node, void *p,
mxml_save_cb_t cb, int ws,
int col, _mxml_putc_cb_t putc_cb);
@@ -400,7 +367,7 @@ mxmlSaveString(mxml_node_t *node, /* I - Node to write */
mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
{
int col; /* Final column */
- char *ptr[2]; /* Pointers for putc_cb */
+ char *ptr[3]; /* Pointers for putc_cb */
_mxml_global_t *global = _mxml_global();
/* Global data */
@@ -411,6 +378,7 @@ mxmlSaveString(mxml_node_t *node, /* I - Node to write */
ptr[0] = buffer;
ptr[1] = buffer + bufsize;
+ ptr[2] = 0;
if ((col = mxml_write_node(node, ptr, cb, 0, mxml_string_putc, global)) < 0)
return (-1);
@@ -422,7 +390,7 @@ mxmlSaveString(mxml_node_t *node, /* I - Node to write */
* Nul-terminate the buffer...
*/
- if (ptr[0] >= ptr[1])
+ if (ptr[2] != 0)
buffer[bufsize - 1] = '\0';
else
ptr[0][0] = '\0';
@@ -567,7 +535,7 @@ mxmlSAXLoadString(
*
* The save function accepts a node pointer and must return a malloc'd
* string on success and NULL on error.
- *
+ *
*/
void
@@ -756,7 +724,7 @@ mxml_fd_getc(void *p, /* I - File descriptor buffer */
return (EOF);
ch = *(buf->current)++;
-
+
if (ch != 0xff)
return (EOF);
@@ -775,7 +743,7 @@ mxml_fd_getc(void *p, /* I - File descriptor buffer */
return (EOF);
ch = *(buf->current)++;
-
+
if (ch != 0xfe)
return (EOF);
@@ -1287,8 +1255,8 @@ mxml_file_getc(void *p, /* I - Pointer to file */
* Multi-word UTF-16 char...
*/
- int lch = (getc(fp) << 8);
- lch |= getc(fp);
+ int lch = getc(fp);
+ lch = (lch << 8) | getc(fp);
if (lch < 0xdc00 || lch >= 0xdfff)
return (EOF);
@@ -1317,7 +1285,7 @@ mxml_file_getc(void *p, /* I - Pointer to file */
*/
int lch = getc(fp);
- lch |= (getc(fp) << 8);
+ lch |= (getc(fp) << 8);
if (lch < 0xdc00 || lch >= 0xdfff)
return (EOF);
@@ -1463,8 +1431,10 @@ mxml_load_data(
if (cb && parent)
type = (*cb)(parent);
- else
+ else if (parent)
type = MXML_TEXT;
+ else
+ type = MXML_IGNORE;
while ((ch = (*getc_cb)(p, &encoding)) != EOF)
{
@@ -1518,7 +1488,7 @@ mxml_load_data(
default : /* Ignore... */
node = NULL;
break;
- }
+ }
if (*bufptr)
{
@@ -1661,9 +1631,9 @@ mxml_load_data(
* There can only be one root element!
*/
- mxml_error("<%s> cannot be a second root node after <%s>",
+ mxml_error("<%s> cannot be a second root node after <%s>",
buffer, first->value.element.name);
- goto error;
+ goto error;
}
if ((node = mxmlNewElement(parent, buffer)) == NULL)
@@ -1729,9 +1699,9 @@ mxml_load_data(
* There can only be one root element!
*/
- mxml_error("<%s> cannot be a second root node after <%s>",
+ mxml_error("<%s> cannot be a second root node after <%s>",
buffer, first->value.element.name);
- goto error;
+ goto error;
}
if ((node = mxmlNewElement(parent, buffer)) == NULL)
@@ -1796,9 +1766,9 @@ mxml_load_data(
* There can only be one root element!
*/
- mxml_error("<%s> cannot be a second root node after <%s>",
+ mxml_error("<%s> cannot be a second root node after <%s>",
buffer, first->value.element.name);
- goto error;
+ goto error;
}
if ((node = mxmlNewElement(parent, buffer)) == NULL)
@@ -1882,9 +1852,9 @@ mxml_load_data(
* There can only be one root element!
*/
- mxml_error("<%s> cannot be a second root node after <%s>",
+ mxml_error("<%s> cannot be a second root node after <%s>",
buffer, first->value.element.name);
- goto error;
+ goto error;
}
if ((node = mxmlNewElement(parent, buffer)) == NULL)
@@ -1974,9 +1944,9 @@ mxml_load_data(
* There can only be one root element!
*/
- mxml_error("<%s> cannot be a second root node after <%s>",
+ mxml_error("<%s> cannot be a second root node after <%s>",
buffer, first->value.element.name);
- goto error;
+ goto error;
}
if ((node = mxmlNewElement(parent, buffer)) == NULL)
@@ -2076,7 +2046,7 @@ mxml_load_data(
{
node = parent;
- while (parent->parent != top && parent->parent)
+ while (parent != top && parent->parent)
parent = parent->parent;
if (node != parent)
@@ -2286,7 +2256,7 @@ mxml_parse_element(
if (ch == '&')
if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
goto error;
-
+
if (mxml_add_char(ch, &ptr, &value, &valsize))
goto error;
}
@@ -2310,7 +2280,7 @@ mxml_parse_element(
if (ch == '&')
if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
goto error;
-
+
if (mxml_add_char(ch, &ptr, &value, &valsize))
goto error;
}
@@ -2643,8 +2613,12 @@ mxml_string_putc(int ch, /* I - Character to write */
pp = (char **)p;
- if (pp[0] < pp[1])
- pp[0][0] = ch;
+ if (pp[2] == 0) {
+ if (pp[0] < pp[1])
+ pp[0][0] = ch;
+ else
+ pp[2] = (char *)1;
+ }
pp[0] ++;
@@ -3078,5 +3052,5 @@ mxml_write_ws(mxml_node_t *node, /* I - Current node */
/*
- * End of "$Id: mxml-file.c 438 2011-03-24 05:47:51Z mike $".
+ * End of "$Id: mxml-file.c 455 2014-01-05 03:28:03Z msweet $".
*/
diff --git a/daemon/mxml/mxml-get.c b/daemon/mxml/mxml-get.c
index a5356d5..40ed3d0 100644
--- a/daemon/mxml/mxml-get.c
+++ b/daemon/mxml/mxml-get.c
@@ -1,9 +1,9 @@
/*
- * "$Id: mxml-get.c 427 2011-01-03 02:03:29Z mike $"
+ * "$Id: mxml-get.c 451 2014-01-04 21:50:06Z msweet $"
*
* Node get functions for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2011 by Michael R Sweet.
+ * Copyright 2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -11,26 +11,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
- *
- * Contents:
- *
- * mxmlGetCDATA() - Get the value for a CDATA node.
- * mxmlGetCustom() - Get the value for a custom node.
- * mxmlGetElement() - Get the name for an element node.
- * mxmlGetFirstChild() - Get the first child of an element node.
- * mxmlGetInteger() - Get the integer value from the specified node or its
- * first child.
- * mxmlGetLastChild() - Get the last child of an element node.
- * mxmlGetNextSibling() - Get the next node for the current parent.
- * mxmlGetOpaque() - Get an opaque string value for a node or its first
- * child.
- * mxmlGetParent() - Get the parent node.
- * mxmlGetPrevSibling() - Get the previous node for the current parent.
- * mxmlGetReal() - Get the real value for a node or its first child.
- * mxmlGetText() - Get the text value for a node or its first child.
- * mxmlGetType() - Get the node type.
- * mxmlGetUserData() - Get the user data pointer for a node.
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -467,5 +448,5 @@ mxmlGetUserData(mxml_node_t *node) /* I - Node to get */
/*
- * End of "$Id: mxml-get.c 427 2011-01-03 02:03:29Z mike $".
+ * End of "$Id: mxml-get.c 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/daemon/mxml/mxml-index.c b/daemon/mxml/mxml-index.c
index b6efc66..1081439 100644
--- a/daemon/mxml/mxml-index.c
+++ b/daemon/mxml/mxml-index.c
@@ -1,9 +1,9 @@
/*
- * "$Id: mxml-index.c 426 2011-01-01 23:42:17Z mike $"
+ * "$Id: mxml-index.c 451 2014-01-04 21:50:06Z msweet $"
*
* Index support code for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2003-2011 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -11,10 +11,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
- *
- * Contents:
- *
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -658,5 +655,5 @@ index_sort(mxml_index_t *ind, /* I - Index to sort */
/*
- * End of "$Id: mxml-index.c 426 2011-01-01 23:42:17Z mike $".
+ * End of "$Id: mxml-index.c 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/daemon/mxml/mxml-node.c b/daemon/mxml/mxml-node.c
index 44af759..128cda1 100644
--- a/daemon/mxml/mxml-node.c
+++ b/daemon/mxml/mxml-node.c
@@ -1,9 +1,9 @@
/*
- * "$Id: mxml-node.c 436 2011-01-22 01:02:05Z mike $"
+ * "$Id: mxml-node.c 451 2014-01-04 21:50:06Z msweet $"
*
* Node support code for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2003-2011 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -11,26 +11,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
- *
- * Contents:
- *
- * mxmlAdd() - Add a node to a tree.
- * mxmlDelete() - Delete a node and all of its children.
- * mxmlGetRefCount() - Get the current reference (use) count for a node.
- * mxmlNewCDATA() - Create a new CDATA node.
- * mxmlNewCustom() - Create a new custom data node.
- * mxmlNewElement() - Create a new element node.
- * mxmlNewInteger() - Create a new integer node.
- * mxmlNewOpaque() - Create a new opaque string.
- * mxmlNewReal() - Create a new real number node.
- * mxmlNewText() - Create a new text fragment node.
- * mxmlNewTextf() - Create a new formatted text fragment node.
- * mxmlRemove() - Remove a node from its parent.
- * mxmlNewXML() - Create a new XML document tree.
- * mxmlRelease() - Release a node.
- * mxmlRetain() - Retain a node.
- * mxml_new() - Create a new node.
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -529,7 +510,7 @@ mxmlNewReal(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
* list. The constant MXML_NO_PARENT can be used to specify that the new
* text node has no parent. The whitespace parameter is used to specify
* whether leading whitespace is present before the node. The text
- * string must be nul-terminated and is copied into the new node.
+ * string must be nul-terminated and is copied into the new node.
*/
mxml_node_t * /* O - New node */
@@ -573,7 +554,7 @@ mxmlNewText(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
* list. The constant MXML_NO_PARENT can be used to specify that the new
* text node has no parent. The whitespace parameter is used to specify
* whether leading whitespace is present before the node. The format
- * string must be nul-terminated and is formatted into the new node.
+ * string must be nul-terminated and is formatted into the new node.
*/
mxml_node_t * /* O - New node */
@@ -803,5 +784,5 @@ mxml_new(mxml_node_t *parent, /* I - Parent node */
/*
- * End of "$Id: mxml-node.c 436 2011-01-22 01:02:05Z mike $".
+ * End of "$Id: mxml-node.c 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/daemon/mxml/mxml-private.c b/daemon/mxml/mxml-private.c
index 72f3e23..bec4bbf 100644
--- a/daemon/mxml/mxml-private.c
+++ b/daemon/mxml/mxml-private.c
@@ -1,9 +1,9 @@
/*
- * "$Id: mxml-private.c 422 2010-11-07 22:55:11Z mike $"
+ * "$Id: mxml-private.c 451 2014-01-04 21:50:06Z msweet $"
*
* Private functions for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2003-2010 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -11,15 +11,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
- *
- * Contents:
- *
- * mxml_error() - Display an error message.
- * mxml_integer_cb() - Default callback for integer values.
- * mxml_opaque_cb() - Default callback for opaque values.
- * mxml_real_cb() - Default callback for real number values.
- * _mxml_global() - Get global data.
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -238,7 +230,7 @@ static DWORD _mxml_tls_index; /* Index for global storage */
/*
* 'DllMain()' - Main entry for library.
*/
-
+
BOOL WINAPI /* O - Success/failure */
DllMain(HINSTANCE hinst, /* I - DLL module handle */
DWORD reason, /* I - Reason */
@@ -250,28 +242,28 @@ DllMain(HINSTANCE hinst, /* I - DLL module handle */
(void)hinst;
(void)reserved;
- switch (reason)
- {
+ switch (reason)
+ {
case DLL_PROCESS_ATTACH : /* Called on library initialization */
- if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
- return (FALSE);
- break;
+ if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ return (FALSE);
+ break;
case DLL_THREAD_DETACH : /* Called when a thread terminates */
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
free(global);
- break;
+ break;
case DLL_PROCESS_DETACH : /* Called when library is unloaded */
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
free(global);
- TlsFree(_mxml_tls_index);
- break;
+ TlsFree(_mxml_tls_index);
+ break;
- default:
- break;
- }
+ default:
+ break;
+ }
return (TRUE);
}
@@ -295,7 +287,7 @@ _mxml_global(void)
global->entity_cbs[0] = _mxml_entity_cb;
global->wrap = 72;
- TlsSetValue(_mxml_tls_index, (LPVOID)global);
+ TlsSetValue(_mxml_tls_index, (LPVOID)global);
}
return (global);
@@ -327,5 +319,5 @@ _mxml_global(void)
/*
- * End of "$Id: mxml-private.c 422 2010-11-07 22:55:11Z mike $".
+ * End of "$Id: mxml-private.c 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/daemon/mxml/mxml-private.h b/daemon/mxml/mxml-private.h
index 8789e6c..c5e4e6b 100644
--- a/daemon/mxml/mxml-private.h
+++ b/daemon/mxml/mxml-private.h
@@ -1,9 +1,9 @@
/*
- * "$Id: mxml-private.h 408 2010-09-19 05:26:46Z mike $"
+ * "$Id: mxml-private.h 451 2014-01-04 21:50:06Z msweet $"
*
* Private definitions for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2003-2010 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -11,7 +11,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -46,5 +46,5 @@ extern int _mxml_entity_cb(const char *name);
/*
- * End of "$Id: mxml-private.h 408 2010-09-19 05:26:46Z mike $".
+ * End of "$Id: mxml-private.h 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/daemon/mxml/mxml-search.c b/daemon/mxml/mxml-search.c
index f975af1..313a52f 100644
--- a/daemon/mxml/mxml-search.c
+++ b/daemon/mxml/mxml-search.c
@@ -1,10 +1,10 @@
/*
- * "$Id: mxml-search.c 427 2011-01-03 02:03:29Z mike $"
+ * "$Id: mxml-search.c 451 2014-01-04 21:50:06Z msweet $"
*
* Search/navigation functions for Mini-XML, a small XML-like file
* parsing library.
*
- * Copyright 2003-2010 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -12,14 +12,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
- *
- * Contents:
- *
- * mxmlFindElement() - Find the named element.
- * mxmlFindValue() - Find a value with the given path.
- * mxmlWalkNext() - Walk to the next logical node in the tree.
- * mxmlWalkPrev() - Walk to the previous logical node in the tree.
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -126,7 +119,7 @@ mxmlFindElement(mxml_node_t *node, /* I - Current node */
*
* The first child node of the found node is returned if the given node has
* children and the first child is a value node.
- *
+ *
* @since Mini-XML 2.7@
*/
@@ -283,5 +276,5 @@ mxmlWalkPrev(mxml_node_t *node, /* I - Current node */
/*
- * End of "$Id: mxml-search.c 427 2011-01-03 02:03:29Z mike $".
+ * End of "$Id: mxml-search.c 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/daemon/mxml/mxml-set.c b/daemon/mxml/mxml-set.c
index b0bd527..16d4bf1 100644
--- a/daemon/mxml/mxml-set.c
+++ b/daemon/mxml/mxml-set.c
@@ -1,9 +1,9 @@
/*
- * "$Id: mxml-set.c 441 2011-12-09 23:49:00Z mike $"
+ * "$Id: mxml-set.c 451 2014-01-04 21:50:06Z msweet $"
*
* Node set functions for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2003-2011 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -11,19 +11,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
- *
- * Contents:
- *
- * mxmlSetCDATA() - Set the element name of a CDATA node.
- * mxmlSetCustom() - Set the data and destructor of a custom data node.
- * mxmlSetElement() - Set the name of an element node.
- * mxmlSetInteger() - Set the value of an integer node.
- * mxmlSetOpaque() - Set the value of an opaque node.
- * mxmlSetReal() - Set the value of a real number node.
- * mxmlSetText() - Set the value of a text node.
- * mxmlSetTextf() - Set the value of a text node to a formatted string.
- * mxmlSetUserData() - Set the user data pointer for a node.
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -345,5 +333,5 @@ mxmlSetUserData(mxml_node_t *node, /* I - Node to set */
/*
- * End of "$Id: mxml-set.c 441 2011-12-09 23:49:00Z mike $".
+ * End of "$Id: mxml-set.c 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/daemon/mxml/mxml-string.c b/daemon/mxml/mxml-string.c
index 6be4252..9d5b58e 100644
--- a/daemon/mxml/mxml-string.c
+++ b/daemon/mxml/mxml-string.c
@@ -1,9 +1,9 @@
/*
- * "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $"
+ * "$Id: mxml-string.c 454 2014-01-05 03:25:07Z msweet $"
*
* String functions for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2003-2010 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -11,15 +11,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
- *
- * Contents:
- *
- * _mxml_snprintf() - Format a string.
- * _mxml_strdup() - Duplicate a string.
- * _mxml_strdupf() - Format and duplicate a string.
- * _mxml_vsnprintf() - Format a string into a fixed size buffer.
- * _mxml_vstrdupf() - Format and duplicate a string.
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -38,7 +30,7 @@
# ifdef __va_copy
# define va_copy(dst,src) __va_copy(dst,src)
# else
-# define va_copy(dst,src) memcpy(&dst, &src, sizeof(va_list))
+# define va_copy(dst,src) memcpy(&dst, src, sizeof(va_list))
# endif /* __va_copy */
#endif /* va_copy */
@@ -157,7 +149,8 @@ _mxml_vsnprintf(char *buffer, /* O - Output buffer */
if (*format == '%')
{
- if (bufptr && bufptr < bufend) *bufptr++ = *format;
+ if (bufptr && bufptr < bufend)
+ *bufptr++ = *format;
bytes ++;
format ++;
continue;
@@ -472,5 +465,5 @@ _mxml_vstrdupf(const char *format, /* I - Printf-style format string */
/*
- * End of "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $".
+ * End of "$Id: mxml-string.c 454 2014-01-05 03:25:07Z msweet $".
*/
diff --git a/daemon/mxml/mxml.h b/daemon/mxml/mxml.h
index 79c711f..bba5fd2 100644
--- a/daemon/mxml/mxml.h
+++ b/daemon/mxml/mxml.h
@@ -1,9 +1,9 @@
/*
- * "$Id: mxml.h 427 2011-01-03 02:03:29Z mike $"
+ * "$Id: mxml.h 451 2014-01-04 21:50:06Z msweet $"
*
* Header file for Mini-XML, a small XML-like file parsing library.
*
- * Copyright 2003-2011 by Michael R Sweet.
+ * Copyright 2003-2014 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
@@ -11,7 +11,7 @@
* which should have been included with this file. If this file is
* missing or damaged, see the license at:
*
- * http://www.minixml.org/
+ * http://www.msweet.org/projects.php/Mini-XML
*/
/*
@@ -36,6 +36,9 @@
* Constants...
*/
+# define MXML_MAJOR_VERSION 2 /* Major version number */
+# define MXML_MINOR_VERSION 8 /* Minor version number */
+
# define MXML_TAB 8 /* Tabs every N columns */
# define MXML_NO_CALLBACK 0 /* Don't use a type callback */
@@ -93,7 +96,7 @@ typedef enum mxml_type_e /**** The XML node type. ****/
typedef void (*mxml_custom_destroy_cb_t)(void *);
/**** Custom data destructor ****/
-typedef void (*mxml_error_cb_t)(const char *);
+typedef void (*mxml_error_cb_t)(const char *);
/**** Error callback function ****/
typedef struct mxml_attr_s /**** An XML element attribute value. @private@ ****/
@@ -161,7 +164,7 @@ typedef struct mxml_index_s mxml_index_t;
typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *);
/**** Custom data load callback function ****/
-typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);
+typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);
/**** Custom data save callback function ****/
typedef int (*mxml_entity_cb_t)(const char *);
@@ -173,7 +176,7 @@ typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *);
typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int);
/**** Save callback function ****/
-typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *);
+typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *);
/**** SAX callback function ****/
@@ -325,5 +328,5 @@ extern mxml_type_t mxml_real_cb(mxml_node_t *node);
/*
- * End of "$Id: mxml.h 427 2011-01-03 02:03:29Z mike $".
+ * End of "$Id: mxml.h 451 2014-01-04 21:50:06Z msweet $".
*/
diff --git a/driver/Makefile b/driver/Makefile
index 12c14e8..28d2070 100644
--- a/driver/Makefile
+++ b/driver/Makefile
@@ -14,7 +14,6 @@ gator-y := gator_main.o \
gator_events_net.o \
gator_events_perf_pmu.o \
gator_events_sched.o \
- gator_events_threads.o \
# Convert the old GATOR_WITH_MALI_SUPPORT to the new kernel flags
ifneq ($(GATOR_WITH_MALI_SUPPORT),)
@@ -54,16 +53,15 @@ GATOR_TEST ?= 0
EXTRA_CFLAGS += -DGATOR_TEST=$(GATOR_TEST)
# Should the original or new block_rq_complete API be used?
-OLD_BLOCK_RQ_COMPLETE := $(shell grep -A3 block_rq_complete include/trace/events/block.h | grep nr_bytes > /dev/null; echo $$?)
+OLD_BLOCK_RQ_COMPLETE := $(shell grep -A3 block_rq_complete $(srctree)/include/trace/events/block.h | grep nr_bytes -q; echo $$?)
EXTRA_CFLAGS += -DOLD_BLOCK_RQ_COMPLETE=$(OLD_BLOCK_RQ_COMPLETE)
gator-$(CONFIG_ARM) += gator_events_armv6.o \
gator_events_armv7.o \
- gator_events_ccn-504.o \
gator_events_l2c-310.o \
gator_events_scorpion.o
-gator-$(CONFIG_ARM64) += gator_events_ccn-504.o
+gator-$(CONFIG_ARM64) +=
else
diff --git a/driver/gator.h b/driver/gator.h
index df76afa..5cc73a3 100644
--- a/driver/gator.h
+++ b/driver/gator.h
@@ -14,13 +14,13 @@
#include <linux/mm.h>
#include <linux/list.h>
-#define GATOR_PERF_SUPPORT LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
-#define GATOR_PERF_PMU_SUPPORT GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && (!(defined(__arm__) || defined(__aarch64__)) || defined(CONFIG_HW_PERF_EVENTS))
+#define GATOR_PERF_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+#define GATOR_PERF_PMU_SUPPORT (GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && (!(defined(__arm__) || defined(__aarch64__)) || defined(CONFIG_HW_PERF_EVENTS)))
#define GATOR_NO_PERF_SUPPORT (!(GATOR_PERF_SUPPORT))
-#define GATOR_CPU_FREQ_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ)
+#define GATOR_CPU_FREQ_SUPPORT ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ))
#define GATOR_IKS_SUPPORT defined(CONFIG_BL_SWITCHER)
-// cpu ids
+/* cpu ids */
#define ARM1136 0xb36
#define ARM1156 0xb56
#define ARM1176 0xb76
@@ -29,7 +29,6 @@
#define CORTEX_A7 0xc07
#define CORTEX_A8 0xc08
#define CORTEX_A9 0xc09
-#define CORTEX_A12 0xc0d
#define CORTEX_A15 0xc0f
#define CORTEX_A17 0xc0e
#define SCORPION 0x00f
@@ -42,7 +41,7 @@
#define AARCH64 0xd0f
#define OTHER 0xfff
-// gpu enums
+/* gpu enums */
#define MALI_4xx 1
#define MALI_MIDGARD 2
@@ -50,12 +49,12 @@
struct gator_cpu {
const int cpuid;
- // Human readable name
+ /* Human readable name */
const char core_name[MAXSIZE_CORE_NAME];
- // gatorfs event and Perf PMU name
- const char * const pmnc_name;
- // compatible from Documentation/devicetree/bindings/arm/cpus.txt
- const char * const dt_name;
+ /* gatorfs event and Perf PMU name */
+ const char *const pmnc_name;
+ /* compatible from Documentation/devicetree/bindings/arm/cpus.txt */
+ const char *const dt_name;
const int pmnc_counters;
};
@@ -107,15 +106,19 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
* Events
******************************************************************************/
struct gator_interface {
- void (*shutdown)(void); // Complementary function to init
+ /* Complementary function to init */
+ void (*shutdown)(void);
int (*create_files)(struct super_block *sb, struct dentry *root);
int (*start)(void);
- void (*stop)(void); // Complementary function to start
+ /* Complementary function to start */
+ void (*stop)(void);
int (*online)(int **buffer, bool migrate);
int (*offline)(int **buffer, bool migrate);
- void (*online_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu'
- void (*offline_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu'
- int (*read)(int **buffer);
+ /* called in process context but may not be running on core 'cpu' */
+ void (*online_dispatch)(int cpu, bool migrate);
+ /* called in process context but may not be running on core 'cpu' */
+ void (*offline_dispatch)(int cpu, bool migrate);
+ int (*read)(int **buffer, bool sched_switch);
int (*read64)(long long **buffer);
int (*read_proc)(long long **buffer, struct task_struct *);
struct list_head list;
@@ -146,4 +149,4 @@ int pcpu_to_lcpu(const int pcpu);
#define get_logical_cpu() smp_processor_id()
#define on_primary_core() (get_logical_cpu() == 0)
-#endif // GATOR_H_
+#endif /* GATOR_H_ */
diff --git a/driver/gator_annotate.c b/driver/gator_annotate.c
index 7e2c6e5..ff9a3ce 100644
--- a/driver/gator_annotate.c
+++ b/driver/gator_annotate.c
@@ -11,12 +11,12 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/sched.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/current.h>
#include <linux/spinlock.h>
static DEFINE_SPINLOCK(annotate_lock);
-static bool collect_annotations = false;
+static bool collect_annotations;
static int annotate_copy(struct file *file, char const __user *buf, size_t count)
{
@@ -24,10 +24,10 @@ static int annotate_copy(struct file *file, char const __user *buf, size_t count
int write = per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF];
if (file == NULL) {
- // copy from kernel
+ /* copy from kernel */
memcpy(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count);
} else {
- // copy from user space
+ /* copy from user space */
if (copy_from_user(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count) != 0)
return -1;
}
@@ -41,70 +41,70 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
int pid, cpu, header_size, available, contiguous, length1, length2, size, count = count_orig & 0x7fffffff;
bool interrupt_context;
- if (*offset) {
+ if (*offset)
return -EINVAL;
- }
interrupt_context = in_interrupt();
- // Annotations are not supported in interrupt context, but may work if you comment out the the next four lines of code.
- // By doing so, annotations in interrupt context can result in deadlocks and lost data.
+ /* Annotations are not supported in interrupt context, but may work
+ * if you comment out the the next four lines of code. By doing so,
+ * annotations in interrupt context can result in deadlocks and lost
+ * data.
+ */
if (interrupt_context) {
- printk(KERN_WARNING "gator: Annotations are not supported in interrupt context. Edit gator_annotate.c in the gator driver to enable annotations in interrupt context.\n");
+ pr_warning("gator: Annotations are not supported in interrupt context. Edit gator_annotate.c in the gator driver to enable annotations in interrupt context.\n");
return -EINVAL;
}
retry:
- // synchronize between cores and with collect_annotations
+ /* synchronize between cores and with collect_annotations */
spin_lock(&annotate_lock);
if (!collect_annotations) {
- // Not collecting annotations, tell the caller everything was written
+ /* Not collecting annotations, tell the caller everything was written */
size = count_orig;
goto annotate_write_out;
}
- // Annotation only uses a single per-cpu buffer as the data must be in order to the engine
+ /* Annotation only uses a single per-cpu buffer as the data must be in order to the engine */
cpu = 0;
- if (current == NULL) {
+ if (current == NULL)
pid = 0;
- } else {
+ else
pid = current->pid;
- }
- // determine total size of the payload
+ /* determine total size of the payload */
header_size = MAXSIZE_PACK32 * 3 + MAXSIZE_PACK64;
available = buffer_bytes_available(cpu, ANNOTATE_BUF) - header_size;
size = count < available ? count : available;
if (size <= 0) {
- // Buffer is full, wait until space is available
+ /* Buffer is full, wait until space is available */
spin_unlock(&annotate_lock);
- // Drop the annotation as blocking is not allowed in interrupt context
- if (interrupt_context) {
+ /* Drop the annotation as blocking is not allowed in interrupt context */
+ if (interrupt_context)
return -EINVAL;
- }
wait_event_interruptible(gator_annotate_wait, buffer_bytes_available(cpu, ANNOTATE_BUF) > header_size || !collect_annotations);
- // Check to see if a signal is pending
- if (signal_pending(current)) {
+ /* Check to see if a signal is pending */
+ if (signal_pending(current))
return -EINTR;
- }
goto retry;
}
- // synchronize shared variables annotateBuf and annotatePos
+ /* synchronize shared variables annotateBuf and annotatePos */
if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF]) {
u64 time = gator_get_time();
+
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu());
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid);
gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, time);
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, size);
- // determine the sizes to capture, length1 + length2 will equal size
+ /* determine the sizes to capture, length1 + length2 will equal size */
contiguous = contiguous_space_available(cpu, ANNOTATE_BUF);
if (size < contiguous) {
length1 = size;
@@ -124,14 +124,14 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
goto annotate_write_out;
}
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, ANNOTATE_BUF, time);
}
annotate_write_out:
spin_unlock(&annotate_lock);
- // return the number of bytes written
+ /* return the number of bytes written */
return size;
}
@@ -141,18 +141,21 @@ static int annotate_release(struct inode *inode, struct file *file)
{
int cpu = 0;
- // synchronize between cores
+ /* synchronize between cores */
spin_lock(&annotate_lock);
if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) {
uint32_t pid = current->pid;
+
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu());
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid);
- gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time
- gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size
+ /* time */
+ gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0);
+ /* size */
+ gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0);
}
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, ANNOTATE_BUF, gator_get_time());
spin_unlock(&annotate_lock);
@@ -178,7 +181,7 @@ static int gator_annotate_start(void)
static void gator_annotate_stop(void)
{
- // the spinlock here will ensure that when this function exits, we are not in the middle of an annotation
+ /* the spinlock here will ensure that when this function exits, we are not in the middle of an annotation */
spin_lock(&annotate_lock);
collect_annotations = false;
wake_up(&gator_annotate_wait);
diff --git a/driver/gator_annotate_kernel.c b/driver/gator_annotate_kernel.c
index 0108068..69471f9 100644
--- a/driver/gator_annotate_kernel.c
+++ b/driver/gator_annotate_kernel.c
@@ -19,10 +19,11 @@ static void kannotate_write(const char *ptr, unsigned int size)
int retval;
int pos = 0;
loff_t offset = 0;
+
while (pos < size) {
retval = annotate_write(NULL, &ptr[pos], size - pos, &offset);
if (retval < 0) {
- printk(KERN_WARNING "gator: kannotate_write failed with return value %d\n", retval);
+ pr_warning("gator: kannotate_write failed with return value %d\n", retval);
return;
}
pos += retval;
@@ -47,6 +48,7 @@ void gator_annotate_channel(int channel, const char *str)
{
const u16 str_size = strlen(str) & 0xffff;
char header[8];
+
header[0] = ESCAPE_CODE;
header[1] = STRING_ANNOTATION;
marshal_u32(header + 2, channel);
@@ -54,20 +56,19 @@ void gator_annotate_channel(int channel, const char *str)
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size);
}
-
EXPORT_SYMBOL(gator_annotate_channel);
void gator_annotate(const char *str)
{
gator_annotate_channel(0, str);
}
-
EXPORT_SYMBOL(gator_annotate);
void gator_annotate_channel_color(int channel, int color, const char *str)
{
const u16 str_size = (strlen(str) + 4) & 0xffff;
char header[12];
+
header[0] = ESCAPE_CODE;
header[1] = STRING_ANNOTATION;
marshal_u32(header + 2, channel);
@@ -76,39 +77,37 @@ void gator_annotate_channel_color(int channel, int color, const char *str)
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size - 4);
}
-
EXPORT_SYMBOL(gator_annotate_channel_color);
void gator_annotate_color(int color, const char *str)
{
gator_annotate_channel_color(0, color, str);
}
-
EXPORT_SYMBOL(gator_annotate_color);
void gator_annotate_channel_end(int channel)
{
char header[8];
+
header[0] = ESCAPE_CODE;
header[1] = STRING_ANNOTATION;
marshal_u32(header + 2, channel);
marshal_u16(header + 6, 0);
kannotate_write(header, sizeof(header));
}
-
EXPORT_SYMBOL(gator_annotate_channel_end);
void gator_annotate_end(void)
{
gator_annotate_channel_end(0);
}
-
EXPORT_SYMBOL(gator_annotate_end);
-void gator_annotate_name_channel(int channel, int group, const char* str)
+void gator_annotate_name_channel(int channel, int group, const char *str)
{
const u16 str_size = strlen(str) & 0xffff;
char header[12];
+
header[0] = ESCAPE_CODE;
header[1] = NAME_CHANNEL_ANNOTATION;
marshal_u32(header + 2, channel);
@@ -117,13 +116,13 @@ void gator_annotate_name_channel(int channel, int group, const char* str)
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size);
}
-
EXPORT_SYMBOL(gator_annotate_name_channel);
-void gator_annotate_name_group(int group, const char* str)
+void gator_annotate_name_group(int group, const char *str)
{
const u16 str_size = strlen(str) & 0xffff;
char header[8];
+
header[0] = ESCAPE_CODE;
header[1] = NAME_GROUP_ANNOTATION;
marshal_u32(header + 2, group);
@@ -131,7 +130,6 @@ void gator_annotate_name_group(int group, const char* str)
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size);
}
-
EXPORT_SYMBOL(gator_annotate_name_group);
void gator_annotate_visual(const char *data, unsigned int length, const char *str)
@@ -139,6 +137,7 @@ void gator_annotate_visual(const char *data, unsigned int length, const char *st
const u16 str_size = strlen(str) & 0xffff;
char header[4];
char header_length[4];
+
header[0] = ESCAPE_CODE;
header[1] = VISUAL_ANNOTATION;
marshal_u16(header + 2, str_size);
@@ -148,49 +147,49 @@ void gator_annotate_visual(const char *data, unsigned int length, const char *st
kannotate_write(header_length, sizeof(header_length));
kannotate_write(data, length);
}
-
EXPORT_SYMBOL(gator_annotate_visual);
void gator_annotate_marker(void)
{
char header[4];
+
header[0] = ESCAPE_CODE;
header[1] = MARKER_ANNOTATION;
marshal_u16(header + 2, 0);
kannotate_write(header, sizeof(header));
}
-
EXPORT_SYMBOL(gator_annotate_marker);
void gator_annotate_marker_str(const char *str)
{
const u16 str_size = strlen(str) & 0xffff;
char header[4];
+
header[0] = ESCAPE_CODE;
header[1] = MARKER_ANNOTATION;
marshal_u16(header + 2, str_size);
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size);
}
-
EXPORT_SYMBOL(gator_annotate_marker_str);
void gator_annotate_marker_color(int color)
{
char header[8];
+
header[0] = ESCAPE_CODE;
header[1] = MARKER_ANNOTATION;
marshal_u16(header + 2, 4);
marshal_u32(header + 4, color);
kannotate_write(header, sizeof(header));
}
-
EXPORT_SYMBOL(gator_annotate_marker_color);
void gator_annotate_marker_color_str(int color, const char *str)
{
const u16 str_size = (strlen(str) + 4) & 0xffff;
char header[8];
+
header[0] = ESCAPE_CODE;
header[1] = MARKER_ANNOTATION;
marshal_u16(header + 2, str_size);
@@ -198,5 +197,4 @@ void gator_annotate_marker_color_str(int color, const char *str)
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size - 4);
}
-
EXPORT_SYMBOL(gator_annotate_marker_color_str);
diff --git a/driver/gator_backtrace.c b/driver/gator_backtrace.c
index e03c165..76c941d 100644
--- a/driver/gator_backtrace.c
+++ b/driver/gator_backtrace.c
@@ -14,17 +14,17 @@ struct stack_frame_eabi {
union {
struct {
unsigned long fp;
- // May be the fp in the case of a leaf function or clang
+ /* May be the fp in the case of a leaf function or clang */
unsigned long lr;
- // If lr is really the fp, lr2 is the corresponding lr
+ /* If lr is really the fp, lr2 is the corresponding lr */
unsigned long lr2;
};
- // Used to read 32 bit fp/lr from a 64 bit kernel
+ /* Used to read 32 bit fp/lr from a 64 bit kernel */
struct {
u32 fp_32;
- // same as lr above
+ /* same as lr above */
u32 lr_32;
- // same as lr2 above
+ /* same as lr2 above */
u32 lr2_32;
};
};
@@ -35,9 +35,8 @@ static void gator_add_trace(int cpu, unsigned long address)
off_t offset = 0;
unsigned long cookie = get_address_cookie(cpu, current, address & ~1, &offset);
- if (cookie == NO_COOKIE || cookie == UNRESOLVED_COOKIE) {
+ if (cookie == NO_COOKIE || cookie == UNRESOLVED_COOKIE)
offset = address;
- }
marshal_backtrace(offset & ~1, cookie, 0);
}
@@ -54,36 +53,34 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
unsigned long lr = regs->ARM_lr;
const int gcc_frame_offset = sizeof(unsigned long);
#else
- // Is userspace aarch32 (32 bit)
+ /* Is userspace aarch32 (32 bit) */
const bool is_compat = compat_user_mode(regs);
unsigned long fp = (is_compat ? regs->regs[11] : regs->regs[29]);
unsigned long sp = (is_compat ? regs->compat_sp : regs->sp);
unsigned long lr = (is_compat ? regs->compat_lr : regs->regs[30]);
const int gcc_frame_offset = (is_compat ? sizeof(u32) : 0);
#endif
- // clang frame offset is always zero
+ /* clang frame offset is always zero */
int is_user_mode = user_mode(regs);
- // pc (current function) has already been added
+ /* pc (current function) has already been added */
- if (!is_user_mode) {
+ if (!is_user_mode)
return;
- }
- // Add the lr (parent function)
- // entry preamble may not have executed
+ /* Add the lr (parent function), entry preamble may not have
+ * executed
+ */
gator_add_trace(cpu, lr);
- // check fp is valid
- if (fp == 0 || fp < sp) {
+ /* check fp is valid */
+ if (fp == 0 || fp < sp)
return;
- }
- // Get the current stack frame
+ /* Get the current stack frame */
curr = (struct stack_frame_eabi *)(fp - gcc_frame_offset);
- if ((unsigned long)curr & 3) {
+ if ((unsigned long)curr & 3)
return;
- }
while (depth-- && curr) {
if (!access_ok(VERIFY_READ, curr, sizeof(struct stack_frame_eabi)) ||
@@ -95,13 +92,15 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
lr = (is_compat ? bufcurr.lr_32 : bufcurr.lr);
#define calc_next(reg) ((reg) - gcc_frame_offset)
- // Returns true if reg is a valid fp
+ /* Returns true if reg is a valid fp */
#define validate_next(reg, curr) \
((reg) != 0 && (calc_next(reg) & 3) == 0 && (unsigned long)(curr) < calc_next(reg))
- // Try lr from the stack as the fp because gcc leaf functions do not push lr
- // If gcc_frame_offset is non-zero, the lr will also be the clang fp
- // This assumes code is at a lower address than the stack
+ /* Try lr from the stack as the fp because gcc leaf functions do
+ * not push lr. If gcc_frame_offset is non-zero, the lr will also
+ * be the clang fp. This assumes code is at a lower address than
+ * the stack
+ */
if (validate_next(lr, curr)) {
fp = lr;
lr = (is_compat ? bufcurr.lr2_32 : bufcurr.lr2);
@@ -109,11 +108,10 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
gator_add_trace(cpu, lr);
- if (!validate_next(fp, curr)) {
+ if (!validate_next(fp, curr))
return;
- }
- // Move to the next stack frame
+ /* Move to the next stack frame */
curr = (struct stack_frame_eabi *)calc_next(fp);
}
#endif
@@ -129,6 +127,7 @@ static int report_trace(struct stackframe *frame, void *d)
#if defined(MODULE)
unsigned int cpu = get_physical_cpu();
struct module *mod = __module_address(addr);
+
if (mod) {
cookie = get_cookie(cpu, current, mod->name, false);
addr = addr - (unsigned long)mod->module_core;
@@ -142,13 +141,13 @@ static int report_trace(struct stackframe *frame, void *d)
}
#endif
-// Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile
-// #define GATOR_KERNEL_STACK_UNWINDING
+/* Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile */
+/* #define GATOR_KERNEL_STACK_UNWINDING */
#if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING)
-// Disabled by default
+/* Disabled by default */
MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding.");
-static bool kernel_stack_unwinding = 0;
+static bool kernel_stack_unwinding;
module_param(kernel_stack_unwinding, bool, 0644);
#endif
@@ -161,6 +160,7 @@ static void kernel_backtrace(int cpu, struct pt_regs *const regs)
int depth = (kernel_stack_unwinding ? gator_backtrace_depth : 1);
#endif
struct stackframe frame;
+
if (depth == 0)
depth = 1;
#if defined(__arm__)
@@ -196,10 +196,10 @@ static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time)
if (in_kernel) {
kernel_backtrace(cpu, regs);
} else {
- // Cookie+PC
+ /* Cookie+PC */
gator_add_trace(cpu, PC_REG);
- // Backtrace
+ /* Backtrace */
if (gator_backtrace_depth)
arm_backtrace_eabi(cpu, regs, gator_backtrace_depth);
}
diff --git a/driver/gator_buffer.c b/driver/gator_buffer.c
index dfbc97d..910d5aa 100644
--- a/driver/gator_buffer.c
+++ b/driver/gator_buffer.c
@@ -10,55 +10,65 @@
static void marshal_frame(int cpu, int buftype)
{
int frame;
+ bool write_cpu;
- if (!per_cpu(gator_buffer, cpu)[buftype]) {
+ if (!per_cpu(gator_buffer, cpu)[buftype])
return;
- }
switch (buftype) {
case SUMMARY_BUF:
+ write_cpu = false;
frame = FRAME_SUMMARY;
break;
case BACKTRACE_BUF:
+ write_cpu = true;
frame = FRAME_BACKTRACE;
break;
case NAME_BUF:
+ write_cpu = true;
frame = FRAME_NAME;
break;
case COUNTER_BUF:
+ write_cpu = false;
frame = FRAME_COUNTER;
break;
case BLOCK_COUNTER_BUF:
+ write_cpu = true;
frame = FRAME_BLOCK_COUNTER;
break;
case ANNOTATE_BUF:
+ write_cpu = false;
frame = FRAME_ANNOTATE;
break;
case SCHED_TRACE_BUF:
+ write_cpu = true;
frame = FRAME_SCHED_TRACE;
break;
case IDLE_BUF:
+ write_cpu = false;
frame = FRAME_IDLE;
break;
case ACTIVITY_BUF:
+ write_cpu = false;
frame = FRAME_ACTIVITY;
break;
default:
+ write_cpu = false;
frame = -1;
break;
}
- // add response type
- if (gator_response_type > 0) {
+ /* add response type */
+ if (gator_response_type > 0)
gator_buffer_write_packed_int(cpu, buftype, gator_response_type);
- }
- // leave space for 4-byte unpacked length
+ /* leave space for 4-byte unpacked length */
per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype];
- // add frame type and core number
+ /* add frame type and core number */
gator_buffer_write_packed_int(cpu, buftype, frame);
- gator_buffer_write_packed_int(cpu, buftype, cpu);
+ if (write_cpu)
+ gator_buffer_write_packed_int(cpu, buftype, cpu);
}
static int buffer_bytes_available(int cpu, int buftype)
@@ -66,19 +76,17 @@ static int buffer_bytes_available(int cpu, int buftype)
int remaining, filled;
filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype];
- if (filled < 0) {
+ if (filled < 0)
filled += gator_buffer_size[buftype];
- }
remaining = gator_buffer_size[buftype] - filled;
- if (per_cpu(buffer_space_available, cpu)[buftype]) {
- // Give some extra room; also allows space to insert the overflow error packet
+ if (per_cpu(buffer_space_available, cpu)[buftype])
+ /* Give some extra room; also allows space to insert the overflow error packet */
remaining -= 200;
- } else {
- // Hysteresis, prevents multiple overflow messages
+ else
+ /* Hysteresis, prevents multiple overflow messages */
remaining -= 2000;
- }
return remaining;
}
@@ -87,11 +95,10 @@ static bool buffer_check_space(int cpu, int buftype, int bytes)
{
int remaining = buffer_bytes_available(cpu, buftype);
- if (remaining < bytes) {
+ if (remaining < bytes)
per_cpu(buffer_space_available, cpu)[buftype] = false;
- } else {
+ else
per_cpu(buffer_space_available, cpu)[buftype] = true;
- }
return per_cpu(buffer_space_available, cpu)[buftype];
}
@@ -100,10 +107,10 @@ static int contiguous_space_available(int cpu, int buftype)
{
int remaining = buffer_bytes_available(cpu, buftype);
int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype];
+
if (remaining < contiguous)
return remaining;
- else
- return contiguous;
+ return contiguous;
}
static void gator_commit_buffer(int cpu, int buftype, u64 time)
@@ -114,41 +121,38 @@ static void gator_commit_buffer(int cpu, int buftype, u64 time)
if (!per_cpu(gator_buffer, cpu)[buftype])
return;
- // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
+ /* post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload */
local_irq_save(flags);
type_length = gator_response_type ? 1 : 0;
commit = per_cpu(gator_buffer_commit, cpu)[buftype];
length = per_cpu(gator_buffer_write, cpu)[buftype] - commit;
- if (length < 0) {
+ if (length < 0)
length += gator_buffer_size[buftype];
- }
length = length - type_length - sizeof(s32);
if (length <= FRAME_HEADER_SIZE) {
- // Nothing to write, only the frame header is present
+ /* Nothing to write, only the frame header is present */
local_irq_restore(flags);
return;
}
- for (byte = 0; byte < sizeof(s32); byte++) {
+ for (byte = 0; byte < sizeof(s32); byte++)
per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
- }
per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
if (gator_live_rate > 0) {
- while (time > per_cpu(gator_buffer_commit_time, cpu)) {
+ while (time > per_cpu(gator_buffer_commit_time, cpu))
per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
- }
}
marshal_frame(cpu, buftype);
local_irq_restore(flags);
- // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
+ /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */
if (per_cpu(in_scheduler_context, cpu)) {
#ifndef CONFIG_PREEMPT_RT_FULL
- // mod_timer can not be used in interrupt context in RT-Preempt full
+ /* mod_timer can not be used in interrupt context in RT-Preempt full */
mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
#endif
} else {
@@ -159,10 +163,9 @@ static void gator_commit_buffer(int cpu, int buftype, u64 time)
static void buffer_check(int cpu, int buftype, u64 time)
{
int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype];
- if (filled < 0) {
+
+ if (filled < 0)
filled += gator_buffer_size[buftype];
- }
- if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
+ if (filled >= ((gator_buffer_size[buftype] * 3) / 4))
gator_commit_buffer(cpu, buftype, time);
- }
}
diff --git a/driver/gator_buffer_write.c b/driver/gator_buffer_write.c
index b621ba9..654ec60 100644
--- a/driver/gator_buffer_write.c
+++ b/driver/gator_buffer_write.c
@@ -14,16 +14,17 @@ static void gator_buffer_write_packed_int(int cpu, int buftype, int x)
char *buffer = per_cpu(gator_buffer, cpu)[buftype];
int packedBytes = 0;
int more = true;
+
while (more) {
- // low order 7 bits of x
+ /* low order 7 bits of x */
char b = x & 0x7f;
+
x >>= 7;
- if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
+ if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0))
more = false;
- } else {
+ else
b |= 0x80;
- }
buffer[(write + packedBytes) & mask] = b;
packedBytes++;
@@ -39,16 +40,17 @@ static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x)
char *buffer = per_cpu(gator_buffer, cpu)[buftype];
int packedBytes = 0;
int more = true;
+
while (more) {
- // low order 7 bits of x
+ /* low order 7 bits of x */
char b = x & 0x7f;
+
x >>= 7;
- if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
+ if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0))
more = false;
- } else {
+ else
b |= 0x80;
- }
buffer[(write + packedBytes) & mask] = b;
packedBytes++;
@@ -75,6 +77,7 @@ static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int le
static void gator_buffer_write_string(int cpu, int buftype, const char *x)
{
int len = strlen(x);
+
gator_buffer_write_packed_int(cpu, buftype, len);
gator_buffer_write_bytes(cpu, buftype, x, len);
}
diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c
index 5c7d842..c43cce8 100644
--- a/driver/gator_cookies.c
+++ b/driver/gator_cookies.c
@@ -7,8 +7,10 @@
*
*/
-#define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */
-#define TRANSLATE_BUFFER_SIZE 512 // must be a power of 2 - 512/4 = 128 entries
+/* must be power of 2 */
+#define COOKIEMAP_ENTRIES 1024
+/* must be a power of 2 - 512/4 = 128 entries */
+#define TRANSLATE_BUFFER_SIZE 512
#define TRANSLATE_TEXT_SIZE 256
#define MAX_COLLISIONS 2
@@ -38,6 +40,7 @@ static uint32_t cookiemap_code(uint64_t value64)
{
uint32_t value = (uint32_t)((value64 >> 32) + value64);
uint32_t cookiecode = (value >> 24) & 0xff;
+
cookiecode = cookiecode * 31 + ((value >> 16) & 0xff);
cookiecode = cookiecode * 31 + ((value >> 8) & 0xff);
cookiecode = cookiecode * 31 + ((value >> 0) & 0xff);
@@ -52,9 +55,8 @@ static uint32_t gator_chksum_crc32(const char *data)
int i, length = strlen(data);
crc = 0xFFFFFFFF;
- for (i = 0; i < length; i++) {
+ for (i = 0; i < length; i++)
crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF];
- }
return (crc ^ 0xFFFFFFFF);
}
@@ -72,11 +74,12 @@ static uint32_t cookiemap_exists(uint64_t key)
uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
- // Can be called from interrupt handler or from work queue
+ /* Can be called from interrupt handler or from work queue */
local_irq_save(flags);
for (x = 0; x < MAX_COLLISIONS; x++) {
if (keys[x] == key) {
uint32_t value = values[x];
+
for (; x > 0; x--) {
keys[x] = keys[x - 1];
values[x] = values[x - 1];
@@ -126,7 +129,7 @@ static void translate_buffer_write_args(int cpu, struct task_struct *task, const
write = per_cpu(translate_buffer_write, cpu);
next_write = (write + 1) & translate_buffer_mask;
- // At least one entry must always remain available as when read == write, the queue is empty not full
+ /* At least one entry must always remain available as when read == write, the queue is empty not full */
if (next_write != per_cpu(translate_buffer_read, cpu)) {
args = &per_cpu(translate_buffer, cpu)[write];
args->task = task;
@@ -178,11 +181,11 @@ static void wq_cookie_handler(struct work_struct *unused)
static void app_process_wake_up_handler(unsigned long unused_data)
{
- // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
+ /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */
schedule_work(&cookie_work);
}
-// Retrieve full name from proc/pid/cmdline for java processes on Android
+/* Retrieve full name from proc/pid/cmdline for java processes on Android */
static int translate_app_process(const char **text, int cpu, struct task_struct *task, bool from_wq)
{
void *maddr;
@@ -195,12 +198,16 @@ static int translate_app_process(const char **text, int cpu, struct task_struct
char *buf = per_cpu(translate_text, cpu);
#ifndef CONFIG_PREEMPT_RT_FULL
- // Push work into a work queue if in atomic context as the kernel functions below might sleep
- // Rely on the in_interrupt variable rather than in_irq() or in_interrupt() kernel functions, as the value of these functions seems
- // inconsistent during a context switch between android/linux versions
+ /* Push work into a work queue if in atomic context as the kernel
+ * functions below might sleep. Rely on the in_interrupt variable
+ * rather than in_irq() or in_interrupt() kernel functions, as the
+ * value of these functions seems inconsistent during a context
+ * switch between android/linux versions
+ */
if (!from_wq) {
- // Check if already in buffer
+ /* Check if already in buffer */
int pos = per_cpu(translate_buffer_read, cpu);
+
while (pos != per_cpu(translate_buffer_write, cpu)) {
if (per_cpu(translate_buffer, cpu)[pos].task == task)
goto out;
@@ -209,7 +216,7 @@ static int translate_app_process(const char **text, int cpu, struct task_struct
translate_buffer_write_args(cpu, task, *text);
- // Not safe to call in RT-Preempt full in schedule switch context
+ /* Not safe to call in RT-Preempt full in schedule switch context */
mod_timer(&app_process_wake_up_timer, jiffies + 1);
goto out;
}
@@ -239,7 +246,8 @@ static int translate_app_process(const char **text, int cpu, struct task_struct
copy_from_user_page(page_vma, page, addr, buf, maddr + offset, bytes);
- kunmap(page); // release page allocated by get_user_pages()
+ /* release page allocated by get_user_pages() */
+ kunmap(page);
page_cache_release(page);
len -= bytes;
@@ -250,7 +258,7 @@ static int translate_app_process(const char **text, int cpu, struct task_struct
retval = 1;
}
- // On app_process startup, /proc/pid/cmdline is initially "zygote" then "<pre-initialized>" but changes after an initial startup period
+ /* On app_process startup, /proc/pid/cmdline is initially "zygote" then "<pre-initialized>" but changes after an initial startup period */
if (strcmp(*text, "zygote") == 0 || strcmp(*text, "<pre-initialized>") == 0)
retval = 0;
@@ -262,6 +270,8 @@ out:
return retval;
}
+static const char APP_PROCESS[] = "app_process";
+
static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq)
{
unsigned long flags, cookie;
@@ -271,16 +281,16 @@ static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text,
key = (key << 32) | (uint32_t)task->tgid;
cookie = cookiemap_exists(key);
- if (cookie) {
+ if (cookie)
return cookie;
- }
- if (strcmp(text, "app_process") == 0) {
+ /* On 64-bit android app_process can be app_process32 or app_process64 */
+ if (strncmp(text, APP_PROCESS, sizeof(APP_PROCESS) - 1) == 0) {
if (!translate_app_process(&text, cpu, task, from_wq))
return UNRESOLVED_COOKIE;
}
- // Can be called from interrupt handler or from work queue or from scheduler trace
+ /* Can be called from interrupt handler or from work queue or from scheduler trace */
local_irq_save(flags);
cookie = UNRESOLVED_COOKIE;
@@ -300,7 +310,7 @@ static int get_exec_cookie(int cpu, struct task_struct *task)
struct mm_struct *mm = task->mm;
const char *text;
- // kernel threads have no address space
+ /* kernel threads have no address space */
if (!mm)
return NO_COOKIE;
@@ -355,7 +365,7 @@ static int cookies_initialize(void)
per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu;
size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t);
- per_cpu(cookie_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL);
+ per_cpu(cookie_keys, cpu) = kmalloc(size, GFP_KERNEL);
if (!per_cpu(cookie_keys, cpu)) {
err = -ENOMEM;
goto cookie_setup_error;
@@ -363,14 +373,14 @@ static int cookies_initialize(void)
memset(per_cpu(cookie_keys, cpu), 0, size);
size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t);
- per_cpu(cookie_values, cpu) = (uint32_t *)kmalloc(size, GFP_KERNEL);
+ per_cpu(cookie_values, cpu) = kmalloc(size, GFP_KERNEL);
if (!per_cpu(cookie_values, cpu)) {
err = -ENOMEM;
goto cookie_setup_error;
}
memset(per_cpu(cookie_values, cpu), 0, size);
- per_cpu(translate_buffer, cpu) = (struct cookie_args *)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL);
+ per_cpu(translate_buffer, cpu) = kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL);
if (!per_cpu(translate_buffer, cpu)) {
err = -ENOMEM;
goto cookie_setup_error;
@@ -379,16 +389,16 @@ static int cookies_initialize(void)
per_cpu(translate_buffer_write, cpu) = 0;
per_cpu(translate_buffer_read, cpu) = 0;
- per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL);
+ per_cpu(translate_text, cpu) = kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL);
if (!per_cpu(translate_text, cpu)) {
err = -ENOMEM;
goto cookie_setup_error;
}
}
- // build CRC32 table
+ /* build CRC32 table */
poly = 0x04c11db7;
- gator_crc32_table = (uint32_t *)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL);
+ gator_crc32_table = kmalloc(256 * sizeof(*gator_crc32_table), GFP_KERNEL);
if (!gator_crc32_table) {
err = -ENOMEM;
goto cookie_setup_error;
@@ -396,11 +406,10 @@ static int cookies_initialize(void)
for (i = 0; i < 256; i++) {
crc = i;
for (j = 8; j > 0; j--) {
- if (crc & 1) {
+ if (crc & 1)
crc = (crc >> 1) ^ poly;
- } else {
+ else
crc >>= 1;
- }
}
gator_crc32_table[i] = crc;
}
diff --git a/driver/gator_events_armv6.c b/driver/gator_events_armv6.c
index 3536456..a157a00 100644
--- a/driver/gator_events_armv6.c
+++ b/driver/gator_events_armv6.c
@@ -8,7 +8,7 @@
#include "gator.h"
-// gator_events_perf_pmu.c is used if perf is supported
+/* gator_events_perf_pmu.c is used if perf is supported */
#if GATOR_NO_PERF_SUPPORT
static const char *pmnc_name;
@@ -28,7 +28,7 @@ static const char *pmnc_name;
#define CCNT 2
#define CNTMAX (CCNT+1)
-static int pmnc_counters = 0;
+static int pmnc_counters;
static unsigned long pmnc_enabled[CNTMAX];
static unsigned long pmnc_event[CNTMAX];
static unsigned long pmnc_key[CNTMAX];
@@ -45,6 +45,7 @@ static inline void armv6_pmnc_write(u32 val)
static inline u32 armv6_pmnc_read(void)
{
u32 val;
+
asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
return val;
}
@@ -52,6 +53,7 @@ static inline u32 armv6_pmnc_read(void)
static void armv6_pmnc_reset_counter(unsigned int cnt)
{
u32 val = 0;
+
switch (cnt) {
case CCNT:
asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
@@ -74,20 +76,18 @@ int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
for (i = PMN0; i <= CCNT; i++) {
char buf[40];
- if (i == CCNT) {
- snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
- } else {
- snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i);
- }
+
+ if (i == CCNT)
+ snprintf(buf, sizeof(buf), "ARM_%s_ccnt", pmnc_name);
+ else
+ snprintf(buf, sizeof(buf), "ARM_%s_cnt%d", pmnc_name, i);
dir = gatorfs_mkdir(sb, root, buf);
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
- if (i != CCNT) {
+ if (i != CCNT)
gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
- }
}
return 0;
@@ -98,9 +98,8 @@ static int gator_events_armv6_online(int **buffer, bool migrate)
unsigned int cnt, len = 0, cpu = smp_processor_id();
u32 pmnc;
- if (armv6_pmnc_read() & PMCR_E) {
+ if (armv6_pmnc_read() & PMCR_E)
armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
- }
/* initialize PMNC, reset overflow, D bit, C bit and P bit. */
armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
@@ -115,19 +114,18 @@ static int gator_events_armv6_online(int **buffer, bool migrate)
event = pmnc_event[cnt] & 255;
- // Set event (if destined for PMNx counters)
- if (cnt == PMN0) {
+ /* Set event (if destined for PMNx counters) */
+ if (cnt == PMN0)
pmnc |= event << 20;
- } else if (cnt == PMN1) {
+ else if (cnt == PMN1)
pmnc |= event << 12;
- }
- // Reset counter
+ /* Reset counter */
armv6_pmnc_reset_counter(cnt);
}
armv6_pmnc_write(pmnc | PMCR_E);
- // return zero values, no need to read as the counters were just reset
+ /* return zero values, no need to read as the counters were just reset */
for (cnt = PMN0; cnt <= CCNT; cnt++) {
if (pmnc_enabled[cnt]) {
per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
@@ -146,9 +144,8 @@ static int gator_events_armv6_offline(int **buffer, bool migrate)
unsigned int cnt;
armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
- for (cnt = PMN0; cnt <= CCNT; cnt++) {
+ for (cnt = PMN0; cnt <= CCNT; cnt++)
armv6_pmnc_reset_counter(cnt);
- }
return 0;
}
@@ -163,19 +160,19 @@ static void gator_events_armv6_stop(void)
}
}
-static int gator_events_armv6_read(int **buffer)
+static int gator_events_armv6_read(int **buffer, bool sched_switch)
{
int cnt, len = 0;
int cpu = smp_processor_id();
- // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
- if (!(armv6_pmnc_read() & PMCR_E)) {
+ /* a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled */
+ if (!(armv6_pmnc_read() & PMCR_E))
return 0;
- }
for (cnt = PMN0; cnt <= CCNT; cnt++) {
if (pmnc_enabled[cnt]) {
u32 value = 0;
+
switch (cnt) {
case CCNT:
asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));
diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c
index bd8a9ba..09c9422 100644
--- a/driver/gator_events_armv7.c
+++ b/driver/gator_events_armv7.c
@@ -15,16 +15,16 @@
#include "gator.h"
-// gator_events_perf_pmu.c is used if perf is supported
+/* gator_events_perf_pmu.c is used if perf is supported */
#if GATOR_NO_PERF_SUPPORT
-// Per-CPU PMNC: config reg
+/* Per-CPU PMNC: config reg */
#define PMNC_E (1 << 0) /* Enable all counters */
#define PMNC_P (1 << 1) /* Reset all counters */
#define PMNC_C (1 << 2) /* Cycle counter reset */
#define PMNC_MASK 0x3f /* Mask for writable bits */
-// ccnt reg
+/* ccnt reg */
#define CCNT_REG (1 << 31)
#define CCNT 0
@@ -49,6 +49,7 @@ inline void armv7_pmnc_write(u32 val)
inline u32 armv7_pmnc_read(void)
{
u32 val;
+
asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
return val;
}
@@ -61,10 +62,10 @@ inline u32 armv7_ccnt_read(u32 reset_value)
u32 val;
local_irq_save(flags);
- asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
- asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); // read
- asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval)); // new value
- asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); /* disable */
+ asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); /* read */
+ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval)); /* new value */
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); /* enable */
local_irq_restore(flags);
return val;
@@ -79,11 +80,11 @@ inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value)
u32 oldval;
local_irq_save(flags);
- asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
- asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); // select
- asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); // read
- asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval)); // new value
- asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); /* disable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); /* select */
+ asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); /* read */
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval)); /* new value */
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); /* enable */
local_irq_restore(flags);
return oldval;
@@ -92,13 +93,15 @@ inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value)
static inline void armv7_pmnc_disable_interrupt(unsigned int cnt)
{
u32 val = cnt ? (1 << (cnt - CNT0)) : (1 << 31);
+
asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val));
}
inline u32 armv7_pmnc_reset_interrupt(void)
{
- // Get and reset overflow status flags
+ /* Get and reset overflow status flags */
u32 flags;
+
asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (flags));
flags &= 0x8000003f;
asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (flags));
@@ -108,6 +111,7 @@ inline u32 armv7_pmnc_reset_interrupt(void)
static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
{
u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG;
+
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
return cnt;
}
@@ -115,6 +119,7 @@ static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
{
u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG;
+
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
return cnt;
}
@@ -122,15 +127,15 @@ static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
static inline int armv7_pmnc_select_counter(unsigned int cnt)
{
u32 val = (cnt - CNT0);
+
asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
return cnt;
}
static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
{
- if (armv7_pmnc_select_counter(cnt) == cnt) {
+ if (armv7_pmnc_select_counter(cnt) == cnt)
asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
- }
}
static int gator_events_armv7_create_files(struct super_block *sb, struct dentry *root)
@@ -140,20 +145,18 @@ static int gator_events_armv7_create_files(struct super_block *sb, struct dentry
for (i = 0; i < pmnc_counters; i++) {
char buf[40];
- if (i == 0) {
- snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
- } else {
- snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1);
- }
+
+ if (i == 0)
+ snprintf(buf, sizeof(buf), "%s_ccnt", pmnc_name);
+ else
+ snprintf(buf, sizeof(buf), "%s_cnt%d", pmnc_name, i - 1);
dir = gatorfs_mkdir(sb, root, buf);
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
- if (i > 0) {
+ if (i > 0)
gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
- }
}
return 0;
@@ -163,14 +166,13 @@ static int gator_events_armv7_online(int **buffer, bool migrate)
{
unsigned int cnt, len = 0, cpu = smp_processor_id();
- if (armv7_pmnc_read() & PMNC_E) {
+ if (armv7_pmnc_read() & PMNC_E)
armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
- }
- // Initialize & Reset PMNC: C bit and P bit
+ /* Initialize & Reset PMNC: C bit and P bit */
armv7_pmnc_write(PMNC_P | PMNC_C);
- // Reset overflow flags
+ /* Reset overflow flags */
armv7_pmnc_reset_interrupt();
for (cnt = CCNT; cnt < CNTMAX; cnt++) {
@@ -179,28 +181,28 @@ static int gator_events_armv7_online(int **buffer, bool migrate)
if (!pmnc_enabled[cnt])
continue;
- // Disable counter
+ /* Disable counter */
armv7_pmnc_disable_counter(cnt);
event = pmnc_event[cnt] & 255;
- // Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count
+ /* Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count */
if (cnt != CCNT)
armv7_pmnc_write_evtsel(cnt, event);
armv7_pmnc_disable_interrupt(cnt);
- // Reset counter
+ /* Reset counter */
cnt ? armv7_cntn_read(cnt, 0) : armv7_ccnt_read(0);
- // Enable counter
+ /* Enable counter */
armv7_pmnc_enable_counter(cnt);
}
- // enable
+ /* enable */
armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
- // return zero values, no need to read as the counters were just reset
+ /* return zero values, no need to read as the counters were just reset */
for (cnt = 0; cnt < pmnc_counters; cnt++) {
if (pmnc_enabled[cnt]) {
per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
@@ -216,7 +218,7 @@ static int gator_events_armv7_online(int **buffer, bool migrate)
static int gator_events_armv7_offline(int **buffer, bool migrate)
{
- // disable all counters, including PMCCNTR; overflow IRQs will not be signaled
+ /* disable all counters, including PMCCNTR; overflow IRQs will not be signaled */
armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
return 0;
@@ -232,24 +234,23 @@ static void gator_events_armv7_stop(void)
}
}
-static int gator_events_armv7_read(int **buffer)
+static int gator_events_armv7_read(int **buffer, bool sched_switch)
{
int cnt, len = 0;
int cpu = smp_processor_id();
- // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
- if (!(armv7_pmnc_read() & PMNC_E)) {
+ /* a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled */
+ if (!(armv7_pmnc_read() & PMNC_E))
return 0;
- }
for (cnt = 0; cnt < pmnc_counters; cnt++) {
if (pmnc_enabled[cnt]) {
int value;
- if (cnt == CCNT) {
+
+ if (cnt == CCNT)
value = armv7_ccnt_read(0);
- } else {
+ else
value = armv7_cntn_read(cnt, 0);
- }
per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
per_cpu(perfCnt, cpu)[len++] = value;
}
@@ -290,17 +291,16 @@ int gator_events_armv7_init(void)
pmnc_name = "ARMv7_Cortex_A9";
pmnc_counters = 6;
break;
- // ARM Cortex A12 is not supported by version of Linux before 3.0
case CORTEX_A15:
pmnc_name = "ARMv7_Cortex_A15";
pmnc_counters = 6;
break;
- // ARM Cortex A17 is not supported by version of Linux before 3.0
+ /* ARM Cortex A17 is not supported by version of Linux before 3.0 */
default:
return -1;
}
- pmnc_counters++; // CNT[n] + CCNT
+ pmnc_counters++; /* CNT[n] + CCNT */
for (cnt = CCNT; cnt < CNTMAX; cnt++) {
pmnc_enabled[cnt] = 0;
diff --git a/driver/gator_events_block.c b/driver/gator_events_block.c
index 03eed4f..a352a54 100644
--- a/driver/gator_events_block.c
+++ b/driver/gator_events_block.c
@@ -28,7 +28,7 @@ static ulong block_rq_rd_key;
static atomic_t blockCnt[BLOCK_TOTAL];
static int blockGet[BLOCK_TOTAL * 4];
-// Tracepoint changed in 3.15 backported to older kernels. The Makefile tries to autodetect the correct value, but if it fails change the #if below
+/* Tracepoint changed in 3.15 backported to older kernels. The Makefile tries to autodetect the correct value, but if it fails change the #if below */
#if OLD_BLOCK_RQ_COMPLETE
GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq))
#else
@@ -52,13 +52,11 @@ GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct r
return;
if (write) {
- if (block_rq_wr_enabled) {
+ if (block_rq_wr_enabled)
atomic_add(size, &blockCnt[BLOCK_RQ_WR]);
- }
} else {
- if (block_rq_rd_enabled) {
+ if (block_rq_rd_enabled)
atomic_add(size, &blockCnt[BLOCK_RQ_RD]);
- }
}
}
@@ -68,17 +66,15 @@ static int gator_events_block_create_files(struct super_block *sb, struct dentry
/* block_complete_wr */
dir = gatorfs_mkdir(sb, root, "Linux_block_rq_wr");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &block_rq_wr_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_wr_key);
/* block_complete_rd */
dir = gatorfs_mkdir(sb, root, "Linux_block_rq_rd");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &block_rq_rd_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_rd_key);
@@ -87,7 +83,7 @@ static int gator_events_block_create_files(struct super_block *sb, struct dentry
static int gator_events_block_start(void)
{
- // register tracepoints
+ /* register tracepoints */
if (block_rq_wr_enabled || block_rq_rd_enabled)
if (GATOR_REGISTER_TRACE(block_rq_complete))
goto fail_block_rq_exit;
@@ -95,7 +91,7 @@ static int gator_events_block_start(void)
return 0;
- // unregister tracepoints on error
+ /* unregister tracepoints on error */
fail_block_rq_exit:
pr_err("gator: block event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
@@ -112,19 +108,19 @@ static void gator_events_block_stop(void)
block_rq_rd_enabled = 0;
}
-static int gator_events_block_read(int **buffer)
+static int gator_events_block_read(int **buffer, bool sched_switch)
{
int len, value, data = 0;
- if (!on_primary_core()) {
+ if (!on_primary_core())
return 0;
- }
len = 0;
if (block_rq_wr_enabled && (value = atomic_read(&blockCnt[BLOCK_RQ_WR])) > 0) {
atomic_sub(value, &blockCnt[BLOCK_RQ_WR]);
blockGet[len++] = block_rq_wr_key;
- blockGet[len++] = 0; // indicates to Streamline that value bytes were written now, not since the last message
+ /* Indicates to Streamline that value bytes were written now, not since the last message */
+ blockGet[len++] = 0;
blockGet[len++] = block_rq_wr_key;
blockGet[len++] = value;
data += value;
@@ -132,7 +128,8 @@ static int gator_events_block_read(int **buffer)
if (block_rq_rd_enabled && (value = atomic_read(&blockCnt[BLOCK_RQ_RD])) > 0) {
atomic_sub(value, &blockCnt[BLOCK_RQ_RD]);
blockGet[len++] = block_rq_rd_key;
- blockGet[len++] = 0; // indicates to Streamline that value bytes were read now, not since the last message
+ /* Indicates to Streamline that value bytes were read now, not since the last message */
+ blockGet[len++] = 0;
blockGet[len++] = block_rq_rd_key;
blockGet[len++] = value;
data += value;
diff --git a/driver/gator_events_ccn-504.c b/driver/gator_events_ccn-504.c
deleted file mode 100644
index 024ffc2..0000000
--- a/driver/gator_events_ccn-504.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/io.h>
-#include <linux/module.h>
-
-#include "gator.h"
-
-#define NUM_REGIONS 256
-#define REGION_SIZE (64*1024)
-#define REGION_DEBUG 1
-#define REGION_XP 64
-#define NUM_XPS 11
-
-// DT (Debug) region
-#define PMEVCNTSR0 0x0150
-#define PMCCNTRSR 0x0190
-#define PMCR 0x01A8
-#define PMSR 0x01B0
-#define PMSR_REQ 0x01B8
-#define PMSR_CLR 0x01C0
-
-// XP region
-#define DT_CONFIG 0x0300
-#define DT_CONTROL 0x0370
-
-// Multiple
-#define PMU_EVENT_SEL 0x0600
-#define OLY_ID 0xFF00
-
-#define CCNT 4
-#define CNTMAX (CCNT + 1)
-
-#define get_pmu_event_id(event) (((event) >> 0) & 0xFF)
-#define get_node_type(event) (((event) >> 8) & 0xFF)
-#define get_region(event) (((event) >> 16) & 0xFF)
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
-
-// From kernel/params.c
-#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
- int param_set_##name(const char *val, struct kernel_param *kp) \
- { \
- tmptype l; \
- int ret; \
- \
- if (!val) return -EINVAL; \
- ret = strtolfn(val, 0, &l); \
- if (ret == -EINVAL || ((type)l != l)) \
- return -EINVAL; \
- *((type *)kp->arg) = l; \
- return 0; \
- } \
- int param_get_##name(char *buffer, struct kernel_param *kp) \
- { \
- return sprintf(buffer, format, *((type *)kp->arg)); \
- }
-
-#else
-
-// From kernel/params.c
-#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
- int param_set_##name(const char *val, const struct kernel_param *kp) \
- { \
- tmptype l; \
- int ret; \
- \
- ret = strtolfn(val, 0, &l); \
- if (ret < 0 || ((type)l != l)) \
- return ret < 0 ? ret : -EINVAL; \
- *((type *)kp->arg) = l; \
- return 0; \
- } \
- int param_get_##name(char *buffer, const struct kernel_param *kp) \
- { \
- return scnprintf(buffer, PAGE_SIZE, format, \
- *((type *)kp->arg)); \
- } \
- struct kernel_param_ops param_ops_##name = { \
- .set = param_set_##name, \
- .get = param_get_##name, \
- }; \
- EXPORT_SYMBOL(param_set_##name); \
- EXPORT_SYMBOL(param_get_##name); \
- EXPORT_SYMBOL(param_ops_##name)
-
-#endif
-
-STANDARD_PARAM_DEF(u64, u64, "%llu", u64, strict_strtoull);
-
-// From include/linux/moduleparam.h
-#define param_check_u64(name, p) __param_check(name, p, u64)
-
-MODULE_PARM_DESC(ccn504_addr, "CCN-504 physical base address");
-static u64 ccn504_addr = 0;
-module_param(ccn504_addr, u64, 0444);
-
-static void __iomem *gator_events_ccn504_base;
-static bool gator_events_ccn504_global_enabled;
-static unsigned long gator_events_ccn504_enabled[CNTMAX];
-static unsigned long gator_events_ccn504_event[CNTMAX];
-static unsigned long gator_events_ccn504_key[CNTMAX];
-static int gator_events_ccn504_buffer[2*CNTMAX];
-static int gator_events_ccn504_prev[CNTMAX];
-
-static void gator_events_ccn504_create_shutdown(void)
-{
- if (gator_events_ccn504_base != NULL) {
- iounmap(gator_events_ccn504_base);
- }
-}
-
-static int gator_events_ccn504_create_files(struct super_block *sb, struct dentry *root)
-{
- struct dentry *dir;
- int i;
- char buf[32];
-
- for (i = 0; i < CNTMAX; ++i) {
- if (i == CCNT) {
- snprintf(buf, sizeof(buf), "CCN-504_ccnt");
- } else {
- snprintf(buf, sizeof(buf), "CCN-504_cnt%i", i);
- }
- dir = gatorfs_mkdir(sb, root, buf);
- if (!dir) {
- return -1;
- }
-
- gatorfs_create_ulong(sb, dir, "enabled", &gator_events_ccn504_enabled[i]);
- if (i != CCNT) {
- gatorfs_create_ulong(sb, dir, "event", &gator_events_ccn504_event[i]);
- }
- gatorfs_create_ro_ulong(sb, dir, "key", &gator_events_ccn504_key[i]);
- }
-
- return 0;
-}
-
-static void gator_events_ccn504_set_dt_config(int xp_node_id, int event_num, int value)
-{
- u32 dt_config;
-
- dt_config = readl(gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
- dt_config |= (value + event_num) << (4*event_num);
- writel(dt_config, gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
-}
-
-static int gator_events_ccn504_start(void)
-{
- int i;
-
- gator_events_ccn504_global_enabled = 0;
- for (i = 0; i < CNTMAX; ++i) {
- if (gator_events_ccn504_enabled[i]) {
- gator_events_ccn504_global_enabled = 1;
- break;
- }
- }
-
- if (!gator_events_ccn504_global_enabled) {
- return 0;
- }
-
- memset(&gator_events_ccn504_prev, 0x80, sizeof(gator_events_ccn504_prev));
-
- // Disable INTREQ on overflow
- // [6] ovfl_intr_en = 0
- // perhaps set to 1?
- // [5] cntr_rst = 0
- // No register paring
- // [4:1] cntcfg = 0
- // Enable PMU features
- // [0] pmu_en = 1
- writel(0x1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMCR);
-
- // Configure the XPs
- for (i = 0; i < NUM_XPS; ++i) {
- int dt_control;
-
- // Pass on all events
- writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
-
- // Enable PMU capability
- // [0] dt_enable = 1
- dt_control = readl(gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL);
- dt_control |= 0x1;
- writel(dt_control, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL);
- }
-
- // Assume no other pmu_event_sel registers are set
-
- // cycle counter does not need to be enabled
- for (i = 0; i < CCNT; ++i) {
- int pmu_event_id;
- int node_type;
- int region;
- u32 pmu_event_sel;
- u32 oly_id_whole;
- u32 oly_id;
- u32 node_id;
-
- if (!gator_events_ccn504_enabled[i]) {
- continue;
- }
-
- pmu_event_id = get_pmu_event_id(gator_events_ccn504_event[i]);
- node_type = get_node_type(gator_events_ccn504_event[i]);
- region = get_region(gator_events_ccn504_event[i]);
-
- // Verify the node_type
- oly_id_whole = readl(gator_events_ccn504_base + region*REGION_SIZE + OLY_ID);
- oly_id = oly_id_whole & 0x1F;
- node_id = (oly_id_whole >> 8) & 0x7F;
- if ((oly_id != node_type) ||
- ((node_type == 0x16) && ((oly_id != 0x14) && (oly_id != 0x15) && (oly_id != 0x16) && (oly_id != 0x18) && (oly_id != 0x19) && (oly_id != 0x1A)))) {
- printk(KERN_ERR "gator: oly_id is 0x%x expected 0x%x\n", oly_id, node_type);
- return -1;
- }
-
- // Set the control register
- pmu_event_sel = readl(gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
- switch (node_type) {
- case 0x08: // XP
- pmu_event_sel |= pmu_event_id << (7*i);
- gator_events_ccn504_set_dt_config(node_id, i, 0x4);
- break;
- case 0x04: // HN-F
- case 0x16: // RN-I
- case 0x10: // SBAS
- pmu_event_sel |= pmu_event_id << (4*i);
- gator_events_ccn504_set_dt_config(node_id/2, i, (node_id & 1) == 0 ? 0x8 : 0xC);
- break;
- }
- writel(pmu_event_sel, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
- }
-
- return 0;
-}
-
-static void gator_events_ccn504_stop(void)
-{
- int i;
-
- if (!gator_events_ccn504_global_enabled) {
- return;
- }
-
- // cycle counter does not need to be disabled
- for (i = 0; i < CCNT; ++i) {
- int region;
-
- if (!gator_events_ccn504_enabled[i]) {
- continue;
- }
-
- region = get_region(gator_events_ccn504_event[i]);
-
- writel(0, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
- }
-
- // Clear dt_config
- for (i = 0; i < NUM_XPS; ++i) {
- writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
- }
-}
-
-static int gator_events_ccn504_read(int **buffer)
-{
- int i;
- int len = 0;
- int value;
-
- if (!on_primary_core() || !gator_events_ccn504_global_enabled) {
- return 0;
- }
-
- // Verify the pmsr register is zero
- while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0);
-
- // Request a PMU snapshot
- writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_REQ);
-
- // Wait for the snapshot
- while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0);
-
- // Read the shadow registers
- for (i = 0; i < CNTMAX; ++i) {
- if (!gator_events_ccn504_enabled[i]) {
- continue;
- }
-
- value = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i));
- if (gator_events_ccn504_prev[i] != 0x80808080) {
- gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i];
- gator_events_ccn504_buffer[len++] = value - gator_events_ccn504_prev[i];
- }
- gator_events_ccn504_prev[i] = value;
-
- // Are the counters registers cleared when read? Is that what the cntr_rst bit on the pmcr register does?
- }
-
- // Clear the PMU snapshot status
- writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_CLR);
-
- if (buffer)
- *buffer = gator_events_ccn504_buffer;
-
- return len;
-}
-
-static struct gator_interface gator_events_ccn504_interface = {
- .shutdown = gator_events_ccn504_create_shutdown,
- .create_files = gator_events_ccn504_create_files,
- .start = gator_events_ccn504_start,
- .stop = gator_events_ccn504_stop,
- .read = gator_events_ccn504_read,
-};
-
-int gator_events_ccn504_init(void)
-{
- int i;
-
- if (ccn504_addr == 0) {
- return -1;
- }
-
- gator_events_ccn504_base = ioremap(ccn504_addr, NUM_REGIONS*REGION_SIZE);
- if (gator_events_ccn504_base == NULL) {
- printk(KERN_ERR "gator: ioremap returned NULL\n");
- return -1;
- }
-
- for (i = 0; i < CNTMAX; ++i) {
- gator_events_ccn504_enabled[i] = 0;
- gator_events_ccn504_event[i] = 0;
- gator_events_ccn504_key[i] = gator_events_get_key();
- }
-
- return gator_events_install(&gator_events_ccn504_interface);
-}
diff --git a/driver/gator_events_irq.c b/driver/gator_events_irq.c
index facbdd6..5221aac 100644
--- a/driver/gator_events_irq.c
+++ b/driver/gator_events_irq.c
@@ -42,17 +42,15 @@ static int gator_events_irq_create_files(struct super_block *sb, struct dentry *
/* irq */
dir = gatorfs_mkdir(sb, root, "Linux_irq_irq");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &hardirq_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &hardirq_key);
/* soft irq */
dir = gatorfs_mkdir(sb, root, "Linux_irq_softirq");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &softirq_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &softirq_key);
@@ -63,7 +61,7 @@ static int gator_events_irq_online(int **buffer, bool migrate)
{
int len = 0, cpu = get_physical_cpu();
- // synchronization with the irq_exit functions is not necessary as the values are being reset
+ /* synchronization with the irq_exit functions is not necessary as the values are being reset */
if (hardirq_enabled) {
atomic_set(&per_cpu(irqCnt, cpu)[HARDIRQ], 0);
per_cpu(irqGet, cpu)[len++] = hardirq_key;
@@ -84,7 +82,7 @@ static int gator_events_irq_online(int **buffer, bool migrate)
static int gator_events_irq_start(void)
{
- // register tracepoints
+ /* register tracepoints */
if (hardirq_enabled)
if (GATOR_REGISTER_TRACE(irq_handler_exit))
goto fail_hardirq_exit;
@@ -95,7 +93,7 @@ static int gator_events_irq_start(void)
return 0;
- // unregister tracepoints on error
+ /* unregister tracepoints on error */
fail_softirq_exit:
if (hardirq_enabled)
GATOR_UNREGISTER_TRACE(irq_handler_exit);
@@ -117,7 +115,7 @@ static void gator_events_irq_stop(void)
softirq_enabled = 0;
}
-static int gator_events_irq_read(int **buffer)
+static int gator_events_irq_read(int **buffer, bool sched_switch)
{
int len, value;
int cpu = get_physical_cpu();
diff --git a/driver/gator_events_l2c-310.c b/driver/gator_events_l2c-310.c
index 553f970..73aaac3 100644
--- a/driver/gator_events_l2c-310.c
+++ b/driver/gator_events_l2c-310.c
@@ -91,7 +91,7 @@ static void gator_events_l2c310_stop(void)
writel(0, l2c310_base + L2X0_EVENT_CNT_CTRL);
}
-static int gator_events_l2c310_read(int **buffer)
+static int gator_events_l2c310_read(int **buffer, bool sched_switch)
{
static const unsigned long l2x0_event_cntx_val[L2C310_COUNTERS_NUM] = {
L2X0_EVENT_CNT0_VAL,
@@ -149,8 +149,8 @@ static void __iomem *gator_events_l2c310_probe(void)
0xa0412000,
#endif
#if defined(CONFIG_ARCH_VEXPRESS)
- 0x1e00a000, // A9x4 core tile (HBI-0191)
- 0x2c0f0000, // New memory map tiles
+ 0x1e00a000, /* A9x4 core tile (HBI-0191) */
+ 0x2c0f0000, /* New memory map tiles */
#endif
};
int i;
diff --git a/driver/gator_events_mali_4xx.c b/driver/gator_events_mali_4xx.c
index 77712ea..9cf43fe 100644
--- a/driver/gator_events_mali_4xx.c
+++ b/driver/gator_events_mali_4xx.c
@@ -36,7 +36,7 @@
#elif GATOR_MALI_INTERFACE_STYLE == 2
#error GATOR_MALI_INTERFACE_STYLE 2 is obsolete
#elif GATOR_MALI_INTERFACE_STYLE >= 3
-// Valid GATOR_MALI_INTERFACE_STYLE
+/* Valid GATOR_MALI_INTERFACE_STYLE */
#else
#error Unknown GATOR_MALI_INTERFACE_STYLE option.
#endif
@@ -73,8 +73,8 @@ static u32 *counter_address[NUMBER_OF_EVENTS];
/* An array used to return the data we recorded
* as key,value pairs hence the *2
*/
-static unsigned long counter_dump[NUMBER_OF_EVENTS * 2];
-static unsigned long counter_prev[NUMBER_OF_EVENTS];
+static int counter_dump[NUMBER_OF_EVENTS * 2];
+static int counter_prev[NUMBER_OF_EVENTS];
static bool prev_set[NUMBER_OF_EVENTS];
/* Note whether tracepoints have been registered */
@@ -89,8 +89,8 @@ static unsigned int n_vp_cores = MAX_NUM_VP_CORES;
static unsigned int n_l2_cores = MAX_NUM_L2_CACHE_CORES;
static unsigned int n_fp_cores = MAX_NUM_FP_CORES;
-extern mali_counter mali_activity[2];
-static const char* const mali_activity_names[] = {
+extern struct mali_counter mali_activity[2];
+static const char *const mali_activity_names[] = {
"fragment",
"vertex",
};
@@ -112,36 +112,11 @@ static inline int is_hw_counter(unsigned int event_id)
return (event_id >= FIRST_HW_COUNTER && event_id <= LAST_HW_COUNTER);
}
-/*
- * These are provided for utgard compatibility.
- */
-typedef void _mali_profiling_get_mali_version_type(struct _mali_profiling_mali_version *values);
-typedef u32 _mali_profiling_get_l2_counters_type(_mali_profiling_l2_counter_values *values);
-
-/* Probe for continuously sampled counter */
-#if 0 //WE_DONT_CURRENTLY_USE_THIS_SO_SUPPRESS_WARNING
-GATOR_DEFINE_PROBE(mali_sample_address, TP_PROTO(unsigned int event_id, u32 *addr))
-{
- /* Turning on too many pr_debug statements in frequently called functions
- * can cause stability and/or performance problems
- */
- //pr_debug("gator: mali_sample_address %d %d\n", event_id, addr);
- if (event_id >= ACTIVITY_VP && event_id <= COUNTER_FP3_C1) {
- counter_address[event_id] = addr;
- }
-}
-#endif
-
/* Probe for hardware counter events */
GATOR_DEFINE_PROBE(mali_hw_counter, TP_PROTO(unsigned int event_id, unsigned int value))
{
- /* Turning on too many pr_debug statements in frequently called functions
- * can cause stability and/or performance problems
- */
- //pr_debug("gator: mali_hw_counter %d %d\n", event_id, value);
- if (is_hw_counter(event_id)) {
+ if (is_hw_counter(event_id))
counter_data[event_id] = value;
- }
}
GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surface_id, unsigned int *counters))
@@ -150,9 +125,8 @@ GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surfac
/* Copy over the values for those counters which are enabled. */
for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++) {
- if (counter_enabled[i]) {
+ if (counter_enabled[i])
counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]);
- }
}
}
@@ -172,13 +146,11 @@ static int create_fs_entry(struct super_block *sb, struct dentry *root, const ch
dir = gatorfs_mkdir(sb, root, name);
- if (!dir) {
+ if (!dir)
return -1;
- }
- if (create_event_item) {
+ if (create_event_item)
gatorfs_create_ulong(sb, dir, "event", &counter_event[event]);
- }
gatorfs_create_ulong(sb, dir, "enabled", &counter_enabled[event]);
gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]);
@@ -192,7 +164,7 @@ static int create_fs_entry(struct super_block *sb, struct dentry *root, const ch
*/
static void initialise_version_info(void)
{
- _mali_profiling_get_mali_version_type *mali_profiling_get_mali_version_symbol;
+ void (*mali_profiling_get_mali_version_symbol)(struct _mali_profiling_mali_version *values);
mali_profiling_get_mali_version_symbol = symbol_get(_mali_profiling_get_mali_version);
@@ -214,8 +186,8 @@ static void initialise_version_info(void)
/* Release the function - we're done with it. */
symbol_put(_mali_profiling_get_mali_version);
} else {
- printk("gator: mali online _mali_profiling_get_mali_version symbol not found\n");
- printk("gator: check your Mali DDK version versus the GATOR_MALI_INTERFACE_STYLE setting\n");
+ pr_err("gator: mali online _mali_profiling_get_mali_version symbol not found\n");
+ pr_err("gator: check your Mali DDK version versus the GATOR_MALI_INTERFACE_STYLE setting\n");
}
}
#endif
@@ -242,26 +214,24 @@ static int create_files(struct super_block *sb, struct dentry *root)
mali_activity[0].cores = n_fp_cores;
mali_activity[1].cores = n_vp_cores;
for (event = 0; event < ARRAY_SIZE(mali_activity); event++) {
- if (gator_mali_create_file_system(mali_name, mali_activity_names[event], sb, root, &mali_activity[event], NULL) != 0) {
+ if (gator_mali_create_file_system(mali_name, mali_activity_names[event], sb, root, &mali_activity[event], NULL) != 0)
return -1;
- }
}
/* Vertex processor counters */
for (core_id = 0; core_id < n_vp_cores; core_id++) {
int activity_counter_id = ACTIVITY_VP_0;
- snprintf(buf, sizeof buf, "ARM_Mali-%s_VP_%d_active", mali_name, core_id);
- if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) {
+
+ snprintf(buf, sizeof(buf), "ARM_Mali-%s_VP_%d_active", mali_name, core_id);
+ if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0)
return -1;
- }
for (counter_number = 0; counter_number < 2; counter_number++) {
int counter_id = COUNTER_VP_0_C0 + (2 * core_id) + counter_number;
- snprintf(buf, sizeof buf, "ARM_Mali-%s_VP_%d_cnt%d", mali_name, core_id, counter_number);
- if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
+ snprintf(buf, sizeof(buf), "ARM_Mali-%s_VP_%d_cnt%d", mali_name, core_id, counter_number);
+ if (create_fs_entry(sb, root, buf, counter_id, 1) != 0)
return -1;
- }
}
}
@@ -269,18 +239,16 @@ static int create_files(struct super_block *sb, struct dentry *root)
for (core_id = 0; core_id < n_fp_cores; core_id++) {
int activity_counter_id = ACTIVITY_FP_0 + core_id;
- snprintf(buf, sizeof buf, "ARM_Mali-%s_FP_%d_active", mali_name, core_id);
- if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) {
+ snprintf(buf, sizeof(buf), "ARM_Mali-%s_FP_%d_active", mali_name, core_id);
+ if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0)
return -1;
- }
for (counter_number = 0; counter_number < 2; counter_number++) {
int counter_id = COUNTER_FP_0_C0 + (2 * core_id) + counter_number;
- snprintf(buf, sizeof buf, "ARM_Mali-%s_FP_%d_cnt%d", mali_name, core_id, counter_number);
- if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
+ snprintf(buf, sizeof(buf), "ARM_Mali-%s_FP_%d_cnt%d", mali_name, core_id, counter_number);
+ if (create_fs_entry(sb, root, buf, counter_id, 1) != 0)
return -1;
- }
}
}
@@ -289,10 +257,9 @@ static int create_files(struct super_block *sb, struct dentry *root)
for (counter_number = 0; counter_number < 2; counter_number++) {
int counter_id = COUNTER_L2_0_C0 + (2 * core_id) + counter_number;
- snprintf(buf, sizeof buf, "ARM_Mali-%s_L2_%d_cnt%d", mali_name, core_id, counter_number);
- if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
+ snprintf(buf, sizeof(buf), "ARM_Mali-%s_L2_%d_cnt%d", mali_name, core_id, counter_number);
+ if (create_fs_entry(sb, root, buf, counter_id, 1) != 0)
return -1;
- }
}
}
@@ -300,27 +267,23 @@ static int create_files(struct super_block *sb, struct dentry *root)
for (event = FIRST_SW_COUNTER; event <= LAST_SW_COUNTER; event++) {
snprintf(buf, sizeof(buf), "ARM_Mali-%s_SW_%d", mali_name, event - FIRST_SW_COUNTER);
- if (create_fs_entry(sb, root, buf, event, 0) != 0) {
+ if (create_fs_entry(sb, root, buf, event, 0) != 0)
return -1;
- }
}
/* Now set up the special counter entries */
snprintf(buf, sizeof(buf), "ARM_Mali-%s_Filmstrip_cnt0", mali_name);
- if (create_fs_entry(sb, root, buf, COUNTER_FILMSTRIP, 1) != 0) {
+ if (create_fs_entry(sb, root, buf, COUNTER_FILMSTRIP, 1) != 0)
return -1;
- }
#ifdef DVFS_REPORTED_BY_DDK
snprintf(buf, sizeof(buf), "ARM_Mali-%s_Frequency", mali_name);
- if (create_fs_entry(sb, root, buf, COUNTER_FREQUENCY, 1) != 0) {
+ if (create_fs_entry(sb, root, buf, COUNTER_FREQUENCY, 1) != 0)
return -1;
- }
snprintf(buf, sizeof(buf), "ARM_Mali-%s_Voltage", mali_name);
- if (create_fs_entry(sb, root, buf, COUNTER_VOLTAGE, 1) != 0) {
+ if (create_fs_entry(sb, root, buf, COUNTER_VOLTAGE, 1) != 0)
return -1;
- }
#endif
return 0;
@@ -330,8 +293,8 @@ static int create_files(struct super_block *sb, struct dentry *root)
* Local store for the get_counters entry point into the DDK.
* This is stored here since it is used very regularly.
*/
-static mali_profiling_get_counters_type *mali_get_counters = NULL;
-static _mali_profiling_get_l2_counters_type *mali_get_l2_counters = NULL;
+static void (*mali_get_counters)(unsigned int *, unsigned int *, unsigned int *, unsigned int *);
+static u32 (*mali_get_l2_counters)(struct _mali_profiling_l2_counter_values *values);
/*
* Examine list of counters between two index limits and determine if any one is enabled.
@@ -342,9 +305,8 @@ static int is_any_counter_enabled(unsigned int first_counter, unsigned int last_
unsigned int i;
for (i = first_counter; i <= last_counter; i++) {
- if (counter_enabled[i]) {
+ if (counter_enabled[i])
return 1; /* At least one counter is enabled */
- }
}
return 0; /* No s/w counters enabled */
@@ -366,16 +328,15 @@ static void init_counters(unsigned int from_counter, unsigned int to_counter)
pr_debug("gator: mali online _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event);
for (counter_id = from_counter; counter_id <= to_counter; counter_id++) {
- if (counter_enabled[counter_id]) {
+ if (counter_enabled[counter_id])
mali_set_hw_event(counter_id, counter_event[counter_id]);
- } else {
+ else
mali_set_hw_event(counter_id, 0xFFFFFFFF);
- }
}
symbol_put(_mali_profiling_set_event);
} else {
- printk("gator: mali online _mali_profiling_set_event symbol not found\n");
+ pr_err("gator: mali online _mali_profiling_set_event symbol not found\n");
}
}
@@ -407,27 +368,23 @@ static void mali_counter_initialize(void)
symbol_put(_mali_profiling_control);
} else {
- printk("gator: mali online _mali_profiling_control symbol not found\n");
+ pr_err("gator: mali online _mali_profiling_control symbol not found\n");
}
mali_get_counters = symbol_get(_mali_profiling_get_counters);
- if (mali_get_counters) {
+ if (mali_get_counters)
pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", mali_get_counters);
-
- } else {
- pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined");
- }
+ else
+ pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined\n");
mali_get_l2_counters = symbol_get(_mali_profiling_get_l2_counters);
- if (mali_get_l2_counters) {
+ if (mali_get_l2_counters)
pr_debug("gator: mali online _mali_profiling_get_l2_counters symbol @ %p\n", mali_get_l2_counters);
-
- } else {
- pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined");
- }
+ else
+ pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined\n");
if (!mali_get_counters && !mali_get_l2_counters) {
- pr_debug("gator: WARNING: no L2 counters available");
+ pr_debug("gator: WARNING: no L2 counters available\n");
n_l2_cores = 0;
}
@@ -449,13 +406,12 @@ static void mali_counter_deinitialize(void)
int i;
pr_debug("gator: mali offline _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event);
- for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++) {
+ for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++)
mali_set_hw_event(i, 0xFFFFFFFF);
- }
symbol_put(_mali_profiling_set_event);
} else {
- printk("gator: mali offline _mali_profiling_set_event symbol not found\n");
+ pr_err("gator: mali offline _mali_profiling_set_event symbol not found\n");
}
/* Generic control interface for Mali DDK. */
@@ -471,29 +427,27 @@ static void mali_counter_deinitialize(void)
symbol_put(_mali_profiling_control);
} else {
- printk("gator: mali offline _mali_profiling_control symbol not found\n");
+ pr_err("gator: mali offline _mali_profiling_control symbol not found\n");
}
- if (mali_get_counters) {
+ if (mali_get_counters)
symbol_put(_mali_profiling_get_counters);
- }
- if (mali_get_l2_counters) {
+ if (mali_get_l2_counters)
symbol_put(_mali_profiling_get_l2_counters);
- }
}
static int start(void)
{
- // register tracepoints
+ /* register tracepoints */
if (GATOR_REGISTER_TRACE(mali_hw_counter)) {
- printk("gator: mali_hw_counter tracepoint failed to activate\n");
+ pr_err("gator: mali_hw_counter tracepoint failed to activate\n");
return -1;
}
/* For Mali drivers with built-in support. */
if (GATOR_REGISTER_TRACE(mali_sw_counters)) {
- printk("gator: mali_sw_counters tracepoint failed to activate\n");
+ pr_err("gator: mali_sw_counters tracepoint failed to activate\n");
return -1;
}
@@ -543,17 +497,17 @@ static void dump_counters(unsigned int from_counter, unsigned int to_counter, un
}
}
-static int read(int **buffer)
+static int read(int **buffer, bool sched_switch)
{
int len = 0;
if (!on_primary_core())
return 0;
- // Read the L2 C0 and C1 here.
+ /* Read the L2 C0 and C1 here. */
if (n_l2_cores > 0 && is_any_counter_enabled(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores))) {
unsigned int unavailable_l2_caches = 0;
- _mali_profiling_l2_counter_values cache_values;
+ struct _mali_profiling_l2_counter_values cache_values;
unsigned int cache_id;
struct _mali_profiling_core_counters *per_core;
@@ -572,25 +526,24 @@ static int read(int **buffer)
unsigned int counter_id_0 = COUNTER_L2_0_C0 + (2 * cache_id);
unsigned int counter_id_1 = counter_id_0 + 1;
- if ((1 << cache_id) & unavailable_l2_caches) {
+ if ((1 << cache_id) & unavailable_l2_caches)
continue; /* This cache is unavailable (powered-off, possibly). */
- }
per_core = &cache_values.cores[cache_id];
if (counter_enabled[counter_id_0] && prev_set[counter_id_0]) {
- // Calculate and save src0's counter val0
+ /* Calculate and save src0's counter val0 */
counter_dump[len++] = counter_key[counter_id_0];
counter_dump[len++] = per_core->value0 - counter_prev[counter_id_0];
}
if (counter_enabled[counter_id_1] && prev_set[counter_id_1]) {
- // Calculate and save src1's counter val1
+ /* Calculate and save src1's counter val1 */
counter_dump[len++] = counter_key[counter_id_1];
counter_dump[len++] = per_core->value1 - counter_prev[counter_id_1];
}
- // Save the previous values for the counters.
+ /* Save the previous values for the counters. */
counter_prev[counter_id_0] = per_core->value0;
prev_set[counter_id_0] = true;
counter_prev[counter_id_1] = per_core->value1;
@@ -608,8 +561,9 @@ static int read(int **buffer)
{
int cnt;
/*
- * Add in the voltage and frequency counters if enabled. Note that, since these are
- * actually passed as events, the counter value should not be cleared.
+ * Add in the voltage and frequency counters if enabled. Note
+ * that, since these are actually passed as events, the counter
+ * value should not be cleared.
*/
cnt = COUNTER_FREQUENCY;
if (counter_enabled[cnt]) {
@@ -625,9 +579,8 @@ static int read(int **buffer)
}
#endif
- if (buffer) {
- *buffer = (int *)counter_dump;
- }
+ if (buffer)
+ *buffer = counter_dump;
return len;
}
diff --git a/driver/gator_events_mali_common.c b/driver/gator_events_mali_common.c
index c3d0503..1af87d6 100644
--- a/driver/gator_events_mali_common.c
+++ b/driver/gator_events_mali_common.c
@@ -8,7 +8,7 @@
*/
#include "gator_events_mali_common.h"
-extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event)
+extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, struct mali_counter *counter, unsigned long *event)
{
int err;
char buf[255];
@@ -17,40 +17,39 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even
/* If the counter name is empty ignore it */
if (strlen(event_name) != 0) {
/* Set up the filesystem entry for this event. */
- if (mali_name == NULL) {
+ if (mali_name == NULL)
snprintf(buf, sizeof(buf), "ARM_Mali-%s", event_name);
- } else {
+ else
snprintf(buf, sizeof(buf), "ARM_Mali-%s_%s", mali_name, event_name);
- }
dir = gatorfs_mkdir(sb, root, buf);
if (dir == NULL) {
- pr_debug("gator: %s: error creating file system for: %s (%s)", mali_name, event_name, buf);
+ pr_debug("gator: %s: error creating file system for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
err = gatorfs_create_ulong(sb, dir, "enabled", &counter->enabled);
if (err != 0) {
- pr_debug("gator: %s: error calling gatorfs_create_ulong for: %s (%s)", mali_name, event_name, buf);
+ pr_debug("gator: %s: error calling gatorfs_create_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
err = gatorfs_create_ro_ulong(sb, dir, "key", &counter->key);
if (err != 0) {
- pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)", mali_name, event_name, buf);
+ pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
if (counter->cores != -1) {
err = gatorfs_create_ro_ulong(sb, dir, "cores", &counter->cores);
if (err != 0) {
- pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)", mali_name, event_name, buf);
+ pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
}
if (event != NULL) {
err = gatorfs_create_ulong(sb, dir, "event", event);
if (err != 0) {
- pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)", mali_name, event_name, buf);
+ pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
}
@@ -59,12 +58,12 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even
return 0;
}
-extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters)
+extern void gator_mali_initialise_counters(struct mali_counter counters[], unsigned int n_counters)
{
unsigned int cnt;
for (cnt = 0; cnt < n_counters; cnt++) {
- mali_counter *counter = &counters[cnt];
+ struct mali_counter *counter = &counters[cnt];
counter->key = gator_events_get_key();
counter->enabled = 0;
diff --git a/driver/gator_events_mali_common.h b/driver/gator_events_mali_common.h
index 91d871b..e7082e6 100644
--- a/driver/gator_events_mali_common.h
+++ b/driver/gator_events_mali_common.h
@@ -16,7 +16,7 @@
#include <linux/time.h>
#include <linux/math64.h>
#include <linux/slab.h>
-#include <asm/io.h>
+#include <linux/io.h>
/* Ensure that MALI_SUPPORT has been defined to something. */
#ifndef MALI_SUPPORT
@@ -30,21 +30,20 @@
/*
* Runtime state information for a counter.
*/
-typedef struct {
- // 'key' (a unique id set by gatord and returned by gator.ko)
+struct mali_counter {
+ /* 'key' (a unique id set by gatord and returned by gator.ko) */
unsigned long key;
- // counter enable state
+ /* counter enable state */
unsigned long enabled;
- // for activity counters, the number of cores, otherwise -1
+ /* for activity counters, the number of cores, otherwise -1 */
unsigned long cores;
-} mali_counter;
+};
/*
* Mali-4xx
*/
typedef int mali_profiling_set_event_type(unsigned int, int);
typedef void mali_profiling_control_type(unsigned int, unsigned int);
-typedef void mali_profiling_get_counters_type(unsigned int *, unsigned int *, unsigned int *, unsigned int *);
/*
* Driver entry points for functions called directly by gator.
@@ -65,7 +64,7 @@ extern void _mali_profiling_get_counters(unsigned int *, unsigned int *, unsigne
*
* @return 0 if entry point was created, non-zero if not.
*/
-extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event);
+extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, struct mali_counter *counter, unsigned long *event);
/**
* Initializes the counter array.
@@ -73,6 +72,6 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even
* @param keys The array of counters
* @param n_counters The number of entries in each of the arrays.
*/
-extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters);
+extern void gator_mali_initialise_counters(struct mali_counter counters[], unsigned int n_counters);
#endif /* GATOR_EVENTS_MALI_COMMON_H */
diff --git a/driver/gator_events_mali_midgard.c b/driver/gator_events_mali_midgard.c
index ab0584c..0aec906 100644
--- a/driver/gator_events_mali_midgard.c
+++ b/driver/gator_events_mali_midgard.c
@@ -13,7 +13,7 @@
#include <linux/time.h>
#include <linux/math64.h>
#include <linux/slab.h>
-#include <asm/io.h>
+#include <linux/io.h>
#ifdef MALI_DIR_MIDGARD
/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
@@ -49,7 +49,7 @@ static const char mali_name[] = "Midgard";
*/
/* Timeline (start/stop) activity */
-static const char *timeline_event_names[] = {
+static const char *const timeline_event_names[] = {
"PM_SHADER_0",
"PM_SHADER_1",
"PM_SHADER_2",
@@ -88,7 +88,7 @@ enum {
#define NUM_PM_SHADER (8)
/* Software Counters */
-static const char *software_counter_names[] = {
+static const char *const software_counter_names[] = {
"MMU_PAGE_FAULT_0",
"MMU_PAGE_FAULT_1",
"MMU_PAGE_FAULT_2",
@@ -103,7 +103,7 @@ enum {
};
/* Software Counters */
-static const char *accumulators_names[] = {
+static const char *const accumulators_names[] = {
"TOTAL_ALLOC_PAGES"
};
@@ -123,17 +123,18 @@ enum {
/*
* gatorfs variables for counter enable state
*/
-static mali_counter counters[NUMBER_OF_EVENTS];
+static struct mali_counter counters[NUMBER_OF_EVENTS];
static unsigned long filmstrip_event;
/* An array used to return the data we recorded
* as key,value pairs hence the *2
*/
-static unsigned long counter_dump[NUMBER_OF_EVENTS * 2];
+static int counter_dump[NUMBER_OF_EVENTS * 2];
/*
- * Array holding counter start times (in ns) for each counter. A zero here
- * indicates that the activity monitored by this counter is not running.
+ * Array holding counter start times (in ns) for each counter. A zero
+ * here indicates that the activity monitored by this counter is not
+ * running.
*/
static struct timespec timeline_event_starttime[NUMBER_OF_TIMELINE_EVENTS];
@@ -156,6 +157,7 @@ static struct timespec prev_timestamp;
static inline long get_duration_us(const struct timespec *start, const struct timespec *end)
{
long event_duration_us = (end->tv_nsec - start->tv_nsec) / 1000;
+
event_duration_us += (end->tv_sec - start->tv_sec) * 1000000;
return event_duration_us;
@@ -172,9 +174,8 @@ static void record_timeline_event(unsigned int timeline_index, unsigned int type
getnstimeofday(&event_timestamp);
/* Remember the start time if the activity is not already started */
- if (event_start->tv_sec == 0) {
+ if (event_start->tv_sec == 0)
*event_start = event_timestamp; /* Structure copy */
- }
break;
case ACTIVITY_STOP:
@@ -208,9 +209,9 @@ GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long
#define L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */
#define BIT_AT(value, pos) ((value >> pos) & 1)
- static unsigned long long previous_shader_bitmask = 0;
- static unsigned long long previous_tiler_bitmask = 0;
- static unsigned long long previous_l2_bitmask = 0;
+ static unsigned long long previous_shader_bitmask;
+ static unsigned long long previous_tiler_bitmask;
+ static unsigned long long previous_l2_bitmask;
switch (event_id) {
case SHADER_PRESENT_LO:
@@ -219,9 +220,8 @@ GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long
int pos;
for (pos = 0; pos < NUM_PM_SHADER; ++pos) {
- if (BIT_AT(changed_bitmask, pos)) {
+ if (BIT_AT(changed_bitmask, pos))
record_timeline_event(PM_SHADER_0 + pos, BIT_AT(value, pos) ? ACTIVITY_START : ACTIVITY_STOP);
- }
}
previous_shader_bitmask = value;
@@ -232,9 +232,8 @@ GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long
{
unsigned long long changed = previous_tiler_bitmask ^ value;
- if (BIT_AT(changed, 0)) {
+ if (BIT_AT(changed, 0))
record_timeline_event(PM_TILER_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
- }
previous_tiler_bitmask = value;
break;
@@ -244,12 +243,10 @@ GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long
{
unsigned long long changed = previous_l2_bitmask ^ value;
- if (BIT_AT(changed, 0)) {
+ if (BIT_AT(changed, 0))
record_timeline_event(PM_L2_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
- }
- if (BIT_AT(changed, 4)) {
+ if (BIT_AT(changed, 4))
record_timeline_event(PM_L2_1, BIT_AT(value, 4) ? ACTIVITY_START : ACTIVITY_STOP);
- }
previous_l2_bitmask = value;
break;
@@ -297,31 +294,27 @@ static int create_files(struct super_block *sb, struct dentry *root)
mali_profiling_control_type *mali_control;
for (event = FIRST_TIMELINE_EVENT; event < FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS; event++) {
- if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event], NULL) != 0) {
+ if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event], NULL) != 0)
return -1;
- }
counter_index++;
}
counter_index = 0;
for (event = FIRST_SOFTWARE_COUNTER; event < FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS; event++) {
- if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event], NULL) != 0) {
+ if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event], NULL) != 0)
return -1;
- }
counter_index++;
}
counter_index = 0;
for (event = FIRST_ACCUMULATOR; event < FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS; event++) {
- if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event], NULL) != 0) {
+ if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event], NULL) != 0)
return -1;
- }
counter_index++;
}
mali_control = symbol_get(_mali_profiling_control);
if (mali_control) {
- if (gator_mali_create_file_system(mali_name, "Filmstrip_cnt0", sb, root, &counters[FILMSTRIP], &filmstrip_event) != 0) {
+ if (gator_mali_create_file_system(mali_name, "Filmstrip_cnt0", sb, root, &counters[FILMSTRIP], &filmstrip_event) != 0)
return -1;
- }
symbol_put(_mali_profiling_control);
}
@@ -376,18 +369,15 @@ static int start(void)
timeline_data[cnt] = 0;
}
- for (cnt = 0; cnt < NUMBER_OF_SOFTWARE_COUNTERS; cnt++) {
+ for (cnt = 0; cnt < NUMBER_OF_SOFTWARE_COUNTERS; cnt++)
sw_counter_data[cnt] = 0;
- }
- for (cnt = 0; cnt < NUMBER_OF_ACCUMULATORS; cnt++) {
+ for (cnt = 0; cnt < NUMBER_OF_ACCUMULATORS; cnt++)
accumulators_data[cnt] = 0;
- }
/* Register tracepoints */
- if (register_tracepoints() == 0) {
+ if (register_tracepoints() == 0)
return -1;
- }
/* Generic control interface for Mali DDK. */
mali_control = symbol_get(_mali_profiling_control);
@@ -410,7 +400,7 @@ static int start(void)
symbol_put(_mali_profiling_control);
} else {
- printk("gator: mali online _mali_profiling_control symbol not found\n");
+ pr_err("gator: mali online _mali_profiling_control symbol not found\n");
}
/*
@@ -457,20 +447,19 @@ static void stop(void)
symbol_put(_mali_profiling_control);
} else {
- printk("gator: mali offline _mali_profiling_control symbol not found\n");
+ pr_err("gator: mali offline _mali_profiling_control symbol not found\n");
}
}
-static int read(int **buffer)
+static int read(int **buffer, bool sched_switch)
{
int cnt;
int len = 0;
long sample_interval_us = 0;
struct timespec read_timestamp;
- if (!on_primary_core()) {
+ if (!on_primary_core())
return 0;
- }
/* Get the start of this sample period. */
getnstimeofday(&read_timestamp);
@@ -479,9 +468,8 @@ static int read(int **buffer)
* Calculate the sample interval if the previous sample time is valid.
* We use tv_sec since it will not be 0.
*/
- if (prev_timestamp.tv_sec != 0) {
+ if (prev_timestamp.tv_sec != 0)
sample_interval_us = get_duration_us(&prev_timestamp, &read_timestamp);
- }
/* Structure copy. Update the previous timestamp. */
prev_timestamp = read_timestamp;
@@ -490,15 +478,19 @@ static int read(int **buffer)
* Report the timeline counters (ACTIVITY_START/STOP)
*/
for (cnt = FIRST_TIMELINE_EVENT; cnt < (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS); cnt++) {
- mali_counter *counter = &counters[cnt];
+ struct mali_counter *counter = &counters[cnt];
+
if (counter->enabled) {
const int index = cnt - FIRST_TIMELINE_EVENT;
unsigned int value;
- /* If the activity is still running, reset its start time to the start of this sample period
- * to correct the count. Add the time up to the end of the sample onto the count. */
+ /* If the activity is still running, reset its start time to the
+ * start of this sample period to correct the count. Add the
+ * time up to the end of the sample onto the count.
+ */
if (timeline_event_starttime[index].tv_sec != 0) {
const long event_duration = get_duration_us(&timeline_event_starttime[index], &read_timestamp);
+
timeline_data[index] += event_duration;
timeline_event_starttime[index] = read_timestamp; /* Activity is still running. */
}
@@ -521,9 +513,11 @@ static int read(int **buffer)
/* Report the software counters */
for (cnt = FIRST_SOFTWARE_COUNTER; cnt < (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS); cnt++) {
- const mali_counter *counter = &counters[cnt];
+ const struct mali_counter *counter = &counters[cnt];
+
if (counter->enabled) {
const int index = cnt - FIRST_SOFTWARE_COUNTER;
+
counter_dump[len++] = counter->key;
counter_dump[len++] = sw_counter_data[index];
/* Set the value to zero for the next time */
@@ -533,9 +527,11 @@ static int read(int **buffer)
/* Report the accumulators */
for (cnt = FIRST_ACCUMULATOR; cnt < (FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS); cnt++) {
- const mali_counter *counter = &counters[cnt];
+ const struct mali_counter *counter = &counters[cnt];
+
if (counter->enabled) {
const int index = cnt - FIRST_ACCUMULATOR;
+
counter_dump[len++] = counter->key;
counter_dump[len++] = accumulators_data[index];
/* Do not zero the accumulator */
@@ -543,9 +539,8 @@ static int read(int **buffer)
}
/* Update the buffer */
- if (buffer) {
- *buffer = (int *)counter_dump;
- }
+ if (buffer)
+ *buffer = counter_dump;
return len;
}
diff --git a/driver/gator_events_mali_midgard_hw.c b/driver/gator_events_mali_midgard_hw.c
index fe6d889..c8065da 100644
--- a/driver/gator_events_mali_midgard_hw.c
+++ b/driver/gator_events_mali_midgard_hw.c
@@ -13,7 +13,7 @@
#include <linux/time.h>
#include <linux/math64.h>
#include <linux/slab.h>
-#include <asm/io.h>
+#include <linux/io.h>
/* Mali Midgard DDK includes */
#if defined(MALI_SIMPLE_API)
@@ -46,62 +46,46 @@
* Mali-Midgard
*/
#if MALI_DDK_GATOR_API_VERSION == 3
-typedef uint32_t kbase_gator_instr_hwcnt_dump_irq_type(struct kbase_gator_hwcnt_handles *);
-typedef uint32_t kbase_gator_instr_hwcnt_dump_complete_type(struct kbase_gator_hwcnt_handles *, uint32_t *const);
-typedef struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init_type(struct kbase_gator_hwcnt_info *);
-typedef void kbase_gator_hwcnt_term_type(struct kbase_gator_hwcnt_info *, struct kbase_gator_hwcnt_handles *);
-typedef const char *const *kbase_gator_hwcnt_init_names_type(uint32_t *);
-typedef void kbase_gator_hwcnt_term_names_type(void);
-
-static kbase_gator_instr_hwcnt_dump_irq_type *kbase_gator_instr_hwcnt_dump_irq_symbol;
-static kbase_gator_instr_hwcnt_dump_complete_type *kbase_gator_instr_hwcnt_dump_complete_symbol;
-static kbase_gator_hwcnt_init_type *kbase_gator_hwcnt_init_symbol;
-static kbase_gator_hwcnt_term_type *kbase_gator_hwcnt_term_symbol;
+static uint32_t (*kbase_gator_instr_hwcnt_dump_irq_symbol)(struct kbase_gator_hwcnt_handles *);
+static uint32_t (*kbase_gator_instr_hwcnt_dump_complete_symbol)(struct kbase_gator_hwcnt_handles *, uint32_t *const);
+static struct kbase_gator_hwcnt_handles *(*kbase_gator_hwcnt_init_symbol)(struct kbase_gator_hwcnt_info *);
+static void (*kbase_gator_hwcnt_term_symbol)(struct kbase_gator_hwcnt_info *, struct kbase_gator_hwcnt_handles *);
#else
-typedef struct kbase_device *kbase_find_device_type(int);
-typedef struct kbase_context *kbase_create_context_type(struct kbase_device *);
-typedef void kbase_destroy_context_type(struct kbase_context *);
+static struct kbase_device *(*kbase_find_device_symbol)(int);
+static struct kbase_context *(*kbase_create_context_symbol)(struct kbase_device *);
+static void (*kbase_destroy_context_symbol)(struct kbase_context *);
#if MALI_DDK_GATOR_API_VERSION == 1
-typedef void *kbase_va_alloc_type(struct kbase_context *, u32);
-typedef void kbase_va_free_type(struct kbase_context *, void *);
+static void *(*kbase_va_alloc_symbol)(struct kbase_context *, u32);
+static void (*kbase_va_free_symbol)(struct kbase_context *, void *);
#elif MALI_DDK_GATOR_API_VERSION == 2
-typedef void *kbase_va_alloc_type(struct kbase_context *, u32, struct kbase_hwc_dma_mapping *);
-typedef void kbase_va_free_type(struct kbase_context *, struct kbase_hwc_dma_mapping *);
+static void *(*kbase_va_alloc_symbol)(struct kbase_context *, u32, struct kbase_hwc_dma_mapping *);
+static void (*kbase_va_free_symbol)(struct kbase_context *, struct kbase_hwc_dma_mapping *);
#endif
-typedef mali_error kbase_instr_hwcnt_enable_type(struct kbase_context *, struct kbase_uk_hwcnt_setup *);
-typedef mali_error kbase_instr_hwcnt_disable_type(struct kbase_context *);
-typedef mali_error kbase_instr_hwcnt_clear_type(struct kbase_context *);
-typedef mali_error kbase_instr_hwcnt_dump_irq_type(struct kbase_context *);
-typedef mali_bool kbase_instr_hwcnt_dump_complete_type(struct kbase_context *, mali_bool *);
-
-static kbase_find_device_type *kbase_find_device_symbol;
-static kbase_create_context_type *kbase_create_context_symbol;
-static kbase_va_alloc_type *kbase_va_alloc_symbol;
-static kbase_instr_hwcnt_enable_type *kbase_instr_hwcnt_enable_symbol;
-static kbase_instr_hwcnt_clear_type *kbase_instr_hwcnt_clear_symbol;
-static kbase_instr_hwcnt_dump_irq_type *kbase_instr_hwcnt_dump_irq_symbol;
-static kbase_instr_hwcnt_dump_complete_type *kbase_instr_hwcnt_dump_complete_symbol;
-static kbase_instr_hwcnt_disable_type *kbase_instr_hwcnt_disable_symbol;
-static kbase_va_free_type *kbase_va_free_symbol;
-static kbase_destroy_context_type *kbase_destroy_context_symbol;
-
-static long shader_present_low = 0;
+static mali_error (*kbase_instr_hwcnt_enable_symbol)(struct kbase_context *, struct kbase_uk_hwcnt_setup *);
+static mali_error (*kbase_instr_hwcnt_disable_symbol)(struct kbase_context *);
+static mali_error (*kbase_instr_hwcnt_clear_symbol)(struct kbase_context *);
+static mali_error (*kbase_instr_hwcnt_dump_irq_symbol)(struct kbase_context *);
+static mali_bool (*kbase_instr_hwcnt_dump_complete_symbol)(struct kbase_context *, mali_bool *);
+
+static long shader_present_low;
#endif
/** The interval between reads, in ns.
*
- * Earlier we introduced
- * a 'hold off for 1ms after last read' to resolve MIDBASE-2178 and MALINE-724.
- * However, the 1ms hold off is too long if no context switches occur as there is a race
- * between this value and the tick of the read clock in gator which is also 1ms. If we 'miss' the
- * current read, the counter values are effectively 'spread' over 2ms and the values seen are half
- * what they should be (since Streamline averages over sample time). In the presence of context switches
- * this spread can vary and markedly affect the counters. Currently there is no 'proper' solution to
- * this, but empirically we have found that reducing the minimum read interval to 950us causes the
- * counts to be much more stable.
+ * Earlier we introduced a 'hold off for 1ms after last read' to
+ * resolve MIDBASE-2178 and MALINE-724. However, the 1ms hold off is
+ * too long if no context switches occur as there is a race between
+ * this value and the tick of the read clock in gator which is also
+ * 1ms. If we 'miss' the current read, the counter values are
+ * effectively 'spread' over 2ms and the values seen are half what
+ * they should be (since Streamline averages over sample time). In the
+ * presence of context switches this spread can vary and markedly
+ * affect the counters. Currently there is no 'proper' solution to
+ * this, but empirically we have found that reducing the minimum read
+ * interval to 950us causes the counts to be much more stable.
*/
static const int READ_INTERVAL_NSEC = 950000;
@@ -428,26 +412,26 @@ struct kbase_hwc_dma_mapping kernel_dump_buffer_handle;
#endif
/* kbase context and device */
-static struct kbase_context *kbcontext = NULL;
-static struct kbase_device *kbdevice = NULL;
+static struct kbase_context *kbcontext;
+static struct kbase_device *kbdevice;
/*
- * The following function has no external prototype in older DDK revisions. When the DDK
- * is updated then this should be removed.
+ * The following function has no external prototype in older DDK
+ * revisions. When the DDK is updated then this should be removed.
*/
struct kbase_device *kbase_find_device(int minor);
#endif
-static volatile bool kbase_device_busy = false;
+static volatile bool kbase_device_busy;
static unsigned int num_hardware_counters_enabled;
/* gatorfs variables for counter enable state */
-static mali_counter *counters;
+static struct mali_counter *counters;
/* An array used to return the data we recorded as key,value pairs */
-static unsigned long *counter_dump;
+static int *counter_dump;
-extern mali_counter mali_activity[3];
+extern struct mali_counter mali_activity[3];
static const char *const mali_activity_names[] = {
"fragment",
@@ -456,27 +440,26 @@ static const char *const mali_activity_names[] = {
};
#define SYMBOL_GET(FUNCTION, ERROR_COUNT) \
- if(FUNCTION ## _symbol) \
- { \
- printk("gator: mali " #FUNCTION " symbol was already registered\n"); \
- (ERROR_COUNT)++; \
- } \
- else \
- { \
- FUNCTION ## _symbol = symbol_get(FUNCTION); \
- if(! FUNCTION ## _symbol) \
- { \
- printk("gator: mali online " #FUNCTION " symbol not found\n"); \
+ do { \
+ if (FUNCTION ## _symbol) { \
+ pr_err("gator: mali " #FUNCTION " symbol was already registered\n"); \
(ERROR_COUNT)++; \
+ } else { \
+ FUNCTION ## _symbol = symbol_get(FUNCTION); \
+ if (!FUNCTION ## _symbol) { \
+ pr_err("gator: mali online " #FUNCTION " symbol not found\n"); \
+ (ERROR_COUNT)++; \
+ } \
} \
- }
+ } while (0)
#define SYMBOL_CLEANUP(FUNCTION) \
- if(FUNCTION ## _symbol) \
- { \
- symbol_put(FUNCTION); \
- FUNCTION ## _symbol = NULL; \
- }
+ do { \
+ if (FUNCTION ## _symbol) { \
+ symbol_put(FUNCTION); \
+ FUNCTION ## _symbol = NULL; \
+ } \
+ } while (0)
/**
* Execute symbol_get for all the Mali symbols and check for success.
@@ -541,14 +524,12 @@ static void clean_symbols(void)
static int is_read_scheduled(const struct timespec *current_time, u32 *prev_time_s, s32 *next_read_time_ns)
{
/* If the current ns count rolls over a second, roll the next read time too. */
- if (current_time->tv_sec != *prev_time_s) {
+ if (current_time->tv_sec != *prev_time_s)
*next_read_time_ns = *next_read_time_ns - NSEC_PER_SEC;
- }
/* Abort the read if the next read time has not arrived. */
- if (current_time->tv_nsec < *next_read_time_ns) {
+ if (current_time->tv_nsec < *next_read_time_ns)
return 0;
- }
/* Set the next read some fixed time after this one, and update the read timestamp. */
*next_read_time_ns = current_time->tv_nsec + READ_INTERVAL_NSEC;
@@ -572,16 +553,16 @@ static int start(void)
num_hardware_counters_enabled = 0;
/* Declare and initialise kbase_gator_hwcnt_info structure */
- in_out_info = kmalloc(sizeof(struct kbase_gator_hwcnt_info), GFP_KERNEL);
- for (cnt = 0; cnt < ARRAY_SIZE(in_out_info->bitmask); cnt++) {
+ in_out_info = kmalloc(sizeof(*in_out_info), GFP_KERNEL);
+ for (cnt = 0; cnt < ARRAY_SIZE(in_out_info->bitmask); cnt++)
in_out_info->bitmask[cnt] = 0;
- }
/* Calculate enable bitmasks based on counters_enabled array */
for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
if (counters[cnt].enabled) {
int block = GET_HW_BLOCK(cnt);
int enable_bit = GET_COUNTER_OFFSET(cnt) / 4;
+
in_out_info->bitmask[block] |= (1 << enable_bit);
pr_debug("gator: Mali-Midgard: hardware counter %s selected [%d]\n", hardware_counter_names[cnt], cnt);
num_hardware_counters_enabled++;
@@ -598,9 +579,8 @@ static int start(void)
handles = kbase_gator_hwcnt_init_symbol(in_out_info);
- if (handles == NULL) {
+ if (handles == NULL)
goto out;
- }
kbase_device_busy = false;
}
@@ -612,10 +592,12 @@ static int start(void)
/* Calculate enable bitmasks based on counters_enabled array */
for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
- const mali_counter *counter = &counters[cnt];
+ const struct mali_counter *counter = &counters[cnt];
+
if (counter->enabled) {
int block = GET_HW_BLOCK(cnt);
int enable_bit = GET_COUNTER_OFFSET(cnt) / 4;
+
bitmask[block] |= (1 << enable_bit);
pr_debug("gator: Mali-Midgard: hardware counter %s selected [%d]\n", hardware_counter_names[cnt], cnt);
num_hardware_counters_enabled++;
@@ -684,7 +666,7 @@ static int start(void)
}
pr_debug("gator: Mali-Midgard: hardware counters enabled\n");
kbase_instr_hwcnt_clear_symbol(kbcontext);
- pr_debug("gator: Mali-Midgard: hardware counters cleared \n");
+ pr_debug("gator: Mali-Midgard: hardware counters cleared\n");
kbase_device_busy = false;
}
@@ -719,9 +701,8 @@ static void stop(void)
pr_debug("gator: Mali-Midgard: stop\n");
/* Set all counters as disabled */
- for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
+ for (cnt = 0; cnt < number_of_hardware_counters; cnt++)
counters[cnt].enabled = 0;
- }
/* Destroy the context for HW counters */
#if MALI_DDK_GATOR_API_VERSION == 3
@@ -763,30 +744,87 @@ static void stop(void)
}
}
-static int read(int **buffer)
+static int read_counter(const int cnt, const int len, const struct mali_counter *counter)
+{
+ const int block = GET_HW_BLOCK(cnt);
+ const int counter_offset = GET_COUNTER_OFFSET(cnt);
+
+#if MALI_DDK_GATOR_API_VERSION == 3
+ const char *block_base_address = (char *)in_out_info->kernel_dump_buffer;
+ int i;
+ int shader_core_count = 0;
+ u32 value = 0;
+
+ for (i = 0; i < in_out_info->nr_hwc_blocks; i++) {
+ if (block == in_out_info->hwc_layout[i]) {
+ value += *((u32 *)(block_base_address + (0x100 * i)) + counter_offset);
+ if (block == SHADER_BLOCK)
+ ++shader_core_count;
+ }
+ }
+
+ if (shader_core_count > 1)
+ value /= shader_core_count;
+#else
+ const char *block_base_address = (char *)kernel_dump_buffer + vithar_blocks[block];
+
+ /* If counter belongs to shader block need to take into account all cores */
+ if (block == SHADER_BLOCK) {
+ int i = 0;
+ int shader_core_count = 0;
+
+ value = 0;
+
+ for (i = 0; i < 4; i++) {
+ if ((shader_present_low >> i) & 1) {
+ value += *((u32 *)(block_base_address + (0x100 * i)) + counter_offset);
+ shader_core_count++;
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ if ((shader_present_low >> (i+4)) & 1) {
+ value += *((u32 *)(block_base_address + (0x100 * i) + 0x800) + counter_offset);
+ shader_core_count++;
+ }
+ }
+
+ /* Need to total by number of cores to produce an average */
+ if (shader_core_count != 0)
+ value /= shader_core_count;
+ } else {
+ value = *((u32 *)block_base_address + counter_offset);
+ }
+#endif
+
+ counter_dump[len + 0] = counter->key;
+ counter_dump[len + 1] = value;
+
+ return 2;
+}
+
+static int read(int **buffer, bool sched_switch)
{
int cnt;
int len = 0;
- u32 value = 0;
uint32_t success;
struct timespec current_time;
- static u32 prev_time_s = 0;
- static s32 next_read_time_ns = 0;
+ static u32 prev_time_s;
+ static s32 next_read_time_ns;
- if (!on_primary_core()) {
+ if (!on_primary_core() || sched_switch)
return 0;
- }
getnstimeofday(&current_time);
/*
- * Discard reads unless a respectable time has passed. This reduces the load on the GPU without sacrificing
- * accuracy on the Streamline display.
+ * Discard reads unless a respectable time has passed. This
+ * reduces the load on the GPU without sacrificing accuracy on
+ * the Streamline display.
*/
- if (!is_read_scheduled(&current_time, &prev_time_s, &next_read_time_ns)) {
+ if (!is_read_scheduled(&current_time, &prev_time_s, &next_read_time_ns))
return 0;
- }
/*
* Report the HW counters
@@ -803,16 +841,14 @@ static int read(int **buffer)
#endif
#if MALI_DDK_GATOR_API_VERSION == 3
- if (!handles) {
+ if (!handles)
return -1;
- }
/* Mali symbols can be called safely since a kbcontext is valid */
if (kbase_gator_instr_hwcnt_dump_complete_symbol(handles, &success) == MALI_TRUE) {
#else
- if (!kbcontext) {
+ if (!kbcontext)
return -1;
- }
/* Mali symbols can be called safely since a kbcontext is valid */
if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success) == MALI_TRUE) {
@@ -822,64 +858,10 @@ static int read(int **buffer)
if (success == MALI_TRUE) {
/* Cycle through hardware counters and accumulate totals */
for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
- const mali_counter *counter = &counters[cnt];
- if (counter->enabled) {
- const int block = GET_HW_BLOCK(cnt);
- const int counter_offset = GET_COUNTER_OFFSET(cnt);
-
-#if MALI_DDK_GATOR_API_VERSION == 3
- const char *block_base_address = (char *)in_out_info->kernel_dump_buffer;
- int i;
- int shader_core_count = 0;
- value = 0;
-
- for (i = 0; i < in_out_info->nr_hwc_blocks; i++) {
- if (block == in_out_info->hwc_layout[i]) {
- value += *((u32 *)(block_base_address + (0x100 * i)) + counter_offset);
- if (block == SHADER_BLOCK) {
- ++shader_core_count;
- }
- }
- }
-
- if (shader_core_count > 1) {
- value /= shader_core_count;
- }
-#else
- const char *block_base_address = (char *)kernel_dump_buffer + vithar_blocks[block];
-
- /* If counter belongs to shader block need to take into account all cores */
- if (block == SHADER_BLOCK) {
- int i = 0;
- int shader_core_count = 0;
- value = 0;
-
- for (i = 0; i < 4; i++) {
- if ((shader_present_low >> i) & 1) {
- value += *((u32 *)(block_base_address + (0x100 * i)) + counter_offset);
- shader_core_count++;
- }
- }
-
- for (i = 0; i < 4; i++) {
- if((shader_present_low >> (i+4)) & 1) {
- value += *((u32 *)(block_base_address + (0x100 * i) + 0x800) + counter_offset);
- shader_core_count++;
- }
- }
-
- /* Need to total by number of cores to produce an average */
- if (shader_core_count != 0) {
- value /= shader_core_count;
- }
- } else {
- value = *((u32 *)block_base_address + counter_offset);
- }
-#endif
+ const struct mali_counter *counter = &counters[cnt];
- counter_dump[len++] = counter->key;
- counter_dump[len++] = value;
- }
+ if (counter->enabled)
+ len += read_counter(cnt, len, counter);
}
}
}
@@ -895,9 +877,8 @@ static int read(int **buffer)
}
/* Update the buffer */
- if (buffer) {
- *buffer = (int *)counter_dump;
- }
+ if (buffer)
+ *buffer = counter_dump;
return len;
}
@@ -909,15 +890,13 @@ static int create_files(struct super_block *sb, struct dentry *root)
* Create the filesystem for all events
*/
for (event = 0; event < ARRAY_SIZE(mali_activity); event++) {
- if (gator_mali_create_file_system("Midgard", mali_activity_names[event], sb, root, &mali_activity[event], NULL) != 0) {
+ if (gator_mali_create_file_system("Midgard", mali_activity_names[event], sb, root, &mali_activity[event], NULL) != 0)
return -1;
- }
}
for (event = 0; event < number_of_hardware_counters; event++) {
- if (gator_mali_create_file_system(mali_name, hardware_counter_names[event], sb, root, &counters[event], NULL) != 0) {
+ if (gator_mali_create_file_system(mali_name, hardware_counter_names[event], sb, root, &counters[event], NULL) != 0)
return -1;
- }
}
return 0;
@@ -926,7 +905,7 @@ static int create_files(struct super_block *sb, struct dentry *root)
static void shutdown(void)
{
#if MALI_DDK_GATOR_API_VERSION == 3
- kbase_gator_hwcnt_term_names_type *kbase_gator_hwcnt_term_names_symbol = NULL;
+ void (*kbase_gator_hwcnt_term_names_symbol)(void) = NULL;
int error_count = 0;
#endif
@@ -940,7 +919,7 @@ static void shutdown(void)
hardware_counter_names = NULL;
if (kbase_gator_hwcnt_term_names_symbol != NULL) {
kbase_gator_hwcnt_term_names_symbol();
- printk(KERN_ERR "Released symbols\n");
+ pr_err("Released symbols\n");
}
SYMBOL_CLEANUP(kbase_gator_hwcnt_term_names);
@@ -958,7 +937,7 @@ static struct gator_interface gator_events_mali_midgard_interface = {
int gator_events_mali_midgard_hw_init(void)
{
#if MALI_DDK_GATOR_API_VERSION == 3
- kbase_gator_hwcnt_init_names_type *kbase_gator_hwcnt_init_names_symbol = NULL;
+ const char *const *(*kbase_gator_hwcnt_init_names_symbol)(uint32_t *) = NULL;
int error_count = 0;
#endif
@@ -981,7 +960,7 @@ int gator_events_mali_midgard_hw_init(void)
SYMBOL_CLEANUP(kbase_gator_hwcnt_init_names);
if ((hardware_counter_names == NULL) || (number_of_hardware_counters <= 0)) {
- printk(KERN_ERR "gator: Error reading hardware counters names: got %d names\n", number_of_hardware_counters);
+ pr_err("gator: Error reading hardware counters names: got %d names\n", number_of_hardware_counters);
return -1;
}
#else
diff --git a/driver/gator_events_mali_midgard_hw_test.c b/driver/gator_events_mali_midgard_hw_test.c
index ba6553f..31a91e1 100644
--- a/driver/gator_events_mali_midgard_hw_test.c
+++ b/driver/gator_events_mali_midgard_hw_test.c
@@ -23,12 +23,12 @@ static int test_is_read_scheduled(u32 s, u32 ns, u32 prev_s, s32 next_ns, int ex
current_time.tv_nsec = ns;
if (is_read_scheduled(&current_time, &prev_time_s, &next_read_time_ns) != expected_result) {
- printk("Failed do_read(%u, %u, %u, %d): expected %d\n", s, ns, prev_s, next_ns, expected_result);
+ pr_err("Failed do_read(%u, %u, %u, %d): expected %d\n", s, ns, prev_s, next_ns, expected_result);
return 0;
}
if (next_read_time_ns != expected_next_ns) {
- printk("Failed: next_read_ns expected=%d, actual=%d\n", expected_next_ns, next_read_time_ns);
+ pr_err("Failed: next_read_ns expected=%d, actual=%d\n", expected_next_ns, next_read_time_ns);
return 0;
}
@@ -40,7 +40,7 @@ static void test_all_is_read_scheduled(void)
const int HIGHEST_NS = 999999999;
int n_tests_passed = 0;
- printk("gator: running tests on %s\n", __FILE__);
+ pr_err("gator: running tests on %s\n", __FILE__);
n_tests_passed += test_is_read_scheduled(0, 0, 0, 0, 1, READ_INTERVAL_NSEC); /* Null time */
n_tests_passed += test_is_read_scheduled(100, 1000, 0, 0, 1, READ_INTERVAL_NSEC + 1000); /* Initial values */
@@ -51,5 +51,5 @@ static void test_all_is_read_scheduled(void)
n_tests_passed += test_is_read_scheduled(101, 600, 100, HIGHEST_NS + 500, 1, 600 + READ_INTERVAL_NSEC);
- printk("gator: %d tests passed\n", n_tests_passed);
+ pr_err("gator: %d tests passed\n", n_tests_passed);
}
diff --git a/driver/gator_events_meminfo.c b/driver/gator_events_meminfo.c
index c633dfd..c625ac5 100644
--- a/driver/gator_events_meminfo.c
+++ b/driver/gator_events_meminfo.c
@@ -16,6 +16,8 @@
#include <linux/workqueue.h>
#include <trace/events/kmem.h>
+#define USE_THREAD defined(CONFIG_PREEMPT_RT_FULL)
+
enum {
MEMINFO_MEMFREE,
MEMINFO_MEMUSED,
@@ -48,7 +50,7 @@ static bool meminfo_global_enabled;
static ulong meminfo_enabled[MEMINFO_TOTAL];
static ulong meminfo_keys[MEMINFO_TOTAL];
static long long meminfo_buffer[2 * (MEMINFO_TOTAL + 2)];
-static int meminfo_length = 0;
+static int meminfo_length;
static bool new_data_avail;
static bool proc_global_enabled;
@@ -56,22 +58,44 @@ static ulong proc_enabled[PROC_COUNT];
static ulong proc_keys[PROC_COUNT];
static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]);
+#if USE_THREAD
+
static int gator_meminfo_func(void *data);
static bool gator_meminfo_run;
-// Initialize semaphore unlocked to initialize memory values
+/* Initialize semaphore unlocked to initialize memory values */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
static DECLARE_MUTEX(gator_meminfo_sem);
#else
static DEFINE_SEMAPHORE(gator_meminfo_sem);
#endif
+static void notify(void)
+{
+ up(&gator_meminfo_sem);
+}
+
+#else
+
+static unsigned int mem_event;
+static void wq_sched_handler(struct work_struct *wsptr);
+DECLARE_WORK(work, wq_sched_handler);
+static struct timer_list meminfo_wake_up_timer;
+static void meminfo_wake_up_handler(unsigned long unused_data);
+
+static void notify(void)
+{
+ mem_event++;
+}
+
+#endif
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order))
#else
GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order))
#endif
{
- up(&gator_meminfo_sem);
+ notify();
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
@@ -80,12 +104,12 @@ GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold))
GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold))
#endif
{
- up(&gator_meminfo_sem);
+ notify();
}
GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype))
{
- up(&gator_meminfo_sem);
+ notify();
}
static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
@@ -95,18 +119,16 @@ static int gator_events_meminfo_create_files(struct super_block *sb, struct dent
for (i = 0; i < MEMINFO_TOTAL; i++) {
dir = gatorfs_mkdir(sb, root, meminfo_names[i]);
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_keys[i]);
}
for (i = 0; i < PROC_COUNT; ++i) {
dir = gatorfs_mkdir(sb, root, proc_names[i]);
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &proc_enabled[i]);
gatorfs_create_ro_ulong(sb, dir, "key", &proc_keys[i]);
}
@@ -134,9 +156,8 @@ static int gator_events_meminfo_start(void)
break;
}
}
- if (meminfo_enabled[MEMINFO_MEMUSED]) {
+ if (meminfo_enabled[MEMINFO_MEMUSED])
proc_global_enabled = 1;
- }
if (meminfo_global_enabled == 0)
return 0;
@@ -156,16 +177,22 @@ static int gator_events_meminfo_start(void)
if (GATOR_REGISTER_TRACE(mm_page_alloc))
goto mm_page_alloc_exit;
- // Start worker thread
+#if USE_THREAD
+ /* Start worker thread */
gator_meminfo_run = true;
- // Since the mutex starts unlocked, memory values will be initialized
+ /* Since the mutex starts unlocked, memory values will be initialized */
if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo")))
goto kthread_run_exit;
+#else
+ setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
+#endif
return 0;
+#if USE_THREAD
kthread_run_exit:
GATOR_UNREGISTER_TRACE(mm_page_alloc);
+#endif
mm_page_alloc_exit:
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
GATOR_UNREGISTER_TRACE(mm_pagevec_free);
@@ -194,75 +221,111 @@ static void gator_events_meminfo_stop(void)
#endif
GATOR_UNREGISTER_TRACE(mm_page_alloc);
- // Stop worker thread
+#if USE_THREAD
+ /* Stop worker thread */
gator_meminfo_run = false;
up(&gator_meminfo_sem);
+#else
+ del_timer_sync(&meminfo_wake_up_timer);
+#endif
}
}
-// Must be run in process context as the kernel function si_meminfo() can sleep
-static int gator_meminfo_func(void *data)
+static void do_read(void)
{
struct sysinfo info;
int i, len;
unsigned long long value;
- for (;;) {
- if (down_killable(&gator_meminfo_sem)) {
- break;
+ meminfo_length = len = 0;
+
+ si_meminfo(&info);
+ for (i = 0; i < MEMINFO_TOTAL; i++) {
+ if (meminfo_enabled[i]) {
+ switch (i) {
+ case MEMINFO_MEMFREE:
+ value = info.freeram * PAGE_SIZE;
+ break;
+ case MEMINFO_MEMUSED:
+ /* pid -1 means system wide */
+ meminfo_buffer[len++] = 1;
+ meminfo_buffer[len++] = -1;
+ /* Emit value */
+ meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED];
+ meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE;
+ /* Clear pid */
+ meminfo_buffer[len++] = 1;
+ meminfo_buffer[len++] = 0;
+ continue;
+ case MEMINFO_BUFFERRAM:
+ value = info.bufferram * PAGE_SIZE;
+ break;
+ default:
+ value = 0;
+ break;
+ }
+ meminfo_buffer[len++] = meminfo_keys[i];
+ meminfo_buffer[len++] = value;
}
+ }
- // Eat up any pending events
- while (!down_trylock(&gator_meminfo_sem));
+ meminfo_length = len;
+ new_data_avail = true;
+}
- if (!gator_meminfo_run) {
+#if USE_THREAD
+
+static int gator_meminfo_func(void *data)
+{
+ for (;;) {
+ if (down_killable(&gator_meminfo_sem))
break;
- }
- meminfo_length = len = 0;
-
- si_meminfo(&info);
- for (i = 0; i < MEMINFO_TOTAL; i++) {
- if (meminfo_enabled[i]) {
- switch (i) {
- case MEMINFO_MEMFREE:
- value = info.freeram * PAGE_SIZE;
- break;
- case MEMINFO_MEMUSED:
- // pid -1 means system wide
- meminfo_buffer[len++] = 1;
- meminfo_buffer[len++] = -1;
- // Emit value
- meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED];
- meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE;
- // Clear pid
- meminfo_buffer[len++] = 1;
- meminfo_buffer[len++] = 0;
- continue;
- case MEMINFO_BUFFERRAM:
- value = info.bufferram * PAGE_SIZE;
- break;
- default:
- value = 0;
- break;
- }
- meminfo_buffer[len++] = meminfo_keys[i];
- meminfo_buffer[len++] = value;
- }
- }
+ /* Eat up any pending events */
+ while (!down_trylock(&gator_meminfo_sem))
+ ;
+
+ if (!gator_meminfo_run)
+ break;
- meminfo_length = len;
- new_data_avail = true;
+ do_read();
}
return 0;
}
+#else
+
+/* Must be run in process context as the kernel function si_meminfo() can sleep */
+static void wq_sched_handler(struct work_struct *wsptr)
+{
+ do_read();
+}
+
+static void meminfo_wake_up_handler(unsigned long unused_data)
+{
+ /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */
+ schedule_work(&work);
+}
+
+#endif
+
static int gator_events_meminfo_read(long long **buffer)
{
+#if !USE_THREAD
+ static unsigned int last_mem_event;
+#endif
+
if (!on_primary_core() || !meminfo_global_enabled)
return 0;
+#if !USE_THREAD
+ if (last_mem_event != mem_event) {
+ last_mem_event = mem_event;
+ mod_timer(&meminfo_wake_up_timer, jiffies + 1);
+ }
+#endif
+
if (!new_data_avail)
return 0;
@@ -280,6 +343,7 @@ static inline unsigned long gator_get_mm_counter(struct mm_struct *mm, int membe
{
#ifdef SPLIT_RSS_COUNTING
long val = atomic_long_read(&mm->rss_stat.count[member]);
+
if (val < 0)
val = 0;
return (unsigned long)val;
@@ -306,22 +370,19 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
int cpu = get_physical_cpu();
long long *buf = per_cpu(proc_buffer, cpu);
- if (!proc_global_enabled) {
+ if (!proc_global_enabled)
return 0;
- }
- // Collect the memory stats of the process instead of the thread
- if (task->group_leader != NULL) {
+ /* Collect the memory stats of the process instead of the thread */
+ if (task->group_leader != NULL)
task = task->group_leader;
- }
- // get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch
+ /* get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch */
mm = task->mm;
- if (mm == NULL) {
+ if (mm == NULL)
return 0;
- }
- // Derived from task_statm in fs/proc/task_mmu.c
+ /* Derived from task_statm in fs/proc/task_mmu.c */
if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) {
share = get_mm_counter(mm,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
@@ -332,7 +393,7 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
);
}
- // key of 1 indicates a pid
+ /* key of 1 indicates a pid */
buf[len++] = 1;
buf[len++] = task->pid;
@@ -366,12 +427,12 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
MM_ANONPAGES
#endif
);
- // Send resident for this pid
+ /* Send resident for this pid */
buf[len++] = meminfo_keys[MEMINFO_MEMUSED];
buf[len++] = value * PAGE_SIZE;
}
- // Clear pid
+ /* Clear pid */
buf[len++] = 1;
buf[len++] = 0;
diff --git a/driver/gator_events_mmapped.c b/driver/gator_events_mmapped.c
index 5bc01c4..6b2af99 100644
--- a/driver/gator_events_mmapped.c
+++ b/driver/gator_events_mmapped.c
@@ -103,7 +103,7 @@ static int mmapped_simulate(int counter, int delta_in_us)
switch (counter) {
case 0: /* sort-of-sine */
{
- static int t = 0;
+ static int t;
int x;
t += delta_in_us;
@@ -140,7 +140,7 @@ static int mmapped_simulate(int counter, int delta_in_us)
break;
case 2: /* PWM signal */
{
- static int dc, x, t = 0;
+ static int dc, x, t;
t += delta_in_us;
if (t > 1000000)
@@ -157,7 +157,7 @@ static int mmapped_simulate(int counter, int delta_in_us)
return result;
}
-static int gator_events_mmapped_read(int **buffer)
+static int gator_events_mmapped_read(int **buffer, bool sched_switch)
{
int i;
int len = 0;
diff --git a/driver/gator_events_net.c b/driver/gator_events_net.c
index 11c10e3..d21b4db 100644
--- a/driver/gator_events_net.c
+++ b/driver/gator_events_net.c
@@ -25,7 +25,7 @@ static int netGet[TOTALNET * 4];
static struct timer_list net_wake_up_timer;
-// Must be run in process context as the kernel function dev_get_stats() can sleep
+/* Must be run in process context as the kernel function dev_get_stats() can sleep */
static void get_network_stats(struct work_struct *wsptr)
{
int rx = 0, tx = 0;
@@ -49,7 +49,7 @@ DECLARE_WORK(wq_get_stats, get_network_stats);
static void net_wake_up_handler(unsigned long unused_data)
{
- // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
+ /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */
schedule_work(&wq_get_stats);
}
@@ -73,21 +73,19 @@ static void calculate_delta(int *rx, int *tx)
static int gator_events_net_create_files(struct super_block *sb, struct dentry *root)
{
- // Network counters are not currently supported in RT-Preempt full because mod_timer is used
+ /* Network counters are not currently supported in RT-Preempt full because mod_timer is used */
#ifndef CONFIG_PREEMPT_RT_FULL
struct dentry *dir;
dir = gatorfs_mkdir(sb, root, "Linux_net_rx");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &netrx_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &netrx_key);
dir = gatorfs_mkdir(sb, root, "Linux_net_tx");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &nettx_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &nettx_key);
#endif
@@ -115,10 +113,10 @@ static void gator_events_net_stop(void)
nettx_enabled = 0;
}
-static int gator_events_net_read(int **buffer)
+static int gator_events_net_read(int **buffer, bool sched_switch)
{
int len, rx_delta, tx_delta;
- static int last_rx_delta = 0, last_tx_delta = 0;
+ static int last_rx_delta, last_tx_delta;
if (!on_primary_core())
return 0;
@@ -134,7 +132,8 @@ static int gator_events_net_read(int **buffer)
if (netrx_enabled && last_rx_delta != rx_delta) {
last_rx_delta = rx_delta;
netGet[len++] = netrx_key;
- netGet[len++] = 0; // indicates to Streamline that rx_delta bytes were transmitted now, not since the last message
+ /* indicates to Streamline that rx_delta bytes were transmitted now, not since the last message */
+ netGet[len++] = 0;
netGet[len++] = netrx_key;
netGet[len++] = rx_delta;
}
@@ -142,7 +141,8 @@ static int gator_events_net_read(int **buffer)
if (nettx_enabled && last_tx_delta != tx_delta) {
last_tx_delta = tx_delta;
netGet[len++] = nettx_key;
- netGet[len++] = 0; // indicates to Streamline that tx_delta bytes were transmitted now, not since the last message
+ /* indicates to Streamline that tx_delta bytes were transmitted now, not since the last message */
+ netGet[len++] = 0;
netGet[len++] = nettx_key;
netGet[len++] = tx_delta;
}
diff --git a/driver/gator_events_perf_pmu.c b/driver/gator_events_perf_pmu.c
index 06bbad5..47cf278 100644
--- a/driver/gator_events_perf_pmu.c
+++ b/driver/gator_events_perf_pmu.c
@@ -8,7 +8,7 @@
#include "gator.h"
-// gator_events_armvX.c is used for Linux 2.6.x
+/* gator_events_armvX.c is used for Linux 2.6.x */
#if GATOR_PERF_PMU_SUPPORT
#include <linux/io.h>
@@ -20,39 +20,41 @@
extern bool event_based_sampling;
-// Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE
+/* Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE */
#define CNTMAX 16
#define CCI_400 4
-// Maximum number of uncore counters
-// + 1 for the cci-400 cycles counter
-#define UCCNT (CCI_400 + 1)
+#define CCN_5XX 8
+/* Maximum number of uncore counters */
+/* + 1 for the cci-400 cycles counter */
+/* + 1 for the CCN-5xx cycles counter */
+#define UCCNT (CCI_400 + 1 + CCN_5XX + 1)
-// Default to 0 if unable to probe the revision which was the previous behavior
+/* Default to 0 if unable to probe the revision which was the previous behavior */
#define DEFAULT_CCI_REVISION 0
-// A gator_attr is needed for every counter
+/* A gator_attr is needed for every counter */
struct gator_attr {
- // Set once in gator_events_perf_pmu_*_init - the name of the event in the gatorfs
+ /* Set once in gator_events_perf_pmu_*_init - the name of the event in the gatorfs */
char name[40];
- // Exposed in gatorfs - set by gatord to enable this counter
+ /* Exposed in gatorfs - set by gatord to enable this counter */
unsigned long enabled;
- // Set once in gator_events_perf_pmu_*_init - the perf type to use, see perf_type_id in the perf_event.h header file.
+ /* Set once in gator_events_perf_pmu_*_init - the perf type to use, see perf_type_id in the perf_event.h header file. */
unsigned long type;
- // Exposed in gatorfs - set by gatord to select the event to collect
+ /* Exposed in gatorfs - set by gatord to select the event to collect */
unsigned long event;
- // Exposed in gatorfs - set by gatord with the sample period to use and enable EBS for this counter
+ /* Exposed in gatorfs - set by gatord with the sample period to use and enable EBS for this counter */
unsigned long count;
- // Exposed as read only in gatorfs - set once in __attr_init as the key to use in the APC data
+ /* Exposed as read only in gatorfs - set once in __attr_init as the key to use in the APC data */
unsigned long key;
};
-// Per-core counter attributes
+/* Per-core counter attributes */
static struct gator_attr attrs[CNTMAX];
-// Number of initialized per-core counters
+/* Number of initialized per-core counters */
static int attr_count;
-// Uncore counter attributes
+/* Uncore counter attributes */
static struct gator_attr uc_attrs[UCCNT];
-// Number of initialized uncore counters
+/* Number of initialized uncore counters */
static int uc_attr_count;
struct gator_event {
@@ -74,13 +76,11 @@ static int __create_files(struct super_block *sb, struct dentry *root, struct ga
{
struct dentry *dir;
- if (attr->name[0] == '\0') {
+ if (attr->name[0] == '\0')
return 0;
- }
dir = gatorfs_mkdir(sb, root, attr->name);
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &attr->enabled);
gatorfs_create_ulong(sb, dir, "count", &attr->count);
gatorfs_create_ro_ulong(sb, dir, "key", &attr->key);
@@ -94,15 +94,13 @@ static int gator_events_perf_pmu_create_files(struct super_block *sb, struct den
int cnt;
for (cnt = 0; cnt < attr_count; cnt++) {
- if (__create_files(sb, root, &attrs[cnt]) != 0) {
+ if (__create_files(sb, root, &attrs[cnt]) != 0)
return -1;
- }
}
for (cnt = 0; cnt < uc_attr_count; cnt++) {
- if (__create_files(sb, root, &uc_attrs[cnt]) != 0) {
+ if (__create_files(sb, root, &uc_attrs[cnt]) != 0)
return -1;
- }
}
return 0;
@@ -123,14 +121,14 @@ static void dummy_handler(struct perf_event *event, int unused, struct perf_samp
static void dummy_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
#endif
{
-// Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll
+ /* Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll */
}
-static int gator_events_perf_pmu_read(int **buffer);
+static int gator_events_perf_pmu_read(int **buffer, bool sched_switch);
static int gator_events_perf_pmu_online(int **buffer, bool migrate)
{
- return gator_events_perf_pmu_read(buffer);
+ return gator_events_perf_pmu_read(buffer, false);
}
static void __online_dispatch(int cpu, bool migrate, struct gator_attr *const attr, struct gator_event *const event)
@@ -139,15 +137,13 @@ static void __online_dispatch(int cpu, bool migrate, struct gator_attr *const at
event->zero = true;
- if (event->pevent != NULL || event->pevent_attr == 0 || migrate) {
+ if (event->pevent != NULL || event->pevent_attr == 0 || migrate)
return;
- }
- if (attr->count > 0) {
+ if (attr->count > 0)
handler = ebs_overflow_handler;
- } else {
+ else
handler = dummy_handler;
- }
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
event->pevent = perf_event_create_kernel_counter(event->pevent_attr, cpu, 0, handler);
@@ -174,14 +170,12 @@ static void gator_events_perf_pmu_online_dispatch(int cpu, bool migrate)
cpu = pcpu_to_lcpu(cpu);
- for (cnt = 0; cnt < attr_count; cnt++) {
+ for (cnt = 0; cnt < attr_count; cnt++)
__online_dispatch(cpu, migrate, &attrs[cnt], &per_cpu(events, cpu)[cnt]);
- }
if (cpu == 0) {
- for (cnt = 0; cnt < uc_attr_count; cnt++) {
+ for (cnt = 0; cnt < uc_attr_count; cnt++)
__online_dispatch(cpu, migrate, &uc_attrs[cnt], &uc_events[cnt]);
- }
}
}
@@ -194,28 +188,24 @@ static void __offline_dispatch(int cpu, struct gator_event *const event)
event->pevent = NULL;
}
- if (pe) {
+ if (pe)
perf_event_release_kernel(pe);
- }
}
static void gator_events_perf_pmu_offline_dispatch(int cpu, bool migrate)
{
int cnt;
- if (migrate) {
+ if (migrate)
return;
- }
cpu = pcpu_to_lcpu(cpu);
- for (cnt = 0; cnt < attr_count; cnt++) {
+ for (cnt = 0; cnt < attr_count; cnt++)
__offline_dispatch(cpu, &per_cpu(events, cpu)[cnt]);
- }
if (cpu == 0) {
- for (cnt = 0; cnt < uc_attr_count; cnt++) {
+ for (cnt = 0; cnt < uc_attr_count; cnt++)
__offline_dispatch(cpu, &uc_events[cnt]);
- }
}
}
@@ -225,7 +215,7 @@ static int __check_ebs(struct gator_attr *const attr)
if (!event_based_sampling) {
event_based_sampling = true;
} else {
- printk(KERN_WARNING "gator: Only one ebs counter is allowed\n");
+ pr_warning("gator: Only one ebs counter is allowed\n");
return -1;
}
}
@@ -238,9 +228,9 @@ static int __start(struct gator_attr *const attr, struct gator_event *const even
u32 size = sizeof(struct perf_event_attr);
event->pevent = NULL;
- if (!attr->enabled) { // Skip disabled counters
+ /* Skip disabled counters */
+ if (!attr->enabled)
return 0;
- }
event->prev = 0;
event->curr = 0;
@@ -267,29 +257,25 @@ static int gator_events_perf_pmu_start(void)
event_based_sampling = false;
for (cnt = 0; cnt < attr_count; cnt++) {
- if (__check_ebs(&attrs[cnt]) != 0) {
+ if (__check_ebs(&attrs[cnt]) != 0)
return -1;
- }
}
for (cnt = 0; cnt < uc_attr_count; cnt++) {
- if (__check_ebs(&uc_attrs[cnt]) != 0) {
+ if (__check_ebs(&uc_attrs[cnt]) != 0)
return -1;
- }
}
for_each_present_cpu(cpu) {
for (cnt = 0; cnt < attr_count; cnt++) {
- if (__start(&attrs[cnt], &per_cpu(events, cpu)[cnt]) != 0) {
+ if (__start(&attrs[cnt], &per_cpu(events, cpu)[cnt]) != 0)
return -1;
- }
}
}
for (cnt = 0; cnt < uc_attr_count; cnt++) {
- if (__start(&uc_attrs[cnt], &uc_events[cnt]) != 0) {
+ if (__start(&uc_attrs[cnt], &uc_events[cnt]) != 0)
return -1;
- }
}
return 0;
@@ -297,10 +283,8 @@ static int gator_events_perf_pmu_start(void)
static void __event_stop(struct gator_event *const event)
{
- if (event->pevent_attr) {
- kfree(event->pevent_attr);
- event->pevent_attr = NULL;
- }
+ kfree(event->pevent_attr);
+ event->pevent_attr = NULL;
}
static void __attr_stop(struct gator_attr *const attr)
@@ -315,29 +299,25 @@ static void gator_events_perf_pmu_stop(void)
unsigned int cnt, cpu;
for_each_present_cpu(cpu) {
- for (cnt = 0; cnt < attr_count; cnt++) {
+ for (cnt = 0; cnt < attr_count; cnt++)
__event_stop(&per_cpu(events, cpu)[cnt]);
- }
}
- for (cnt = 0; cnt < uc_attr_count; cnt++) {
+ for (cnt = 0; cnt < uc_attr_count; cnt++)
__event_stop(&uc_events[cnt]);
- }
- for (cnt = 0; cnt < attr_count; cnt++) {
+ for (cnt = 0; cnt < attr_count; cnt++)
__attr_stop(&attrs[cnt]);
- }
- for (cnt = 0; cnt < uc_attr_count; cnt++) {
+ for (cnt = 0; cnt < uc_attr_count; cnt++)
__attr_stop(&uc_attrs[cnt]);
- }
}
static void __read(int *const len, int cpu, struct gator_attr *const attr, struct gator_event *const event)
{
int delta;
-
struct perf_event *const ev = event->pevent;
+
if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
/* After creating the perf counter in __online_dispatch, there
* is a race condition between gator_events_perf_pmu_online and
@@ -361,33 +341,29 @@ static void __read(int *const len, int cpu, struct gator_attr *const attr, struc
event->prev_delta = delta;
event->prev = event->curr;
per_cpu(perf_cnt, cpu)[(*len)++] = attr->key;
- if (delta < 0) {
+ if (delta < 0)
delta *= -1;
- }
per_cpu(perf_cnt, cpu)[(*len)++] = delta;
}
}
}
}
-static int gator_events_perf_pmu_read(int **buffer)
+static int gator_events_perf_pmu_read(int **buffer, bool sched_switch)
{
int cnt, len = 0;
const int cpu = get_logical_cpu();
- for (cnt = 0; cnt < attr_count; cnt++) {
+ for (cnt = 0; cnt < attr_count; cnt++)
__read(&len, cpu, &attrs[cnt], &per_cpu(events, cpu)[cnt]);
- }
if (cpu == 0) {
- for (cnt = 0; cnt < uc_attr_count; cnt++) {
+ for (cnt = 0; cnt < uc_attr_count; cnt++)
__read(&len, cpu, &uc_attrs[cnt], &uc_events[cnt]);
- }
}
- if (buffer) {
+ if (buffer)
*buffer = per_cpu(perf_cnt, cpu);
- }
return len;
}
@@ -428,23 +404,20 @@ static int probe_cci_revision(void)
int ret = DEFAULT_CCI_REVISION;
np = of_find_matching_node(NULL, arm_cci_matches);
- if (!np) {
+ if (!np)
return ret;
- }
- if (of_address_to_resource(np, 0, &res)) {
+ if (of_address_to_resource(np, 0, &res))
goto node_put;
- }
cci_ctrl_base = ioremap(res.start, resource_size(&res));
rev = (readl_relaxed(cci_ctrl_base + 0xfe8) >> 4) & 0xf;
- if (rev <= 4) {
+ if (rev <= 4)
ret = 0;
- } else if (rev <= 6) {
+ else if (rev <= 6)
ret = 1;
- }
iounmap(cci_ctrl_base);
@@ -463,9 +436,24 @@ static int probe_cci_revision(void)
#endif
-static void gator_events_perf_pmu_cci_init(const int type)
+static void gator_events_perf_pmu_uncore_init(const char *const name, const int type, const int count)
{
int cnt;
+
+ snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", name);
+ uc_attrs[uc_attr_count].type = type;
+ ++uc_attr_count;
+
+ for (cnt = 0; cnt < count; ++cnt, ++uc_attr_count) {
+ struct gator_attr *const attr = &uc_attrs[uc_attr_count];
+
+ snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", name, cnt);
+ attr->type = type;
+ }
+}
+
+static void gator_events_perf_pmu_cci_init(const int type)
+{
const char *cci_name;
switch (probe_cci_revision()) {
@@ -480,15 +468,7 @@ static void gator_events_perf_pmu_cci_init(const int type)
return;
}
- snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", cci_name);
- uc_attrs[uc_attr_count].type = type;
- ++uc_attr_count;
-
- for (cnt = 0; cnt < CCI_400; ++cnt, ++uc_attr_count) {
- struct gator_attr *const attr = &uc_attrs[uc_attr_count];
- snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", cci_name, cnt);
- attr->type = type;
- }
+ gator_events_perf_pmu_uncore_init(cci_name, type, CCI_400);
}
static void gator_events_perf_pmu_cpu_init(const struct gator_cpu *const gator_cpu, const int type)
@@ -501,6 +481,7 @@ static void gator_events_perf_pmu_cpu_init(const struct gator_cpu *const gator_c
for (cnt = 0; cnt < gator_cpu->pmnc_counters; ++cnt, ++attr_count) {
struct gator_attr *const attr = &attrs[attr_count];
+
snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", gator_cpu->pmnc_name, cnt);
attr->type = type;
}
@@ -516,12 +497,10 @@ int gator_events_perf_pmu_init(void)
int cnt;
bool found_cpu = false;
- for (cnt = 0; cnt < CNTMAX; cnt++) {
+ for (cnt = 0; cnt < CNTMAX; cnt++)
__attr_init(&attrs[cnt]);
- }
- for (cnt = 0; cnt < UCCNT; cnt++) {
+ for (cnt = 0; cnt < UCCNT; cnt++)
__attr_init(&uc_attrs[cnt]);
- }
memset(&pea, 0, sizeof(pea));
pea.size = sizeof(pea);
@@ -531,7 +510,7 @@ int gator_events_perf_pmu_init(void)
for (type = PERF_TYPE_MAX; type < 0x20; ++type) {
pea.type = type;
- // A particular PMU may work on some but not all cores, so try on each core
+ /* A particular PMU may work on some but not all cores, so try on each core */
pe = NULL;
for_each_present_cpu(cpu) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
@@ -539,23 +518,31 @@ int gator_events_perf_pmu_init(void)
#else
pe = perf_event_create_kernel_counter(&pea, cpu, 0, dummy_handler, 0);
#endif
- if (!IS_ERR(pe)) {
+ if (!IS_ERR(pe))
break;
- }
}
- // Assume that valid PMUs are contiguous
+ /* Assume that valid PMUs are contiguous */
if (IS_ERR(pe)) {
- break;
+ pea.config = 0xff00;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
+ pe = perf_event_create_kernel_counter(&pea, 0, 0, dummy_handler);
+#else
+ pe = perf_event_create_kernel_counter(&pea, 0, 0, dummy_handler, 0);
+#endif
+ if (IS_ERR(pe))
+ break;
}
if (pe->pmu != NULL && type == pe->pmu->type) {
if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0 || strcmp("CCI_400-r1", pe->pmu->name) == 0) {
gator_events_perf_pmu_cci_init(type);
+ } else if (strcmp("ccn", pe->pmu->name) == 0) {
+ gator_events_perf_pmu_uncore_init("ARM_CCN_5XX", type, CCN_5XX);
} else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) {
found_cpu = true;
gator_events_perf_pmu_cpu_init(gator_cpu, type);
}
- // Initialize gator_attrs for dynamic PMUs here
+ /* Initialize gator_attrs for dynamic PMUs here */
}
perf_event_release_kernel(pe);
@@ -563,21 +550,21 @@ int gator_events_perf_pmu_init(void)
if (!found_cpu) {
const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(gator_cpuid());
- if (gator_cpu == NULL) {
+
+ if (gator_cpu == NULL)
return -1;
- }
gator_events_perf_pmu_cpu_init(gator_cpu, PERF_TYPE_RAW);
}
- // Initialize gator_attrs for non-dynamic PMUs here
+ /* Initialize gator_attrs for non-dynamic PMUs here */
if (attr_count > CNTMAX) {
- printk(KERN_ERR "gator: Too many perf counters\n");
+ pr_err("gator: Too many perf counters\n");
return -1;
}
if (uc_attr_count > UCCNT) {
- printk(KERN_ERR "gator: Too many perf uncore counters\n");
+ pr_err("gator: Too many perf uncore counters\n");
return -1;
}
diff --git a/driver/gator_events_sched.c b/driver/gator_events_sched.c
index 9e39158..637107d 100644
--- a/driver/gator_events_sched.c
+++ b/driver/gator_events_sched.c
@@ -26,8 +26,9 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_
{
unsigned long flags;
- // disable interrupts to synchronize with gator_events_sched_read()
- // spinlocks not needed since percpu buffers are used
+ /* disable interrupts to synchronize with gator_events_sched_read()
+ * spinlocks not needed since percpu buffers are used
+ */
local_irq_save(flags);
per_cpu(schedCnt, get_physical_cpu())[SCHED_SWITCH]++;
local_irq_restore(flags);
@@ -39,9 +40,8 @@ static int gator_events_sched_create_files(struct super_block *sb, struct dentry
/* switch */
dir = gatorfs_mkdir(sb, root, "Linux_sched_switch");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &sched_switch_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &sched_switch_key);
@@ -50,7 +50,7 @@ static int gator_events_sched_create_files(struct super_block *sb, struct dentry
static int gator_events_sched_start(void)
{
- // register tracepoints
+ /* register tracepoints */
if (sched_switch_enabled)
if (GATOR_REGISTER_TRACE(sched_switch))
goto sched_switch_exit;
@@ -58,7 +58,7 @@ static int gator_events_sched_start(void)
return 0;
- // unregister tracepoints on error
+ /* unregister tracepoints on error */
sched_switch_exit:
pr_err("gator: scheduler event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
@@ -74,7 +74,7 @@ static void gator_events_sched_stop(void)
sched_switch_enabled = 0;
}
-static int gator_events_sched_read(int **buffer)
+static int gator_events_sched_read(int **buffer, bool sched_switch)
{
unsigned long flags;
int len, value;
diff --git a/driver/gator_events_scorpion.c b/driver/gator_events_scorpion.c
index 2e5be8d..4921936 100644
--- a/driver/gator_events_scorpion.c
+++ b/driver/gator_events_scorpion.c
@@ -8,13 +8,13 @@
#include "gator.h"
-// gator_events_perf_pmu.c is used if perf is supported
+/* gator_events_perf_pmu.c is used if perf is supported */
#if GATOR_NO_PERF_SUPPORT
static const char *pmnc_name;
static int pmnc_counters;
-// Per-CPU PMNC: config reg
+/* Per-CPU PMNC: config reg */
#define PMNC_E (1 << 0) /* Enable all counters */
#define PMNC_P (1 << 1) /* Reset all counters */
#define PMNC_C (1 << 2) /* Cycle counter reset */
@@ -23,7 +23,7 @@ static int pmnc_counters;
#define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug */
#define PMNC_MASK 0x3f /* Mask for writable bits */
-// ccnt reg
+/* ccnt reg */
#define CCNT_REG (1 << 31)
#define CCNT 0
@@ -243,6 +243,7 @@ static inline void scorpion_pmnc_write(u32 val)
static inline u32 scorpion_pmnc_read(void)
{
u32 val;
+
asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
return val;
}
@@ -250,6 +251,7 @@ static inline u32 scorpion_pmnc_read(void)
static inline u32 scorpion_ccnt_read(void)
{
u32 val;
+
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
return val;
}
@@ -257,6 +259,7 @@ static inline u32 scorpion_ccnt_read(void)
static inline u32 scorpion_cntn_read(void)
{
u32 val;
+
asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
return val;
}
@@ -317,6 +320,7 @@ static inline int scorpion_pmnc_select_counter(unsigned int cnt)
static u32 scorpion_read_lpm0(void)
{
u32 val;
+
asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val));
return val;
}
@@ -329,6 +333,7 @@ static void scorpion_write_lpm0(u32 val)
static u32 scorpion_read_lpm1(void)
{
u32 val;
+
asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val));
return val;
}
@@ -341,6 +346,7 @@ static void scorpion_write_lpm1(u32 val)
static u32 scorpion_read_lpm2(void)
{
u32 val;
+
asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val));
return val;
}
@@ -353,6 +359,7 @@ static void scorpion_write_lpm2(u32 val)
static u32 scorpion_read_l2lpm(void)
{
u32 val;
+
asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val));
return val;
}
@@ -365,6 +372,7 @@ static void scorpion_write_l2lpm(u32 val)
static u32 scorpion_read_vlpm(void)
{
u32 val;
+
asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
return val;
}
@@ -375,7 +383,7 @@ static void scorpion_write_vlpm(u32 val)
}
struct scorpion_access_funcs {
- u32(*read)(void);
+ u32 (*read)(void);
void (*write)(u32);
};
@@ -420,17 +428,17 @@ static u32 scorpion_get_columnmask(u32 setval)
{
if (setval & COLMN0MASK)
return 0xffffff00;
- else if (setval & COLMN1MASK)
+ if (setval & COLMN1MASK)
return 0xffff00ff;
- else if (setval & COLMN2MASK)
+ if (setval & COLMN2MASK)
return 0xff00ffff;
- else
- return 0x80ffffff;
+ return 0x80ffffff;
}
static void scorpion_evt_setup(u32 gr, u32 setval)
{
u32 val;
+
if (gr == 4)
scorpion_pre_vlpm();
val = scorpion_get_columnmask(setval) & scor_func[gr].read();
@@ -443,6 +451,7 @@ static void scorpion_evt_setup(u32 gr, u32 setval)
static int get_scorpion_evtinfo(unsigned int evt_type, struct scorp_evt *evtinfo)
{
u32 idx;
+
if ((evt_type < 0x4c) || (evt_type >= MSM_MAX_EVT))
return 0;
idx = evt_type - 0x4c;
@@ -463,7 +472,7 @@ static inline void scorpion_pmnc_write_evtsel(unsigned int cnt, u32 val)
} else {
u32 zero = 0;
struct scorp_evt evtinfo;
- // extract evtinfo.grp and evtinfo.tevt_type_act from val
+ /* extract evtinfo.grp and evtinfo.tevt_type_act from val */
if (get_scorpion_evtinfo(val, &evtinfo) == 0)
return;
asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (evtinfo.evt_type_act));
@@ -505,20 +514,18 @@ static int gator_events_scorpion_create_files(struct super_block *sb, struct den
for (i = 0; i < pmnc_counters; i++) {
char buf[40];
- if (i == 0) {
- snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
- } else {
- snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1);
- }
+
+ if (i == 0)
+ snprintf(buf, sizeof(buf), "%s_ccnt", pmnc_name);
+ else
+ snprintf(buf, sizeof(buf), "%s_cnt%d", pmnc_name, i - 1);
dir = gatorfs_mkdir(sb, root, buf);
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
- if (i > 0) {
+ if (i > 0)
gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
- }
}
return 0;
@@ -528,9 +535,8 @@ static int gator_events_scorpion_online(int **buffer, bool migrate)
{
unsigned int cnt, len = 0, cpu = smp_processor_id();
- if (scorpion_pmnc_read() & PMNC_E) {
+ if (scorpion_pmnc_read() & PMNC_E)
scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
- }
/* Initialize & Reset PMNC: C bit and P bit */
scorpion_pmnc_write(PMNC_P | PMNC_C);
@@ -541,33 +547,32 @@ static int gator_events_scorpion_online(int **buffer, bool migrate)
if (!pmnc_enabled[cnt])
continue;
- // disable counter
+ /* disable counter */
scorpion_pmnc_disable_counter(cnt);
event = pmnc_event[cnt] & 255;
- // Set event (if destined for PMNx counters), We don't need to set the event if it's a cycle count
+ /* Set event (if destined for PMNx counters), We don't need to set the event if it's a cycle count */
if (cnt != CCNT)
scorpion_pmnc_write_evtsel(cnt, event);
- // reset counter
+ /* reset counter */
scorpion_pmnc_reset_counter(cnt);
- // Enable counter, do not enable interrupt for this counter
+ /* Enable counter, do not enable interrupt for this counter */
scorpion_pmnc_enable_counter(cnt);
}
- // enable
+ /* enable */
scorpion_pmnc_write(scorpion_pmnc_read() | PMNC_E);
- // read the counters and toss the invalid data, return zero instead
+ /* read the counters and toss the invalid data, return zero instead */
for (cnt = 0; cnt < pmnc_counters; cnt++) {
if (pmnc_enabled[cnt]) {
- if (cnt == CCNT) {
+ if (cnt == CCNT)
scorpion_ccnt_read();
- } else if (scorpion_pmnc_select_counter(cnt) == cnt) {
+ else if (scorpion_pmnc_select_counter(cnt) == cnt)
scorpion_cntn_read();
- }
scorpion_pmnc_reset_counter(cnt);
per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
@@ -597,26 +602,25 @@ static void gator_events_scorpion_stop(void)
}
}
-static int gator_events_scorpion_read(int **buffer)
+static int gator_events_scorpion_read(int **buffer, bool sched_switch)
{
int cnt, len = 0;
int cpu = smp_processor_id();
- // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
- if (!(scorpion_pmnc_read() & PMNC_E)) {
+ /* a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled */
+ if (!(scorpion_pmnc_read() & PMNC_E))
return 0;
- }
for (cnt = 0; cnt < pmnc_counters; cnt++) {
if (pmnc_enabled[cnt]) {
int value;
- if (cnt == CCNT) {
+
+ if (cnt == CCNT)
value = scorpion_ccnt_read();
- } else if (scorpion_pmnc_select_counter(cnt) == cnt) {
+ else if (scorpion_pmnc_select_counter(cnt) == cnt)
value = scorpion_cntn_read();
- } else {
+ else
value = 0;
- }
scorpion_pmnc_reset_counter(cnt);
per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
@@ -655,7 +659,8 @@ int gator_events_scorpion_init(void)
return -1;
}
- pmnc_counters++; // CNT[n] + CCNT
+ /* CNT[n] + CCNT */
+ pmnc_counters++;
for (cnt = CCNT; cnt < CNTMAX; cnt++) {
pmnc_enabled[cnt] = 0;
diff --git a/driver/gator_events_threads.c b/driver/gator_events_threads.c
deleted file mode 100644
index 9de8586..0000000
--- a/driver/gator_events_threads.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Sample activity provider
- *
- * Copyright (C) ARM Limited 2014. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * See gator_events_mmapped.c for additional directions and
- * troubleshooting.
- *
- * For this sample to work these entries must be present in the
- * events.xml file. So create an events-threads.xml in the gator
- * daemon source directory with the following contents and rebuild
- * gatord:
- *
- * <category name="threads">
- * <event counter="Linux_threads" title="Linux" name="Threads" class="activity" activity1="odd" activity_color1="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" description="Linux syscall activity"/>
- * </category>
- */
-
-#include <trace/events/sched.h>
-
-#include "gator.h"
-
-static ulong threads_enabled;
-static ulong threads_key;
-static ulong threads_cores;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
-#else
-GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
-#endif
-{
- int cpu = get_physical_cpu();
- int pid = next->pid;
- if (pid == 0) {
- // idle
- gator_marshal_activity_switch(cpu, threads_key, 0, 0);
- } else if (pid & 1) {
- // odd
- gator_marshal_activity_switch(cpu, threads_key, 1, pid);
- } else {
- // even
- //gator_marshal_activity_switch(cpu, threads_key, 2, current->pid);
- // Multiple activities are not yet supported so emit idle
- gator_marshal_activity_switch(cpu, threads_key, 0, 0);
- }
-}
-
-// Adds Linux_threads directory and enabled, key, and cores files to /dev/gator/events
-static int gator_events_threads_create_files(struct super_block *sb, struct dentry *root)
-{
- struct dentry *dir;
-
- dir = gatorfs_mkdir(sb, root, "Linux_threads");
- if (!dir) {
- return -1;
- }
- gatorfs_create_ulong(sb, dir, "enabled", &threads_enabled);
- gatorfs_create_ro_ulong(sb, dir, "key", &threads_key);
- // Number of cores associated with this activity
- gatorfs_create_ro_ulong(sb, dir, "cores", &threads_cores);
-
- return 0;
-}
-
-static int gator_events_threads_start(void)
-{
- int cpu;
-
- if (threads_enabled) {
- preempt_disable();
- for (cpu = 0; cpu < nr_cpu_ids; ++cpu) {
- gator_marshal_activity_switch(cpu, threads_key, 0, 0);
- }
- preempt_enable();
-
- if (GATOR_REGISTER_TRACE(sched_switch)) {
- goto fail_sched_switch;
- }
- }
-
- return 0;
-
-fail_sched_switch:
- return -1;
-}
-
-static void gator_events_threads_stop(void)
-{
- if (threads_enabled) {
- GATOR_UNREGISTER_TRACE(sched_switch);
- }
-
- threads_enabled = 0;
-}
-
-static struct gator_interface gator_events_threads_interface = {
- .create_files = gator_events_threads_create_files,
- .start = gator_events_threads_start,
- .stop = gator_events_threads_stop,
-};
-
-// Must not be static. Ensure that this init function is added to GATOR_EVENTS_LIST in gator_main.c
-int __init gator_events_threads_init(void)
-{
- threads_enabled = 0;
- threads_key = gator_events_get_key();
- threads_cores = nr_cpu_ids;
-
- return gator_events_install(&gator_events_threads_interface);
-}
diff --git a/driver/gator_fs.c b/driver/gator_fs.c
index 166cfe7..d8fb357 100644
--- a/driver/gator_fs.c
+++ b/driver/gator_fs.c
@@ -14,7 +14,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#define gatorfs_MAGIC 0x24051020
#define TMPBUFSIZE 50
@@ -43,6 +43,7 @@ static ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t
{
char tmpbuf[TMPBUFSIZE];
size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
+
if (maxlen > TMPBUFSIZE)
maxlen = TMPBUFSIZE;
return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
@@ -52,6 +53,7 @@ static ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff
{
char tmpbuf[TMPBUFSIZE];
size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%llu\n", val);
+
if (maxlen > TMPBUFSIZE)
maxlen = TMPBUFSIZE;
return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
@@ -104,12 +106,14 @@ static int gatorfs_u64_from_user(u64 *val, char const __user *buf, size_t count)
static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
unsigned long *val = file->private_data;
+
return gatorfs_ulong_to_user(*val, buf, count, offset);
}
static ssize_t u64_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
u64 *val = file->private_data;
+
return gatorfs_u64_to_user(*val, buf, count, offset);
}
@@ -231,7 +235,7 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
}
static int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root,
- char const *name, u64 * val)
+ char const *name, u64 *val)
{
struct dentry *d =
__gatorfs_create_file(sb, root, name, &u64_ro_fops, 0444);
@@ -245,6 +249,7 @@ static int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root,
static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
atomic_t *val = file->private_data;
+
return gatorfs_ulong_to_user(atomic_read(val), buf, count, offset);
}
diff --git a/driver/gator_hrtimer_gator.c b/driver/gator_hrtimer_gator.c
index 7658455..c1525e1 100644
--- a/driver/gator_hrtimer_gator.c
+++ b/driver/gator_hrtimer_gator.c
@@ -18,6 +18,7 @@ static void gator_hrtimer_offline(void);
static enum hrtimer_restart gator_hrtimer_notify(struct hrtimer *hrtimer)
{
int cpu = get_logical_cpu();
+
hrtimer_forward(hrtimer, per_cpu(hrtimer_expire, cpu), profiling_interval);
per_cpu(hrtimer_expire, cpu) = ktime_add(per_cpu(hrtimer_expire, cpu), profiling_interval);
(*callback)();
@@ -64,12 +65,11 @@ static int gator_hrtimer_init(int interval, void (*func)(void))
per_cpu(hrtimer_is_active, cpu) = 0;
}
- // calculate profiling interval
- if (interval > 0) {
+ /* calculate profiling interval */
+ if (interval > 0)
profiling_interval = ns_to_ktime(1000000000UL / interval);
- } else {
+ else
profiling_interval.tv64 = 0;
- }
return 0;
}
diff --git a/driver/gator_iks.c b/driver/gator_iks.c
index 9180b87..fb78c10 100644
--- a/driver/gator_iks.c
+++ b/driver/gator_iks.c
@@ -16,7 +16,7 @@
static bool map_cpuids;
static int mpidr_cpuids[NR_CPUS];
-static const struct gator_cpu * mpidr_cpus[NR_CPUS];
+static const struct gator_cpu *mpidr_cpus[NR_CPUS];
static int __lcpu_to_pcpu[NR_CPUS];
static const struct gator_cpu *gator_find_cpu_by_dt_name(const char *const name)
@@ -25,9 +25,9 @@ static const struct gator_cpu *gator_find_cpu_by_dt_name(const char *const name)
for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
const struct gator_cpu *const gator_cpu = &gator_cpus[i];
- if (gator_cpu->dt_name != NULL && strcmp(gator_cpu->dt_name, name) == 0) {
+
+ if (gator_cpu->dt_name != NULL && strcmp(gator_cpu->dt_name, name) == 0)
return gator_cpu;
- }
}
return NULL;
@@ -41,7 +41,7 @@ static void calc_first_cluster_size(void)
struct device_node *cn = NULL;
int mpidr_cpuids_count = 0;
- // Zero is a valid cpuid, so initialize the array to 0xff's
+ /* Zero is a valid cpuid, so initialize the array to 0xff's */
memset(&mpidr_cpuids, 0xff, sizeof(mpidr_cpuids));
memset(&mpidr_cpus, 0, sizeof(mpidr_cpus));
@@ -70,10 +70,10 @@ static void calc_first_cluster_size(void)
static int linearize_mpidr(int mpidr)
{
int i;
+
for (i = 0; i < nr_cpu_ids; ++i) {
- if (mpidr_cpuids[i] == mpidr) {
+ if (mpidr_cpuids[i] == mpidr)
return i;
- }
}
BUG();
@@ -113,6 +113,7 @@ static void gator_update_cpu_mapping(u32 cpu_hwid)
{
int lcpu = smp_processor_id();
int pcpu = linearize_mpidr(cpu_hwid & MPIDR_HWID_BITMASK);
+
BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0);
BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0);
__lcpu_to_pcpu[lcpu] = pcpu;
@@ -132,7 +133,7 @@ GATOR_DEFINE_PROBE(cpu_migrate_finish, TP_PROTO(u64 timestamp, u32 cpu_hwid))
gator_update_cpu_mapping(cpu_hwid);
- // get_physical_cpu must be called after gator_update_cpu_mapping
+ /* get_physical_cpu must be called after gator_update_cpu_mapping */
cpu = get_physical_cpu();
gator_timer_online_dispatch(cpu, true);
gator_timer_online((void *)1);
@@ -146,12 +147,11 @@ GATOR_DEFINE_PROBE(cpu_migrate_current, TP_PROTO(u64 timestamp, u32 cpu_hwid))
static void gator_send_iks_core_names(void)
{
int cpu;
- // Send the cpu names
+ /* Send the cpu names */
preempt_disable();
for (cpu = 0; cpu < nr_cpu_ids; ++cpu) {
- if (mpidr_cpus[cpu] != NULL) {
+ if (mpidr_cpus[cpu] != NULL)
gator_send_core_name(cpu, mpidr_cpus[cpu]->cpuid);
- }
}
preempt_enable();
}
@@ -170,7 +170,7 @@ static int gator_migrate_start(void)
if (retval == 0)
retval = GATOR_REGISTER_TRACE(cpu_migrate_current);
if (retval == 0) {
- // Initialize the logical to physical cpu mapping
+ /* Initialize the logical to physical cpu mapping */
memset(&__lcpu_to_pcpu, 0xff, sizeof(__lcpu_to_pcpu));
bL_switcher_trace_trigger();
}
diff --git a/driver/gator_main.c b/driver/gator_main.c
index 034c2ee..30bf60d 100644
--- a/driver/gator_main.c
+++ b/driver/gator_main.c
@@ -7,8 +7,8 @@
*
*/
-// This version must match the gator daemon version
-#define PROTOCOL_VERSION 19
+/* This version must match the gator daemon version */
+#define PROTOCOL_VERSION 20
static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#include <linux/slab.h>
@@ -25,7 +25,7 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#include <linux/utsname.h>
#include <linux/kthread.h>
#include <asm/stacktrace.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "gator.h"
@@ -67,11 +67,11 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#define SUMMARY_BUFFER_SIZE (1*1024)
#define BACKTRACE_BUFFER_SIZE (128*1024)
#define NAME_BUFFER_SIZE (64*1024)
-#define COUNTER_BUFFER_SIZE (64*1024) // counters have the core as part of the data and the core value in the frame header may be discarded
+#define COUNTER_BUFFER_SIZE (64*1024) /* counters have the core as part of the data and the core value in the frame header may be discarded */
#define BLOCK_COUNTER_BUFFER_SIZE (128*1024)
-#define ANNOTATE_BUFFER_SIZE (128*1024) // annotate counters have the core as part of the data and the core value in the frame header may be discarded
+#define ANNOTATE_BUFFER_SIZE (128*1024) /* annotate counters have the core as part of the data and the core value in the frame header may be discarded */
#define SCHED_TRACE_BUFFER_SIZE (128*1024)
-#define IDLE_BUFFER_SIZE (32*1024) // idle counters have the core as part of the data and the core value in the frame header may be discarded
+#define IDLE_BUFFER_SIZE (32*1024) /* idle counters have the core as part of the data and the core value in the frame header may be discarded */
#define ACTIVITY_BUFFER_SIZE (128*1024)
#define NO_COOKIE 0U
@@ -89,24 +89,24 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#define MESSAGE_END_BACKTRACE 1
-// Name Frame Messages
+/* Name Frame Messages */
#define MESSAGE_COOKIE 1
#define MESSAGE_THREAD_NAME 2
#define MESSAGE_LINK 4
-// Scheduler Trace Frame Messages
+/* Scheduler Trace Frame Messages */
#define MESSAGE_SCHED_SWITCH 1
#define MESSAGE_SCHED_EXIT 2
-// Idle Frame Messages
+/* Idle Frame Messages */
#define MESSAGE_IDLE_ENTER 1
#define MESSAGE_IDLE_EXIT 2
-// Summary Frame Messages
+/* Summary Frame Messages */
#define MESSAGE_SUMMARY 1
#define MESSAGE_CORE_NAME 3
-// Activity Frame Messages
+/* Activity Frame Messages */
#define MESSAGE_SWITCH 2
#define MESSAGE_EXIT 3
@@ -140,14 +140,15 @@ enum {
* Globals
******************************************************************************/
static unsigned long gator_cpu_cores;
-// Size of the largest buffer. Effectively constant, set in gator_op_create_files
+/* Size of the largest buffer. Effectively constant, set in gator_op_create_files */
static unsigned long userspace_buffer_size;
static unsigned long gator_backtrace_depth;
-// How often to commit the buffers for live in nanoseconds
+/* How often to commit the buffers for live in nanoseconds */
static u64 gator_live_rate;
static unsigned long gator_started;
static u64 gator_monotonic_started;
+static u64 gator_sync_time;
static u64 gator_hibernate_time;
static unsigned long gator_buffer_opened;
static unsigned long gator_timer_count;
@@ -161,7 +162,7 @@ static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait);
static struct timer_list gator_buffer_wake_up_timer;
static bool gator_buffer_wake_run;
-// Initialize semaphore unlocked to initialize memory values
+/* Initialize semaphore unlocked to initialize memory values */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
static DECLARE_MUTEX(gator_buffer_wake_sem);
#else
@@ -183,33 +184,43 @@ static DEFINE_PER_CPU(bool, in_scheduler_context);
* Prototypes
******************************************************************************/
static u64 gator_get_time(void);
+static void gator_emit_perf_time(u64 time);
static void gator_op_create_files(struct super_block *sb, struct dentry *root);
-// gator_buffer is protected by being per_cpu and by having IRQs disabled when writing to it.
-// Most marshal_* calls take care of this except for marshal_cookie*, marshal_backtrace* and marshal_frame where the caller is responsible for doing so.
-// No synchronization is needed with the backtrace buffer as it is per cpu and is only used from the hrtimer.
-// The annotate_lock must be held when using the annotation buffer as it is not per cpu.
-// collect_counters which is the sole writer to the block counter frame is additionally protected by the per cpu collecting flag
+/* gator_buffer is protected by being per_cpu and by having IRQs
+ * disabled when writing to it. Most marshal_* calls take care of this
+ * except for marshal_cookie*, marshal_backtrace* and marshal_frame
+ * where the caller is responsible for doing so. No synchronization is
+ * needed with the backtrace buffer as it is per cpu and is only used
+ * from the hrtimer. The annotate_lock must be held when using the
+ * annotation buffer as it is not per cpu. collect_counters which is
+ * the sole writer to the block counter frame is additionally
+ * protected by the per cpu collecting flag.
+ */
-// Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup.
+/* Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup. */
static uint32_t gator_buffer_size[NUM_GATOR_BUFS];
-// gator_buffer_size - 1, bitwise and with pos to get offset into the array. Effectively constant, set in gator_op_setup.
+/* gator_buffer_size - 1, bitwise and with pos to get offset into the array. Effectively constant, set in gator_op_setup. */
static uint32_t gator_buffer_mask[NUM_GATOR_BUFS];
-// Read position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are read by userspace in userspace_buffer_read
+/* Read position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are read by userspace in userspace_buffer_read */
static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_read);
-// Write position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are written to the buffer
+/* Write position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are written to the buffer */
static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_write);
-// Commit position in the buffer. Initialized to zero in gator_op_setup and incremented after a frame is ready to be read by userspace
+/* Commit position in the buffer. Initialized to zero in gator_op_setup and incremented after a frame is ready to be read by userspace */
static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_commit);
-// If set to false, decreases the number of bytes returned by buffer_bytes_available. Set in buffer_check_space if no space is remaining. Initialized to true in gator_op_setup
-// This means that if we run out of space, continue to report that no space is available until bytes are read by userspace
+/* If set to false, decreases the number of bytes returned by
+ * buffer_bytes_available. Set in buffer_check_space if no space is
+ * remaining. Initialized to true in gator_op_setup. This means that
+ * if we run out of space, continue to report that no space is
+ * available until bytes are read by userspace
+ */
static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], buffer_space_available);
-// The buffer. Allocated in gator_op_setup
+/* The buffer. Allocated in gator_op_setup */
static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer);
-// The time after which the buffer should be committed for live display
+/* The time after which the buffer should be committed for live display */
static DEFINE_PER_CPU(u64, gator_buffer_commit_time);
-// List of all gator events - new events must be added to this list
+/* List of all gator events - new events must be added to this list */
#define GATOR_EVENTS_LIST \
GATOR_EVENT(gator_events_armv6_init) \
GATOR_EVENT(gator_events_armv7_init) \
@@ -226,7 +237,6 @@ static DEFINE_PER_CPU(u64, gator_buffer_commit_time);
GATOR_EVENT(gator_events_perf_pmu_init) \
GATOR_EVENT(gator_events_sched_init) \
GATOR_EVENT(gator_events_scorpion_init) \
- GATOR_EVENT(gator_events_threads_init) \
#define GATOR_EVENT(EVENT_INIT) __weak int EVENT_INIT(void);
GATOR_EVENTS_LIST
@@ -315,13 +325,6 @@ static const struct gator_cpu gator_cpus[] = {
.pmnc_counters = 6,
},
{
- .cpuid = CORTEX_A12,
- .core_name = "Cortex-A12",
- .pmnc_name = "ARMv7_Cortex_A12",
- .dt_name = "arm,cortex-a12",
- .pmnc_counters = 6,
- },
- {
.cpuid = CORTEX_A15,
.core_name = "Cortex-A15",
.pmnc_name = "ARMv7_Cortex_A15",
@@ -400,23 +403,32 @@ const struct gator_cpu *gator_find_cpu_by_cpuid(const u32 cpuid)
for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
const struct gator_cpu *const gator_cpu = &gator_cpus[i];
- if (gator_cpu->cpuid == cpuid) {
+
+ if (gator_cpu->cpuid == cpuid)
return gator_cpu;
- }
}
return NULL;
}
+static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
+static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_";
+
const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name)
{
int i;
for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
const struct gator_cpu *const gator_cpu = &gator_cpus[i];
- if (gator_cpu->pmnc_name != NULL && strcmp(gator_cpu->pmnc_name, name) == 0) {
+
+ if (gator_cpu->pmnc_name != NULL &&
+ /* Do the names match exactly? */
+ (strcasecmp(gator_cpu->pmnc_name, name) == 0 ||
+ /* Do these names match but have the old vs new prefix? */
+ ((strncasecmp(name, OLD_PMU_PREFIX, sizeof(OLD_PMU_PREFIX) - 1) == 0 &&
+ strncasecmp(gator_cpu->pmnc_name, NEW_PMU_PREFIX, sizeof(NEW_PMU_PREFIX) - 1) == 0 &&
+ strcasecmp(name + sizeof(OLD_PMU_PREFIX) - 1, gator_cpu->pmnc_name + sizeof(NEW_PMU_PREFIX) - 1) == 0))))
return gator_cpu;
- }
}
return NULL;
@@ -445,16 +457,15 @@ static void gator_buffer_wake_up(unsigned long data)
static int gator_buffer_wake_func(void *data)
{
for (;;) {
- if (down_killable(&gator_buffer_wake_sem)) {
+ if (down_killable(&gator_buffer_wake_sem))
break;
- }
- // Eat up any pending events
- while (!down_trylock(&gator_buffer_wake_sem));
+ /* Eat up any pending events */
+ while (!down_trylock(&gator_buffer_wake_sem))
+ ;
- if (!gator_buffer_wake_run) {
+ if (!gator_buffer_wake_run)
break;
- }
gator_buffer_wake_up(0);
}
@@ -468,6 +479,7 @@ static int gator_buffer_wake_func(void *data)
static bool buffer_commit_ready(int *cpu, int *buftype)
{
int cpu_x, x;
+
for_each_present_cpu(cpu_x) {
for (x = 0; x < NUM_GATOR_BUFS; x++)
if (per_cpu(gator_buffer_commit, cpu_x)[x] != per_cpu(gator_buffer_read, cpu_x)[x]) {
@@ -487,6 +499,7 @@ static bool buffer_commit_ready(int *cpu, int *buftype)
static void gator_timer_interrupt(void)
{
struct pt_regs *const regs = get_irq_regs();
+
gator_backtrace_handler(regs);
}
@@ -495,15 +508,14 @@ void gator_backtrace_handler(struct pt_regs *const regs)
u64 time = gator_get_time();
int cpu = get_physical_cpu();
- // Output backtrace
+ /* Output backtrace */
gator_add_sample(cpu, regs, time);
- // Collect counters
- if (!per_cpu(collecting, cpu)) {
- collect_counters(time, NULL);
- }
+ /* Collect counters */
+ if (!per_cpu(collecting, cpu))
+ collect_counters(time, current, false);
- // No buffer flushing occurs during sched switch for RT-Preempt full. The block counter frame will be flushed by collect_counters, but the sched buffer needs to be explicitly flushed
+ /* No buffer flushing occurs during sched switch for RT-Preempt full. The block counter frame will be flushed by collect_counters, but the sched buffer needs to be explicitly flushed */
#ifdef CONFIG_PREEMPT_RT_FULL
buffer_check(cpu, SCHED_TRACE_BUF, time);
#endif
@@ -511,7 +523,7 @@ void gator_backtrace_handler(struct pt_regs *const regs)
static int gator_running;
-// This function runs in interrupt context and on the appropriate core
+/* This function runs in interrupt context and on the appropriate core */
static void gator_timer_offline(void *migrate)
{
struct gator_interface *gi;
@@ -522,11 +534,10 @@ static void gator_timer_offline(void *migrate)
gator_trace_sched_offline();
gator_trace_power_offline();
- if (!migrate) {
+ if (!migrate)
gator_hrtimer_offline();
- }
- // Offline any events and output counters
+ /* Offline any events and output counters */
time = gator_get_time();
if (marshal_event_header(time)) {
list_for_each_entry(gi, &gator_events, list) {
@@ -535,24 +546,23 @@ static void gator_timer_offline(void *migrate)
marshal_event(len, buffer);
}
}
- // Only check after writing all counters so that time and corresponding counters appear in the same frame
+ /* Only check after writing all counters so that time and corresponding counters appear in the same frame */
buffer_check(cpu, BLOCK_COUNTER_BUF, time);
}
- // Flush all buffers on this core
+ /* Flush all buffers on this core */
for (i = 0; i < NUM_GATOR_BUFS; i++)
gator_commit_buffer(cpu, i, time);
}
-// This function runs in interrupt context and may be running on a core other than core 'cpu'
+/* This function runs in interrupt context and may be running on a core other than core 'cpu' */
static void gator_timer_offline_dispatch(int cpu, bool migrate)
{
struct gator_interface *gi;
list_for_each_entry(gi, &gator_events, list) {
- if (gi->offline_dispatch) {
+ if (gi->offline_dispatch)
gi->offline_dispatch(cpu, migrate);
- }
}
}
@@ -579,16 +589,15 @@ static void gator_send_core_name(const int cpu, const u32 cpuid)
const char *core_name = NULL;
char core_name_buf[32];
- // Save off this cpuid
+ /* Save off this cpuid */
gator_cpuids[cpu] = cpuid;
if (gator_cpu != NULL) {
core_name = gator_cpu->core_name;
} else {
- if (cpuid == -1) {
+ if (cpuid == -1)
snprintf(core_name_buf, sizeof(core_name_buf), "Unknown");
- } else {
+ else
snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.3x)", cpuid);
- }
core_name = core_name_buf;
}
@@ -598,12 +607,12 @@ static void gator_send_core_name(const int cpu, const u32 cpuid)
#endif
}
-static void gator_read_cpuid(void * arg)
+static void gator_read_cpuid(void *arg)
{
gator_cpuids[get_physical_cpu()] = gator_cpuid();
}
-// This function runs in interrupt context and on the appropriate core
+/* This function runs in interrupt context and on the appropriate core */
static void gator_timer_online(void *migrate)
{
struct gator_interface *gi;
@@ -611,12 +620,12 @@ static void gator_timer_online(void *migrate)
int *buffer;
u64 time;
- // Send what is currently running on this core
+ /* Send what is currently running on this core */
marshal_sched_trace_switch(current->pid, 0);
gator_trace_power_online();
- // online any events and output counters
+ /* online any events and output counters */
time = gator_get_time();
if (marshal_event_header(time)) {
list_for_each_entry(gi, &gator_events, list) {
@@ -625,26 +634,24 @@ static void gator_timer_online(void *migrate)
marshal_event(len, buffer);
}
}
- // Only check after writing all counters so that time and corresponding counters appear in the same frame
+ /* Only check after writing all counters so that time and corresponding counters appear in the same frame */
buffer_check(cpu, BLOCK_COUNTER_BUF, time);
}
- if (!migrate) {
+ if (!migrate)
gator_hrtimer_online();
- }
gator_send_core_name(cpu, gator_cpuid());
}
-// This function runs in interrupt context and may be running on a core other than core 'cpu'
+/* This function runs in interrupt context and may be running on a core other than core 'cpu' */
static void gator_timer_online_dispatch(int cpu, bool migrate)
{
struct gator_interface *gi;
list_for_each_entry(gi, &gator_events, list) {
- if (gi->online_dispatch) {
+ if (gi->online_dispatch)
gi->online_dispatch(cpu, migrate);
- }
}
}
@@ -661,15 +668,14 @@ static int gator_timer_start(unsigned long sample_rate)
gator_running = 1;
- // event based sampling trumps hr timer based sampling
- if (event_based_sampling) {
+ /* event based sampling trumps hr timer based sampling */
+ if (event_based_sampling)
sample_rate = 0;
- }
if (gator_hrtimer_init(sample_rate, gator_timer_interrupt) == -1)
return -1;
- // Send off the previously saved cpuids
+ /* Send off the previously saved cpuids */
for_each_present_cpu(cpu) {
preempt_disable();
gator_send_core_name(cpu, gator_cpuids[cpu]);
@@ -693,21 +699,24 @@ static u64 gator_get_time(void)
u64 delta;
int cpu = smp_processor_id();
- // Match clock_gettime(CLOCK_MONOTONIC_RAW, &ts) from userspace
+ /* Match clock_gettime(CLOCK_MONOTONIC_RAW, &ts) from userspace */
getrawmonotonic(&ts);
timestamp = timespec_to_ns(&ts);
- // getrawmonotonic is not monotonic on all systems. Detect and attempt to correct these cases.
- // up to 0.5ms delta has been seen on some systems, which can skew Streamline data when viewing at high resolution.
- // This doesn't work well with interrupts, but that it's OK - the real concern is to catch big jumps in time
+ /* getrawmonotonic is not monotonic on all systems. Detect and
+ * attempt to correct these cases. up to 0.5ms delta has been seen
+ * on some systems, which can skew Streamline data when viewing at
+ * high resolution. This doesn't work well with interrupts, but that
+ * it's OK - the real concern is to catch big jumps in time
+ */
prev_timestamp = per_cpu(last_timestamp, cpu);
if (prev_timestamp <= timestamp) {
per_cpu(last_timestamp, cpu) = timestamp;
} else {
delta = prev_timestamp - timestamp;
- // Log the error once
+ /* Log the error once */
if (!printed_monotonic_warning && delta > 500000) {
- printk(KERN_ERR "%s: getrawmonotonic is not monotonic cpu: %i delta: %lli\nSkew in Streamline data may be present at the fine zoom levels\n", __FUNCTION__, cpu, delta);
+ pr_err("%s: getrawmonotonic is not monotonic cpu: %i delta: %lli\nSkew in Streamline data may be present at the fine zoom levels\n", __func__, cpu, delta);
printed_monotonic_warning = true;
}
timestamp = prev_timestamp;
@@ -716,6 +725,19 @@ static u64 gator_get_time(void)
return timestamp - gator_monotonic_started;
}
+static void gator_emit_perf_time(u64 time)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ if (time >= gator_sync_time) {
+ int cpu = get_physical_cpu();
+
+ marshal_event_single64(0, -1, local_clock());
+ gator_sync_time += NSEC_PER_SEC;
+ gator_commit_buffer(cpu, COUNTER_BUF, time);
+ }
+#endif
+}
+
/******************************************************************************
* cpu hotplug and pm notifiers
******************************************************************************/
@@ -743,8 +765,10 @@ static struct notifier_block __refdata gator_hotcpu_notifier = {
.notifier_call = gator_hotcpu_notify,
};
-// n.b. calling "on_each_cpu" only runs on those that are online
-// Registered linux events are not disabled, so their counters will continue to collect
+/* n.b. calling "on_each_cpu" only runs on those that are online.
+ * Registered linux events are not disabled, so their counters will
+ * continue to collect
+ */
static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy)
{
int cpu;
@@ -760,13 +784,13 @@ static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void
gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false);
}
- // Record the wallclock hibernate time
+ /* Record the wallclock hibernate time */
getnstimeofday(&ts);
gator_hibernate_time = timespec_to_ns(&ts) - gator_get_time();
break;
case PM_POST_HIBERNATION:
case PM_POST_SUSPEND:
- // Adjust gator_monotonic_started for the time spent sleeping, as gator_get_time does not account for it
+ /* Adjust gator_monotonic_started for the time spent sleeping, as gator_get_time does not account for it */
if (gator_hibernate_time > 0) {
getnstimeofday(&ts);
gator_monotonic_started += gator_hibernate_time + gator_get_time() - timespec_to_ns(&ts);
@@ -792,6 +816,7 @@ static struct notifier_block gator_pm_notifier = {
static int gator_notifier_start(void)
{
int retval;
+
retval = register_hotcpu_notifier(&gator_hotcpu_notifier);
if (retval == 0)
retval = register_pm_notifier(&gator_pm_notifier);
@@ -812,28 +837,37 @@ static void gator_summary(void)
u64 timestamp, uptime;
struct timespec ts;
char uname_buf[512];
- void (*m2b)(struct timespec *ts);
snprintf(uname_buf, sizeof(uname_buf), "%s %s %s %s %s GNU/Linux", utsname()->sysname, utsname()->nodename, utsname()->release, utsname()->version, utsname()->machine);
getnstimeofday(&ts);
timestamp = timespec_to_ns(&ts);
- do_posix_clock_monotonic_gettime(&ts);
- // monotonic_to_bootbased is not defined for some versions of Android
- m2b = symbol_get(monotonic_to_bootbased);
- if (m2b) {
- m2b(&ts);
+ /* Similar to reading /proc/uptime from fs/proc/uptime.c, calculate uptime */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
+ {
+ void (*m2b)(struct timespec *ts);
+
+ do_posix_clock_monotonic_gettime(&ts);
+ /* monotonic_to_bootbased is not defined for some versions of Android */
+ m2b = symbol_get(monotonic_to_bootbased);
+ if (m2b)
+ m2b(&ts);
}
+#else
+ get_monotonic_boottime(&ts);
+#endif
uptime = timespec_to_ns(&ts);
- // Disable preemption as gator_get_time calls smp_processor_id to verify time is monotonic
+ /* Disable preemption as gator_get_time calls smp_processor_id to verify time is monotonic */
preempt_disable();
- // Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started
+ /* Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started */
gator_monotonic_started = 0;
gator_monotonic_started = gator_get_time();
marshal_summary(timestamp, uptime, gator_monotonic_started, uname_buf);
+ gator_sync_time = 0;
+ gator_emit_perf_time(gator_monotonic_started);
preempt_enable();
}
@@ -846,12 +880,14 @@ int gator_events_install(struct gator_interface *interface)
int gator_events_get_key(void)
{
- // key 0 is reserved as a timestamp
- // key 1 is reserved as the marker for thread specific counters
- // Odd keys are assigned by the driver, even keys by the daemon
+ /* key 0 is reserved as a timestamp. key 1 is reserved as the marker
+ * for thread specific counters. key 2 is reserved as the marker for
+ * core. Odd keys are assigned by the driver, even keys by the
+ * daemon.
+ */
static int key = 3;
-
const int ret = key;
+
key += 2;
return ret;
}
@@ -862,7 +898,7 @@ static int gator_init(void)
calc_first_cluster_size();
- // events sources
+ /* events sources */
for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
if (gator_events_list[i])
gator_events_list[i]();
@@ -888,26 +924,25 @@ static int gator_start(void)
struct gator_interface *gi;
gator_buffer_wake_run = true;
- if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) {
+ gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake");
+ if (IS_ERR(gator_buffer_wake_thread))
goto bwake_failure;
- }
if (gator_migrate_start())
goto migrate_failure;
- // Initialize the buffer with the frame type and core
+ /* Initialize the buffer with the frame type and core */
for_each_present_cpu(cpu) {
- for (i = 0; i < NUM_GATOR_BUFS; i++) {
+ for (i = 0; i < NUM_GATOR_BUFS; i++)
marshal_frame(cpu, i);
- }
per_cpu(last_timestamp, cpu) = 0;
}
printed_monotonic_warning = false;
- // Capture the start time
+ /* Capture the start time */
gator_summary();
- // start all events
+ /* start all events */
list_for_each_entry(gi, &gator_events, list) {
if (gi->start && gi->start() != 0) {
struct list_head *ptr = gi->list.prev;
@@ -924,7 +959,7 @@ static int gator_start(void)
}
}
- // cookies shall be initialized before trace_sched_start() and gator_timer_start()
+ /* cookies shall be initialized before trace_sched_start() and gator_timer_start() */
if (cookies_initialize())
goto cookies_failure;
if (gator_annotate_start())
@@ -955,7 +990,7 @@ sched_failure:
annotate_failure:
cookies_release();
cookies_failure:
- // stop all events
+ /* stop all events */
list_for_each_entry(gi, &gator_events, list)
if (gi->stop)
gi->stop();
@@ -979,11 +1014,11 @@ static void gator_stop(void)
gator_trace_power_stop();
gator_trace_gpu_stop();
- // stop all interrupt callback reads before tearing down other interfaces
- gator_notifier_stop(); // should be called before gator_timer_stop to avoid re-enabling the hrtimer after it has been offlined
+ /* stop all interrupt callback reads before tearing down other interfaces */
+ gator_notifier_stop(); /* should be called before gator_timer_stop to avoid re-enabling the hrtimer after it has been offlined */
gator_timer_stop();
- // stop all events
+ /* stop all events */
list_for_each_entry(gi, &gator_events, list)
if (gi->stop)
gi->stop();
@@ -1033,9 +1068,9 @@ static int gator_op_setup(void)
gator_buffer_size[ACTIVITY_BUF] = ACTIVITY_BUFFER_SIZE;
gator_buffer_mask[ACTIVITY_BUF] = ACTIVITY_BUFFER_SIZE - 1;
- // Initialize percpu per buffer variables
+ /* Initialize percpu per buffer variables */
for (i = 0; i < NUM_GATOR_BUFS; i++) {
- // Verify buffers are a power of 2
+ /* Verify buffers are a power of 2 */
if (gator_buffer_size[i] & (gator_buffer_size[i] - 1)) {
err = -ENOEXEC;
goto setup_error;
@@ -1048,7 +1083,7 @@ static int gator_op_setup(void)
per_cpu(buffer_space_available, cpu)[i] = true;
per_cpu(gator_buffer_commit_time, cpu) = gator_live_rate;
- // Annotation is a special case that only uses a single buffer
+ /* Annotation is a special case that only uses a single buffer */
if (cpu > 0 && i == ANNOTATE_BUF) {
per_cpu(gator_buffer, cpu)[i] = NULL;
continue;
@@ -1188,7 +1223,8 @@ static int userspace_buffer_open(struct inode *inode, struct file *file)
if (test_and_set_bit_lock(0, &gator_buffer_opened))
return -EBUSY;
- if ((err = gator_op_setup()))
+ err = gator_op_setup();
+ if (err)
goto fail;
/* NB: the actual start happens from userspace
@@ -1218,22 +1254,20 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t
int cpu, buftype;
int written = 0;
- // ensure there is enough space for a whole frame
- if (count < userspace_buffer_size || *offset) {
+ /* ensure there is enough space for a whole frame */
+ if (count < userspace_buffer_size || *offset)
return -EINVAL;
- }
- // sleep until the condition is true or a signal is received
- // the condition is checked each time gator_buffer_wait is woken up
+ /* sleep until the condition is true or a signal is received the
+ * condition is checked each time gator_buffer_wait is woken up
+ */
wait_event_interruptible(gator_buffer_wait, buffer_commit_ready(&cpu, &buftype) || !gator_started);
- if (signal_pending(current)) {
+ if (signal_pending(current))
return -EINTR;
- }
- if (buftype == -1 || cpu == -1) {
+ if (buftype == -1 || cpu == -1)
return 0;
- }
mutex_lock(&gator_buffer_mutex);
@@ -1241,12 +1275,11 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t
read = per_cpu(gator_buffer_read, cpu)[buftype];
commit = per_cpu(gator_buffer_commit, cpu)[buftype];
- // May happen if the buffer is freed during pending reads.
- if (!per_cpu(gator_buffer, cpu)[buftype]) {
+ /* May happen if the buffer is freed during pending reads. */
+ if (!per_cpu(gator_buffer, cpu)[buftype])
break;
- }
- // determine the size of two halves
+ /* determine the size of two halves */
length1 = commit - read;
length2 = 0;
buffer1 = &(per_cpu(gator_buffer, cpu)[buftype][read]);
@@ -1256,32 +1289,28 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t
length2 = commit;
}
- if (length1 + length2 > count - written) {
+ if (length1 + length2 > count - written)
break;
- }
- // start, middle or end
- if (length1 > 0 && copy_to_user(&buf[written], buffer1, length1)) {
+ /* start, middle or end */
+ if (length1 > 0 && copy_to_user(&buf[written], buffer1, length1))
break;
- }
- // possible wrap around
- if (length2 > 0 && copy_to_user(&buf[written + length1], buffer2, length2)) {
+ /* possible wrap around */
+ if (length2 > 0 && copy_to_user(&buf[written + length1], buffer2, length2))
break;
- }
per_cpu(gator_buffer_read, cpu)[buftype] = commit;
written += length1 + length2;
- // Wake up annotate_write if more space is available
- if (buftype == ANNOTATE_BUF) {
+ /* Wake up annotate_write if more space is available */
+ if (buftype == ANNOTATE_BUF)
wake_up(&gator_annotate_wait);
- }
} while (buffer_commit_ready(&cpu, &buftype));
mutex_unlock(&gator_buffer_mutex);
- // kick just in case we've lost an SMP event
+ /* kick just in case we've lost an SMP event */
wake_up(&gator_buffer_wait);
return written > 0 ? written : -EFAULT;
@@ -1348,19 +1377,19 @@ static void gator_op_create_files(struct super_block *sb, struct dentry *root)
gatorfs_create_ro_u64(sb, root, "started", &gator_monotonic_started);
gatorfs_create_u64(sb, root, "live_rate", &gator_live_rate);
- // Annotate interface
+ /* Annotate interface */
gator_annotate_create_files(sb, root);
- // Linux Events
+ /* Linux Events */
dir = gatorfs_mkdir(sb, root, "events");
list_for_each_entry(gi, &gator_events, list)
if (gi->create_files)
gi->create_files(sb, dir);
- // Sched Events
+ /* Sched Events */
sched_trace_create_files(sb, dir);
- // Power interface
+ /* Power interface */
gator_trace_power_create_files(sb, dir);
}
@@ -1396,19 +1425,22 @@ static void gator_op_create_files(struct super_block *sb, struct dentry *root)
GATOR_HANDLE_TRACEPOINT(sched_process_free); \
GATOR_HANDLE_TRACEPOINT(sched_switch); \
GATOR_HANDLE_TRACEPOINT(softirq_exit); \
+ GATOR_HANDLE_TRACEPOINT(task_rename); \
#define GATOR_HANDLE_TRACEPOINT(probe_name) \
struct tracepoint *gator_tracepoint_##probe_name
GATOR_TRACEPOINTS;
#undef GATOR_HANDLE_TRACEPOINT
-static void gator_fct(struct tracepoint *tp, void *priv)
+static void gator_save_tracepoint(struct tracepoint *tp, void *priv)
{
#define GATOR_HANDLE_TRACEPOINT(probe_name) \
- if (strcmp(tp->name, #probe_name) == 0) { \
- gator_tracepoint_##probe_name = tp; \
- return; \
- }
+ do { \
+ if (strcmp(tp->name, #probe_name) == 0) { \
+ gator_tracepoint_##probe_name = tp; \
+ return; \
+ } \
+ } while (0)
GATOR_TRACEPOINTS;
#undef GATOR_HANDLE_TRACEPOINT
}
@@ -1421,11 +1453,10 @@ GATOR_TRACEPOINTS;
static int __init gator_module_init(void)
{
- for_each_kernel_tracepoint(gator_fct, NULL);
+ for_each_kernel_tracepoint(gator_save_tracepoint, NULL);
- if (gatorfs_register()) {
+ if (gatorfs_register())
return -1;
- }
if (gator_init()) {
gatorfs_unregister();
@@ -1434,7 +1465,7 @@ static int __init gator_module_init(void)
setup_timer(&gator_buffer_wake_up_timer, gator_buffer_wake_up, 0);
- // Initialize the list of cpuids
+ /* Initialize the list of cpuids */
memset(gator_cpuids, -1, sizeof(gator_cpuids));
on_each_cpu(gator_read_cpuid, NULL, 1);
diff --git a/driver/gator_marshaling.c b/driver/gator_marshaling.c
index 31af325..0d11676 100644
--- a/driver/gator_marshaling.c
+++ b/driver/gator_marshaling.c
@@ -23,7 +23,7 @@
#include "gator_events_mali_common.h"
#endif
-static void marshal_summary(long long timestamp, long long uptime, long long monotonic_delta, const char * uname)
+static void marshal_summary(long long timestamp, long long uptime, long long monotonic_delta, const char *uname)
{
unsigned long flags;
int cpu = 0;
@@ -40,7 +40,15 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
gator_buffer_write_string(cpu, SUMMARY_BUF, "iks");
gator_buffer_write_string(cpu, SUMMARY_BUF, "");
#endif
- // Let Streamline know which GPU is used so that it can label the GPU Activity appropriately. This is a temporary fix, to be improved in a future release.
+#ifdef CONFIG_PREEMPT_RTB
+ gator_buffer_write_string(cpu, SUMMARY_BUF, "preempt_rtb");
+ gator_buffer_write_string(cpu, SUMMARY_BUF, "");
+#endif
+#ifdef CONFIG_PREEMPT_RT_FULL
+ gator_buffer_write_string(cpu, SUMMARY_BUF, "preempt_rt_full");
+ gator_buffer_write_string(cpu, SUMMARY_BUF, "");
+#endif
+ /* Let Streamline know which GPU is used so that it can label the GPU Activity appropriately. This is a temporary fix, to be improved in a future release. */
#ifdef MALI_SUPPORT
gator_buffer_write_string(cpu, SUMMARY_BUF, "mali_type");
#if (MALI_SUPPORT == MALI_4xx)
@@ -52,7 +60,7 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
#endif
#endif
gator_buffer_write_string(cpu, SUMMARY_BUF, "");
- // Commit the buffer now so it can be one of the first frames read by Streamline
+ /* Commit the buffer now so it can be one of the first frames read by Streamline */
local_irq_restore(flags);
gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
}
@@ -60,13 +68,14 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon
static bool marshal_cookie_header(const char *text)
{
int cpu = get_physical_cpu();
+
return buffer_check_space(cpu, NAME_BUF, strlen(text) + 3 * MAXSIZE_PACK32);
}
static void marshal_cookie(int cookie, const char *text)
{
int cpu = get_physical_cpu();
- // buffer_check_space already called by marshal_cookie_header
+ /* buffer_check_space already called by marshal_cookie_header */
gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_COOKIE);
gator_buffer_write_packed_int(cpu, NAME_BUF, cookie);
gator_buffer_write_string(cpu, NAME_BUF, text);
@@ -77,6 +86,7 @@ static void marshal_thread_name(int pid, char *name)
{
unsigned long flags, cpu;
u64 time;
+
local_irq_save(flags);
cpu = get_physical_cpu();
time = gator_get_time();
@@ -105,15 +115,16 @@ static void marshal_link(int cookie, int tgid, int pid)
gator_buffer_write_packed_int(cpu, NAME_BUF, pid);
}
local_irq_restore(flags);
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, NAME_BUF, time);
}
static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, u64 time)
{
int cpu = get_physical_cpu();
+
if (!buffer_check_space(cpu, BACKTRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32 + gator_backtrace_depth * 2 * MAXSIZE_PACK32)) {
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, BACKTRACE_BUF, time);
return false;
@@ -130,9 +141,9 @@ static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, u64 tim
static void marshal_backtrace(unsigned long address, int cookie, int in_kernel)
{
int cpu = get_physical_cpu();
- if (cookie == 0 && !in_kernel) {
+
+ if (cookie == 0 && !in_kernel)
cookie = UNRESOLVED_COOKIE;
- }
gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie);
gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, address);
}
@@ -140,9 +151,10 @@ static void marshal_backtrace(unsigned long address, int cookie, int in_kernel)
static void marshal_backtrace_footer(u64 time)
{
int cpu = get_physical_cpu();
+
gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_END_BACKTRACE);
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, BACKTRACE_BUF, time);
}
@@ -153,7 +165,7 @@ static bool marshal_event_header(u64 time)
local_irq_save(flags);
if (buffer_check_space(cpu, BLOCK_COUNTER_BUF, MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
- gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, 0); // key of zero indicates a timestamp
+ gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, 0); /* key of zero indicates a timestamp */
gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, time);
retval = true;
}
@@ -169,18 +181,17 @@ static void marshal_event(int len, int *buffer)
if (len <= 0)
return;
- // length must be even since all data is a (key, value) pair
+ /* length must be even since all data is a (key, value) pair */
if (len & 0x1) {
- pr_err("gator: invalid counter data detected and discarded");
+ pr_err("gator: invalid counter data detected and discarded\n");
return;
}
- // events must be written in key,value pairs
+ /* events must be written in key,value pairs */
local_irq_save(flags);
for (i = 0; i < len; i += 2) {
- if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK32)) {
+ if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK32))
break;
- }
gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i]);
gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i + 1]);
}
@@ -194,26 +205,24 @@ static void marshal_event64(int len, long long *buffer64)
if (len <= 0)
return;
- // length must be even since all data is a (key, value) pair
+ /* length must be even since all data is a (key, value) pair */
if (len & 0x1) {
- pr_err("gator: invalid counter data detected and discarded");
+ pr_err("gator: invalid counter data detected and discarded\n");
return;
}
- // events must be written in key,value pairs
+ /* events must be written in key,value pairs */
local_irq_save(flags);
for (i = 0; i < len; i += 2) {
- if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK64)) {
+ if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK64))
break;
- }
gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i]);
gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i + 1]);
}
local_irq_restore(flags);
}
-#if GATOR_CPU_FREQ_SUPPORT
-static void marshal_event_single(int core, int key, int value)
+static void __maybe_unused marshal_event_single(int core, int key, int value)
{
unsigned long flags, cpu;
u64 time;
@@ -228,11 +237,11 @@ static void marshal_event_single(int core, int key, int value)
gator_buffer_write_packed_int(cpu, COUNTER_BUF, value);
}
local_irq_restore(flags);
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, COUNTER_BUF, time);
}
-static void marshal_event_single64(int core, int key, long long value)
+static void __maybe_unused marshal_event_single64(int core, int key, long long value)
{
unsigned long flags, cpu;
u64 time;
@@ -247,10 +256,9 @@ static void marshal_event_single64(int core, int key, long long value)
gator_buffer_write_packed_int64(cpu, COUNTER_BUF, value);
}
local_irq_restore(flags);
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, COUNTER_BUF, time);
}
-#endif
static void marshal_sched_trace_switch(int pid, int state)
{
@@ -269,7 +277,7 @@ static void marshal_sched_trace_switch(int pid, int state)
gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, state);
}
local_irq_restore(flags);
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, SCHED_TRACE_BUF, time);
}
@@ -289,7 +297,7 @@ static void marshal_sched_trace_exit(int tgid, int pid)
gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid);
}
local_irq_restore(flags);
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, SCHED_TRACE_BUF, time);
}
@@ -308,7 +316,7 @@ static void marshal_idle(int core, int state)
gator_buffer_write_packed_int(cpu, IDLE_BUF, core);
}
local_irq_restore(flags);
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, IDLE_BUF, time);
}
#endif
@@ -318,6 +326,7 @@ static void marshal_core_name(const int core, const int cpuid, const char *name)
{
int cpu = get_physical_cpu();
unsigned long flags;
+
local_irq_save(flags);
if (buffer_check_space(cpu, SUMMARY_BUF, MAXSIZE_PACK32 + MAXSIZE_CORE_NAME)) {
gator_buffer_write_packed_int(cpu, SUMMARY_BUF, MESSAGE_CORE_NAME);
@@ -325,7 +334,7 @@ static void marshal_core_name(const int core, const int cpuid, const char *name)
gator_buffer_write_packed_int(cpu, SUMMARY_BUF, cpuid);
gator_buffer_write_string(cpu, SUMMARY_BUF, name);
}
- // Commit core names now so that they can show up in live
+ /* Commit core names now so that they can show up in live */
local_irq_restore(flags);
gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
}
@@ -351,12 +360,12 @@ static void marshal_activity_switch(int core, int key, int activity, int pid, in
gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, state);
}
local_irq_restore(flags);
- // Check and commit; commit is set to occur once buffer is 3/4 full
+ /* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, ACTIVITY_BUF, time);
}
void gator_marshal_activity_switch(int core, int key, int activity, int pid)
{
- // state is reserved for cpu use only
+ /* state is reserved for cpu use only */
marshal_activity_switch(core, key, activity, pid, 0);
}
diff --git a/driver/gator_trace_gpu.c b/driver/gator_trace_gpu.c
index fbfb275..5de9152 100644
--- a/driver/gator_trace_gpu.c
+++ b/driver/gator_trace_gpu.c
@@ -58,11 +58,12 @@ struct mali_activity {
static struct mali_activity mali_activities[NUMBER_OF_GPU_UNITS*NUMBER_OF_GPU_CORES];
static DEFINE_SPINLOCK(mali_activities_lock);
-/* Only one event should be running on a unit and core at a time (ie, a start
- * event can only be followed by a stop and vice versa), but because the kernel
- * only knows when a job is enqueued and not started, it is possible for a
- * start1, start2, stop1, stop2. Change it back into start1, stop1, start2,
- * stop2 by queueing up start2 and releasing it when stop1 is received.
+/* Only one event should be running on a unit and core at a time (ie,
+ * a start event can only be followed by a stop and vice versa), but
+ * because the kernel only knows when a job is enqueued and not
+ * started, it is possible for a start1, start2, stop1, stop2. Change
+ * it back into start1, stop1, start2, stop2 by queueing up start2 and
+ * releasing it when stop1 is received.
*/
static int mali_activity_index(int core, int key)
@@ -70,9 +71,8 @@ static int mali_activity_index(int core, int key)
int i;
for (i = 0; i < ARRAY_SIZE(mali_activities); ++i) {
- if ((mali_activities[i].core == core) && (mali_activities[i].key == key)) {
+ if ((mali_activities[i].core == core) && (mali_activities[i].key == key))
break;
- }
if ((mali_activities[i].core == 0) && (mali_activities[i].key == 0)) {
mali_activities[i].core = core;
mali_activities[i].key = key;
@@ -101,9 +101,8 @@ static void mali_activity_enqueue(int core, int key, int activity, int pid)
}
spin_unlock(&mali_activities_lock);
- if (!count) {
+ if (!count)
gator_marshal_activity_switch(core, key, activity, pid);
- }
}
static void mali_activity_stop(int core, int key)
@@ -129,12 +128,11 @@ static void mali_activity_stop(int core, int key)
spin_unlock(&mali_activities_lock);
gator_marshal_activity_switch(core, key, 0, 0);
- if (count) {
+ if (count)
gator_marshal_activity_switch(core, key, last_activity, last_pid);
- }
}
-void mali_activity_clear(mali_counter mali_activity[], size_t mali_activity_size)
+void mali_activity_clear(struct mali_counter mali_activity[], size_t mali_activity_size)
{
int activity;
int cores;
@@ -142,9 +140,8 @@ void mali_activity_clear(mali_counter mali_activity[], size_t mali_activity_size
for (activity = 0; activity < mali_activity_size; ++activity) {
cores = mali_activity[activity].cores;
- if (cores < 0) {
+ if (cores < 0)
cores = 1;
- }
for (core = 0; core < cores; ++core) {
if (mali_activity[activity].enabled) {
preempt_disable();
@@ -185,40 +182,36 @@ enum {
EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE = 1,
};
-mali_counter mali_activity[2];
+struct mali_counter mali_activity[2];
GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4))
{
unsigned int component, state;
- // do as much work as possible before disabling interrupts
- component = (event_id >> 16) & 0xFF; // component is an 8-bit field
- state = (event_id >> 24) & 0xF; // state is a 4-bit field
+ /* do as much work as possible before disabling interrupts */
+ component = (event_id >> 16) & 0xFF; /* component is an 8-bit field */
+ state = (event_id >> 24) & 0xF; /* state is a 4-bit field */
switch (state) {
case EVENT_TYPE_START:
if (component == EVENT_CHANNEL_VP0) {
/* tgid = d0; pid = d1; */
- if (mali_activity[1].enabled) {
+ if (mali_activity[1].enabled)
mali_activity_enqueue(0, mali_activity[1].key, 1, d1);
- }
} else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
/* tgid = d0; pid = d1; */
- if (mali_activity[0].enabled) {
+ if (mali_activity[0].enabled)
mali_activity_enqueue(component - EVENT_CHANNEL_FP0, mali_activity[0].key, 1, d1);
- }
}
break;
case EVENT_TYPE_STOP:
if (component == EVENT_CHANNEL_VP0) {
- if (mali_activity[1].enabled) {
+ if (mali_activity[1].enabled)
mali_activity_stop(0, mali_activity[1].key);
- }
} else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
- if (mali_activity[0].enabled) {
+ if (mali_activity[0].enabled)
mali_activity_stop(component - EVENT_CHANNEL_FP0, mali_activity[0].key);
- }
}
break;
@@ -226,9 +219,8 @@ GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned
if (component == EVENT_CHANNEL_GPU) {
unsigned int reason = (event_id & 0xffff);
- if (reason == EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE) {
+ if (reason == EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE)
gator_events_mali_log_dvfs_event(d0, d1);
- }
}
break;
@@ -240,7 +232,7 @@ GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned
#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_MIDGARD)
-mali_counter mali_activity[3];
+struct mali_counter mali_activity[3];
#if defined(MALI_JOB_SLOTS_EVENT_CHANGED)
GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid, unsigned char job_id))
@@ -253,8 +245,8 @@ GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigne
unsigned char job_id = 0;
#endif
- component = (event_id >> 16) & 0xFF; // component is an 8-bit field
- state = (event_id >> 24) & 0xF; // state is a 4-bit field
+ component = (event_id >> 16) & 0xFF; /* component is an 8-bit field */
+ state = (event_id >> 24) & 0xF; /* state is a 4-bit field */
switch (component) {
case 0:
@@ -273,15 +265,13 @@ GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigne
if (unit != GPU_UNIT_NONE) {
switch (state) {
case EVENT_TYPE_START:
- if (mali_activity[component].enabled) {
+ if (mali_activity[component].enabled)
mali_activity_enqueue(0, mali_activity[component].key, 1, (pid != 0 ? pid : tgid));
- }
break;
case EVENT_TYPE_STOP:
- default: // Some jobs can be soft-stopped, so ensure that this terminates the activity trace.
- if (mali_activity[component].enabled) {
+ default: /* Some jobs can be soft-stopped, so ensure that this terminates the activity trace. */
+ if (mali_activity[component].enabled)
mali_activity_stop(0, mali_activity[component].key);
- }
break;
}
}
@@ -302,16 +292,14 @@ static int gator_trace_gpu_start(void)
#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_MIDGARD)
mali_activity_clear(mali_activity, ARRAY_SIZE(mali_activity));
- if (!GATOR_REGISTER_TRACE(mali_timeline_event)) {
+ if (!GATOR_REGISTER_TRACE(mali_timeline_event))
mali_timeline_trace_registered = 1;
- }
#endif
#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_MIDGARD)
mali_activity_clear(mali_activity, ARRAY_SIZE(mali_activity));
- if (!GATOR_REGISTER_TRACE(mali_job_slots_event)) {
+ if (!GATOR_REGISTER_TRACE(mali_job_slots_event))
mali_job_slots_trace_registered = 1;
- }
#endif
return 0;
@@ -320,15 +308,13 @@ static int gator_trace_gpu_start(void)
static void gator_trace_gpu_stop(void)
{
#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_MIDGARD)
- if (mali_timeline_trace_registered) {
+ if (mali_timeline_trace_registered)
GATOR_UNREGISTER_TRACE(mali_timeline_event);
- }
#endif
#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_MIDGARD)
- if (mali_job_slots_trace_registered) {
+ if (mali_job_slots_trace_registered)
GATOR_UNREGISTER_TRACE(mali_job_slots_event);
- }
#endif
mali_timeline_trace_registered = mali_job_slots_trace_registered = 0;
diff --git a/driver/gator_trace_power.c b/driver/gator_trace_power.c
index f2754b1..46e04b2 100644
--- a/driver/gator_trace_power.c
+++ b/driver/gator_trace_power.c
@@ -22,18 +22,20 @@
#endif
-// cpu_frequency and cpu_idle trace points were introduced in Linux kernel v2.6.38
-// the now deprecated power_frequency trace point was available prior to 2.6.38, but only for x86
+/* cpu_frequency and cpu_idle trace points were introduced in Linux
+ * kernel v2.6.38 the now deprecated power_frequency trace point was
+ * available prior to 2.6.38, but only for x86
+ */
#if GATOR_CPU_FREQ_SUPPORT
enum {
POWER_CPU_FREQ,
- POWER_CPU_IDLE,
POWER_TOTAL
};
static DEFINE_PER_CPU(ulong, idle_prev_state);
static ulong power_cpu_enabled[POWER_TOTAL];
static ulong power_cpu_key[POWER_TOTAL];
+static ulong power_cpu_cores;
static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root)
{
@@ -41,8 +43,9 @@ static int gator_trace_power_create_files(struct super_block *sb, struct dentry
int cpu;
bool found_nonzero_freq = false;
- // Even if CONFIG_CPU_FREQ is defined, it still may not be used. Check
- // for non-zero values from cpufreq_quick_get
+ /* Even if CONFIG_CPU_FREQ is defined, it still may not be
+ * used. Check for non-zero values from cpufreq_quick_get
+ */
for_each_online_cpu(cpu) {
if (cpufreq_quick_get(cpu) > 0) {
found_nonzero_freq = true;
@@ -51,27 +54,18 @@ static int gator_trace_power_create_files(struct super_block *sb, struct dentry
}
if (found_nonzero_freq) {
- // cpu_frequency
+ /* cpu_frequency */
dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_freq");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_FREQ]);
gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_FREQ]);
}
- // cpu_idle
- dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_idle");
- if (!dir) {
- return -1;
- }
- gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_IDLE]);
- gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_IDLE]);
-
return 0;
}
-// 'cpu' may not equal smp_processor_id(), i.e. may not be running on the core that is having the freq/idle state change
+/* 'cpu' may not equal smp_processor_id(), i.e. may not be running on the core that is having the freq/idle state change */
GATOR_DEFINE_PROBE(cpu_frequency, TP_PROTO(unsigned int frequency, unsigned int cpu))
{
cpu = lcpu_to_pcpu(cpu);
@@ -82,56 +76,50 @@ GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu))
{
cpu = lcpu_to_pcpu(cpu);
- if (state == per_cpu(idle_prev_state, cpu)) {
+ if (state == per_cpu(idle_prev_state, cpu))
return;
- }
if (implements_wfi()) {
if (state == PWR_EVENT_EXIT) {
- // transition from wfi to non-wfi
+ /* transition from wfi to non-wfi */
marshal_idle(cpu, MESSAGE_IDLE_EXIT);
} else {
- // transition from non-wfi to wfi
+ /* transition from non-wfi to wfi */
marshal_idle(cpu, MESSAGE_IDLE_ENTER);
}
}
per_cpu(idle_prev_state, cpu) = state;
-
- if (power_cpu_enabled[POWER_CPU_IDLE]) {
- // Increment state so that no negative numbers are sent
- marshal_event_single(cpu, power_cpu_key[POWER_CPU_IDLE], state + 1);
- }
}
static void gator_trace_power_online(void)
{
int pcpu = get_physical_cpu();
int lcpu = get_logical_cpu();
- if (power_cpu_enabled[POWER_CPU_FREQ]) {
+
+ if (power_cpu_enabled[POWER_CPU_FREQ])
marshal_event_single64(pcpu, power_cpu_key[POWER_CPU_FREQ], cpufreq_quick_get(lcpu) * 1000L);
- }
}
static void gator_trace_power_offline(void)
{
- // Set frequency to zero on an offline
+ /* Set frequency to zero on an offline */
int cpu = get_physical_cpu();
- if (power_cpu_enabled[POWER_CPU_FREQ]) {
+
+ if (power_cpu_enabled[POWER_CPU_FREQ])
marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], 0);
- }
}
static int gator_trace_power_start(void)
{
int cpu;
- // register tracepoints
+ /* register tracepoints */
if (power_cpu_enabled[POWER_CPU_FREQ])
if (GATOR_REGISTER_TRACE(cpu_frequency))
goto fail_cpu_frequency_exit;
- // Always register for cpu:idle for detecting WFI, independent of power_cpu_enabled[POWER_CPU_IDLE]
+ /* Always register for cpu_idle for detecting WFI */
if (GATOR_REGISTER_TRACE(cpu_idle))
goto fail_cpu_idle_exit;
pr_debug("gator: registered power event tracepoints\n");
@@ -142,7 +130,7 @@ static int gator_trace_power_start(void)
return 0;
- // unregister tracepoints on error
+ /* unregister tracepoints on error */
fail_cpu_idle_exit:
if (power_cpu_enabled[POWER_CPU_FREQ])
GATOR_UNREGISTER_TRACE(cpu_frequency);
@@ -161,14 +149,15 @@ static void gator_trace_power_stop(void)
GATOR_UNREGISTER_TRACE(cpu_idle);
pr_debug("gator: unregistered power event tracepoints\n");
- for (i = 0; i < POWER_TOTAL; i++) {
+ for (i = 0; i < POWER_TOTAL; i++)
power_cpu_enabled[i] = 0;
- }
}
static void gator_trace_power_init(void)
{
int i;
+
+ power_cpu_cores = nr_cpu_ids;
for (i = 0; i < POWER_TOTAL; i++) {
power_cpu_enabled[i] = 0;
power_cpu_key[i] = gator_events_get_key();
diff --git a/driver/gator_trace_sched.c b/driver/gator_trace_sched.c
index 6550086..6d7cbd7 100644
--- a/driver/gator_trace_sched.c
+++ b/driver/gator_trace_sched.c
@@ -8,6 +8,10 @@
*/
#include <trace/events/sched.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+#include <trace/events/task.h>
+#endif
+
#include "gator.h"
#define TASK_MAP_ENTRIES 1024 /* must be power of 2 */
@@ -23,8 +27,10 @@ enum {
static DEFINE_PER_CPU(uint64_t *, taskname_keys);
static DEFINE_PER_CPU(int, collecting);
-// this array is never read as the cpu wait charts are derived counters
-// the files are needed, nonetheless, to show that these counters are available
+/* this array is never read as the cpu wait charts are derived
+ * counters the files are needed, nonetheless, to show that these
+ * counters are available
+ */
static ulong cpu_wait_enabled[CPU_WAIT_TOTAL];
static ulong sched_cpu_key[CPU_WAIT_TOTAL];
@@ -32,26 +38,24 @@ static int sched_trace_create_files(struct super_block *sb, struct dentry *root)
{
struct dentry *dir;
- // CPU Wait - Contention
+ /* CPU Wait - Contention */
dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_contention");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_CONTENTION]);
gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_CONTENTION]);
- // CPU Wait - I/O
+ /* CPU Wait - I/O */
dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_io");
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_WAIT_ON_IO]);
gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_WAIT_ON_IO]);
return 0;
}
-static void emit_pid_name(struct task_struct *task)
+static void emit_pid_name(const char *comm, struct task_struct *task)
{
bool found = false;
char taskcomm[TASK_COMM_LEN + 3];
@@ -59,10 +63,10 @@ static void emit_pid_name(struct task_struct *task)
uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]);
uint64_t value;
- value = gator_chksum_crc32(task->comm);
+ value = gator_chksum_crc32(comm);
value = (value << 32) | (uint32_t)task->pid;
- // determine if the thread name was emitted already
+ /* determine if the thread name was emitted already */
for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
if (keys[x] == value) {
found = true;
@@ -71,17 +75,18 @@ static void emit_pid_name(struct task_struct *task)
}
if (!found) {
- // shift values, new value always in front
+ /* shift values, new value always in front */
uint64_t oldv, newv = value;
+
for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
oldv = keys[x];
keys[x] = newv;
newv = oldv;
}
- // emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions
- if (strlcpy(taskcomm, task->comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1) {
- // append ellipses if task->comm has length of TASK_COMM_LEN - 1
+ /* emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions */
+ if (strlcpy(taskcomm, comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1) {
+ /* append ellipses if comm has length of TASK_COMM_LEN - 1 */
strcat(taskcomm, "...");
}
@@ -89,7 +94,7 @@ static void emit_pid_name(struct task_struct *task)
}
}
-static void collect_counters(u64 time, struct task_struct *task)
+static void collect_counters(u64 time, struct task_struct *task, bool sched_switch)
{
int *buffer, len, cpu = get_physical_cpu();
long long *buffer64;
@@ -98,7 +103,7 @@ static void collect_counters(u64 time, struct task_struct *task)
if (marshal_event_header(time)) {
list_for_each_entry(gi, &gator_events, list) {
if (gi->read) {
- len = gi->read(&buffer);
+ len = gi->read(&buffer, sched_switch);
marshal_event(len, buffer);
} else if (gi->read64) {
len = gi->read64(&buffer64);
@@ -109,22 +114,26 @@ static void collect_counters(u64 time, struct task_struct *task)
marshal_event64(len, buffer64);
}
}
- // Only check after writing all counters so that time and corresponding counters appear in the same frame
+ if (cpu == 0)
+ gator_emit_perf_time(time);
+ /* Only check after writing all counters so that time and corresponding counters appear in the same frame */
buffer_check(cpu, BLOCK_COUNTER_BUF, time);
- // Commit buffers on timeout
+ /* Commit buffers on timeout */
if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) {
static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF, ACTIVITY_BUF };
int i;
- for (i = 0; i < ARRAY_SIZE(buftypes); ++i) {
+ for (i = 0; i < ARRAY_SIZE(buftypes); ++i)
gator_commit_buffer(cpu, buftypes[i], time);
- }
- // spinlocks are noops on uniprocessor machines and mutexes do not work in sched_switch context in
- // RT-Preempt full, so disable proactive flushing of the annotate frame on uniprocessor machines.
+ /* spinlocks are noops on uniprocessor machines and mutexes do
+ * not work in sched_switch context in RT-Preempt full, so
+ * disable proactive flushing of the annotate frame on
+ * uniprocessor machines.
+ */
#ifdef CONFIG_SMP
- // Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full
+ /* Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full */
if (on_primary_core() && spin_trylock(&annotate_lock)) {
gator_commit_buffer(0, ANNOTATE_BUF, time);
spin_unlock(&annotate_lock);
@@ -134,7 +143,7 @@ static void collect_counters(u64 time, struct task_struct *task)
}
}
-// special case used during a suspend of the system
+/* special case used during a suspend of the system */
static void trace_sched_insert_idle(void)
{
marshal_sched_trace_switch(0, 0);
@@ -146,7 +155,7 @@ static void gator_trace_emit_link(struct task_struct *p)
int cpu = get_physical_cpu();
cookie = get_exec_cookie(cpu, p);
- emit_pid_name(p);
+ emit_pid_name(p->comm, p);
marshal_link(cookie, p->tgid, p->pid);
}
@@ -161,6 +170,15 @@ GATOR_DEFINE_PROBE(sched_process_exec, TP_PROTO(struct task_struct *p, pid_t old
{
gator_trace_emit_link(p);
}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)
+GATOR_DEFINE_PROBE(task_rename, TP_PROTO(struct task_struct *task, char *comm))
+#else
+GATOR_DEFINE_PROBE(task_rename, TP_PROTO(struct task_struct *task, const char *comm))
+#endif
+{
+ emit_pid_name(comm, task);
+}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
@@ -174,17 +192,16 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_
per_cpu(in_scheduler_context, cpu) = true;
- // do as much work as possible before disabling interrupts
- if (prev->state == TASK_RUNNING) {
+ /* do as much work as possible before disabling interrupts */
+ if (prev->state == TASK_RUNNING)
state = STATE_CONTENTION;
- } else if (prev->in_iowait) {
+ else if (prev->in_iowait)
state = STATE_WAIT_ON_IO;
- } else {
+ else
state = STATE_WAIT_ON_OTHER;
- }
per_cpu(collecting, cpu) = 1;
- collect_counters(gator_get_time(), prev);
+ collect_counters(gator_get_time(), prev, true);
per_cpu(collecting, cpu) = 0;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
@@ -202,18 +219,20 @@ GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
static void do_nothing(void *info)
{
- // Intentionally do nothing
+ /* Intentionally do nothing */
(void)info;
}
static int register_scheduler_tracepoints(void)
{
- // register tracepoints
+ /* register tracepoints */
if (GATOR_REGISTER_TRACE(sched_process_fork))
goto fail_sched_process_fork;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
if (GATOR_REGISTER_TRACE(sched_process_exec))
goto fail_sched_process_exec;
+ if (GATOR_REGISTER_TRACE(task_rename))
+ goto fail_task_rename;
#endif
if (GATOR_REGISTER_TRACE(sched_switch))
goto fail_sched_switch;
@@ -221,21 +240,24 @@ static int register_scheduler_tracepoints(void)
goto fail_sched_process_free;
pr_debug("gator: registered tracepoints\n");
- // Now that the scheduler tracepoint is registered, force a context switch
- // on all cpus to capture what is currently running.
+ /* Now that the scheduler tracepoint is registered, force a context
+ * switch on all cpus to capture what is currently running.
+ */
on_each_cpu(do_nothing, NULL, 0);
return 0;
- // unregister tracepoints on error
+ /* unregister tracepoints on error */
fail_sched_process_free:
GATOR_UNREGISTER_TRACE(sched_switch);
fail_sched_switch:
- GATOR_UNREGISTER_TRACE(sched_process_fork);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
-fail_sched_process_exec:
+ GATOR_UNREGISTER_TRACE(task_rename);
+fail_task_rename:
GATOR_UNREGISTER_TRACE(sched_process_exec);
+fail_sched_process_exec:
#endif
+ GATOR_UNREGISTER_TRACE(sched_process_fork);
fail_sched_process_fork:
pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
@@ -247,6 +269,7 @@ static void unregister_scheduler_tracepoints(void)
GATOR_UNREGISTER_TRACE(sched_process_fork);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
GATOR_UNREGISTER_TRACE(sched_process_exec);
+ GATOR_UNREGISTER_TRACE(task_rename);
#endif
GATOR_UNREGISTER_TRACE(sched_switch);
GATOR_UNREGISTER_TRACE(sched_process_free);
@@ -271,7 +294,7 @@ static int gator_trace_sched_start(void)
for_each_present_cpu(cpu) {
size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t);
- per_cpu(taskname_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL);
+ per_cpu(taskname_keys, cpu) = kmalloc(size, GFP_KERNEL);
if (!per_cpu(taskname_keys, cpu))
return -1;
memset(per_cpu(taskname_keys, cpu), 0, size);
@@ -290,6 +313,7 @@ static void gator_trace_sched_offline(void)
static void gator_trace_sched_init(void)
{
int i;
+
for (i = 0; i < CPU_WAIT_TOTAL; i++) {
cpu_wait_enabled[i] = 0;
sched_cpu_key[i] = gator_events_get_key();
diff --git a/driver/mali/mali_mjollnir_profiling_gator_api.h b/driver/mali/mali_mjollnir_profiling_gator_api.h
index ff00d90..2bc0b03 100644
--- a/driver/mali/mali_mjollnir_profiling_gator_api.h
+++ b/driver/mali/mali_mjollnir_profiling_gator_api.h
@@ -23,83 +23,82 @@ extern "C"
#define MAX_NUM_VP_CORES (1)
#define MAX_NUM_L2_CACHE_CORES (1)
-enum counters
-{
- /* Timeline activity */
- ACTIVITY_VP_0 = 0,
- ACTIVITY_FP_0,
- ACTIVITY_FP_1,
- ACTIVITY_FP_2,
- ACTIVITY_FP_3,
-
- /* L2 cache counters */
- COUNTER_L2_0_C0,
- COUNTER_L2_0_C1,
-
- /* Vertex processor counters */
- COUNTER_VP_0_C0,
- COUNTER_VP_0_C1,
-
- /* Fragment processor counters */
- COUNTER_FP_0_C0,
- COUNTER_FP_0_C1,
- COUNTER_FP_1_C0,
- COUNTER_FP_1_C1,
- COUNTER_FP_2_C0,
- COUNTER_FP_2_C1,
- COUNTER_FP_3_C0,
- COUNTER_FP_3_C1,
-
- /* EGL Software Counters */
- COUNTER_EGL_BLIT_TIME,
-
- /* GLES Software Counters */
- COUNTER_GLES_DRAW_ELEMENTS_CALLS,
- COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES,
- COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED,
- COUNTER_GLES_DRAW_ARRAYS_CALLS,
- COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED,
- COUNTER_GLES_DRAW_POINTS,
- COUNTER_GLES_DRAW_LINES,
- COUNTER_GLES_DRAW_LINE_LOOP,
- COUNTER_GLES_DRAW_LINE_STRIP,
- COUNTER_GLES_DRAW_TRIANGLES,
- COUNTER_GLES_DRAW_TRIANGLE_STRIP,
- COUNTER_GLES_DRAW_TRIANGLE_FAN,
- COUNTER_GLES_NON_VBO_DATA_COPY_TIME,
- COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI,
- COUNTER_GLES_UPLOAD_TEXTURE_TIME,
- COUNTER_GLES_UPLOAD_VBO_TIME,
- COUNTER_GLES_NUM_FLUSHES,
- COUNTER_GLES_NUM_VSHADERS_GENERATED,
- COUNTER_GLES_NUM_FSHADERS_GENERATED,
- COUNTER_GLES_VSHADER_GEN_TIME,
- COUNTER_GLES_FSHADER_GEN_TIME,
- COUNTER_GLES_INPUT_TRIANGLES,
- COUNTER_GLES_VXCACHE_HIT,
- COUNTER_GLES_VXCACHE_MISS,
- COUNTER_GLES_VXCACHE_COLLISION,
- COUNTER_GLES_CULLED_TRIANGLES,
- COUNTER_GLES_CULLED_LINES,
- COUNTER_GLES_BACKFACE_TRIANGLES,
- COUNTER_GLES_GBCLIP_TRIANGLES,
- COUNTER_GLES_GBCLIP_LINES,
- COUNTER_GLES_TRIANGLES_DRAWN,
- COUNTER_GLES_DRAWCALL_TIME,
- COUNTER_GLES_TRIANGLES_COUNT,
- COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT,
- COUNTER_GLES_STRIP_TRIANGLES_COUNT,
- COUNTER_GLES_FAN_TRIANGLES_COUNT,
- COUNTER_GLES_LINES_COUNT,
- COUNTER_GLES_INDEPENDENT_LINES_COUNT,
- COUNTER_GLES_STRIP_LINES_COUNT,
- COUNTER_GLES_LOOP_LINES_COUNT,
-
- COUNTER_FILMSTRIP,
- COUNTER_FREQUENCY,
- COUNTER_VOLTAGE,
-
- NUMBER_OF_EVENTS
+enum counters {
+ /* Timeline activity */
+ ACTIVITY_VP_0 = 0,
+ ACTIVITY_FP_0,
+ ACTIVITY_FP_1,
+ ACTIVITY_FP_2,
+ ACTIVITY_FP_3,
+
+ /* L2 cache counters */
+ COUNTER_L2_0_C0,
+ COUNTER_L2_0_C1,
+
+ /* Vertex processor counters */
+ COUNTER_VP_0_C0,
+ COUNTER_VP_0_C1,
+
+ /* Fragment processor counters */
+ COUNTER_FP_0_C0,
+ COUNTER_FP_0_C1,
+ COUNTER_FP_1_C0,
+ COUNTER_FP_1_C1,
+ COUNTER_FP_2_C0,
+ COUNTER_FP_2_C1,
+ COUNTER_FP_3_C0,
+ COUNTER_FP_3_C1,
+
+ /* EGL Software Counters */
+ COUNTER_EGL_BLIT_TIME,
+
+ /* GLES Software Counters */
+ COUNTER_GLES_DRAW_ELEMENTS_CALLS,
+ COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES,
+ COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED,
+ COUNTER_GLES_DRAW_ARRAYS_CALLS,
+ COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED,
+ COUNTER_GLES_DRAW_POINTS,
+ COUNTER_GLES_DRAW_LINES,
+ COUNTER_GLES_DRAW_LINE_LOOP,
+ COUNTER_GLES_DRAW_LINE_STRIP,
+ COUNTER_GLES_DRAW_TRIANGLES,
+ COUNTER_GLES_DRAW_TRIANGLE_STRIP,
+ COUNTER_GLES_DRAW_TRIANGLE_FAN,
+ COUNTER_GLES_NON_VBO_DATA_COPY_TIME,
+ COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI,
+ COUNTER_GLES_UPLOAD_TEXTURE_TIME,
+ COUNTER_GLES_UPLOAD_VBO_TIME,
+ COUNTER_GLES_NUM_FLUSHES,
+ COUNTER_GLES_NUM_VSHADERS_GENERATED,
+ COUNTER_GLES_NUM_FSHADERS_GENERATED,
+ COUNTER_GLES_VSHADER_GEN_TIME,
+ COUNTER_GLES_FSHADER_GEN_TIME,
+ COUNTER_GLES_INPUT_TRIANGLES,
+ COUNTER_GLES_VXCACHE_HIT,
+ COUNTER_GLES_VXCACHE_MISS,
+ COUNTER_GLES_VXCACHE_COLLISION,
+ COUNTER_GLES_CULLED_TRIANGLES,
+ COUNTER_GLES_CULLED_LINES,
+ COUNTER_GLES_BACKFACE_TRIANGLES,
+ COUNTER_GLES_GBCLIP_TRIANGLES,
+ COUNTER_GLES_GBCLIP_LINES,
+ COUNTER_GLES_TRIANGLES_DRAWN,
+ COUNTER_GLES_DRAWCALL_TIME,
+ COUNTER_GLES_TRIANGLES_COUNT,
+ COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT,
+ COUNTER_GLES_STRIP_TRIANGLES_COUNT,
+ COUNTER_GLES_FAN_TRIANGLES_COUNT,
+ COUNTER_GLES_LINES_COUNT,
+ COUNTER_GLES_INDEPENDENT_LINES_COUNT,
+ COUNTER_GLES_STRIP_LINES_COUNT,
+ COUNTER_GLES_LOOP_LINES_COUNT,
+
+ COUNTER_FILMSTRIP,
+ COUNTER_FREQUENCY,
+ COUNTER_VOLTAGE,
+
+ NUMBER_OF_EVENTS
};
#define FIRST_ACTIVITY_EVENT ACTIVITY_VP_0
@@ -117,34 +116,31 @@ enum counters
/**
* Structure to pass performance counter data of a Mali core
*/
-typedef struct _mali_profiling_core_counters
-{
- u32 source0;
- u32 value0;
- u32 source1;
- u32 value1;
-} _mali_profiling_core_counters;
+struct _mali_profiling_core_counters {
+ u32 source0;
+ u32 value0;
+ u32 source1;
+ u32 value1;
+};
/*
* For compatibility with utgard.
*/
-typedef struct _mali_profiling_l2_counter_values
-{
- struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES];
-} _mali_profiling_l2_counter_values;
+struct _mali_profiling_l2_counter_values {
+ struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES];
+};
-typedef struct _mali_profiling_mali_version
-{
- u32 mali_product_id;
- u32 mali_version_major;
- u32 mali_version_minor;
- u32 num_of_l2_cores;
- u32 num_of_fp_cores;
- u32 num_of_vp_cores;
-} _mali_profiling_mali_version;
+struct _mali_profiling_mali_version {
+ u32 mali_product_id;
+ u32 mali_version_major;
+ u32 mali_version_minor;
+ u32 num_of_l2_cores;
+ u32 num_of_fp_cores;
+ u32 num_of_vp_cores;
+};
extern void _mali_profiling_get_mali_version(struct _mali_profiling_mali_version *values);
-extern u32 _mali_profiling_get_l2_counters(_mali_profiling_l2_counter_values *values);
+extern u32 _mali_profiling_get_l2_counters(struct _mali_profiling_l2_counter_values *values);
/*
* List of possible actions allowing DDK to be controlled by Streamline.
diff --git a/driver/mali/mali_utgard_profiling_gator_api.h b/driver/mali/mali_utgard_profiling_gator_api.h
index 43c5760..d646531 100644
--- a/driver/mali/mali_utgard_profiling_gator_api.h
+++ b/driver/mali/mali_utgard_profiling_gator_api.h
@@ -22,105 +22,104 @@ extern "C"
#define MAX_NUM_VP_CORES 1
/** The list of events supported by the Mali DDK. */
-typedef enum
-{
- /* Vertex processor activity */
- ACTIVITY_VP_0 = 0,
-
- /* Fragment processor activity */
- ACTIVITY_FP_0, /* 1 */
- ACTIVITY_FP_1,
- ACTIVITY_FP_2,
- ACTIVITY_FP_3,
- ACTIVITY_FP_4,
- ACTIVITY_FP_5,
- ACTIVITY_FP_6,
- ACTIVITY_FP_7,
-
- /* L2 cache counters */
- COUNTER_L2_0_C0,
- COUNTER_L2_0_C1,
- COUNTER_L2_1_C0,
- COUNTER_L2_1_C1,
- COUNTER_L2_2_C0,
- COUNTER_L2_2_C1,
-
- /* Vertex processor counters */
- COUNTER_VP_0_C0, /*15*/
- COUNTER_VP_0_C1,
-
- /* Fragment processor counters */
- COUNTER_FP_0_C0,
- COUNTER_FP_0_C1,
- COUNTER_FP_1_C0,
- COUNTER_FP_1_C1,
- COUNTER_FP_2_C0,
- COUNTER_FP_2_C1,
- COUNTER_FP_3_C0,
- COUNTER_FP_3_C1,
- COUNTER_FP_4_C0,
- COUNTER_FP_4_C1,
- COUNTER_FP_5_C0,
- COUNTER_FP_5_C1,
- COUNTER_FP_6_C0,
- COUNTER_FP_6_C1,
- COUNTER_FP_7_C0,
- COUNTER_FP_7_C1, /* 32 */
-
- /*
- * If more hardware counters are added, the _mali_osk_hw_counter_table
- * below should also be updated.
- */
-
- /* EGL software counters */
- COUNTER_EGL_BLIT_TIME,
-
- /* GLES software counters */
- COUNTER_GLES_DRAW_ELEMENTS_CALLS,
- COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES,
- COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED,
- COUNTER_GLES_DRAW_ARRAYS_CALLS,
- COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED,
- COUNTER_GLES_DRAW_POINTS,
- COUNTER_GLES_DRAW_LINES,
- COUNTER_GLES_DRAW_LINE_LOOP,
- COUNTER_GLES_DRAW_LINE_STRIP,
- COUNTER_GLES_DRAW_TRIANGLES,
- COUNTER_GLES_DRAW_TRIANGLE_STRIP,
- COUNTER_GLES_DRAW_TRIANGLE_FAN,
- COUNTER_GLES_NON_VBO_DATA_COPY_TIME,
- COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI,
- COUNTER_GLES_UPLOAD_TEXTURE_TIME,
- COUNTER_GLES_UPLOAD_VBO_TIME,
- COUNTER_GLES_NUM_FLUSHES,
- COUNTER_GLES_NUM_VSHADERS_GENERATED,
- COUNTER_GLES_NUM_FSHADERS_GENERATED,
- COUNTER_GLES_VSHADER_GEN_TIME,
- COUNTER_GLES_FSHADER_GEN_TIME,
- COUNTER_GLES_INPUT_TRIANGLES,
- COUNTER_GLES_VXCACHE_HIT,
- COUNTER_GLES_VXCACHE_MISS,
- COUNTER_GLES_VXCACHE_COLLISION,
- COUNTER_GLES_CULLED_TRIANGLES,
- COUNTER_GLES_CULLED_LINES,
- COUNTER_GLES_BACKFACE_TRIANGLES,
- COUNTER_GLES_GBCLIP_TRIANGLES,
- COUNTER_GLES_GBCLIP_LINES,
- COUNTER_GLES_TRIANGLES_DRAWN,
- COUNTER_GLES_DRAWCALL_TIME,
- COUNTER_GLES_TRIANGLES_COUNT,
- COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT,
- COUNTER_GLES_STRIP_TRIANGLES_COUNT,
- COUNTER_GLES_FAN_TRIANGLES_COUNT,
- COUNTER_GLES_LINES_COUNT,
- COUNTER_GLES_INDEPENDENT_LINES_COUNT,
- COUNTER_GLES_STRIP_LINES_COUNT,
- COUNTER_GLES_LOOP_LINES_COUNT,
-
- /* Framebuffer capture pseudo-counter */
- COUNTER_FILMSTRIP,
-
- NUMBER_OF_EVENTS
+enum {
+ /* Vertex processor activity */
+ ACTIVITY_VP_0 = 0,
+
+ /* Fragment processor activity */
+ ACTIVITY_FP_0, /* 1 */
+ ACTIVITY_FP_1,
+ ACTIVITY_FP_2,
+ ACTIVITY_FP_3,
+ ACTIVITY_FP_4,
+ ACTIVITY_FP_5,
+ ACTIVITY_FP_6,
+ ACTIVITY_FP_7,
+
+ /* L2 cache counters */
+ COUNTER_L2_0_C0,
+ COUNTER_L2_0_C1,
+ COUNTER_L2_1_C0,
+ COUNTER_L2_1_C1,
+ COUNTER_L2_2_C0,
+ COUNTER_L2_2_C1,
+
+ /* Vertex processor counters */
+ COUNTER_VP_0_C0, /*15*/
+ COUNTER_VP_0_C1,
+
+ /* Fragment processor counters */
+ COUNTER_FP_0_C0,
+ COUNTER_FP_0_C1,
+ COUNTER_FP_1_C0,
+ COUNTER_FP_1_C1,
+ COUNTER_FP_2_C0,
+ COUNTER_FP_2_C1,
+ COUNTER_FP_3_C0,
+ COUNTER_FP_3_C1,
+ COUNTER_FP_4_C0,
+ COUNTER_FP_4_C1,
+ COUNTER_FP_5_C0,
+ COUNTER_FP_5_C1,
+ COUNTER_FP_6_C0,
+ COUNTER_FP_6_C1,
+ COUNTER_FP_7_C0,
+ COUNTER_FP_7_C1, /* 32 */
+
+ /*
+ * If more hardware counters are added, the _mali_osk_hw_counter_table
+ * below should also be updated.
+ */
+
+ /* EGL software counters */
+ COUNTER_EGL_BLIT_TIME,
+
+ /* GLES software counters */
+ COUNTER_GLES_DRAW_ELEMENTS_CALLS,
+ COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES,
+ COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED,
+ COUNTER_GLES_DRAW_ARRAYS_CALLS,
+ COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED,
+ COUNTER_GLES_DRAW_POINTS,
+ COUNTER_GLES_DRAW_LINES,
+ COUNTER_GLES_DRAW_LINE_LOOP,
+ COUNTER_GLES_DRAW_LINE_STRIP,
+ COUNTER_GLES_DRAW_TRIANGLES,
+ COUNTER_GLES_DRAW_TRIANGLE_STRIP,
+ COUNTER_GLES_DRAW_TRIANGLE_FAN,
+ COUNTER_GLES_NON_VBO_DATA_COPY_TIME,
+ COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI,
+ COUNTER_GLES_UPLOAD_TEXTURE_TIME,
+ COUNTER_GLES_UPLOAD_VBO_TIME,
+ COUNTER_GLES_NUM_FLUSHES,
+ COUNTER_GLES_NUM_VSHADERS_GENERATED,
+ COUNTER_GLES_NUM_FSHADERS_GENERATED,
+ COUNTER_GLES_VSHADER_GEN_TIME,
+ COUNTER_GLES_FSHADER_GEN_TIME,
+ COUNTER_GLES_INPUT_TRIANGLES,
+ COUNTER_GLES_VXCACHE_HIT,
+ COUNTER_GLES_VXCACHE_MISS,
+ COUNTER_GLES_VXCACHE_COLLISION,
+ COUNTER_GLES_CULLED_TRIANGLES,
+ COUNTER_GLES_CULLED_LINES,
+ COUNTER_GLES_BACKFACE_TRIANGLES,
+ COUNTER_GLES_GBCLIP_TRIANGLES,
+ COUNTER_GLES_GBCLIP_LINES,
+ COUNTER_GLES_TRIANGLES_DRAWN,
+ COUNTER_GLES_DRAWCALL_TIME,
+ COUNTER_GLES_TRIANGLES_COUNT,
+ COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT,
+ COUNTER_GLES_STRIP_TRIANGLES_COUNT,
+ COUNTER_GLES_FAN_TRIANGLES_COUNT,
+ COUNTER_GLES_LINES_COUNT,
+ COUNTER_GLES_INDEPENDENT_LINES_COUNT,
+ COUNTER_GLES_STRIP_LINES_COUNT,
+ COUNTER_GLES_LOOP_LINES_COUNT,
+
+ /* Framebuffer capture pseudo-counter */
+ COUNTER_FILMSTRIP,
+
+ NUMBER_OF_EVENTS
} _mali_osk_counter_id;
#define FIRST_ACTIVITY_EVENT ACTIVITY_VP_0
@@ -138,21 +137,19 @@ typedef enum
/**
* Structure to pass performance counter data of a Mali core
*/
-typedef struct _mali_profiling_core_counters
-{
+struct _mali_profiling_core_counters {
u32 source0;
u32 value0;
u32 source1;
u32 value1;
-} _mali_profiling_core_counters;
+};
/**
* Structure to pass performance counter data of Mali L2 cache cores
*/
-typedef struct _mali_profiling_l2_counter_values
-{
+struct _mali_profiling_l2_counter_values {
struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES];
-} _mali_profiling_l2_counter_values;
+};
/**
* Structure to pass data defining Mali instance in use:
@@ -164,15 +161,14 @@ typedef struct _mali_profiling_l2_counter_values
* num_of_fp_cores - number of fragment processor cores
* num_of_vp_cores - number of vertex processor cores
*/
-typedef struct _mali_profiling_mali_version
-{
+struct _mali_profiling_mali_version {
u32 mali_product_id;
u32 mali_version_major;
u32 mali_version_minor;
u32 num_of_l2_cores;
u32 num_of_fp_cores;
u32 num_of_vp_cores;
-} _mali_profiling_mali_version;
+};
/*
* List of possible actions to be controlled by Streamline.
@@ -186,7 +182,7 @@ typedef struct _mali_profiling_mali_version
void _mali_profiling_control(u32 action, u32 value);
-u32 _mali_profiling_get_l2_counters(_mali_profiling_l2_counter_values *values);
+u32 _mali_profiling_get_l2_counters(struct _mali_profiling_l2_counter_values *values);
int _mali_profiling_set_event(u32 counter_id, s32 event_id);