aboutsummaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'daemon')
-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
50 files changed, 4305 insertions, 0 deletions
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;
+}