gator: Version 5.18 DS-5.18
authorJon Medhurst <tixy@linaro.org>
Wed, 9 Apr 2014 11:39:14 +0000 (12:39 +0100)
committerJon Medhurst <tixy@linaro.org>
Wed, 9 Apr 2014 11:40:23 +0000 (12:40 +0100)
Signed-off-by: Jon Medhurst <tixy@linaro.org>
119 files changed:
README_Streamline.txt
daemon/Android.mk
daemon/Buffer.cpp
daemon/Buffer.h
daemon/CapturedXML.cpp
daemon/CapturedXML.h
daemon/Child.cpp
daemon/Child.h
daemon/Collector.h [deleted file]
daemon/Config.h [new file with mode: 0644]
daemon/ConfigurationXML.cpp
daemon/ConfigurationXML.h
daemon/Counter.h
daemon/Driver.cpp
daemon/Driver.h
daemon/DriverSource.cpp [moved from daemon/Collector.cpp with 58% similarity]
daemon/DriverSource.h [new file with mode: 0644]
daemon/DynBuf.cpp [new file with mode: 0644]
daemon/DynBuf.h [new file with mode: 0644]
daemon/EventsXML.cpp
daemon/EventsXML.h
daemon/ExternalSource.cpp [new file with mode: 0644]
daemon/ExternalSource.h [new file with mode: 0644]
daemon/Fifo.cpp
daemon/Fifo.h
daemon/Hwmon.cpp
daemon/Hwmon.h
daemon/KMod.cpp
daemon/KMod.h
daemon/LocalCapture.cpp
daemon/LocalCapture.h
daemon/Logging.cpp
daemon/Logging.h
daemon/Monitor.cpp [new file with mode: 0644]
daemon/Monitor.h [new file with mode: 0644]
daemon/OlySocket.cpp
daemon/OlySocket.h
daemon/OlyUtility.cpp
daemon/OlyUtility.h
daemon/PerfBuffer.cpp [new file with mode: 0644]
daemon/PerfBuffer.h [new file with mode: 0644]
daemon/PerfDriver.cpp [new file with mode: 0644]
daemon/PerfDriver.h [new file with mode: 0644]
daemon/PerfGroup.cpp [new file with mode: 0644]
daemon/PerfGroup.h [new file with mode: 0644]
daemon/PerfSource.cpp [new file with mode: 0644]
daemon/PerfSource.h [new file with mode: 0644]
daemon/Proc.cpp [new file with mode: 0644]
daemon/Proc.h [new file with mode: 0644]
daemon/Sender.cpp
daemon/Sender.h
daemon/SessionData.cpp
daemon/SessionData.h
daemon/SessionXML.cpp
daemon/SessionXML.h
daemon/Source.cpp [new file with mode: 0644]
daemon/Source.h [new file with mode: 0644]
daemon/StreamlineSetup.cpp
daemon/StreamlineSetup.h
daemon/UEvent.cpp [new file with mode: 0644]
daemon/UEvent.h [new file with mode: 0644]
daemon/UserSpaceSource.cpp [new file with mode: 0644]
daemon/UserSpaceSource.h [new file with mode: 0644]
daemon/common.mk
daemon/defaults.xml [moved from daemon/configuration.xml with 51% similarity]
daemon/escape.c
daemon/events-Cortex-A12.xml
daemon/events-Cortex-A15.xml
daemon/events-Cortex-A5.xml
daemon/events-Cortex-A7.xml
daemon/events-Cortex-A8.xml
daemon/events-Cortex-A9.xml
daemon/events-Linux.xml
daemon/events-Mali-4xx.xml
daemon/events-Mali-T6xx.xml
daemon/events-Perf-Hardware.xml [new file with mode: 0644]
daemon/k/perf_event.3.12.h [new file with mode: 0644]
daemon/k/perf_event.h [new symlink]
daemon/main.cpp
driver/Kconfig [new file with mode: 0644]
driver/gator.h
driver/gator_annotate.c
driver/gator_annotate_kernel.c
driver/gator_backtrace.c
driver/gator_buffer.c [new file with mode: 0644]
driver/gator_buffer_write.c [moved from driver/gator_pack.c with 68% similarity]
driver/gator_cookies.c
driver/gator_events_armv6.c
driver/gator_events_armv7.c
driver/gator_events_block.c
driver/gator_events_ccn-504.c
driver/gator_events_irq.c
driver/gator_events_l2c-310.c
driver/gator_events_mali_4xx.c
driver/gator_events_mali_4xx.h
driver/gator_events_mali_common.c
driver/gator_events_mali_common.h
driver/gator_events_mali_t6xx.c
driver/gator_events_mali_t6xx_hw.c
driver/gator_events_mali_t6xx_hw_test.c
driver/gator_events_meminfo.c
driver/gator_events_mmapped.c
driver/gator_events_net.c
driver/gator_events_perf_pmu.c
driver/gator_events_sched.c
driver/gator_events_scorpion.c
driver/gator_fs.c
driver/gator_hrtimer_gator.c
driver/gator_hrtimer_perf.c [deleted file]
driver/gator_iks.c
driver/gator_main.c
driver/gator_marshaling.c
driver/gator_trace_gpu.c
driver/gator_trace_gpu.h
driver/gator_trace_power.c
driver/gator_trace_sched.c
driver/mali/mali_mjollnir_profiling_gator_api.h
driver/mali/mali_utgard_profiling_gator_api.h
driver/mali_t6xx.mk

index 744c33f3d9f4aa76f07f1c4923c48e821f33c29d..df3f923fe6e4f384ff41e949fb8b4e2b19547667 100755 (executable)
@@ -2,18 +2,19 @@
 *** Purpose ***\r
 \r
 Instructions on setting up ARM Streamline on the target.\r
-The gator driver and gator daemon are required to run on the ARM linux target in order for ARM Streamline to operate.\r
+The gator driver and gator daemon are required to run on the ARM Linux target in order for ARM Streamline to operate. A new early access feature allows the gator daemon can run without the gator driver by using userspace APIs with reduced functionality when using Linux 3.12 or later.\r
 The driver should be built as a module and the daemon must run with root permissions on the target.\r
 \r
 *** Introduction ***\r
 \r
-A linux development environment with cross compiling tools is most likely required, depending on what is already created and provided.\r
+A Linux development environment with cross compiling tools is most likely required, depending on what is already created and provided.\r
 -For users, the ideal environment is to be given a BSP with gatord and gator.ko already running on a properly configured kernel. In such a scenario, a development environment is not needed, root permission may or may not be needed (gatord must be executed with root permissions but can be automatically started, see below), and the user can run Streamline and profile the system without any setup.\r
 -The ideal development environment has the kernel source code available to be rebuilt, usually by cross-compiling on a host machine. This environment allows the greatest flexibility in configuring the kernel and building the gator driver module.\r
 -However, it is possible that a user/developer has a kernel but does not have the source code. In this scenario it may or may not be possible to obtain a valid profile.\r
        -First, check if the kernel has the proper configuration options (see below). Profiling cannot occur using a kernel that is not configured properly, a new kernel must be created. See if /proc/config.gz exists on the target.\r
        -Second, given a properly configured kernel, check if the filesystem contains the kernel source/headers, which can be used to re-create the gator driver. These files may be located in different areas, but common locations are /lib/modules/ and /usr/src.\r
        -If the kernel is not properly configured or sources/headers are not available, the developer is on their own and kernel creation is beyond the scope of this document. Note: It is possible for a module to work when compiled against a similar kernel source code, though this is not guaranteed to work due to differences in kernel structures, exported symbols and incompatible configuration parameters.\r
+       -If the target is running Linux 3.12 or later the kernel driver is not required and userspace APIs will be used instead.\r
 \r
 *** Kernel configuration ***\r
 \r
@@ -24,7 +25,7 @@ menuconfig options (depending on the kernel version, the location of these confi
   - [*] Profiling Support (enables CONFIG_PROFILING)\r
 - Kernel Features\r
   - [*] High Resolution Timer Support (enables CONFIG_HIGH_RES_TIMERS)\r
-  - [*] Use local timer interrupts (only required for SMP, enables CONFIG_LOCAL_TIMERS)\r
+  - [*] Use local timer interrupts (only required for SMP and for version before Linux 3.12, enables CONFIG_LOCAL_TIMERS)\r
   - [*] Enable hardware performance counter support for perf events (enables CONFIG_HW_PERF_EVENTS)\r
 - CPU Power Management\r
   - CPU Frequency scaling\r
@@ -46,8 +47,10 @@ CONFIG_DEBUG_INFO (optional, used for analyzing the kernel)
 CONFIG_CPU_FREQ (optional, provides frequency setting of the CPU)\r
 \r
 These may be verified on a running system using /proc/config.gz (if this file exists) by running 'zcat /proc/config.gz | grep <option>'. For example, confirming that CONFIG_PROFILING is enabled\r
-  > zcat /proc/config.gz | grep CONFIG_PROFILING\r
-  CONFIG_PROFILING=y\r
+       > zcat /proc/config.gz | grep CONFIG_PROFILING\r
+       CONFIG_PROFILING=y\r
+\r
+If a device tree is used it must include the pmu bindings, see Documentation/devicetree/bindings/arm/pmu.txt for details.\r
 \r
 *** Checking the gator requirements ***\r
 \r
@@ -64,6 +67,17 @@ for example when using the linaro-toolchain-binaries
        make -C /home/username/kernel_2.6.32/ M=`pwd` ARCH=arm CROSS_COMPILE=/home/username/gcc-linaro-arm-linux-gnueabihf-4.7-2013.01-20130125_linux/bin/arm-linux-gnueabihf- modules\r
 If successful, a gator.ko module should be generated\r
 \r
+It is also possible to integrate the gator.ko module into the kernel build system\r
+       cd /path/to/kernel/build/dir\r
+       cd drivers\r
+       mkdir gator\r
+       cp -r /path/to/gator/driver-src/* gator\r
+Edit Makefile in the kernel drivers folder and add this to the end\r
+       obj-$(CONFIG_GATOR)             += gator/\r
+Edit Kconfig in the kernel drivers folder and add this before the last endmenu\r
+       source "drivers/gator/Kconfig"\r
+You can now select gator when using menuconfig while configuring the kernel and rebuild as directed\r
+\r
 *** Building the gator daemon ***\r
 \r
 cd /path/to/gator/daemon-src\r
@@ -78,6 +92,9 @@ For Android targets (install the android ndk, see developer.android.com)
        ndk-build\r
                or execute /path/to/ndk/ndk-build if the ndk is not on your path\r
        gatord should now be created and located in libs/armeabi\r
+       If you get an error like the following, upgrade to a more recent version of the android ndk\r
+               jni/PerfGroup.cpp: In function 'int sys_perf_event_open(perf_event_attr*, pid_t, int, int, long unsigned int)':\r
+               jni/PerfGroup.cpp:36:17: error: '__NR_perf_event_open' was not declared in this scope\r
 \r
 *** Running gator ***\r
 \r
@@ -88,6 +105,7 @@ gator.ko must be located in the same directory as gatord on the target or the lo
 With root privileges, run the daemon\r
        sudo ./gatord &\r
 Note: gatord requires libstdc++.so.6 which is usually supplied by the Linux distribution on the target. A copy of libstdc++.so.6 is available in the DS-5 Linux example distribution.\r
+If gator.ko is not loaded and is not in the same directory as gatord when using Linux 3.12 or later, gatord can run without gator.ko by using userspace APIs. Not all features are supported by userspace gator. If /dev/gator/version does not exist after starting gatord it is running userspace gator.\r
 \r
 *** Customizing the l2c-310 Counter ***\r
 \r
@@ -96,6 +114,10 @@ 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:\r
        insmod gator.ko l2c310_addr=0\r
 \r
+*** CCN-504 ***\r
+\r
+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.\r
+\r
 *** Compiling an application or shared library ***\r
 \r
 Recommended compiler settings:\r
@@ -113,18 +135,31 @@ Attempting to run an incompatible binary often results in the confusing error me
 *** Bugs ***\r
 \r
 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.\r
-\r
-# ls /sys/bus/event_source/devices/\r
-ARMv7_Cortex_A9  breakpoint  software  tracepoint\r
-\r
+       # ls /sys/bus/event_source/devices/\r
+       ARMv7_Cortex_A9  breakpoint  software  tracepoint\r
 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\r
 \r
+There is a bug in some Linux kernels where an Oops may occurs when using userspace gator and a core is offlined. The fix was merged into mainline in 3.14-rc5, see http://git.kernel.org/tip/e3703f8cdfcf39c25c4338c3ad8e68891cca3731, and as been backported to older kernels.\r
+\r
+If you see this error when using SELinux, ex: Android 4.4 or later\r
+       # ./gatord\r
+       Unable to load (insmod) gator.ko driver:\r
+         >>> gator.ko must be built against the current kernel version & configuration\r
+         >>> See dmesg for more details\r
+       # dmesg\r
+       ...\r
+       <7>[ 6745.475110] SELinux: initialized (dev gatorfs, type gatorfs), not configured for labeling\r
+       <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\r
+disable SELinux so that gatorfs can be mounted by running\r
+       # setenforce 0\r
+Once gator is started, SELinux can be reenabled\r
+\r
 *** Profiling the kernel (optional) ***\r
 \r
 CONFIG_DEBUG_INFO must be enabled, see "Kernel configuration" section above.\r
 Use vmlinux as the image for debug symbols in Streamline.\r
 Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the driver as an image to Streamline.\r
-To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko.\r
+To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko or run "echo 1 > /sys/module/gator/parameters/kernel_stack_unwinding" as root on the target after gatord is started.\r
 \r
 *** Automatically start gator on boot (optional) ***\r
 \r
@@ -137,4 +172,3 @@ update-rc.d rungator.sh defaults
 *** GPL License ***\r
 \r
 For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz.\r
-\r
index a0429712fa82267f0db9430c4dff2bae61c338c3..045d028fda5f5176d8f2e2ab966732efa2da1a4d 100644 (file)
@@ -1,7 +1,7 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h configuration_xml.h)
+XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h)
 
 LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -DETCDIR=\"/etc\" -Ilibsensors
 
@@ -9,22 +9,33 @@ LOCAL_SRC_FILES := \
        Buffer.cpp \
        CapturedXML.cpp \
        Child.cpp \
-       Collector.cpp \
        ConfigurationXML.cpp \
        Driver.cpp \
+       DriverSource.cpp \
+       DynBuf.cpp \
        EventsXML.cpp \
+       ExternalSource.cpp \
        Fifo.cpp \
        Hwmon.cpp \
        KMod.cpp \
        LocalCapture.cpp \
        Logging.cpp \
        main.cpp \
+       Monitor.cpp \
        OlySocket.cpp \
        OlyUtility.cpp \
+       PerfBuffer.cpp \
+       PerfDriver.cpp \
+       PerfGroup.cpp \
+       PerfSource.cpp \
+       Proc.cpp \
        Sender.cpp \
        SessionData.cpp \
        SessionXML.cpp \
+       Source.cpp \
        StreamlineSetup.cpp \
+       UEvent.cpp \
+       UserSpaceSource.cpp \
        libsensors/access.c \
        libsensors/conf-lex.c \
        libsensors/conf-parse.c \
index 090a71553277b6ab74073552c106a627688b2588..93557dabed9f1835910243ab7cff0802ad3d38fe 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
 #include "Sender.h"
 #include "SessionData.h"
 
-#define mask (size - 1)
-
-Buffer::Buffer (const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : core(core), buftype(buftype), size(size), readPos(0), writePos(0), commitPos(0), available(true), done(false), buf(new char[size]), commitTime(gSessionData->mLiveRate), readerSem(readerSem) {
-       if ((size & mask) != 0) {
+#define mask (mSize - 1)
+
+enum {
+       CODE_PEA    = 1,
+       CODE_KEYS   = 2,
+       CODE_FORMAT = 3,
+       CODE_MAPS   = 4,
+       CODE_COMM   = 5,
+};
+
+// Summary Frame Messages
+enum {
+       MESSAGE_SUMMARY = 1,
+       MESSAGE_CORE_NAME = 3,
+};
+
+// From gator_marshaling.c
+#define NEWLINE_CANARY \
+       /* Unix */ \
+       "1\n" \
+       /* Windows */ \
+       "2\r\n" \
+       /* Mac OS */ \
+       "3\r" \
+       /* RISC OS */ \
+       "4\n\r" \
+       /* 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) {
+       if ((mSize & mask) != 0) {
                logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
                handleException();
        }
        frame();
 }
 
-Buffer::~Buffer () {
-       delete [] buf;
+Buffer::~Buffer() {
+       delete [] mBuf;
 }
 
-void Buffer::write (Sender * const sender) {
+void Buffer::write(Sender *const sender) {
        if (!commitReady()) {
                return;
        }
 
        // determine the size of two halves
-       int length1 = commitPos - readPos;
-       char * buffer1 = buf + readPos;
+       int length1 = mCommitPos - mReadPos;
+       char *buffer1 = mBuf + mReadPos;
        int length2 = 0;
-       char * buffer2 = buf;
+       char *buffer2 = mBuf;
        if (length1 < 0) {
-               length1 = size - readPos;
-               length2 = commitPos;
+               length1 = mSize - mReadPos;
+               length2 = mCommitPos;
        }
 
        logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
@@ -53,22 +80,22 @@ void Buffer::write (Sender * const sender) {
                sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
        }
 
-       readPos = commitPos;
+       mReadPos = mCommitPos;
 }
 
-bool Buffer::commitReady () const {
-       return commitPos != readPos;
+bool Buffer::commitReady() const {
+       return mCommitPos != mReadPos;
 }
 
-int Buffer::bytesAvailable () const {
-       int filled = writePos - readPos;
+int Buffer::bytesAvailable() const {
+       int filled = mWritePos - mReadPos;
        if (filled < 0) {
-               filled += size;
+               filled += mSize;
        }
 
-       int remaining = size - filled;
+       int remaining = mSize - filled;
 
-       if (available) {
+       if (mAvailable) {
                // Give some extra room; also allows space to insert the overflow error packet
                remaining -= 200;
        } else {
@@ -79,58 +106,68 @@ int Buffer::bytesAvailable () const {
        return remaining;
 }
 
-bool Buffer::checkSpace (const int bytes) {
+bool Buffer::checkSpace(const int bytes) {
        const int remaining = bytesAvailable();
 
        if (remaining < bytes) {
-               available = false;
+               mAvailable = false;
        } else {
-               available = true;
+               mAvailable = true;
        }
 
-       return available;
+       return mAvailable;
+}
+
+int Buffer::contiguousSpaceAvailable() const {
+       int remaining = bytesAvailable();
+       int contiguous = mSize - mWritePos;
+       if (remaining < contiguous) {
+               return remaining;
+       } else {
+               return contiguous;
+       }
 }
 
-void Buffer::commit (const uint64_t time) {
+void Buffer::commit(const uint64_t time) {
        // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
        const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
-       int length = writePos - commitPos;
+       int length = mWritePos - mCommitPos;
        if (length < 0) {
-               length += size;
+               length += mSize;
        }
        length = length - typeLength - sizeof(int32_t);
        for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
-               buf[(commitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
+               mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
        }
 
-       logg->logMessage("Committing data readPos: %i writePos: %i commitPos: %i", readPos, writePos, commitPos);
-       commitPos = writePos;
+       logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
+       mCommitPos = mWritePos;
 
        if (gSessionData->mLiveRate > 0) {
-               while (time > commitTime) {
-                       commitTime += gSessionData->mLiveRate;
+               while (time > mCommitTime) {
+                       mCommitTime += gSessionData->mLiveRate;
                }
        }
 
-       if (!done) {
+       if (!mIsDone) {
                frame();
        }
 
        // send a notification that data is ready
-       sem_post(readerSem);
+       sem_post(mReaderSem);
 }
 
-void Buffer::check (const uint64_t time) {
-       int filled = writePos - commitPos;
+void Buffer::check(const uint64_t time) {
+       int filled = mWritePos - mCommitPos;
        if (filled < 0) {
-               filled += size;
+               filled += mSize;
        }
-       if (filled >= ((size * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= commitTime)) {
+       if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
                commit(time);
        }
 }
 
-void Buffer::packInt (int32_t x) {
+void Buffer::packInt(int32_t x) {
        int packedBytes = 0;
        int more = true;
        while (more) {
@@ -144,14 +181,14 @@ void Buffer::packInt (int32_t x) {
                        b |= 0x80;
                }
 
-               buf[(writePos + packedBytes) & mask] = b;
+               mBuf[(mWritePos + packedBytes) & mask] = b;
                packedBytes++;
        }
 
-       writePos = (writePos + packedBytes) & mask;
+       mWritePos = (mWritePos + packedBytes) & mask;
 }
 
-void Buffer::packInt64 (int64_t x) {
+void Buffer::packInt64(int64_t x) {
        int packedBytes = 0;
        int more = true;
        while (more) {
@@ -165,24 +202,61 @@ void Buffer::packInt64 (int64_t x) {
                        b |= 0x80;
                }
 
-               buf[(writePos + packedBytes) & mask] = b;
+               mBuf[(mWritePos + packedBytes) & mask] = b;
                packedBytes++;
        }
 
-       writePos = (writePos + packedBytes) & mask;
+       mWritePos = (mWritePos + packedBytes) & mask;
+}
+
+void Buffer::writeBytes(const void *const data, size_t count) {
+       size_t i;
+       for (i = 0; i < count; ++i) {
+               mBuf[(mWritePos + i) & mask] = static_cast<const char *>(data)[i];
+       }
+
+       mWritePos = (mWritePos + i) & mask;
 }
 
-void Buffer::frame () {
+void Buffer::writeString(const char *const str) {
+       const int len = strlen(str);
+       packInt(len);
+       writeBytes(str, len);
+}
+
+void Buffer::frame() {
        if (!gSessionData->mLocalCapture) {
                packInt(RESPONSE_APC_DATA);
        }
        // Reserve space for the length
-       writePos += sizeof(int32_t);
-       packInt(buftype);
-       packInt(core);
+       mWritePos += sizeof(int32_t);
+       packInt(mBufType);
+       packInt(mCore);
 }
 
-bool Buffer::eventHeader (const uint64_t curr_time) {
+void Buffer::summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
+       packInt(MESSAGE_SUMMARY);
+       writeString(NEWLINE_CANARY);
+       packInt64(timestamp);
+       packInt64(uptime);
+       packInt64(monotonicDelta);
+       writeString("uname");
+       writeString(uname);
+       writeString("");
+       check(1);
+}
+
+void Buffer::coreName(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);
+}
+
+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
@@ -193,9 +267,9 @@ bool Buffer::eventHeader (const uint64_t curr_time) {
        return retval;
 }
 
-bool Buffer::eventTid (const int tid) {
+bool Buffer::eventTid(const int tid) {
        bool retval = false;
-       if (checkSpace(2*MAXSIZE_PACK32)) {
+       if (checkSpace(2 * MAXSIZE_PACK32)) {
                packInt(1);     // key of 1 indicates a tid
                packInt(tid);
                retval = true;
@@ -204,25 +278,94 @@ bool Buffer::eventTid (const int tid) {
        return retval;
 }
 
-void Buffer::event (const int32_t key, const int32_t value) {
+void Buffer::event(const int32_t 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) {
+void Buffer::event64(const int64_t key, const int64_t value) {
        if (checkSpace(2 * MAXSIZE_PACK64)) {
                packInt64(key);
                packInt64(value);
        }
 }
 
-void Buffer::setDone () {
-       done = true;
+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();
+       }
+       // Don't know the real perf time so use 1 as it will work for now
+       check(1);
+}
+
+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();
+       }
+       check(1);
+}
+
+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();
+       }
+       check(1);
+}
+
+void Buffer::maps(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();
+       }
+       check(1);
+}
+
+void Buffer::comm(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();
+       }
+       check(1);
+}
+
+void Buffer::setDone() {
+       mIsDone = true;
        commit(0);
 }
 
-bool Buffer::isDone () const {
-       return done && readPos == commitPos && commitPos == writePos;
+bool Buffer::isDone() const {
+       return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;
 }
index b3c8d78cf758af6cffbacd0a8e5e43bee2e4c5b2..50237771860c184d1c03b8c2a2687cadd8aed9d9 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
@@ -9,54 +9,89 @@
 #ifndef BUFFER_H
 #define BUFFER_H
 
-#include <stddef.h>
 #include <stdint.h>
 #include <semaphore.h>
 
+#include "k/perf_event.h"
+
 class Sender;
 
+enum {
+       FRAME_SUMMARY       =  1,
+       FRAME_BLOCK_COUNTER =  5,
+       FRAME_EXTERNAL      = 10,
+       FRAME_PERF_ATTRS    = 11,
+       FRAME_PERF          = 12,
+};
+
 class Buffer {
 public:
        static const size_t MAXSIZE_PACK32 = 5;
        static const size_t MAXSIZE_PACK64 = 10;
 
-       Buffer (int32_t core, int32_t buftype, const int size, sem_t *const readerSem);
-       ~Buffer ();
+       Buffer(int32_t core, int32_t buftype, const int size, sem_t *const readerSem);
+       ~Buffer();
+
+       void write(Sender *sender);
+
+       int bytesAvailable() const;
+       int contiguousSpaceAvailable() const;
+       void commit(const uint64_t time);
+       void check(const uint64_t time);
 
-       void write (Sender * sender);
+       void frame();
 
-       int bytesAvailable () const;
-       void commit (const uint64_t time);
-       void check (const uint64_t time);
+       // 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 frame ();
+       // 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);
 
-       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);
+       // 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 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 setDone ();
-       bool isDone () const;
+       void setDone();
+       bool isDone() const;
+
+       // Prefer a new member to using these functions if possible
+       char *getWritePos() { return mBuf + mWritePos; }
+       void advanceWrite(int bytes) { mWritePos = (mWritePos + bytes) & /*mask*/(mSize - 1); }
+
+       static void writeLEInt(unsigned char *buf, int v) {
+               buf[0] = (v >> 0) & 0xFF;
+               buf[1] = (v >> 8) & 0xFF;
+               buf[2] = (v >> 16) & 0xFF;
+               buf[3] = (v >> 24) & 0xFF;
+       }
 
 private:
-       bool commitReady () const;
-       bool checkSpace (int bytes);
-
-       void packInt (int32_t x);
-       void packInt64 (int64_t x);
-
-       const int32_t core;
-       const int32_t buftype;
-       const int size;
-       int readPos;
-       int writePos;
-       int commitPos;
-       bool available;
-       bool done;
-       char *const buf;
-       uint64_t commitTime;
-       sem_t *const readerSem;
+       bool commitReady() const;
+       bool checkSpace(int bytes);
+
+       void packInt(int32_t x);
+       void packInt64(int64_t x);
+       void writeBytes(const void *const data, size_t count);
+       void writeString(const char *const str);
+
+       const int32_t mCore;
+       const int32_t mBufType;
+       const int mSize;
+       int mReadPos;
+       int mWritePos;
+       int mCommitPos;
+       bool mAvailable;
+       bool mIsDone;
+       char *const mBuf;
+       uint64_t mCommitTime;
+       sem_t *const mReaderSem;
 
        // Intentionally unimplemented
        Buffer(const Buffer &);
index 30c4c44c5d92dc6cdc9f87cc23d8ed53fafd83e7..cf79b72a1166966a2e1f71d0aff8a26a7befa59a 100644 (file)
@@ -1,16 +1,18 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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 "CapturedXML.h"
+
 #include <stdlib.h>
 #include <string.h>
 #include <dirent.h>
+
 #include "SessionData.h"
-#include "CapturedXML.h"
 #include "Logging.h"
 #include "OlyUtility.h"
 
@@ -30,6 +32,9 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
 
        captured = mxmlNewElement(xml, "captured");
        mxmlElementSetAttr(captured, "version", "1");
+       if (gSessionData->perf.isSetup()) {
+         mxmlElementSetAttr(captured, "type", "Perf");
+       }
        mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION);
        if (includeTime) { // Send the following only after the capture is complete
                if (time(NULL) > 1267000000) { // If the time is reasonable (after Feb 23, 2010)
@@ -41,7 +46,7 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
        mxmlElementSetAttr(target, "name", gSessionData->mCoreName);
        mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate);
        mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores);
-       mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mCpuId);
+       mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mMaxCpuId);
 
        if (!gSessionData->mOneShot && (gSessionData->mSampleRate > 0)) {
                mxmlElementSetAttr(target, "supports_live", "yes");
index b0482f593c6f8444fb56f242bd855b035f5a4de7..efc1e52bdba33519fb83f8a0af02a8b835995ff5 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index 9ee2ef8afb9d582225cb0823151758138e9b119c..ca33561ffdca6d21dbacb4af3b8d4d23d252c5fc 100644 (file)
@@ -1,38 +1,39 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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 "Child.h"
+
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
 #include <unistd.h>
 #include <sys/prctl.h>
+
 #include "Logging.h"
 #include "CapturedXML.h"
 #include "SessionData.h"
-#include "Child.h"
 #include "LocalCapture.h"
-#include "Collector.h"
 #include "Sender.h"
 #include "OlyUtility.h"
+#include "OlySocket.h"
 #include "StreamlineSetup.h"
 #include "ConfigurationXML.h"
 #include "Driver.h"
-#include "Fifo.h"
-#include "Buffer.h"
-
-#define NS_PER_S ((uint64_t)1000000000)
-#define NS_PER_US 1000
+#include "PerfSource.h"
+#include "DriverSource.h"
+#include "UserSpaceSource.h"
+#include "ExternalSource.h"
 
 static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads
-static Fifo* collectorFifo = NULL;   // Shared by Child.cpp and spawned threads
-static Buffer* buffer = NULL;
+static Source *primarySource = NULL;
+static Source *userSpaceSource = NULL;
+static Source *externalSource = NULL;
 static Sender* sender = NULL;        // Shared by Child.cpp and spawned threads
-static Collector* collector = NULL;
 Child* child = NULL;                 // shared by Child.cpp and main.cpp
 
 extern void cleanUp();
@@ -78,7 +79,7 @@ static void child_handler(int signum) {
        }
        beenHere = true;
        logg->logMessage("Gator is shutting down.");
-       if (signum == SIGALRM || !collector) {
+       if (signum == SIGALRM || !primarySource) {
                exit(1);
        } else {
                child->endSession();
@@ -139,77 +140,22 @@ static void *stopThread(void *) {
        return 0;
 }
 
-static void *countersThread(void *) {
-       prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
-
-       gSessionData->hwmon.start();
-
-       int64_t monotonic_started = 0;
-       while (monotonic_started <= 0) {
-               usleep(10);
-
-               if (Collector::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
-                       logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
-                       handleException();
-               }
-       }
-
-       uint64_t next_time = 0;
-       while (gSessionData->mSessionIsActive) {
-               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();
-               }
-               const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started;
-               // Sample ten times a second ignoring gSessionData->mSampleRate
-               next_time += NS_PER_S/10;//gSessionData->mSampleRate;
-               if (next_time < curr_time) {
-                       logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
-                       next_time = curr_time;
-               }
-
-               if (buffer->eventHeader(curr_time)) {
-                       gSessionData->hwmon.read(buffer);
-                       // Only check after writing all counters so that time and corresponding counters appear in the same frame
-                       buffer->check(curr_time);
-               }
-
-               if (buffer->bytesAvailable() <= 0) {
-                       logg->logMessage("One shot (counters)");
-                       child->endSession();
-               }
-
-               usleep((next_time - curr_time)/NS_PER_US);
-       }
-
-       buffer->setDone();
-
-       return NULL;
-}
-
 static void *senderThread(void *) {
-       int length = 1;
-       char* data;
        char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0};
 
        sem_post(&senderThreadStarted);
        prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0);
        sem_wait(&haltPipeline);
 
-       while (length > 0 || !buffer->isDone()) {
+       while (!primarySource->isDone() || (userSpaceSource != NULL && !userSpaceSource->isDone()) || (externalSource != NULL && !externalSource->isDone())) {
                sem_wait(&senderSem);
-               data = collectorFifo->read(&length);
-               if (data != NULL) {
-                       sender->writeData(data, length, RESPONSE_APC_DATA);
-                       collectorFifo->release();
+
+               primarySource->write(sender);
+               if (userSpaceSource != NULL) {
+                       userSpaceSource->write(sender);
                }
-               if (!buffer->isDone()) {
-                       buffer->write(sender);
+               if (externalSource != NULL) {
+                       externalSource->write(sender);
                }
        }
 
@@ -255,15 +201,13 @@ void Child::initialization() {
 
 void Child::endSession() {
        gSessionData->mSessionIsActive = false;
-       collector->stop();
+       primarySource->interrupt();
        sem_post(&haltPipeline);
 }
 
 void Child::run() {
-       char* collectBuffer;
-       int bytesCollected = 0;
        LocalCapture* localCapture = NULL;
-       pthread_t durationThreadID, stopThreadID, senderThreadID, countersThreadID;
+       pthread_t durationThreadID, stopThreadID, senderThreadID;
 
        prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0);
 
@@ -282,7 +226,11 @@ void Child::run() {
        { ConfigurationXML configuration; }
 
        // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
-       collector = new Collector();
+       if (!gSessionData->perf.isSetup()) {
+         primarySource = new DriverSource(&senderSem, &startProfile);
+       } else {
+         primarySource = new PerfSource(&senderSem, &startProfile);
+       }
 
        // Initialize all drivers
        for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
@@ -317,15 +265,11 @@ void Child::run() {
                free(xmlString);
        }
 
-       // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
-       logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, collector->getBufferSize());
-       collectorFifo = new Fifo(collector->getBufferSize() + 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem);
-
-       // Get the initial pointer to the collect buffer
-       collectBuffer = collectorFifo->start();
-
-       // Create a new Block Counter Buffer
-       buffer = new Buffer(0, 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem);
+       // Must be after session XML is parsed
+       if (!primarySource->prepare()) {
+               logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
+               handleException();
+       }
 
        // Sender thread shall be halted until it is signaled for one shot mode
        sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
@@ -340,14 +284,21 @@ void Child::run() {
                thread_creation_success = false;
        }
 
-       bool startcountersThread = gSessionData->hwmon.countersEnabled();
-       if (startcountersThread) {
-               if (pthread_create(&countersThreadID, NULL, countersThread, this)) {
-                       thread_creation_success = false;
+       if (gSessionData->hwmon.countersEnabled()) {
+               userSpaceSource = new UserSpaceSource(&senderSem);
+               if (!userSpaceSource->prepare()) {
+                       logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
+                       handleException();
                }
-       } else {
-               // Let senderThread know there is no buffer data to send
-               buffer->setDone();
+               userSpaceSource->start();
+       }
+       if (access("/tmp/gator", F_OK) == 0) {
+               externalSource = new ExternalSource(&senderSem);
+               if (!externalSource->prepare()) {
+                       logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
+                       handleException();
+               }
+               externalSource->start();
        }
 
        if (!thread_creation_success) {
@@ -359,28 +310,13 @@ void Child::run() {
        sem_wait(&senderThreadStarted);
 
        // Start profiling
-       logg->logMessage("********** Profiling started **********");
-       collector->start();
-       sem_post(&startProfile);
-
-       // Collect Data
-       do {
-               // This command will stall until data is received from the driver
-               bytesCollected = collector->collect(collectBuffer);
-
-               // In one shot mode, stop collection once all the buffers are filled
-               if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
-                       if (bytesCollected == -1 || collectorFifo->willFill(bytesCollected)) {
-                               logg->logMessage("One shot");
-                               endSession();
-                       }
-               }
-               collectBuffer = collectorFifo->write(bytesCollected);
-       } while (bytesCollected > 0);
-       logg->logMessage("Exit collect data loop");
+       primarySource->run();
 
-       if (startcountersThread) {
-               pthread_join(countersThreadID, NULL);
+       if (externalSource != NULL) {
+               externalSource->join();
+       }
+       if (userSpaceSource != NULL) {
+               userSpaceSource->join();
        }
 
        // Wait for the other threads to exit
@@ -401,9 +337,9 @@ void Child::run() {
 
        logg->logMessage("Profiling ended.");
 
-       delete buffer;
-       delete collectorFifo;
+       delete externalSource;
+       delete userSpaceSource;
+       delete primarySource;
        delete sender;
-       delete collector;
        delete localCapture;
 }
index 0330e9d780276c1228e95c3eabcae708dedb8390..9e206d7113b8353d3375f08fdff409ed1a1c5570 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -9,8 +9,6 @@
 #ifndef        __CHILD_H__
 #define        __CHILD_H__
 
-#include <pthread.h>
-
 class OlySocket;
 
 class Child {
diff --git a/daemon/Collector.h b/daemon/Collector.h
deleted file mode 100644 (file)
index c5e9eac..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2010-2013. 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        __COLLECTOR_H__
-#define        __COLLECTOR_H__
-
-#include <stdio.h>
-
-class Collector {
-public:
-       Collector();
-       ~Collector();
-       void start();
-       void stop();
-       int collect(char* buffer);
-       int getBufferSize() {return mBufferSize;}
-
-       static int readIntDriver(const char* path, int* value);
-       static int readInt64Driver(const char* path, int64_t* value);
-       static int writeDriver(const char* path, int value);
-       static int writeDriver(const char* path, int64_t value);
-       static int writeDriver(const char* path, const char* data);
-       static int writeReadDriver(const char* path, int* value);
-       static int writeReadDriver(const char* path, int64_t* value);
-
-private:
-       int mBufferSize;
-       int mBufferFD;
-
-       void checkVersion();
-};
-
-#endif         //__COLLECTOR_H__
diff --git a/daemon/Config.h b/daemon/Config.h
new file mode 100644 (file)
index 0000000..6f5e2aa
--- /dev/null
@@ -0,0 +1,17 @@
+/**
+ * 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 CONFIG_H
+#define CONFIG_H
+
+#define ARRAY_LENGTH(A) static_cast<int>(sizeof(A)/sizeof((A)[0]))
+
+#define MAX_PERFORMANCE_COUNTERS 50
+#define NR_CPUS 16
+
+#endif // CONFIG_H
index 2a5252a5bb04933f29e84411c049f0f1d5b2d5d9..fd479f2452cd0267bbbbbed280335ae524843924 100644 (file)
@@ -1,15 +1,17 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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 "ConfigurationXML.h"
+
 #include <string.h>
 #include <stdlib.h>
 #include <dirent.h>
-#include "ConfigurationXML.h"
+
 #include "Driver.h"
 #include "Logging.h"
 #include "OlyUtility.h"
@@ -67,6 +69,7 @@ int ConfigurationXML::parse(const char* configurationXML) {
 
        // clear counter overflow
        gSessionData->mCounterOverflow = 0;
+       gSessionData->mIsEBS = false;
        mIndex = 0;
 
        // disable all counters prior to parsing the configuration xml
@@ -155,6 +158,9 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
        if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER));
        if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16));
        if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10));
+       if (counter.getCount() > 0) {
+               gSessionData->mIsEBS = true;
+       }
        counter.setEnabled(true);
 
        // Associate a driver with each counter
@@ -181,9 +187,9 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
 }
 
 void ConfigurationXML::getDefaultConfigurationXml(const char * & xml, unsigned int & len) {
-#include "configuration_xml.h" // defines and initializes char configuration_xml[] and int configuration_xml_len
-       xml = (const char *)configuration_xml;
-       len = configuration_xml_len;
+#include "defaults_xml.h" // defines and initializes char defaults_xml[] and int defaults_xml_len
+       xml = (const char *)defaults_xml;
+       len = defaults_xml_len;
 }
 
 void ConfigurationXML::getPath(char* path) {
index 5650f487b990a45f16e047bc16c0ca573bc4986f..efa415e508b6fd17c78250160ebcd0621f895668 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index 231a85d6e3b55d5c57597f37ce663206d8b34dc8..689174573e4e5518292a6f06034ab947199f04c2 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
@@ -25,7 +25,7 @@ public:
        void clear () {
                mType[0] = '\0';
                mEnabled = false;
-               mEvent = 0;
+               mEvent = -1;
                mCount = 0;
                mKey = 0;
                mDriver = NULL;
index c262467dc219c18ec8c40a175de5530e7d8ff646..09e04016291232477fc2d4d38ff8a75ec48b0dc9 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
index f3a932f852cb089a9cb970a8b5a10fdf6e21da5c..e5ed7b6c1295993bcc454a5b55efbb814b129129 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
@@ -27,7 +27,7 @@ public:
        virtual void setupCounter(Counter &counter) = 0;
 
        // Emits available counters
-       virtual void writeCounters(mxml_node_t *root) const = 0;
+       virtual int writeCounters(mxml_node_t *root) const = 0;
        // Emits possible dynamically generated events/counters
        virtual void writeEvents(mxml_node_t *) const {}
 
similarity index 58%
rename from daemon/Collector.cpp
rename to daemon/DriverSource.cpp
index bf73534692a0b0713a0e1fc2437f677a2255a85b..f78ec6b7ce413648d6b3d8df8e6295b9f37d3fb2 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -8,23 +8,47 @@
 
 #define __STDC_FORMAT_MACROS
 
+#include "DriverSource.h"
+
 #include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/time.h>
 #include <inttypes.h>
-#include "Collector.h"
-#include "SessionData.h"
+#include <unistd.h>
+
+#include "Child.h"
+#include "Fifo.h"
 #include "Logging.h"
 #include "Sender.h"
+#include "SessionData.h"
+
+extern Child *child;
 
-// Driver initialization independent of session settings
-Collector::Collector() {
-       mBufferFD = 0;
+DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) {
+       int driver_version = 0;
 
-       checkVersion();
+       if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
+               logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
+               handleException();
+       }
+
+       // Verify the driver version matches the daemon version
+       if (driver_version != PROTOCOL_VERSION) {
+               if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
+                       // One of the mismatched versions is development version
+                       logg->logError(__FILE__, __LINE__,
+                               "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
+                               ">> The following must be synchronized from engineering repository:\n"
+                               ">> * gator driver\n"
+                               ">> * gator daemon\n"
+                               ">> * Streamline", driver_version, PROTOCOL_VERSION);
+                       handleException();
+               } else {
+                       // Release version mismatch
+                       logg->logError(__FILE__, __LINE__, 
+                               "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
+                               ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
+                       handleException();
+               }
+       }
 
        int enable = -1;
        if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) {
@@ -37,14 +61,15 @@ Collector::Collector() {
                gSessionData->mCores = 1;
        }
 
-       mBufferSize = 0;
        if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) {
                logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size");
                handleException();
        }
 }
 
-Collector::~Collector() {
+DriverSource::~DriverSource() {
+       delete mFifo;
+
        // Write zero for safety, as a zero should have already been written
        writeDriver("/dev/gator/enable", "0");
 
@@ -54,36 +79,21 @@ Collector::~Collector() {
        }
 }
 
-void Collector::checkVersion() {
-       int driver_version = 0;
-
-       if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
-               logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
-               handleException();
-       }
+bool DriverSource::prepare() {
+       // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
+       logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, mBufferSize);
+       mFifo = new Fifo(mBufferSize + 5, gSessionData->mTotalBufferSize*1024*1024, mSenderSem);
 
-       // Verify the driver version matches the daemon version
-       if (driver_version != PROTOCOL_VERSION) {
-               if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
-                       // One of the mismatched versions is development version
-                       logg->logError(__FILE__, __LINE__,
-                               "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
-                               ">> The following must be synchronized from engineering repository:\n"
-                               ">> * gator driver\n"
-                               ">> * gator daemon\n"
-                               ">> * Streamline", driver_version, PROTOCOL_VERSION);
-                       handleException();
-               } else {
-                       // Release version mismatch
-                       logg->logError(__FILE__, __LINE__, 
-                               "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
-                               ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
-                       handleException();
-               }
-       }
+       return true;
 }
 
-void Collector::start() {
+void DriverSource::run() {
+       // Get the initial pointer to the collect buffer
+       char *collectBuffer = mFifo->start();
+       int bytesCollected = 0;
+
+       logg->logMessage("********** Profiling started **********");
+
        // Set the maximum backtrace depth
        if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) {
                logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
@@ -125,79 +135,112 @@ void Collector::start() {
        }
 
        lseek(mBufferFD, 0, SEEK_SET);
+
+       sem_post(mStartProfile);
+
+       // Collect Data
+       do {
+               // This command will stall until data is received from the driver
+               // Calls event_buffer_read in the driver
+               errno = 0;
+               bytesCollected = read(mBufferFD, collectBuffer, mBufferSize);
+
+               // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
+               if (bytesCollected == -1 && errno == EINTR) {
+                       bytesCollected = read(mBufferFD, collectBuffer, mBufferSize);
+               }
+
+               // return the total bytes written
+               logg->logMessage("Driver read of %d bytes", bytesCollected);
+
+               // In one shot mode, stop collection once all the buffers are filled
+               if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
+                       if (bytesCollected == -1 || mFifo->willFill(bytesCollected)) {
+                               logg->logMessage("One shot");
+                               child->endSession();
+                       }
+               }
+               collectBuffer = mFifo->write(bytesCollected);
+       } while (bytesCollected > 0);
+
+       logg->logMessage("Exit collect data loop");
 }
 
-// These commands should cause the read() function in collect() to return
-void Collector::stop() {
-       // This will stop the driver from profiling
+void DriverSource::interrupt() {
+       // This command should cause the read() function in collect() to return and stop the driver from profiling
        if (writeDriver("/dev/gator/enable", "0") != 0) {
                logg->logMessage("Stopping kernel failed");
        }
 }
 
-int Collector::collect(char* buffer) {
-       // Calls event_buffer_read in the driver
-       int bytesRead;
-
-       errno = 0;
-       bytesRead = read(mBufferFD, buffer, mBufferSize);
+bool DriverSource::isDone() {
+       return mLength <= 0;
+}
 
-       // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
-       if (bytesRead == -1 && errno == EINTR) {
-               bytesRead = read(mBufferFD, buffer, mBufferSize);
+void DriverSource::write(Sender *sender) {
+       char *data = mFifo->read(&mLength);
+       if (data != NULL) {
+               sender->writeData(data, mLength, RESPONSE_APC_DATA);
+               mFifo->release();
        }
-
-       // return the total bytes written
-       logg->logMessage("Driver read of %d bytes", bytesRead);
-       return bytesRead;
 }
 
-int Collector::readIntDriver(const char* fullpath, int* value) {
-       FILE* file = fopen(fullpath, "r");
-       if (file == NULL) {
+int DriverSource::readIntDriver(const char *fullpath, int *value) {
+       char data[40]; // Sufficiently large to hold any integer
+       const int fd = open(fullpath, O_RDONLY);
+       if (fd < 0) {
+               return -1;
+       }
+
+       const ssize_t bytes = read(fd, data, sizeof(data) - 1);
+       close(fd);
+       if (bytes < 0) {
                return -1;
        }
-       if (fscanf(file, "%u", value) != 1) {
-               fclose(file);
+       data[bytes] = '\0';
+
+       char *endptr;
+       errno = 0;
+       *value = strtol(data, &endptr, 10);
+       if (errno != 0 || *endptr != '\n') {
                logg->logMessage("Invalid value in file %s", fullpath);
                return -1;
        }
-       fclose(file);
+
        return 0;
 }
 
-int Collector::readInt64Driver(const char* fullpath, int64_t* value) {
-       FILE* file = fopen(fullpath, "r");
-       if (file == NULL) {
+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);
+       if (fd < 0) {
                return -1;
        }
-       if (fscanf(file, "%" SCNi64, value) != 1) {
-               fclose(file);
-               logg->logMessage("Invalid value in file %s", fullpath);
+
+       const ssize_t bytes = read(fd, data, sizeof(data) - 1);
+       close(fd);
+       if (bytes < 0) {
                return -1;
        }
-       fclose(file);
-       return 0;
-}
+       data[bytes] = '\0';
 
-int Collector::writeDriver(const char* path, int value) {
-       char data[40]; // Sufficiently large to hold any integer
-       snprintf(data, sizeof(data), "%d", value);
-       return writeDriver(path, data);
-}
+       char *endptr;
+       errno = 0;
+       *value = strtoll(data, &endptr, 10);
+       if (errno != 0 || *endptr != '\n') {
+               logg->logMessage("Invalid value in file %s", fullpath);
+               return -1;
+       }
 
-int Collector::writeDriver(const char* path, int64_t value) {
-       char data[40]; // Sufficiently large to hold any integer
-       snprintf(data, sizeof(data), "%" PRIi64, value);
-       return writeDriver(path, data);
+       return 0;
 }
 
-int Collector::writeDriver(const char* fullpath, const char* data) {
+int DriverSource::writeDriver(const char *fullpath, const char *data) {
        int fd = open(fullpath, O_WRONLY);
        if (fd < 0) {
                return -1;
        }
-       if (write(fd, data, strlen(data)) < 0) {
+       if (::write(fd, data, strlen(data)) < 0) {
                close(fd);
                logg->logMessage("Opened but could not write to %s", fullpath);
                return -1;
@@ -206,14 +249,26 @@ int Collector::writeDriver(const char* fullpath, const char* data) {
        return 0;
 }
 
-int Collector::writeReadDriver(const char* path, int* value) {
+int DriverSource::writeDriver(const char *path, int value) {
+       char data[40]; // Sufficiently large to hold any integer
+       snprintf(data, sizeof(data), "%d", value);
+       return writeDriver(path, data);
+}
+
+int DriverSource::writeDriver(const char *path, int64_t value) {
+       char data[40]; // Sufficiently large to hold any integer
+       snprintf(data, sizeof(data), "%" PRIi64, value);
+       return writeDriver(path, data);
+}
+
+int DriverSource::writeReadDriver(const char *path, int *value) {
        if (writeDriver(path, *value) || readIntDriver(path, value)) {
                return -1;
        }
        return 0;
 }
 
-int Collector::writeReadDriver(const char* path, int64_t* value) {
+int DriverSource::writeReadDriver(const char *path, int64_t *value) {
        if (writeDriver(path, *value) || readInt64Driver(path, value)) {
                return -1;
        }
diff --git a/daemon/DriverSource.h b/daemon/DriverSource.h
new file mode 100644 (file)
index 0000000..dcf1078
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * 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 DRIVERSOURCE_H
+#define DRIVERSOURCE_H
+
+#include <semaphore.h>
+#include <stdint.h>
+
+#include "Source.h"
+
+class Fifo;
+
+class DriverSource : public Source {
+public:
+       DriverSource(sem_t *senderSem, sem_t *startProfile);
+       ~DriverSource();
+
+       bool prepare();
+       void run();
+       void interrupt();
+
+       bool isDone();
+       void write(Sender *sender);
+
+       static int readIntDriver(const char *fullpath, int *value);
+       static int readInt64Driver(const char *fullpath, int64_t *value);
+       static int writeDriver(const char *fullpath, const char *data);
+       static int writeDriver(const char *path, int value);
+       static int writeDriver(const char *path, int64_t value);
+       static int writeReadDriver(const char *path, int *value);
+       static int writeReadDriver(const char *path, int64_t *value);
+
+private:
+       Fifo *mFifo;
+       sem_t *const mSenderSem;
+       sem_t *const mStartProfile;
+       int mBufferSize;
+       int mBufferFD;
+       int mLength;
+
+       // Intentionally unimplemented
+       DriverSource(const DriverSource &);
+       DriverSource &operator=(const DriverSource &);
+};
+
+#endif // DRIVERSOURCE_H
diff --git a/daemon/DynBuf.cpp b/daemon/DynBuf.cpp
new file mode 100644 (file)
index 0000000..6f92b33
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * 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 "DynBuf.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "Logging.h"
+
+// Pick an aggressive size as buffer is primarily used for disk IO
+#define MIN_BUFFER_FREE (1 << 12)
+
+int DynBuf::resize(const size_t minCapacity) {
+       size_t scaledCapacity = 2 * capacity;
+       if (scaledCapacity < minCapacity) {
+               scaledCapacity = minCapacity;
+       }
+       if (scaledCapacity < 2 * MIN_BUFFER_FREE) {
+               scaledCapacity = 2 * MIN_BUFFER_FREE;
+       }
+       capacity = scaledCapacity;
+
+       buf = static_cast<char *>(realloc(buf, capacity));
+       if (buf == NULL) {
+               return -errno;
+       }
+
+       return 0;
+}
+
+bool DynBuf::read(const char *const path) {
+       int result = false;
+
+       const int fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       length = 0;
+
+       for (;;) {
+               const size_t minCapacity = length + MIN_BUFFER_FREE + 1;
+               if (capacity < minCapacity) {
+                       if (resize(minCapacity) != 0) {
+                               logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
+                               goto fail;
+                       }
+               }
+
+               const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1);
+               if (bytes < 0) {
+                       logg->logMessage("%s(%s:%i): read failed", __FUNCTION__, __FILE__, __LINE__);
+                       goto fail;
+               } else if (bytes == 0) {
+                       break;
+               }
+               length += bytes;
+       }
+
+       buf[length] = '\0';
+       result = true;
+
+ fail:
+       close(fd);
+
+       return result;
+}
+
+int DynBuf::readlink(const char *const path) {
+       ssize_t bytes = MIN_BUFFER_FREE;
+
+       for (;;) {
+               if (static_cast<size_t>(bytes) >= capacity) {
+                       const int err = resize(2 * bytes);
+                       if (err != 0) {
+                               return err;
+                       }
+               }
+               bytes = ::readlink(path, buf, capacity);
+               if (bytes < 0) {
+                       return -errno;
+               } else if (static_cast<size_t>(bytes) < capacity) {
+                       break;
+               }
+       }
+
+       length = bytes;
+       buf[bytes] = '\0';
+
+       return 0;
+}
+
+bool DynBuf::printf(const char *format, ...) {
+       va_list ap;
+
+       if (capacity <= 0) {
+               if (resize(2 * MIN_BUFFER_FREE) != 0) {
+                       logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+       }
+
+       va_start(ap, format);
+       int bytes = vsnprintf(buf, capacity, format, ap);
+       va_end(ap);
+       if (bytes < 0) {
+               logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       if (static_cast<size_t>(bytes) > capacity) {
+               if (resize(bytes + 1) != 0) {
+                       logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+
+               va_start(ap, format);
+               bytes = vsnprintf(buf, capacity, format, ap);
+               va_end(ap);
+               if (bytes < 0) {
+                       logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+       }
+
+       length = bytes;
+
+       return true;
+}
diff --git a/daemon/DynBuf.h b/daemon/DynBuf.h
new file mode 100644 (file)
index 0000000..2f4554a
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * 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 DYNBUF_H
+#define DYNBUF_H
+
+#include <stdlib.h>
+
+class DynBuf {
+public:
+       DynBuf() : capacity(0), length(0), buf(NULL) {}
+       ~DynBuf() {
+               reset();
+       }
+
+       inline void reset() {
+               capacity = 0;
+               length = 0;
+               if (buf != NULL) {
+                       free(buf);
+                       buf = NULL;
+               }
+       }
+
+       bool read(const char *const path);
+       // On error instead of printing the error and returning false, this returns -errno
+       int readlink(const char *const path);
+       __attribute__ ((format(printf, 2, 3)))
+       bool printf(const char *format, ...);
+
+       size_t getLength() const { return length; }
+       const char *getBuf() const { return buf; }
+       char *getBuf() { return buf; }
+
+private:
+       int resize(const size_t minCapacity);
+
+       size_t capacity;
+       size_t length;
+       char *buf;
+
+       // Intentionally undefined
+       DynBuf(const DynBuf &);
+       DynBuf &operator=(const DynBuf &);
+};
+
+#endif // DYNBUF_H
index 2a80482e0b8d1f76b013519f225e5585081b17ff..a07a046f335367b7825f639b6d037800c458a54c 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
@@ -35,7 +35,7 @@ char* EventsXML::getXML() {
                fclose(fl);
        } else {
                logg->logMessage("Unable to locate events.xml, using default");
-               xml = mxmlLoadString(NULL, (char *)events_xml, MXML_NO_CALLBACK);
+               xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK);
        }
 
        // Add dynamic events from the drivers
index 8e693efab2021271e15d9add17a8b63d892bcea8..6cd1560f7d4e13d042281c31e1bdfe8288c054ba 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
diff --git a/daemon/ExternalSource.cpp b/daemon/ExternalSource.cpp
new file mode 100644 (file)
index 0000000..fe5824b
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * 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 "ExternalSource.h"
+
+#include <sys/prctl.h>
+
+#include "Logging.h"
+#include "OlySocket.h"
+#include "SessionData.h"
+
+ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 1024, senderSem), mSock("/tmp/gator") {
+}
+
+ExternalSource::~ExternalSource() {
+}
+
+bool ExternalSource::prepare() {
+       return true;
+}
+
+void ExternalSource::run() {
+       prctl(PR_SET_NAME, (unsigned long)&"gatord-uds", 0, 0, 0);
+
+       while (gSessionData->mSessionIsActive) {
+               // Will be aborted when the socket is closed at the end of the capture
+               int length = mSock.receive(mBuffer.getWritePos(), mBuffer.contiguousSpaceAvailable());
+               if (length <= 0) {
+                       break;
+               }
+
+               mBuffer.advanceWrite(length);
+               mBuffer.check(0);
+       }
+
+       mBuffer.setDone();
+}
+
+void ExternalSource::interrupt() {
+       // Do nothing
+}
+
+bool ExternalSource::isDone() {
+       return mBuffer.isDone();
+}
+
+void ExternalSource::write(Sender *sender) {
+       if (!mBuffer.isDone()) {
+               mBuffer.write(sender);
+       }
+}
diff --git a/daemon/ExternalSource.h b/daemon/ExternalSource.h
new file mode 100644 (file)
index 0000000..2052bdf
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * 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 EXTERNALSOURCE_H
+#define EXTERNALSOURCE_H
+
+#include <semaphore.h>
+
+#include "Buffer.h"
+#include "OlySocket.h"
+#include "Source.h"
+
+// Unix domain socket counters from external sources like graphics drivers
+class ExternalSource : public Source {
+public:
+       ExternalSource(sem_t *senderSem);
+       ~ExternalSource();
+
+       bool prepare();
+       void run();
+       void interrupt();
+
+       bool isDone();
+       void write(Sender *sender);
+
+private:
+       Buffer mBuffer;
+       OlySocket mSock;
+
+       // Intentionally unimplemented
+       ExternalSource(const ExternalSource &);
+       ExternalSource &operator=(const ExternalSource &);
+};
+
+#endif // EXTERNALSOURCE_H
index 250a4d023bf265f72e170fdc24a5678421294cb7..f672e92a6807403c43274ad3705cc16a2dd2aee6 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index d25cd68825614a621eab87089fb877669d9ef7d3..7dd7426132d8c332c026a83879e20b20bfd7d0f5 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -12,7 +12,7 @@
 #ifdef WIN32
 #include <windows.h>
 #define sem_t HANDLE
-#define sem_init(sem, pshared, value) ((*(sem) = CreateSemaphore(NULL, value, INFINITE, NULL)) == NULL)
+#define sem_init(sem, pshared, value) ((*(sem) = CreateSemaphore(NULL, value, LONG_MAX, NULL)) == NULL)
 #define sem_wait(sem) WaitForSingleObject(*(sem), INFINITE)
 #define sem_post(sem) ReleaseSemaphore(*(sem), 1, NULL)
 #define sem_destroy(sem) CloseHandle(*(sem))
index 1d7c0da9cc83673eb1beba18c72518f7f9e43380..778f30755dfe14a99bbb42f0ecf01051a5cb9851 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
@@ -17,7 +17,7 @@
 
 class HwmonCounter {
 public:
-       HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature);
+       HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature);
        ~HwmonCounter();
 
        HwmonCounter *getNext() const { return next; }
@@ -69,7 +69,7 @@ private:
        HwmonCounter &operator=(const HwmonCounter &);
 };
 
-HwmonCounter::HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(key), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) {
+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];
@@ -205,6 +205,23 @@ bool HwmonCounter::canRead() {
 }
 
 Hwmon::Hwmon() : counters(NULL) {
+}
+
+Hwmon::~Hwmon() {
+       while (counters != NULL) {
+               HwmonCounter * counter = counters;
+               counters = counter->getNext();
+               delete counter;
+       }
+       sensors_cleanup();
+}
+
+void Hwmon::setup() {
+       // hwmon does not currently work with perf
+       if (gSessionData->perf.isSetup()) {
+               return;
+       }
+
        int err = sensors_init(NULL);
        if (err) {
                logg->logMessage("Failed to initialize libsensors! (%d)", err);
@@ -218,20 +235,11 @@ Hwmon::Hwmon() : counters(NULL) {
                int feature_nr = 0;
                const sensors_feature *feature;
                while ((feature = sensors_get_features(chip, &feature_nr))) {
-                       counters = new HwmonCounter(counters, getEventKey(), chip, feature);
+                       counters = new HwmonCounter(counters, chip, feature);
                }
        }
 }
 
-Hwmon::~Hwmon() {
-       while (counters != NULL) {
-               HwmonCounter * counter = counters;
-               counters = counter->getNext();
-               delete counter;
-       }
-       sensors_cleanup();
-}
-
 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) {
@@ -271,14 +279,18 @@ void Hwmon::setupCounter(Counter &counter) {
        counter.setKey(hwmonCounter->getKey());
 }
 
-void Hwmon::writeCounters(mxml_node_t *root) const {
+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 {
index 46bb42e898d7dee083cfe2e4f36823446de47470..a22a3609f99f81241e54f3f5a40ef7e0aa1c94cf 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
@@ -19,12 +19,14 @@ public:
        Hwmon();
        ~Hwmon();
 
+       void setup();
+
        bool claimCounter(const Counter &counter) const;
        bool countersEnabled() const;
        void resetCounters();
        void setupCounter(Counter &counter);
 
-       void writeCounters(mxml_node_t *root) const;
+       int writeCounters(mxml_node_t *root) const;
        void writeEvents(mxml_node_t *root) const;
 
        void start();
index 559297fe2274dd99780df1549fab53733d8e7c48..9300002f3fb2a41126b1c97d7f136e9b545aea2d 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
@@ -12,9 +12,9 @@
 #include <dirent.h>
 #include <unistd.h>
 
-#include "Collector.h"
 #include "ConfigurationXML.h"
 #include "Counter.h"
+#include "DriverSource.h"
 #include "Logging.h"
 
 // Claim all the counters in /dev/gator/events
@@ -38,9 +38,9 @@ void KMod::resetCounters() {
                                continue;
                        snprintf(base, sizeof(base), "/dev/gator/events/%s", ent->d_name);
                        snprintf(text, sizeof(text), "%s/enabled", base);
-                       Collector::writeDriver(text, 0);
+                       DriverSource::writeDriver(text, 0);
                        snprintf(text, sizeof(text), "%s/count", base);
-                       Collector::writeDriver(text, 0);
+                       DriverSource::writeDriver(text, 0);
                }
                closedir(dir);
        }
@@ -53,22 +53,22 @@ void KMod::setupCounter(Counter &counter) {
 
        snprintf(text, sizeof(text), "%s/enabled", base);
        int enabled = true;
-       if (Collector::writeReadDriver(text, &enabled) || !enabled) {
+       if (DriverSource::writeReadDriver(text, &enabled) || !enabled) {
                counter.setEnabled(false);
                return;
        }
 
        snprintf(text, sizeof(text), "%s/key", base);
        int key = 0;
-       Collector::readIntDriver(text, &key);
+       DriverSource::readIntDriver(text, &key);
        counter.setKey(key);
 
        snprintf(text, sizeof(text), "%s/event", base);
-       Collector::writeDriver(text, counter.getEvent());
+       DriverSource::writeDriver(text, counter.getEvent());
        snprintf(text, sizeof(text), "%s/count", base);
        if (access(text, F_OK) == 0) {
                int count = counter.getCount();
-               if (Collector::writeReadDriver(text, &count) && counter.getCount() > 0) {
+               if (DriverSource::writeReadDriver(text, &count) && counter.getCount() > 0) {
                        logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount());
                        handleException();
                }
@@ -80,23 +80,26 @@ void KMod::setupCounter(Counter &counter) {
        }
 }
 
-void KMod::writeCounters(mxml_node_t *root) const {
+int KMod::writeCounters(mxml_node_t *root) const {
        struct dirent *ent;
        mxml_node_t *counter;
 
        // counters.xml is simply a file listing of /dev/gator/events
        DIR* dir = opendir("/dev/gator/events");
        if (dir == NULL) {
-               logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events");
-               handleException();
+               return 0;
        }
 
+       int count = 0;
        while ((ent = readdir(dir)) != NULL) {
                // skip hidden files, current dir, and parent dir
                if (ent->d_name[0] == '.')
                        continue;
                counter = mxmlNewElement(root, "counter");
                mxmlElementSetAttr(counter, "name", ent->d_name);
+               ++count;
        }
        closedir(dir);
+
+       return count;
 }
index 797426290dfc752dd46e4a6ebe9379e68c5c6706..fb7fc8a8f9c6200fc31a9fe190d36d3d309370df 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
@@ -21,7 +21,7 @@ public:
        void resetCounters();
        void setupCounter(Counter &counter);
 
-       void writeCounters(mxml_node_t *root) const;
+       int writeCounters(mxml_node_t *root) const;
 };
 
 #endif // KMOD_H
index 3235a34ae9c718f76db3cc426d43cc9e7325b6e4..d2a4b799d7ac721e25f141054bff1d3bb86bba9e 100644 (file)
@@ -1,18 +1,20 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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 "LocalCapture.h"
+
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include "LocalCapture.h"
+
 #include "SessionData.h"
 #include "Logging.h"
 #include "OlyUtility.h"
index 8042d6a8dc37e11c1633f5fa952d0c1c736b0059..aadeccecf0ccf28b61c57ac79cc9f3efa1283a8d 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index 5fd45b54f90ad8371c9008ca4f4c52b29f899fcb..b8d3178950d6c5a119e69ac03b0faf706608bbaf 100644 (file)
@@ -1,11 +1,13 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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 "Logging.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -23,8 +25,6 @@
 #define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex)
 #endif
 
-#include "Logging.h"
-
 // Global thread-safe logging
 Logging* logg = NULL;
 
index 8f960de27bf35a9f4f529565a4ffc47ce00d8527..6ae328046989342db0fd4270896d72cbe090fe0e 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -9,14 +9,7 @@
 #ifndef        __LOGGING_H__
 #define        __LOGGING_H__
 
-#include <stdio.h>
-#include <string.h>
-#include <limits.h>
-#ifdef WIN32
-#include <windows.h>
-#else
 #include <pthread.h>
-#endif
 
 #define DRIVER_ERROR "\n Driver issue:\n  >> gator.ko must be built against the current kernel version & configuration\n  >> gator.ko should be co-located with gatord in the same directory\n  >>   OR insmod gator.ko prior to launching gatord"
 
@@ -33,11 +26,7 @@ private:
        char    mErrBuf[4096]; // Arbitrarily large buffer to hold a string
        char    mLogBuf[4096]; // Arbitrarily large buffer to hold a string
        bool    mDebug;
-#ifdef WIN32
-       HANDLE  mLoggingMutex;
-#else
        pthread_mutex_t mLoggingMutex;
-#endif
 };
 
 extern Logging* logg;
diff --git a/daemon/Monitor.cpp b/daemon/Monitor.cpp
new file mode 100644 (file)
index 0000000..90d5c47
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * 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 "Monitor.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "Logging.h"
+
+Monitor::Monitor() : mFd(-1) {
+}
+
+Monitor::~Monitor() {
+       if (mFd >= -1) {
+               close(mFd);
+       }
+}
+
+bool Monitor::init() {
+       mFd = epoll_create(16);
+       if (mFd < 0) {
+               logg->logMessage("%s(%s:%i): epoll_create1 failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       return true;
+}
+
+bool Monitor::add(const int fd) {
+       struct epoll_event event;
+       memset(&event, 0, sizeof(event));
+       event.data.fd = fd;
+       event.events = EPOLLIN;
+       if (epoll_ctl(mFd, EPOLL_CTL_ADD, fd, &event) != 0) {
+               logg->logMessage("%s(%s:%i): epoll_ctl failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       return true;
+}
+
+int Monitor::wait(struct epoll_event *const events, int maxevents, int timeout) {
+       int result = epoll_wait(mFd, events, maxevents, timeout);
+       if (result < 0) {
+               // Ignore if the call was interrupted as this will happen when SIGINT is received
+               if (errno == EINTR) {
+                       result = 0;
+               } else {
+                       logg->logMessage("%s(%s:%i): epoll_wait failed", __FUNCTION__, __FILE__, __LINE__);
+               }
+       }
+
+       return result;
+}
diff --git a/daemon/Monitor.h b/daemon/Monitor.h
new file mode 100644 (file)
index 0000000..6e268b6
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * 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 MONITOR_H
+#define MONITOR_H
+
+#include <sys/epoll.h>
+
+class Monitor {
+public:
+       Monitor();
+       ~Monitor();
+
+       bool init();
+       bool add(const int fd);
+       int wait(struct epoll_event *const events, int maxevents, int timeout);
+
+private:
+
+       int mFd;
+
+       // Intentionally unimplemented
+       Monitor(const Monitor &);
+       Monitor &operator=(const Monitor &);
+};
+
+#endif // MONITOR_H
index ab5c3c2c89383d5b26ab916c2508134bd34629f7..26e4768f39342440d0c25a81a2bdd8c579d352a6 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -15,6 +15,7 @@
 #else
 #include <netinet/in.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <unistd.h>
 #include <netdb.h>
 #endif
@@ -30,7 +31,7 @@
 #define SHUTDOWN_RX_TX SHUT_RDWR
 #endif
 
-OlySocket::OlySocket(int port, bool multiple) {
+OlyServerSocket::OlyServerSocket(int port) {
 #ifdef WIN32
   WSADATA wsaData;
   if (WSAStartup(0x0202, &wsaData) != 0) {
@@ -39,24 +40,82 @@ OlySocket::OlySocket(int port, bool multiple) {
   }
 #endif
 
-  if (multiple) {
-    createServerSocket(port);
-  } else {
-    createSingleServerConnection(port);
-  }
+  createServerSocket(port);
 }
 
-OlySocket::OlySocket(int port, char* host) {
-  mFDServer = 0;
+OlySocket::OlySocket(int port, const char* host) {
   createClientSocket(host, port);
 }
 
+OlySocket::OlySocket(int socketID) : mSocketID(socketID) {
+}
+
+#ifndef WIN32
+
+OlyServerSocket::OlyServerSocket(const char* path) {
+  // Create socket
+  mFDServer = socket(PF_UNIX, SOCK_STREAM, 0);
+  if (mFDServer < 0) {
+    logg->logError(__FILE__, __LINE__, "Error creating server socket");
+    handleException();
+  }
+
+  unlink(path);
+
+  // Create sockaddr_in structure, ensuring non-populated fields are zero
+  struct sockaddr_un sockaddr;
+  memset((void*)&sockaddr, 0, sizeof(sockaddr));
+  sockaddr.sun_family = AF_UNIX;
+  strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
+  sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
+
+  // Bind the socket to an address
+  if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
+    logg->logError(__FILE__, __LINE__, "Binding of server socket failed.");
+    handleException();
+  }
+
+  // Listen for connections on this socket
+  if (listen(mFDServer, 1) < 0) {
+    logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
+    handleException();
+  }
+}
+
+OlySocket::OlySocket(const char* path) {
+  mSocketID = socket(PF_UNIX, SOCK_STREAM, 0);
+  if (mSocketID < 0) {
+    return;
+  }
+
+  // Create sockaddr_in structure, ensuring non-populated fields are zero
+  struct sockaddr_un sockaddr;
+  memset((void*)&sockaddr, 0, sizeof(sockaddr));
+  sockaddr.sun_family = AF_UNIX;
+  strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
+  sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
+
+  if (connect(mSocketID, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
+    close(mSocketID);
+    mSocketID = -1;
+    return;
+  }
+}
+
+#endif
+
 OlySocket::~OlySocket() {
   if (mSocketID > 0) {
     CLOSE_SOCKET(mSocketID);
   }
 }
 
+OlyServerSocket::~OlyServerSocket() {
+  if (mFDServer > 0) {
+    CLOSE_SOCKET(mFDServer);
+  }
+}
+
 void OlySocket::shutdownConnection() {
   // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions
   shutdown(mSocketID, SHUTDOWN_RX_TX);
@@ -70,7 +129,7 @@ void OlySocket::closeSocket() {
   }
 }
 
-void OlySocket::closeServerSocket() {
+void OlyServerSocket::closeServerSocket() {
   if (CLOSE_SOCKET(mFDServer) != 0) {
     logg->logError(__FILE__, __LINE__, "Failed to close server socket.");
     handleException();
@@ -78,7 +137,7 @@ void OlySocket::closeServerSocket() {
   mFDServer = 0;
 }
 
-void OlySocket::createClientSocket(char* hostname, int portno) {
+void OlySocket::createClientSocket(const char* hostname, int portno) {
 #ifdef WIN32
   // TODO: Implement for Windows
 #else
@@ -119,14 +178,7 @@ void OlySocket::createClientSocket(char* hostname, int portno) {
 #endif
 }
 
-void OlySocket::createSingleServerConnection(int port) {
-  createServerSocket(port);
-
-  mSocketID = acceptConnection();
-  closeServerSocket();
-}
-
-void OlySocket::createServerSocket(int port) {
+void OlyServerSocket::createServerSocket(int port) {
   int family = AF_INET6;
 
   // Create socket
@@ -169,22 +221,23 @@ void OlySocket::createServerSocket(int port) {
 
 // mSocketID is always set to the most recently accepted connection
 // The user of this class should maintain the different socket connections, e.g. by forking the process
-int OlySocket::acceptConnection() {
+int OlyServerSocket::acceptConnection() {
+  int socketID;
   if (mFDServer <= 0) {
     logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
     handleException();
   }
 
   // Accept a connection, note that this call blocks until a client connects
-  mSocketID = accept(mFDServer, NULL, NULL);
-  if (mSocketID < 0) {
+  socketID = accept(mFDServer, NULL, NULL);
+  if (socketID < 0) {
     logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
     handleException();
   }
-  return mSocketID;
+  return socketID;
 }
 
-void OlySocket::send(char* buffer, int size) {
+void OlySocket::send(const char* buffer, int size) {
   if (size <= 0 || buffer == NULL) {
     return;
   }
index 5bab7d1f4cc46f4152443cae99254b012629ec51..eab786b304bf3907cfe361623751d8c7018126a9 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -9,27 +9,44 @@
 #ifndef __OLY_SOCKET_H__
 #define __OLY_SOCKET_H__
 
-#include <string.h>
-
 class OlySocket {
 public:
-  OlySocket(int port, bool multipleConnections = false);
-  OlySocket(int port, char* hostname);
+  OlySocket(int port, const char* hostname);
+  OlySocket(int socketID);
+#ifndef WIN32
+  OlySocket(const char* path);
+#endif
   ~OlySocket();
-  int acceptConnection();
+
   void closeSocket();
-  void closeServerSocket();
   void shutdownConnection();
-  void send(char* buffer, int size);
-  void sendString(const char* string) {send((char*)string, strlen(string));}
+  void send(const char* buffer, int size);
   int receive(char* buffer, int size);
   int receiveNBytes(char* buffer, int size);
   int receiveString(char* buffer, int size);
-  int getSocketID() {return mSocketID;}
+
+  bool isValid() const { return mSocketID >= 0; }
+
+private:
+  int mSocketID;
+
+  void createClientSocket(const char* hostname, int port);
+};
+
+class OlyServerSocket {
+public:
+  OlyServerSocket(int port);
+#ifndef WIN32
+  OlyServerSocket(const char* path);
+#endif
+  ~OlyServerSocket();
+
+  int acceptConnection();
+  void closeServerSocket();
+
 private:
-  int mSocketID, mFDServer;
-  void createClientSocket(char* hostname, int port);
-  void createSingleServerConnection(int port);
+  int mFDServer;
+
   void createServerSocket(int port);
 };
 
index 0b22d6ebd027c1c9148af424e8949acf754e9fda..45340a27d9fa5dd26a51dad284d69281603f353a 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index abab0a510a7c0cc5d1e10018aac64a537e79c834..1d26beb596fae3452939b266640f3d2899362085 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
diff --git a/daemon/PerfBuffer.cpp b/daemon/PerfBuffer.cpp
new file mode 100644 (file)
index 0000000..5fad583
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * 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 "PerfBuffer.h"
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include "Buffer.h"
+#include "Logging.h"
+#include "Sender.h"
+#include "SessionData.h"
+
+PerfBuffer::PerfBuffer() {
+       for (int cpu = 0; cpu < ARRAY_LENGTH(mBuf); ++cpu) {
+               mBuf[cpu] = MAP_FAILED;
+               mDiscard[cpu] = false;
+       }
+}
+
+PerfBuffer::~PerfBuffer() {
+       for (int cpu = ARRAY_LENGTH(mBuf) - 1; cpu >= 0; --cpu) {
+               if (mBuf[cpu] != MAP_FAILED) {
+                       munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
+               }
+       }
+}
+
+bool PerfBuffer::useFd(const int cpu, const int fd, const int groupFd) {
+       if (fd == groupFd) {
+               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;
+               }
+
+               // The buffer isn't mapped yet
+               mBuf[cpu] = mmap(NULL, gSessionData->mPageSize + BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+               if (mBuf[cpu] == MAP_FAILED) {
+                       logg->logMessage("%s(%s:%i): mmap failed", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+
+               // Check the version
+               struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
+               if (pemp->compat_version != 0) {
+                       logg->logMessage("%s(%s:%i): Incompatible perf_event_mmap_page compat_version", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+       } else {
+               if (mBuf[cpu] == MAP_FAILED) {
+                       logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+
+               if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, groupFd) < 0) {
+                       logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+void PerfBuffer::discard(const int cpu) {
+       if (mBuf[cpu] != MAP_FAILED) {
+               mDiscard[cpu] = true;
+       }
+}
+
+bool PerfBuffer::isEmpty() {
+       for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+               if (mBuf[cpu] != MAP_FAILED) {
+                       // Take a snapshot of the positions
+                       struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
+                       const __u64 head = pemp->data_head;
+                       const __u64 tail = pemp->data_tail;
+
+                       if (head != tail) {
+                               return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
+bool PerfBuffer::send(Sender *const sender) {
+       for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+               if (mBuf[cpu] == MAP_FAILED) {
+                       continue;
+               }
+
+               // Take a snapshot of the positions
+               struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
+               const __u64 head = pemp->data_head;
+               const __u64 tail = pemp->data_tail;
+
+               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);
+                       }
+
+                       // Update tail with the data read
+                       pemp->data_tail = head;
+               }
+
+               if (mDiscard[cpu]) {
+                       munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
+                       mBuf[cpu] = MAP_FAILED;
+                       mDiscard[cpu] = false;
+                       logg->logMessage("%s(%s:%i): Unmaped cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
+               }
+       }
+
+       return true;
+}
diff --git a/daemon/PerfBuffer.h b/daemon/PerfBuffer.h
new file mode 100644 (file)
index 0000000..278a3b9
--- /dev/null
@@ -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 PERF_BUFFER
+#define PERF_BUFFER
+
+#include "Config.h"
+
+#define BUF_SIZE (gSessionData->mTotalBufferSize * 1024 * 1024)
+#define BUF_MASK (BUF_SIZE - 1)
+
+class Sender;
+
+class PerfBuffer {
+public:
+       PerfBuffer();
+       ~PerfBuffer();
+
+       bool useFd(const int cpu, const int fd, const int groupFd);
+       void discard(const int cpu);
+       bool isEmpty();
+       bool send(Sender *const sender);
+
+private:
+       void *mBuf[NR_CPUS];
+       // After the buffer is flushed it should be unmaped
+       bool mDiscard[NR_CPUS];
+
+       // Intentionally undefined
+       PerfBuffer(const PerfBuffer &);
+       PerfBuffer &operator=(const PerfBuffer &);
+};
+
+#endif // PERF_BUFFER
diff --git a/daemon/PerfDriver.cpp b/daemon/PerfDriver.cpp
new file mode 100644 (file)
index 0000000..8e25c22
--- /dev/null
@@ -0,0 +1,355 @@
+/**
+ * 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 "PerfDriver.h"
+
+#include <dirent.h>
+#include <sys/utsname.h>
+#include <time.h>
+
+#include "Buffer.h"
+#include "Config.h"
+#include "ConfigurationXML.h"
+#include "Counter.h"
+#include "DriverSource.h"
+#include "DynBuf.h"
+#include "Logging.h"
+#include "PerfGroup.h"
+#include "SessionData.h"
+
+#define PERF_DEVICES "/sys/bus/event_source/devices"
+
+#define TYPE_DERIVED ~0U
+
+// From gator.h
+struct gator_cpu {
+       const int cpuid;
+       // Human readable name
+       const char core_name[32];
+       // gatorfs event and Perf PMU name
+       const char *const pmnc_name;
+       const int pmnc_counters;
+};
+
+// From gator_main.c
+static const struct gator_cpu gator_cpus[] = {
+       { 0xb36, "ARM1136",      "ARM_ARM11",        3 },
+       { 0xb56, "ARM1156",      "ARM_ARM11",        3 },
+       { 0xb76, "ARM1176",      "ARM_ARM11",        3 },
+       { 0xb02, "ARM11MPCore",  "ARM_ARM11MPCore",  3 },
+       { 0xc05, "Cortex-A5",    "ARMv7_Cortex_A5",  2 },
+       { 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 },
+       { 0x02d, "ScorpionMP",   "ScorpionMP",       4 },
+       { 0x049, "KraitSIM",     "Krait",            4 },
+       { 0x04d, "Krait",        "Krait",            4 },
+       { 0x06f, "Krait S4 Pro", "Krait",            4 },
+       { 0xd03, "Cortex-A53",   "ARM_Cortex-A53",   6 },
+       { 0xd07, "Cortex-A57",   "ARM_Cortex-A57",   6 },
+       { 0xd0f, "AArch64",      "ARM_AArch64",      6 },
+};
+
+static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
+static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_";
+
+class PerfCounter {
+public:
+       PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false) {}
+       ~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; }
+
+private:
+       PerfCounter *const mNext;
+       const char *const mName;
+       const uint32_t mType;
+       int mCount;
+       const int mKey;
+       uint64_t mConfig;
+       bool mEnabled;
+};
+
+PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(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);
+
+       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);
+       }
+}
+
+// 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__);
+               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, 12, 0)) {
+               logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       // Add supported PMUs
+       bool foundCpu = false;
+       DIR *dir = opendir(PERF_DEVICES);
+       if (dir == NULL) {
+               logg->logMessage("%s(%s:%i): opendif failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       struct dirent *dirent;
+       while ((dirent = readdir(dir)) != NULL) {
+               for (int i = 0; i < ARRAY_LENGTH(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)) {
+                               continue;
+                       }
+
+                       int type;
+                       char buf[256];
+                       snprintf(buf, sizeof(buf), PERF_DEVICES "/%s/type", dirent->d_name);
+                       if (DriverSource::readIntDriver(buf, &type) != 0) {
+                               continue;
+                       }
+
+                       foundCpu = true;
+                       addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters);
+               }
+       }
+       closedir(dir);
+
+       if (!foundCpu) {
+               // If no cpu was found based on pmu names, try by cpuid
+               for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
+                       if (gSessionData->mMaxCpuId != gator_cpus[i].cpuid) {
+                               continue;
+                       }
+
+                       foundCpu = true;
+                       addCpuCounters(gator_cpus[i].pmnc_name, PERF_TYPE_RAW, gator_cpus[i].pmnc_counters);
+               }
+       }
+
+       /*
+       if (!foundCpu) {
+               // If all else fails, use the perf architected counters
+               // 9 because that's how many are in events-Perf-Hardware.xml - assume they can all be enabled at once
+               addCpuCounters("Perf_Hardware", PERF_TYPE_HARDWARE, 9);
+       }
+       */
+
+       // Add supported software counters
+       long long id;
+       DynBuf printb;
+
+       id = getTracepointId("irq/softirq_exit", &printb);
+       if (id >= 0) {
+               mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id);
+       }
+
+       id = getTracepointId("irq/irq_handler_exit", &printb);
+       if (id >= 0) {
+               mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id);
+       }
+
+       //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);
+       }
+
+       //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);
+
+       //Linux_cpu_wait_io
+
+       mIsSetup = true;
+       return true;
+}
+
+bool PerfDriver::summary(Buffer *const buffer) {
+       struct utsname utsname;
+       if (uname(&utsname) != 0) {
+               logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       char buf[512];
+       snprintf(buf, sizeof(buf), "%s %s %s %s %s GNU/Linux", utsname.sysname, utsname.nodename, utsname.release, utsname.version, utsname.machine);
+
+       struct timespec ts;
+       if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
+               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;
+
+       if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
+               logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+       const int64_t uptime = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec;
+
+       buffer->summary(timestamp, uptime, 0, buf);
+
+       for (int i = 0; i < gSessionData->mCores; ++i) {
+               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 {
+                       snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]);
+                       buffer->coreName(i, gSessionData->mCpuIds[i], buf);
+               }
+       }
+       buffer->commit(1);
+
+       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;
+               }
+       }
+
+       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);
+       }
+}
+
+void PerfDriver::setupCounter(Counter &counter) {
+       PerfCounter *const perfCounter = findCounter(counter);
+       if (perfCounter == NULL) {
+               counter.setEnabled(false);
+               return;
+       }
+
+       // Don't use the config from counters XML if it's not set, ex: software counters
+       if (counter.getEvent() != -1) {
+               perfCounter->setConfig(counter.getEvent());
+       }
+       perfCounter->setCount(counter.getCount());
+       perfCounter->setEnabled(true);
+       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 *group, Buffer *const buffer) const {
+       for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
+               if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
+                       if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), 0, 0)) {
+                               logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__);
+                               return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
+long long PerfDriver::getTracepointId(const char *const name, DynBuf *const printb) {
+       if (!printb->printf(EVENTS_PATH "/%s/id", name)) {
+               logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+               return -1;
+       }
+
+       int64_t result;
+       if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) {
+               logg->logMessage("%s(%s:%i): DriverSource::readInt64Driver failed", __FUNCTION__, __FILE__, __LINE__);
+               return -1;
+       }
+
+       return result;
+}
diff --git a/daemon/PerfDriver.h b/daemon/PerfDriver.h
new file mode 100644 (file)
index 0000000..3181b74
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * 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 PERFDRIVER_H
+#define PERFDRIVER_H
+
+#include "Driver.h"
+
+// If debugfs is not mounted at /sys/kernel/debug, update DEBUGFS_PATH
+#define DEBUGFS_PATH "/sys/kernel/debug"
+#define EVENTS_PATH DEBUGFS_PATH "/tracing/events"
+
+#define SCHED_SWITCH "sched/sched_switch"
+
+class Buffer;
+class DynBuf;
+class PerfCounter;
+class PerfGroup;
+
+class PerfDriver : public Driver {
+public:
+       PerfDriver();
+       ~PerfDriver();
+
+       bool setup();
+       bool summary(Buffer *const buffer);
+       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 *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);
+
+       PerfCounter *mCounters;
+       bool mIsSetup;
+
+       // Intentionally undefined
+       PerfDriver(const PerfDriver &);
+       PerfDriver &operator=(const PerfDriver &);
+};
+
+#endif // PERFDRIVER_H
diff --git a/daemon/PerfGroup.cpp b/daemon/PerfGroup.cpp
new file mode 100644 (file)
index 0000000..faf5fca
--- /dev/null
@@ -0,0 +1,206 @@
+/**
+ * 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 "PerfGroup.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "Buffer.h"
+#include "Logging.h"
+#include "Monitor.h"
+#include "PerfBuffer.h"
+#include "SessionData.h"
+
+#define DEFAULT_PEA_ARGS(pea, additionalSampleType) \
+       pea.size = sizeof(pea); \
+       /* Emit time, read_format below, group leader id, and raw tracepoint info */ \
+       pea.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER | additionalSampleType; \
+       /* Emit emit value in group format */ \
+       pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP; \
+       /* start out disabled */ \
+       pea.disabled = 1; \
+       /* 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
+
+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);
+}
+
+PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) {
+       memset(&mAttrs, 0, sizeof(mAttrs));
+       memset(&mKeys, -1, sizeof(mKeys));
+       memset(&mFds, -1, sizeof(mFds));
+}
+
+PerfGroup::~PerfGroup() {
+       for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
+               if (mFds[pos] >= 0) {
+                       close(mFds[pos]);
+               }
+       }
+}
+
+bool PerfGroup::add(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) {
+                       break;
+               }
+       }
+
+       if (i >= ARRAY_LENGTH(mKeys)) {
+               logg->logMessage("%s(%s:%i): Too many counters", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       DEFAULT_PEA_ARGS(mAttrs[i], sampleType);
+       mAttrs[i].type = type;
+       mAttrs[i].config = config;
+       mAttrs[i].sample_period = sample;
+       // always be on the CPU but only a group leader can be pinned
+       mAttrs[i].pinned = (i == 0 ? 1 : 0);
+       mAttrs[i].mmap = (flags & PERF_GROUP_MMAP ? 1 : 0);
+       mAttrs[i].comm = (flags & PERF_GROUP_COMM ? 1 : 0);
+       mAttrs[i].freq = (flags & PERF_GROUP_FREQ ? 1 : 0);
+       mAttrs[i].task = (flags & PERF_GROUP_TASK ? 1 : 0);
+       mAttrs[i].sample_id_all = (flags & PERF_GROUP_SAMPLE_ID_ALL ? 1 : 0);
+
+       mKeys[i] = key;
+
+       buffer->pea(&mAttrs[i], key);
+
+       return true;
+}
+
+bool PerfGroup::prepareCPU(const int cpu) {
+       logg->logMessage("%s(%s:%i): Onlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
+
+       for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+               if (mKeys[i] < 0) {
+                       continue;
+               }
+
+               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;
+               }
+
+               logg->logMessage("%s(%s:%i): perf_event_open cpu: %i type: %lli config: %lli sample: %lli sample_type: %lli", __FUNCTION__, __FILE__, __LINE__, cpu, (long long)mAttrs[i].type, (long long)mAttrs[i].config, (long long)mAttrs[i].sample_period, (long long)mAttrs[i].sample_type);
+               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));
+                       continue;
+               }
+
+               if (!mPb->useFd(cpu, mFds[cpu + offset], mFds[cpu])) {
+                       logg->logMessage("%s(%s:%i): PerfBuffer::useFd failed", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor) {
+       __u64 ids[ARRAY_LENGTH(mKeys)];
+       int coreKeys[ARRAY_LENGTH(mKeys)];
+       int idCount = 0;
+
+       for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+               const int fd = mFds[cpu + i * gSessionData->mCores];
+               if (fd < 0) {
+                       continue;
+               }
+
+               coreKeys[idCount] = mKeys[i];
+               if (ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0) {
+                       logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+               ++idCount;
+       }
+
+       if (!monitor->add(mFds[cpu])) {
+               logg->logMessage("%s(%s:%i): Monitor::add failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       buffer->keys(idCount, ids, coreKeys);
+
+       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) {
+                               logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+                               return false;
+                       }
+               }
+       }
+
+       return idCount;
+}
+
+bool PerfGroup::offlineCPU(const int cpu) {
+       logg->logMessage("%s(%s:%i): Offlining cpu %i", __FUNCTION__, __FILE__, __LINE__, 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) {
+                       logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+       }
+
+       // Mark the buffer so that it will be released next time it's read
+       mPb->discard(cpu);
+
+       for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+               if (mKeys[i] < 0) {
+                       continue;
+               }
+
+               int offset = i * gSessionData->mCores + cpu;
+               if (mFds[offset] >= 0) {
+                       close(mFds[offset]);
+                       mFds[offset] = -1;
+               }
+       }
+
+       return true;
+}
+
+bool PerfGroup::start() {
+       for (int pos = 0; pos < ARRAY_LENGTH(mFds); ++pos) {
+               if (mFds[pos] >= 0 && ioctl(mFds[pos], PERF_EVENT_IOC_ENABLE) < 0) {
+                       logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+                       goto fail;
+               }
+       }
+
+       return true;
+
+ fail:
+       stop();
+
+       return false;
+}
+
+void PerfGroup::stop() {
+       for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
+               if (mFds[pos] >= 0) {
+                       ioctl(mFds[pos], PERF_EVENT_IOC_DISABLE);
+               }
+       }
+}
diff --git a/daemon/PerfGroup.h b/daemon/PerfGroup.h
new file mode 100644 (file)
index 0000000..af496d4
--- /dev/null
@@ -0,0 +1,55 @@
+ /**
+ * 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 PERF_GROUP
+#define PERF_GROUP
+
+// 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"
+
+#include "Config.h"
+
+class Buffer;
+class Monitor;
+class PerfBuffer;
+
+enum PerfGroupFlags {
+       PERF_GROUP_MMAP          = 1 << 0,
+       PERF_GROUP_COMM          = 1 << 1,
+       PERF_GROUP_FREQ          = 1 << 2,
+       PERF_GROUP_TASK          = 1 << 3,
+       PERF_GROUP_SAMPLE_ID_ALL = 1 << 4,
+};
+
+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);
+       // Safe to call concurrently
+       bool prepareCPU(const int cpu);
+       // 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);
+       bool offlineCPU(int cpu);
+       bool start();
+       void stop();
+
+private:
+       // +1 for the group leader
+       struct perf_event_attr mAttrs[MAX_PERFORMANCE_COUNTERS + 1];
+       int mKeys[MAX_PERFORMANCE_COUNTERS + 1];
+       int mFds[NR_CPUS * (MAX_PERFORMANCE_COUNTERS + 1)];
+       PerfBuffer *const mPb;
+
+       // Intentionally undefined
+       PerfGroup(const PerfGroup &);
+       PerfGroup &operator=(const PerfGroup &);
+};
+
+#endif // PERF_GROUP
diff --git a/daemon/PerfSource.cpp b/daemon/PerfSource.cpp
new file mode 100644 (file)
index 0000000..1f1cb19
--- /dev/null
@@ -0,0 +1,271 @@
+/**
+ * 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 "PerfSource.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "Child.h"
+#include "DynBuf.h"
+#include "Logging.h"
+#include "PerfDriver.h"
+#include "Proc.h"
+#include "SessionData.h"
+
+#define MS_PER_US 1000000
+
+extern Child *child;
+
+static bool sendTracepointFormat(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;
+       }
+       if (!b->read(printb->getBuf())) {
+               logg->logMessage("%s(%s:%i): DynBuf::read failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+       buffer->format(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, 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");
+               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");
+               handleException();
+       }
+       gSessionData->mCores = static_cast<int>(l);
+}
+
+PerfSource::~PerfSource() {
+}
+
+struct PrepareParallelArgs {
+       PerfGroup *pg;
+       int cpu;
+};
+
+void *prepareParallel(void *arg) {
+       const PrepareParallelArgs *const args = (PrepareParallelArgs *)arg;
+       args->pg->prepareCPU(args->cpu);
+       return NULL;
+}
+
+bool PerfSource::prepare() {
+       DynBuf printb;
+       DynBuf b1;
+       DynBuf b2;
+       DynBuf b3;
+       long long schedSwitchId;
+
+       if (0
+                       || !mMonitor.init()
+                       || !mUEvent.init()
+                       || !mMonitor.add(mUEvent.getFd())
+
+                       || (schedSwitchId = PerfDriver::getTracepointId(SCHED_SWITCH, &printb)) < 0
+                       || !sendTracepointFormat(&mBuffer, SCHED_SWITCH, &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)
+
+                       // 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, 0))
+
+                       || !gSessionData->perf.enable(&mCountersGroup, &mBuffer)
+                       || 0) {
+               logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.12 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) {
+                       if (pthread_join(threads[cpu], NULL) != 0) {
+                               logg->logMessage("%s(%s:%i): pthread_join failed", __FUNCTION__, __FILE__, __LINE__);
+                               return false;
+                       }
+               }
+       }
+
+       int numEvents = 0;
+       for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+               numEvents += mCountersGroup.onlineCPU(cpu, false, &mBuffer, &mMonitor);
+       }
+       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;
+       }
+
+       if (!readProc(&mBuffer, &printb, &b1, &b2, &b3)) {
+               logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       mBuffer.commit(1);
+
+       return true;
+}
+
+static const char CPU_DEVPATH[] = "/devices/system/cpu/cpu";
+
+void PerfSource::run() {
+       int pipefd[2];
+
+       if (pipe(pipefd) != 0) {
+               logg->logError(__FILE__, __LINE__, "pipe failed");
+               handleException();
+       }
+       mInterruptFd = pipefd[1];
+
+       if (!mMonitor.add(pipefd[0])) {
+               logg->logError(__FILE__, __LINE__, "Monitor::add failed");
+               handleException();
+       }
+
+       int timeout = -1;
+       if (gSessionData->mLiveRate > 0) {
+               timeout = gSessionData->mLiveRate/MS_PER_US;
+       }
+
+       sem_post(mStartProfile);
+
+       while (gSessionData->mSessionIsActive) {
+               // +1 for uevents, +1 for pipe
+               struct epoll_event events[NR_CPUS + 2];
+               int ready = mMonitor.wait(events, ARRAY_LENGTH(events), timeout);
+               if (ready < 0) {
+                       logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
+                       handleException();
+               }
+
+               for (int i = 0; i < ready; ++i) {
+                       if (events[i].data.fd == mUEvent.getFd()) {
+                               if (!handleUEvent()) {
+                                       logg->logError(__FILE__, __LINE__, "PerfSource::handleUEvent failed");
+                                       handleException();
+                               }
+                               break;
+                       }
+               }
+
+               // send a notification that data is ready
+               sem_post(mSenderSem);
+
+               // In one shot mode, stop collection once all the buffers are filled
+               // Assume timeout == 0 in this case
+               if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
+                       logg->logMessage("%s(%s:%i): One shot", __FUNCTION__, __FILE__, __LINE__);
+                       child->endSession();
+               }
+       }
+
+       mCountersGroup.stop();
+       mBuffer.setDone();
+       mIsDone = true;
+
+       // send a notification that data is ready
+       sem_post(mSenderSem);
+
+       mInterruptFd = -1;
+       close(pipefd[0]);
+       close(pipefd[1]);
+}
+
+bool PerfSource::handleUEvent() {
+       UEventResult result;
+       if (!mUEvent.read(&result)) {
+               logg->logMessage("%s(%s:%i): UEvent::Read failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       if (strcmp(result.mSubsystem, "cpu") == 0) {
+               if (strncmp(result.mDevPath, CPU_DEVPATH, sizeof(CPU_DEVPATH) - 1) != 0) {
+                       logg->logMessage("%s(%s:%i): Unexpected cpu DEVPATH format", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+               char *endptr;
+               errno = 0;
+               int cpu = strtol(result.mDevPath + sizeof(CPU_DEVPATH) - 1, &endptr, 10);
+               if (errno != 0 || *endptr != '\0') {
+                       logg->logMessage("%s(%s:%i): strtol failed", __FUNCTION__, __FILE__, __LINE__);
+                       return false;
+               }
+               if (strcmp(result.mAction, "online") == 0) {
+                       // Only call onlineCPU if prepareCPU succeeded
+                       const bool result = mCountersGroup.prepareCPU(cpu) &&
+                               mCountersGroup.onlineCPU(cpu, true, &mBuffer, &mMonitor);
+                       mBuffer.commit(1);
+                       return result;
+               } else if (strcmp(result.mAction, "offline") == 0) {
+                       return mCountersGroup.offlineCPU(cpu);
+               }
+       }
+
+       return true;
+}
+
+void PerfSource::interrupt() {
+       if (mInterruptFd >= 0) {
+               int8_t c = 0;
+               // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread
+               if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) {
+                       logg->logError(__FILE__, __LINE__, "write failed");
+                       handleException();
+               }
+       }
+}
+
+bool PerfSource::isDone () {
+       return mBuffer.isDone() && mIsDone && mCountersBuf.isEmpty();
+}
+
+void PerfSource::write (Sender *sender) {
+       if (!mSummary.isDone()) {
+               mSummary.write(sender);
+       }
+       if (!mBuffer.isDone()) {
+               mBuffer.write(sender);
+       }
+       if (!mCountersBuf.send(sender)) {
+               logg->logError(__FILE__, __LINE__, "PerfBuffer::send failed");
+               handleException();
+       }
+}
diff --git a/daemon/PerfSource.h b/daemon/PerfSource.h
new file mode 100644 (file)
index 0000000..3f471c8
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+ * 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 PERFSOURCE_H
+#define PERFSOURCE_H
+
+#include <semaphore.h>
+
+#include "Buffer.h"
+#include "Monitor.h"
+#include "PerfBuffer.h"
+#include "PerfGroup.h"
+#include "Source.h"
+#include "UEvent.h"
+
+class Sender;
+
+class PerfSource : public Source {
+public:
+       PerfSource(sem_t *senderSem, sem_t *startProfile);
+       ~PerfSource();
+
+       bool prepare();
+       void run();
+       void interrupt();
+
+       bool isDone();
+       void write(Sender *sender);
+
+private:
+       bool handleUEvent();
+
+       Buffer mSummary;
+       Buffer mBuffer;
+       PerfBuffer mCountersBuf;
+       PerfGroup mCountersGroup;
+       Monitor mMonitor;
+       UEvent mUEvent;
+       sem_t *const mSenderSem;
+       sem_t *const mStartProfile;
+       int mInterruptFd;
+       bool mIsDone;
+
+       // Intentionally undefined
+       PerfSource(const PerfSource &);
+       PerfSource &operator=(const PerfSource &);
+};
+
+#endif // PERFSOURCE_H
diff --git a/daemon/Proc.cpp b/daemon/Proc.cpp
new file mode 100644 (file)
index 0000000..e0b9e22
--- /dev/null
@@ -0,0 +1,179 @@
+/**
+ * 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 "Proc.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "Buffer.h"
+#include "DynBuf.h"
+#include "Logging.h"
+
+struct ProcStat {
+       // From linux-dev/include/linux/sched.h
+#define TASK_COMM_LEN 16
+       // TASK_COMM_LEN may grow, so be ready for it to get larger
+       char comm[2*TASK_COMM_LEN];
+       long numThreads;
+};
+
+static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf *const b) {
+       if (!b->read(pathname)) {
+               logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__);
+               // This is not a fatal error - the thread just doesn't exist any more
+               return true;
+       }
+
+       char *comm = strchr(b->getBuf(), '(');
+       if (comm == NULL) {
+               logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+       ++comm;
+       char *const str = strrchr(comm, ')');
+       if (str == NULL) {
+               logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+       *str = '\0';
+       strncpy(ps->comm, comm, sizeof(ps->comm) - 1);
+       ps->comm[sizeof(ps->comm) - 1] = '\0';
+
+       const int count = sscanf(str + 2, " %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %ld", &ps->numThreads);
+       if (count != 1) {
+               logg->logMessage("%s(%s:%i): sscanf failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       return true;
+}
+
+static bool readProcTask(Buffer *const buffer, const int pid, const char *const image, DynBuf *const printb, DynBuf *const b) {
+       bool result = false;
+
+       if (!b->printf("/proc/%i/task", pid)) {
+               logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+               return result;
+       }
+       DIR *task = opendir(b->getBuf());
+       if (task == NULL) {
+               logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
+               return result;
+       }
+
+       struct dirent *dirent;
+       while ((dirent = readdir(task)) != NULL) {
+               char *endptr;
+               const int tid = strtol(dirent->d_name, &endptr, 10);
+               if (*endptr != '\0') {
+                       // Ignore task items that are not integers like ., etc...
+                       continue;
+               }
+
+               if (!printb->printf("/proc/%i/task/%i/stat", pid, tid)) {
+                       logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+                       goto fail;
+               }
+               ProcStat ps;
+               if (!readProcStat(&ps, printb->getBuf(), b)) {
+                       logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
+                       goto fail;
+               }
+
+               buffer->comm(pid, tid, image, ps.comm);
+       }
+
+       result = true;
+
+ fail:
+       closedir(task);
+
+       return result;
+}
+
+bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) {
+       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/stat", pid)) {
+                       logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+                       goto fail;
+               }
+               ProcStat ps;
+               if (!readProcStat(&ps, printb->getBuf(), b1)) {
+                       logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
+                       goto fail;
+               }
+
+               if (!printb->printf("/proc/%i/exe", pid)) {
+                       logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+                       goto fail;
+               }
+               const int err = b1->readlink(printb->getBuf());
+               const char *image;
+               if (err == 0) {
+                       image = strrchr(b1->getBuf(), '/');
+                       if (image == NULL) {
+                               image = b1->getBuf();
+                       } else {
+                               ++image;
+                       }
+               } else if (err == -ENOENT) {
+                       // readlink /proc/[pid]/exe returns ENOENT for kernel threads
+                       image = "\0";
+               } else {
+                       logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__);
+                       goto fail;
+               }
+
+               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) {
+                       buffer->comm(pid, pid, image, ps.comm);
+               } else {
+                       if (!readProcTask(buffer, pid, image, printb, b3)) {
+                               logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__);
+                               goto fail;
+                       }
+               }
+       }
+
+       result = true;
+
+ fail:
+       closedir(proc);
+
+       return result;
+}
diff --git a/daemon/Proc.h b/daemon/Proc.h
new file mode 100644 (file)
index 0000000..057b610
--- /dev/null
@@ -0,0 +1,17 @@
+/**
+ * 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 PROC_H
+#define PROC_H
+
+class Buffer;
+class DynBuf;
+
+bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3);
+
+#endif // PROC_H
index 8eb348ff3a069bd9319de78e4dbf53e4e2731bfe..3a981a6427be01ebbe0aa525cbb8b65ebed91184 100644 (file)
@@ -1,19 +1,18 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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 <string.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
+#include "Sender.h"
+
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
-#include "Sender.h"
+
+#include "Buffer.h"
 #include "Logging.h"
 #include "OlySocket.h"
 #include "SessionData.h"
@@ -49,9 +48,12 @@ Sender::Sender(OlySocket* socket) {
 }
 
 Sender::~Sender() {
-       delete mDataSocket;
-       mDataSocket = NULL;
-       if (mDataFile) {
+       // Just close it as the client socket is on the stack
+       if (mDataSocket != NULL) {
+               mDataSocket->closeSocket();
+               mDataSocket = NULL;
+       }
+       if (mDataFile != NULL) {
                fclose(mDataFile);
        }
 }
@@ -95,10 +97,7 @@ void Sender::writeData(const char* data, int length, int type) {
                        // type and length already added by the Collector for apc data
                        unsigned char header[5];
                        header[0] = type;
-                       header[1] = (length >> 0) & 0xff;
-                       header[2] = (length >> 8) & 0xff;
-                       header[3] = (length >> 16) & 0xff;
-                       header[4] = (length >> 24) & 0xff;
+                       Buffer::writeLEInt(header + 1, length);
                        mDataSocket->send((char*)&header, sizeof(header));
                }
 
@@ -106,7 +105,7 @@ void Sender::writeData(const char* data, int length, int type) {
                const int chunkSize = 100*1000 * alarmDuration / 8;
                int pos = 0;
                while (true) {
-                       mDataSocket->send((char*)data + pos, min(length - pos, chunkSize));
+                       mDataSocket->send((const char*)data + pos, min(length - pos, chunkSize));
                        pos += chunkSize;
                        if (pos >= length) {
                                break;
index b388f039bad7d33ff89e04fdf6213f55216f23dc..4c359dba82f87b79be729583ea6a5d2ccc8bc1d8 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index cf844075401f919448e9a3e70b3a568fc3c9bb05..c169299af8720d0c16da229a0939264a81c21500 100644 (file)
@@ -1,13 +1,15 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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 <string.h>
 #include "SessionData.h"
+
+#include <string.h>
+
 #include "SessionXML.h"
 #include "Logging.h"
 
@@ -38,6 +40,7 @@ void SessionData::initialize() {
        mTotalBufferSize = 0;
        // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
        mCores = 1;
+       mPageSize = 0;
 }
 
 void SessionData::parseSessionXML(char* xmlString) {
@@ -88,7 +91,8 @@ void SessionData::parseSessionXML(char* xmlString) {
 void SessionData::readCpuInfo() {
        char temp[256]; // arbitrarily large amount
        strcpy(mCoreName, "unknown");
-       mCpuId = -1;
+       memset(&mCpuIds, -1, sizeof(mCpuIds));
+       mMaxCpuId = -1;
 
        FILE* f = fopen("/proc/cpuinfo", "r");  
        if (f == NULL) {
@@ -98,15 +102,16 @@ void SessionData::readCpuInfo() {
        }
 
        bool foundCoreName = false;
-       bool foundCpuId = false;
-       while (fgets(temp, sizeof(temp), f) && (!foundCoreName || !foundCpuId)) {
+       int processor = 0;
+       while (fgets(temp, sizeof(temp), f)) {
                if (strlen(temp) > 0) {
                        temp[strlen(temp) - 1] = 0;     // Replace the line feed with a null
                }
 
                const bool foundHardware = strstr(temp, "Hardware") != 0;
                const bool foundCPUPart = strstr(temp, "CPU part") != 0;
-               if (foundHardware || foundCPUPart) {
+               const bool foundProcessor = strstr(temp, "processor") != 0;
+               if (foundHardware || foundCPUPart || foundProcessor) {
                        char* position = strchr(temp, ':');
                        if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
                                logg->logMessage("Unknown format of /proc/cpuinfo\n"
@@ -122,11 +127,15 @@ void SessionData::readCpuInfo() {
                        }
 
                        if (foundCPUPart) {
-                               int cpuId = strtol(position, NULL, 16);
-                               if (cpuId > mCpuId) {
-                                       mCpuId = cpuId;
+                               mCpuIds[processor] = strtol(position, NULL, 0);
+                               // If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId
+                               if (mCpuIds[processor] > mMaxCpuId) {
+                                       mMaxCpuId = mCpuIds[processor];
                                }
-                               foundCpuId = true;
+                       }
+
+                       if (foundProcessor) {
+                               processor = strtol(position, NULL, 0);
                        }
                }
        }
index c834251527cf22334e3a06f2346c20d9f97fbd09..ea34240e2df7c3ec271bf9b6917d7c45ba4037f8 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
 
 #include <stdint.h>
 
+#include "Config.h"
 #include "Counter.h"
 #include "Hwmon.h"
+#include "PerfDriver.h"
 
-#define MAX_PERFORMANCE_COUNTERS       50
-
-#define PROTOCOL_VERSION       17
+#define PROTOCOL_VERSION       18
 #define PROTOCOL_DEV           1000    // Differentiates development versions (timestamp) from release versions
 
 struct ImageLinkList {
@@ -34,6 +34,7 @@ public:
        void parseSessionXML(char* xmlString);
 
        Hwmon hwmon;
+       PerfDriver perf;
 
        char mCoreName[MAX_STRING_LEN];
        struct ImageLinkList *mImages;
@@ -47,6 +48,7 @@ public:
        bool mSessionIsActive;
        bool mLocalCapture;
        bool mOneShot;          // halt processing of the driver data until profiling is complete or the buffer is filled
+       bool mIsEBS;
        
        int mBacktraceDepth;
        int mTotalBufferSize;   // number of MB to use for the entire collection buffer
@@ -54,7 +56,9 @@ public:
        int64_t mLiveRate;
        int mDuration;
        int mCores;
-       int mCpuId;
+       int mPageSize;
+       int mCpuIds[NR_CPUS];
+       int mMaxCpuId;
 
        // PMU Counters
        int mCounterOverflow;
index 0a0a02779176aa971d53d340ce15f46ca281b3d9..55b2f92807092ee071a2cfdbd8c36b43f435b590 100644 (file)
@@ -1,15 +1,17 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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 "SessionXML.h"
+
 #include <string.h>
 #include <stdlib.h>
 #include <limits.h>
-#include "SessionXML.h"
+
 #include "Logging.h"
 #include "OlyUtility.h"
 #include "SessionData.h"
@@ -25,7 +27,7 @@ static const char*    ATTR_DURATION           = "duration";
 static const char*     ATTR_PATH               = "path";
 static const char*     ATTR_LIVE_RATE      = "live_rate";
 
-SessionXML::SessionXML(const charstr) {
+SessionXML::SessionXML(const char *str) {
        parameters.buffer_mode[0] = 0;
        parameters.sample_rate[0] = 0;
        parameters.duration = 0;
@@ -33,13 +35,13 @@ SessionXML::SessionXML(const char* str) {
        parameters.live_rate = 0;
        parameters.images = NULL;
        mPath = 0;
-       mSessionXML = (char*)str;
+       mSessionXML = (const char *)str;
        logg->logMessage(mSessionXML);
 }
 
 SessionXML::~SessionXML() {
        if (mPath != 0) {
-               free(mSessionXML);
+               free((char *)mSessionXML);
        }
 }
 
index 0fb03bd6627c75bd8344a308666cfc057e55cf7d..e146094a4d1751c260e356075fd36b322b1db849 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -24,13 +24,13 @@ struct ConfigParameters {
 
 class SessionXML {
 public:
-       SessionXML(const charstr);
+       SessionXML(const char *str);
        ~SessionXML();
        void parse();
        ConfigParameters parameters;
 private:
-       char*  mSessionXML;
-       char*  mPath;
+       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/Source.cpp b/daemon/Source.cpp
new file mode 100644 (file)
index 0000000..60cf704
--- /dev/null
@@ -0,0 +1,33 @@
+/**
+ * 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 "Source.h"
+
+#include "Logging.h"
+
+Source::Source() : mThreadID() {
+}
+
+Source::~Source() {
+}
+
+void Source::start() {
+       if (pthread_create(&mThreadID, NULL, runStatic, this)) {
+               logg->logError(__FILE__, __LINE__, "Failed to create source thread");
+               handleException();
+       }
+}
+
+void Source::join() {
+       pthread_join(mThreadID, NULL);
+}
+
+void *Source::runStatic(void *arg) {
+       static_cast<Source *>(arg)->run();
+       return NULL;
+}
diff --git a/daemon/Source.h b/daemon/Source.h
new file mode 100644 (file)
index 0000000..56ac3d6
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * 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 SOURCE_H
+#define SOURCE_H
+
+#include <pthread.h>
+
+class Sender;
+
+class Source {
+public:
+       Source();
+       virtual ~Source();
+
+       virtual bool prepare() = 0;
+       void start();
+       virtual void run() = 0;
+       virtual void interrupt() = 0;
+       void join();
+
+       virtual bool isDone() = 0;
+       virtual void write(Sender *sender) = 0;
+
+private:
+       static void *runStatic(void *arg);
+
+       pthread_t mThreadID;
+
+       // Intentionally undefined
+       Source(const Source &);
+       Source &operator=(const Source &);
+};
+
+#endif // SOURCE_H
index 2faada23f842094e7fc1cfeab7d3868529963abb..caa665e67193a9f88f378c290ce9b74d3aad3f91 100644 (file)
@@ -1,26 +1,23 @@
 /**
- * Copyright (C) ARM Limited 2011-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2011-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 <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include "Sender.h"
-#include "Logging.h"
-#include "OlyUtility.h"
-#include "SessionData.h"
-#include "CapturedXML.h"
 #include "StreamlineSetup.h"
+
+#include "Buffer.h"
+#include "CapturedXML.h"
 #include "ConfigurationXML.h"
 #include "Driver.h"
 #include "EventsXML.h"
+#include "Logging.h"
+#include "OlySocket.h"
+#include "OlyUtility.h"
+#include "Sender.h"
+#include "SessionData.h"
 
 static const char* TAG_SESSION = "session";
 static const char* TAG_REQUEST = "request";
@@ -198,12 +195,9 @@ void StreamlineSetup::handleDeliver(char* xml) {
 void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
        unsigned char header[5];
        header[0] = type;
-       header[1] = (length >> 0) & 0xff;
-       header[2] = (length >> 8) & 0xff;
-       header[3] = (length >> 16) & 0xff;
-       header[4] = (length >> 24) & 0xff;
+       Buffer::writeLEInt(header + 1, length);
        mSocket->send((char*)&header, sizeof(header));
-       mSocket->send((char*)data, length);
+       mSocket->send((const char*)data, length);
 }
 
 void StreamlineSetup::sendEvents() {
@@ -241,8 +235,14 @@ void StreamlineSetup::sendCounters() {
 
        xml = mxmlNewXML("1.0");
        counters = mxmlNewElement(xml, "counters");
+       int count = 0;
        for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
-               driver->writeCounters(counters);
+               count += driver->writeCounters(counters);
+       }
+
+       if (count == 0) {
+               logg->logError(__FILE__, __LINE__, "No counters found, this could be because /dev/gator/events can not be read or because perf is not working correctly");
+               handleException();
        }
 
        char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
index d6d9a6ea29919db845ec5c4777c56b28698adda1..74bb197e35ff2a563b10b53397ad5c47d8ac4b1e 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -9,7 +9,10 @@
 #ifndef        __STREAMLINE_SETUP_H__
 #define        __STREAMLINE_SETUP_H__
 
-#include "OlySocket.h"
+#include <stdint.h>
+#include <string.h>
+
+class OlySocket;
 
 // Commands from Streamline
 enum {
diff --git a/daemon/UEvent.cpp b/daemon/UEvent.cpp
new file mode 100644 (file)
index 0000000..282e965
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * 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 "UEvent.h"
+
+#include <linux/netlink.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "Logging.h"
+
+static const char EMPTY[] = "";
+static const char ACTION[] = "ACTION=";
+static const char DEVPATH[] = "DEVPATH=";
+static const char SUBSYSTEM[] = "SUBSYSTEM=";
+
+UEvent::UEvent() : mFd(-1) {
+}
+
+UEvent::~UEvent() {
+       if (mFd >= 0) {
+               close(mFd);
+       }
+}
+
+bool UEvent::init() {
+       mFd = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
+       if (mFd < 0) {
+               logg->logMessage("%s(%s:%i): socket failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       struct sockaddr_nl sockaddr;
+       memset(&sockaddr, 0, sizeof(sockaddr));
+       sockaddr.nl_family = AF_NETLINK;
+       sockaddr.nl_groups = 1; // bitmask: (1 << 0) == kernel events, (1 << 1) == udev events
+       sockaddr.nl_pid = 0;
+       if (bind(mFd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0) {
+               logg->logMessage("%s(%s:%i): bind failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       return true;
+}
+
+bool UEvent::read(UEventResult *const result) {
+       ssize_t bytes = recv(mFd, result->mBuf, sizeof(result->mBuf), 0);
+       if (bytes <= 0) {
+               logg->logMessage("%s(%s:%i): recv failed", __FUNCTION__, __FILE__, __LINE__);
+               return false;
+       }
+
+       result->mAction = EMPTY;
+       result->mDevPath = EMPTY;
+       result->mSubsystem = EMPTY;
+
+       for (int pos = 0; pos < bytes; pos += strlen(result->mBuf + pos) + 1) {
+               char *const str = result->mBuf + pos;
+               if (strncmp(str, ACTION, sizeof(ACTION) - 1) == 0) {
+                       result->mAction = str + sizeof(ACTION) - 1;
+               } else if (strncmp(str, DEVPATH, sizeof(DEVPATH) - 1) == 0) {
+                       result->mDevPath = str + sizeof(DEVPATH) - 1;
+               } else if (strncmp(str, SUBSYSTEM, sizeof(SUBSYSTEM) - 1) == 0) {
+                       result->mSubsystem = str + sizeof(SUBSYSTEM) - 1;
+               }
+       }
+
+       return true;
+}
diff --git a/daemon/UEvent.h b/daemon/UEvent.h
new file mode 100644 (file)
index 0000000..2f7ef2c
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * 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 UEVENT_H
+#define UEVENT_H
+
+struct UEventResult {
+       const char *mAction;
+       const char *mDevPath;
+       const char *mSubsystem;
+       char mBuf[1<<13];
+};
+
+class UEvent {
+public:
+       UEvent();
+       ~UEvent();
+
+       bool init();
+       bool read(UEventResult *const result);
+       int getFd() const { return mFd; }
+
+private:
+       int mFd;
+
+       // Intentionally undefined
+       UEvent(const UEvent &);
+       UEvent &operator=(const UEvent &);
+};
+
+#endif // UEVENT_H
diff --git a/daemon/UserSpaceSource.cpp b/daemon/UserSpaceSource.cpp
new file mode 100644 (file)
index 0000000..debe696
--- /dev/null
@@ -0,0 +1,97 @@
+/**
+ * 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 "UserSpaceSource.h"
+
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include "Child.h"
+#include "DriverSource.h"
+#include "Logging.h"
+#include "SessionData.h"
+
+#define NS_PER_S ((uint64_t)1000000000)
+#define NS_PER_US 1000
+
+extern Child *child;
+
+UserSpaceSource::UserSpaceSource(sem_t *senderSem) : mBuffer(0, FRAME_BLOCK_COUNTER, gSessionData->mTotalBufferSize*1024*1024, senderSem) {
+}
+
+UserSpaceSource::~UserSpaceSource() {
+}
+
+bool UserSpaceSource::prepare() {
+       return true;
+}
+
+void UserSpaceSource::run() {
+       prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
+
+       gSessionData->hwmon.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();
+               }
+       }
+
+       uint64_t next_time = 0;
+       while (gSessionData->mSessionIsActive) {
+               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();
+               }
+               const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started;
+               // Sample ten times a second ignoring gSessionData->mSampleRate
+               next_time += NS_PER_S/10;//gSessionData->mSampleRate;
+               if (next_time < curr_time) {
+                       logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
+                       next_time = curr_time;
+               }
+
+               if (mBuffer.eventHeader(curr_time)) {
+                       gSessionData->hwmon.read(&mBuffer);
+                       // Only check after writing all counters so that time and corresponding counters appear in the same frame
+                       mBuffer.check(curr_time);
+               }
+
+               if (mBuffer.bytesAvailable() <= 0) {
+                       logg->logMessage("One shot (counters)");
+                       child->endSession();
+               }
+
+               usleep((next_time - curr_time)/NS_PER_US);
+       }
+
+       mBuffer.setDone();
+}
+
+void UserSpaceSource::interrupt() {
+       // Do nothing
+}
+
+bool UserSpaceSource::isDone() {
+       return mBuffer.isDone();
+}
+
+void UserSpaceSource::write(Sender *sender) {
+       if (!mBuffer.isDone()) {
+               mBuffer.write(sender);
+       }
+}
diff --git a/daemon/UserSpaceSource.h b/daemon/UserSpaceSource.h
new file mode 100644 (file)
index 0000000..fb5889d
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * 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 USERSPACESOURCE_H
+#define USERSPACESOURCE_H
+
+#include <semaphore.h>
+
+#include "Buffer.h"
+#include "Source.h"
+
+// User space counters - currently just hwmon
+class UserSpaceSource : public Source {
+public:
+       UserSpaceSource(sem_t *senderSem);
+       ~UserSpaceSource();
+
+       bool prepare();
+       void run();
+       void interrupt();
+
+       bool isDone();
+       void write(Sender *sender);
+
+private:
+       Buffer mBuffer;
+
+       // Intentionally unimplemented
+       UserSpaceSource(const UserSpaceSource &);
+       UserSpaceSource &operator=(const UserSpaceSource &);
+};
+
+#endif // USERSPACESOURCE_H
index 031d169068817e3182ec3c3dd5e16487bb7da16f..d9dc14606b0716082cddfc4d5e95dd1d18dd9a39 100644 (file)
@@ -25,7 +25,7 @@ include $(wildcard *.d)
 include $(wildcard mxml/*.d)
 
 EventsXML.cpp: events_xml.h
-ConfigurationXML.cpp: configuration_xml.h
+ConfigurationXML.cpp: defaults_xml.h
 
 # Don't regenerate conf-lex.c or conf-parse.c
 libsensors/conf-lex.c: ;
@@ -47,4 +47,4 @@ escape: escape.c
        gcc $^ -o $@
 
 clean:
-       rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h configuration_xml.h
+       rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h defaults_xml.h
similarity index 51%
rename from daemon/configuration.xml
rename to daemon/defaults.xml
index b44c00a79e88057d27d79613a10bc584a00cb0ec..5bf096cb2a459ab586fede46931231406a97e976 100644 (file)
@@ -6,29 +6,34 @@
   <configuration counter="ARM_ARM11MPCore_ccnt" event="0xff"/>
   <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08"/>
   <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b"/>
-  <configuration counter="ARM_Cortex-A5_ccnt" event="0xff"/>
-  <configuration counter="ARM_Cortex-A5_cnt0" event="0x8"/>
-  <configuration counter="ARM_Cortex-A5_cnt1" event="0x1"/>
-  <configuration counter="ARM_Cortex-A7_ccnt" event="0xff"/>
-  <configuration counter="ARM_Cortex-A7_cnt0" event="0x08"/>
-  <configuration counter="ARM_Cortex-A7_cnt1" event="0x10"/>
-  <configuration counter="ARM_Cortex-A7_cnt2" event="0x16"/>
-  <configuration counter="ARM_Cortex-A8_ccnt" event="0xff"/>
-  <configuration counter="ARM_Cortex-A8_cnt0" event="0x8"/>
-  <configuration counter="ARM_Cortex-A8_cnt1" event="0x44"/>
-  <configuration counter="ARM_Cortex-A8_cnt2" event="0x43"/>
-  <configuration counter="ARM_Cortex-A8_cnt3" event="0x10"/>
-  <configuration counter="ARM_Cortex-A9_ccnt" event="0xff"/>
-  <configuration counter="ARM_Cortex-A9_cnt0" event="0x68"/>
-  <configuration counter="ARM_Cortex-A9_cnt1" event="0x06"/>
-  <configuration counter="ARM_Cortex-A9_cnt2" event="0x07"/>
-  <configuration counter="ARM_Cortex-A9_cnt3" event="0x03"/>
-  <configuration counter="ARM_Cortex-A9_cnt4" event="0x04"/>
-  <configuration counter="ARM_Cortex-A15_ccnt" event="0xff"/>
-  <configuration counter="ARM_Cortex-A15_cnt0" event="0x8"/>
-  <configuration counter="ARM_Cortex-A15_cnt1" event="0x16"/>
-  <configuration counter="ARM_Cortex-A15_cnt2" event="0x10"/>
-  <configuration counter="ARM_Cortex-A15_cnt3" event="0x19"/>
+  <configuration counter="ARMv7_Cortex_A5_ccnt" event="0xff"/>
+  <configuration counter="ARMv7_Cortex_A5_cnt0" event="0x8"/>
+  <configuration counter="ARMv7_Cortex_A5_cnt1" event="0x1"/>
+  <configuration counter="ARMv7_Cortex_A7_ccnt" event="0xff"/>
+  <configuration counter="ARMv7_Cortex_A7_cnt0" event="0x08"/>
+  <configuration counter="ARMv7_Cortex_A7_cnt1" event="0x10"/>
+  <configuration counter="ARMv7_Cortex_A7_cnt2" event="0x16"/>
+  <configuration counter="ARMv7_Cortex_A8_ccnt" event="0xff"/>
+  <configuration counter="ARMv7_Cortex_A8_cnt0" event="0x8"/>
+  <configuration counter="ARMv7_Cortex_A8_cnt1" event="0x44"/>
+  <configuration counter="ARMv7_Cortex_A8_cnt2" event="0x43"/>
+  <configuration counter="ARMv7_Cortex_A8_cnt3" event="0x10"/>
+  <configuration counter="ARMv7_Cortex_A9_ccnt" event="0xff"/>
+  <configuration counter="ARMv7_Cortex_A9_cnt0" event="0x68"/>
+  <configuration counter="ARMv7_Cortex_A9_cnt1" event="0x06"/>
+  <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="ARM_Cortex-A53_ccnt" event="0x11"/>
   <configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/>
   <configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/>
index 3eec1f8d38d34d2e2c3b5ce290b07c65a0c19d4b..c54aa1c3e75d9be24d0febffefbb8f13e80d13a9 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index 20a4772c45878d0ee5a5222f06c512a52db7564b..9c04354ad137b2fb4f34eaa0e152bc254994a4c7 100644 (file)
@@ -1,6 +1,6 @@
-  <counter_set name="ARM_Cortex-A12_cnt" count="6"/>
-  <category name="Cortex-A12" counter_set="ARM_Cortex-A12_cnt" per_cpu="yes" supports_event_based_sampling="yes">
-    <event counter="ARM_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_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"/>
     <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"/>
index faa8b1cbcfb2c3a0f420297e678791650828079c..f50e55d6619502cd2aca0e9d7ce76473a70e92cd 100644 (file)
@@ -1,6 +1,6 @@
-  <counter_set name="ARM_Cortex-A15_cnt" count="6"/>
-  <category name="Cortex-A15" counter_set="ARM_Cortex-A15_cnt" per_cpu="yes" supports_event_based_sampling="yes">
-    <event counter="ARM_Cortex-A15_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_A15_cnt" count="6"/>
+  <category name="Cortex-A15" counter_set="ARMv7_Cortex_A15_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+    <event counter="ARMv7_Cortex_A15_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="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
     <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"/>
index a5b15466be5221eb04abab8b3a5aac1a8d522063..d67581d77c08d3b41ac6a979138e69bdb2d0ceb9 100644 (file)
@@ -1,6 +1,6 @@
-  <counter_set name="ARM_Cortex-A5_cnt" count="2"/>
-  <category name="Cortex-A5" counter_set="ARM_Cortex-A5_cnt" per_cpu="yes" supports_event_based_sampling="yes">
-    <event counter="ARM_Cortex-A5_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_A5_cnt" count="2"/>
+  <category name="Cortex-A5" counter_set="ARMv7_Cortex_A5_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+    <event counter="ARMv7_Cortex_A5_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="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
     <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
     <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
index 54d7264bc08e49b93bfbf97057cdbffc5c970cb5..6e078b3cffa3d8562ec52bfd4cb5868670efe5c5 100644 (file)
@@ -1,6 +1,6 @@
-  <counter_set name="ARM_Cortex-A7_cnt" count="4"/>
-  <category name="Cortex-A7" counter_set="ARM_Cortex-A7_cnt" per_cpu="yes" supports_event_based_sampling="yes">
-    <event counter="ARM_Cortex-A7_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_A7_cnt" count="4"/>
+  <category name="Cortex-A7" counter_set="ARMv7_Cortex_A7_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+    <event counter="ARMv7_Cortex_A7_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="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
     <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"/>
index f2518237983af904a8eeaab18cec9001f8001966..a69e25ab2c3483f6985d924a1ea55265fd682d29 100644 (file)
@@ -1,6 +1,6 @@
-  <counter_set name="ARM_Cortex-A8_cnt" count="4"/>
-  <category name="Cortex-A8" counter_set="ARM_Cortex-A8_cnt" per_cpu="yes" supports_event_based_sampling="yes">
-    <event counter="ARM_Cortex-A8_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_A8_cnt" count="4"/>
+  <category name="Cortex-A8" counter_set="ARMv7_Cortex_A8_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+    <event counter="ARMv7_Cortex_A8_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="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
     <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
     <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
index 75f09c80425e5f431fd7e8608777ea0a5bf8be4f..3e7f8289062e596f5bca5fa9c6f9ed118bbda606 100644 (file)
@@ -1,6 +1,6 @@
-  <counter_set name="ARM_Cortex-A9_cnt" count="6"/>
-  <category name="Cortex-A9" counter_set="ARM_Cortex-A9_cnt" per_cpu="yes" supports_event_based_sampling="yes">
-    <event counter="ARM_Cortex-A9_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_A9_cnt" count="6"/>
+  <category name="Cortex-A9" counter_set="ARMv7_Cortex_A9_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+    <event counter="ARMv7_Cortex_A9_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="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
     <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
     <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
index 31a90a1d6335e16a08bf3e37dbe2c836db3f3bfa..4d677e15db7e8546c0db6b4052c77575e5931f7c 100644 (file)
@@ -6,12 +6,12 @@
     <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" display="maximum" 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_memfree" title="Memory" name="Free" display="minimum" units="B" description="Available memory size"/>
-    <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" display="maximum" units="B" description="Memory used by OS disk buffers"/>
-    <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" display="maximum" 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" display="maximum" 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" display="average" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on contended resource"/>
-    <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" display="average" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on I/O resource"/>
+    <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_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" 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" description="Thread waiting on I/O resource"/>
   </category>
 
index 8772ce410b95d18530b83703f17252bdc06e1468..5a71386830ba1ff627ca30f3051826c54c79e3e2 100644 (file)
     <event event="0x0400" option_set="fs" title="ARM Mali-4xx" name="Filmstrip" description="Scaled framebuffer"/>
   </category>
   <category name="ARM_Mali-4xx_Voltage" per_cpu="no">
-    <event counter="ARM_Mali-4xx_Voltage" title="Mali GPU Voltage" name="Voltage" display="average" average_selection="yes" units="mV" description="GPU core voltage."/>
+    <event counter="ARM_Mali-4xx_Voltage" title="Mali GPU Voltage" name="Voltage" class="absolute" display="average" average_selection="yes" units="mV" description="GPU core voltage."/>
   </category>
   <category name="ARM_Mali-4xx_Frequency" per_cpu="no">
     <event counter="ARM_Mali-4xx_Frequency" title="Mali GPU Frequency" name="Frequency" display="average" average_selection="yes" units="MHz" description="GPU core frequency."/>
index 2465238a8bda8eeff71ba566d7932230af15cd77..ec9ca006f85fd6e7f2102537009171cdc578cc53 100644 (file)
@@ -4,14 +4,14 @@
   </category>
 
   <category name="Mali-T6xx-PMShader" per_cpu="no">
-    <event counter="ARM_Mali-T6xx_PM_SHADER_0" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 0" description="Mali PM Shader: PM Shader Core 0."/>
-    <event counter="ARM_Mali-T6xx_PM_SHADER_1" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 1" description="Mali PM Shader: PM Shader Core 1."/>
-    <event counter="ARM_Mali-T6xx_PM_SHADER_2" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 2" description="Mali PM Shader: PM Shader Core 2."/>
-    <event counter="ARM_Mali-T6xx_PM_SHADER_3" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 3" description="Mali PM Shader: PM Shader Core 3."/>
-    <event counter="ARM_Mali-T6xx_PM_SHADER_4" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 4" description="Mali PM Shader: PM Shader Core 4."/>
-    <event counter="ARM_Mali-T6xx_PM_SHADER_5" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 5" description="Mali PM Shader: PM Shader Core 5."/>
-    <event counter="ARM_Mali-T6xx_PM_SHADER_6" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 6" description="Mali PM Shader: PM Shader Core 6."/>
-    <event counter="ARM_Mali-T6xx_PM_SHADER_7" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 7" description="Mali PM Shader: PM Shader Core 7."/>
+    <event counter="ARM_Mali-T6xx_PM_SHADER_0" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 0" description="Mali PM Shader: PM Shader Core 0."/>
+    <event counter="ARM_Mali-T6xx_PM_SHADER_1" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 1" description="Mali PM Shader: PM Shader Core 1."/>
+    <event counter="ARM_Mali-T6xx_PM_SHADER_2" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 2" description="Mali PM Shader: PM Shader Core 2."/>
+    <event counter="ARM_Mali-T6xx_PM_SHADER_3" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 3" description="Mali PM Shader: PM Shader Core 3."/>
+    <event counter="ARM_Mali-T6xx_PM_SHADER_4" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 4" description="Mali PM Shader: PM Shader Core 4."/>
+    <event counter="ARM_Mali-T6xx_PM_SHADER_5" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 5" description="Mali PM Shader: PM Shader Core 5."/>
+    <event counter="ARM_Mali-T6xx_PM_SHADER_6" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 6" description="Mali PM Shader: PM Shader Core 6."/>
+    <event counter="ARM_Mali-T6xx_PM_SHADER_7" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 7" description="Mali PM Shader: PM Shader Core 7."/>
   </category>
 
   <category name="Mali-T6xx-PMTiler" per_cpu="no">
diff --git a/daemon/events-Perf-Hardware.xml b/daemon/events-Perf-Hardware.xml
new file mode 100644 (file)
index 0000000..423696f
--- /dev/null
@@ -0,0 +1,12 @@
+  <counter_set name="Perf_Hardware_cnt" count="6"/>
+  <category name="Perf Hardware" counter_set="Perf_Hardware_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+    <event counter="Perf_Hardware_ccnt" event="0" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+    <event event="1" title="Instruction" name="Executed" description="Instruction executed"/>
+    <event event="2" title="Cache" name="References" description="Cache References"/>
+    <event event="3" title="Cache" name="Misses" description="Cache Misses"/>
+    <event event="4" title="Branch" name="Instructions" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+    <event event="5" title="Branch" name="Misses" description="Branch mispredicted or not predicted"/>
+    <event event="6" title="Bus" name="Cycles" description="Bus Cycles"/>
+    <event event="7" title="Instruction" name="Stalled Frontend" description="Stalled Frontend Cycles"/>
+    <event event="8" title="Instruction" name="Stalled Backend" description="Stalled Backend Cycles"/>
+  </category>
diff --git a/daemon/k/perf_event.3.12.h b/daemon/k/perf_event.3.12.h
new file mode 100644 (file)
index 0000000..e886c48
--- /dev/null
@@ -0,0 +1,792 @@
+/*
+ * Performance events:
+ *
+ *    Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
+ *    Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
+ *    Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra
+ *
+ * Data type definitions, declarations, prototypes.
+ *
+ *    Started by: Thomas Gleixner and Ingo Molnar
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+#ifndef _LINUX_PERF_EVENT_H
+#define _LINUX_PERF_EVENT_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/byteorder.h>
+
+/*
+ * User-space ABI bits:
+ */
+
+/*
+ * attr.type
+ */
+enum perf_type_id {
+       PERF_TYPE_HARDWARE                      = 0,
+       PERF_TYPE_SOFTWARE                      = 1,
+       PERF_TYPE_TRACEPOINT                    = 2,
+       PERF_TYPE_HW_CACHE                      = 3,
+       PERF_TYPE_RAW                           = 4,
+       PERF_TYPE_BREAKPOINT                    = 5,
+
+       PERF_TYPE_MAX,                          /* non-ABI */
+};
+
+/*
+ * Generalized performance event event_id types, used by the
+ * attr.event_id parameter of the sys_perf_event_open()
+ * syscall:
+ */
+enum perf_hw_id {
+       /*
+        * Common hardware events, generalized by the kernel:
+        */
+       PERF_COUNT_HW_CPU_CYCLES                = 0,
+       PERF_COUNT_HW_INSTRUCTIONS              = 1,
+       PERF_COUNT_HW_CACHE_REFERENCES          = 2,
+       PERF_COUNT_HW_CACHE_MISSES              = 3,
+       PERF_COUNT_HW_BRANCH_INSTRUCTIONS       = 4,
+       PERF_COUNT_HW_BRANCH_MISSES             = 5,
+       PERF_COUNT_HW_BUS_CYCLES                = 6,
+       PERF_COUNT_HW_STALLED_CYCLES_FRONTEND   = 7,
+       PERF_COUNT_HW_STALLED_CYCLES_BACKEND    = 8,
+       PERF_COUNT_HW_REF_CPU_CYCLES            = 9,
+
+       PERF_COUNT_HW_MAX,                      /* non-ABI */
+};
+
+/*
+ * Generalized hardware cache events:
+ *
+ *       { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
+ *       { read, write, prefetch } x
+ *       { accesses, misses }
+ */
+enum perf_hw_cache_id {
+       PERF_COUNT_HW_CACHE_L1D                 = 0,
+       PERF_COUNT_HW_CACHE_L1I                 = 1,
+       PERF_COUNT_HW_CACHE_LL                  = 2,
+       PERF_COUNT_HW_CACHE_DTLB                = 3,
+       PERF_COUNT_HW_CACHE_ITLB                = 4,
+       PERF_COUNT_HW_CACHE_BPU                 = 5,
+       PERF_COUNT_HW_CACHE_NODE                = 6,
+
+       PERF_COUNT_HW_CACHE_MAX,                /* non-ABI */
+};
+
+enum perf_hw_cache_op_id {
+       PERF_COUNT_HW_CACHE_OP_READ             = 0,
+       PERF_COUNT_HW_CACHE_OP_WRITE            = 1,
+       PERF_COUNT_HW_CACHE_OP_PREFETCH         = 2,
+
+       PERF_COUNT_HW_CACHE_OP_MAX,             /* non-ABI */
+};
+
+enum perf_hw_cache_op_result_id {
+       PERF_COUNT_HW_CACHE_RESULT_ACCESS       = 0,
+       PERF_COUNT_HW_CACHE_RESULT_MISS         = 1,
+
+       PERF_COUNT_HW_CACHE_RESULT_MAX,         /* non-ABI */
+};
+
+/*
+ * Special "software" events provided by the kernel, even if the hardware
+ * does not support performance events. These events measure various
+ * physical and sw events of the kernel (and allow the profiling of them as
+ * well):
+ */
+enum perf_sw_ids {
+       PERF_COUNT_SW_CPU_CLOCK                 = 0,
+       PERF_COUNT_SW_TASK_CLOCK                = 1,
+       PERF_COUNT_SW_PAGE_FAULTS               = 2,
+       PERF_COUNT_SW_CONTEXT_SWITCHES          = 3,
+       PERF_COUNT_SW_CPU_MIGRATIONS            = 4,
+       PERF_COUNT_SW_PAGE_FAULTS_MIN           = 5,
+       PERF_COUNT_SW_PAGE_FAULTS_MAJ           = 6,
+       PERF_COUNT_SW_ALIGNMENT_FAULTS          = 7,
+       PERF_COUNT_SW_EMULATION_FAULTS          = 8,
+       PERF_COUNT_SW_DUMMY                     = 9,
+
+       PERF_COUNT_SW_MAX,                      /* non-ABI */
+};
+
+/*
+ * Bits that can be set in attr.sample_type to request information
+ * in the overflow packets.
+ */
+enum perf_event_sample_format {
+       PERF_SAMPLE_IP                          = 1U << 0,
+       PERF_SAMPLE_TID                         = 1U << 1,
+       PERF_SAMPLE_TIME                        = 1U << 2,
+       PERF_SAMPLE_ADDR                        = 1U << 3,
+       PERF_SAMPLE_READ                        = 1U << 4,
+       PERF_SAMPLE_CALLCHAIN                   = 1U << 5,
+       PERF_SAMPLE_ID                          = 1U << 6,
+       PERF_SAMPLE_CPU                         = 1U << 7,
+       PERF_SAMPLE_PERIOD                      = 1U << 8,
+       PERF_SAMPLE_STREAM_ID                   = 1U << 9,
+       PERF_SAMPLE_RAW                         = 1U << 10,
+       PERF_SAMPLE_BRANCH_STACK                = 1U << 11,
+       PERF_SAMPLE_REGS_USER                   = 1U << 12,
+       PERF_SAMPLE_STACK_USER                  = 1U << 13,
+       PERF_SAMPLE_WEIGHT                      = 1U << 14,
+       PERF_SAMPLE_DATA_SRC                    = 1U << 15,
+       PERF_SAMPLE_IDENTIFIER                  = 1U << 16,
+
+       PERF_SAMPLE_MAX = 1U << 17,             /* non-ABI */
+};
+
+/*
+ * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
+ *
+ * If the user does not pass priv level information via branch_sample_type,
+ * the kernel uses the event's priv level. Branch and event priv levels do
+ * not have to match. Branch priv level is checked for permissions.
+ *
+ * The branch types can be combined, however BRANCH_ANY covers all types
+ * of branches and therefore it supersedes all the other types.
+ */
+enum perf_branch_sample_type {
+       PERF_SAMPLE_BRANCH_USER         = 1U << 0, /* user branches */
+       PERF_SAMPLE_BRANCH_KERNEL       = 1U << 1, /* kernel branches */
+       PERF_SAMPLE_BRANCH_HV           = 1U << 2, /* hypervisor branches */
+
+       PERF_SAMPLE_BRANCH_ANY          = 1U << 3, /* any branch types */
+       PERF_SAMPLE_BRANCH_ANY_CALL     = 1U << 4, /* any call branch */
+       PERF_SAMPLE_BRANCH_ANY_RETURN   = 1U << 5, /* any return branch */
+       PERF_SAMPLE_BRANCH_IND_CALL     = 1U << 6, /* indirect calls */
+       PERF_SAMPLE_BRANCH_ABORT_TX     = 1U << 7, /* transaction aborts */
+       PERF_SAMPLE_BRANCH_IN_TX        = 1U << 8, /* in transaction */
+       PERF_SAMPLE_BRANCH_NO_TX        = 1U << 9, /* not in transaction */
+
+       PERF_SAMPLE_BRANCH_MAX          = 1U << 10, /* non-ABI */
+};
+
+#define PERF_SAMPLE_BRANCH_PLM_ALL \
+       (PERF_SAMPLE_BRANCH_USER|\
+        PERF_SAMPLE_BRANCH_KERNEL|\
+        PERF_SAMPLE_BRANCH_HV)
+
+/*
+ * Values to determine ABI of the registers dump.
+ */
+enum perf_sample_regs_abi {
+       PERF_SAMPLE_REGS_ABI_NONE       = 0,
+       PERF_SAMPLE_REGS_ABI_32         = 1,
+       PERF_SAMPLE_REGS_ABI_64         = 2,
+};
+
+/*
+ * The format of the data returned by read() on a perf event fd,
+ * as specified by attr.read_format:
+ *
+ * struct read_format {
+ *     { u64           value;
+ *       { u64         time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ *       { u64         time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
+ *       { u64         id;           } && PERF_FORMAT_ID
+ *     } && !PERF_FORMAT_GROUP
+ *
+ *     { u64           nr;
+ *       { u64         time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ *       { u64         time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
+ *       { u64         value;
+ *         { u64       id;           } && PERF_FORMAT_ID
+ *       }             cntr[nr];
+ *     } && PERF_FORMAT_GROUP
+ * };
+ */
+enum perf_event_read_format {
+       PERF_FORMAT_TOTAL_TIME_ENABLED          = 1U << 0,
+       PERF_FORMAT_TOTAL_TIME_RUNNING          = 1U << 1,
+       PERF_FORMAT_ID                          = 1U << 2,
+       PERF_FORMAT_GROUP                       = 1U << 3,
+
+       PERF_FORMAT_MAX = 1U << 4,              /* non-ABI */
+};
+
+#define PERF_ATTR_SIZE_VER0    64      /* sizeof first published struct */
+#define PERF_ATTR_SIZE_VER1    72      /* add: config2 */
+#define PERF_ATTR_SIZE_VER2    80      /* add: branch_sample_type */
+#define PERF_ATTR_SIZE_VER3    96      /* add: sample_regs_user */
+                                       /* add: sample_stack_user */
+
+/*
+ * Hardware event_id to monitor via a performance monitoring event:
+ */
+struct perf_event_attr {
+
+       /*
+        * Major type: hardware/software/tracepoint/etc.
+        */
+       __u32                   type;
+
+       /*
+        * Size of the attr structure, for fwd/bwd compat.
+        */
+       __u32                   size;
+
+       /*
+        * Type specific configuration information.
+        */
+       __u64                   config;
+
+       union {
+               __u64           sample_period;
+               __u64           sample_freq;
+       };
+
+       __u64                   sample_type;
+       __u64                   read_format;
+
+       __u64                   disabled       :  1, /* off by default        */
+                               inherit        :  1, /* children inherit it   */
+                               pinned         :  1, /* must always be on PMU */
+                               exclusive      :  1, /* only group on PMU     */
+                               exclude_user   :  1, /* don't count user      */
+                               exclude_kernel :  1, /* ditto kernel          */
+                               exclude_hv     :  1, /* ditto hypervisor      */
+                               exclude_idle   :  1, /* don't count when idle */
+                               mmap           :  1, /* include mmap data     */
+                               comm           :  1, /* include comm data     */
+                               freq           :  1, /* use freq, not period  */
+                               inherit_stat   :  1, /* per task counts       */
+                               enable_on_exec :  1, /* next exec enables     */
+                               task           :  1, /* trace fork/exit       */
+                               watermark      :  1, /* wakeup_watermark      */
+                               /*
+                                * precise_ip:
+                                *
+                                *  0 - SAMPLE_IP can have arbitrary skid
+                                *  1 - SAMPLE_IP must have constant skid
+                                *  2 - SAMPLE_IP requested to have 0 skid
+                                *  3 - SAMPLE_IP must have 0 skid
+                                *
+                                *  See also PERF_RECORD_MISC_EXACT_IP
+                                */
+                               precise_ip     :  2, /* skid constraint       */
+                               mmap_data      :  1, /* non-exec mmap data    */
+                               sample_id_all  :  1, /* sample_type all events */
+
+                               exclude_host   :  1, /* don't count in host   */
+                               exclude_guest  :  1, /* don't count in guest  */
+
+                               exclude_callchain_kernel : 1, /* exclude kernel callchains */
+                               exclude_callchain_user   : 1, /* exclude user callchains */
+                               mmap2          :  1, /* include mmap with inode data     */
+
+                               __reserved_1   : 40;
+
+       union {
+               __u32           wakeup_events;    /* wakeup every n events */
+               __u32           wakeup_watermark; /* bytes before wakeup   */
+       };
+
+       __u32                   bp_type;
+       union {
+               __u64           bp_addr;
+               __u64           config1; /* extension of config */
+       };
+       union {
+               __u64           bp_len;
+               __u64           config2; /* extension of config1 */
+       };
+       __u64   branch_sample_type; /* enum perf_branch_sample_type */
+
+       /*
+        * Defines set of user regs to dump on samples.
+        * See asm/perf_regs.h for details.
+        */
+       __u64   sample_regs_user;
+
+       /*
+        * Defines size of the user stack to dump on samples.
+        */
+       __u32   sample_stack_user;
+
+       /* Align to u64. */
+       __u32   __reserved_2;
+};
+
+#define perf_flags(attr)       (*(&(attr)->read_format + 1))
+
+/*
+ * Ioctls that can be done on a perf event fd:
+ */
+#define PERF_EVENT_IOC_ENABLE          _IO ('$', 0)
+#define PERF_EVENT_IOC_DISABLE         _IO ('$', 1)
+#define PERF_EVENT_IOC_REFRESH         _IO ('$', 2)
+#define PERF_EVENT_IOC_RESET           _IO ('$', 3)
+#define PERF_EVENT_IOC_PERIOD          _IOW('$', 4, __u64)
+#define PERF_EVENT_IOC_SET_OUTPUT      _IO ('$', 5)
+#define PERF_EVENT_IOC_SET_FILTER      _IOW('$', 6, char *)
+#define PERF_EVENT_IOC_ID              _IOR('$', 7, __u64 *)
+
+enum perf_event_ioc_flags {
+       PERF_IOC_FLAG_GROUP             = 1U << 0,
+};
+
+/*
+ * Structure of the page that can be mapped via mmap
+ */
+struct perf_event_mmap_page {
+       __u32   version;                /* version number of this structure */
+       __u32   compat_version;         /* lowest version this is compat with */
+
+       /*
+        * Bits needed to read the hw events in user-space.
+        *
+        *   u32 seq, time_mult, time_shift, idx, width;
+        *   u64 count, enabled, running;
+        *   u64 cyc, time_offset;
+        *   s64 pmc = 0;
+        *
+        *   do {
+        *     seq = pc->lock;
+        *     barrier()
+        *
+        *     enabled = pc->time_enabled;
+        *     running = pc->time_running;
+        *
+        *     if (pc->cap_usr_time && enabled != running) {
+        *       cyc = rdtsc();
+        *       time_offset = pc->time_offset;
+        *       time_mult   = pc->time_mult;
+        *       time_shift  = pc->time_shift;
+        *     }
+        *
+        *     idx = pc->index;
+        *     count = pc->offset;
+        *     if (pc->cap_usr_rdpmc && idx) {
+        *       width = pc->pmc_width;
+        *       pmc = rdpmc(idx - 1);
+        *     }
+        *
+        *     barrier();
+        *   } while (pc->lock != seq);
+        *
+        * NOTE: for obvious reason this only works on self-monitoring
+        *       processes.
+        */
+       __u32   lock;                   /* seqlock for synchronization */
+       __u32   index;                  /* hardware event identifier */
+       __s64   offset;                 /* add to hardware event value */
+       __u64   time_enabled;           /* time event active */
+       __u64   time_running;           /* time event on cpu */
+       union {
+               __u64   capabilities;
+               struct {
+                       __u64   cap_bit0                : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
+                               cap_bit0_is_deprecated  : 1, /* Always 1, signals that bit 0 is zero */
+
+                               cap_user_rdpmc          : 1, /* The RDPMC instruction can be used to read counts */
+                               cap_user_time           : 1, /* The time_* fields are used */
+                               cap_user_time_zero      : 1, /* The time_zero field is used */
+                               cap_____res             : 59;
+               };
+       };
+
+       /*
+        * If cap_usr_rdpmc this field provides the bit-width of the value
+        * read using the rdpmc() or equivalent instruction. This can be used
+        * to sign extend the result like:
+        *
+        *   pmc <<= 64 - width;
+        *   pmc >>= 64 - width; // signed shift right
+        *   count += pmc;
+        */
+       __u16   pmc_width;
+
+       /*
+        * If cap_usr_time the below fields can be used to compute the time
+        * delta since time_enabled (in ns) using rdtsc or similar.
+        *
+        *   u64 quot, rem;
+        *   u64 delta;
+        *
+        *   quot = (cyc >> time_shift);
+        *   rem = cyc & ((1 << time_shift) - 1);
+        *   delta = time_offset + quot * time_mult +
+        *              ((rem * time_mult) >> time_shift);
+        *
+        * Where time_offset,time_mult,time_shift and cyc are read in the
+        * seqcount loop described above. This delta can then be added to
+        * enabled and possible running (if idx), improving the scaling:
+        *
+        *   enabled += delta;
+        *   if (idx)
+        *     running += delta;
+        *
+        *   quot = count / running;
+        *   rem  = count % running;
+        *   count = quot * enabled + (rem * enabled) / running;
+        */
+       __u16   time_shift;
+       __u32   time_mult;
+       __u64   time_offset;
+       /*
+        * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
+        * from sample timestamps.
+        *
+        *   time = timestamp - time_zero;
+        *   quot = time / time_mult;
+        *   rem  = time % time_mult;
+        *   cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
+        *
+        * And vice versa:
+        *
+        *   quot = cyc >> time_shift;
+        *   rem  = cyc & ((1 << time_shift) - 1);
+        *   timestamp = time_zero + quot * time_mult +
+        *               ((rem * time_mult) >> time_shift);
+        */
+       __u64   time_zero;
+       __u32   size;                   /* Header size up to __reserved[] fields. */
+
+               /*
+                * Hole for extension of the self monitor capabilities
+                */
+
+       __u8    __reserved[118*8+4];    /* align to 1k. */
+
+       /*
+        * Control data for the mmap() data buffer.
+        *
+        * User-space reading the @data_head value should issue an smp_rmb(),
+        * after reading this value.
+        *
+        * When the mapping is PROT_WRITE the @data_tail value should be
+        * written by userspace to reflect the last read data, after issueing
+        * an smp_mb() to separate the data read from the ->data_tail store.
+        * In this case the kernel will not over-write unread data.
+        *
+        * See perf_output_put_handle() for the data ordering.
+        */
+       __u64   data_head;              /* head in the data section */
+       __u64   data_tail;              /* user-space written tail */
+};
+
+#define PERF_RECORD_MISC_CPUMODE_MASK          (7 << 0)
+#define PERF_RECORD_MISC_CPUMODE_UNKNOWN       (0 << 0)
+#define PERF_RECORD_MISC_KERNEL                        (1 << 0)
+#define PERF_RECORD_MISC_USER                  (2 << 0)
+#define PERF_RECORD_MISC_HYPERVISOR            (3 << 0)
+#define PERF_RECORD_MISC_GUEST_KERNEL          (4 << 0)
+#define PERF_RECORD_MISC_GUEST_USER            (5 << 0)
+
+#define PERF_RECORD_MISC_MMAP_DATA             (1 << 13)
+/*
+ * Indicates that the content of PERF_SAMPLE_IP points to
+ * the actual instruction that triggered the event. See also
+ * perf_event_attr::precise_ip.
+ */
+#define PERF_RECORD_MISC_EXACT_IP              (1 << 14)
+/*
+ * Reserve the last bit to indicate some extended misc field
+ */
+#define PERF_RECORD_MISC_EXT_RESERVED          (1 << 15)
+
+struct perf_event_header {
+       __u32   type;
+       __u16   misc;
+       __u16   size;
+};
+
+enum perf_event_type {
+
+       /*
+        * If perf_event_attr.sample_id_all is set then all event types will
+        * have the sample_type selected fields related to where/when
+        * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
+        * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
+        * just after the perf_event_header and the fields already present for
+        * the existing fields, i.e. at the end of the payload. That way a newer
+        * perf.data file will be supported by older perf tools, with these new
+        * optional fields being ignored.
+        *
+        * struct sample_id {
+        *      { u32                   pid, tid; } && PERF_SAMPLE_TID
+        *      { u64                   time;     } && PERF_SAMPLE_TIME
+        *      { u64                   id;       } && PERF_SAMPLE_ID
+        *      { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
+        *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
+        *      { u64                   id;       } && PERF_SAMPLE_IDENTIFIER
+        * } && perf_event_attr::sample_id_all
+        *
+        * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.  The
+        * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
+        * relative to header.size.
+        */
+
+       /*
+        * The MMAP events record the PROT_EXEC mappings so that we can
+        * correlate userspace IPs to code. They have the following structure:
+        *
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      u32                             pid, tid;
+        *      u64                             addr;
+        *      u64                             len;
+        *      u64                             pgoff;
+        *      char                            filename[];
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_MMAP                        = 1,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u64                             id;
+        *      u64                             lost;
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_LOST                        = 2,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      u32                             pid, tid;
+        *      char                            comm[];
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_COMM                        = 3,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, ppid;
+        *      u32                             tid, ptid;
+        *      u64                             time;
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_EXIT                        = 4,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u64                             time;
+        *      u64                             id;
+        *      u64                             stream_id;
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_THROTTLE                    = 5,
+       PERF_RECORD_UNTHROTTLE                  = 6,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, ppid;
+        *      u32                             tid, ptid;
+        *      u64                             time;
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_FORK                        = 7,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, tid;
+        *
+        *      struct read_format              values;
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_READ                        = 8,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      #
+        *      # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
+        *      # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
+        *      # is fixed relative to header.
+        *      #
+        *
+        *      { u64                   id;       } && PERF_SAMPLE_IDENTIFIER
+        *      { u64                   ip;       } && PERF_SAMPLE_IP
+        *      { u32                   pid, tid; } && PERF_SAMPLE_TID
+        *      { u64                   time;     } && PERF_SAMPLE_TIME
+        *      { u64                   addr;     } && PERF_SAMPLE_ADDR
+        *      { u64                   id;       } && PERF_SAMPLE_ID
+        *      { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
+        *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
+        *      { u64                   period;   } && PERF_SAMPLE_PERIOD
+        *
+        *      { struct read_format    values;   } && PERF_SAMPLE_READ
+        *
+        *      { u64                   nr,
+        *        u64                   ips[nr];  } && PERF_SAMPLE_CALLCHAIN
+        *
+        *      #
+        *      # The RAW record below is opaque data wrt the ABI
+        *      #
+        *      # That is, the ABI doesn't make any promises wrt to
+        *      # the stability of its content, it may vary depending
+        *      # on event, hardware, kernel version and phase of
+        *      # the moon.
+        *      #
+        *      # In other words, PERF_SAMPLE_RAW contents are not an ABI.
+        *      #
+        *
+        *      { u32                   size;
+        *        char                  data[size];}&& PERF_SAMPLE_RAW
+        *
+        *      { u64                   nr;
+        *        { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+        *
+        *      { u64                   abi; # enum perf_sample_regs_abi
+        *        u64                   regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
+        *
+        *      { u64                   size;
+        *        char                  data[size];
+        *        u64                   dyn_size; } && PERF_SAMPLE_STACK_USER
+        *
+        *      { u64                   weight;   } && PERF_SAMPLE_WEIGHT
+        *      { u64                   data_src; } && PERF_SAMPLE_DATA_SRC
+        * };
+        */
+       PERF_RECORD_SAMPLE                      = 9,
+
+       /*
+        * The MMAP2 records are an augmented version of MMAP, they add
+        * maj, min, ino numbers to be used to uniquely identify each mapping
+        *
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      u32                             pid, tid;
+        *      u64                             addr;
+        *      u64                             len;
+        *      u64                             pgoff;
+        *      u32                             maj;
+        *      u32                             min;
+        *      u64                             ino;
+        *      u64                             ino_generation;
+        *      char                            filename[];
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_MMAP2                       = 10,
+
+       PERF_RECORD_MAX,                        /* non-ABI */
+};
+
+#define PERF_MAX_STACK_DEPTH           127
+
+enum perf_callchain_context {
+       PERF_CONTEXT_HV                 = (__u64)-32,
+       PERF_CONTEXT_KERNEL             = (__u64)-128,
+       PERF_CONTEXT_USER               = (__u64)-512,
+
+       PERF_CONTEXT_GUEST              = (__u64)-2048,
+       PERF_CONTEXT_GUEST_KERNEL       = (__u64)-2176,
+       PERF_CONTEXT_GUEST_USER         = (__u64)-2560,
+
+       PERF_CONTEXT_MAX                = (__u64)-4095,
+};
+
+#define PERF_FLAG_FD_NO_GROUP          (1U << 0)
+#define PERF_FLAG_FD_OUTPUT            (1U << 1)
+#define PERF_FLAG_PID_CGROUP           (1U << 2) /* pid=cgroup id, per-cpu mode only */
+
+union perf_mem_data_src {
+       __u64 val;
+       struct {
+               __u64   mem_op:5,       /* type of opcode */
+                       mem_lvl:14,     /* memory hierarchy level */
+                       mem_snoop:5,    /* snoop mode */
+                       mem_lock:2,     /* lock instr */
+                       mem_dtlb:7,     /* tlb access */
+                       mem_rsvd:31;
+       };
+};
+
+/* type of opcode (load/store/prefetch,code) */
+#define PERF_MEM_OP_NA         0x01 /* not available */
+#define PERF_MEM_OP_LOAD       0x02 /* load instruction */
+#define PERF_MEM_OP_STORE      0x04 /* store instruction */
+#define PERF_MEM_OP_PFETCH     0x08 /* prefetch */
+#define PERF_MEM_OP_EXEC       0x10 /* code (execution) */
+#define PERF_MEM_OP_SHIFT      0
+
+/* memory hierarchy (memory level, hit or miss) */
+#define PERF_MEM_LVL_NA                0x01  /* not available */
+#define PERF_MEM_LVL_HIT       0x02  /* hit level */
+#define PERF_MEM_LVL_MISS      0x04  /* miss level  */
+#define PERF_MEM_LVL_L1                0x08  /* L1 */
+#define PERF_MEM_LVL_LFB       0x10  /* Line Fill Buffer */
+#define PERF_MEM_LVL_L2                0x20  /* L2 */
+#define PERF_MEM_LVL_L3                0x40  /* L3 */
+#define PERF_MEM_LVL_LOC_RAM   0x80  /* Local DRAM */
+#define PERF_MEM_LVL_REM_RAM1  0x100 /* Remote DRAM (1 hop) */
+#define PERF_MEM_LVL_REM_RAM2  0x200 /* Remote DRAM (2 hops) */
+#define PERF_MEM_LVL_REM_CCE1  0x400 /* Remote Cache (1 hop) */
+#define PERF_MEM_LVL_REM_CCE2  0x800 /* Remote Cache (2 hops) */
+#define PERF_MEM_LVL_IO                0x1000 /* I/O memory */
+#define PERF_MEM_LVL_UNC       0x2000 /* Uncached memory */
+#define PERF_MEM_LVL_SHIFT     5
+
+/* snoop mode */
+#define PERF_MEM_SNOOP_NA      0x01 /* not available */
+#define PERF_MEM_SNOOP_NONE    0x02 /* no snoop */
+#define PERF_MEM_SNOOP_HIT     0x04 /* snoop hit */
+#define PERF_MEM_SNOOP_MISS    0x08 /* snoop miss */
+#define PERF_MEM_SNOOP_HITM    0x10 /* snoop hit modified */
+#define PERF_MEM_SNOOP_SHIFT   19
+
+/* locked instruction */
+#define PERF_MEM_LOCK_NA       0x01 /* not available */
+#define PERF_MEM_LOCK_LOCKED   0x02 /* locked transaction */
+#define PERF_MEM_LOCK_SHIFT    24
+
+/* TLB access */
+#define PERF_MEM_TLB_NA                0x01 /* not available */
+#define PERF_MEM_TLB_HIT       0x02 /* hit level */
+#define PERF_MEM_TLB_MISS      0x04 /* miss level */
+#define PERF_MEM_TLB_L1                0x08 /* L1 */
+#define PERF_MEM_TLB_L2                0x10 /* L2 */
+#define PERF_MEM_TLB_WK                0x20 /* Hardware Walker*/
+#define PERF_MEM_TLB_OS                0x40 /* OS fault handler */
+#define PERF_MEM_TLB_SHIFT     26
+
+#define PERF_MEM_S(a, s) \
+       (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
+
+/*
+ * single taken branch record layout:
+ *
+ *      from: source instruction (may not always be a branch insn)
+ *        to: branch target
+ *   mispred: branch target was mispredicted
+ * predicted: branch target was predicted
+ *
+ * support for mispred, predicted is optional. In case it
+ * is not supported mispred = predicted = 0.
+ *
+ *     in_tx: running in a hardware transaction
+ *     abort: aborting a hardware transaction
+ */
+struct perf_branch_entry {
+       __u64   from;
+       __u64   to;
+       __u64   mispred:1,  /* target mispredicted */
+               predicted:1,/* target predicted */
+               in_tx:1,    /* in transaction */
+               abort:1,    /* transaction abort */
+               reserved:60;
+};
+
+#endif /* _LINUX_PERF_EVENT_H */
diff --git a/daemon/k/perf_event.h b/daemon/k/perf_event.h
new file mode 120000 (symlink)
index 0000000..e5dff8c
--- /dev/null
@@ -0,0 +1 @@
+perf_event.3.12.h
\ No newline at end of file
index bfd36b98766c63319b76702d0845d75cc2a92c87..1275aef1cb7938ffe804f7168095c7cd47b6e187 100644 (file)
@@ -1,32 +1,30 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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 <stdlib.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-#include <sys/prctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
+#include <arpa/inet.h>
 #include <fcntl.h>
+#include <pthread.h>
 #include <sys/mman.h>
-#include <sys/time.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
 #include <sys/resource.h>
-#include <arpa/inet.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
 #include "Child.h"
-#include "SessionData.h"
-#include "OlySocket.h"
+#include "KMod.h"
 #include "Logging.h"
+#include "OlySocket.h"
 #include "OlyUtility.h"
-#include "KMod.h"
+#include "SessionData.h"
 
 #define DEBUG false
 
@@ -34,7 +32,7 @@ extern Child* child;
 static int shutdownFilesystem();
 static pthread_mutex_t numSessions_mutex;
 static int numSessions = 0;
-static OlySocket* sock = NULL;
+static OlyServerSocket* sock = NULL;
 static bool driverRunningAtStart = false;
 static bool driverMountedAtStart = false;
 
@@ -157,6 +155,7 @@ typedef struct {
 static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 };
 
 static void* answerThread(void* pVoid) {
+       prctl(PR_SET_NAME, (unsigned long)&"gatord-discover", 0, 0, 0);
        const struct cmdline_t * const cmdline = (struct cmdline_t *)pVoid;
        RVIConfigureInfo dstAns;
        int req = udpPort(UDP_REQ_PORT);
@@ -231,16 +230,7 @@ static bool init_module (const char * const location) {
        return ret;
 }
 
-static int setupFilesystem(char* module) {
-       int retval;
-
-       // Verify root permissions
-       uid_t euid = geteuid();
-       if (euid) {
-               logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
-               handleException();
-       }
-
+static bool setupFilesystem(char* module) {
        if (module) {
                // unmount and rmmod if the module was specified on the commandline, i.e. ensure that the specified module is indeed running
                shutdownFilesystem();
@@ -252,7 +242,7 @@ static int setupFilesystem(char* module) {
                }
        }
 
-       retval = mountGatorFS();
+       const int retval = mountGatorFS();
        if (retval == 1) {
                logg->logMessage("Driver already running at startup");
                driverRunningAtStart = true;
@@ -274,8 +264,8 @@ static int setupFilesystem(char* module) {
                }
 
                if (access(location, F_OK) == -1) {
-                       logg->logError(__FILE__, __LINE__, "Unable to locate gator.ko driver:\n  >>> 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");
-                       handleException();
+                       // The gator kernel is not already loaded and unable to locate gator.ko
+                       return false;
                }
 
                // Load driver
@@ -296,7 +286,7 @@ static int setupFilesystem(char* module) {
                }
        }
 
-       return 0;
+       return true;
 }
 
 static int shutdownFilesystem() {
@@ -418,8 +408,28 @@ int main(int argc, char** argv) {
        // Parse the command line parameters
        struct cmdline_t cmdline = parseCommandLine(argc, argv);
 
+       // Verify root permissions
+       uid_t euid = geteuid();
+       if (euid) {
+               logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
+               handleException();
+       }
+
        // Call before setting up the SIGCHLD handler, as system() spawns child processes
-       setupFilesystem(cmdline.module);
+       if (!setupFilesystem(cmdline.module)) {
+               logg->logMessage("Unable to setup gatorfs, trying perf");
+               if (!gSessionData->perf.setup()) {
+                       logg->logError(__FILE__, __LINE__,
+                                                                                "Unable to locate gator.ko driver:\n"
+                                                                                "  >>> 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.12 or later with perf support to collect data via userspace only");
+                       handleException();
+               }
+       }
+
+       gSessionData->hwmon.setup();
 
        // Handle child exit codes
        signal(SIGCHLD, child_exit);
@@ -439,11 +449,11 @@ int main(int argc, char** argv) {
                        logg->logError(__FILE__, __LINE__, "Failed to create answer thread");
                        handleException();
                }
-               sock = new OlySocket(cmdline.port, true);
+               sock = new OlyServerSocket(cmdline.port);
                // Forever loop, can be exited via a signal or exception
                while (1) {
                        logg->logMessage("Waiting on connection...");
-                       sock->acceptConnection();
+                       OlySocket client(sock->acceptConnection());
 
                        int pid = fork();
                        if (pid < 0) {
@@ -452,13 +462,13 @@ int main(int argc, char** argv) {
                        } else if (pid == 0) {
                                // Child
                                sock->closeServerSocket();
-                               child = new Child(sock, numSessions + 1);
+                               child = new Child(&client, numSessions + 1);
                                child->run();
                                delete child;
                                exit(0);
                        } else {
                                // Parent
-                               sock->closeSocket();
+                               client.closeSocket();
 
                                pthread_mutex_lock(&numSessions_mutex);
                                numSessions++;
diff --git a/driver/Kconfig b/driver/Kconfig
new file mode 100644 (file)
index 0000000..e46ccb9
--- /dev/null
@@ -0,0 +1,39 @@
+config GATOR
+       tristate "Gator module for ARM's Streamline Performance Analyzer"
+       default m if (ARM || ARM64)
+       depends on PROFILING
+       depends on HIGH_RES_TIMERS
+       depends on LOCAL_TIMERS || !(ARM && SMP)
+       depends on PERF_EVENTS
+       depends on HW_PERF_EVENTS || !(ARM || ARM64)
+       select TRACING
+       help
+         Gator module for ARM's Streamline Performance Analyzer
+
+config GATOR_WITH_MALI_SUPPORT
+       bool
+
+choice
+       prompt "Enable Mali GPU support in Gator"
+       depends on GATOR
+       optional
+       help
+         Enable Mali GPU support in Gator
+
+config GATOR_MALI_4XXMP
+       bool "Mali-400MP or Mali-450MP"
+       select GATOR_WITH_MALI_SUPPORT
+
+config GATOR_MALI_T6XX
+       bool "Mali-T604 or Mali-T658"
+       select GATOR_WITH_MALI_SUPPORT
+
+endchoice
+
+config GATOR_MALI_PATH
+       string "Path to Mali driver"
+       depends on GATOR_WITH_MALI_SUPPORT
+       default "drivers/gpu/arm/mali400mp"
+       help
+         The gator code adds this to its include path so it can get the Mali
+         trace headers with: #include "linux/mali_linux_trace.h"
index d8981ed85a6a101cbfa5aadcfda9af4f99859a54..586cd9e742fb14bc2a6d2e8f808fe5539ec95919 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -31,6 +31,7 @@
 #define CORTEX_A9   0xc09
 #define CORTEX_A12  0xc0d
 #define CORTEX_A15  0xc0f
+#define CORTEX_A17  0xc0e
 #define SCORPION    0x00f
 #define SCORPIONMP  0x02d
 #define KRAITSIM    0x049
@@ -47,9 +48,7 @@ struct gator_cpu {
        const int cpuid;
        // Human readable name
        const char core_name[MAXSIZE_CORE_NAME];
-       // Perf PMU name
-       const char * const pmu_name;
-       // gatorfs event 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;
@@ -62,10 +61,6 @@ const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name);
 /******************************************************************************
  * Filesystem
  ******************************************************************************/
-int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
-                            char const *name,
-                            const struct file_operations *fops, int perm);
-
 struct dentry *gatorfs_mkdir(struct super_block *sb, struct dentry *root,
                             char const *name);
 
@@ -75,8 +70,6 @@ int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
 int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
                            char const *name, unsigned long *val);
 
-void gator_op_create_files(struct super_block *sb, struct dentry *root);
-
 /******************************************************************************
  * Tracepoints
  ******************************************************************************/
index 5b9399bea230c7cccd982bc81ba49216786175af..7e2c6e5d871510033cb92c971a9a53235023b601 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index a406e4882974ba27571d7dadb12feaf1050103e8..0108068255297285859854a15bc632579365de15 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
@@ -29,12 +29,14 @@ static void kannotate_write(const char *ptr, unsigned int size)
        }
 }
 
-static void marshal_u16(char *buf, u16 val) {
+static void marshal_u16(char *buf, u16 val)
+{
        buf[0] = val & 0xff;
        buf[1] = (val >> 8) & 0xff;
 }
 
-static void marshal_u32(char *buf, u32 val) {
+static void marshal_u32(char *buf, u32 val)
+{
        buf[0] = val & 0xff;
        buf[1] = (val >> 8) & 0xff;
        buf[2] = (val >> 16) & 0xff;
index ffacb490194cb60a7161bea3b2f7886f1b732891..9f305cf7242c8c2b3a196a13d7e3ad5e6e1811b7 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -30,6 +30,18 @@ struct stack_frame_eabi {
        };
 };
 
+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) {
+               offset = address;
+       }
+
+       marshal_backtrace(offset & ~1, cookie, 0);
+}
+
 static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth)
 {
 #if defined(__arm__) || defined(__aarch64__)
@@ -122,7 +134,7 @@ static int report_trace(struct stackframe *frame, void *d)
                        addr = addr - (unsigned long)mod->module_core;
                }
 #endif
-               marshal_backtrace(addr & ~1, cookie);
+               marshal_backtrace(addr & ~1, cookie, 1);
                (*depth)--;
        }
 
@@ -136,7 +148,7 @@ static int report_trace(struct stackframe *frame, void *d)
 #if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING)
 // Disabled by default
 MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding.");
-bool kernel_stack_unwinding = 0;
+static bool kernel_stack_unwinding = 0;
 module_param(kernel_stack_unwinding, bool, 0644);
 #endif
 
@@ -163,6 +175,34 @@ static void kernel_backtrace(int cpu, struct pt_regs *const regs)
 #endif
        walk_stackframe(&frame, report_trace, &depth);
 #else
-       marshal_backtrace(PC_REG & ~1, NO_COOKIE);
+       marshal_backtrace(PC_REG & ~1, NO_COOKIE, 1);
 #endif
 }
+static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time)
+{
+       bool in_kernel;
+       unsigned long exec_cookie;
+
+       if (!regs)
+               return;
+
+       in_kernel = !user_mode(regs);
+       exec_cookie = get_exec_cookie(cpu, current);
+
+       if (!marshal_backtrace_header(exec_cookie, current->tgid, current->pid, time))
+               return;
+
+       if (in_kernel) {
+               kernel_backtrace(cpu, regs);
+       } else {
+               // Cookie+PC
+               gator_add_trace(cpu, PC_REG);
+
+               // Backtrace
+               if (gator_backtrace_depth)
+                       arm_backtrace_eabi(cpu, regs, gator_backtrace_depth);
+       }
+
+       marshal_backtrace_footer(time);
+}
diff --git a/driver/gator_buffer.c b/driver/gator_buffer.c
new file mode 100644 (file)
index 0000000..eba22df
--- /dev/null
@@ -0,0 +1,168 @@
+/**
+ * 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.
+ *
+ */
+
+static void marshal_frame(int cpu, int buftype)
+{
+       int frame;
+
+       if (!per_cpu(gator_buffer, cpu)[buftype]) {
+               return;
+       }
+
+       switch (buftype) {
+       case SUMMARY_BUF:
+               frame = FRAME_SUMMARY;
+               break;
+       case BACKTRACE_BUF:
+               frame = FRAME_BACKTRACE;
+               break;
+       case NAME_BUF:
+               frame = FRAME_NAME;
+               break;
+       case COUNTER_BUF:
+               frame = FRAME_COUNTER;
+               break;
+       case BLOCK_COUNTER_BUF:
+               frame = FRAME_BLOCK_COUNTER;
+               break;
+       case ANNOTATE_BUF:
+               frame = FRAME_ANNOTATE;
+               break;
+       case SCHED_TRACE_BUF:
+               frame = FRAME_SCHED_TRACE;
+               break;
+       case GPU_TRACE_BUF:
+               frame = FRAME_GPU_TRACE;
+               break;
+       case IDLE_BUF:
+               frame = FRAME_IDLE;
+               break;
+       default:
+               frame = -1;
+               break;
+       }
+
+       // 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
+       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
+       gator_buffer_write_packed_int(cpu, buftype, frame);
+       gator_buffer_write_packed_int(cpu, buftype, cpu);
+}
+
+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) {
+               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
+               remaining -= 200;
+       } else {
+               // Hysteresis, prevents multiple overflow messages
+               remaining -= 2000;
+       }
+
+       return remaining;
+}
+
+static bool buffer_check_space(int cpu, int buftype, int bytes)
+{
+       int remaining = buffer_bytes_available(cpu, buftype);
+
+       if (remaining < bytes) {
+               per_cpu(buffer_space_available, cpu)[buftype] = false;
+       } else {
+               per_cpu(buffer_space_available, cpu)[buftype] = true;
+       }
+
+       return per_cpu(buffer_space_available, cpu)[buftype];
+}
+
+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;
+}
+
+static void gator_commit_buffer(int cpu, int buftype, u64 time)
+{
+       int type_length, commit, length, byte;
+       unsigned long flags;
+
+       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
+       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) {
+               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
+               local_irq_restore(flags);
+               return;
+       }
+
+       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)) {
+                       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
+       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(&gator_buffer_wake_up_timer, jiffies + 1);
+#endif
+       } else {
+               up(&gator_buffer_wake_sem);
+       }
+}
+
+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) {
+               filled += gator_buffer_size[buftype];
+       }
+       if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
+               gator_commit_buffer(cpu, buftype, time);
+       }
+}
similarity index 68%
rename from driver/gator_pack.c
rename to driver/gator_buffer_write.c
index 2c082f283adc18037964cb70c40ae03d5f0d7b3c..b621ba93ee5e452e89bd8ab32a49e11118e0c496 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -56,3 +56,25 @@ static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x)
 
        per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask;
 }
+
+static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len)
+{
+       int i;
+       u32 write = per_cpu(gator_buffer_write, cpu)[buftype];
+       u32 mask = gator_buffer_mask[buftype];
+       char *buffer = per_cpu(gator_buffer, cpu)[buftype];
+
+       for (i = 0; i < len; i++) {
+               buffer[write] = x[i];
+               write = (write + 1) & mask;
+       }
+
+       per_cpu(gator_buffer_write, cpu)[buftype] = write;
+}
+
+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);
+}
index eb9b946170c1cd57c17cfd19c305cbbe6abefe10..5c7d842070e0097325cf6b4602dcfb8688e94c50 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -30,7 +30,7 @@ static DEFINE_PER_CPU(struct cookie_args *, translate_buffer);
 
 static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq);
 static void wq_cookie_handler(struct work_struct *unused);
-DECLARE_WORK(cookie_work, wq_cookie_handler);
+static DECLARE_WORK(cookie_work, wq_cookie_handler);
 static struct timer_list app_process_wake_up_timer;
 static void app_process_wake_up_handler(unsigned long unused_data);
 
@@ -131,7 +131,9 @@ static void translate_buffer_write_args(int cpu, struct task_struct *task, const
                args = &per_cpu(translate_buffer, cpu)[write];
                args->task = task;
                args->text = text;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
                get_task_struct(task);
+#endif
                per_cpu(translate_buffer_write, cpu) = next_write;
        }
 
@@ -165,7 +167,9 @@ static void wq_cookie_handler(struct work_struct *unused)
                        translate_buffer_read_args(cpu, &args);
                        cookie = get_cookie(cpu, args.task, args.text, true);
                        marshal_link(cookie, args.task->tgid, args.task->pid);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
                        put_task_struct(args.task);
+#endif
                }
        }
 
index dd7974090b821d3e9bec339a9487ff8e864e6df6..353645622306048fbcd6f06e6af15da68a1544b0 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index 30881c8fd3fd94443d9e9781ab5c218b33939e09..153119b463e654c1cacc53633cfb412b69da9a43 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
@@ -141,9 +141,9 @@ 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, "ARM_%s_ccnt", pmnc_name);
+                       snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
                } else {
-                       snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i - 1);
+                       snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1);
                }
                dir = gatorfs_mkdir(sb, root, buf);
                if (!dir) {
@@ -275,25 +275,27 @@ int gator_events_armv7_init(void)
 
        switch (gator_cpuid()) {
        case CORTEX_A5:
-               pmnc_name = "Cortex-A5";
+               pmnc_name = "ARMv7_Cortex_A5";
                pmnc_counters = 2;
                break;
        case CORTEX_A7:
-               pmnc_name = "Cortex-A7";
+               pmnc_name = "ARMv7_Cortex_A7";
                pmnc_counters = 4;
                break;
        case CORTEX_A8:
-               pmnc_name = "Cortex-A8";
+               pmnc_name = "ARMv7_Cortex_A8";
                pmnc_counters = 4;
                break;
        case CORTEX_A9:
-               pmnc_name = "Cortex-A9";
+               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 = "Cortex-A15";
+               pmnc_name = "ARMv7_Cortex_A15";
                pmnc_counters = 6;
                break;
+       // ARM Cortex A17 is not supported by version of Linux before 3.0
        default:
                return -1;
        }
index 691ef2574536e580516c9e7057401f92bee04b6f..b2bc414e462e4df23b86e40abfa04ba55e9e974a 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index b89231967c75c75fc00bdeda5aa4fb1f9ffa9fec..024ffc2856aa0b7312ad84a89f0d680494c27bf4 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2013. All rights reserved.
+ * 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
index b11879a248f831f130a8beb8eaf976a36ef582b5..facbdd62325eccbc722a82f516ac15652a7ad860 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index ee521af22517a0f9bcf6d597ddc0618298bd248d..553f9707bdbf6161b3b0d850c6e41556d8e7a1e8 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * l2c310 (L2 Cache Controller) event counters for gator
  *
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index 6719c1ec73a2e07be50b198c1928b59c9f2e5411..85d47645a9d9e0333ab245ee246da3ce2c0cb901 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * 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
index 413ad0ffe7943170359554583ad18694f67501f9..976ca8c4cfa1af78567327951a2ab1de2b094f04 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2011-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2011-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
index 466ca1683c7e99f2baf82fd44de8073fe70ed161..dc58dcf0c6628cded90241571d3b4d31e0905372 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
index 509f9b61884a3c6620d1c2520bc12ffc6384644e..41c2a3c13fae69ccc6c6aae407951f6a5872a882 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
index 7bf7d6a6dbf9b0a09f08d61935ed297d319f6f28..76f14eee76764cda89ca2a48b26badf235b0538d 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2011-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2011-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
 #include <linux/slab.h>
 #include <asm/io.h>
 
+#ifdef MALI_DIR_MIDGARD
+/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
+#include "mali_linux_trace.h"
+#else
+/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
 #include "linux/mali_linux_trace.h"
+#endif
 
 #include "gator_events_mali_common.h"
 
index e406991398d997fbf1ac32303f0c9742696766a0..dfbc91ffd765524bebb5e4bd06109ec593c82cab 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
 #include <asm/io.h>
 
 /* Mali T6xx DDK includes */
+#ifdef MALI_DIR_MIDGARD
+/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
+#include "mali_linux_trace.h"
+#include "mali_kbase.h"
+#include "mali_kbase_mem_linux.h"
+#else
+/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
 #include "linux/mali_linux_trace.h"
 #include "kbase/src/common/mali_kbase.h"
 #include "kbase/src/linux/mali_kbase_mem_linux.h"
+#endif
 
 #include "gator_events_mali_common.h"
 
index efb32ddf5483049cb79e3fca874f86286579f3d2..ba6553f3540f4bf1ae4641534f3561a2596de99a 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2012-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2012-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
index 451290d9af1759fa5759a985a44df303b98089e4..c633dfdce3069c91ac6c19bb8b2d2ab694945dbb 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2010-2013