aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrew Richardson <drew.richardson@arm.com>2011-09-30 12:00:00 -0700
committerDrew Richardson <drew.richardson@arm.com>2014-12-19 15:16:17 -0800
commitc5f78695067d4614bcb494d5f54bde4405c43609 (patch)
tree5413ee61289c45be1917e93852d491aa1f778087
parent73158f9d05b7087bb6ff895e820017af3c94a1a6 (diff)
downloadgator-c5f78695067d4614bcb494d5f54bde4405c43609.tar.gz
gator: Version 5.75.7
Signed-off-by: Drew Richardson <drew.richardson@arm.com>
-rw-r--r--.gitignore3
-rw-r--r--README_Streamline.txt10
-rw-r--r--daemon/Android.mk32
-rw-r--r--daemon/CapturedXML.cpp97
-rw-r--r--daemon/CapturedXML.h22
-rw-r--r--daemon/Child.cpp300
-rw-r--r--daemon/Child.h35
-rw-r--r--daemon/Collector.cpp258
-rw-r--r--daemon/Collector.h38
-rw-r--r--daemon/ConfigurationXML.cpp153
-rw-r--r--daemon/ConfigurationXML.h29
-rw-r--r--daemon/Fifo.cpp104
-rw-r--r--daemon/Fifo.h41
-rw-r--r--daemon/HashMap.cpp64
-rw-r--r--daemon/HashMap.h34
-rw-r--r--daemon/LocalCapture.cpp201
-rw-r--r--daemon/LocalCapture.h27
-rw-r--r--daemon/Logging.cpp97
-rw-r--r--daemon/Logging.h47
-rw-r--r--daemon/Makefile41
-rw-r--r--daemon/OlySocket.cpp258
-rw-r--r--daemon/OlySocket.h38
-rw-r--r--daemon/OlyUtility.cpp166
-rw-r--r--daemon/OlyUtility.h35
-rw-r--r--daemon/ReadSession.cpp118
-rw-r--r--daemon/ReadSession.h40
-rw-r--r--daemon/RequestXML.cpp62
-rw-r--r--daemon/RequestXML.h33
-rw-r--r--daemon/Sender.cpp99
-rw-r--r--daemon/Sender.h36
-rw-r--r--daemon/SessionData.cpp101
-rw-r--r--daemon/SessionData.h67
-rw-r--r--daemon/StreamlineSetup.cpp319
-rw-r--r--daemon/StreamlineSetup.h46
-rw-r--r--daemon/XMLOut.cpp176
-rw-r--r--daemon/XMLOut.h45
-rw-r--r--daemon/XMLReader.cpp165
-rw-r--r--daemon/XMLReader.h27
-rw-r--r--daemon/configuration.xml39
-rw-r--r--daemon/events-ARM11.xml43
-rw-r--r--daemon/events-ARM11MPCore.xml30
-rw-r--r--daemon/events-Cortex-A15.xml77
-rw-r--r--daemon/events-Cortex-A5.xml39
-rw-r--r--daemon/events-Cortex-A8.xml58
-rw-r--r--daemon/events-Cortex-A9.xml67
-rw-r--r--daemon/events-L2C-310.xml21
-rw-r--r--daemon/events-Linux.xml16
-rw-r--r--daemon/events-Scorpion.xml113
-rw-r--r--daemon/events-ScorpionMP.xml96
-rw-r--r--daemon/events_footer.xml1
-rw-r--r--daemon/events_header.xml2
-rw-r--r--daemon/main.cpp252
-rw-r--r--driver/Makefile5
-rw-r--r--driver/gator.h12
-rw-r--r--driver/gator_annotate.c28
-rw-r--r--driver/gator_backtrace.c6
-rw-r--r--driver/gator_cookies.c40
-rw-r--r--driver/gator_ebs.c160
-rw-r--r--driver/gator_events_armv6.c40
-rw-r--r--driver/gator_events_armv7.c186
-rw-r--r--driver/gator_events_armv7.h38
-rw-r--r--driver/gator_events_l2c-310.c182
-rw-r--r--driver/gator_events_meminfo.c11
-rw-r--r--driver/gator_events_pl310.c176
-rw-r--r--driver/gator_events_scorpion.c40
-rw-r--r--driver/gator_main.c528
-rw-r--r--driver/gator_pack.c262
-rw-r--r--driver/gator_trace_sched.c228
68 files changed, 5489 insertions, 771 deletions
diff --git a/.gitignore b/.gitignore
index 2564078..e52c69a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+daemon/*.o
+daemon/events.xml
+daemon/gatord
driver/*.cmd
driver/*.mod.c
driver/*.o
diff --git a/README_Streamline.txt b/README_Streamline.txt
index 0510d71..51f8e24 100644
--- a/README_Streamline.txt
+++ b/README_Streamline.txt
@@ -41,10 +41,14 @@ Note: Configurations may not be supported on all targets
make -j5 ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- uImage
+*** Checking the gator requirements ***
+
+(optional) Use the hrtimer_module utility to validate the kernel High Resolution Timer requirement.
+
*** Building the gator module ***
To create the gator.ko module,
- cd /ds-5-install-directory/arm/gator/src
+ cd /ds-5-install-directory/arm/gator/driver-src
tar xzf gator-driver.tar.gz
cd gator-driver
make -C <kernel_build_dir> M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules
@@ -62,7 +66,7 @@ Recommended compiler settings:
*** Running gator ***
Load the kernel onto the target and copy gatord and gator.ko into the target's filesystem.
-gatord is located in <installdir>/arm/gator/.
+gatord is located in <installdir>/arm/gator/linux or <installdir>/arm/gator/android or can be built from source.
Ensure gatord has execute permissions
chmod +x gatord
gator.ko must be located in the same directory as gatord on the target.
@@ -90,4 +94,4 @@ update-rc.d rungator.sh defaults
*** GPL License ***
-For license information, please see the file LICENSE.
+For license information, please see the file LICENSE after unzipping driver-src/gator-driver.tar.gz.
diff --git a/daemon/Android.mk b/daemon/Android.mk
new file mode 100644
index 0000000..45f5b7d
--- /dev/null
+++ b/daemon/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS += -Wall -O3 -ftree-vectorize
+
+LOCAL_SRC_FILES:= \
+ CapturedXML.cpp \
+ Child.cpp \
+ Collector.cpp \
+ ConfigurationXML.cpp \
+ Fifo.cpp \
+ HashMap.cpp \
+ LocalCapture.cpp \
+ Logging.cpp \
+ main.cpp \
+ OlySocket.cpp \
+ OlyUtility.cpp \
+ ReadSession.cpp \
+ RequestXML.cpp \
+ Sender.cpp \
+ SessionData.cpp \
+ StreamlineSetup.cpp \
+ XMLOut.cpp \
+ XMLReader.cpp
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_MODULE:= gatord
+
+LOCAL_LDLIBS := -lz -llog
+
+include $(BUILD_EXECUTABLE)
diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp
new file mode 100644
index 0000000..9d9fd84
--- /dev/null
+++ b/daemon/CapturedXML.cpp
@@ -0,0 +1,97 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+typedef long long int64_t;
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include "SessionData.h"
+#include "CapturedXML.h"
+#include "Logging.h"
+#include "OlyUtility.h"
+
+extern void handleException();
+
+CapturedXML::CapturedXML() {
+}
+
+CapturedXML::~CapturedXML() {
+}
+
+const char* CapturedXML::getXML() {
+ bool perfCounters = false;
+ int x;
+
+ clearXmlString();
+ xmlHeader();
+
+ for (x=0; x<MAX_PERFORMANCE_COUNTERS; x++) {
+ if (gSessionData.mPerfCounterEnabled[x]) {
+ perfCounters = true;
+ break;
+ }
+ }
+
+ startElement("captured");
+ attributeInt("version", 1);
+ attributeInt("protocol", PROTOCOL_VERSION);
+ if (gSessionData.mBytes > 0) { // Send the following only after the capture is complete
+ if (time(NULL) > 1267000000) { // If the time is reasonable (after Feb 23, 2010)
+ attributeUInt("created", time(NULL)); // Valid until the year 2038
+ }
+ attributeUInt("bytes", gSessionData.mBytes);
+ }
+ startElement("target");
+ attributeString("name", gSessionData.mCoreName);
+ attributeInt("sample_rate", gSessionData.mSampleRate);
+ attributeInt("cores", gSessionData.mCores);
+ endElement("target");
+ if (perfCounters) {
+ startElement("counters");
+ for (x = 0; x < MAX_PERFORMANCE_COUNTERS; x++) {
+ if (gSessionData.mPerfCounterEnabled[x]) {
+ startElement("counter");
+ attributeString("title", gSessionData.mPerfCounterTitle[x]);
+ attributeString("name", gSessionData.mPerfCounterName[x]);
+ attributeHex8("color", gSessionData.mPerfCounterColor[x]);
+ attributeHex8("key", gSessionData.mPerfCounterKey[x]);
+ attributeString("type", gSessionData.mPerfCounterType[x]);
+ attributeHex8("event", gSessionData.mPerfCounterEvent[x]);
+ if (gSessionData.mPerfCounterPerCPU[x]) {
+ attributeBool("per_cpu", true);
+ }
+ if (strlen(gSessionData.mPerfCounterOperation[x]) > 0) {
+ attributeString("operation", gSessionData.mPerfCounterOperation[x]);
+ }
+ if (gSessionData.mPerfCounterCount[x] > 0) {
+ attributeInt("count", gSessionData.mPerfCounterCount[x]);
+ }
+ attributeString("description", gSessionData.mPerfCounterDescription[x]);
+ endElement("counter");
+ }
+ }
+ endElement("counters");
+ }
+ endElement("captured");
+ return getXmlString();
+}
+
+void CapturedXML::write(char* path) {
+ char file[PATH_MAX];
+
+ // Set full path
+ snprintf(file, sizeof(file), "%s/captured.xml", path);
+
+ // Write the file
+ const char* xml = getXML();
+ if (util->writeToDisk(file, xml) < 0) {
+ logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
+ handleException();
+ }
+}
diff --git a/daemon/CapturedXML.h b/daemon/CapturedXML.h
new file mode 100644
index 0000000..aafeefe
--- /dev/null
+++ b/daemon/CapturedXML.h
@@ -0,0 +1,22 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 __CAPTURED_XML_H__
+#define __CAPTURED_XML_H__
+
+#include "XMLOut.h"
+
+class CapturedXML : XMLOut {
+public:
+ CapturedXML();
+ ~CapturedXML();
+ const char* getXML();
+ void write(char* path);
+};
+
+#endif //__CAPTURED_XML_H__
diff --git a/daemon/Child.cpp b/daemon/Child.cpp
new file mode 100644
index 0000000..0abfd1a
--- /dev/null
+++ b/daemon/Child.cpp
@@ -0,0 +1,300 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/syscall.h>
+#include <sys/resource.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 "StreamlineSetup.h"
+
+static sem_t haltPipeline, senderThreadStarted, startProfile; // Shared by Child and spawned threads
+static Fifo* collectorFifo = NULL; // Shared by Child.cpp and spawned threads
+static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
+Collector* collector = NULL; // shared by Child.cpp and ConfigurationXML.cpp
+Child* child = NULL; // shared by Child.cpp and main.cpp
+
+extern void cleanUp();
+void handleException() {
+ if (child && child->numExceptions++ > 0) {
+ // it is possible one of the below functions itself can cause an exception, thus allow only one exception
+ logg->logMessage("Received multiple exceptions, terminating the child");
+ exit(1);
+ }
+ fprintf(stderr, "%s", logg->getLastError());
+
+ if (child && child->socket) {
+ if (sender) {
+ // send the error, regardless of the command sent by Streamline
+ sender->writeData(logg->getLastError(), strlen(logg->getLastError()), RESPONSE_ERROR);
+
+ // cannot close the socket before Streamline issues the command, so wait for the command before exiting
+ if (gSessionData.mWaitingOnCommand) {
+ char discard;
+ child->socket->receiveNBytes(&discard, 1);
+ }
+
+ // this indirectly calls close socket which will ensure the data has been sent
+ delete sender;
+ }
+ }
+
+ if (gSessionData.mLocalCapture)
+ cleanUp();
+
+ exit(1);
+}
+
+// CTRL C Signal Handler for child process
+void child_handler(int signum) {
+ static bool beenHere = false;
+ if (beenHere == true) {
+ logg->logMessage("Gator is being forced to shut down.");
+ exit(1);
+ }
+ beenHere = true;
+ logg->logMessage("Gator is shutting down.");
+ if (signum == SIGALRM || !collector) {
+ exit(1);
+ } else {
+ child->endSession();
+ alarm(5); // Safety net in case endSession does not complete within 5 seconds
+ }
+}
+
+void* durationThread(void* pVoid) {
+ prctl(PR_SET_NAME, (unsigned int)&"gatord-duration", 0, 0, 0);
+ sem_wait(&startProfile);
+ if (gSessionData.mSessionIsActive) {
+ // Time out after duration seconds
+ // Add a second for host-side filtering
+ sleep(gSessionData.mDuration + 1);
+ if (gSessionData.mSessionIsActive) {
+ logg->logMessage("Duration expired.");
+ child->endSession();
+ }
+ }
+ logg->logMessage("Exit duration thread");
+ return 0;
+}
+
+void* stopThread(void* pVoid) {
+ int length;
+ char type;
+ OlySocket* socket = child->socket;
+
+ prctl(PR_SET_NAME, (unsigned int)&"gatord-stopper", 0, 0, 0);
+ while (gSessionData.mSessionIsActive) {
+ // This thread will stall until the APC_STOP or PING command is received over the socket or the socket is disconnected
+ if (socket->receiveNBytes(&type, sizeof(type)) > 0) {
+ if ((type != COMMAND_APC_STOP) && (type != COMMAND_PING)) {
+ logg->logMessage("INVESTIGATE: Received unknown command type %d", type);
+ } else {
+ // verify a length of zero
+ if (socket->receiveNBytes((char*)&length, sizeof(length)) < 0) {
+ break;
+ }
+
+ if (length == 0) {
+ if (type == COMMAND_APC_STOP) {
+ logg->logMessage("Stop command received.");
+ child->endSession();
+ } else {
+ // Ping is used to make sure gator is alive and requires an ACK as the response
+ logg->logMessage("Ping command received.");
+ sender->writeData(NULL, 0, RESPONSE_ACK);
+ }
+ } else {
+ logg->logMessage("INVESTIGATE: Received stop command but with length = %d", length);
+ }
+ }
+ }
+ }
+
+ logg->logMessage("Exit stop thread");
+ return 0;
+}
+
+void* senderThread(void* pVoid) {
+ int length;
+ char* data;
+
+ sem_post(&senderThreadStarted);
+ prctl(PR_SET_NAME, (unsigned int)&"gatord-sender", 0, 0, 0);
+ sem_wait(&haltPipeline);
+
+ do {
+ data = collectorFifo->read(&length);
+ sender->writeData(data, length, RESPONSE_APC_DATA);
+ } while (length > 0);
+ logg->logMessage("Exit sender thread");
+ return 0;
+}
+
+Child::Child(char* path) {
+ initialization();
+ sessionXMLPath = path;
+}
+
+Child::Child(OlySocket* sock, int conn) {
+ initialization();
+ socket = sock;
+ numConnections = conn;
+}
+
+Child::~Child() {
+}
+
+void Child::initialization() {
+ // Set up different handlers for signals
+ gSessionData.mSessionIsActive = true;
+ signal(SIGINT, child_handler);
+ signal(SIGTERM, child_handler);
+ signal(SIGABRT, child_handler);
+ signal(SIGALRM, child_handler);
+ socket = NULL;
+ numExceptions = 0;
+ numConnections = 0;
+ sessionXMLPath = 0;
+
+ // Initialize semaphores
+ sem_init(&senderThreadStarted, 0, 0);
+ sem_init(&startProfile, 0, 0);
+}
+
+void Child::endSession() {
+ gSessionData.mSessionIsActive = false;
+ collector->stop();
+ sem_post(&haltPipeline);
+ sem_post(&haltPipeline);
+}
+
+void Child::run() {
+ char* collectBuffer;
+ int bytesCollected = 0;
+ LocalCapture* localCapture = NULL;
+
+ prctl(PR_SET_NAME, (unsigned int)&"gatord-child", 0, 0, 0);
+
+ // Instantiate the Sender - must be done first, afterwhich error messages can be sent
+ sender = new Sender(socket);
+
+ if (numConnections > 1) {
+ logg->logError(__FILE__, __LINE__, "Session already in progress");
+ handleException();
+ }
+
+ // Set up the driver
+ collector = new Collector();
+
+ // Start up and parse session xml
+ if (socket) {
+ // Respond to Streamline requests
+ StreamlineSetup ss(socket);
+ } else {
+ xmlString = util->readFromDisk(sessionXMLPath);
+ gSessionData.mLocalCapture = true;
+ if (xmlString == 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to read session xml file: %s", sessionXMLPath);
+ handleException();
+ }
+ gSessionData.parseSessionXML(xmlString);
+ localCapture = new LocalCapture();
+ localCapture->createAPCDirectory(gSessionData.target_path, gSessionData.title);
+ localCapture->copyImages(gSessionData.images);
+ localCapture->write(xmlString);
+ sender->createDataFile(gSessionData.apcDir);
+ delete xmlString;
+ }
+
+ // Create user-space buffers to pass the driver data to the socket driver
+ // Could optimize by using a zero-copy pipe/splice to copy directly from the gator driver to the socket buffer
+ int fifoBufferSize = collector->getBufferSize();
+ int numCollectorBuffers = (gSessionData.mTotalBufferSize * 1024 * 1024 + fifoBufferSize - 1) / fifoBufferSize;
+ numCollectorBuffers = (numCollectorBuffers < 4) ? 4 : numCollectorBuffers;
+ logg->logMessage("Created %d %d-byte collector buffers", numCollectorBuffers, fifoBufferSize);
+ collectorFifo = new Fifo(numCollectorBuffers, fifoBufferSize);
+
+ // Get the initial pointer to the collect buffer
+ collectBuffer = collectorFifo->start();
+
+ // Sender thread shall be halted until it is signaled for one shot mode
+ sem_init(&haltPipeline, 0, gSessionData.mOneShot ? 0 : 2);
+
+ // Create the duration, stop, and sender threads
+ bool thread_creation_success = true;
+ if (gSessionData.mDuration > 0 && pthread_create(&durationThreadID, NULL, durationThread, NULL))
+ thread_creation_success = false;
+ else if (socket && pthread_create(&stopThreadID, NULL, stopThread, NULL))
+ thread_creation_success = false;
+ else if (pthread_create(&senderThreadID, NULL, senderThread, NULL))
+ thread_creation_success = false;
+ if (!thread_creation_success) {
+ logg->logError(__FILE__, __LINE__, "Failed to create gator threads");
+ handleException();
+ }
+
+ // Wait until thread has started
+ 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) {
+ // Depth minus 1 because write() has not yet been called
+ if ((bytesCollected == -1) || (collectorFifo->numWriteToReadBuffersFilled() == collectorFifo->depth() - 1)) {
+ logg->logMessage("One shot");
+ endSession();
+ }
+ }
+ collectBuffer = collectorFifo->write(bytesCollected);
+ } while (bytesCollected > 0);
+ logg->logMessage("Exit collect data loop");
+
+ // Wait for the other threads to exit
+ pthread_join(senderThreadID, NULL);
+
+ // Shutting down the connection should break the stop thread which is stalling on the socket recv() function
+ if (socket) {
+ logg->logMessage("Waiting on stop thread");
+ socket->shutdownConnection();
+ pthread_join(stopThreadID, NULL);
+ }
+
+ // Write the captured xml file
+ if (gSessionData.mLocalCapture) {
+ CapturedXML capturedXML;
+ capturedXML.write(gSessionData.apcDir);
+ }
+
+ logg->logMessage("Profiling ended.");
+
+ delete collectorFifo;
+ delete sender;
+ delete collector;
+ delete localCapture;
+}
diff --git a/daemon/Child.h b/daemon/Child.h
new file mode 100644
index 0000000..950eb94
--- /dev/null
+++ b/daemon/Child.h
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 __CHILD_H__
+#define __CHILD_H__
+
+#include <pthread.h>
+#include "Fifo.h"
+#include "OlySocket.h"
+
+class Child {
+public:
+ Child(char* sessionXMLPath);
+ Child(OlySocket* sock, int numConnections);
+ ~Child();
+ void run();
+ OlySocket *socket;
+ void endSession();
+ int numExceptions;
+private:
+ char* xmlString;
+ char* sessionXMLPath;
+ int numConnections;
+ time_t timeStart;
+ pthread_t durationThreadID, stopThreadID, senderThreadID;
+
+ void initialization();
+};
+
+#endif //__CHILD_H__
diff --git a/daemon/Collector.cpp b/daemon/Collector.cpp
new file mode 100644
index 0000000..c413347
--- /dev/null
+++ b/daemon/Collector.cpp
@@ -0,0 +1,258 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <fcntl.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include "Collector.h"
+#include "SessionData.h"
+#include "Logging.h"
+#include "ConfigurationXML.h"
+
+extern void handleException();
+
+// Driver initialization independent of session settings
+Collector::Collector() {
+ bufferFD = 0;
+
+ checkVersion();
+
+ readIntDriver("cpu_cores", &gSessionData.mCores);
+ if (gSessionData.mCores == 0) {
+ gSessionData.mCores = 1;
+ }
+
+ if (writeDriver("buffer_size", 256*1024)) {
+ logg->logError(__FILE__, __LINE__, "Unable to set the cpu buffer settings");
+ handleException();
+ }
+
+ readIntDriver("buffer_size", &bufferSize);
+ if (bufferSize <= 0) {
+ logg->logError(__FILE__, __LINE__, "bufferSize %d is invalid", bufferSize);
+ handleException();
+ }
+
+ getCoreName();
+
+ // populate performance counter session data
+ new ConfigurationXML();
+}
+
+Collector::~Collector() {
+ // Write zero for safety, as a zero should have already been written
+ writeDriver("enable", "0");
+
+ // Calls event_buffer_release in the driver
+ if (bufferFD) {
+ close(bufferFD);
+ }
+}
+
+void Collector::enablePerfCounters() {
+ for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
+ char base[256];
+ char text[256];
+ if (!gSessionData.mPerfCounterEnabled[i]) {
+ continue;
+ }
+ snprintf(base, sizeof(base), "events/%s", gSessionData.mPerfCounterType[i]);
+ snprintf(text, sizeof(text), "%s/event", base);
+ writeDriver(text, gSessionData.mPerfCounterEvent[i]);
+ snprintf(text, sizeof(text), "%s/key", base);
+ readIntDriver(text, &gSessionData.mPerfCounterKey[i]);
+ if (gSessionData.mPerfCounterEBSCapable[i]) {
+ snprintf(text, sizeof(text), "%s/count", base);
+ if (writeReadDriver(text, &gSessionData.mPerfCounterCount[i]))
+ gSessionData.mPerfCounterCount[i] = 0;
+ if (gSessionData.mPerfCounterCount[i] > 0)
+ logg->logMessage("EBS enabled for %s with a count of %d", gSessionData.mPerfCounterName[i], gSessionData.mPerfCounterCount[i]);
+ }
+ snprintf(text, sizeof(text), "%s/enabled", base);
+ if (writeReadDriver(text, &gSessionData.mPerfCounterEnabled[i])) {
+ gSessionData.mPerfCounterEnabled[i] = 0;
+ }
+ }
+}
+
+void Collector::checkVersion() {
+ int driver_version = 0;
+
+ if (readIntDriver("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();
+ }
+ }
+}
+
+void Collector::start() {
+ // Set the maximum backtrace depth
+ if (writeReadDriver("backtrace_depth", &gSessionData.mBacktraceDepth)) {
+ logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
+ handleException();
+ }
+
+ // open the buffer which calls userspace_buffer_open() in the driver
+ char* fullpath = resolvePath("buffer");
+ bufferFD = open(fullpath, O_RDONLY);
+ if (bufferFD < 0) {
+ logg->logError(__FILE__, __LINE__, "The gator driver did not set up properly. Please view the linux console or dmesg log for more information on the failure.");
+ handleException();
+ }
+
+ // set the tick rate of the profiling timer
+ if (writeReadDriver("tick", &gSessionData.mSampleRate) != 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to set the driver tick");
+ handleException();
+ }
+
+ // set the frequency of syncing data, i.e. once per second
+ int streaming = (int)!gSessionData.mOneShot;
+ if (writeReadDriver("streaming", &streaming) != 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to set streaming");
+ handleException();
+ }
+
+ logg->logMessage("Start the driver");
+
+ // This command makes the driver start profiling by calling gator_op_start() in the driver
+ if (writeDriver("enable", "1") != 0) {
+ logg->logError(__FILE__, __LINE__, "The gator driver did not start properly. Please view the linux console or dmesg log for more information on the failure.");
+ handleException();
+ }
+
+ lseek(bufferFD, 0, SEEK_SET);
+}
+
+// These commands should cause the read() function in collect() to return
+void Collector::stop() {
+ // This will stop the driver from profiling
+ if (writeDriver("enable", "0") != 0) {
+ logg->logMessage("Stopping kernel failed");
+ }
+}
+
+int Collector::collect(char* buffer) {
+ // Calls event_buffer_read in the driver
+ int bytesRead = read(bufferFD, buffer, bufferSize);
+
+ // 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(bufferFD, buffer, bufferSize);
+ }
+
+ logg->logMessage("Driver read of %d bytes", bytesRead);
+
+ return bytesRead;
+}
+
+void Collector::getCoreName() {
+ char temp[256];
+ strncpy(gSessionData.mCoreName, "unknown", sizeof(gSessionData.mCoreName));
+
+ FILE* f = fopen("/proc/cpuinfo", "r");
+ if (f == NULL) {
+ logg->logMessage("Error opening /proc/cpuinfo\n"
+ "The core name in the captured xml file will be 'unknown'.");
+ return;
+ }
+
+ while (fgets(temp, sizeof(temp), f)) {
+ if (strlen(temp) > 0)
+ temp[strlen(temp) - 1] = 0; // Replace the line feed with a null
+
+ if (strstr(temp, "Hardware") != 0) {
+ char* position = strchr(temp, ':');
+ if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
+ logg->logMessage("Unknown format of /proc/cpuinfo\n"
+ "The core name in the captured xml file will be 'unknown'.");
+ return;
+ }
+ strncpy(gSessionData.mCoreName, (char *)((int)position + 2), sizeof(gSessionData.mCoreName));
+ fclose(f);
+ return;
+ }
+ }
+
+ logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
+ "The core name in the captured xml file will be 'unknown'.");
+ fclose(f);
+}
+
+char* Collector::resolvePath(const char* file) {
+ static char fullpath[128];
+ snprintf(fullpath, sizeof(fullpath), "/dev/gator/%s", file);
+ return fullpath;
+}
+
+int Collector::readIntDriver(const char* path, int* value) {
+ char* fullpath = resolvePath(path);
+ FILE* file = fopen(fullpath, "r");
+ if (file == NULL) {
+ return -1;
+ }
+ if (fscanf(file, "%u", value) != 1) {
+ fclose(file);
+ logg->logMessage(__FILE__, __LINE__, "Invalid value in file %s", fullpath);
+ return -1;
+ }
+ fclose(file);
+ return 0;
+}
+
+int Collector::writeDriver(const char* path, int value) {
+ char data[40];
+ snprintf(data, sizeof(data), "%d", value);
+ return writeDriver(path, data);
+}
+
+int Collector::writeDriver(const char* path, const char* data) {
+ char* fullpath = resolvePath(path);
+ int fd = open(fullpath, O_WRONLY);
+ if (fd < 0) {
+ return -1;
+ }
+ if (write(fd, data, strlen(data)) < 0) {
+ close(fd);
+ logg->logMessage("Opened but could not write to %s", fullpath);
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
+
+int Collector::writeReadDriver(const char* path, int* value) {
+ if (writeDriver(path, *value) || readIntDriver(path, value)) {
+ return -1;
+ }
+ return 0;
+}
diff --git a/daemon/Collector.h b/daemon/Collector.h
new file mode 100644
index 0000000..bcdfc23
--- /dev/null
+++ b/daemon/Collector.h
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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);
+ void enablePerfCounters();
+ int getBufferSize() {return bufferSize;}
+private:
+ int bufferSize;
+ int bufferFD;
+ char * buffer;
+
+ void checkVersion();
+ void getCoreName();
+
+ char* resolvePath(const char* file);
+ int readIntDriver(const char* path, int* value);
+ int writeDriver(const char* path, int value);
+ int writeDriver(const char* path, const char* data);
+ int writeReadDriver(const char* path, int* value);
+};
+
+#endif //__COLLECTOR_H__
diff --git a/daemon/ConfigurationXML.cpp b/daemon/ConfigurationXML.cpp
new file mode 100644
index 0000000..365d422
--- /dev/null
+++ b/daemon/ConfigurationXML.cpp
@@ -0,0 +1,153 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+typedef long long int64_t;
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include "ConfigurationXML.h"
+#include "Logging.h"
+#include "Collector.h"
+#include "OlyUtility.h"
+#include "SessionData.h"
+
+extern void handleException();
+extern Collector* collector;
+
+static const char* ATTR_COUNTER = "counter";
+static const char* ATTR_VERSION = "version";
+static const char* ATTR_TITLE = "title";
+static const char* ATTR_NAME = "name";
+static const char* ATTR_EVENT = "event";
+static const char* ATTR_COLOR = "color";
+static const char* ATTR_COUNT = "count";
+static const char* ATTR_OPERATION = "operation";
+static const char* ATTR_PER_CPU = "per_cpu";
+static const char* ATTR_DESCRIPTION = "description";
+static const char* ATTR_EBS = "event_based_sampling";
+
+ConfigurationXML::ConfigurationXML() {
+#include "configuration_xml.h"
+ char path[PATH_MAX];
+ index = 0;
+
+ if (util->getApplicationFullPath(path, sizeof(path)) != 0) {
+ logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
+ }
+ strcat(path, "configuration.xml");
+ mConfigurationXML = util->readFromDisk(path);
+
+ if (mConfigurationXML == NULL) {
+ logg->logMessage("Unable to locate configuration.xml, using default in binary");
+ // null-terminate configuration_xml
+ mConfigurationXML = (char*)malloc(configuration_xml_len + 1);
+ memcpy(mConfigurationXML, (const void*)configuration_xml, configuration_xml_len);
+ mConfigurationXML[configuration_xml_len] = 0;
+ }
+
+ gSessionData.initializeCounters();
+
+ int ret = parse(mConfigurationXML);
+ if (ret == 1) {
+ // remove configuration.xml on disk to use the default
+ if (remove(path) != 0) {
+ logg->logError(__FILE__, __LINE__, "Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk");
+ handleException();
+ }
+ } else if (ret < 0 || isValid() == false) {
+ logg->logError(__FILE__, __LINE__, "Parsing of the configuration.xml file failed. Please verify configuration.xml on the target filesystem is valid or delete it to use the default.");
+ handleException();
+ }
+
+ collector->enablePerfCounters();
+}
+
+ConfigurationXML::~ConfigurationXML() {
+ if (mConfigurationXML) {
+ free((void*)mConfigurationXML);
+ }
+}
+
+int ConfigurationXML::parse(const char* configurationXML) {
+ int ret = 0;
+ XMLReader reader(configurationXML);
+ char * tag = reader.nextTag();
+ while(tag != 0 && ret == 0) {
+ if (strcmp(tag, "configurations") == 0) {
+ ret = configurationsTag(&reader);
+ } else if (strcmp(tag, "configuration") == 0) {
+ ret = configurationTag(&reader);
+ }
+ tag = reader.nextTag();
+ }
+
+ return ret;
+}
+
+bool ConfigurationXML::isValid(void) {
+ for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
+ if (gSessionData.mPerfCounterEnabled[i]) {
+ if (strcmp(gSessionData.mPerfCounterType[i], "") == 0 ||
+ strcmp(gSessionData.mPerfCounterTitle[i], "") == 0 ||
+ strcmp(gSessionData.mPerfCounterName[i], "") == 0) {
+ logg->logMessage("Invalid required attribute\n counter=\"%s\"\n title=\"%s\"\n name=\"%s\"\n event=%d\n", gSessionData.mPerfCounterType[i], gSessionData.mPerfCounterTitle[i], gSessionData.mPerfCounterName[i], gSessionData.mPerfCounterEvent[i]);
+ return false; // failure
+ }
+
+ // iterate through the remaining enabled performance counters
+ for (int j = i + 1; j < MAX_PERFORMANCE_COUNTERS; j++) {
+ if (gSessionData.mPerfCounterEnabled[j]) {
+ // check if the type or device are the same
+ if (strcmp(gSessionData.mPerfCounterType[i], gSessionData.mPerfCounterType[j]) == 0) {
+ logg->logMessage("Duplicate performance counter type: %s", gSessionData.mPerfCounterType[i]);
+ return false; // failure
+ }
+ }
+ }
+ }
+ }
+
+ return true; // success
+}
+
+#define CONFIGURATION_VERSION 1
+int ConfigurationXML::configurationsTag(XMLReader *in) {
+ int version = in->getAttributeAsInteger(ATTR_VERSION, 0);
+ if (version != CONFIGURATION_VERSION) {
+ logg->logMessage("Incompatible configuration.xml version (%d) detected. The version needs to be %d.", version, CONFIGURATION_VERSION);
+ return 1; // version issue
+ }
+ return 0;
+}
+
+int ConfigurationXML::configurationTag(XMLReader* in) {
+ // handle all other performance counters
+ if (index >= MAX_PERFORMANCE_COUNTERS) {
+ logg->logMessage("Invalid performance counter index: %d", index);
+ return -1; // failure
+ }
+
+ // read attributes
+ in->getAttribute(ATTR_COUNTER, gSessionData.mPerfCounterType[index], sizeof(gSessionData.mPerfCounterType[index]), "");
+ in->getAttribute(ATTR_TITLE, gSessionData.mPerfCounterTitle[index], sizeof(gSessionData.mPerfCounterTitle[index]), "");
+ in->getAttribute(ATTR_NAME, gSessionData.mPerfCounterName[index], sizeof(gSessionData.mPerfCounterName[index]), "");
+ in->getAttribute(ATTR_DESCRIPTION, gSessionData.mPerfCounterDescription[index], sizeof(gSessionData.mPerfCounterDescription[index]), "");
+ gSessionData.mPerfCounterEvent[index] = in->getAttributeAsInteger(ATTR_EVENT, 0);
+ gSessionData.mPerfCounterCount[index] = in->getAttributeAsInteger(ATTR_COUNT, 0);
+ gSessionData.mPerfCounterColor[index] = in->getAttributeAsInteger(ATTR_COLOR, 0);
+ gSessionData.mPerfCounterPerCPU[index] = in->getAttributeAsBoolean(ATTR_PER_CPU, false);
+ gSessionData.mPerfCounterEBSCapable[index] = in->getAttributeAsBoolean(ATTR_EBS, false);
+ in->getAttribute(ATTR_OPERATION, gSessionData.mPerfCounterOperation[index], sizeof(gSessionData.mPerfCounterOperation[index]), "");
+ gSessionData.mPerfCounterEnabled[index] = true;
+
+ // update counter index
+ index++;
+
+ return 0; // success
+}
diff --git a/daemon/ConfigurationXML.h b/daemon/ConfigurationXML.h
new file mode 100644
index 0000000..57a426e
--- /dev/null
+++ b/daemon/ConfigurationXML.h
@@ -0,0 +1,29 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 COUNTERS_H
+#define COUNTERS_H
+
+#include "XMLReader.h"
+
+class ConfigurationXML {
+public:
+ ConfigurationXML();
+ ~ConfigurationXML();
+ const char* getConfigurationXML() {return mConfigurationXML;}
+private:
+ char* mConfigurationXML;
+
+ int parse(const char* xmlFile);
+ bool isValid(void);
+ int configurationsTag(XMLReader *in);
+ int configurationTag(XMLReader* in);
+ int index;
+};
+
+#endif // COUNTERS_H
diff --git a/daemon/Fifo.cpp b/daemon/Fifo.cpp
new file mode 100644
index 0000000..bbc43a7
--- /dev/null
+++ b/daemon/Fifo.cpp
@@ -0,0 +1,104 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "Fifo.h"
+#include "Logging.h"
+
+extern void handleException();
+
+Fifo::Fifo(int numBuffers, int bufferSize) {
+ int which;
+
+ if (numBuffers > FIFO_BUFFER_LIMIT) {
+ logg->logError(__FILE__, __LINE__, "Number of fifo buffers exceeds maximum");
+ handleException();
+ }
+ mNumBuffers = numBuffers;
+ mBufferSize = bufferSize;
+ mWriteCurrent = 0;
+ mReadCurrent = mNumBuffers - 1; // (n-1) pipelined
+
+ for (which=0; which<mNumBuffers; which++) {
+ // initialized read-to-write sem to 1, so that first wait goes through; write-to-read init'd to 0
+ if (sem_init(&mReadToWriteSem[which], 0, 1) ||
+ sem_init(&mWriteToReadSem[which], 0, 0)) {
+ logg->logError(__FILE__, __LINE__, "sem_init(%d) failed", which);
+ handleException();
+ }
+ // page-align allocate buffers
+ mBuffer[which] = (char*)valloc(bufferSize);
+ if (mBuffer[which] == NULL) {
+ logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize);
+ handleException();
+ }
+ // touch each page to fault it in
+ for (int i=0; i<bufferSize; i+= getpagesize()) {
+ *mBuffer[which] = 0;
+ }
+ }
+}
+
+Fifo::~Fifo() {
+ for (int which=0; which<mNumBuffers; which++) {
+ if (mBuffer[which] != NULL) {
+ free(mBuffer[which]);
+ mBuffer[which] = NULL;
+ }
+ }
+}
+
+int Fifo::depth(void) {
+ return mNumBuffers;
+}
+
+int Fifo::numReadToWriteBuffersFilled() {
+ int value;
+ int numFilled = 0;
+ for (int which=0; which<mNumBuffers; which++) {
+ if (sem_getvalue(&mReadToWriteSem[which], &value) == 0) numFilled += value;
+ }
+ return numFilled;
+}
+
+int Fifo::numWriteToReadBuffersFilled() {
+ int value;
+ int numFilled = 0;
+ for (int which=0; which<mNumBuffers; which++) {
+ if (sem_getvalue(&mWriteToReadSem[which], &value) == 0) numFilled += value;
+ }
+ return numFilled;
+}
+
+char* Fifo::start() {
+ sem_wait(&mReadToWriteSem[mWriteCurrent]);
+ return mBuffer[mWriteCurrent];
+}
+
+char* Fifo::write(int length) {
+ mLength[mWriteCurrent] = length;
+ sem_post(&mWriteToReadSem[mWriteCurrent]);
+ mWriteCurrent = (mWriteCurrent + 1) % mNumBuffers;
+ sem_wait(&mReadToWriteSem[mWriteCurrent]);
+ return mBuffer[mWriteCurrent];
+}
+
+char* Fifo::read(int* length) {
+ static bool firstTime = true;
+ if (!firstTime) {
+ sem_post(&mReadToWriteSem[mReadCurrent]);
+ }
+ firstTime = false;
+ mReadCurrent = (mReadCurrent + 1) % mNumBuffers;
+ sem_wait(&mWriteToReadSem[mReadCurrent]);
+ *length = mLength[mReadCurrent];
+ return mBuffer[mReadCurrent];
+}
diff --git a/daemon/Fifo.h b/daemon/Fifo.h
new file mode 100644
index 0000000..02372d5
--- /dev/null
+++ b/daemon/Fifo.h
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 __FIFO_H__
+#define __FIFO_H__
+
+#include <semaphore.h>
+
+// Driver buffer size is 512k, large buffer mode with 2GB of total RAM will allocate 256M
+#define FIFO_BUFFER_LIMIT 256*1024/512
+
+class Fifo {
+public:
+ Fifo(int numBuffers, int bufferSize);
+ ~Fifo();
+ int depth(void);
+ int numReadToWriteBuffersFilled();
+ int numWriteToReadBuffersFilled();
+ int numReadToWriteBuffersEmpty() {return depth() - numReadToWriteBuffersFilled();}
+ int numWriteToReadBuffersEmpty() {return depth() - numWriteToReadBuffersFilled();}
+ char* start();
+ char* write(int length);
+ char* read(int* length);
+
+private:
+ int mNumBuffers;
+ int mBufferSize;
+ int mWriteCurrent;
+ int mReadCurrent;
+ sem_t mReadToWriteSem[FIFO_BUFFER_LIMIT];
+ sem_t mWriteToReadSem[FIFO_BUFFER_LIMIT];
+ char* mBuffer[FIFO_BUFFER_LIMIT];
+ int mLength[FIFO_BUFFER_LIMIT];
+};
+
+#endif //__FIFO_H__
diff --git a/daemon/HashMap.cpp b/daemon/HashMap.cpp
new file mode 100644
index 0000000..1ff6e31
--- /dev/null
+++ b/daemon/HashMap.cpp
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 "HashMap.h"
+
+/*
+ * LRU Lossy HashMap
+ * Values are always inserted to first slot
+ * Value hits are moved to the first slot
+ */
+
+HashMap::HashMap() {
+ history = (int*)calloc(HASHMAP_ENTRIES * MAX_COLLISIONS, sizeof(int));
+}
+
+HashMap::~HashMap() {
+ free(history);
+}
+
+int *HashMap::hashEntries(int value) {
+ int hashCode = (value >> 24) & 0xff;
+ hashCode = hashCode * 31 + ((value >> 16) & 0xff);
+ hashCode = hashCode * 31 + ((value >> 8) & 0xff);
+ hashCode = hashCode * 31 + ((value >> 0) & 0xff);
+ hashCode &= (HASHMAP_ENTRIES-1);
+ return &history[hashCode * MAX_COLLISIONS];
+}
+
+/*
+ * Exists
+ * Pre: [0][1][v][3]..[n-1]
+ * Post: [v][0][1][3]..[n-1]
+ * Add
+ * Pre: [0][1][2][3]..[n-1]
+ * Post: [v][0][1][2]..[n-2]
+ */
+bool HashMap::existsAdd(int value) {
+ int *line = hashEntries(value);
+
+ /* exists */
+ for (int x = 0; x < MAX_COLLISIONS; x++) {
+ if (line[x] == value) {
+ for (; x > 0; x--) {
+ line[x] = line[x-1];
+ }
+ line[0] = value;
+ return true;
+ }
+ }
+
+ /* add */
+ for (int x = MAX_COLLISIONS-1; x > 0; x--) {
+ line[x] = line[x-1];
+ }
+ line[0] = value;
+
+ return false;
+}
diff --git a/daemon/HashMap.h b/daemon/HashMap.h
new file mode 100644
index 0000000..3831f03
--- /dev/null
+++ b/daemon/HashMap.h
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 __HASH_MAP_H__
+#define __HASH_MAP_H__
+
+/**********************************
+This class is a limited and lossy hash map, where each hash table bucket will contain at most MAX_COLLISIONS entries
+If the limit is exceeded, one of the old entries is dropped from the table
+This limit eliminates the need for dynamic memory allocation
+It is efficient with a data set containing a lot of use-only-once data
+Zero is used as an invalid (unused) hash entry value
+**********************************/
+
+#define HASHMAP_ENTRIES 1024 /* must be power of 2 */
+#define MAX_COLLISIONS 2
+
+class HashMap {
+public:
+ HashMap();
+ ~HashMap();
+ bool existsAdd(int value);
+private:
+ int *hashEntries(int key);
+ int *history;
+};
+
+#endif //__HASH_MAP_H__
diff --git a/daemon/LocalCapture.cpp b/daemon/LocalCapture.cpp
new file mode 100644
index 0000000..9927035
--- /dev/null
+++ b/daemon/LocalCapture.cpp
@@ -0,0 +1,201 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+typedef long long int64_t;
+#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"
+
+extern void handleException();
+
+LocalCapture::LocalCapture() {}
+
+LocalCapture::~LocalCapture() {}
+
+void LocalCapture::createAPCDirectory(char* target_path, char* name) {
+ gSessionData.apcDir = createUniqueDirectory(target_path, ".apc", name);
+ if ((removeDirAndAllContents(gSessionData.apcDir) != 0 || mkdir(gSessionData.apcDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)) {
+ logg->logError(__FILE__, __LINE__, "Unable to create directory %s", gSessionData.apcDir);
+ handleException();
+ }
+}
+
+void LocalCapture::write(char* string) {
+ char file[PATH_MAX];
+
+ // Set full path
+ snprintf(file, sizeof(file), "%s/session.xml", gSessionData.apcDir);
+
+ // Write the file
+ if (util->writeToDisk(file, string) < 0) {
+ logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
+ handleException();
+ }
+}
+
+char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* ending, char* title) {
+ int i;
+ char path[PATH_MAX];
+
+ // Ensure the path is an absolute path, i.e. starts with a slash
+ if (initialPath == 0 || strlen(initialPath) == 0) {
+ if (getcwd(path, sizeof(path)) == 0)
+ logg->logMessage("Unable to retrive the current working directory");
+ strncat(path, "/@F_@N", sizeof(path) - strlen(path) - 1);
+ } else if (initialPath[0] != '/') {
+ if (getcwd(path, sizeof(path)) == 0)
+ logg->logMessage("Unable to retrive the current working directory");
+ strncat(path, "/", sizeof(path) - strlen(path) - 1);
+ strncat(path, initialPath, sizeof(path) - strlen(path) - 1);
+ } else {
+ strncpy(path, initialPath, sizeof(path));
+ }
+
+ // Convert to uppercase
+ replaceAll(path, "@f", "@F", sizeof(path));
+ replaceAll(path, "@n", "@N", sizeof(path));
+
+ // Replace @F with the session xml title
+ replaceAll(path, "@F", title, sizeof(path));
+
+ // Add ending if it is not already there
+ if (strcmp(&path[strlen(path) - strlen(ending)], ending) != 0) {
+ strncat(path, ending, sizeof(path) - strlen(path) - 1);
+ }
+
+ // Replace @N with a unique integer
+ if (strstr(path, "@N")) {
+ char tempPath[PATH_MAX];
+ for (i = 1; i < 1000; i++) {
+ char number[4];
+ snprintf(number, sizeof(number), "%03d", i);
+ strncpy(tempPath, path, sizeof(tempPath));
+ replaceAll(tempPath, "@N", number, sizeof(tempPath));
+ struct stat mFileInfo;
+ if (stat(tempPath, &mFileInfo) != 0) {
+ // if the direcotry does not exist, break
+ break;
+ }
+ }
+
+ if (i == 1000) {
+ logg->logError(__FILE__, __LINE__, "Unable to create .apc directory, please delete older directories.");
+ handleException();
+ }
+
+ strncpy(path, tempPath, sizeof(path));
+ }
+
+ char* output = strdup(path);
+ return output;
+}
+
+//Replaces all occurrences of <find> in <target> with <replace> provided enough <size> is available
+void LocalCapture::replaceAll(char* target, const char* find, const char* replace, unsigned int size) {
+ char* nextOccurrence;
+ unsigned int count = 0;
+
+ // Duplicate the original string
+ char* original = strdup(target);
+ char* ptr = original;
+
+ // Determine number of <find>s
+ ptr = strstr(ptr, find);
+ while (ptr) {
+ count++;
+ ptr += strlen(find);
+ ptr = strstr(ptr, find);
+ }
+
+ // Is there enough space available
+ if (strlen(target) + (strlen(replace) - strlen(find)) * count > size - 1) {
+ free(original);
+ return;
+ }
+
+ // Reset
+ ptr = original;
+
+ nextOccurrence = strstr(ptr, find);
+ while (nextOccurrence) {
+ // Move pointers to location of replace
+ int length = nextOccurrence - ptr;
+ target += length;
+ ptr += length;
+
+ // Replace <find> with <replace>
+ memcpy(target, replace, strlen(replace));
+
+ // Increment over <replace>/<find>
+ target += strlen(replace);
+ ptr += strlen(find);
+
+ // Copy remainder of ptr
+ strcpy(target, ptr);
+
+ // Get next occurrence
+ nextOccurrence = strstr(ptr, find);
+ }
+
+ free(original);
+}
+
+int LocalCapture::removeDirAndAllContents(char *path) {
+ int error = 0;
+ struct stat mFileInfo;
+ // Does the path exist?
+ if (stat(path, &mFileInfo) == 0) {
+ // Is it a directory?
+ if (mFileInfo.st_mode & S_IFDIR) {
+ DIR * dir = opendir(path);
+ dirent* entry = readdir(dir);
+ while (entry) {
+ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
+ char* newpath = (char*)malloc(strlen(path) + strlen(entry->d_name) + 2);
+ sprintf(newpath, "%s/%s", path, entry->d_name);
+ error = removeDirAndAllContents(newpath);
+ free(newpath);
+ if (error) break;
+ }
+ entry = readdir(dir);
+ }
+ closedir(dir);
+ if (error == 0) {
+ error = rmdir(path);
+ }
+ } else {
+ error = remove(path);
+ }
+ }
+ return error;
+}
+
+void LocalCapture::copyImages(ImageLinkList* ptr) {
+ char dstfilename[PATH_MAX];
+
+ while (ptr) {
+ strncpy(dstfilename, gSessionData.apcDir, sizeof(dstfilename));
+ if (gSessionData.apcDir[strlen(gSessionData.apcDir) - 1] != '/')
+ strncat(dstfilename, "/", sizeof(dstfilename));
+ strncat(dstfilename, util->getFilePart(ptr->path), sizeof(dstfilename) - strlen(dstfilename) - 1);
+ if (util->copyFile(ptr->path, dstfilename))
+ logg->logMessage("copied file %s to %s", ptr->path, dstfilename);
+ else
+ logg->logMessage("copy of file %s to %s failed", ptr->path, dstfilename);
+
+ ptr = ptr->next;
+ }
+}
diff --git a/daemon/LocalCapture.h b/daemon/LocalCapture.h
new file mode 100644
index 0000000..f2db593
--- /dev/null
+++ b/daemon/LocalCapture.h
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 __LOCAL_CAPTURE_H__
+#define __LOCAL_CAPTURE_H__
+
+#include "ReadSession.h"
+
+class LocalCapture {
+public:
+ LocalCapture();
+ ~LocalCapture();
+ void write(char *string);
+ void copyImages(ImageLinkList* ptr);
+ void createAPCDirectory(char* target_path, char* name);
+private:
+ char* createUniqueDirectory(const char* path, const char* ending, char* title);
+ void replaceAll(char* target, const char* find, const char* replace, unsigned int size);
+ int removeDirAndAllContents(char *path);
+};
+
+#endif //__LOCAL_CAPTURE_H__
diff --git a/daemon/Logging.cpp b/daemon/Logging.cpp
new file mode 100644
index 0000000..972a83f
--- /dev/null
+++ b/daemon/Logging.cpp
@@ -0,0 +1,97 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include "OlyUtility.h"
+
+#ifdef WIN32
+#define MUTEX_INIT() mLoggingMutex = CreateMutex(NULL, false, NULL);
+#define MUTEX_LOCK() WaitForSingleObject(mLoggingMutex, 0xFFFFFFFF);
+#define MUTEX_UNLOCK() ReleaseMutex(mLoggingMutex);
+#define snprintf _snprintf
+#else
+#include <pthread.h>
+#define MUTEX_INIT() pthread_mutex_init(&mLoggingMutex, NULL)
+#define MUTEX_LOCK() pthread_mutex_lock(&mLoggingMutex)
+#define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex)
+#endif
+
+#include "Logging.h"
+
+// Global thread-safe logging
+Logging* logg = NULL;
+
+Logging::Logging(bool debug) {
+ mFileCreated = false;
+ mWarningXMLPath[0] = 0;
+ mDebug = debug;
+ MUTEX_INIT();
+
+ strcpy(mErrBuf, "Unknown Error");
+ strcpy(mLogBuf, "Unknown Message");
+}
+
+Logging::~Logging() {
+ if (mFileCreated) {
+ util->appendToDisk(mWarningXMLPath, "</warnings>");
+ }
+}
+
+void Logging::logError(const char* file, int line, const char* fmt, ...) {
+ va_list args;
+
+ MUTEX_LOCK();
+ if (mDebug) {
+ snprintf(mErrBuf, sizeof(mErrBuf), "ERROR[%s:%d]: ", file, line);
+ } else {
+ mErrBuf[0] = 0;
+ }
+
+ va_start(args, fmt);
+ vsnprintf(mErrBuf + strlen(mErrBuf), sizeof(mErrBuf) - 2 - strlen(mErrBuf), fmt, args); // subtract 2 for \n and \0
+ va_end(args);
+
+ // Add the message to the warning file if the warning file was created
+ if (mWarningXMLPath[0] != 0) {
+ if (!mFileCreated) {
+ if (util->writeToDisk(mWarningXMLPath, "<?xml version=\"1.0\" encoding='UTF-8'?>\n<warnings version=\"1\">\n") < 0) {
+ return;
+ }
+ mFileCreated = true;
+ }
+ util->appendToDisk(mWarningXMLPath, " <warning text=\"");
+ util->appendToDisk(mWarningXMLPath, mErrBuf);
+ util->appendToDisk(mWarningXMLPath, "\"/>\n");
+ }
+ if (strlen(mErrBuf) > 0) {
+ strcat(mErrBuf, "\n");
+ }
+ MUTEX_UNLOCK();
+}
+
+void Logging::logMessage(const char* fmt, ...) {
+ if (mDebug) {
+ va_list args;
+
+ MUTEX_LOCK();
+ strcpy(mLogBuf, "INFO: ");
+
+ va_start(args, fmt);
+ vsnprintf(mLogBuf + strlen(mLogBuf), sizeof(mLogBuf) - 2 - strlen(mLogBuf), fmt, args); // subtract 2 for \n and \0
+ va_end(args);
+ strcat(mLogBuf, "\n");
+
+ fprintf(stdout, "%s", mLogBuf);
+ fflush(stdout);
+ MUTEX_UNLOCK();
+ }
+}
diff --git a/daemon/Logging.h b/daemon/Logging.h
new file mode 100644
index 0000000..4579f7c
--- /dev/null
+++ b/daemon/Logging.h
@@ -0,0 +1,47 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 __LOGGING_H__
+#define __LOGGING_H__
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+
+#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"
+
+class Logging {
+public:
+ Logging(bool debug);
+ ~Logging();
+ void logError(const char* file, int line, const char* fmt, ...);
+ void logMessage(const char* fmt, ...);
+ void SetWarningFile(char* path) {strncpy(mWarningXMLPath, path, sizeof(mWarningXMLPath) - 1);}
+ char* getLastError() {return mErrBuf;}
+ char* getLastMessage() {return mLogBuf;}
+
+private:
+ char mWarningXMLPath[4096];
+ char mErrBuf[4096];
+ char mLogBuf[4096];
+ bool mDebug;
+ bool mFileCreated;
+#ifdef WIN32
+ HANDLE mLoggingMutex;
+#else
+ pthread_mutex_t mLoggingMutex;
+#endif
+};
+
+extern Logging* logg;
+
+#endif //__LOGGING_H__
diff --git a/daemon/Makefile b/daemon/Makefile
new file mode 100644
index 0000000..2ccc886
--- /dev/null
+++ b/daemon/Makefile
@@ -0,0 +1,41 @@
+#
+# Makefile for ARM Streamline - Gator Daemon
+#
+
+# Uncomment and define CROSS_COMPILE if it is not already defined
+# CROSS_COMPILE=/path/to/cross-compiler/arm-none-linux-gnueabi-
+ARCH=arm
+
+CPP=$(CROSS_COMPILE)g++
+
+# -g produces debugging information
+# -O3 maximum optimization
+# -O0 no optimization, used for debugging
+# -Wall enables most warnings
+# -Werror treats warnings as errors
+# -std=c++0x is the planned new c++ standard
+# -std=c++98 is the 1998 c++ standard
+# -march=armv5t is required to set the minimum architecture
+# -mthumb-interwork is required for interworking to ARM or Thumb stdlibc
+CFLAGS=-O3 -Wall -Werror -march=armv5t -mthumb-interwork
+TARGET=gatord
+CPP_SRC = $(wildcard *.cpp) $(wildcard ../../reptilia/*.cpp)
+TGT_OBJS = $(CPP_SRC:%.cpp=%.o)
+INCLUDES = -I../../reptilia
+
+all: $(TARGET)
+
+%.o: %.cpp *.h
+ $(CPP) $(INCLUDES) -c $(CFLAGS) -o $@ $<
+
+$(TARGET): convert $(TGT_OBJS)
+ $(CPP) -s -o $@ $(TGT_OBJS) -lc -lrt
+ rm events_xml.h configuration_xml.h
+
+convert:
+ cat events_header.xml events-*\.xml events_footer.xml > events.xml
+ xxd -i events.xml > events_xml.h
+ xxd -i configuration.xml > configuration_xml.h
+
+clean:
+ rm -f *.o $(TARGET) events.xml events_xml.h configuration_xml.h ../../reptilia/*.o
diff --git a/daemon/OlySocket.cpp b/daemon/OlySocket.cpp
new file mode 100644
index 0000000..d95210c
--- /dev/null
+++ b/daemon/OlySocket.cpp
@@ -0,0 +1,258 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <stdio.h>
+#ifdef WIN32
+#include <Winsock2.h>
+#else
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include "OlySocket.h"
+#include "Logging.h"
+
+#ifdef WIN32
+#define CLOSE_SOCKET(x) closesocket(x)
+#define SHUTDOWN_RX_TX SD_BOTH
+#define snprintf _snprintf
+#else
+#define CLOSE_SOCKET(x) close(x)
+#define SHUTDOWN_RX_TX SHUT_RDWR
+#endif
+
+extern void handleException();
+
+OlySocket::OlySocket(int port, bool multiple) {
+#ifdef WIN32
+ WSADATA wsaData;
+ if (WSAStartup(0x0202, &wsaData) != 0) {
+ logg->logError(__FILE__, __LINE__, "Windows socket initialization failed");
+ handleException();
+ }
+#endif
+
+ if (multiple) {
+ createServerSocket(port);
+ } else {
+ createSingleServerConnection(port);
+ }
+}
+
+// Implement client socket for windows
+/*OlySocket::OlySocket(int port, char* host) {
+ fdServer = 0;
+ createClientSocket(host, port);
+}*/
+
+OlySocket::~OlySocket() {
+ if (mSocketID > 0) {
+ CLOSE_SOCKET(mSocketID);
+ }
+}
+
+void OlySocket::shutdownConnection() {
+ // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions
+ shutdown(mSocketID, SHUTDOWN_RX_TX);
+}
+
+void OlySocket::closeSocket() {
+ // Used for closing an accepted socket but keeping the server socket active
+ if (mSocketID > 0) {
+ CLOSE_SOCKET(mSocketID);
+ mSocketID = -1;
+ }
+}
+
+void OlySocket::closeServerSocket() {
+ if (CLOSE_SOCKET(fdServer) != 0) {
+ logg->logError(__FILE__, __LINE__, "Failed to close server socket.");
+ handleException();
+ }
+ fdServer = 0;
+}
+
+// Implement for windows
+/*
+void OlySocket::createClientSocket(char* hostname, int portno) {
+ char buf[32];
+ struct addrinfo hints, *res, *res0;
+
+ snprintf(buf, sizeof(buf), "%d", portno);
+ mSocketID = -1;
+ memset((void*)&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if (getaddrinfo(hostname, buf, &hints, &res0)) {
+ logg->logError(__FILE__, __LINE__, "Client socket failed to get address info for %s", hostname);
+ handleException();
+ }
+ for (res=res0; res!=NULL; res = res->ai_next) {
+ if ( res->ai_family != PF_INET || res->ai_socktype != SOCK_STREAM )
+ continue;
+ mSocketID = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (mSocketID < 0) {
+ continue;
+ }
+ if (connect(mSocketID, res->ai_addr, res->ai_addrlen) < 0) {
+ close(mSocketID);
+ mSocketID = -1;
+ }
+ if (mSocketID > 0) break;
+ }
+ freeaddrinfo(res0);
+ if (mSocketID <= 0) {
+ logg->logError(__FILE__, __LINE__, "Could not connect to client socket. Ensure ARM Streamline is running.");
+ handleException();
+ }
+}
+*/
+
+void OlySocket::createSingleServerConnection(int port) {
+ createServerSocket(port);
+
+ mSocketID = acceptConnection();
+ closeServerSocket();
+}
+
+void OlySocket::createServerSocket(int port) {
+ // Create socket
+ fdServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fdServer < 0) {
+ logg->logError(__FILE__, __LINE__, "Error creating server socket");
+ handleException();
+ }
+
+ // Enable address reuse, another solution would be to create the server socket once and only close it when the object exits
+ int on = 1;
+ if (setsockopt(fdServer, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)) != 0) {
+ logg->logError(__FILE__, __LINE__, "Setting server socket options failed");
+ handleException();
+ }
+
+ // Create sockaddr_in structure, ensuring non-populated fields are zero
+ struct sockaddr_in sockaddr;
+ memset((void*)&sockaddr, 0, sizeof(struct sockaddr_in));
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_port = htons(port);
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+
+ // Bind the socket to an address
+ if (bind(fdServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
+ logg->logError(__FILE__, __LINE__, "Binding of server socket failed.\nIs an instance already running?");
+ handleException();
+ }
+
+ // Listen for connections on this socket
+ if (listen(fdServer, 1) < 0) {
+ logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
+ handleException();
+ }
+}
+
+// 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() {
+ if (fdServer <= 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(fdServer, NULL, NULL);
+ if (mSocketID < 0) {
+ logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
+ handleException();
+ }
+ return mSocketID;
+}
+
+void OlySocket::send(char* buffer, int size) {
+ if (size <= 0 || buffer == NULL) {
+ return;
+ }
+
+ while (size > 0) {
+ int n = ::send(mSocketID, buffer, size, 0);
+ if (n < 0) {
+ logg->logError(__FILE__, __LINE__, "Socket send error");
+ handleException();
+ }
+ size -= n;
+ buffer += n;
+ }
+}
+
+// Returns the number of bytes received
+int OlySocket::receive(char* buffer, int size) {
+ if (size <= 0 || buffer == NULL) {
+ return 0;
+ }
+
+ int bytes = recv(mSocketID, buffer, size, 0);
+ if (bytes < 0) {
+ logg->logError(__FILE__, __LINE__, "Socket receive error");
+ handleException();
+ } else if (bytes == 0) {
+ logg->logMessage("Socket disconnected");
+ return -1;
+ }
+ return bytes;
+}
+
+// Receive exactly size bytes of data. Note, this function will block until all bytes are received
+int OlySocket::receiveNBytes(char* buffer, int size) {
+ int bytes = 0;
+ while (size > 0 && buffer != NULL) {
+ bytes = recv(mSocketID, buffer, size, 0);
+ if (bytes < 0) {
+ logg->logError(__FILE__, __LINE__, "Socket receive error");
+ handleException();
+ } else if (bytes == 0) {
+ logg->logMessage("Socket disconnected");
+ return -1;
+ }
+ buffer += bytes;
+ size -= bytes;
+ }
+ return bytes;
+}
+
+// Receive data until a carriage return, line feed, or null is encountered, or the buffer fills
+int OlySocket::receiveString(char* buffer, int size) {
+ int bytes_received = 0;
+ bool found = false;
+
+ if (buffer == 0)
+ return 0;
+
+ while (!found && bytes_received < size) {
+ // Receive a single character
+ int bytes = recv(mSocketID, &buffer[bytes_received], 1, 0);
+ if (bytes < 0) {
+ logg->logError(__FILE__, __LINE__, "Socket receive error");
+ handleException();
+ } else if (bytes == 0) {
+ logg->logMessage("Socket disconnected");
+ return -1;
+ }
+
+ // Replace carriage returns and line feeds with zero
+ if (buffer[bytes_received] == '\n' || buffer[bytes_received] == '\r' || buffer[bytes_received] == '\0') {
+ buffer[bytes_received] = '\0';
+ found = true;
+ }
+
+ bytes_received++;
+ }
+
+ return bytes_received;
+}
diff --git a/daemon/OlySocket.h b/daemon/OlySocket.h
new file mode 100644
index 0000000..5e110aa
--- /dev/null
+++ b/daemon/OlySocket.h
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 __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 acceptConnection();
+ void closeSocket();
+ void closeServerSocket();
+ void shutdownConnection();
+ void send(char* buffer, int size);
+ void sendString(const char* string) {send((char*)string, strlen(string));}
+ int receive(char* buffer, int size);
+ int receiveNBytes(char* buffer, int size);
+ int receiveString(char* buffer, int size);
+ char* getLastError() {return strError;}
+ int getSocketID() {return mSocketID;}
+private:
+ char* strError;
+ int mSocketID, fdServer;
+ // void createClientSocket(char* hostname, int port);
+ void createSingleServerConnection(int port);
+ void createServerSocket(int port);
+};
+
+#endif //__OLY_SOCKET_H__
diff --git a/daemon/OlyUtility.cpp b/daemon/OlyUtility.cpp
new file mode 100644
index 0000000..5c3bfcc
--- /dev/null
+++ b/daemon/OlyUtility.cpp
@@ -0,0 +1,166 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <Windows.h>
+#endif
+
+#include "OlyUtility.h"
+
+OlyUtility* util = NULL;
+
+void OlyUtility::stringToLower(char* string) {
+ if (string == NULL)
+ return;
+
+ while (*string) {
+ *string = tolower(*string);
+ string++;
+ }
+}
+
+// Modifies fullpath with the path part including the trailing path separator
+int OlyUtility::getApplicationFullPath(char* fullpath, int sizeOfPath) {
+ memset(fullpath, 0, sizeOfPath);
+#ifdef WIN32
+ int length = GetModuleFileName(NULL, fullpath, sizeOfPath);
+#else
+ int length = readlink("/proc/self/exe", fullpath, sizeOfPath);
+#endif
+
+ if (length == sizeOfPath)
+ return -1;
+
+ fullpath[length] = 0;
+ fullpath = getPathPart(fullpath);
+
+ return 0;
+}
+
+char* OlyUtility::readFromDisk(const char* file, unsigned int *size, bool appendNull) {
+ // Open the file
+ FILE* pFile = fopen(file, "rb");
+ if (pFile==NULL) return NULL;
+
+ // Obtain file size
+ fseek(pFile , 0 , SEEK_END);
+ unsigned int lSize = ftell(pFile);
+ rewind(pFile);
+
+ // Allocate memory to contain the whole file
+ char* buffer = (char*)malloc(lSize + (int)appendNull);
+ if (buffer == NULL) return NULL;
+
+ // Copy the file into the buffer
+ if (fread(buffer, 1, lSize, pFile) != lSize) return NULL;
+
+ // Terminate
+ fclose(pFile);
+
+ if (appendNull)
+ buffer[lSize] = 0;
+
+ if (size)
+ *size = lSize;
+
+ return buffer;
+}
+
+int OlyUtility::writeToDisk(const char* path, const char* data) {
+ // Open the file
+ FILE* pFile = fopen(path, "wb");
+ if (pFile == NULL) return -1;
+
+ // Write the data to disk
+ if (fwrite(data, 1, strlen(data), pFile) != strlen(data)) return -1;
+
+ // Terminate
+ fclose(pFile);
+ return 0;
+}
+
+int OlyUtility::appendToDisk(const char* path, const char* data) {
+ // Open the file
+ FILE* pFile = fopen(path, "a");
+ if (pFile == NULL) return -1;
+
+ // Write the data to disk
+ if (fwrite(data, 1, strlen(data), pFile) != strlen(data)) return -1;
+
+ // Terminate
+ fclose(pFile);
+ return 0;
+}
+
+/**
+ * Copies the srcFile into dstFile in 1kB chunks.
+ * The dstFile will be overwritten if it exists.
+ * 0 is returned on an error; otherwise 1.
+ */
+int OlyUtility::copyFile(const char * srcFile, const char * dstFile) {
+ char buffer[1024];
+ FILE * f_src = fopen(srcFile,"rb");
+ if (!f_src) {
+ return 0;
+ }
+ FILE * f_dst = fopen(dstFile,"wb");
+ if (!f_dst) {
+ fclose(f_src);
+ return 0;
+ }
+ while (!feof(f_src)) {
+ int num_bytes_read = fread(buffer, 1, sizeof(buffer), f_src);
+ if (num_bytes_read < (int)sizeof(buffer) && !feof(f_src)) {
+ fclose(f_src);
+ fclose(f_dst);
+ return 0;
+ }
+ int num_bytes_written = fwrite(buffer, 1, num_bytes_read, f_dst);
+ if (num_bytes_written != num_bytes_read) {
+ fclose(f_src);
+ fclose(f_dst);
+ return 0;
+ }
+ }
+ fclose(f_src);
+ fclose(f_dst);
+ return 1;
+}
+
+const char* OlyUtility::getFilePart(const char* path) {
+ const char* last_sep = strrchr(path, PATH_SEPARATOR);
+
+ // in case path is not a full path
+ if (last_sep == NULL) {
+ return path;
+ }
+
+ return (const char*)((int)last_sep + 1);
+}
+
+// getPathPart may modify the contents of path
+// returns the path including the trailing path separator
+char* OlyUtility::getPathPart(char* path) {
+ char* last_sep = strrchr(path, PATH_SEPARATOR);
+
+ // in case path is not a full path
+ if (last_sep == NULL) {
+ return 0;
+ }
+ *(char*)((int)last_sep + 1) = 0;
+
+ return (path);
+}
diff --git a/daemon/OlyUtility.h b/daemon/OlyUtility.h
new file mode 100644
index 0000000..e516c01
--- /dev/null
+++ b/daemon/OlyUtility.h
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 OLY_UTILITY_H
+#define OLY_UTILITY_H
+
+#ifdef WIN32
+#define PATH_SEPARATOR '\\'
+#else
+#define PATH_SEPARATOR '/'
+#endif
+
+class OlyUtility {
+public:
+ OlyUtility() {};
+ ~OlyUtility() {};
+ void stringToLower(char* string);
+ int getApplicationFullPath(char* path, int sizeOfPath);
+ char* readFromDisk(const char* file, unsigned int *size = NULL, bool appendNull = true);
+ int writeToDisk(const char* path, const char* file);
+ int appendToDisk(const char* path, const char* file);
+ int copyFile(const char * srcFile, const char * dstFile);
+ const char* getFilePart(const char* path);
+ char* getPathPart(char* path);
+private:
+};
+
+extern OlyUtility* util;
+
+#endif // OLY_UTILITY_H
diff --git a/daemon/ReadSession.cpp b/daemon/ReadSession.cpp
new file mode 100644
index 0000000..1aaf4d8
--- /dev/null
+++ b/daemon/ReadSession.cpp
@@ -0,0 +1,118 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "ReadSession.h"
+#include "Logging.h"
+
+extern void handleException();
+
+static const char* TAG_SESSION = "session";
+static const char* TAG_IMAGE = "image";
+
+static const char* ATTR_VERSION = "version";
+static const char* ATTR_TITLE = "title";
+static const char* ATTR_UUID = "uuid";
+static const char* ATTR_CALL_STACK_UNWINDING = "call_stack_unwinding";
+static const char* ATTR_BUFFER_MODE = "buffer_mode";
+static const char* ATTR_SAMPLE_RATE = "sample_rate";
+static const char* ATTR_TARGET_PATH = "target_path";
+static const char* ATTR_OUTPUT_PATH = "output_path";
+static const char* ATTR_DURATION = "duration";
+static const char* ATTR_PATH = "path";
+
+ReadSession::ReadSession(const char * str) {
+ parameters.title = 0;
+ parameters.uuid[0] = 0;
+ parameters.target_path = 0;
+ parameters.output_path = 0;
+ parameters.buffer_mode[0] = 0;
+ parameters.sample_rate[0] = 0;
+ parameters.duration = 0;
+ parameters.call_stack_unwinding = false;
+ parameters.images = NULL;
+ mPath = 0;
+ mSessionXML = (char*)str;
+ logg->logMessage(mSessionXML);
+}
+
+ReadSession::~ReadSession() {
+ if (mPath != 0) {
+ free(mSessionXML);
+ }
+}
+
+void ReadSession::parse() {
+ XMLReader reader(mSessionXML);
+ char * tag = reader.nextTag();
+ while(tag != 0) {
+ if (strcmp(tag, TAG_SESSION) == 0) {
+ sessionTag(&reader);
+ return;
+ }
+ tag = reader.nextTag();
+ }
+
+ logg->logError(__FILE__, __LINE__, "No session tag found in the session.xml file");
+ handleException();
+}
+
+void ReadSession::sessionTag(XMLReader* in) {
+ char tempBuffer[PATH_MAX];
+ int version = in->getAttributeAsInteger(ATTR_VERSION, 0);
+ if (version != 1) {
+ logg->logError(__FILE__, __LINE__, "Invalid session.xml version: %d", version);
+ handleException();
+ }
+
+ in->getAttribute(ATTR_TITLE, tempBuffer, sizeof(tempBuffer), "unnamed");
+ parameters.title = strdup(tempBuffer); // freed when the child process exits
+ if (parameters.title == NULL) {
+ logg->logError(__FILE__, __LINE__, "failed to allocate parameters.title (%d bytes)", strlen(tempBuffer));
+ handleException();
+ }
+ in->getAttribute(ATTR_UUID, parameters.uuid, sizeof(parameters.uuid), "");
+ parameters.duration = in->getAttributeAsInteger(ATTR_DURATION, 0);
+ parameters.call_stack_unwinding = in->getAttributeAsBoolean(ATTR_CALL_STACK_UNWINDING, true);
+ in->getAttribute(ATTR_BUFFER_MODE, parameters.buffer_mode, sizeof(parameters.buffer_mode), "normal");
+ in->getAttribute(ATTR_SAMPLE_RATE, parameters.sample_rate, sizeof(parameters.sample_rate), "");
+ in->getAttribute(ATTR_TARGET_PATH, tempBuffer, sizeof(tempBuffer), "");
+ parameters.target_path = strdup(tempBuffer); // freed when the child process exits
+ if (parameters.target_path == NULL) {
+ logg->logError(__FILE__, __LINE__, "failed to allocate parameters.target_path (%d bytes)", strlen(tempBuffer));
+ handleException();
+ }
+ in->getAttribute(ATTR_OUTPUT_PATH, tempBuffer, sizeof(tempBuffer), "");
+ parameters.output_path = strdup(tempBuffer); // freed when the child process exits
+ if (parameters.output_path == NULL) {
+ logg->logError(__FILE__, __LINE__, "failed to allocate parameters.output_path (%d bytes)", strlen(tempBuffer));
+ handleException();
+ }
+
+ char * tag = in->nextTag();
+ while(tag != 0) {
+ if (strcmp(tag, TAG_IMAGE) == 0) {
+ sessionImage(in);
+ }
+ tag = in->nextTag();
+ }
+}
+
+void ReadSession::sessionImage(XMLReader* in) {
+ int length = in->getAttributeLength(ATTR_PATH);
+ struct ImageLinkList *image;
+
+ image = (struct ImageLinkList *)malloc(sizeof(struct ImageLinkList));
+ image->path = (char *)malloc(length + 1);
+ in->getAttribute(ATTR_PATH, image->path, length + 1, "");
+ image->next = parameters.images;
+ parameters.images = image;
+}
diff --git a/daemon/ReadSession.h b/daemon/ReadSession.h
new file mode 100644
index 0000000..b2e3eae
--- /dev/null
+++ b/daemon/ReadSession.h
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 READ_SESSION_H
+#define READ_SESSION_H
+
+#include "XMLReader.h"
+#include "SessionData.h"
+
+struct ConfigParameters {
+ char* title; // status title
+ char uuid[64]; // universal unique identifier
+ char* target_path; // target path of where to write to disk
+ char* output_path; // host path of where to write to disk
+ char buffer_mode[64]; // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size
+ char sample_rate[64]; // capture mode, "high", "normal", or "low"
+ int duration; // length of profile in seconds
+ bool call_stack_unwinding; // whether stack unwinding is performed
+ struct ImageLinkList *images; // linked list of image strings
+};
+
+class ReadSession {
+public:
+ ReadSession(const char * str);
+ ~ReadSession();
+ void parse();
+ ConfigParameters parameters;
+private:
+ char* mSessionXML;
+ char* mPath;
+ void sessionTag(XMLReader* in);
+ void sessionImage(XMLReader* in);
+};
+
+#endif // READ_SESSION_H
diff --git a/daemon/RequestXML.cpp b/daemon/RequestXML.cpp
new file mode 100644
index 0000000..cdc1e8e
--- /dev/null
+++ b/daemon/RequestXML.cpp
@@ -0,0 +1,62 @@
+/**
+ * Copyright (C) ARM Limited 2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "RequestXML.h"
+#include "Logging.h"
+
+extern void handleException();
+
+static const char* TAG_REQUEST = "request";
+
+static const char* ATTR_PROTOCOL = "protocol";
+static const char* ATTR_EVENTS = "events";
+static const char* ATTR_CONFIGURATION = "configuration";
+static const char* ATTR_COUNTERS = "counters";
+static const char* ATTR_SESSION = "session";
+static const char* ATTR_CAPTURED = "captured";
+static const char* ATTR_DEFAULTS = "defaults";
+
+RequestXML::RequestXML(const char * str) {
+ parameters.protocol = false;
+ parameters.events = false;
+ parameters.configuration = false;
+ parameters.counters = false;
+ parameters.session = false;
+ parameters.captured = false;
+ parameters.defaults = false;
+
+ XMLReader reader(str);
+ char * tag = reader.nextTag();
+ while(tag != 0) {
+ if (strcmp(tag, TAG_REQUEST) == 0) {
+ requestTag(&reader);
+ return;
+ }
+ tag = reader.nextTag();
+ }
+
+ logg->logError(__FILE__, __LINE__, "No request tag found in the request.xml file");
+ handleException();
+}
+
+RequestXML::~RequestXML() {
+}
+
+void RequestXML::requestTag(XMLReader* in) {
+ parameters.protocol = in->getAttributeAsBoolean(ATTR_PROTOCOL, false);
+ parameters.events = in->getAttributeAsBoolean(ATTR_EVENTS, false);
+ parameters.configuration = in->getAttributeAsBoolean(ATTR_CONFIGURATION, false);
+ parameters.counters = in->getAttributeAsBoolean(ATTR_COUNTERS, false);
+ parameters.session = in->getAttributeAsBoolean(ATTR_SESSION, false);
+ parameters.captured = in->getAttributeAsBoolean(ATTR_CAPTURED, false);
+ parameters.defaults = in->getAttributeAsBoolean(ATTR_DEFAULTS, false);
+}
diff --git a/daemon/RequestXML.h b/daemon/RequestXML.h
new file mode 100644
index 0000000..eff242e
--- /dev/null
+++ b/daemon/RequestXML.h
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 REQUEST_XML_H
+#define REQUEST_XML_H
+
+#include "XMLReader.h"
+
+struct ConfigParameters {
+ bool protocol;
+ bool events;
+ bool configuration;
+ bool counters;
+ bool session;
+ bool captured;
+ bool defaults;
+};
+
+class RequestXML {
+public:
+ RequestXML(const char * str);
+ ~RequestXML();
+ ConfigParameters parameters;
+private:
+ void requestTag(XMLReader* in);
+};
+
+#endif // REQUEST_XML_H
diff --git a/daemon/Sender.cpp b/daemon/Sender.cpp
new file mode 100644
index 0000000..547d425
--- /dev/null
+++ b/daemon/Sender.cpp
@@ -0,0 +1,99 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "Sender.h"
+#include "Logging.h"
+#include "SessionData.h"
+
+extern void handleException();
+
+Sender::Sender(OlySocket* socket) {
+ dataFile = NULL;
+
+ // Set up the socket connection
+ if (socket) {
+ char streamline[64] = {0};
+ dataSocket = socket;
+
+ // Receive magic sequence - can wait forever
+ // Streamline will send data prior to the magic sequence for legacy support, which should be ignored for v4+
+ while (strcmp("STREAMLINE", streamline) != 0) {
+ if (dataSocket->receiveString(streamline, sizeof(streamline)) == -1) {
+ logg->logError(__FILE__, __LINE__, "Socket disconnected");
+ handleException();
+ }
+ }
+
+ // Send magic sequence - must be done first, afterwhich error messages can be sent
+ char magic[] = {'G', 'A', 'T', 'O', 'R', '\n'};
+ dataSocket->send(magic, sizeof(magic));
+
+ gSessionData.mWaitingOnCommand = true;
+ logg->logMessage("Completed magic sequence");
+ }
+}
+
+Sender::~Sender() {
+ delete dataSocket;
+ dataSocket = NULL;
+ if (dataFile) {
+ fclose(dataFile);
+ }
+}
+
+void Sender::createDataFile(char* apcDir) {
+ if (apcDir == NULL)
+ return;
+
+ dataFileName = (char*)malloc(strlen(apcDir) + 12);
+ sprintf(dataFileName, "%s/0000000000", apcDir);
+ dataFile = fopen(dataFileName, "wb");
+ if (!dataFile) {
+ logg->logError(__FILE__, __LINE__, "Failed to open binary file: %s", dataFileName);
+ handleException();
+ }
+}
+
+void Sender::writeData(const char* data, int length, int type) {
+ if (length < 0 || (data == NULL && length > 0)) {
+ return;
+ }
+
+ // Send data over the socket connection
+ if (dataSocket) {
+ // Start alarm
+ alarm(5);
+
+ // Send data over the socket, sending the type and size first
+ logg->logMessage("Sending data with length %d", length);
+ dataSocket->send((char*)&type, 1);
+ dataSocket->send((char*)&length, sizeof(length));
+ dataSocket->send((char*)data, length);
+
+ // Stop alarm
+ alarm(0);
+ }
+
+ // Write data to disk as long as it is not meta data
+ if (dataFile && type == RESPONSE_APC_DATA) {
+ logg->logMessage("Writing data with length %d", length);
+ // Send data to the data file, storing the size first
+ if ((fwrite((char*)&length, 1, sizeof(length), dataFile) != sizeof(length)) || (fwrite(data, 1, length, dataFile) != (unsigned int)length)) {
+ logg->logError(__FILE__, __LINE__, "Failed writing binary file %s", dataFileName);
+ handleException();
+ }
+ }
+}
diff --git a/daemon/Sender.h b/daemon/Sender.h
new file mode 100644
index 0000000..9584c10
--- /dev/null
+++ b/daemon/Sender.h
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 __SENDER_H__
+#define __SENDER_H__
+
+#include <stdio.h>
+#include "OlySocket.h"
+
+enum {
+ RESPONSE_END = 0, // unused
+ RESPONSE_XML = 1,
+ RESPONSE_APC_DATA = 3,
+ RESPONSE_ACK = 4,
+ RESPONSE_NAK = 5,
+ RESPONSE_ERROR = 0xFF
+};
+
+class Sender {
+public:
+ Sender(OlySocket* socket);
+ ~Sender();
+ void writeData(const char* data, int length, int type);
+ void createDataFile(char* apcDir);
+private:
+ OlySocket* dataSocket;
+ FILE* dataFile;
+ char* dataFileName;
+};
+
+#endif //__SENDER_H__
diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp
new file mode 100644
index 0000000..0672804
--- /dev/null
+++ b/daemon/SessionData.cpp
@@ -0,0 +1,101 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <string.h>
+#include "SessionData.h"
+#include "ReadSession.h"
+#include "Logging.h"
+extern void handleException();
+
+SessionData gSessionData;
+
+SessionData::SessionData() {
+ initialize();
+}
+
+SessionData::~SessionData() {
+}
+
+void SessionData::initialize() {
+ mWaitingOnCommand = false;
+ mSessionIsActive = false;
+ mLocalCapture = false;
+ mOneShot = false;
+ strcpy(mCoreName, "unknown");
+ apcDir = NULL;
+ mSampleRate = 0;
+ mDuration = 0;
+ mBytes = 0;
+ mBacktraceDepth = 0;
+ mTotalBufferSize = 0;
+ mCores = 1;
+}
+
+void SessionData::initializeCounters() {
+ // PMU Counters
+ for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
+ mPerfCounterType[i][0] = 0;
+ mPerfCounterTitle[i][0] = 0;
+ mPerfCounterName[i][0] = 0;
+ mPerfCounterDescription[i][0] = 0;
+ mPerfCounterEnabled[i] = 0;
+ mPerfCounterEvent[i] = 0;
+ mPerfCounterColor[i] = 0;
+ mPerfCounterKey[i] = 0;
+ mPerfCounterCount[i] = 0;
+ mPerfCounterOperation[i][0] = 0;
+ mPerfCounterPerCPU[i] = false;
+ mPerfCounterEBSCapable[i] = false;
+ }
+}
+
+void SessionData::parseSessionXML(char* xmlString) {
+ ReadSession session(xmlString);
+ session.parse();
+
+ // Parameter error checking
+ if (session.parameters.output_path == 0 && session.parameters.target_path == 0) {
+ logg->logError(__FILE__, __LINE__, "No capture path (target or host) was provided.");
+ handleException();
+ } else if (gSessionData.mLocalCapture && session.parameters.target_path == 0) {
+ logg->logError(__FILE__, __LINE__, "Missing target_path tag in session xml required for a local capture.");
+ handleException();
+ }
+
+ // Set session data values
+ if (strcmp(session.parameters.sample_rate, "high") == 0) {
+ gSessionData.mSampleRate = 10000;
+ } else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
+ gSessionData.mSampleRate = 1000;
+ } else { // "low"
+ gSessionData.mSampleRate = 100;
+ }
+ gSessionData.mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0;
+ gSessionData.mDuration = session.parameters.duration;
+
+ // Determine buffer size (in MB) based on buffer mode
+ gSessionData.mOneShot = true;
+ if (strcmp(session.parameters.buffer_mode, "streaming") == 0) {
+ gSessionData.mOneShot = false;
+ gSessionData.mTotalBufferSize = 1;
+ } else if (strcmp(session.parameters.buffer_mode, "small") == 0) {
+ gSessionData.mTotalBufferSize = 1;
+ } else if (strcmp(session.parameters.buffer_mode, "normal") == 0) {
+ gSessionData.mTotalBufferSize = 4;
+ } else if (strcmp(session.parameters.buffer_mode, "large") == 0) {
+ gSessionData.mTotalBufferSize = 16;
+ } else {
+ logg->logError(__FILE__, __LINE__, "Invalid value for buffer mode in session xml.");
+ handleException();
+ }
+
+ gSessionData.images = session.parameters.images;
+ gSessionData.target_path = session.parameters.target_path;
+ gSessionData.title = session.parameters.title;
+}
diff --git a/daemon/SessionData.h b/daemon/SessionData.h
new file mode 100644
index 0000000..7e8ce3c
--- /dev/null
+++ b/daemon/SessionData.h
@@ -0,0 +1,67 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 SESSION_DATA_H
+#define SESSION_DATA_H
+
+#define MAX_PERFORMANCE_COUNTERS 50
+#define MAX_STRING_LEN 80
+#define MAX_DESCRIPTION_LEN 400
+
+#define PROTOCOL_VERSION 6
+#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions
+
+struct ImageLinkList {
+ char *path;
+ struct ImageLinkList *next;
+};
+
+class SessionData {
+public:
+ SessionData();
+ ~SessionData();
+ void initialize();
+ void initializeCounters();
+ void parseSessionXML(char* xmlString);
+
+ char mCoreName[MAX_STRING_LEN];
+ struct ImageLinkList *images;
+ char* target_path;
+ char* apcDir;
+ char* title;
+
+ bool mWaitingOnCommand;
+ bool mSessionIsActive;
+ bool mLocalCapture;
+ bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled
+
+ int mBacktraceDepth;
+ int mTotalBufferSize; // approximate number of MB to use for the entire collection buffer, the actual amount is a multiple based on a buffer size retrieved from the driver
+ int mSampleRate;
+ int mDuration;
+ int mCores;
+ int mBytes;
+
+ // PMU Counters
+ char mPerfCounterType[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
+ char mPerfCounterTitle[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
+ char mPerfCounterName[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
+ char mPerfCounterDescription[MAX_PERFORMANCE_COUNTERS][MAX_DESCRIPTION_LEN];
+ int mPerfCounterEnabled[MAX_PERFORMANCE_COUNTERS];
+ int mPerfCounterEvent[MAX_PERFORMANCE_COUNTERS];
+ int mPerfCounterColor[MAX_PERFORMANCE_COUNTERS];
+ int mPerfCounterCount[MAX_PERFORMANCE_COUNTERS];
+ int mPerfCounterKey[MAX_PERFORMANCE_COUNTERS];
+ bool mPerfCounterPerCPU[MAX_PERFORMANCE_COUNTERS];
+ bool mPerfCounterEBSCapable[MAX_PERFORMANCE_COUNTERS];
+ char mPerfCounterOperation[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
+};
+
+extern SessionData gSessionData;
+
+#endif // SESSION_DATA_H
diff --git a/daemon/StreamlineSetup.cpp b/daemon/StreamlineSetup.cpp
new file mode 100644
index 0000000..8473f8f
--- /dev/null
+++ b/daemon/StreamlineSetup.cpp
@@ -0,0 +1,319 @@
+/**
+ * Copyright (C) ARM Limited 2011. 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.
+ */
+
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "XMLOut.h"
+#include "Sender.h"
+#include "Logging.h"
+#include "XMLReader.h"
+#include "RequestXML.h"
+#include "OlyUtility.h"
+#include "SessionData.h"
+#include "CapturedXML.h"
+#include "StreamlineSetup.h"
+#include "ConfigurationXML.h"
+
+extern void handleException();
+
+static const char* TAG_SESSION = "session";
+static const char* TAG_CONFIGURATIONS = "configurations";
+
+StreamlineSetup::StreamlineSetup(OlySocket* s) {
+ bool ready = false;
+ char *data = NULL;
+ int type;
+
+ socket = s;
+ mSessionXML = NULL;
+
+ // Receive commands from Streamline (master)
+ while (!ready) {
+ // receive command over socket
+ gSessionData.mWaitingOnCommand = true;
+ data = readCommand(&type);
+
+ // parse and handle data
+ switch (type) {
+ case COMMAND_REQUEST_XML:
+ handleRequest(data);
+ break;
+ case COMMAND_DELIVER_XML:
+ handleDeliver(data);
+ break;
+ case COMMAND_APC_START:
+ logg->logMessage("Received apc start request");
+ ready = true;
+ break;
+ case COMMAND_APC_STOP:
+ // Clear error log so no text appears on console and exit
+ logg->logMessage("Received apc stop request before apc start request");
+ logg->logError(__FILE__, __LINE__, "");
+ handleException();
+ break;
+ case COMMAND_DISCONNECT:
+ // Clear error log so no text appears on console and exit
+ logg->logMessage("Received disconnect command");
+ logg->logError(__FILE__, __LINE__, "");
+ handleException();
+ break;
+ case COMMAND_PING:
+ logg->logMessage("Received ping command");
+ sendData(NULL, 0, RESPONSE_ACK);
+ break;
+ default:
+ logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type);
+ handleException();
+ }
+
+ delete(data);
+ }
+}
+
+StreamlineSetup::~StreamlineSetup() {
+ if (mSessionXML)
+ free(mSessionXML);
+}
+
+char* StreamlineSetup::readCommand(int* command) {
+ char type;
+ char* data;
+ int response, length;
+
+ // receive type
+ response = socket->receiveNBytes(&type, sizeof(type));
+
+ // After receiving a single byte, we are no longer waiting on a command
+ gSessionData.mWaitingOnCommand = false;
+
+ if (response < 0) {
+ logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
+ handleException();
+ }
+
+ // receive length
+ response = socket->receiveNBytes((char*)&length, sizeof(length));
+ if (response < 0) {
+ logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
+ handleException();
+ }
+
+ // add artificial limit
+ if ((length < 0) || length > 1024 * 1024) {
+ logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length);
+ handleException();
+ }
+
+ // allocate memory to contain the xml file, size of zero returns a zero size object
+ data = (char*)calloc(length + 1, 1);
+ if (data == NULL) {
+ logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml");
+ handleException();
+ }
+
+ // receive data
+ response = socket->receiveNBytes(data, length);
+ if (response < 0) {
+ logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
+ handleException();
+ }
+
+ // null terminate the data for string parsing
+ if (length > 0) {
+ data[length] = 0;
+ }
+
+ *command = type;
+ return data;
+}
+
+void StreamlineSetup::handleRequest(char* xml) {
+ RequestXML request(xml);
+
+ if (request.parameters.protocol) {
+ sendProtocol();
+ logg->logMessage("Sent protocol xml response");
+ } else if (request.parameters.events) {
+ sendEvents();
+ logg->logMessage("Sent events xml response");
+ } else if (request.parameters.configuration) {
+ sendConfiguration();
+ logg->logMessage("Sent configuration xml response");
+ } else if (request.parameters.counters) {
+ sendCounters();
+ logg->logMessage("Sent counters xml response");
+ } else if (request.parameters.session) {
+ sendData(mSessionXML, strlen(mSessionXML), RESPONSE_XML);
+ logg->logMessage("Sent session xml response");
+ } else if (request.parameters.captured) {
+ CapturedXML capturedXML;
+ const char* capturedText = capturedXML.getXML();
+ sendData(capturedText, strlen(capturedText), RESPONSE_XML);
+ logg->logMessage("Sent captured xml response");
+ } else if (request.parameters.defaults) {
+ sendDefaults();
+ logg->logMessage("Sent default configuration xml response");
+ } else {
+ char error[] = "Unknown request";
+ sendData(error, strlen(error), RESPONSE_NAK);
+ logg->logMessage("Received unknown request:\n%s", xml);
+ }
+}
+
+typedef enum {UNKNOWN, SESSION_XML, CONFIGURATION_XML} delivery_type_t;
+void StreamlineSetup::handleDeliver(char* xml) {
+ delivery_type_t type = UNKNOWN;
+
+ // Determine xml type
+ XMLReader reader(xml);
+ char * tag = reader.nextTag();
+ while(tag != 0) {
+ if (strcmp(tag, TAG_SESSION) == 0) {
+ type = SESSION_XML;
+ break;
+ } else if (strcmp(tag, TAG_CONFIGURATIONS) == 0) {
+ type = CONFIGURATION_XML;
+ break;
+ }
+ tag = reader.nextTag();
+ }
+
+ switch (type) {
+ case UNKNOWN:
+ logg->logMessage("Received unknown delivery type: %d", type);
+ sendData(NULL, 0, RESPONSE_NAK);
+ break;
+ case SESSION_XML:
+ // Parse the session xml
+ gSessionData.parseSessionXML(xml);
+
+ // Save xml
+ mSessionXML = strdup(xml);
+ if (mSessionXML == NULL) {
+ logg->logError(__FILE__, __LINE__, "malloc failed for size %d", strlen(xml) + 1);
+ handleException();
+ }
+ sendData(NULL, 0, RESPONSE_ACK);
+ logg->logMessage("Received session xml");
+ break;
+ case CONFIGURATION_XML:
+ writeConfiguration(xml);
+ sendData(NULL, 0, RESPONSE_ACK);
+ logg->logMessage("Received configuration xml");
+ break;
+ }
+}
+
+void StreamlineSetup::sendData(const char* data, int length, int type) {
+ socket->send((char*)&type, 1);
+ socket->send((char*)&length, sizeof(length));
+ socket->send((char*)data, length);
+}
+
+void StreamlineSetup::sendProtocol() {
+ XMLOut out;
+ out.xmlHeader();
+
+ out.startElement("protocol");
+ out.attributeInt("version", PROTOCOL_VERSION);
+ out.endElement("protocol");
+
+ sendString(out.getXmlString(), RESPONSE_XML);
+}
+
+void StreamlineSetup::sendEvents() {
+#include "events_xml.h"
+ char path[PATH_MAX];
+ char * buffer;
+ unsigned int size = 0;
+
+ util->getApplicationFullPath(path, sizeof(path));
+ strncat(path, "events.xml", sizeof(path) - strlen(path) - 1);
+ buffer = util->readFromDisk(path, &size);
+ if (buffer == NULL) {
+ logg->logMessage("Unable to locate events.xml, using default");
+ buffer = (char*)events_xml;
+ size = events_xml_len;
+ }
+
+ sendData(buffer, size, RESPONSE_XML);
+ if (buffer != (char*)events_xml) {
+ free(buffer);
+ }
+}
+
+void StreamlineSetup::sendConfiguration() {
+ ConfigurationXML xml;
+
+ const char* string = xml.getConfigurationXML();
+ sendData(string, strlen(string), RESPONSE_XML);
+}
+
+void StreamlineSetup::sendDefaults() {
+#include "configuration_xml.h"
+ // Send the config built into the binary
+ char* xml = (char*)configuration_xml;
+ unsigned int size = configuration_xml_len;
+
+ // Artificial size restriction
+ if (size > 1024*1024) {
+ logg->logError(__FILE__, __LINE__, "Corrupt default configuration file");
+ handleException();
+ }
+
+ sendData(xml, size, RESPONSE_XML);
+}
+
+#include <dirent.h>
+void StreamlineSetup::sendCounters() {
+ XMLOut out;
+ struct dirent *ent;
+
+ // 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();
+ }
+
+ out.xmlHeader();
+ out.startElement("counters");
+ while ((ent = readdir(dir)) != NULL) {
+ // skip hidden files, current dir, and parent dir
+ if (ent->d_name[0] == '.')
+ continue;
+ out.startElement("counter");
+ out.attributeString("name", ent->d_name);
+ out.endElement("counter");
+ }
+ out.endElement("counters");
+ closedir (dir);
+
+ sendString(out.getXmlString(), RESPONSE_XML);
+}
+
+void StreamlineSetup::writeConfiguration(char* xml) {
+ char path[PATH_MAX];
+
+ util->getApplicationFullPath(path, sizeof(path));
+ strncat(path, "configuration.xml", sizeof(path) - strlen(path) - 1);
+ if (util->writeToDisk(path, xml) < 0) {
+ logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", path);
+ handleException();
+ }
+
+ new ConfigurationXML();
+}
diff --git a/daemon/StreamlineSetup.h b/daemon/StreamlineSetup.h
new file mode 100644
index 0000000..c090afb
--- /dev/null
+++ b/daemon/StreamlineSetup.h
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 __STREAMLINE_SETUP_H__
+#define __STREAMLINE_SETUP_H__
+
+#include "OlySocket.h"
+
+// Commands from Streamline
+enum {
+ COMMAND_REQUEST_XML = 0,
+ COMMAND_DELIVER_XML = 1,
+ COMMAND_APC_START = 2,
+ COMMAND_APC_STOP = 3,
+ COMMAND_DISCONNECT = 4,
+ COMMAND_PING = 5
+};
+
+class StreamlineSetup {
+public:
+ StreamlineSetup(OlySocket *socket);
+ ~StreamlineSetup();
+private:
+ int numConnections;
+ OlySocket* socket;
+ char* mSessionXML;
+
+ char* readCommand(int*);
+ void handleRequest(char* xml);
+ void handleDeliver(char* xml);
+ void sendData(const char* data, int length, int type);
+ void sendString(const char* string, int type) {sendData(string, strlen(string), type);}
+ void sendProtocol();
+ void sendEvents();
+ void sendConfiguration();
+ void sendDefaults();
+ void sendCounters();
+ void writeConfiguration(char* xml);
+};
+
+#endif //__STREAMLINE_SETUP_H__
diff --git a/daemon/XMLOut.cpp b/daemon/XMLOut.cpp
new file mode 100644
index 0000000..540f103
--- /dev/null
+++ b/daemon/XMLOut.cpp
@@ -0,0 +1,176 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include "XMLOut.h"
+
+XMLOut::XMLOut() {
+ indent = 0;
+ incomplete = false;
+ xml_string[0] = 0;
+}
+
+XMLOut::~XMLOut() {
+}
+
+void XMLOut::writeTabs() {
+ for (int i = 0; i < indent; i++) {
+ writeData(" ");
+ }
+}
+
+void XMLOut::encodeAttributeData(const char* data) {
+ if (data) {
+ while (*data) {
+ char ch = *data++;
+
+ if (ch == '<') {
+ writeData("&lt;");
+ } else if (ch == '>') {
+ writeData("&gt;");
+ } else if (ch == '&') {
+ writeData("&amp;");
+ } else if (ch == '"') {
+ writeData("&quot;");
+ } else if (ch == '\'') {
+ writeData("&apos;");
+ } else if (ch >= ' ' && ch <= '~') {
+ writeData("%c",ch);
+ } else {
+ writeData("&#%u;",(unsigned int)ch);
+ }
+ }
+ }
+}
+
+void XMLOut::writeData(const char *format, ...) {
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(temp_buffer, sizeof(temp_buffer), format, ap);
+ va_end(ap);
+
+ strncat(xml_string, temp_buffer, sizeof(xml_string)-strlen(xml_string)-1);
+}
+
+const XMLOut & XMLOut::xmlHeader(void) {
+ writeData("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ incomplete = false;
+ return *this;
+}
+
+const XMLOut & XMLOut::comment(const char* text, const bool newline) {
+ if (incomplete) {
+ writeData(">\n");
+ }
+ writeTabs();
+ writeData("<!-- %s -->", text);
+ if (newline) {
+ writeData("\n");
+ }
+ incomplete = false;
+ return *this;
+}
+
+const XMLOut & XMLOut::startElement(const char* tag) {
+ if (incomplete) {
+ writeData(">\n");
+ }
+ writeTabs();
+ writeData("<%s", tag);
+ incomplete = true;
+ indent++;
+ return *this;
+}
+
+const XMLOut & XMLOut::startElement(const char* tag, int index) {
+ if (incomplete) {
+ writeData(">\n");
+ }
+ writeTabs();
+ writeData("<!-- %d -->", index);
+ writeData("<%s", tag);
+ incomplete = true;
+ indent++;
+ return *this;
+}
+
+const XMLOut & XMLOut::endElement(const char* tag) {
+ indent--;
+ if (indent < 0) {
+ indent = 0;
+ }
+ if (incomplete) {
+ writeData("/>\n");
+ incomplete = false;
+ } else {
+ writeTabs();
+ writeData("</%s>\n", tag);
+ }
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeString(const char* name, const char* value) {
+ writeData(" %s=\"", name);
+ encodeAttributeData(value);
+ writeData("\"");
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeInt(const char* name, int value) {
+ writeData(" %s=\"%d\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeUInt(const char* name, unsigned int value) {
+ writeData(" %s=\"%u\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeLong(const char* name, long value) {
+ writeData(" %s=\"%ld\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeULong(const char* name, unsigned long value) {
+ writeData(" %s=\"%lu\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeLongLong(const char* name, long long value) {
+ writeData(" %s=\"%lld\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeULongLong(const char* name, unsigned long long value) {
+ writeData(" %s=\"%llu\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeDouble(const char* name, double value) {
+ writeData(" %s=\"%f\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeBool(const char* name, bool value) {
+ writeData(" %s=\"%s\"", name, value ? "yes" : "no");
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeHex4(const char* name, int value) {
+ writeData(" %s=\"0x%04x\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeHex8(const char* name, int value) {
+ writeData(" %s=\"0x%08x\"", name, value);
+ return *this;
+}
diff --git a/daemon/XMLOut.h b/daemon/XMLOut.h
new file mode 100644
index 0000000..057222c
--- /dev/null
+++ b/daemon/XMLOut.h
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 __XMLOUT_H
+#define __XMLOUT_H
+
+class XMLOut {
+ int indent;
+ bool incomplete;
+ char temp_buffer[4096];
+ char xml_string[64*1024];
+
+ void writeTabs();
+ void encodeAttributeData(const char* data);
+ void writeData(const char *format, ...);
+
+public:
+ XMLOut();
+ ~XMLOut();
+ char* getXmlString() {return xml_string;}
+ void clearXmlString() {xml_string[0]=0;}
+ const XMLOut & xmlHeader(void);
+ const XMLOut & comment(const char* text, const bool newline);
+ const XMLOut & startElement(const char* tag);
+ const XMLOut & startElement(const char* tag, int index);
+ const XMLOut & endElement(const char* tag);
+ const XMLOut & attributeString(const char* name, const char* value);
+ const XMLOut & attributeInt(const char* name, int value);
+ const XMLOut & attributeUInt(const char* name, unsigned int value);
+ const XMLOut & attributeLong(const char* name, long value);
+ const XMLOut & attributeULong(const char* name, unsigned long value);
+ const XMLOut & attributeLongLong(const char* name, long long value);
+ const XMLOut & attributeULongLong(const char* name, unsigned long long value);
+ const XMLOut & attributeDouble(const char* name, double value);
+ const XMLOut & attributeBool(const char* name, bool value);
+ const XMLOut & attributeHex4(const char* name, int value);
+ const XMLOut & attributeHex8(const char* name, int value);
+};
+
+#endif // __XMLOUT_H
diff --git a/daemon/XMLReader.cpp b/daemon/XMLReader.cpp
new file mode 100644
index 0000000..6766dfd
--- /dev/null
+++ b/daemon/XMLReader.cpp
@@ -0,0 +1,165 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "XMLReader.h"
+extern void handleException();
+
+XMLReader::XMLReader(const char* xmlstring) {
+ mPtr = (char*)xmlstring;
+ mNoMore = false;
+ mFirstTime = true;
+}
+
+XMLReader::~XMLReader() {
+}
+
+char* XMLReader::nextTag() {
+ static char tag[128];
+
+ // Check if past the end of the root tag
+ if (mNoMore) return NULL;
+
+ // Find start character
+ mPtr = strchr(mPtr, '<');
+
+ if (mPtr == NULL) return mPtr;
+
+ // Skip tag if it begins with <?
+ if (mPtr[1] == '?') {
+ mPtr++;
+ return nextTag();
+ }
+
+ // Find end of tag name
+ mPtr++;
+ char* end = strchr(mPtr, ' ');
+ if (end == NULL)
+ end = strchr(mPtr, '>');
+ if (end == NULL)
+ return 0;
+
+ // Check if tag has no attributes
+ char* tagend = strchr(mPtr, '>');
+ if (tagend < end) end = tagend;
+
+ // Check the tag name length
+ unsigned int length = (int)end - (int)mPtr;
+ if (length > sizeof(tag) - 1) {
+ // tag name too long, skip it
+ return nextTag();
+ }
+
+ // Return the tag name
+ strncpy(tag, mPtr, length);
+ tag[length] = 0;
+
+ // Mark the root tag
+ if (mFirstTime) {
+ mEndXML[0] = '/';
+ strcpy(&mEndXML[1], tag);
+ mFirstTime = false;
+ } else if (strcmp(tag, mEndXML) == 0) {
+ // End of root tag found
+ mNoMore = true;
+ }
+
+ return tag;
+}
+
+void XMLReader::getAttribute(const char* name, char* value, int maxSize, const char* defValue) {
+ char searchString[128];
+
+ // Set up default
+ strncpy(value, defValue, maxSize - 1);
+ value[maxSize - 1] = 0;
+
+ // Determine search string by ending the name with ="
+ if (strlen(name) > sizeof(searchString) - 3) return;
+ strcpy(searchString, name);
+ strcat(searchString, "=\"");
+
+ // Find the beginning of the attribute's search string
+ char* begin = strstr(mPtr, searchString);
+ if (begin == NULL) return;
+
+ // Find the beginning of the attribute's value
+ begin += strlen(searchString);
+
+ // Find the end of the current tag to make sure the attribute exists within the tag
+ char* endtag = strchr(mPtr, '>');
+ if (endtag < begin) return;
+
+ // Find the end of the attribute's value
+ char* end = strchr(begin, '"');
+ if (end == NULL) return;
+
+ // Determine length
+ int length = (int)end - (int)begin;
+ if (length > maxSize - 1) return;
+
+ strncpy(value, begin, length);
+ value[length] = 0;
+}
+
+int XMLReader::getAttributeAsInteger(const char* name, int defValue) {
+ char value[32];
+ getAttribute(name, value, sizeof(value), "");
+ if (value[0] == 0) return defValue;
+ if (value[0] == '0' && value[1] == 'x') {
+ return (int) strtoul(&value[2], (char**)NULL, 16);
+ }
+ return atoi(value);
+}
+
+bool XMLReader::getAttributeAsBoolean(const char* name, bool defValue) {
+ char value[32];
+ getAttribute(name, value, sizeof(value), "");
+ if (value[0] == 0) return defValue;
+
+ // Convert to lowercase
+ int i = 0;
+ while (value[i]) {
+ value[i] = tolower(value[i]);
+ i++;
+ }
+
+ if (strcmp(value, "true") == 0 || strcmp(value, "yes") == 0 || strcmp(value, "1") == 0 || strcmp(value, "on") == 0) return true;
+ else if (strcmp(value, "false") == 0 || strcmp(value, "no") == 0 || strcmp(value, "0") == 0 || strcmp(value, "off") == 0) return false;
+ else return defValue;
+}
+
+int XMLReader::getAttributeLength(const char* name) {
+ char searchString[128];
+
+ // Determine search string by ending the name with ="
+ if (strlen(name) > sizeof(searchString) - 3) return 0;
+ strcpy(searchString, name);
+ strcat(searchString, "=\"");
+
+ // Find the beginning of the attribute's search string
+ char* begin = strstr(mPtr, searchString);
+ if (begin == NULL) return 0;
+
+ // Find the beginning of the attribute's value
+ begin += strlen(searchString);
+
+ // Find the end of the current tag to make sure the attribute exists within the tag
+ char* endtag = strchr(mPtr, '>');
+ if (endtag < begin) return 0;
+
+ // Find the end of the attribute's value
+ char* end = strchr(begin, '"');
+ if (end == NULL) return 0;
+
+ // Determine length
+ return (int)end - (int)begin;
+}
diff --git a/daemon/XMLReader.h b/daemon/XMLReader.h
new file mode 100644
index 0000000..55f655b
--- /dev/null
+++ b/daemon/XMLReader.h
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 _XMLREADER_H
+#define _XMLREADER_H
+
+class XMLReader {
+public:
+ XMLReader(const char* xmlstring);
+ ~XMLReader();
+ char* nextTag();
+ void getAttribute(const char* name, char* value, int maxSize, const char* defValue);
+ int getAttributeAsInteger(const char* name, int defValue);
+ bool getAttributeAsBoolean(const char* name, bool defValue);
+ int getAttributeLength(const char* name);
+private:
+ char* mPtr;
+ bool mFirstTime, mNoMore;
+ char mEndXML[128];
+};
+
+#endif // _XMLREADER_H
diff --git a/daemon/configuration.xml b/daemon/configuration.xml
new file mode 100644
index 0000000..0f91065
--- /dev/null
+++ b/daemon/configuration.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding='UTF-8'?>
+<configurations version="1">
+ <configuration counter="ARM_ARM11_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_ARM11_cnt0" event="0x7" title="Instruction" name="Executed" color="0x80008000" per_cpu="yes" description="Instructions executed"/>
+ <configuration counter="ARM_ARM11_cnt1" event="0xa" title="Cache" name="Data miss" color="0x80C92211" per_cpu="yes" description="Data cache miss, not including Cache Operations"/>
+ <configuration counter="ARM_ARM11MPCore_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08" title="Core" name="Instructions" color="0x80008000" per_cpu="yes" description="Instructions executed"/>
+ <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b" title="Cache" name="Data read miss" color="0x000080FF" per_cpu="yes" description="Data cache miss, not including Cache Operations"/>
+ <configuration counter="ARM_Cortex-A5_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" event_based_sampling="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_Cortex-A5_cnt0" event="0x8" title="Instruction" name="Executed" color="0x80008000" per_cpu="yes" event_based_sampling="yes" description="Instruction architecturally executed"/>
+ <configuration counter="ARM_Cortex-A5_cnt1" event="0x1" title="Cache" name="Instruction refill" color="0x80C92211" per_cpu="yes" event_based_sampling="yes" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <configuration counter="ARM_Cortex-A8_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" event_based_sampling="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_Cortex-A8_cnt0" event="0x8" title="Instruction" name="Executed" color="0x80008000" per_cpu="yes" event_based_sampling="yes" description="Instruction architecturally executed"/>
+ <configuration counter="ARM_Cortex-A8_cnt1" event="0x44" title="Cache" name="L2 miss" color="0x80C92211" per_cpu="yes" event_based_sampling="yes" description="Any cacheable miss in the L2 cache"/>
+ <configuration counter="ARM_Cortex-A8_cnt2" event="0x43" title="Cache" name="L1 miss" color="0x80FFC000" per_cpu="yes" event_based_sampling="yes" description="Any accesses to the L2 cache"/>
+ <configuration counter="ARM_Cortex-A8_cnt3" event="0x10" title="Branch" name="Mispredicted" color="0x80FFFF33" per_cpu="yes" event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
+ <configuration counter="ARM_Cortex-A9_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" event_based_sampling="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_Cortex-A9_cnt0" event="0x68" title="Instruction" name="Executed" color="0x80008000" per_cpu="yes" event_based_sampling="yes" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and even more approximate of the total number of instructions architecturally executed"/>
+ <configuration counter="ARM_Cortex-A9_cnt1" event="0x50" title="Cache" name="Coherency miss" color="0x80C92211" per_cpu="yes" event_based_sampling="yes" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which also miss in all the other Cortex-A9 processors, meaning that the request is sent to the external memory"/>
+ <configuration counter="ARM_Cortex-A9_cnt2" event="0x51" title="Cache" name="Coherency hit" color="0x80FFC000" per_cpu="yes" event_based_sampling="yes" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which hit in another Cortex-A9 processor, meaning that the linefill data is fetched directly from the relevant Cortex-A9 cache"/>
+ <configuration counter="ARM_Cortex-A9_cnt3" event="0x0c" title="Branch" name="PC change" color="0x809900FF" per_cpu="yes" event_based_sampling="yes" description="Software change of Program Counter, except by an exception, architecturally executed"/>
+ <configuration counter="ARM_Cortex-A9_cnt4" event="0x10" title="Branch" name="Mispredicted" color="0x80FFFF33" per_cpu="yes" event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
+ <configuration counter="ARM_Cortex-A9_cnt5" event="0x0f" title="Fault" name="Unaligned access" color="0x666666" per_cpu="yes" event_based_sampling="yes" description="Unaligned access architecturally executed"/>
+ <configuration counter="ARM_Cortex-A15_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" event_based_sampling="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_Cortex-A15_cnt0" event="0x8" title="Instruction" name="Executed" color="0x80008000" per_cpu="yes" event_based_sampling="yes" description="Instruction architecturally executed"/>
+ <configuration counter="ARM_Cortex-A15_cnt1" event="0x16" title="Cache" name="L2 data access" color="0x80C92211" per_cpu="yes" event_based_sampling="yes" description="Level 2 data cache access"/>
+ <configuration counter="ARM_Cortex-A15_cnt2" event="0x10" title="Branch" name="Mispredicted" color="0x80FFFF33" per_cpu="yes" event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
+ <configuration counter="ARM_Cortex-A15_cnt3" event="0x19" title="Bus" name="Access" color="0x809900FF" per_cpu="yes" event_based_sampling="yes" description=""/>
+ <configuration counter="Linux_irq_irq" title="Interrupts" name="IRQ" color="0x805050F4" per_cpu="yes" description="Linux IRQ taken"/>
+ <configuration counter="Linux_irq_softirq" title="Interrupts" name="SoftIRQ" color="0x80FF9000" per_cpu="yes" description="Linux SoftIRQ taken"/>
+ <configuration counter="Linux_block_rq_wr" title="Disk IO" name="Write" color="0x80FF4020" description="Disk IO Bytes Written"/>
+ <configuration counter="Linux_block_rq_rd" title="Disk IO" name="Read" color="0x800090FF" description="Disk IO Bytes Read"/>
+ <configuration counter="Linux_meminfo_memused" title="Memory" name="Used" color="0x800084ab" operation="maximum" description="Total used memory size"/>
+ <configuration counter="Linux_meminfo_memfree" title="Memory" name="Free" color="0x80e9e9e9" operation="maximum" description="Available memory size"/>
+ <configuration counter="Linux_net_rx" title="Network" name="Receive" color="0x805050F4" description="Receive network traffic, excluding effect from Streamline"/>
+ <configuration counter="Linux_net_tx" title="Network" name="Transmit" color="0x80FF9000" description="Transmit network traffic, excluding effect from Streamline"/>
+ <configuration counter="Linux_cpuload_system" title="CPU Load" name="System" color="0x80FF0000" description="Scheduler CPU Load of System Behavior"/>
+ <configuration counter="Linux_cpuload_user" title="CPU Load" name="User" color="0x8000FF00" description="Scheduler CPU Load of User Application"/>
+</configurations>
diff --git a/daemon/events-ARM11.xml b/daemon/events-ARM11.xml
new file mode 100644
index 0000000..48a614e
--- /dev/null
+++ b/daemon/events-ARM11.xml
@@ -0,0 +1,43 @@
+ <counter_set name="ARM_ARM11_cntX">
+ <counter name="ARM_ARM11_cnt0"/>
+ <counter name="ARM_ARM11_cnt1"/>
+ <counter name="ARM_ARM11_cnt2"/>
+ </counter_set>
+ <category name="ARM11" counter_set="ARM_ARM11_cntX" per_cpu="yes">
+ <event counter="ARM_ARM11_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/>
+ <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/>
+ <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/>
+ <event event="0x03" title="Cache" name="Inst micro TLB miss" description="Instruction MicroTLB miss (unused on ARM1156)"/>
+ <event event="0x04" title="Cache" name="Data micro TLB miss" description="Data MicroTLB miss (unused on ARM1156)"/>
+ <event event="0x05" title="Branch" name="Instruction executed" description="Branch instruction executed, branch might or might not have changed program flow"/>
+ <event event="0x06" title="Branch" name="Mispredicted" description="Branch mis-predicted"/>
+ <event event="0x07" title="Instruction" name="Executed" description="Instructions executed"/>
+ <event event="0x09" title="Cache" name="Data access" description="Data cache access, not including Cache operations"/>
+ <event event="0x0a" title="Cache" name="Data all access" description="Data cache access, not including Cache Operations regardless of whether or not the location is cacheable"/>
+ <event event="0x0b" title="Cache" name="Data miss" description="Data cache miss, not including Cache Operations"/>
+ <event event="0x0c" title="Cache" name="Write-back" description="Data cache write-back"/>
+ <event event="0x0d" title="Program Counter" name="SW change" description="Software changed the PC"/>
+ <event event="0x0f" title="Cache " name="TLB miss" description="Main TLB miss (unused on ARM1156)"/>
+ <event event="0x10" title="External" name="Access" description="Explicit external data or peripheral access"/>
+ <event event="0x11" title="Cache" name="Data miss" description="Stall because of Load Store Unit request queue being full"/>
+ <event event="0x12" title="Write Buffer" name="Drains" description="The number of times the Write Buffer was drained because of a Data Synchronization Barrier command or Strongly Ordered operation"/>
+ <event event="0x13" title="Disable Interrupts" name="FIQ" description="The number of cycles which FIQ interrupts are disabled (ARM1156 only)"/>
+ <event event="0x14" title="Disable Interrupts" name="IRQ" description="The number of cycles which IRQ interrupts are disabled (ARM1156 only)"/>
+ <event event="0x20" title="ETM" name="ETMEXTOUT[0]" description="ETMEXTOUT[0] signal was asserted for a cycle"/>
+ <event event="0x21" title="ETM" name="ETMEXTOUT[1]" description="ETMEXTOUT[1] signal was asserted for a cycle"/>
+ <event event="0x22" title="ETM" name="ETMEXTOUT[0,1]" description="ETMEXTOUT[0] or ETMEXTOUT[1] was asserted"/>
+ <event event="0x23" title="Procedure" name="Calls" description="Procedure call instruction executed"/>
+ <event event="0x24" title="Procedure" name="Returns" description="Procedure return instruction executed"/>
+ <event event="0x25" title="Procedure" name="Return and predicted" description="Procedure return instruction executed and return address predicted"/>
+ <event event="0x26" title="Procedure" name="Return and mispredicted" description="Procedure return instruction executed and return address predicted incorrectly"/>
+ <event event="0x30" title="Cache" name="Inst tag or parity error" description="Instruction cache Tag or Valid RAM parity error (ARM1156 only)"/>
+ <event event="0x31" title="Cache" name="Inst parity error" description="Instruction cache RAM parity error (ARM1156 only)"/>
+ <event event="0x32" title="Cache" name="Data tag or parity error" description="Data cache Tag or Valid RAM parity error (ARM1156 only)"/>
+ <event event="0x33" title="Cache" name="Data parity error" description="Data cache RAM parity error (ARM1156 only)"/>
+ <event event="0x34" title="ITCM" name="Error" description="ITCM error (ARM1156 only)"/>
+ <event event="0x35" title="DTCM" name="Error" description="DTCM error (ARM1156 only)"/>
+ <event event="0x36" title="Procedure" name="Return address pop" description="Procedure return address popped off the return stack (ARM1156 only)"/>
+ <event event="0x37" title="Procedure" name="Return address misprediction" description="Procedure return address popped off the return stack has been incorrectly predicted by the PFU (ARM1156 only)"/>
+ <event event="0x38" title="Cache" name="Data dirty parity error" description="Data cache Dirty RAM parity error (ARM1156 only)"/>
+ </category>
diff --git a/daemon/events-ARM11MPCore.xml b/daemon/events-ARM11MPCore.xml
new file mode 100644
index 0000000..6da9ecb
--- /dev/null
+++ b/daemon/events-ARM11MPCore.xml
@@ -0,0 +1,30 @@
+ <counter_set name="ARM_ARM11MPCore_cntX">
+ <counter name="ARM_ARM11MPCore_cnt0"/>
+ <counter name="ARM_ARM11MPCore_cnt1"/>
+ <counter name="ARM_ARM11MPCore_cnt2"/>
+ </counter_set>
+ <category name="ARM11MPCore" counter_set="ARM_ARM11MPCore_cntX" per_cpu="yes">
+ <event counter="ARM_ARM11MPCore_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/>
+ <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/>
+ <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/>
+ <event event="0x03" title="Cache" name="Inst micro TLB miss" description="Instruction MicroTLB miss (unused on ARM1156)"/>
+ <event event="0x04" title="Cache" name="Data micro TLB miss" description="Data MicroTLB miss (unused on ARM1156)"/>
+ <event event="0x05" title="Branch" name="Instruction executed" description="Branch instructions executed, branch might or might not have changed program flow"/>
+ <event event="0x06" title="Branch" name="Not predicted" description="Branch not predicted"/>
+ <event event="0x07" title="Branch" name="Mispredicted" description="Branch mispredicted"/>
+ <event event="0x08" title="Core" name="Instructions" description="Instructions executed"/>
+ <event event="0x09" title="Core" name="Folded Instructions" description="Folded instructions executed"/>
+ <event event="0x0a" title="Cache" name="Data read access" description="Data cache read access, not including cache operations"/>
+ <event event="0x0b" title="Cache" name="Data read miss" description="Data cache miss, not including Cache Operations"/>
+ <event event="0x0c" title="Cache" name="Data write access" description="Data cache write access"/>
+ <event event="0x0d" title="Cache" name="Data write miss" description="Data cache write miss"/>
+ <event event="0x0e" title="Cache" name="Data line eviction" description="Data cache line eviction, not including cache operations"/>
+ <event event="0x0f" title="Branch" name="PC change w/o mode change" description="Software changed the PC and there is not a mode change"/>
+ <event event="0x10" title="Cache " name="TLB miss" description="Main TLB miss"/>
+ <event event="0x11" title="External" name="External Memory request" description="External memory request (cache refill, noncachable, write-back)"/>
+ <event event="0x12" title="Cache" name="Stall" description="Stall because of Load Store Unit request queue being full"/>
+ <event event="0x13" title="Write Buffer" name="Drains" description="The number of times the Write Buffer was drained because of LSU ordering constraints or CP15 operations (Data Synchronization Barrier command) or Strongly Ordered operation"/>
+ <event event="0x14" title="Write Buffer" name="Write Merges" description="Buffered write merged in a store buffer slot"/>
+ <event event="0xFF" title="Core" name="Cycle counter" description="An increment each cycle"/>
+ </category> \ No newline at end of file
diff --git a/daemon/events-Cortex-A15.xml b/daemon/events-Cortex-A15.xml
new file mode 100644
index 0000000..78a4b17
--- /dev/null
+++ b/daemon/events-Cortex-A15.xml
@@ -0,0 +1,77 @@
+ <counter_set name="ARM_Cortex-A15_cntX">
+ <counter name="ARM_Cortex-A15_cnt0"/>
+ <counter name="ARM_Cortex-A15_cnt1"/>
+ <counter name="ARM_Cortex-A15_cnt2"/>
+ <counter name="ARM_Cortex-A15_cnt3"/>
+ <counter name="ARM_Cortex-A15_cnt4"/>
+ <counter name="ARM_Cortex-A15_cnt5"/>
+ </counter_set>
+ <category name="Cortex-A15" counter_set="ARM_Cortex-A15_cntX" per_cpu="yes" event_based_sampling="yes">
+ <event counter="ARM_Cortex-A15_ccnt" title="Clock" name="Cycles" 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"/>
+ <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"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x11" title="Cycle" name="Cycle" description=""/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
+ <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/>
+ <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/>
+ <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
+ <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
+ <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
+ <event event="0x19" title="Bus" name="Access" description=""/>
+ <event event="0x1a" title="Memory" name="Error" description="Local memory error"/>
+ <event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/>
+ <event event="0x1c" title="Memory" name="Translation table" description="Write to translation table base architecturally executed"/>
+ <event event="0x1d" title="Bus" name="Cycle" description=""/>
+ <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
+ <event event="0x41" title="Cache" name="L1 data write" description="Level 1 data cache access - Write"/>
+ <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/>
+ <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/>
+ <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-Back - Victim"/>
+ <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-Back - Cleaning and coherency"/>
+ <event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/>
+ <event event="0x4c" title="TLB" name="L1 data refill read" description="Level 1 data TLB refill - Read"/>
+ <event event="0x4d" title="TLB" name="L1 data refill write" description="Level 1 data TLB refill - Write"/>
+ <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
+ <event event="0x51" title="Cache" name="L2 data write" description="Level 2 data cache access - Write"/>
+ <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/>
+ <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/>
+ <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-Back - Victim"/>
+ <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-Back - Cleaning and coherency"/>
+ <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
+ <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
+ <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
+ <event event="0x64" title="Bus" name="Access" description="Bus access - Normal"/>
+ <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
+ <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
+ <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
+ <event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access - Read"/>
+ <event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access - Write"/>
+ <event event="0x6a" title="Memory" name="Unaligned" description="Unaligned access"/>
+ <event event="0x6c" title="Intrinsic" name="LDREX" description="Exclusive instruction speculatively executed - LDREX"/>
+ <event event="0x6d" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed - STREX pass"/>
+ <event event="0x6e" title="Intrinsic" name="STREX fail" description="Exclusive instruction speculatively executed - STREX fail"/>
+ <event event="0x70" title="Instructions" name="Load" description="Instruction speculatively executed - Load"/>
+ <event event="0x71" title="Instructions" name="Store" description="Instruction speculatively executed - Store"/>
+ <event event="0x72" title="Instructions" name="Load/Store" description="Instruction speculatively executed - Load or store"/>
+ <event event="0x73" title="Instructions" name="Integer" description="Instruction speculatively executed - Integer data processing"/>
+ <event event="0x74" title="Instructions" name="Advanced SIMD" description="Instruction speculatively executed - Advanced SIMD"/>
+ <event event="0x75" title="Instructions" name="VFP" description="Instruction speculatively executed - VFP"/>
+ <event event="0x76" title="Instructions" name="Software change" description="Instruction speculatively executed - Software change of the PC"/>
+ <event event="0x78" title="Instructions" name="Immediate branch" description="Branch speculatively executed - Immediate branch"/>
+ <event event="0x79" title="Instructions" name="Procedure return" description="Branch speculatively executed - Procedure return"/>
+ <event event="0x7a" title="Instructions" name="Indirect branch" description="Branch speculatively executed - Indirect branch"/>
+ <event event="0x7c" title="Instructions" name="ISB" description="Barrier speculatively executed - ISB"/>
+ <event event="0x7d" title="Instructions" name="DSB" description="Barrier speculatively executed - DSB"/>
+ <event event="0x7e" title="Instructions" name="DMB" description="Barrier speculatively executed - DMB"/>
+ </category>
+ \ No newline at end of file
diff --git a/daemon/events-Cortex-A5.xml b/daemon/events-Cortex-A5.xml
new file mode 100644
index 0000000..3e2f5b2
--- /dev/null
+++ b/daemon/events-Cortex-A5.xml
@@ -0,0 +1,39 @@
+ <counter_set name="ARM_Cortex-A5_cntX">
+ <counter name="ARM_Cortex-A5_cnt0"/>
+ <counter name="ARM_Cortex-A5_cnt1"/>
+ </counter_set>
+ <category name="Cortex-A5" counter_set="ARM_Cortex-A5_cntX" per_cpu="yes" event_based_sampling="yes">
+ <event counter="ARM_Cortex-A5_ccnt" title="Clock" name="Cycles" 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"/>
+ <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"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0e" title="Procedure" name="Return" description="Procedure return, other than exception return, architecturally executed"/>
+ <event event="0x0f" title="Fault" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
+ <event event="0x14" title="Cache" name="Instruction access" description="Instruction cache access"/>
+ <event event="0x15" title="Cache" name="Data eviction" description="Data cache eviction"/>
+ <event event="0x86" title="Interrupts" name="IRQ" description="IRQ exception taken"/>
+ <event event="0x87" title="Interrupts" name="FIQ" description="FIQ exception taken"/>
+ <event event="0xC0" title="Memory" name="External request" description="External memory request"/>
+ <event event="0xC1" title="Memory" name="Non-cacheable ext req" description="Non-cacheable external memory request"/>
+ <event event="0xC2" title="Cache" name="Linefill" description="Linefill because of prefetch"/>
+ <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
+ <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
+ <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
+ <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description=""/>
+ <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description=""/>
+ <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
+ </category>
diff --git a/daemon/events-Cortex-A8.xml b/daemon/events-Cortex-A8.xml
new file mode 100644
index 0000000..1f78b0c
--- /dev/null
+++ b/daemon/events-Cortex-A8.xml
@@ -0,0 +1,58 @@
+ <counter_set name="ARM_Cortex-A8_cntX">
+ <counter name="ARM_Cortex-A8_cnt0"/>
+ <counter name="ARM_Cortex-A8_cnt1"/>
+ <counter name="ARM_Cortex-A8_cnt2"/>
+ <counter name="ARM_Cortex-A8_cnt3"/>
+ </counter_set>
+ <category name="Cortex-A8" counter_set="ARM_Cortex-A8_cntX" per_cpu="yes" event_based_sampling="yes">
+ <event counter="ARM_Cortex-A8_ccnt" title="Clock" name="Cycles" 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"/>
+ <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"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0e" title="Procedure" name="Return" description="Procedure return, other than exception return, architecturally executed"/>
+ <event event="0x0f" title="Fault" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x40" title="Cache" name="Write buffer full" description="Any write buffer full cycle"/>
+ <event event="0x41" title="Cache" name="L2 store" description="Any store that is merged in the L2 memory system"/>
+ <event event="0x42" title="Cache" name="Bufferable transaction" description="Any bufferable store transaction from load/store to L2 cache, excluding eviction or cast out data"/>
+ <event event="0x43" title="Cache" name="L1 miss" description="Any accesses to the L2 cache"/>
+ <event event="0x44" title="Cache" name="L2 miss" description="Any cacheable miss in the L2 cache"/>
+ <event event="0x45" title="AXI" name="Read" description="The number of AXI read data transfers"/>
+ <event event="0x46" title="AXI" name="Write" description="The number of AXI write data transfers"/>
+ <event event="0x47" title="Memory" name="Replay event" description="Any replay event in the memory system"/>
+ <event event="0x48" title="Memory" name="Unaligned access" description="Any unaligned memory access that results in a replay"/>
+ <event event="0x49" title="Cache" name="L1 data miss" description="Any L1 data memory access that misses in the cache as a result of the hashing algorithm"/>
+ <event event="0x4a" title="Cache" name="L1 inst miss" description="Any L1 instruction memory access that misses in the cache as a result of the hashing algorithm"/>
+ <event event="0x4b" title="Cache" name="L1 page coloring" description="Any L1 data memory access in which a page coloring alias occurs"/>
+ <event event="0x4c" title="NEON" name="L1 cache hit" description="Any NEON access that hits in the L1 data cache"/>
+ <event event="0x4d" title="NEON" name="L1 cache access" description="Any NEON cacheable data accesses for L1 data cache"/>
+ <event event="0x4e" title="NEON" name="L2 cache access" description="Any L2 cache accesses as a result of a NEON memory access"/>
+ <event event="0x4f" title="NEON" name="L2 cache hit" description="Any NEON hit in the L2 cache"/>
+ <event event="0x50" title="Cache" name="L1 inst access" description="Any L1 instruction cache access, excluding CP15 cache accesses"/>
+ <event event="0x51" title="Branch" name="Return stack misprediction" description="Any return stack misprediction because of incorrect target address for a taken return stack pop"/>
+ <event event="0x52" title="Branch" name="Direction misprediction" description="Branch direction misprediction"/>
+ <event event="0x53" title="Branch" name="Taken prediction" description="Any predictable branch that is predicted to be taken"/>
+ <event event="0x54" title="Branch" name="Executed and taken prediction" description="Any predictable branch that is executed and taken"/>
+ <event event="0x55" title="Core" name="Operations issued" description="Number of operations issued, where an operation is either: an instruction or one operation in a sequence of operations that make up a multi-cycle instruction"/>
+ <event event="0x56" title="Core" name="No issue cycles" description="Increment for every cycle that no instructions are available for issue"/>
+ <event event="0x57" title="Core" name="Issue cycles" description="For every cycle, this event counts the number of instructions issued in that cycle. Multi-cycle instructions are only counted once"/>
+ <event event="0x58" title="NEON" name="MRC data wait" description="Number of cycles the processor stalls waiting on MRC data from NEON"/>
+ <event event="0x59" title="NEON" name="Full queue" description="Number of cycles that the processor stalls as a result of a full NEON instruction queue or NEON load queue"/>
+ <event event="0x5a" title="NEON" name="Idle" description="Number of cycles that NEON and integer processors are both not idle"/>
+ <event event="0x70" title="External" name="PMUEXTIN[0]" description="Counts any event from external input source PMUEXTIN[0]"/>
+ <event event="0x71" title="External" name="PMUEXTIN[1]" description="Counts any event from external input source PMUEXTIN[1]"/>
+ <event event="0x72" title="External" name="PMUEXTIN[0,1]" description="Counts any event from both external input sources PMUEXTIN[0] and PMUEXTIN[1]"/>
+ </category>
+ \ No newline at end of file
diff --git a/daemon/events-Cortex-A9.xml b/daemon/events-Cortex-A9.xml
new file mode 100644
index 0000000..7bc2f21
--- /dev/null
+++ b/daemon/events-Cortex-A9.xml
@@ -0,0 +1,67 @@
+ <counter_set name="ARM_Cortex-A9_cntX">
+ <counter name="ARM_Cortex-A9_cnt0"/>
+ <counter name="ARM_Cortex-A9_cnt1"/>
+ <counter name="ARM_Cortex-A9_cnt2"/>
+ <counter name="ARM_Cortex-A9_cnt3"/>
+ <counter name="ARM_Cortex-A9_cnt4"/>
+ <counter name="ARM_Cortex-A9_cnt5"/>
+ </counter_set>
+ <category name="Cortex-A9" counter_set="ARM_Cortex-A9_cntX" per_cpu="yes" event_based_sampling="yes">
+ <event counter="ARM_Cortex-A9_ccnt" title="Clock" name="Cycles" 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"/>
+ <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"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0f" title="Fault" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x40" title="Java" name="Bytecode execute" description="Counts the number of Java bytecodes being decoded, including speculative ones"/>
+ <event event="0x41" title="Java" name="SW bytecode execute" description="Counts the number of software java bytecodes being decoded, including speculative ones"/>
+ <event event="0x42" title="Jazelle" name="Backward branch execute" description="Counts the number of Jazelle taken branches being executed"/>
+ <event event="0x50" title="Cache" name="Coherency miss" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which also miss in all the other Cortex-A9 processors, meaning that the request is sent to the external memory"/>
+ <event event="0x51" title="Cache" name="Coherency hit" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which hit in another Cortex-A9 processor, meaning that the linefill data is fetched directly from the relevant Cortex-A9 cache"/>
+ <event event="0x60" title="Cache" name="Inst dependent stall" description="Counts the number of cycles where the processor is ready to accept new instructions, but does not receive any because of the instruction side not being able to provide any and the instruction cache is currently performing at least one linefill"/>
+ <event event="0x61" title="Cache" name="Data dependent stall" description="Counts the number of cycles where the core has some instructions that it cannot issue to any pipeline, and the Load Store unit has at least one pending linefill request, and no pending TLB requests"/>
+ <event event="0x62" title="Cache" name="TLB stall" description="Counts the number of cycles where the processor is stalled waiting for the completion of translation table walks from the main TLB"/>
+ <event event="0x63" title="Intrinsic" name="STREX pass" description="Counts the number of STREX instructions architecturally executed and passed"/>
+ <event event="0x64" title="Intrinsic" name="STREX fail" description="Counts the number of STREX instructions architecturally executed and failed"/>
+ <event event="0x65" title="Cache" name="Data eviction" description="Counts the number of eviction requests because of a linefill in the data cache"/>
+ <event event="0x66" title="Pipeline" name="Issue stage no dispatch" description="Counts the number of cycles where the issue stage does not dispatch any instruction because it is empty or cannot dispatch any instructions"/>
+ <event event="0x67" title="Pipeline" name="Issue stage empty" description="Counts the number of cycles where the issue stage is empty"/>
+ <event event="0x68" title="Instruction" name="Executed" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and even more approximate of the total number of instructions architecturally executed"/>
+ <event event="0x6E" title="Core" name="Functions" description="Counts the number of procedure returns whose condition codes do not fail, excluding all returns from exception"/>
+ <event event="0x70" title="Instructions" name="Main execution unit" description="Counts the number of instructions being executed in the main execution pipeline of the processor, the multiply pipeline and arithmetic logic unit pipeline"/>
+ <event event="0x71" title="Instructions" name="Second execution unit" description="Counts the number of instructions being executed in the processor second execution pipeline (ALU)"/>
+ <event event="0x72" title="Instructions" name="Load/Store" description="Counts the number of instructions being executed in the Load/Store unit"/>
+ <event event="0x73" title="Instructions" name="Floating point" description="Counts the number of Floating-point instructions going through the Register Rename stage"/>
+ <event event="0x74" title="Instructions" name="NEON" description="Counts the number of NEON instructions going through the Register Rename stage"/>
+ <event event="0x80" title="Stalls" name="PLD" description="Counts the number of cycles where the processor is stalled because PLD slots are all full"/>
+ <event event="0x81" title="Stalls" name="Memory write" description="Counts the number of cycles when the processor is stalled and the data side is stalled too because it is full and executing writes to the external memory"/>
+ <event event="0x82" title="Stalls" name="Inst main TLB miss" description="Counts the number of stall cycles because of main TLB misses on requests issued by the instruction side"/>
+ <event event="0x83" title="Stalls" name="Data main TLB miss" description="Counts the number of stall cycles because of main TLB misses on requests issued by the data side"/>
+ <event event="0x84" title="Stalls" name="Inst micro TLB miss" description="Counts the number of stall cycles because of micro TLB misses on the instruction side"/>
+ <event event="0x85" title="Stalls" name="Data micro TLB miss" description="Counts the number of stall cycles because of micro TLB misses on the data side"/>
+ <event event="0x86" title="Stalls" name="DMB" description="Counts the number of stall cycles because of the execution of a DMB memory barrier"/>
+ <event event="0x8A" title="Clock" name="Integer core" description="Counts the number of cycles during which the integer core clock is enabled"/>
+ <event event="0x8B" title="Clock" name="Data engine" description="Counts the number of cycles during which the Data Engine clock is enabled"/>
+ <event event="0x90" title="Instructions" name="ISB" description="Counts the number of ISB instructions architecturally executed"/>
+ <event event="0x91" title="Instructions" name="DSB" description="Counts the number of DSB instructions architecturally executed"/>
+ <event event="0x92" title="Instructions" name="DMB" description="Counts the number of DMB instructions speculatively executed"/>
+ <event event="0x93" title="External" name="Interrupts" description="Counts the number of external interrupts executed by the processor"/>
+ <event event="0xA0" title="PLE" name="Cache line rq completed" description="Counts the number of PLE cache line requests completed"/>
+ <event event="0xA1" title="PLE" name="Cache line rq skipped" description="Counts the number of PLE cache line requests skipped"/>
+ <event event="0xA2" title="PLE" name="FIFO flush" description="Counts the number of PLE FIFO flush requests"/>
+ <event event="0xA3" title="PLE" name="Request completed" description="Counts the number of PLE FIFO flush completed"/>
+ <event event="0xA4" title="PLE" name="FIFO overflow" description="Counts the number of PLE FIFO flush overflowed"/>
+ <event event="0xA5" title="PLE" name="Request programmed" description="Counts the number of PLE FIFO flush program requests"/>
+ </category>
+ \ No newline at end of file
diff --git a/daemon/events-L2C-310.xml b/daemon/events-L2C-310.xml
new file mode 100644
index 0000000..100f109
--- /dev/null
+++ b/daemon/events-L2C-310.xml
@@ -0,0 +1,21 @@
+ <counter_set name="L2C-310_cntX">
+ <counter name="L2C-310_cnt0"/>
+ <counter name="L2C-310_cnt1"/>
+ </counter_set>
+ <category name="L2C-310" counter_set="L2C-310_cntX" per_cpu="no">
+ <event event="0x1" title="L2Cache" name="CO" description="Eviction, CastOut, of a line from the L2 cache"/>
+ <event event="0x2" title="L2Cache" name="DRH" description="Data read hit"/>
+ <event event="0x3" title="L2Cache" name="DRREQ" description="Data read request"/>
+ <event event="0x4" title="L2Cache" name="DWHIT" description="Data write hit"/>
+ <event event="0x5" title="L2Cache" name="DWREQ" description="Data write request"/>
+ <event event="0x6" title="L2Cache" name="DWTREQ" description="Data write request with write-through attribute"/>
+ <event event="0x7" title="L2Cache" name="IRHIT" description="Instruction read hit"/>
+ <event event="0x8" title="L2Cache" name="IRREQ" description="Instruction read request"/>
+ <event event="0x9" title="L2Cache" name="WA" description="Write allocate"/>
+ <event event="0xa" title="L2Cache" name="IPFALLOC" description="Allocation of a prefetch generated by L2C-310 into the L2 cache"/>
+ <event event="0xb" title="L2Cache" name="EPFHIT" description="Prefetch hint hits in the L2 cache"/>
+ <event event="0xc" title="L2Cache" name="EPFALLOC" description="Prefetch hint allocated into the L2 cache"/>
+ <event event="0xd" title="L2Cache" name="SRRCVD" description="Speculative read received"/>
+ <event event="0xe" title="L2Cache" name="SRCONF" description="Speculative read confirmed"/>
+ <event event="0xf" title="L2Cache" name="EPFRCVD" description="Prefetch hint received"/>
+ </category>
diff --git a/daemon/events-Linux.xml b/daemon/events-Linux.xml
new file mode 100644
index 0000000..ed50429
--- /dev/null
+++ b/daemon/events-Linux.xml
@@ -0,0 +1,16 @@
+ <category name="Linux">
+ <event counter="Linux_cpuload_user" title="CPU Load" name="User" per_cpu="yes" description="Scheduler CPU Load of User Application" operation="percentage"/>
+ <event counter="Linux_cpuload_system" title="CPU Load" name="System" per_cpu="yes" description="Scheduler CPU Load of System Behavior" operation="percentage"/>
+ <event counter="Linux_irq_softirq" title="Interrupts" name="SoftIRQ" per_cpu="yes" description="Linux SoftIRQ taken"/>
+ <event counter="Linux_irq_irq" title="Interrupts" name="IRQ" per_cpu="yes" description="Linux IRQ taken"/>
+ <event counter="Linux_block_rq_wr" title="Disk IO" name="Write" description="Disk IO Bytes Written"/>
+ <event counter="Linux_block_rq_rd" title="Disk IO" name="Read" description="Disk IO Bytes Read"/>
+ <event counter="Linux_meminfo_memused" title="Memory" name="Used" description="Total used memory size" operation="maximum"/>
+ <event counter="Linux_meminfo_memfree" title="Memory" name="Free" description="Available memory size" operation="maximum"/>
+ <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" description="Memory used by buffers" operation="maximum"/>
+ <event counter="Linux_net_drv" title="Network" name="Gator" description="Network traffic from Gator driver"/>
+ <event counter="Linux_net_rx" title="Network" name="Receive" description="Receive network traffic, excluding effect from Streamline"/>
+ <event counter="Linux_net_tx" title="Network" name="Transmit" description="Transmit network traffic, excluding effect from Streamline"/>
+ <event counter="Linux_sched_switch" title="Scheduler" name="Switch" description="Context switch events"/>
+ </category>
+ \ No newline at end of file
diff --git a/daemon/events-Scorpion.xml b/daemon/events-Scorpion.xml
new file mode 100644
index 0000000..212bfed
--- /dev/null
+++ b/daemon/events-Scorpion.xml
@@ -0,0 +1,113 @@
+ <counter_set name="Scorpion_cntX">
+ <counter name="Scorpion_cnt0"/>
+ <counter name="Scorpion_cnt1"/>
+ <counter name="Scorpion_cnt2"/>
+ <counter name="Scorpion_cnt3"/>
+ </counter_set>
+ <category name="Scorpion" counter_set="Scorpion_cntX" per_cpu="yes">
+ <event counter="Scorpion_ccnt" title="Clock" name="Cycles" 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"/>
+ <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"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Program Counter" name="SW change" description="Software change of PC, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0f" title="Fault" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x11" title="Cycle" name="Cycle" description=""/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x4c" title="Scorpion" name="ICACHE_EXPL_INV" description=""/>
+ <event event="0x4d" title="Scorpion" name="ICACHE_MISS" description=""/>
+ <event event="0x4e" title="Scorpion" name="ICACHE_ACCESS" description=""/>
+ <event event="0x4f" title="Scorpion" name="ICACHE_CACHEREQ_L2" description=""/>
+ <event event="0x50" title="Scorpion" name="ICACHE_NOCACHE_L2" description=""/>
+ <event event="0x51" title="Scorpion" name="HIQUP_NOPED" description=""/>
+ <event event="0x52" title="Scorpion" name="DATA_ABORT" description=""/>
+ <event event="0x53" title="Scorpion" name="IRQ" description=""/>
+ <event event="0x54" title="Scorpion" name="FIQ" description=""/>
+ <event event="0x55" title="Scorpion" name="ALL_EXCPT" description=""/>
+ <event event="0x56" title="Scorpion" name="UNDEF" description=""/>
+ <event event="0x57" title="Scorpion" name="SVC" description=""/>
+ <event event="0x58" title="Scorpion" name="SMC" description=""/>
+ <event event="0x59" title="Scorpion" name="PREFETCH_ABORT" description=""/>
+ <event event="0x5a" title="Scorpion" name="INDEX_CHECK" description=""/>
+ <event event="0x5b" title="Scorpion" name="NULL_CHECK" description=""/>
+ <event event="0x5c" title="Scorpion" name="EXPL_ICIALLU" description=""/>
+ <event event="0x5d" title="Scorpion" name="IMPL_ICIALLU" description=""/>
+ <event event="0x5e" title="Scorpion" name="NONICIALLU_BTAC_INV" description=""/>
+ <event event="0x5f" title="Scorpion" name="ICIMVAU_IMPL_ICIALLU" description=""/>
+ <event event="0x60" title="Scorpion" name="SPIPE_ONLY_CYCLES" description=""/>
+ <event event="0x61" title="Scorpion" name="XPIPE_ONLY_CYCLES" description=""/>
+ <event event="0x62" title="Scorpion" name="DUAL_CYCLES" description=""/>
+ <event event="0x63" title="Scorpion" name="DISPATCH_ANY_CYCLES" description=""/>
+ <event event="0x64" title="Scorpion" name="FIFO_FULLBLK_CMT" description=""/>
+ <event event="0x65" title="Scorpion" name="FAIL_COND_INST" description=""/>
+ <event event="0x66" title="Scorpion" name="PASS_COND_INST" description=""/>
+ <event event="0x67" title="Scorpion" name="ALLOW_VU_CLK" description=""/>
+ <event event="0x68" title="Scorpion" name="VU_IDLE" description=""/>
+ <event event="0x69" title="Scorpion" name="ALLOW_L2_CLK" description=""/>
+ <event event="0x6a" title="Scorpion" name="L2_IDLE" description=""/>
+ <event event="0x6b" title="Scorpion" name="DTLB_IMPL_INV_SCTLR_DACR" description=""/>
+ <event event="0x6c" title="Scorpion" name="DTLB_EXPL_INV" description=""/>
+ <event event="0x6d" title="Scorpion" name="DTLB_MISS" description=""/>
+ <event event="0x6e" title="Scorpion" name="DTLB_ACCESS" description=""/>
+ <event event="0x6f" title="Scorpion" name="ITLB_MISS" description=""/>
+ <event event="0x70" title="Scorpion" name="ITLB_IMPL_INV" description=""/>
+ <event event="0x71" title="Scorpion" name="ITLB_EXPL_INV" description=""/>
+ <event event="0x72" title="Scorpion" name="UTLB_D_MISS" description=""/>
+ <event event="0x73" title="Scorpion" name="UTLB_D_ACCESS" description=""/>
+ <event event="0x74" title="Scorpion" name="UTLB_I_MISS" description=""/>
+ <event event="0x75" title="Scorpion" name="UTLB_I_ACCESS" description=""/>
+ <event event="0x76" title="Scorpion" name="UTLB_INV_ASID" description=""/>
+ <event event="0x77" title="Scorpion" name="UTLB_INV_MVA" description=""/>
+ <event event="0x78" title="Scorpion" name="UTLB_INV_ALL" description=""/>
+ <event event="0x79" title="Scorpion" name="S2_HOLD_RDQ_UNAVAIL" description=""/>
+ <event event="0x7a" title="Scorpion" name="S2_HOLD" description=""/>
+ <event event="0x7b" title="Scorpion" name="S2_HOLD_DEV_OP" description=""/>
+ <event event="0x7c" title="Scorpion" name="S2_HOLD_ORDER" description=""/>
+ <event event="0x7d" title="Scorpion" name="S2_HOLD_BARRIER" description=""/>
+ <event event="0x7e" title="Scorpion" name="VIU_DUAL_CYCLE" description=""/>
+ <event event="0x7f" title="Scorpion" name="VIU_SINGLE_CYCLE" description=""/>
+ <event event="0x80" title="Scorpion" name="VX_PIPE_WAR_STALL_CYCLES" description=""/>
+ <event event="0x81" title="Scorpion" name="VX_PIPE_WAW_STALL_CYCLES" description=""/>
+ <event event="0x82" title="Scorpion" name="VX_PIPE_RAW_STALL_CYCLES" description=""/>
+ <event event="0x83" title="Scorpion" name="VX_PIPE_LOAD_USE_STALL" description=""/>
+ <event event="0x84" title="Scorpion" name="VS_PIPE_WAR_STALL_CYCLES" description=""/>
+ <event event="0x85" title="Scorpion" name="VS_PIPE_WAW_STALL_CYCLES" description=""/>
+ <event event="0x86" title="Scorpion" name="VS_PIPE_RAW_STALL_CYCLES" description=""/>
+ <event event="0x87" title="Scorpion" name="EXCEPTIONS_INV_OPERATION" description=""/>
+ <event event="0x88" title="Scorpion" name="EXCEPTIONS_DIV_BY_ZERO" description=""/>
+ <event event="0x89" title="Scorpion" name="COND_INST_FAIL_VX_PIPE" description=""/>
+ <event event="0x8a" title="Scorpion" name="COND_INST_FAIL_VS_PIPE" description=""/>
+ <event event="0x8b" title="Scorpion" name="EXCEPTIONS_OVERFLOW" description=""/>
+ <event event="0x8c" title="Scorpion" name="EXCEPTIONS_UNDERFLOW" description=""/>
+ <event event="0x8d" title="Scorpion" name="EXCEPTIONS_DENORM" description=""/>
+ <event event="0x8e" title="Scorpion" name="BANK_AB_HIT" description=""/>
+ <event event="0x8f" title="Scorpion" name="BANK_AB_ACCESS" description=""/>
+ <event event="0x90" title="Scorpion" name="BANK_CD_HIT" description=""/>
+ <event event="0x91" title="Scorpion" name="BANK_CD_ACCESS" description=""/>
+ <event event="0x92" title="Scorpion" name="BANK_AB_DSIDE_HIT" description=""/>
+ <event event="0x93" title="Scorpion" name="BANK_AB_DSIDE_ACCESS" description=""/>
+ <event event="0x94" title="Scorpion" name="BANK_CD_DSIDE_HIT" description=""/>
+ <event event="0x95" title="Scorpion" name="BANK_CD_DSIDE_ACCESS" description=""/>
+ <event event="0x96" title="Scorpion" name="BANK_AB_ISIDE_HIT" description=""/>
+ <event event="0x97" title="Scorpion" name="BANK_AB_ISIDE_ACCESS" description=""/>
+ <event event="0x98" title="Scorpion" name="BANK_CD_ISIDE_HIT" description=""/>
+ <event event="0x99" title="Scorpion" name="BANK_CD_ISIDE_ACCESS" description=""/>
+ <event event="0x9a" title="Scorpion" name="ISIDE_RD_WAIT" description=""/>
+ <event event="0x9b" title="Scorpion" name="DSIDE_RD_WAIT" description=""/>
+ <event event="0x9c" title="Scorpion" name="BANK_BYPASS_WRITE" description=""/>
+ <event event="0x9d" title="Scorpion" name="BANK_AB_NON_CASTOUT" description=""/>
+ <event event="0x9e" title="Scorpion" name="BANK_AB_L2_CASTOUT" description=""/>
+ <event event="0x9f" title="Scorpion" name="BANK_CD_NON_CASTOUT" description=""/>
+ <event event="0xa0" title="Scorpion" name="BANK_CD_L2_CASTOUT" description=""/>
+ </category>
+ \ No newline at end of file
diff --git a/daemon/events-ScorpionMP.xml b/daemon/events-ScorpionMP.xml
new file mode 100644
index 0000000..22c93a0
--- /dev/null
+++ b/daemon/events-ScorpionMP.xml
@@ -0,0 +1,96 @@
+ <counter_set name="ScorpionMP_cntX">
+ <counter name="ScorpionMP_cnt0"/>
+ <counter name="ScorpionMP_cnt1"/>
+ <counter name="ScorpionMP_cnt2"/>
+ <counter name="ScorpionMP_cnt3"/>
+ </counter_set>
+ <category name="ScorpionMP" counter_set="ScorpionMP_cntX" per_cpu="yes">
+ <event counter="ScorpionMP_ccnt" title="Clock" name="Cycles" 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"/>
+ <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"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Program Counter" name="SW change" description="Software change of PC, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0f" title="Fault" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x11" title="Cycle" name="Cycle" description=""/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x4c" title="Scorpion" name="ICACHE_EXPL_INV" description=""/>
+ <event event="0x4d" title="Scorpion" name="ICACHE_MISS" description=""/>
+ <event event="0x4e" title="Scorpion" name="ICACHE_ACCESS" description=""/>
+ <event event="0x4f" title="Scorpion" name="ICACHE_CACHEREQ_L2" description=""/>
+ <event event="0x50" title="Scorpion" name="ICACHE_NOCACHE_L2" description=""/>
+ <event event="0x51" title="Scorpion" name="HIQUP_NOPED" description=""/>
+ <event event="0x52" title="Scorpion" name="DATA_ABORT" description=""/>
+ <event event="0x53" title="Scorpion" name="IRQ" description=""/>
+ <event event="0x54" title="Scorpion" name="FIQ" description=""/>
+ <event event="0x55" title="Scorpion" name="ALL_EXCPT" description=""/>
+ <event event="0x56" title="Scorpion" name="UNDEF" description=""/>
+ <event event="0x57" title="Scorpion" name="SVC" description=""/>
+ <event event="0x58" title="Scorpion" name="SMC" description=""/>
+ <event event="0x59" title="Scorpion" name="PREFETCH_ABORT" description=""/>
+ <event event="0x5a" title="Scorpion" name="INDEX_CHECK" description=""/>
+ <event event="0x5b" title="Scorpion" name="NULL_CHECK" description=""/>
+ <event event="0x5c" title="Scorpion" name="EXPL_ICIALLU" description=""/>
+ <event event="0x5d" title="Scorpion" name="IMPL_ICIALLU" description=""/>
+ <event event="0x5e" title="Scorpion" name="NONICIALLU_BTAC_INV" description=""/>
+ <event event="0x5f" title="Scorpion" name="ICIMVAU_IMPL_ICIALLU" description=""/>
+ <event event="0x60" title="Scorpion" name="SPIPE_ONLY_CYCLES" description=""/>
+ <event event="0x61" title="Scorpion" name="XPIPE_ONLY_CYCLES" description=""/>
+ <event event="0x62" title="Scorpion" name="DUAL_CYCLES" description=""/>
+ <event event="0x63" title="Scorpion" name="DISPATCH_ANY_CYCLES" description=""/>
+ <event event="0x64" title="Scorpion" name="FIFO_FULLBLK_CMT" description=""/>
+ <event event="0x65" title="Scorpion" name="FAIL_COND_INST" description=""/>
+ <event event="0x66" title="Scorpion" name="PASS_COND_INST" description=""/>
+ <event event="0x67" title="Scorpion" name="ALLOW_VU_CLK" description=""/>
+ <event event="0x68" title="Scorpion" name="VU_IDLE" description=""/>
+ <event event="0x69" title="Scorpion" name="ALLOW_L2_CLK" description=""/>
+ <event event="0x6a" title="Scorpion" name="L2_IDLE" description=""/>
+ <event event="0x6b" title="Scorpion" name="DTLB_IMPL_INV_SCTLR_DACR" description=""/>
+ <event event="0x6c" title="Scorpion" name="DTLB_EXPL_INV" description=""/>
+ <event event="0x6d" title="Scorpion" name="DTLB_MISS" description=""/>
+ <event event="0x6e" title="Scorpion" name="DTLB_ACCESS" description=""/>
+ <event event="0x6f" title="Scorpion" name="ITLB_MISS" description=""/>
+ <event event="0x70" title="Scorpion" name="ITLB_IMPL_INV" description=""/>
+ <event event="0x71" title="Scorpion" name="ITLB_EXPL_INV" description=""/>
+ <event event="0x72" title="Scorpion" name="UTLB_D_MISS" description=""/>
+ <event event="0x73" title="Scorpion" name="UTLB_D_ACCESS" description=""/>
+ <event event="0x74" title="Scorpion" name="UTLB_I_MISS" description=""/>
+ <event event="0x75" title="Scorpion" name="UTLB_I_ACCESS" description=""/>
+ <event event="0x76" title="Scorpion" name="UTLB_INV_ASID" description=""/>
+ <event event="0x77" title="Scorpion" name="UTLB_INV_MVA" description=""/>
+ <event event="0x78" title="Scorpion" name="UTLB_INV_ALL" description=""/>
+ <event event="0x79" title="Scorpion" name="S2_HOLD_RDQ_UNAVAIL" description=""/>
+ <event event="0x7a" title="Scorpion" name="S2_HOLD" description=""/>
+ <event event="0x7b" title="Scorpion" name="S2_HOLD_DEV_OP" description=""/>
+ <event event="0x7c" title="Scorpion" name="S2_HOLD_ORDER" description=""/>
+ <event event="0x7d" title="Scorpion" name="S2_HOLD_BARRIER" description=""/>
+ <event event="0x7e" title="Scorpion" name="VIU_DUAL_CYCLE" description=""/>
+ <event event="0x7f" title="Scorpion" name="VIU_SINGLE_CYCLE" description=""/>
+ <event event="0x80" title="Scorpion" name="VX_PIPE_WAR_STALL_CYCLES" description=""/>
+ <event event="0x81" title="Scorpion" name="VX_PIPE_WAW_STALL_CYCLES" description=""/>
+ <event event="0x82" title="Scorpion" name="VX_PIPE_RAW_STALL_CYCLES" description=""/>
+ <event event="0x83" title="Scorpion" name="VX_PIPE_LOAD_USE_STALL" description=""/>
+ <event event="0x84" title="Scorpion" name="VS_PIPE_WAR_STALL_CYCLES" description=""/>
+ <event event="0x85" title="Scorpion" name="VS_PIPE_WAW_STALL_CYCLES" description=""/>
+ <event event="0x86" title="Scorpion" name="VS_PIPE_RAW_STALL_CYCLES" description=""/>
+ <event event="0x87" title="Scorpion" name="EXCEPTIONS_INV_OPERATION" description=""/>
+ <event event="0x88" title="Scorpion" name="EXCEPTIONS_DIV_BY_ZERO" description=""/>
+ <event event="0x89" title="Scorpion" name="COND_INST_FAIL_VX_PIPE" description=""/>
+ <event event="0x8a" title="Scorpion" name="COND_INST_FAIL_VS_PIPE" description=""/>
+ <event event="0x8b" title="Scorpion" name="EXCEPTIONS_OVERFLOW" description=""/>
+ <event event="0x8c" title="Scorpion" name="EXCEPTIONS_UNDERFLOW" description=""/>
+ <event event="0x8d" title="Scorpion" name="EXCEPTIONS_DENORM" description=""/>
+ <event event="0x8e" title="ScorpionMP" name="NUM_BARRIERS" description=""/>
+ <event event="0x8f" title="ScorpionMP" name="BARRIER_CYCLES" description=""/>
+ </category>
+ \ No newline at end of file
diff --git a/daemon/events_footer.xml b/daemon/events_footer.xml
new file mode 100644
index 0000000..cd2b446
--- /dev/null
+++ b/daemon/events_footer.xml
@@ -0,0 +1 @@
+</events>
diff --git a/daemon/events_header.xml b/daemon/events_header.xml
new file mode 100644
index 0000000..38ec4c0
--- /dev/null
+++ b/daemon/events_header.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<events>
diff --git a/daemon/main.cpp b/daemon/main.cpp
new file mode 100644
index 0000000..4e8f38b
--- /dev/null
+++ b/daemon/main.cpp
@@ -0,0 +1,252 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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.
+ */
+
+typedef unsigned long long uint64_t;
+#include <stdint.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <ctype.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 "Child.h"
+#include "SessionData.h"
+#include "OlySocket.h"
+#include "Logging.h"
+#include "OlyUtility.h"
+
+#define DEBUG false
+
+extern Child* child;
+extern void handleException();
+int shutdownFilesystem();
+static pthread_mutex_t numSessions_mutex;
+static int numSessions = 0;
+static OlySocket* socket = NULL;
+static bool driverRunningAtStart = false;
+
+struct cmdline_t {
+ int port;
+ char* sessionXML;
+};
+
+void cleanUp() {
+ if (shutdownFilesystem() == -1) {
+ logg->logMessage("Error shutting down gator filesystem");
+ }
+ delete socket;
+ delete util;
+ delete logg;
+}
+
+// CTRL C Signal Handler
+void handler(int signum) {
+ logg->logMessage("Received signal %d, gator daemon exiting", signum);
+ if (numSessions > 0) {
+ // Kill child threads
+ logg->logMessage("Killing process group as %d child was running when signal was received", numSessions);
+ kill(0, SIGINT);
+ }
+
+ cleanUp();
+ exit(0);
+}
+
+// Child exit Signal Handler
+void child_exit(int signum) {
+ int status;
+ int pid = wait(&status);
+ if (pid != -1) {
+ pthread_mutex_lock(&numSessions_mutex);
+ numSessions--;
+ pthread_mutex_unlock(&numSessions_mutex);
+ logg->logMessage("Child process %d exited with status %d", pid, status);
+ }
+}
+
+// retval: -1 = failure; 0 = was already mounted; 1 = successfully mounted
+int mountGatorFS() {
+ // If already mounted,
+ if (access("/dev/gator/buffer", F_OK) != -1)
+ return 0;
+
+ // else, mount the filesystem
+ mkdir("/dev/gator", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ if (mount("nodev", "/dev/gator", "gatorfs", 0, NULL) != 0)
+ return -1;
+ else
+ return 1;
+}
+
+int setupFilesystem() {
+ // Verify root permissions
+ uid_t euid = geteuid();
+ if (euid) {
+ logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
+ handleException();
+ }
+
+ if (mountGatorFS() >= 0) {
+ logg->logMessage("Driver already running at startup");
+ driverRunningAtStart = true;
+ } else {
+ // Load driver
+ char command[512];
+ strcpy(command, "insmod ");
+ if (util->getApplicationFullPath(&command[7], sizeof(command) - 64) != 0) {
+ logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
+ }
+ strcat(command, "gator.ko >/dev/null 2>&1");
+ if (system(command) != 0) {
+ logg->logMessage("Unable to load gator.ko driver with command: %s", command);
+ logg->logError(__FILE__, __LINE__, "Unable to load (insmod) gator.ko driver. %s", DRIVER_ERROR);
+ handleException();
+ }
+
+ if (mountGatorFS() == -1) {
+ logg->logError(__FILE__, __LINE__, "Unable to mount the gator filesystem needed for profiling.");
+ handleException();
+ }
+ }
+
+ return 0;
+}
+
+int shutdownFilesystem() {
+ umount("/dev/gator");
+ if (driverRunningAtStart == true || system("rmmod gator >/dev/null 2>&1") == 0) {
+ return 0;
+ }
+
+ return -1;
+}
+
+struct cmdline_t parseCommandLine(int argc, char** argv) {
+ struct cmdline_t cmdline;
+ cmdline.port = 8080;
+ cmdline.sessionXML = NULL;
+
+ for (int i = 1; i < argc; i++) {
+ // Is the argument a number?
+ if (atoi(argv[i]) > 0) {
+ cmdline.port = atoi(argv[i]);
+ continue;
+ }
+
+ if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0 || strcmp(argv[i], "--help") == 0) {
+ logg->logError(__FILE__, __LINE__,
+ "Streamline gatord version %d. All parameters are optional:\n"
+ "port_number\tport upon which the server listens; default is 8080\n"
+ "session_xml\tfilename of a session xml used for local capture\n"
+ "-v/--version\tversion information\n"
+ "-h/--help\tthis help page\n", PROTOCOL_VERSION);
+ handleException();
+ } else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
+ logg->logError(__FILE__, __LINE__, "Streamline gatord version %d", PROTOCOL_VERSION);
+ handleException();
+ } else {
+ // Assume it is an .xml file
+ cmdline.sessionXML = argv[i];
+ }
+ }
+
+ // Error checking
+ if (cmdline.port != 8080 && cmdline.sessionXML != NULL) {
+ logg->logError(__FILE__, __LINE__, "Only a port or a session xml can be specified, not both");
+ handleException();
+ }
+
+ return cmdline;
+}
+
+// Gator data flow: collector -> collector fifo -> sender
+int main(int argc, char** argv, char *envp[]) {
+ logg = new Logging(DEBUG); // Set up global thread-safe logging
+ util = new OlyUtility(); // Set up global utility class
+
+ prctl(PR_SET_NAME, (unsigned int)&"gatord-main", 0, 0, 0);
+ pthread_mutex_init(&numSessions_mutex, NULL);
+
+ signal(SIGINT, handler);
+ signal(SIGTERM, handler);
+ signal(SIGABRT, handler);
+
+ // Set to high priority
+ setpriority(PRIO_PROCESS, syscall(__NR_gettid), -19);
+
+ // Initialize session data
+ gSessionData.initialize();
+
+ // Parse the command line parameters
+ struct cmdline_t cmdline = parseCommandLine(argc, argv);
+
+ // Call before setting up the SIGCHLD handler, as system() spawns child processes
+ setupFilesystem();
+
+ // Handle child exit codes
+ signal(SIGCHLD, child_exit);
+
+ // Ignore the SIGPIPE signal so that any send to a broken socket will return an error code instead of asserting a signal
+ // Handling the error at the send function call is much easier than trying to do anything intelligent in the sig handler
+ signal(SIGPIPE, SIG_IGN);
+
+ // If the command line argument is a session xml file, no need to open a socket
+ if (cmdline.sessionXML) {
+ child = new Child(cmdline.sessionXML);
+ child->run();
+ delete child;
+ } else {
+ socket = new OlySocket(cmdline.port, true);
+ // Forever loop, can be exited via a signal or exception
+ while (1) {
+ logg->logMessage("Waiting on connection...");
+ socket->acceptConnection();
+
+ int pid = fork();
+ if (pid < 0) {
+ // Error
+ logg->logError(__FILE__, __LINE__, "Fork process failed. Please power cycle the target device if this error persists.");
+ } else if (pid == 0) {
+ // Child
+ strncpy(argv[0],"gatorc",strlen(argv[0])); // rename command line name to gatorc
+ socket->closeServerSocket();
+ child = new Child(socket, numSessions + 1);
+ child->run();
+ delete child;
+ exit(0);
+ } else {
+ // Parent
+ socket->closeSocket();
+
+ pthread_mutex_lock(&numSessions_mutex);
+ numSessions++;
+ pthread_mutex_unlock(&numSessions_mutex);
+
+ // Maximum number of connections is 2
+ int wait = 0;
+ while (numSessions > 1) {
+ // Throttle until one of the children exits before continuing to accept another socket connection
+ logg->logMessage("%d sessions active!", numSessions);
+ if (wait++ >= 10) { // Wait no more than 10 seconds
+ // Kill last created child
+ kill(pid, SIGALRM);
+ break;
+ }
+ sleep(1);
+ }
+ }
+ }
+ }
+
+ cleanUp();
+ return 0;
+}
diff --git a/driver/Makefile b/driver/Makefile
index b3680e1..de59957 100644
--- a/driver/Makefile
+++ b/driver/Makefile
@@ -17,7 +17,8 @@ endif
gator-$(CONFIG_ARM) += gator_events_armv6.o \
gator_events_armv7.o \
- gator_events_pl310.o
+ gator_events_l2c-310.o \
+ gator_events_scorpion.o
$(obj)/gator_main.o: gator_events.h
@@ -40,6 +41,6 @@ all:
$(error)
clean:
- rm -f *.o modules.order Module.symvers gator.ko gator.mod.c
+ rm -f *.o .*.cmd gator_events.h modules.order Module.symvers gator.ko gator.mod.c
endif
diff --git a/driver/gator.h b/driver/gator.h
index 9d802a3..724ae19 100644
--- a/driver/gator.h
+++ b/driver/gator.h
@@ -14,6 +14,16 @@
#include <linux/mm.h>
#include <linux/list.h>
+// cpu ids
+#define ARM1136 0xb36
+#define ARM1156 0xb56
+#define ARM1176 0xb76
+#define ARM11MPCORE 0xb02
+#define CORTEX_A5 0xc05
+#define CORTEX_A8 0xc08
+#define CORTEX_A9 0xc09
+#define CORTEX_A15 0xc0f
+
/******************************************************************************
* Filesystem
******************************************************************************/
@@ -62,6 +72,7 @@ struct gator_interface {
void (*online)(void);
void (*offline)(void);
int (*read)(int **buffer);
+ int (*read64)(long long **buffer);
struct list_head list;
};
@@ -75,5 +86,4 @@ extern u32 gator_cpuid(void);
extern unsigned long gator_net_traffic;
-
#endif // GATOR_H_
diff --git a/driver/gator_annotate.c b/driver/gator_annotate.c
index d8d86af..e096d15 100644
--- a/driver/gator_annotate.c
+++ b/driver/gator_annotate.c
@@ -22,6 +22,7 @@ static char *annotateBuf0;
static char *annotateBuf1;
static int annotatePos;
static int annotateSel;
+static bool collect_annotations = false;
static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
{
@@ -45,16 +46,13 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
if (retval == 0) {
// synchronize shared variables annotateBuf and annotatePos
spin_lock(&annotate_lock);
- if (annotateBuf) {
+ if (collect_annotations && annotateBuf) {
uint32_t tid = current->pid;
- uint32_t tick = gator_master_tick;
uint64_t time = gator_get_time();
uint32_t cpuid = smp_processor_id();
int pos = annotatePos;
pos += gator_write_packed_int(&annotateBuf[pos], tid);
- pos += gator_write_packed_int(&annotateBuf[pos], tick);
- pos += gator_write_packed_int(&annotateBuf[pos], time);
- pos += gator_write_packed_int(&annotateBuf[pos], time >> 32);
+ pos += gator_write_packed_int64(&annotateBuf[pos], time);
pos += gator_write_packed_int(&annotateBuf[pos], cpuid);
pos += gator_write_packed_int(&annotateBuf[pos], size);
memcpy(&annotateBuf[pos], tempBuffer, size);
@@ -81,12 +79,9 @@ static int annotate_release(struct inode *inode, struct file *file)
spin_lock(&annotate_lock);
if (annotateBuf) {
uint32_t tid = current->pid;
- uint32_t tick = gator_master_tick;
int pos = annotatePos;
pos += gator_write_packed_int(&annotateBuf[pos], tid);
- pos += gator_write_packed_int(&annotateBuf[pos], tick);
- pos += gator_write_packed_int(&annotateBuf[pos], 0); // time
- pos += gator_write_packed_int(&annotateBuf[pos], 0); // time
+ pos += gator_write_packed_int64(&annotateBuf[pos], 0); // time
pos += gator_write_packed_int(&annotateBuf[pos], 0); // cpuid
pos += gator_write_packed_int(&annotateBuf[pos], 0); // size
annotatePos = pos;
@@ -118,13 +113,21 @@ static int gator_annotate_init(void)
static int gator_annotate_start(void)
{
- annotatePos = annotateSel = 0;
+ annotateSel = 0;
+ annotatePos = 1;
annotateBuf = annotateBuf0;
+ annotateBuf[0] = FRAME_ANNOTATE;
+ collect_annotations = true;
return 0;
}
static void gator_annotate_stop(void)
{
+ collect_annotations = false;
+}
+
+static void gator_annotate_shutdown(void)
+{
spin_lock(&annotate_lock);
annotateBuf = NULL;
spin_unlock(&annotate_lock);
@@ -141,7 +144,7 @@ static void gator_annotate_exit(void)
static int gator_annotate_ready(void)
{
- return annotatePos && annotateBuf;
+ return annotatePos > 1 && annotateBuf;
}
static int gator_annotate_read(char **buffer)
@@ -158,8 +161,9 @@ static int gator_annotate_read(char **buffer)
spin_lock(&annotate_lock);
len = annotatePos;
- annotatePos = 0;
annotateBuf = annotateSel ? annotateBuf1 : annotateBuf0;
+ annotateBuf[0] = FRAME_ANNOTATE;
+ annotatePos = 1;
spin_unlock(&annotate_lock);
return len;
diff --git a/driver/gator_backtrace.c b/driver/gator_backtrace.c
index 628a18f..b5b0e63 100644
--- a/driver/gator_backtrace.c
+++ b/driver/gator_backtrace.c
@@ -15,7 +15,7 @@ struct frame_tail_eabi {
unsigned long lr;
};
-static void arm_backtrace_eabi(int cpu, struct pt_regs * const regs, unsigned int depth)
+static void arm_backtrace_eabi(int cpu, int buftype, struct pt_regs * const regs, unsigned int depth)
{
#if defined(__arm__)
struct frame_tail_eabi *tail;
@@ -31,7 +31,7 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs * const regs, unsigned in
}
/* entry preamble may not have executed */
- gator_add_trace(cpu, lr);
+ gator_add_trace(cpu, buftype, lr);
/* check tail is valid */
if (fp == 0) {
@@ -49,7 +49,7 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs * const regs, unsigned in
ptrtail = &buftail;
lr = ptrtail[0].lr;
- gator_add_trace(cpu, lr);
+ gator_add_trace(cpu, buftype, lr);
/* frame pointers should progress back up the stack, towards higher addresses */
next = (struct frame_tail_eabi *)(lr - 4);
diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c
index 64be841..a646fb2 100644
--- a/driver/gator_cookies.c
+++ b/driver/gator_cookies.c
@@ -22,7 +22,7 @@ static DEFINE_PER_CPU(int, translate_buffer_read);
static DEFINE_PER_CPU(int, translate_buffer_write);
static DEFINE_PER_CPU(unsigned int *, translate_buffer);
-static inline uint32_t get_cookie(int cpu, struct task_struct *task, struct vm_area_struct *vma, struct module *mod);
+static inline uint32_t get_cookie(int cpu, int buftype, struct task_struct *task, struct vm_area_struct *vma, struct module *mod, bool in_interrupt);
static void wq_cookie_handler(struct work_struct *unused);
DECLARE_WORK(cookie_work, wq_cookie_handler);
@@ -96,7 +96,7 @@ static void cookiemap_add(uint64_t key, uint32_t value) {
for (x = MAX_COLLISIONS-1; x > 0; x--) {
keys[x] = keys[x-1];
- values[x] = keys[x-1];
+ values[x] = values[x-1];
}
keys[0] = key;
values[0] = value;
@@ -126,12 +126,12 @@ static void wq_cookie_handler(struct work_struct *unused)
while (per_cpu(translate_buffer_read, cpu) != commit) {
task = (struct task_struct *)translate_buffer_read_int(cpu);
vma = (struct vm_area_struct *)translate_buffer_read_int(cpu);
- cookie = get_cookie(cpu, task, vma, NULL);
+ cookie = get_cookie(cpu, TIMER_BUF, task, vma, NULL, false);
}
}
// Retrieve full name from proc/pid/cmdline for java processes on Android
-static int translate_app_process(char** text, int cpu, struct task_struct * task, struct vm_area_struct *vma)
+static int translate_app_process(char** text, int cpu, struct task_struct * task, struct vm_area_struct *vma, bool in_interrupt)
{
void *maddr;
unsigned int len;
@@ -143,7 +143,9 @@ static int translate_app_process(char** text, int cpu, struct task_struct * task
char * buf = per_cpu(translate_text, cpu);
// Push work into a work queue if in atomic context as the kernel functions below might sleep
- if (in_irq()) {
+ // Rely on the in_interrupt variable rather than in_irq() or in_interrupt() kernel functions, as the value of these functions seems
+ // inconsistent during a context switch between android/linux versions
+ if (in_interrupt) {
// Check if already in buffer
ptr = per_cpu(translate_buffer_read, cpu);
while (ptr != per_cpu(translate_buffer_write, cpu)) {
@@ -205,7 +207,7 @@ out:
return retval;
}
-static inline uint32_t get_cookie(int cpu, struct task_struct *task, struct vm_area_struct *vma, struct module *mod)
+static inline uint32_t get_cookie(int cpu, int buftype, struct task_struct *task, struct vm_area_struct *vma, struct module *mod, bool in_interrupt)
{
unsigned long flags, cookie;
struct path *path;
@@ -235,26 +237,26 @@ static inline uint32_t get_cookie(int cpu, struct task_struct *task, struct vm_a
}
if (strcmp(text, "app_process") == 0 && !mod) {
- if (!translate_app_process(&text, cpu, task, vma))
+ if (!translate_app_process(&text, cpu, task, vma, in_interrupt))
return INVALID_COOKIE;
}
- // Can be called from interrupt handler or from work queue
+ // Can be called from interrupt handler or from work queue or from scheduler trace
local_irq_save(flags);
cookie = per_cpu(cookie_next_key, cpu)+=nr_cpu_ids;
cookiemap_add(key, cookie);
- gator_buffer_write_packed_int(cpu, PROTOCOL_COOKIE);
- gator_buffer_write_packed_int(cpu, cookie);
- gator_buffer_write_string(cpu, text);
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COOKIE);
+ gator_buffer_write_packed_int(cpu, buftype, cookie);
+ gator_buffer_write_string(cpu, buftype, text);
local_irq_restore(flags);
return cookie;
}
-static int get_exec_cookie(int cpu, struct task_struct *task)
+static int get_exec_cookie(int cpu, int buftype, struct task_struct *task)
{
unsigned long cookie = NO_COOKIE;
struct mm_struct *mm = task->mm;
@@ -268,14 +270,14 @@ static int get_exec_cookie(int cpu, struct task_struct *task)
continue;
if (!(vma->vm_flags & VM_EXECUTABLE))
continue;
- cookie = get_cookie(cpu, task, vma, NULL);
+ cookie = get_cookie(cpu, buftype, task, vma, NULL, true);
break;
}
return cookie;
}
-static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsigned long addr, off_t *offset)
+static unsigned long get_address_cookie(int cpu, int buftype, struct task_struct *task, unsigned long addr, off_t *offset)
{
unsigned long cookie = NO_COOKIE;
struct mm_struct *mm = task->mm;
@@ -289,7 +291,7 @@ static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsig
continue;
if (vma->vm_file) {
- cookie = get_cookie(cpu, task, vma, NULL);
+ cookie = get_cookie(cpu, buftype, task, vma, NULL, true);
*offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
} else {
/* must be an anonymous map */
@@ -318,10 +320,18 @@ static int cookies_initialize(void)
size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t);
per_cpu(cookie_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL);
+ if (!per_cpu(cookie_keys, cpu)) {
+ err = -ENOMEM;
+ goto cookie_setup_error;
+ }
memset(per_cpu(cookie_keys, cpu), 0, size);
size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t);
per_cpu(cookie_values, cpu) = (uint32_t*)kmalloc(size, GFP_KERNEL);
+ if (!per_cpu(cookie_values, cpu)) {
+ err = -ENOMEM;
+ goto cookie_setup_error;
+ }
memset(per_cpu(cookie_values, cpu), 0, size);
per_cpu(translate_buffer, cpu) = (unsigned int *)kmalloc(translate_buffer_size, GFP_KERNEL);
diff --git a/driver/gator_ebs.c b/driver/gator_ebs.c
new file mode 100644
index 0000000..9b55347
--- /dev/null
+++ b/driver/gator_ebs.c
@@ -0,0 +1,160 @@
+/**
+ * Copyright (C) ARM Limited 2011. 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.
+ *
+ */
+
+/******************************************************************************
+ * event based sampling handling
+ ******************************************************************************/
+
+#if defined (__arm__)
+#include "gator_events_armv7.h"
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#if LINUX_PMU_SUPPORT
+#include <asm/pmu.h>
+
+static struct platform_device *pmu_device;
+
+static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg)
+{
+ unsigned int cnt, cpu = smp_processor_id(), buftype = EVENT_BUF;
+ struct pt_regs * const regs = get_irq_regs();
+ u32 flags;
+
+ // Stop irq generation
+ armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
+
+ // Get and reset overflow status flags
+ flags = armv7_pmnc_reset_interrupt();
+
+ // Counters header
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COUNTERS); // type
+ gator_buffer_write_packed_int64(cpu, buftype, gator_get_time()); // time
+
+ // Cycle counter
+ if (flags & (1 << 31)) {
+ int value = armv7_ccnt_read(pmnc_count[CCNT]); // overrun
+ gator_buffer_write_packed_int(cpu, buftype, 2); // length
+ gator_buffer_write_packed_int(cpu, buftype, pmnc_key[CCNT]); // key
+ gator_buffer_write_packed_int(cpu, buftype, value); // value
+ }
+
+ // PMNC counters
+ for (cnt = CNT0; cnt < CNTMAX; cnt++) {
+ if (flags & (1 << (cnt - CNT0))) {
+ int value = armv7_cntn_read(cnt, pmnc_count[cnt]); // overrun
+ gator_buffer_write_packed_int(cpu, buftype, 2); // length
+ gator_buffer_write_packed_int(cpu, buftype, pmnc_key[cnt]); // key
+ gator_buffer_write_packed_int(cpu, buftype, value); // value
+ }
+ }
+
+ // End Counters, length of zero
+ gator_buffer_write_packed_int(cpu, buftype, 0);
+
+ // Output backtrace
+ gator_add_sample(cpu, buftype, regs);
+
+ // Check and commit; commit is set to occur once buffer is 3/4 full
+ event_buffer_check(cpu);
+
+ // Allow irq generation
+ armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+static int gator_event_sampling_start(void)
+{
+ int cnt;
+
+ event_based_sampling = false;
+ for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+ if (pmnc_count[cnt] > 0) {
+ event_based_sampling = true;
+ break;
+ }
+ }
+
+#if LINUX_PMU_SUPPORT
+ pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU);
+ if (IS_ERR(pmu_device) && (unsigned int)pmu_device != -ENODEV) {
+ pr_err("gator: unable to reserve the pmu\n");
+ return -1;
+ }
+
+ if (event_based_sampling) {
+ int irq, i;
+
+ if (IS_ERR(pmu_device)) {
+ pr_err("gator: event based sampling is not supported as the kernel function reserve_pmu() failed");
+ return -1;
+ }
+
+ init_pmu(ARM_PMU_DEVICE_CPU);
+ if (pmu_device->num_resources == 0) {
+ pr_err("gator: no irqs for PMUs defined\n");
+ release_pmu(pmu_device);
+ pmu_device = NULL;
+ return -1;
+ }
+
+ for (i = 0; i < pmu_device->num_resources; ++i) {
+ irq = platform_get_irq(pmu_device, i);
+ if (irq < 0)
+ continue;
+
+ if (request_irq(irq, armv7_pmnc_interrupt, IRQF_DISABLED | IRQF_NOBALANCING, "armpmu", NULL)) {
+ pr_err("gator: unable to request IRQ%d for ARM perf counters\n", irq);
+
+ // clean up and exit
+ for (i = i - 1; i >= 0; --i) {
+ irq = platform_get_irq(pmu_device, i);
+ if (irq >= 0)
+ free_irq(irq, NULL);
+ }
+ release_pmu(pmu_device);
+ pmu_device = NULL;
+ return -1;
+ }
+ }
+ }
+#else
+ if (event_based_sampling) {
+ pr_err("gator: event based sampling only supported in kernel versions 2.6.35 and higher and CONFIG_CPU_HAS_PMU=y\n");
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+static void gator_event_sampling_stop(void)
+{
+#if LINUX_PMU_SUPPORT
+ if (event_based_sampling) {
+ int i, irq;
+ for (i = pmu_device->num_resources - 1; i >= 0; --i) {
+ irq = platform_get_irq(pmu_device, i);
+ if (irq >= 0)
+ free_irq(irq, NULL);
+ }
+ }
+ if (!IS_ERR(pmu_device))
+ release_pmu(pmu_device);
+ pmu_device = NULL;
+#endif
+}
+
+#else
+static int gator_event_sampling_start(void) {return 0;}
+static void gator_event_sampling_stop(void) {}
+#endif
diff --git a/driver/gator_events_armv6.c b/driver/gator_events_armv6.c
index 7b1d875..170f066 100644
--- a/driver/gator_events_armv6.c
+++ b/driver/gator_events_armv6.c
@@ -8,10 +8,6 @@
#include "gator.h"
-#define ARM1136 0xb36
-#define ARM1156 0xb56
-#define ARM1176 0xb76
-
static const char *pmnc_name;
/*
@@ -29,9 +25,10 @@ static const char *pmnc_name;
#define CCNT 2
#define CNTMAX (CCNT+1)
-static int pmnc_count = 0;
+static int pmnc_counters = 0;
static unsigned long pmnc_enabled[CNTMAX];
static unsigned long pmnc_event[CNTMAX];
+static unsigned long pmnc_count[CNTMAX];
static unsigned long pmnc_key[CNTMAX];
static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
@@ -72,7 +69,7 @@ int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
struct dentry *dir;
int i;
- pmnc_count = 3;
+ pmnc_counters = 3;
for (i = PMN0; i <= CCNT; i++) {
char buf[40];
@@ -86,10 +83,11 @@ int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
return -1;
}
gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
+ gatorfs_create_ulong(sb, dir, "count", &pmnc_count[i]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
if (i != CCNT) {
gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
}
- gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
}
return 0;
@@ -119,18 +117,14 @@ static void gator_events_armv6_online(void)
event = pmnc_event[cnt] & 255;
- /*
- * Set event (if destined for PMNx counters)
- */
+ // Set event (if destined for PMNx counters)
if (cnt == PMN0) {
pmnc |= event << 20;
} else if (cnt == PMN1) {
pmnc |= event << 12;
}
- /*
- * Reset counter
- */
+ // Reset counter
armv6_pmnc_reset_counter(cnt);
}
armv6_pmnc_write(pmnc | PMCR_E);
@@ -146,6 +140,20 @@ static void gator_events_armv6_offline(void)
}
}
+static int gator_events_armv6_start(void)
+{
+ int cnt;
+
+ for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+ if (pmnc_count[cnt] > 0) {
+ pr_err("gator: event based sampling not supported on ARM v6 architectures\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
static void gator_events_armv6_stop(void)
{
unsigned int cnt;
@@ -153,6 +161,7 @@ static void gator_events_armv6_stop(void)
for (cnt = PMN0; cnt <= CCNT; cnt++) {
pmnc_enabled[cnt] = 0;
pmnc_event[cnt] = 0;
+ pmnc_count[cnt] = 0;
}
}
@@ -193,6 +202,7 @@ static int gator_events_armv6_read(int **buffer)
static struct gator_interface gator_events_armv6_interface = {
.create_files = gator_events_armv6_create_files,
+ .start = gator_events_armv6_start,
.stop = gator_events_armv6_stop,
.online = gator_events_armv6_online,
.offline = gator_events_armv6_offline,
@@ -209,6 +219,9 @@ int gator_events_armv6_init(void)
case ARM1176:
pmnc_name = "ARM11";
break;
+ case ARM11MPCORE:
+ pmnc_name = "ARM11MPCore";
+ break;
default:
return -1;
}
@@ -216,6 +229,7 @@ int gator_events_armv6_init(void)
for (cnt = PMN0; cnt <= CCNT; cnt++) {
pmnc_enabled[cnt] = 0;
pmnc_event[cnt] = 0;
+ pmnc_count[cnt] = 0;
pmnc_key[cnt] = gator_events_get_key();
}
diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c
index 0f0d7ef..58855f8 100644
--- a/driver/gator_events_armv7.c
+++ b/driver/gator_events_armv7.c
@@ -6,129 +6,116 @@
* published by the Free Software Foundation.
*/
-#include "gator.h"
-
-#define CORTEX_A5 0xc05
-#define CORTEX_A8 0xc08
-#define CORTEX_A9 0xc09
-#define CORTEX_A15 0xc0f
-
-static const char *pmnc_name;
-static int pmnc_count;
-
-// Per-CPU PMNC: config reg
-#define PMNC_E (1 << 0) /* Enable all counters */
-#define PMNC_P (1 << 1) /* Reset all counters */
-#define PMNC_C (1 << 2) /* Cycle counter reset */
-#define PMNC_MASK 0x3f /* Mask for writable bits */
+/* Disabling interrupts
+ * Many of the functions below disable interrupts via local_irq_save(). This disabling of interrupts is done to prevent any race conditions
+ * between multiple entities (e.g. hrtimer interrupts and event based interrupts) calling the same functions. As accessing the pmu involves
+ * several steps (disable, select, read, enable), these steps must be performed atomically. Normal synchronization routines cannot be used
+ * as these functions are being called from interrupt context.
+ */
-// ccnt reg
-#define CCNT_REG (1 << 31)
+#include "gator.h"
+#include "gator_events_armv7.h"
-#define CCNT 0
-#define CNT0 1
-#define CNTMAX (6+1)
+const char *pmnc_name;
+int pmnc_counters;
-static unsigned long pmnc_enabled[CNTMAX];
-static unsigned long pmnc_event[CNTMAX];
-static unsigned long pmnc_key[CNTMAX];
+unsigned long pmnc_enabled[CNTMAX];
+unsigned long pmnc_event[CNTMAX];
+unsigned long pmnc_count[CNTMAX];
+unsigned long pmnc_key[CNTMAX];
static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
-static inline void armv7_pmnc_write(u32 val)
+inline void armv7_pmnc_write(u32 val)
{
val &= PMNC_MASK;
asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
}
-static inline u32 armv7_pmnc_read(void)
+inline u32 armv7_pmnc_read(void)
{
u32 val;
asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
return val;
}
-static inline u32 armv7_ccnt_read(void)
+inline u32 armv7_ccnt_read(u32 reset_value)
{
- u32 zero = 0;
+ unsigned long flags;
+ u32 newval = -reset_value;
u32 den = CCNT_REG;
u32 val;
+ local_irq_save(flags);
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); // read
- asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (zero)); // zero
+ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval));// new value
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
+ local_irq_restore(flags);
return val;
}
-static inline u32 armv7_cntn_read(unsigned int cnt)
+inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value)
{
- u32 zero = 0;
+ unsigned long flags;
+ u32 newval = -reset_value;
u32 sel = (cnt - CNT0);
u32 den = 1 << sel;
- u32 val;
+ u32 oldval;
+ local_irq_save(flags);
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); // select
- asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); // read
- asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (zero)); // zero
+ asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); // read
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval));// new value
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
+ local_irq_restore(flags);
- return val;
+ return oldval;
}
-static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
+static inline void armv7_pmnc_enable_interrupt(unsigned int cnt)
{
- u32 val;
+ u32 val = cnt ? (1 << (cnt - CNT0)) : (1 << 31);
+ asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
+}
- if (cnt >= CNTMAX) {
- pr_err("gator: CPU%u enabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
- return -1;
- }
+static inline void armv7_pmnc_disable_interrupt(unsigned int cnt)
+{
+ u32 val = cnt ? (1 << (cnt - CNT0)) : (1 << 31);
+ asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val));
+}
- if (cnt == CCNT)
- val = CCNT_REG;
- else
- val = (1 << (cnt - CNT0));
+inline u32 armv7_pmnc_reset_interrupt()
+{
+ // Get and reset overflow status flags
+ u32 flags;
+ asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (flags));
+ flags &= 0x8000003f;
+ asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (flags));
+ return flags;
+}
+static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
+{
+ u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG;
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
-
return cnt;
}
static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
{
- u32 val;
-
- if (cnt >= CNTMAX) {
- pr_err("gator: CPU%u disabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
- return -1;
- }
-
- if (cnt == CCNT)
- val = CCNT_REG;
- else
- val = (1 << (cnt - CNT0));
-
+ u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG;
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
-
return cnt;
}
static inline int armv7_pmnc_select_counter(unsigned int cnt)
{
- u32 val;
-
- if ((cnt == CCNT) || (cnt >= CNTMAX)) {
- pr_err("gator: CPU%u selecting wrong PMNC counter %d\n", smp_processor_id(), cnt);
- return -1;
- }
-
- val = (cnt - CNT0);
+ u32 val = (cnt - CNT0);
asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
-
return cnt;
}
@@ -139,37 +126,12 @@ static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
}
}
-static void armv7_pmnc_reset_counter(unsigned int cnt)
-{
- u32 val = 0;
-
- if (cnt == CCNT) {
- armv7_pmnc_disable_counter(cnt);
-
- asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
-
- if (pmnc_enabled[cnt] != 0)
- armv7_pmnc_enable_counter(cnt);
-
- } else if (cnt >= CNTMAX) {
- pr_err("gator: CPU%u resetting wrong PMNC counter %d\n", smp_processor_id(), cnt);
- } else {
- armv7_pmnc_disable_counter(cnt);
-
- if (armv7_pmnc_select_counter(cnt) == cnt)
- asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
-
- if (pmnc_enabled[cnt] != 0)
- armv7_pmnc_enable_counter(cnt);
- }
-}
-
static int gator_events_armv7_create_files(struct super_block *sb, struct dentry *root)
{
struct dentry *dir;
int i;
- for (i = 0; i < pmnc_count; i++) {
+ for (i = 0; i < pmnc_counters; i++) {
char buf[40];
if (i == 0) {
snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
@@ -181,10 +143,11 @@ static int gator_events_armv7_create_files(struct super_block *sb, struct dentry
return -1;
}
gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
+ gatorfs_create_ulong(sb, dir, "count", &pmnc_count[i]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
if (i > 0) {
gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
}
- gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
}
return 0;
@@ -202,6 +165,9 @@ static void gator_events_armv7_online(void)
// Initialize & Reset PMNC: C bit and P bit
armv7_pmnc_write(PMNC_P | PMNC_C);
+ // Reset overflow flags
+ armv7_pmnc_reset_interrupt();
+
for (cnt = CCNT; cnt < CNTMAX; cnt++) {
unsigned long event;
@@ -219,10 +185,16 @@ static void gator_events_armv7_online(void)
if (cnt != CCNT)
armv7_pmnc_write_evtsel(cnt, event);
+ // Enable/disable interrupt
+ if (pmnc_count[cnt] > 0)
+ armv7_pmnc_enable_interrupt(cnt);
+ else
+ armv7_pmnc_disable_interrupt(cnt);
+
// Reset counter
- armv7_pmnc_reset_counter(cnt);
+ cnt ? armv7_cntn_read(cnt, pmnc_count[cnt]) : armv7_ccnt_read(pmnc_count[cnt]);
- // Enable counter, but do not enable interrupt for this counter
+ // Enable counter
armv7_pmnc_enable_counter(cnt);
}
@@ -242,6 +214,7 @@ static void gator_events_armv7_stop(void)
for (cnt = CCNT; cnt < CNTMAX; cnt++) {
pmnc_enabled[cnt] = 0;
pmnc_event[cnt] = 0;
+ pmnc_count[cnt] = 0;
}
}
@@ -250,16 +223,16 @@ static int gator_events_armv7_read(int **buffer)
int cnt, len = 0;
int cpu = smp_processor_id();
- if (!pmnc_count)
+ if (!pmnc_counters)
return 0;
- for (cnt = 0; cnt < pmnc_count; cnt++) {
- if (pmnc_enabled[cnt]) {
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ if (pmnc_enabled[cnt] && pmnc_count[cnt] == 0) {
int value;
if (cnt == CCNT) {
- value = armv7_ccnt_read();
+ value = armv7_ccnt_read(0);
} else {
- value = armv7_cntn_read(cnt);
+ value = armv7_cntn_read(cnt, 0);
}
if (value != per_cpu(perfPrev, cpu)[cnt]) {
per_cpu(perfPrev, cpu)[cnt] = value;
@@ -291,29 +264,30 @@ int gator_events_armv7_init(void)
switch (gator_cpuid()) {
case CORTEX_A5:
pmnc_name = "Cortex-A5";
- pmnc_count = 2;
+ pmnc_counters = 2;
break;
case CORTEX_A8:
pmnc_name = "Cortex-A8";
- pmnc_count = 4;
+ pmnc_counters = 4;
break;
case CORTEX_A9:
pmnc_name = "Cortex-A9";
- pmnc_count = 6;
+ pmnc_counters = 6;
break;
case CORTEX_A15:
pmnc_name = "Cortex-A15";
- pmnc_count = 6;
+ pmnc_counters = 6;
break;
default:
return -1;
}
- pmnc_count++; // CNT[n] + CCNT
+ pmnc_counters++; // CNT[n] + CCNT
for (cnt = CCNT; cnt < CNTMAX; cnt++) {
pmnc_enabled[cnt] = 0;
pmnc_event[cnt] = 0;
+ pmnc_count[cnt] = 0;
pmnc_key[cnt] = gator_events_get_key();
}
diff --git a/driver/gator_events_armv7.h b/driver/gator_events_armv7.h
new file mode 100644
index 0000000..d5e8d6e
--- /dev/null
+++ b/driver/gator_events_armv7.h
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) ARM Limited 2011. 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 GATOR_EVENTS_ARMV7_H_
+#define GATOR_EVENTS_ARMV7_H_
+
+// Per-CPU PMNC: config reg
+#define PMNC_E (1 << 0) /* Enable all counters */
+#define PMNC_P (1 << 1) /* Reset all counters */
+#define PMNC_C (1 << 2) /* Cycle counter reset */
+#define PMNC_MASK 0x3f /* Mask for writable bits */
+
+// ccnt reg
+#define CCNT_REG (1 << 31)
+
+#define CCNT 0
+#define CNT0 1
+#define CNTMAX (6+1)
+
+// Function prototypes
+extern void armv7_pmnc_write(u32 val);
+extern u32 armv7_pmnc_read(void);
+extern u32 armv7_ccnt_read(u32 reset_value);
+extern u32 armv7_cntn_read(unsigned int cnt, u32 reset_value);
+extern u32 armv7_pmnc_reset_interrupt(void);
+
+// Externed variables
+extern unsigned long pmnc_enabled[CNTMAX];
+extern unsigned long pmnc_event[CNTMAX];
+extern unsigned long pmnc_count[CNTMAX];
+extern unsigned long pmnc_key[CNTMAX];
+
+#endif // GATOR_EVENTS_ARMV7_H_
diff --git a/driver/gator_events_l2c-310.c b/driver/gator_events_l2c-310.c
new file mode 100644
index 0000000..96683b3
--- /dev/null
+++ b/driver/gator_events_l2c-310.c
@@ -0,0 +1,182 @@
+/**
+ * l2c310 (L2 Cache Controller) event counters for gator
+ *
+ * Copyright (C) ARM Limited 2010-2011. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include "gator.h"
+
+#define L2C310_COUNTERS_NUM 2
+
+static struct {
+ unsigned long enabled;
+ unsigned long event;
+ unsigned long key;
+} l2c310_counters[L2C310_COUNTERS_NUM];
+
+static int l2c310_buffer[L2C310_COUNTERS_NUM * 2];
+
+static void __iomem *l2c310_base;
+
+
+
+static void gator_events_l2c310_reset_counters(void)
+{
+ u32 val = readl(l2c310_base + L2X0_EVENT_CNT_CTRL);
+
+ val |= ((1 << L2C310_COUNTERS_NUM) - 1) << 1;
+
+ writel(val, l2c310_base + L2X0_EVENT_CNT_CTRL);
+}
+
+
+static int gator_events_l2c310_create_files(struct super_block *sb,
+ struct dentry *root)
+{
+ int i;
+
+ for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
+ char buf[16];
+ struct dentry *dir;
+
+ snprintf(buf, sizeof(buf), "L2C-310_cnt%d", i);
+ dir = gatorfs_mkdir(sb, root, buf);
+ if (WARN_ON(!dir))
+ return -1;
+ gatorfs_create_ulong(sb, dir, "enabled",
+ &l2c310_counters[i].enabled);
+ gatorfs_create_ulong(sb, dir, "event",
+ &l2c310_counters[i].event);
+ gatorfs_create_ro_ulong(sb, dir, "key",
+ &l2c310_counters[i].key);
+ }
+
+ return 0;
+}
+
+static int gator_events_l2c310_start(void)
+{
+ static const unsigned long l2x0_event_cntx_cfg[L2C310_COUNTERS_NUM] = {
+ L2X0_EVENT_CNT0_CFG,
+ L2X0_EVENT_CNT1_CFG,
+ };
+ int i;
+
+ /* Counter event sources */
+ for (i = 0; i < L2C310_COUNTERS_NUM; i++)
+ writel((l2c310_counters[i].event & 0xf) << 2,
+ l2c310_base + l2x0_event_cntx_cfg[i]);
+
+ gator_events_l2c310_reset_counters();
+
+ /* Event counter enable */
+ writel(1, l2c310_base + L2X0_EVENT_CNT_CTRL);
+
+ return 0;
+}
+
+static void gator_events_l2c310_stop(void)
+{
+ /* Event counter disable */
+ writel(0, l2c310_base + L2X0_EVENT_CNT_CTRL);
+}
+
+static int gator_events_l2c310_read(int **buffer)
+{
+ static const unsigned long l2x0_event_cntx_val[L2C310_COUNTERS_NUM] = {
+ L2X0_EVENT_CNT0_VAL,
+ L2X0_EVENT_CNT1_VAL,
+ };
+ int i;
+ int len = 0;
+
+ if (smp_processor_id())
+ return 0;
+
+ for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
+ if (l2c310_counters[i].enabled) {
+ l2c310_buffer[len++] = l2c310_counters[i].key;
+ l2c310_buffer[len++] = readl(l2c310_base +
+ l2x0_event_cntx_val[i]);
+ }
+ }
+
+ /* l2c310 counters are saturating, not wrapping in case of overflow */
+ gator_events_l2c310_reset_counters();
+
+ if (buffer)
+ *buffer = l2c310_buffer;
+
+ return len;
+}
+
+static struct gator_interface gator_events_l2c310_interface = {
+ .create_files = gator_events_l2c310_create_files,
+ .start = gator_events_l2c310_start,
+ .stop = gator_events_l2c310_stop,
+ .read = gator_events_l2c310_read,
+};
+
+static void __maybe_unused gator_events_l2c310_probe(unsigned long phys)
+{
+ if (l2c310_base)
+ return;
+
+ l2c310_base = ioremap(phys, SZ_4K);
+ if (l2c310_base) {
+ u32 cache_id = readl(l2c310_base + L2X0_CACHE_ID);
+
+ if ((cache_id & 0xff0003c0) != 0x410000c0) {
+ iounmap(l2c310_base);
+ l2c310_base = NULL;
+ }
+ }
+}
+
+int gator_events_l2c310_init(void)
+{
+ int i;
+
+ if (gator_cpuid() != CORTEX_A5 && gator_cpuid() != CORTEX_A9)
+ return -1;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+ gator_events_l2c310_probe(0xfe600000);
+#endif
+#if defined(CONFIG_ARCH_S5PV310)
+ gator_events_l2c310_probe(0x10502000);
+#endif
+#if defined(CONFIG_ARCH_OMAP4)
+ gator_events_l2c310_probe(0x48242000);
+#endif
+#if defined(CONFIG_ARCH_TEGRA)
+ gator_events_l2c310_probe(0x50043000);
+#endif
+#if defined(CONFIG_ARCH_U8500)
+ gator_events_l2c310_probe(0xa0412000);
+#endif
+#if defined(CONFIG_ARCH_VEXPRESS)
+ // A9x4 core tile (HBI-0191)
+ gator_events_l2c310_probe(0x1e00a000);
+ // New memory map tiles
+ gator_events_l2c310_probe(0x2c0f0000);
+#endif
+ if (!l2c310_base)
+ return -1;
+
+ for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
+ l2c310_counters[i].enabled = 0;
+ l2c310_counters[i].key = gator_events_get_key();
+ }
+
+ return gator_events_install(&gator_events_l2c310_interface);
+}
+gator_events_init(gator_events_l2c310_init);
diff --git a/driver/gator_events_meminfo.c b/driver/gator_events_meminfo.c
index f1595bd..a1a2031 100644
--- a/driver/gator_events_meminfo.c
+++ b/driver/gator_events_meminfo.c
@@ -19,7 +19,7 @@
static ulong meminfo_global_enabled;
static ulong meminfo_enabled[MEMINFO_TOTAL];
static ulong meminfo_key[MEMINFO_TOTAL];
-static int meminfo_buffer[MEMINFO_TOTAL * 2];
+static unsigned long long meminfo_buffer[MEMINFO_TOTAL * 2];
static int meminfo_length = 0;
static unsigned int mem_event = 0;
static bool new_data_avail;
@@ -120,7 +120,8 @@ static void gator_events_meminfo_stop(void)
static void wq_sched_handler(struct work_struct *wsptr)
{
struct sysinfo info;
- int i, len, value;
+ int i, len;
+ unsigned long long value;
meminfo_length = len = 0;
@@ -141,7 +142,7 @@ static void wq_sched_handler(struct work_struct *wsptr)
value = 0;
break;
}
- meminfo_buffer[len++] = meminfo_key[i];
+ meminfo_buffer[len++] = (unsigned long long)meminfo_key[i];
meminfo_buffer[len++] = value;
}
}
@@ -150,7 +151,7 @@ static void wq_sched_handler(struct work_struct *wsptr)
new_data_avail = true;
}
-static int gator_events_meminfo_read(int **buffer)
+static int gator_events_meminfo_read(long long **buffer)
{
static unsigned int last_mem_event = 0;
@@ -177,7 +178,7 @@ static struct gator_interface gator_events_meminfo_interface = {
.create_files = gator_events_meminfo_create_files,
.start = gator_events_meminfo_start,
.stop = gator_events_meminfo_stop,
- .read = gator_events_meminfo_read,
+ .read64 = gator_events_meminfo_read,
};
int gator_events_meminfo_init(void)
diff --git a/driver/gator_events_pl310.c b/driver/gator_events_pl310.c
deleted file mode 100644
index 0ef0cf3..0000000
--- a/driver/gator_events_pl310.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/**
- * PL310 (L2 Cache Controller) event counters for gator
- *
- * Copyright (C) ARM Limited 2010-2011. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/hardware/cache-l2x0.h>
-
-#include "gator.h"
-
-#define PL310_COUNTERS_NUM 2
-
-static struct {
- unsigned long enabled;
- unsigned long event;
- unsigned long key;
-} pl310_counters[PL310_COUNTERS_NUM];
-
-static int pl310_buffer[PL310_COUNTERS_NUM * 2];
-
-static void __iomem *pl310_base;
-
-
-
-static void gator_events_pl310_reset_counters(void)
-{
- u32 val = readl(pl310_base + L2X0_EVENT_CNT_CTRL);
-
- val |= ((1 << PL310_COUNTERS_NUM) - 1) << 1;
-
- writel(val, pl310_base + L2X0_EVENT_CNT_CTRL);
-}
-
-
-static int gator_events_pl310_create_files(struct super_block *sb,
- struct dentry *root)
-{
- int i;
-
- for (i = 0; i < PL310_COUNTERS_NUM; i++) {
- char buf[16];
- struct dentry *dir;
-
- snprintf(buf, sizeof(buf), "PL310_cnt%d", i);
- dir = gatorfs_mkdir(sb, root, buf);
- if (WARN_ON(!dir))
- return -1;
- gatorfs_create_ulong(sb, dir, "enabled",
- &pl310_counters[i].enabled);
- gatorfs_create_ulong(sb, dir, "event",
- &pl310_counters[i].event);
- gatorfs_create_ro_ulong(sb, dir, "key",
- &pl310_counters[i].key);
- }
-
- return 0;
-}
-
-static int gator_events_pl310_start(void)
-{
- static const unsigned long l2x0_event_cntx_cfg[PL310_COUNTERS_NUM] = {
- L2X0_EVENT_CNT0_CFG,
- L2X0_EVENT_CNT1_CFG,
- };
- int i;
-
- /* Counter event sources */
- for (i = 0; i < PL310_COUNTERS_NUM; i++)
- writel((pl310_counters[i].event & 0xf) << 2,
- pl310_base + l2x0_event_cntx_cfg[i]);
-
- gator_events_pl310_reset_counters();
-
- /* Event counter enable */
- writel(1, pl310_base + L2X0_EVENT_CNT_CTRL);
-
- return 0;
-}
-
-static void gator_events_pl310_stop(void)
-{
- /* Event counter disable */
- writel(0, pl310_base + L2X0_EVENT_CNT_CTRL);
-}
-
-static int gator_events_pl310_read(int **buffer)
-{
- static const unsigned long l2x0_event_cntx_val[PL310_COUNTERS_NUM] = {
- L2X0_EVENT_CNT0_VAL,
- L2X0_EVENT_CNT1_VAL,
- };
- int i;
- int len = 0;
-
- if (smp_processor_id())
- return 0;
-
- for (i = 0; i < PL310_COUNTERS_NUM; i++) {
- if (pl310_counters[i].enabled) {
- pl310_buffer[len++] = pl310_counters[i].key;
- pl310_buffer[len++] = readl(pl310_base +
- l2x0_event_cntx_val[i]);
- }
- }
-
- /* PL310 counters are saturating, not wrapping in case of overflow */
- gator_events_pl310_reset_counters();
-
- if (buffer)
- *buffer = pl310_buffer;
-
- return len;
-}
-
-static struct gator_interface gator_events_pl310_interface = {
- .create_files = gator_events_pl310_create_files,
- .start = gator_events_pl310_start,
- .stop = gator_events_pl310_stop,
- .read = gator_events_pl310_read,
-};
-
-static void __maybe_unused gator_events_pl310_probe(unsigned long phys)
-{
- if (pl310_base)
- return;
-
- pl310_base = ioremap(phys, SZ_4K);
- if (pl310_base) {
- u32 cache_id = readl(pl310_base + L2X0_CACHE_ID);
-
- if ((cache_id & 0xff0003c0) != 0x410000c0) {
- iounmap(pl310_base);
- pl310_base = NULL;
- }
- }
-}
-
-int gator_events_pl310_init(void)
-{
- int i;
-
-#if defined(CONFIG_ARCH_EXYNOS4)
- gator_events_pl310_probe(0xfe600000);
-#endif
-#if defined(CONFIG_ARCH_OMAP4)
- gator_events_pl310_probe(0x48242000);
-#endif
-#if defined(CONFIG_ARCH_TEGRA)
- gator_events_pl310_probe(0x50043000);
-#endif
-#if defined(CONFIG_ARCH_U8500)
- gator_events_pl310_probe(0xa0412000);
-#endif
-#if defined(CONFIG_ARCH_VEXPRESS) && !defined(CONFIG_ARCH_VEXPRESS_CA15X4)
- // A9x4 core tile (HBI-0191)
- gator_events_pl310_probe(0x1e00a000);
- // New memory map tiles
- gator_events_pl310_probe(0x2c0f0000);
-#endif
- if (!pl310_base)
- return -1;
-
- for (i = 0; i < PL310_COUNTERS_NUM; i++) {
- pl310_counters[i].enabled = 0;
- pl310_counters[i].key = gator_events_get_key();
- }
-
- return gator_events_install(&gator_events_pl310_interface);
-}
-gator_events_init(gator_events_pl310_init);
diff --git a/driver/gator_events_scorpion.c b/driver/gator_events_scorpion.c
index d831a50..f51e292 100644
--- a/driver/gator_events_scorpion.c
+++ b/driver/gator_events_scorpion.c
@@ -12,7 +12,7 @@
#define SCORPIONMP 0x2d
static const char *pmnc_name;
-static int pmnc_count;
+static int pmnc_counters;
// Per-CPU PMNC: config reg
#define PMNC_E (1 << 0) /* Enable all counters */
@@ -32,6 +32,7 @@ static int pmnc_count;
static unsigned long pmnc_enabled[CNTMAX];
static unsigned long pmnc_event[CNTMAX];
+static unsigned long pmnc_count[CNTMAX];
static unsigned long pmnc_key[CNTMAX];
static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
@@ -209,6 +210,10 @@ static const struct scorp_evt sc_evt[] = {
{SCORPION_EXCEPTIONS_UNDERFLOW, 0x80000c00, 4, 0x5d},
{SCORPION_EXCEPTIONS_DENORM, 0x8c000000, 4, 0x5f},
+#ifdef CONFIG_ARCH_MSM_SCORPIONMP
+ {SCORPIONMP_NUM_BARRIERS, 0x80000e00, 3, 0x59},
+ {SCORPIONMP_BARRIER_CYCLES, 0x800e0000, 3, 0x5a},
+#else
{SCORPION_BANK_AB_HIT, 0x80000001, 3, 0x58},
{SCORPION_BANK_AB_ACCESS, 0x80000100, 3, 0x59},
{SCORPION_BANK_CD_HIT, 0x80010000, 3, 0x5a},
@@ -228,6 +233,7 @@ static const struct scorp_evt sc_evt[] = {
{SCORPION_BANK_AB_L2_CASTOUT, 0x80000c00, 3, 0x59},
{SCORPION_BANK_CD_NON_CASTOUT, 0x800c0000, 3, 0x5a},
{SCORPION_BANK_CD_L2_CASTOUT, 0x8c000000, 3, 0x5b},
+#endif
};
static inline void scorpion_pmnc_write(u32 val)
@@ -498,7 +504,7 @@ static int gator_events_scorpion_create_files(struct super_block *sb, struct den
struct dentry *dir;
int i;
- for (i = 0; i < pmnc_count; i++) {
+ for (i = 0; i < pmnc_counters; i++) {
char buf[40];
if (i == 0) {
snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
@@ -510,10 +516,11 @@ static int gator_events_scorpion_create_files(struct super_block *sb, struct den
return -1;
}
gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
+ gatorfs_create_ulong(sb, dir, "count", &pmnc_count[i]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
if (i > 0) {
gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
}
- gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
}
return 0;
@@ -565,6 +572,20 @@ static void gator_events_scorpion_offline(void)
// investigate: need to do the clearpmu() here on each counter?
}
+static int gator_events_scorpion_start(void)
+{
+ int cnt;
+
+ for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+ if (pmnc_count[cnt] > 0) {
+ pr_err("gator: event based sampling not supported on Scorpion cores\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
static void gator_events_scorpion_stop(void)
{
unsigned int cnt;
@@ -572,6 +593,7 @@ static void gator_events_scorpion_stop(void)
for (cnt = CCNT; cnt < CNTMAX; cnt++) {
pmnc_enabled[cnt] = 0;
pmnc_event[cnt] = 0;
+ pmnc_count[cnt] = 0;
}
}
@@ -580,10 +602,10 @@ static int gator_events_scorpion_read(int **buffer)
int cnt, len = 0;
int cpu = smp_processor_id();
- if (!pmnc_count)
+ if (!pmnc_counters)
return 0;
- for (cnt = 0; cnt < pmnc_count; cnt++) {
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
if (pmnc_enabled[cnt]) {
int value;
if (cnt == CCNT) {
@@ -611,6 +633,7 @@ static int gator_events_scorpion_read(int **buffer)
static struct gator_interface gator_events_scorpion_interface = {
.create_files = gator_events_scorpion_create_files,
+ .start = gator_events_scorpion_start,
.stop = gator_events_scorpion_stop,
.online = gator_events_scorpion_online,
.offline = gator_events_scorpion_offline,
@@ -636,21 +659,22 @@ int gator_events_scorpion_init(void)
switch (gator_cpuid()) {
case SCORPION:
pmnc_name = "Scorpion";
- pmnc_count = 4;
+ pmnc_counters = 4;
break;
case SCORPIONMP:
pmnc_name = "ScorpionMP";
- pmnc_count = 4;
+ pmnc_counters = 4;
break;
default:
return -1;
}
- pmnc_count++; // CNT[n] + CCNT
+ pmnc_counters++; // CNT[n] + CCNT
for (cnt = CCNT; cnt < CNTMAX; cnt++) {
pmnc_enabled[cnt] = 0;
pmnc_event[cnt] = 0;
+ pmnc_count[cnt] = 0;
pmnc_key[cnt] = gator_events_get_key();
}
diff --git a/driver/gator_main.c b/driver/gator_main.c
index 340756e..87e7f2a 100644
--- a/driver/gator_main.c
+++ b/driver/gator_main.c
@@ -7,7 +7,7 @@
*
*/
-static unsigned long gator_protocol_version = 5;
+static unsigned long gator_protocol_version = 6;
#include <linux/slab.h>
#include <linux/cpu.h>
@@ -36,11 +36,13 @@ static unsigned long gator_protocol_version = 5;
#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined
#endif
+#if defined (__arm__)
#ifdef CONFIG_SMP
#ifndef CONFIG_LOCAL_TIMERS
#error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems
#endif
#endif
+#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
#error kernels prior to 2.6.32 are not supported
@@ -49,22 +51,24 @@ static unsigned long gator_protocol_version = 5;
/******************************************************************************
* DEFINES
******************************************************************************/
-#define BUFFER_SIZE_DEFAULT (256*1024)
-#define SYNC_FREQ_DEFAULT 1000
+#define TIMER_BUFFER_SIZE_DEFAULT (256*1024)
+#define EVENT_BUFFER_SIZE_DEFAULT (128*1024)
#define NO_COOKIE 0UL
#define INVALID_COOKIE ~0UL
-#define PROTOCOL_FRAME ~0
-#define PROTOCOL_START_TICK 1
-#define PROTOCOL_END_TICK 3
-#define PROTOCOL_START_BACKTRACE 5
-#define PROTOCOL_END_BACKTRACE 7
-#define PROTOCOL_COOKIE 9
-#define PROTOCOL_SCHEDULER_TRACE 11
-#define PROTOCOL_COUNTERS 13
-#define PROTOCOL_ANNOTATE 15
-#define PROTOCOL_CPU_SYNC 17
+#define FRAME_HRTIMER 1
+#define FRAME_EVENT 2
+#define FRAME_ANNOTATE 3
+
+#define MESSAGE_COOKIE 1
+#define MESSAGE_COUNTERS 3
+#define MESSAGE_START_BACKTRACE 5
+#define MESSAGE_END_BACKTRACE 7
+#define MESSAGE_SCHEDULER_TRACE 9
+#define MESSAGE_PID_NAME 11
+
+#define LINUX_PMU_SUPPORT LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) && defined(CONFIG_CPU_HAS_PMU)
#if defined(__arm__)
#define PC_REG regs->ARM_pc
@@ -72,42 +76,50 @@ static unsigned long gator_protocol_version = 5;
#define PC_REG regs->ip
#endif
+enum {TIMER_BUF, EVENT_BUF, NUM_GATOR_BUFS};
+
/******************************************************************************
- * PER CPU
+ * Globals
******************************************************************************/
static unsigned long gator_cpu_cores;
-static unsigned long gator_buffer_size;
+static unsigned long userspace_buffer_size;
static unsigned long gator_backtrace_depth;
static unsigned long gator_started;
static unsigned long gator_buffer_opened;
static unsigned long gator_timer_count;
static unsigned long gator_streaming;
-static int gator_master_tick;
static DEFINE_MUTEX(start_mutex);
static DEFINE_MUTEX(gator_buffer_mutex);
unsigned long gator_net_traffic;
+bool event_based_sampling;
#define COMMIT_SIZE 128
#define COMMIT_MASK (COMMIT_SIZE-1)
-static DEFINE_SPINLOCK(gator_commit_lock);
-static int *gator_commit;
-static int gator_commit_read;
-static int gator_commit_write;
+static DEFINE_SPINLOCK(timer_commit_lock);
+static int *gator_commit[NUM_GATOR_BUFS];
+static int gator_commit_read[NUM_GATOR_BUFS];
+static int gator_commit_write[NUM_GATOR_BUFS];
static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
-static DEFINE_PER_CPU(int, gator_cpu_sync);
-static DEFINE_PER_CPU(int, gator_cpu_tick);
static DEFINE_PER_CPU(int, gator_first_time);
+#if LINUX_PMU_SUPPORT
+static void event_buffer_check(int cpu);
+static DEFINE_SPINLOCK(event_commit_lock);
+#endif
+
/******************************************************************************
* Prototypes
******************************************************************************/
-static void gator_buffer_write_packed_int(int cpu, unsigned int x);
-static void gator_buffer_write_string(int cpu, char *x);
+static void gator_buffer_write_packed_int(int cpu, int buftype, unsigned int x);
+static void gator_buffer_write_packed_int64(int cpu, int buftype, unsigned long long x);
+static void gator_buffer_write_string(int cpu, int buftype, char *x);
static int gator_write_packed_int(char *buffer, unsigned int x);
-static void gator_add_trace(int cpu, unsigned int address);
+static int gator_write_packed_int64(char *buffer, unsigned long long x);
+static void gator_add_trace(int cpu, int buftype, unsigned int address);
+static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs);
static uint64_t gator_get_time(void);
/******************************************************************************
@@ -118,6 +130,7 @@ static uint64_t gator_get_time(void);
#include "gator_backtrace.c"
#include "gator_annotate.c"
#include "gator_fs.c"
+#include "gator_ebs.c"
/******************************************************************************
* Misc
@@ -134,204 +147,137 @@ u32 gator_cpuid(void)
/******************************************************************************
* Commit interface
******************************************************************************/
-static int buffer_commit_ready(void)
+static int buffer_commit_ready(int buftype)
{
- return (gator_commit_read != gator_commit_write);
+ return gator_commit_read[buftype] != gator_commit_write[buftype];
}
-static void buffer_commit_read(int *cpu, int *readval, int *writeval)
+static void buffer_commit_read(int *cpu, int buftype, int *readval, int *writeval)
{
- int read = gator_commit_read;
- *cpu = gator_commit[read+0];
- *readval = gator_commit[read+1];
- *writeval = gator_commit[read+2];
- gator_commit_read = (read + 4) & COMMIT_MASK;
+ int read = gator_commit_read[buftype];
+ *cpu = gator_commit[buftype][read+0];
+ *readval = gator_commit[buftype][read+1];
+ *writeval = gator_commit[buftype][read+2];
+ gator_commit_read[buftype] = (read + 4) & COMMIT_MASK;
}
-static void buffer_commit_write(int cpu, int readval, int writeval) {
- int write = gator_commit_write;
- gator_commit[write+0] = cpu;
- gator_commit[write+1] = readval;
- gator_commit[write+2] = writeval;
- gator_commit_write = (write + 4) & COMMIT_MASK;
+static void buffer_commit_write(int cpu, int buftype, int readval, int writeval) {
+ int write = gator_commit_write[buftype];
+ gator_commit[buftype][write+0] = cpu;
+ gator_commit[buftype][write+1] = readval;
+ gator_commit[buftype][write+2] = writeval;
+ gator_commit_write[buftype] = (write + 4) & COMMIT_MASK;
}
/******************************************************************************
* Buffer management
******************************************************************************/
-static uint32_t use_buffer_size;
-static uint32_t use_buffer_mask;
-static DEFINE_PER_CPU(int, use_buffer_seq);
-static DEFINE_PER_CPU(int, use_buffer_read);
-static DEFINE_PER_CPU(int, use_buffer_write);
-static DEFINE_PER_CPU(char *, use_buffer);
-
-static void gator_buffer_write_packed_int(int cpu, unsigned int x)
-{
- uint32_t write = per_cpu(use_buffer_write, cpu);
- uint32_t mask = use_buffer_mask;
- char *buffer = per_cpu(use_buffer, cpu);
- int write0 = (write + 0) & mask;
- int write1 = (write + 1) & mask;
- int write2 = (write + 2) & mask;
- int write3 = (write + 3) & mask;
- int write4 = (write + 4) & mask;
- int write5 = (write + 5) & mask;
-
- if ((x & 0xffffff80) == 0) {
- buffer[write0] = x & 0x7f;
- per_cpu(use_buffer_write, cpu) = write1;
- } else if ((x & 0xffffc000) == 0) {
- buffer[write0] = x | 0x80;
- buffer[write1] = (x>>7) & 0x7f;
- per_cpu(use_buffer_write, cpu) = write2;
- } else if ((x & 0xffe00000) == 0) {
- buffer[write0] = x | 0x80;
- buffer[write1] = (x>>7) | 0x80;
- buffer[write2] = (x>>14) & 0x7f;
- per_cpu(use_buffer_write, cpu) = write3;
- } else if ((x & 0xf0000000) == 0) {
- buffer[write0] = x | 0x80;
- buffer[write1] = (x>>7) | 0x80;
- buffer[write2] = (x>>14) | 0x80;
- buffer[write3] = (x>>21) & 0x7f;
- per_cpu(use_buffer_write, cpu) = write4;
- } else {
- buffer[write0] = x | 0x80;
- buffer[write1] = (x>>7) | 0x80;
- buffer[write2] = (x>>14) | 0x80;
- buffer[write3] = (x>>21) | 0x80;
- buffer[write4] = (x>>28) & 0x0f;
- per_cpu(use_buffer_write, cpu) = write5;
- }
-}
+static uint32_t gator_buffer_size[NUM_GATOR_BUFS];
+static uint32_t gator_buffer_mask[NUM_GATOR_BUFS];
+static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_read);
+static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_write);
+static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer);
+#include "gator_pack.c"
-static int gator_write_packed_int(char *buffer, unsigned int x)
+static void gator_buffer_write_bytes(int cpu, int buftype, char *x, int len)
{
- if ((x & 0xffffff80) == 0) {
- buffer[0] = x & 0x7f;
- return 1;
- } else if ((x & 0xffffc000) == 0) {
- buffer[0] = x | 0x80;
- buffer[1] = (x>>7) & 0x7f;
- return 2;
- } else if ((x & 0xffe00000) == 0) {
- buffer[0] = x | 0x80;
- buffer[1] = (x>>7) | 0x80;
- buffer[2] = (x>>14) & 0x7f;
- return 3;
- } else if ((x & 0xf0000000) == 0) {
- buffer[0] = x | 0x80;
- buffer[1] = (x>>7) | 0x80;
- buffer[2] = (x>>14) | 0x80;
- buffer[3] = (x>>21) & 0x7f;
- return 4;
- } else {
- buffer[0] = x | 0x80;
- buffer[1] = (x>>7) | 0x80;
- buffer[2] = (x>>14) | 0x80;
- buffer[3] = (x>>21) | 0x80;
- buffer[4] = (x>>28) & 0x0f;
- return 5;
- }
-}
-
-static void gator_buffer_write_bytes(int cpu, char *x, int len)
-{
- uint32_t write = per_cpu(use_buffer_write, cpu);
- uint32_t mask = use_buffer_mask;
- char *buffer = per_cpu(use_buffer, cpu);
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(use_buffer_write, cpu) = write;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write;
}
-static void gator_buffer_write_string(int cpu, char *x)
+static void gator_buffer_write_string(int cpu, int buftype, char *x)
{
int len = strlen(x);
- gator_buffer_write_packed_int(cpu, len);
- gator_buffer_write_bytes(cpu, x, len);
+ gator_buffer_write_packed_int(cpu, buftype, len);
+ gator_buffer_write_bytes(cpu, buftype, x, len);
}
-static void gator_buffer_header(int cpu)
+static void gator_buffer_header(int cpu, int buftype)
{
- gator_buffer_write_packed_int(cpu, PROTOCOL_FRAME);
- gator_buffer_write_packed_int(cpu, cpu);
- gator_buffer_write_packed_int(cpu, per_cpu(use_buffer_seq, cpu));
- per_cpu(use_buffer_seq, cpu)++;
+ int frame;
+
+ if (buftype == TIMER_BUF)
+ frame = FRAME_HRTIMER;
+ else if (buftype == EVENT_BUF)
+ frame = FRAME_EVENT;
+ else
+ frame = -1;
+
+ gator_buffer_write_packed_int(cpu, buftype, frame);
+ gator_buffer_write_packed_int(cpu, buftype, cpu);
}
-static void gator_buffer_commit(int cpu)
+static void gator_buffer_commit(int cpu, int buftype)
{
- buffer_commit_write(cpu, per_cpu(use_buffer_read, cpu), per_cpu(use_buffer_write, cpu));
- per_cpu(use_buffer_read, cpu) = per_cpu(use_buffer_write, cpu);
- gator_buffer_header(cpu);
+ buffer_commit_write(cpu, buftype, per_cpu(gator_buffer_read, cpu)[buftype], per_cpu(gator_buffer_write, cpu)[buftype]);
+ per_cpu(gator_buffer_read, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
+ gator_buffer_header(cpu, buftype);
wake_up(&gator_buffer_wait);
}
-static void gator_buffer_check(int cpu, int tick)
+static void timer_buffer_check(int cpu)
{
- if (!(tick % gator_timer_count)) {
- int c, sync;
- spin_lock(&gator_commit_lock);
- // synchronize, if all online cpus have the same tick waypoint
- sync = per_cpu(gator_cpu_sync, cpu) = per_cpu(gator_cpu_tick, cpu);
- for_each_online_cpu(c) {
- if (sync != per_cpu(gator_cpu_sync, c)) {
- sync = 0;
- break;
- }
- }
- if (sync) {
- gator_buffer_write_packed_int(cpu, PROTOCOL_CPU_SYNC);
- }
- gator_buffer_commit(cpu);
- spin_unlock(&gator_commit_lock);
- } else {
- int available = per_cpu(use_buffer_write, cpu) - per_cpu(use_buffer_read, cpu);
- if (available < 0) {
- available += use_buffer_size;
- }
- if (available >= ((use_buffer_size * 3) / 4)) {
- spin_lock(&gator_commit_lock);
- gator_buffer_commit(cpu);
- spin_unlock(&gator_commit_lock);
- }
+ int available = per_cpu(gator_buffer_write, cpu)[TIMER_BUF] - per_cpu(gator_buffer_read, cpu)[TIMER_BUF];
+ if (available < 0) {
+ available += gator_buffer_size[TIMER_BUF];
+ }
+ if (available >= ((gator_buffer_size[TIMER_BUF] * 3) / 4)) {
+ spin_lock(&timer_commit_lock);
+ gator_buffer_commit(cpu, TIMER_BUF);
+ spin_unlock(&timer_commit_lock);
+ }
+}
+
+#if LINUX_PMU_SUPPORT
+static void event_buffer_check(int cpu)
+{
+ int available = per_cpu(gator_buffer_write, cpu)[EVENT_BUF] - per_cpu(gator_buffer_read, cpu)[EVENT_BUF];
+ if (available < 0) {
+ available += gator_buffer_size[EVENT_BUF];
+ }
+ if (available >= ((gator_buffer_size[EVENT_BUF] * 3) / 4)) {
+ spin_lock(&event_commit_lock);
+ gator_buffer_commit(cpu, EVENT_BUF);
+ spin_unlock(&event_commit_lock);
}
}
+#endif
-static void gator_add_trace(int cpu, unsigned int address)
+static void gator_add_trace(int cpu, int buftype, unsigned int address)
{
off_t offset = 0;
- unsigned long cookie = get_address_cookie(cpu, current, address & ~1, &offset);
+ unsigned long cookie = get_address_cookie(cpu, buftype, current, address & ~1, &offset);
if (cookie == NO_COOKIE || cookie == INVALID_COOKIE) {
offset = address;
}
- gator_buffer_write_packed_int(cpu, offset & ~1);
- gator_buffer_write_packed_int(cpu, cookie);
+ gator_buffer_write_packed_int(cpu, buftype, offset & ~1);
+ gator_buffer_write_packed_int(cpu, buftype, cookie);
}
-static void gator_add_sample(int cpu, struct pt_regs * const regs)
+static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs)
{
struct module *mod;
unsigned int addr, cookie = 0;
int inKernel = regs ? !user_mode(regs) : 1;
- unsigned long exec_cookie = !inKernel ? get_exec_cookie(cpu, current) : NO_COOKIE;
+ unsigned long exec_cookie = inKernel ? NO_COOKIE : get_exec_cookie(cpu, buftype, current);
- gator_buffer_write_packed_int(cpu, PROTOCOL_START_BACKTRACE);
-
- // TGID::PID::inKernel
- gator_buffer_write_packed_int(cpu, exec_cookie);
- gator_buffer_write_packed_int(cpu, (unsigned int)current->tgid);
- gator_buffer_write_packed_int(cpu, (unsigned int)current->pid);
- gator_buffer_write_packed_int(cpu, inKernel);
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_START_BACKTRACE);
+ gator_buffer_write_packed_int64(cpu, buftype, gator_get_time());
+ gator_buffer_write_packed_int(cpu, buftype, exec_cookie);
+ gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->tgid);
+ gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->pid);
+ gator_buffer_write_packed_int(cpu, buftype, inKernel);
// get_irq_regs() will return NULL outside of IRQ context (e.g. nested IRQ)
if (regs) {
@@ -339,36 +285,26 @@ static void gator_add_sample(int cpu, struct pt_regs * const regs)
addr = PC_REG;
mod = __module_address(addr);
if (mod) {
- cookie = get_cookie(cpu, current, NULL, mod);
+ cookie = get_cookie(cpu, buftype, current, NULL, mod, true);
addr = addr - (unsigned long)mod->module_core;
}
- gator_buffer_write_packed_int(cpu, addr & ~1);
- gator_buffer_write_packed_int(cpu, cookie);
+ gator_buffer_write_packed_int(cpu, buftype, addr & ~1);
+ gator_buffer_write_packed_int(cpu, buftype, cookie);
} else {
// Cookie+PC
- gator_add_trace(cpu, PC_REG);
+ gator_add_trace(cpu, buftype, PC_REG);
// Backtrace
if (gator_backtrace_depth)
- arm_backtrace_eabi(cpu, regs, gator_backtrace_depth);
+ arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth);
}
}
- gator_buffer_write_packed_int(cpu, PROTOCOL_END_BACKTRACE);
-}
-
-static void gator_write_packet(int cpu, int type, int len, int *buffer)
-{
- int i;
- gator_buffer_write_packed_int(cpu, type);
- gator_buffer_write_packed_int(cpu, len);
- for (i = 0; i < len; i++) {
- gator_buffer_write_packed_int(cpu, buffer[i]);
- }
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_END_BACKTRACE);
}
/******************************************************************************
- * Interrupt Processing
+ * hrtimer interrupt processing
******************************************************************************/
static LIST_HEAD(gator_events);
@@ -376,7 +312,8 @@ static void gator_timer_interrupt(void)
{
struct pt_regs * const regs = get_irq_regs();
int cpu = smp_processor_id();
- int *buffer, len, tick;
+ int *buffer, len, i, buftype = TIMER_BUF;
+ long long *buffer64;
struct gator_interface *gi;
// check full backtrace has enough space, otherwise may
@@ -391,44 +328,48 @@ static void gator_timer_interrupt(void)
return;
}
- // Header
- gator_buffer_write_packed_int(cpu, PROTOCOL_START_TICK); // Escape
-
// Output scheduler
- len = gator_trace_sched_read(&buffer);
+ len = gator_trace_sched_read(&buffer64);
if (len > 0) {
- gator_write_packet(cpu, PROTOCOL_SCHEDULER_TRACE, len, buffer);
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_SCHEDULER_TRACE);
+ gator_buffer_write_packed_int(cpu, buftype, len);
+ for (i = 0; i < len; i++) {
+ gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
+ }
}
// Output counters
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COUNTERS);
+ gator_buffer_write_packed_int64(cpu, buftype, gator_get_time());
list_for_each_entry(gi, &gator_events, list) {
if (gi->read) {
len = gi->read(&buffer);
+ if (len > 0) {
+ gator_buffer_write_packed_int(cpu, buftype, len);
+ for (i = 0; i < len; i++) {
+ gator_buffer_write_packed_int(cpu, buftype, buffer[i]);
+ }
+ }
+ } else if (gi->read64) {
+ len = gi->read64(&buffer64);
if (len > 0)
- gator_write_packet(cpu, PROTOCOL_COUNTERS, len, buffer);
+ gator_buffer_write_packed_int(cpu, buftype, len);
+ for (i = 0; i < len; i++) {
+ gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
+ }
}
}
+ gator_buffer_write_packed_int(cpu, buftype, 0);
// Output backtrace
- gator_add_sample(cpu, regs);
-
- // Timer Tick
- tick = per_cpu(gator_cpu_tick, cpu);
- if (tick == gator_master_tick) {
- tick++;
- per_cpu(gator_cpu_tick, cpu) = gator_master_tick = tick;
- } else {
- per_cpu(gator_cpu_tick, cpu) = tick = gator_master_tick;
+ if (!event_based_sampling) {
+ gator_add_sample(cpu, buftype, regs);
}
- gator_write_packet(cpu, PROTOCOL_END_TICK, 1, &tick);
// Check and commit; generally, commit is set to occur once per second
- gator_buffer_check(cpu, tick);
+ timer_buffer_check(cpu);
}
-/******************************************************************************
- * hrtimer
- ******************************************************************************/
DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
DEFINE_PER_CPU(int, hrtimer_is_active);
static int hrtimer_running;
@@ -454,7 +395,9 @@ static void __gator_timer_offline(void *unused)
struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
hrtimer_cancel(hrtimer);
per_cpu(hrtimer_is_active, cpu) = 0;
- gator_buffer_commit(cpu);
+ gator_buffer_commit(cpu, TIMER_BUF);
+ if (event_based_sampling)
+ gator_buffer_commit(cpu, EVENT_BUF);
// offline any events
list_for_each_entry(gi, &gator_events, list)
@@ -469,10 +412,6 @@ static void gator_timer_offline(void)
hrtimer_running = 0;
on_each_cpu(__gator_timer_offline, NULL, 1);
-
- // output a final sync point
- gator_buffer_write_packed_int(0, PROTOCOL_CPU_SYNC);
- gator_buffer_commit(0);
}
}
@@ -485,7 +424,6 @@ static void __gator_timer_online(void *unused)
hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer->function = gator_hrtimer_notify;
hrtimer_start(hrtimer, profiling_interval, HRTIMER_MODE_REL_PINNED);
- per_cpu(gator_cpu_tick, cpu) = 0;
per_cpu(gator_first_time, cpu) = 1;
per_cpu(hrtimer_is_active, cpu) = 1;
@@ -499,10 +437,10 @@ static void __gator_timer_online(void *unused)
int gator_timer_online(unsigned long setup)
{
if (!setup) {
- pr_err("gator: cannot start due to a system tick value of zero");
+ pr_err("gator: cannot start due to a system tick value of zero\n");
return -1;
} else if (hrtimer_running) {
- pr_notice("gator: high res timer already running");
+ pr_notice("gator: high res timer already running\n");
return 0;
}
@@ -512,7 +450,6 @@ int gator_timer_online(unsigned long setup)
profiling_interval = ns_to_ktime(1000000000UL / setup);
// timer interrupt
- gator_master_tick = 0;
on_each_cpu(__gator_timer_online, NULL, 1);
return 0;
@@ -623,10 +560,14 @@ static int gator_start(void)
}
}
+ if (gator_event_sampling_start())
+ goto event_sampling_failure;
if (gator_annotate_start())
goto annotate_failure;
if (gator_trace_sched_start())
goto sched_failure;
+ if (cookies_initialize())
+ goto cookies_failure;
if (gator_timer_online(gator_timer_count))
goto timer_failure;
if (gator_notifier_start())
@@ -637,10 +578,18 @@ static int gator_start(void)
notifier_failure:
gator_timer_offline();
timer_failure:
+ cookies_release();
+cookies_failure:
gator_trace_sched_stop();
sched_failure:
gator_annotate_stop();
annotate_failure:
+ gator_event_sampling_stop();
+event_sampling_failure:
+ // stop all events
+ list_for_each_entry(gi, &gator_events, list)
+ if (gi->stop)
+ gi->stop();
events_failure:
return -1;
@@ -655,12 +604,13 @@ static void gator_stop(void)
if (gi->stop)
gi->stop();
+ gator_event_sampling_stop();
gator_annotate_stop();
gator_trace_sched_stop();
// stop all interrupt callback reads before tearing down other interfaces
+ gator_notifier_stop(); // should be called before gator_timer_offline to avoid re-enabling the hrtimer after it has been offlined
gator_timer_offline();
- gator_notifier_stop();
}
static void gator_exit(void)
@@ -675,42 +625,45 @@ static void gator_exit(void)
static int gator_op_setup(void)
{
int err = 0;
- int cpu;
+ int cpu, i;
mutex_lock(&start_mutex);
- use_buffer_size = gator_buffer_size;
- use_buffer_mask = use_buffer_size - 1;
+ gator_buffer_size[TIMER_BUF] = userspace_buffer_size;
+ gator_buffer_mask[TIMER_BUF] = userspace_buffer_size - 1;
// must be a power of 2
- if (use_buffer_size & (use_buffer_size - 1)) {
+ if (gator_buffer_size[TIMER_BUF] & (gator_buffer_size[TIMER_BUF] - 1)) {
err = -ENOEXEC;
goto setup_error;
}
- gator_net_traffic = 0;
+ gator_buffer_size[EVENT_BUF] = EVENT_BUFFER_SIZE_DEFAULT;
+ gator_buffer_mask[EVENT_BUF] = gator_buffer_size[EVENT_BUF] - 1;
- gator_commit_read = gator_commit_write = 0;
- gator_commit = vmalloc(COMMIT_SIZE * sizeof(int));
- if (!gator_commit) {
- err = -ENOMEM;
- goto setup_error;
- }
+ gator_net_traffic = 0;
- for_each_present_cpu(cpu) {
- per_cpu(use_buffer, cpu) = vmalloc(use_buffer_size);
- if (!per_cpu(use_buffer, cpu)) {
+ // Initialize per buffer variables
+ for (i = 0; i < NUM_GATOR_BUFS; i++) {
+ gator_commit_read[i] = gator_commit_write[i] = 0;
+ gator_commit[i] = vmalloc(COMMIT_SIZE * sizeof(int));
+ if (!gator_commit[i]) {
err = -ENOMEM;
goto setup_error;
}
- per_cpu(gator_cpu_sync, cpu) = 0;
- per_cpu(gator_cpu_tick, cpu) = 0;
+ // Initialize percpu per buffer variables
+ for_each_present_cpu(cpu) {
+ per_cpu(gator_buffer, cpu)[i] = vmalloc(gator_buffer_size[i]);
+ if (!per_cpu(gator_buffer, cpu)[i]) {
+ err = -ENOMEM;
+ goto setup_error;
+ }
- per_cpu(use_buffer_seq, cpu) = 0;
- per_cpu(use_buffer_read, cpu) = 0;
- per_cpu(use_buffer_write, cpu) = 0;
- gator_buffer_header(cpu);
+ per_cpu(gator_buffer_read, cpu)[i] = 0;
+ per_cpu(gator_buffer_write, cpu)[i] = 0;
+ gator_buffer_header(cpu, i);
+ }
}
setup_error:
@@ -725,7 +678,7 @@ static int gator_op_start(void)
mutex_lock(&start_mutex);
- if (gator_started || gator_start() || cookies_initialize())
+ if (gator_started || gator_start())
err = -EINVAL;
else
gator_started = 1;
@@ -757,20 +710,25 @@ static void gator_op_stop(void)
static void gator_shutdown(void)
{
- int cpu;
+ int cpu, i;
mutex_lock(&start_mutex);
- vfree(gator_commit);
- gator_commit = NULL;
+ gator_annotate_shutdown();
+
+ for (i = 0; i < NUM_GATOR_BUFS; i++) {
+ vfree(gator_commit[i]);
+ gator_commit[i] = NULL;
+ }
for_each_present_cpu(cpu) {
mutex_lock(&gator_buffer_mutex);
- vfree(per_cpu(use_buffer, cpu));
- per_cpu(use_buffer, cpu) = NULL;
- per_cpu(use_buffer_seq, cpu) = 0;
- per_cpu(use_buffer_read, cpu) = 0;
- per_cpu(use_buffer_write, cpu) = 0;
+ for (i = 0; i < NUM_GATOR_BUFS; i++) {
+ vfree(per_cpu(gator_buffer, cpu)[i]);
+ per_cpu(gator_buffer, cpu)[i] = NULL;
+ per_cpu(gator_buffer_read, cpu)[i] = 0;
+ per_cpu(gator_buffer_write, cpu)[i] = 0;
+ }
mutex_unlock(&gator_buffer_mutex);
}
@@ -825,7 +783,7 @@ static const struct file_operations enable_fops = {
.write = enable_write,
};
-static int event_buffer_open(struct inode *inode, struct file *file)
+static int userspace_buffer_open(struct inode *inode, struct file *file)
{
int err = -EPERM;
@@ -849,7 +807,7 @@ fail:
return err;
}
-static int event_buffer_release(struct inode *inode, struct file *file)
+static int userspace_buffer_release(struct inode *inode, struct file *file)
{
gator_op_stop();
gator_shutdown();
@@ -857,55 +815,59 @@ static int event_buffer_release(struct inode *inode, struct file *file)
return 0;
}
-static ssize_t event_buffer_read(struct file *file, char __user *buf,
+static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
size_t count, loff_t *offset)
{
int retval = -EINVAL;
int commit, length1, length2, read;
- char *buffer1, *buffer2;
- char annotate_header[6];
- int cpu;
+ char *buffer1;
+ char *buffer2 = NULL;
+ int cpu, i;
/* do not handle partial reads */
- if (count != use_buffer_size || *offset)
+ if (count != userspace_buffer_size || *offset)
return -EINVAL;
// sleep until the condition is true or a signal is received
// the condition is checked each time gator_buffer_wait is woken up
- wait_event_interruptible(gator_buffer_wait, buffer_commit_ready() || gator_annotate_ready() || !gator_started);
+ wait_event_interruptible(gator_buffer_wait, buffer_commit_ready(TIMER_BUF) || buffer_commit_ready(EVENT_BUF) || gator_annotate_ready() || !gator_started);
if (signal_pending(current))
return -EINTR;
+ length2 = 0;
retval = -EFAULT;
mutex_lock(&gator_buffer_mutex);
- if (buffer_commit_ready()) {
- buffer_commit_read(&cpu, &read, &commit);
+ i = -1;
+ if (buffer_commit_ready(TIMER_BUF)) {
+ i = TIMER_BUF;
+ } else if (buffer_commit_ready(EVENT_BUF)) {
+ i = EVENT_BUF;
+ }
+
+ if (i != -1) {
+ buffer_commit_read(&cpu, i, &read, &commit);
/* May happen if the buffer is freed during pending reads. */
- if (!per_cpu(use_buffer, cpu)) {
+ if (!per_cpu(gator_buffer, cpu)[i]) {
retval = -EFAULT;
goto out;
}
/* determine the size of two halves */
length1 = commit - read;
- length2 = 0;
- buffer1 = &(per_cpu(use_buffer, cpu)[read]);
- buffer2 = &(per_cpu(use_buffer, cpu)[0]);
+ buffer1 = &(per_cpu(gator_buffer, cpu)[i][read]);
+ buffer2 = &(per_cpu(gator_buffer, cpu)[i][0]);
if (length1 < 0) {
- length1 = use_buffer_size - read;
+ length1 = gator_buffer_size[i] - read;
length2 = commit;
}
} else if (gator_annotate_ready()) {
- length2 = gator_annotate_read(&buffer2);
- if (!length2)
+ length1 = gator_annotate_read(&buffer1);
+ if (!length1)
goto out;
- annotate_header[0] = PROTOCOL_ANNOTATE;
- length1 = gator_write_packed_int(&annotate_header[1], length2) + 1;
- buffer1 = annotate_header;
} else {
retval = 0;
goto out;
@@ -939,9 +901,9 @@ out:
}
const struct file_operations gator_event_buffer_fops = {
- .open = event_buffer_open,
- .release = event_buffer_release,
- .read = event_buffer_read,
+ .open = userspace_buffer_open,
+ .release = userspace_buffer_release,
+ .read = userspace_buffer_read,
};
static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
@@ -974,17 +936,6 @@ static const struct file_operations depth_fops = {
.write = depth_write
};
-static const char gator_cpu_type[] = "gator";
-
-static ssize_t cpu_type_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
-{
- return gatorfs_str_to_user(gator_cpu_type, buf, count, offset);
-}
-
-static const struct file_operations cpu_type_fops = {
- .read = cpu_type_read,
-};
-
void gator_op_create_files(struct super_block *sb, struct dentry *root)
{
struct dentry *dir;
@@ -996,15 +947,14 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
for_each_present_cpu(cpu) {
gator_cpu_cores++;
}
- gator_buffer_size = BUFFER_SIZE_DEFAULT;
+ userspace_buffer_size = TIMER_BUFFER_SIZE_DEFAULT;
gator_streaming = 1;
gatorfs_create_file(sb, root, "enable", &enable_fops);
gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops);
gatorfs_create_file(sb, root, "backtrace_depth", &depth_fops);
- gatorfs_create_file(sb, root, "cpu_type", &cpu_type_fops);
gatorfs_create_ulong(sb, root, "cpu_cores", &gator_cpu_cores);
- gatorfs_create_ulong(sb, root, "buffer_size", &gator_buffer_size);
+ gatorfs_create_ulong(sb, root, "buffer_size", &userspace_buffer_size);
gatorfs_create_ulong(sb, root, "tick", &gator_timer_count);
gatorfs_create_ulong(sb, root, "streaming", &gator_streaming);
gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version);
@@ -1033,17 +983,11 @@ static int __init gator_module_init(void)
return -1;
}
-#ifdef GATOR_DEBUG
- pr_err("gator_module_init");
-#endif
return 0;
}
static void __exit gator_module_exit(void)
{
-#ifdef GATOR_DEBUG
- pr_err("gator_module_exit");
-#endif
tracepoint_synchronize_unregister();
gatorfs_unregister();
gator_exit();
diff --git a/driver/gator_pack.c b/driver/gator_pack.c
new file mode 100644
index 0000000..fbab220
--- /dev/null
+++ b/driver/gator_pack.c
@@ -0,0 +1,262 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 gator_buffer_write_packed_int(int cpu, int buftype, unsigned int x)
+{
+ uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype];
+ uint32_t mask = gator_buffer_mask[buftype];
+ char *buffer = per_cpu(gator_buffer, cpu)[buftype];
+ int write0 = (write + 0) & mask;
+ int write1 = (write + 1) & mask;
+
+ if ((x & 0xffffff80) == 0) {
+ buffer[write0] = x & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write1;
+ } else if ((x & 0xffffc000) == 0) {
+ int write2 = (write + 2) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write2;
+ } else if ((x & 0xffe00000) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write3;
+ } else if ((x & 0xf0000000) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write4;
+ } else {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) & 0x0f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write5;
+ }
+}
+
+static void gator_buffer_write_packed_int64(int cpu, int buftype, unsigned long long x)
+{
+ uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype];
+ uint32_t mask = gator_buffer_mask[buftype];
+ char *buffer = per_cpu(gator_buffer, cpu)[buftype];
+ int write0 = (write + 0) & mask;
+ int write1 = (write + 1) & mask;
+
+ if ((x & 0xffffffffffffff80LL) == 0) {
+ buffer[write0] = x & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write1;
+ } else if ((x & 0xffffffffffffc000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write2;
+ } else if ((x & 0xffffffffffe00000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write3;
+ } else if ((x & 0xfffffffff0000000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write4;
+ } else if ((x & 0xfffffff800000000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write5;
+ } else if ((x & 0xfffffc0000000000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ int write6 = (write + 6) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) | 0x80;
+ buffer[write5] = (x>>35) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write6;
+ } else if ((x & 0xfffe000000000000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ int write6 = (write + 6) & mask;
+ int write7 = (write + 7) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) | 0x80;
+ buffer[write5] = (x>>35) | 0x80;
+ buffer[write6] = (x>>42) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write7;
+ } else if ((x & 0xff00000000000000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ int write6 = (write + 6) & mask;
+ int write7 = (write + 7) & mask;
+ int write8 = (write + 8) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) | 0x80;
+ buffer[write5] = (x>>35) | 0x80;
+ buffer[write6] = (x>>42) | 0x80;
+ buffer[write7] = (x>>49) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write8;
+ } else {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ int write6 = (write + 6) & mask;
+ int write7 = (write + 7) & mask;
+ int write8 = (write + 8) & mask;
+ int write9 = (write + 9) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) | 0x80;
+ buffer[write5] = (x>>35) | 0x80;
+ buffer[write6] = (x>>42) | 0x80;
+ buffer[write7] = (x>>49) | 0x80;
+ buffer[write8] = (x>>56) & 0xff;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write9;
+ }
+}
+
+static int gator_write_packed_int(char *buffer, unsigned int x)
+{
+ if ((x & 0xffffff80) == 0) {
+ buffer[0] = x & 0x7f;
+ return 1;
+ } else if ((x & 0xffffc000) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) & 0x7f;
+ return 2;
+ } else if ((x & 0xffe00000) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) & 0x7f;
+ return 3;
+ } else if ((x & 0xf0000000) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) & 0x7f;
+ return 4;
+ } else {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) & 0x0f;
+ return 5;
+ }
+}
+
+static int gator_write_packed_int64(char *buffer, unsigned long long x)
+{
+ if ((x & 0xffffffffffffff80LL) == 0) {
+ buffer[0] = x & 0x7f;
+ return 1;
+ } else if ((x & 0xffffffffffffc000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) & 0x7f;
+ return 2;
+ } else if ((x & 0xffffffffffe00000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) & 0x7f;
+ return 3;
+ } else if ((x & 0xfffffffff0000000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) & 0x7f;
+ return 4;
+ } else if ((x & 0xfffffff800000000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) & 0x7f;
+ return 5;
+ } else if ((x & 0xfffffc0000000000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) | 0x80;
+ buffer[5] = (x>>35) & 0x7f;
+ return 6;
+ } else if ((x & 0xfffe000000000000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) | 0x80;
+ buffer[5] = (x>>35) | 0x80;
+ buffer[6] = (x>>42) & 0x7f;
+ return 7;
+ } else if ((x & 0xff00000000000000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) | 0x80;
+ buffer[5] = (x>>35) | 0x80;
+ buffer[6] = (x>>42) | 0x80;
+ buffer[7] = (x>>49) & 0x7f;
+ return 8;
+ } else {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) | 0x80;
+ buffer[5] = (x>>35) | 0x80;
+ buffer[6] = (x>>42) | 0x80;
+ buffer[7] = (x>>49) | 0x80;
+ buffer[8] = (x>>56) & 0xff;
+ return 9;
+ }
+}
diff --git a/driver/gator_trace_sched.c b/driver/gator_trace_sched.c
index 19d8d89..7c0bd47 100644
--- a/driver/gator_trace_sched.c
+++ b/driver/gator_trace_sched.c
@@ -10,36 +10,89 @@
#include <trace/events/sched.h>
#include "gator.h"
-#define SCHED_TIMER_EVENT 0
-#define SCHED_WAIT_TASK 1
-#define SCHED_WAKEUP 2
-#define SCHED_WAKEUP_NEW 3
-#define SCHED_SWITCH 4
-#define SCHED_MIGRATE_TASK 5
-#define SCHED_PROCESS_FREE 6
-#define SCHED_PROCESS_EXIT 7
-#define SCHED_PROCESS_WAIT 8
-#define SCHED_PROCESS_FORK 9
#define SCHED_OVERFLOW -1
+#define SCHED_SWITCH 1
+#define SCHED_PROCESS_FREE 2
-#define SCHEDSIZE (16*1024)
+#define FIELD_TYPE 0
+#define FIELD_TIME 1
+#define FIELD_PARAM1 2
+#define FIELD_PARAM2 3
+#define FIELD_PARAM3 4
+#define FIELDS_PER_SCHED 5
-static DEFINE_PER_CPU(int *[2], theSchedBuf);
+#define SCHEDSIZE (8*1024)
+#define TASK_MAP_ENTRIES 1024 /* must be power of 2 */
+#define TASK_MAX_COLLISIONS 2
+
+static DEFINE_PER_CPU(uint64_t *[2], theSchedBuf);
static DEFINE_PER_CPU(int, theSchedSel);
static DEFINE_PER_CPU(int, theSchedPos);
static DEFINE_PER_CPU(int, theSchedErr);
+static DEFINE_PER_CPU(uint64_t *, taskname_keys);
+
+void emit_pid_name(uint64_t time, struct task_struct* task)
+{
+ bool found = false;
+ unsigned long flags;
+ char taskcomm[TASK_COMM_LEN + 3];
+ int x, cpu = smp_processor_id();
+ uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]);
+ uint64_t value;
+
+ value = gator_chksum_crc32(task->comm);
+ value = (value << 32) | (uint32_t)task->pid;
+
+ // determine if the thread name was emitted already
+ for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
+ if (keys[x] == value) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ // shift values, new value always in front
+ uint64_t oldv, newv = value;
+ for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
+ oldv = keys[x];
+ keys[x] = newv;
+ newv = oldv;
+ }
+
+ // emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions
+ if (strlcpy(taskcomm, task->comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1)
+ // append ellipses if task->comm has length of TASK_COMM_LEN - 1
+ strcat(taskcomm, "...");
+
+ // disable interrupts to synchronize with hrtimer populating timer buf
+ local_irq_save(flags);
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_PID_NAME);
+ gator_buffer_write_packed_int64(cpu, TIMER_BUF, time);
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, task->pid);
+ gator_buffer_write_string(cpu, TIMER_BUF, taskcomm);
+ local_irq_restore(flags);
+ }
+}
static void probe_sched_write(int type, int param1, int param2, int param3)
{
unsigned long flags;
int cpu = smp_processor_id();
uint64_t time = gator_get_time();
- int *schedBuf;
- int schedPos;
+ uint64_t *schedBuf;
+ int schedPos, cookie = param3;
if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
return;
+ if (param3) {
+ // do as much work as possible before disabling interrupts
+ struct task_struct *task = (struct task_struct *)param3;
+ cookie = get_exec_cookie(cpu, TIMER_BUF, task);
+ emit_pid_name(time, task);
+ }
+
// disable interrupts to synchronize with gator_trace_sched_read(); spinlocks not needed since percpu buffers are used
local_irq_save(flags);
@@ -48,88 +101,37 @@ static void probe_sched_write(int type, int param1, int param2, int param3)
if (schedPos < (SCHEDSIZE-100)) {
// capture
- schedBuf[schedPos+0] = type;
- schedBuf[schedPos+1] = (int)time;
- schedBuf[schedPos+2] = (int)(time >> 32);
- schedBuf[schedPos+3] = param1;
- schedBuf[schedPos+4] = param2;
- schedBuf[schedPos+5] = param3;
- per_cpu(theSchedPos, cpu) = schedPos + 6;
+ schedBuf[schedPos+FIELD_TYPE] = type;
+ schedBuf[schedPos+FIELD_TIME] = time;
+ schedBuf[schedPos+FIELD_PARAM1] = param1;
+ schedBuf[schedPos+FIELD_PARAM2] = param2;
+ schedBuf[schedPos+FIELD_PARAM3] = cookie;
+ per_cpu(theSchedPos, cpu) = schedPos + FIELDS_PER_SCHED;
} else if (!per_cpu(theSchedErr, cpu)) {
per_cpu(theSchedErr, cpu) = 1;
- schedBuf[schedPos+0] = SCHED_OVERFLOW;
- schedBuf[schedPos+1] = 0;
- schedBuf[schedPos+2] = 0;
- schedBuf[schedPos+3] = 0;
- schedBuf[schedPos+4] = 0;
- schedBuf[schedPos+5] = 0;
- per_cpu(theSchedPos, cpu) = schedPos + 6;
+ schedBuf[schedPos+FIELD_TYPE] = SCHED_OVERFLOW;
+ schedBuf[schedPos+FIELD_TIME] = time;
+ schedBuf[schedPos+FIELD_PARAM1] = 0;
+ schedBuf[schedPos+FIELD_PARAM2] = 0;
+ schedBuf[schedPos+FIELD_PARAM3] = 0;
+ per_cpu(theSchedPos, cpu) = schedPos + FIELDS_PER_SCHED;
pr_debug("gator: tracepoint overflow\n");
}
local_irq_restore(flags);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-GATOR_DEFINE_PROBE(sched_wait_task, TP_PROTO(struct rq *rq, struct task_struct *p))
-#else
-GATOR_DEFINE_PROBE(sched_wait_task, TP_PROTO(struct task_struct *p))
-#endif
-{
- probe_sched_write(SCHED_WAIT_TASK, 0, p->pid, 0);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-GATOR_DEFINE_PROBE(sched_wakeup, TP_PROTO(struct rq *rq, struct task_struct *p, int success))
-#else
-GATOR_DEFINE_PROBE(sched_wakeup, TP_PROTO(struct task_struct *p, int success))
-#endif
-{
- if (success)
- probe_sched_write(SCHED_WAKEUP, 0, p->pid, 0);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-GATOR_DEFINE_PROBE(sched_wakeup_new, TP_PROTO(struct rq *rq, struct task_struct *p, int success))
-#else
-GATOR_DEFINE_PROBE(sched_wakeup_new, TP_PROTO(struct task_struct *p, int success))
-#endif
-{
- if (success)
- probe_sched_write(SCHED_WAKEUP_NEW, 0, p->tgid, p->pid);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
#else
GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
#endif
{
- probe_sched_write(SCHED_SWITCH, (int)next, next->tgid, next->pid);
-}
-
-GATOR_DEFINE_PROBE(sched_migrate_task, TP_PROTO(struct task_struct *p, int dest_cpu))
-{
- probe_sched_write(SCHED_MIGRATE_TASK, 0, dest_cpu, p->pid);
+ probe_sched_write(SCHED_SWITCH, next->pid, next->tgid, (int)next);
}
GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
{
- probe_sched_write(SCHED_PROCESS_FREE, 0, p->pid, 0);
-}
-
-GATOR_DEFINE_PROBE(sched_process_exit, TP_PROTO(struct task_struct *p))
-{
- probe_sched_write(SCHED_PROCESS_EXIT, 0, p->pid, 0);
-}
-
-GATOR_DEFINE_PROBE(sched_process_wait, TP_PROTO(struct pid *pid))
-{
- probe_sched_write(SCHED_PROCESS_WAIT, 0, pid_nr(pid), 0);
-}
-
-GATOR_DEFINE_PROBE(sched_process_fork, TP_PROTO(struct task_struct *parent, struct task_struct *child))
-{
- probe_sched_write(SCHED_PROCESS_FORK, (int)child, parent->pid, child->pid);
+ probe_sched_write(SCHED_PROCESS_FREE, p->pid, 0, 0);
}
int gator_trace_sched_init(void)
@@ -139,59 +141,37 @@ int gator_trace_sched_init(void)
int gator_trace_sched_start(void)
{
- int cpu;
+ int cpu, size;
for_each_present_cpu(cpu) {
per_cpu(theSchedSel, cpu) = 0;
per_cpu(theSchedPos, cpu) = 0;
per_cpu(theSchedErr, cpu) = 0;
- per_cpu(theSchedBuf, cpu)[0] = kmalloc(SCHEDSIZE * sizeof(int), GFP_KERNEL);
- per_cpu(theSchedBuf, cpu)[1] = kmalloc(SCHEDSIZE * sizeof(int), GFP_KERNEL);
+ per_cpu(theSchedBuf, cpu)[0] = kmalloc(SCHEDSIZE * sizeof(uint64_t), GFP_KERNEL);
+ per_cpu(theSchedBuf, cpu)[1] = kmalloc(SCHEDSIZE * sizeof(uint64_t), GFP_KERNEL);
if (!per_cpu(theSchedBuf, cpu))
return -1;
+
+ size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t);
+ per_cpu(taskname_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL);
+ if (!per_cpu(taskname_keys, cpu))
+ return -1;
+ memset(per_cpu(taskname_keys, cpu), 0, size);
}
// register tracepoints
- if (GATOR_REGISTER_TRACE(sched_wait_task))
- goto fail_sched_wait_task;
- if (GATOR_REGISTER_TRACE(sched_wakeup))
- goto fail_sched_wakeup;
- if (GATOR_REGISTER_TRACE(sched_wakeup_new))
- goto fail_sched_wakeup_new;
if (GATOR_REGISTER_TRACE(sched_switch))
goto fail_sched_switch;
- if (GATOR_REGISTER_TRACE(sched_migrate_task))
- goto fail_sched_migrate_task;
if (GATOR_REGISTER_TRACE(sched_process_free))
goto fail_sched_process_free;
- if (GATOR_REGISTER_TRACE(sched_process_exit))
- goto fail_sched_process_exit;
- if (GATOR_REGISTER_TRACE(sched_process_wait))
- goto fail_sched_process_wait;
- if (GATOR_REGISTER_TRACE(sched_process_fork))
- goto fail_sched_process_fork;
pr_debug("gator: registered tracepoints\n");
return 0;
// unregister tracepoints on error
-fail_sched_process_fork:
- GATOR_UNREGISTER_TRACE(sched_process_wait);
-fail_sched_process_wait:
- GATOR_UNREGISTER_TRACE(sched_process_exit);
-fail_sched_process_exit:
- GATOR_UNREGISTER_TRACE(sched_process_free);
fail_sched_process_free:
- GATOR_UNREGISTER_TRACE(sched_migrate_task);
-fail_sched_migrate_task:
GATOR_UNREGISTER_TRACE(sched_switch);
fail_sched_switch:
- GATOR_UNREGISTER_TRACE(sched_wakeup_new);
-fail_sched_wakeup_new:
- GATOR_UNREGISTER_TRACE(sched_wakeup);
-fail_sched_wakeup:
- GATOR_UNREGISTER_TRACE(sched_wait_task);
-fail_sched_wait_task:
pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
return -1;
@@ -200,15 +180,8 @@ fail_sched_wait_task:
void gator_trace_sched_stop(void)
{
int cpu;
- GATOR_UNREGISTER_TRACE(sched_wait_task);
- GATOR_UNREGISTER_TRACE(sched_wakeup);
- GATOR_UNREGISTER_TRACE(sched_wakeup_new);
GATOR_UNREGISTER_TRACE(sched_switch);
- GATOR_UNREGISTER_TRACE(sched_migrate_task);
GATOR_UNREGISTER_TRACE(sched_process_free);
- GATOR_UNREGISTER_TRACE(sched_process_exit);
- GATOR_UNREGISTER_TRACE(sched_process_wait);
- GATOR_UNREGISTER_TRACE(sched_process_fork);
pr_debug("gator: unregistered tracepoints\n");
for_each_present_cpu(cpu) {
@@ -216,17 +189,16 @@ void gator_trace_sched_stop(void)
kfree(per_cpu(theSchedBuf, cpu)[1]);
per_cpu(theSchedBuf, cpu)[0] = NULL;
per_cpu(theSchedBuf, cpu)[1] = NULL;
+ kfree(per_cpu(taskname_keys, cpu));
}
}
-int gator_trace_sched_read(int **buffer)
+int gator_trace_sched_read(long long **buffer)
{
- uint64_t time = gator_get_time();
int cpu = smp_processor_id();
unsigned long flags;
- int *schedBuf;
+ uint64_t *schedBuf;
int schedPos;
- int i;
if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
return 0;
@@ -242,20 +214,6 @@ int gator_trace_sched_read(int **buffer)
local_irq_restore(flags);
- // find mm and replace with cookies
- for (i = 0; i < schedPos; i += 6) {
- uint32_t cookie = schedBuf[i+3];
- if (cookie) {
- struct task_struct *task = (struct task_struct *)cookie;
- schedBuf[i+3] = get_exec_cookie(cpu, task);
- }
- }
-
- // timer/end event
- schedBuf[schedPos++] = SCHED_TIMER_EVENT;
- schedBuf[schedPos++] = (int)time;
- schedBuf[schedPos++] = (int)(time >> 32);
-
if (buffer)
*buffer = schedBuf;