aboutsummaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'daemon')
-rw-r--r--daemon/Android.mk3
-rw-r--r--daemon/AtraceDriver.cpp136
-rw-r--r--daemon/AtraceDriver.h39
-rw-r--r--daemon/Buffer.cpp16
-rw-r--r--daemon/Buffer.h3
-rw-r--r--daemon/CCNDriver.cpp41
-rw-r--r--daemon/CCNDriver.h2
-rw-r--r--daemon/CapturedXML.cpp2
-rw-r--r--daemon/Child.cpp50
-rw-r--r--daemon/Command.cpp69
-rw-r--r--daemon/Config.h7
-rw-r--r--daemon/ConfigurationXML.cpp15
-rw-r--r--daemon/DiskIODriver.cpp2
-rw-r--r--daemon/DriverSource.cpp56
-rw-r--r--daemon/DriverSource.h1
-rw-r--r--daemon/EventsXML.cpp4
-rw-r--r--daemon/ExternalDriver.cpp269
-rw-r--r--daemon/ExternalDriver.h41
-rw-r--r--daemon/ExternalSource.cpp84
-rw-r--r--daemon/ExternalSource.h3
-rw-r--r--daemon/FtraceDriver.cpp115
-rw-r--r--daemon/FtraceDriver.h5
-rw-r--r--daemon/FtraceSource.cpp188
-rw-r--r--daemon/FtraceSource.h43
-rw-r--r--daemon/MaliVideoDriver.cpp28
-rw-r--r--daemon/MaliVideoDriver.h1
-rw-r--r--daemon/MemInfoDriver.cpp2
-rw-r--r--daemon/NetDriver.cpp2
-rw-r--r--daemon/PerfDriver.cpp184
-rw-r--r--daemon/PerfDriver.h8
-rw-r--r--daemon/PerfGroup.cpp15
-rw-r--r--daemon/PerfSource.cpp29
-rw-r--r--daemon/Proc.cpp9
-rw-r--r--daemon/Sender.cpp22
-rw-r--r--daemon/SessionData.cpp108
-rw-r--r--daemon/SessionData.h44
-rw-r--r--daemon/Setup.cpp36
-rw-r--r--daemon/StreamlineSetup.cpp10
-rw-r--r--daemon/UserSpaceSource.cpp10
-rw-r--r--daemon/defaults.xml30
-rw-r--r--daemon/events-CCI-400.xml6
-rw-r--r--daemon/events-Cortex-A53.xml6
-rw-r--r--daemon/events-Cortex-A57.xml6
-rw-r--r--daemon/events-Cortex-A72.xml6
-rw-r--r--daemon/events-Mali-4xx.xml11
-rw-r--r--daemon/events-Mali-Midgard_hw.xml4
-rw-r--r--daemon/events-Mali-T82x_hw.xml216
-rw-r--r--daemon/events-Mali-V500.xml4
-rw-r--r--daemon/events-atrace.xml19
-rw-r--r--daemon/events-ftrace.xml20
-rw-r--r--daemon/k/perf_event.3.12.h792
-rw-r--r--[l---------]daemon/k/perf_event.h793
-rw-r--r--daemon/main.cpp31
-rw-r--r--daemon/notify/COPYING339
-rw-r--r--daemon/notify/Makefile24
-rw-r--r--daemon/notify/Notify.java31
56 files changed, 2489 insertions, 1551 deletions
diff --git a/daemon/Android.mk b/daemon/Android.mk
index c5c8bdc..9934211 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -9,6 +9,7 @@ XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h SrcMd5.cpp
LOCAL_SRC_FILES := \
AnnotateListener.cpp \
+ AtraceDriver.cpp \
Buffer.cpp \
CCNDriver.cpp \
CapturedXML.cpp \
@@ -20,11 +21,11 @@ LOCAL_SRC_FILES := \
DriverSource.cpp \
DynBuf.cpp \
EventsXML.cpp \
+ ExternalDriver.cpp \
ExternalSource.cpp \
FSDriver.cpp \
Fifo.cpp \
FtraceDriver.cpp \
- FtraceSource.cpp \
HwmonDriver.cpp \
KMod.cpp \
LocalCapture.cpp \
diff --git a/daemon/AtraceDriver.cpp b/daemon/AtraceDriver.cpp
new file mode 100644
index 0000000..78fe58a
--- /dev/null
+++ b/daemon/AtraceDriver.cpp
@@ -0,0 +1,136 @@
+/**
+ * Copyright (C) ARM Limited 2014-2015. 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 "AtraceDriver.h"
+
+#include <unistd.h>
+
+/*
+#include <regex.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "DriverSource.h"
+#include "Setup.h"
+*/
+
+#include "Logging.h"
+#include "OlyUtility.h"
+#include "SessionData.h"
+
+class AtraceCounter : public DriverCounter {
+public:
+ AtraceCounter(DriverCounter *next, char *name, int flag);
+ ~AtraceCounter();
+
+ int getFlag() const { return mFlag; }
+
+private:
+ const int mFlag;
+
+ // Intentionally unimplemented
+ AtraceCounter(const AtraceCounter &);
+ AtraceCounter &operator=(const AtraceCounter &);
+};
+
+AtraceCounter::AtraceCounter(DriverCounter *next, char *name, int flag) : DriverCounter(next, name), mFlag(flag) {
+}
+
+AtraceCounter::~AtraceCounter() {
+}
+
+AtraceDriver::AtraceDriver() : mSupported(false), mNotifyPath() {
+}
+
+AtraceDriver::~AtraceDriver() {
+}
+
+void AtraceDriver::readEvents(mxml_node_t *const xml) {
+ if (!gSessionData->mFtraceDriver.isSupported()) {
+ logg->logMessage("Atrace support disabled, ftrace support is required");
+ return;
+ }
+ if (access("/system/bin/setprop", X_OK) != 0) {
+ logg->logMessage("Atrace support disabled, setprop is not found, this is not an Android target");
+ return;
+ }
+
+ if (util->getApplicationFullPath(mNotifyPath, sizeof(mNotifyPath)) != 0) {
+ logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
+ }
+ strncat(mNotifyPath, "notify.dex", sizeof(mNotifyPath) - strlen(mNotifyPath) - 1);
+ if (access(mNotifyPath, W_OK) != 0) {
+ logg->logMessage("Atrace support disabled, unable to locate notify.dex");
+ return;
+ }
+
+ mSupported = true;
+
+ mxml_node_t *node = xml;
+ while (true) {
+ node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
+ if (node == NULL) {
+ break;
+ }
+ const char *counter = mxmlElementGetAttr(node, "counter");
+ if (counter == NULL) {
+ continue;
+ }
+
+ if (strncmp(counter, "atrace_", 7) != 0) {
+ continue;
+ }
+
+ const char *flag = mxmlElementGetAttr(node, "flag");
+ if (flag == NULL) {
+ logg->logError("The atrace counter %s is missing the required flag attribute", counter);
+ handleException();
+ }
+ setCounters(new AtraceCounter(getCounters(), strdup(counter), strtol(flag, NULL, 16)));
+ }
+}
+
+void AtraceDriver::setAtrace(const int flags) {
+ logg->logMessage("Setting atrace flags to %i\n", flags);
+ pid_t pid = fork();
+ if (pid < 0) {
+ logg->logError("fork failed");
+ handleException();
+ } else if (pid == 0) {
+ char buf[1<<10];
+ snprintf(buf, sizeof(buf), "setprop debug.atrace.tags.enableflags %i; "
+ "dalvikvm -cp %s com.android.internal.util.WithFramework Notify", flags, mNotifyPath);
+ execlp("sh", "sh", "-c", buf, NULL);
+ exit(0);
+ }
+}
+
+void AtraceDriver::start() {
+ if (!mSupported) {
+ return;
+ }
+
+ int flags = 0;
+ for (AtraceCounter *counter = static_cast<AtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<AtraceCounter *>(counter->getNext())) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ flags |= counter->getFlag();
+ }
+
+ setAtrace(flags);
+}
+
+void AtraceDriver::stop() {
+ if (!mSupported) {
+ return;
+ }
+
+ setAtrace(0);
+}
diff --git a/daemon/AtraceDriver.h b/daemon/AtraceDriver.h
new file mode 100644
index 0000000..0a06858
--- /dev/null
+++ b/daemon/AtraceDriver.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) ARM Limited 2015. 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 ATRACEDRIVER_H
+#define ATRACEDRIVER_H
+
+#include "mxml/mxml.h"
+
+#include "Driver.h"
+
+class AtraceDriver : public SimpleDriver {
+public:
+ AtraceDriver();
+ ~AtraceDriver();
+
+ void readEvents(mxml_node_t *const xml);
+
+ void start();
+ void stop();
+
+ bool isSupported() const { return mSupported; }
+
+private:
+ void setAtrace(const int flags);
+
+ bool mSupported;
+ char mNotifyPath[256];
+
+ // Intentionally unimplemented
+ AtraceDriver(const AtraceDriver &);
+ AtraceDriver &operator=(const AtraceDriver &);
+};
+
+#endif // ATRACEDRIVER_H
diff --git a/daemon/Buffer.cpp b/daemon/Buffer.cpp
index c4ced9f..26deb2e 100644
--- a/daemon/Buffer.cpp
+++ b/daemon/Buffer.cpp
@@ -143,6 +143,16 @@ int Buffer::contiguousSpaceAvailable() const {
}
}
+bool Buffer::hasUncommittedMessages() const {
+ const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
+ int length = mWritePos - mCommitPos;
+ if (length < 0) {
+ length += mSize;
+ }
+ length = length - typeLength - sizeof(int32_t);
+ return length > FRAME_HEADER_SIZE;
+}
+
void Buffer::commit(const uint64_t time, const bool force) {
// post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
@@ -263,7 +273,7 @@ void Buffer::frame() {
}
}
-void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
+void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname, const long pageSize) {
packInt(MESSAGE_SUMMARY);
writeString(NEWLINE_CANARY);
packInt64(timestamp);
@@ -271,6 +281,10 @@ void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int
packInt64(monotonicDelta);
writeString("uname");
writeString(uname);
+ writeString("PAGESIZE");
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%li", pageSize);
+ writeString(buf);
writeString("");
check(currTime);
}
diff --git a/daemon/Buffer.h b/daemon/Buffer.h
index 13c44e1..ea250a9 100644
--- a/daemon/Buffer.h
+++ b/daemon/Buffer.h
@@ -36,11 +36,12 @@ public:
int bytesAvailable() const;
int contiguousSpaceAvailable() const;
+ bool hasUncommittedMessages() const;
void commit(const uint64_t time, const bool force = false);
void check(const uint64_t time);
// Summary messages
- void summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname);
+ void summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname, const long pageSize);
void coreName(const uint64_t currTime, const int core, const int cpuid, const char *const name);
// Block Counter messages
diff --git a/daemon/CCNDriver.cpp b/daemon/CCNDriver.cpp
index d77513a..24eda03 100644
--- a/daemon/CCNDriver.cpp
+++ b/daemon/CCNDriver.cpp
@@ -19,6 +19,7 @@
#include "Config.h"
#include "DriverSource.h"
#include "Logging.h"
+#include "SessionData.h"
static const char TAG_CATEGORY[] = "category";
static const char TAG_COUNTER_SET[] = "counter_set";
@@ -44,6 +45,8 @@ static const char RNI_REGION[] = "RN-I_Region";
static const char SBAS_REGION[] = "SBAS_Region";
static const char CCN_5XX[] = "CCN-5xx";
#define ARM_CCN_5XX "ARM_CCN_5XX_"
+#define CCN_COUNT 8
+static const char ARM_CCN_5XX_CNT[] = ARM_CCN_5XX "cnt";
static const char *const VC_TYPES[] = { "REQ", "RSP", "SNP", "DAT" };
static const char *const XP_EVENT_NAMES[] = { NULL, "H-bit", "S-bit", "P-Cnt", "TknV" };
@@ -173,12 +176,12 @@ int CCNDriver::writeCounters(mxml_node_t *const) const {
void CCNDriver::writeEvents(mxml_node_t *const root) const {
mxml_node_t *const counter_set = mxmlNewElement(root, TAG_COUNTER_SET);
- mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX "cnt");
- mxmlElementSetAttr(counter_set, ATTR_COUNT, "8");
+ mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX_CNT);
+ mxmlElementSetAttr(counter_set, ATTR_COUNT, STRIFY(CCN_COUNT));
mxml_node_t *const category = mxmlNewElement(root, TAG_CATEGORY);
mxmlElementSetAttr(category, ATTR_NAME, CCN_5XX);
- mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX "cnt");
+ mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX_CNT);
mxml_node_t *const clock_event = mxmlNewElement(category, TAG_EVENT);
mxmlElementSetAttr(clock_event, ATTR_COUNTER, ARM_CCN_5XX "ccnt");
@@ -292,3 +295,35 @@ void CCNDriver::writeEvents(mxml_node_t *const root) const {
}
}
}
+
+void CCNDriver::validateCounters() const {
+ int counts[CCN_COUNT][2] = { { 0 } };
+ const unsigned int mask = getConfig(0xff, 0xff, 0, 0, 0);
+
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->mCounters); ++i) {
+ const Counter *const counter = &gSessionData->mCounters[i];
+
+ if (!counter->isEnabled()) {
+ continue;
+ }
+
+ if (strncmp(counter->getType(), ARM_CCN_5XX_CNT, sizeof(ARM_CCN_5XX_CNT) - 1) == 0) {
+ const int node = counter->getEvent() & mask;
+
+ for (int j = 0; j < ARRAY_LENGTH(counts); ++j) {
+ if (counts[j][0] == 0) {
+ counts[j][0] = node;
+ }
+ if (counts[j][0] == node) {
+ ++counts[j][1];
+ if (counts[j][1] > 4) {
+ if (asprintf(&gSessionData->mCountersError, "More than 4 events are assigned to the same CCN node") <= 0) {
+ logg->logError("asprintf failed");
+ handleException();
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/daemon/CCNDriver.h b/daemon/CCNDriver.h
index 06ac33f..8a155a7 100644
--- a/daemon/CCNDriver.h
+++ b/daemon/CCNDriver.h
@@ -24,6 +24,8 @@ public:
int writeCounters(mxml_node_t *const root) const;
void writeEvents(mxml_node_t *const) const;
+ void validateCounters() const;
+
private:
enum NodeType {
NT_UNKNOWN,
diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp
index 1854c77..e87c909 100644
--- a/daemon/CapturedXML.cpp
+++ b/daemon/CapturedXML.cpp
@@ -32,7 +32,7 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
captured = mxmlNewElement(xml, "captured");
mxmlElementSetAttr(captured, "version", "1");
- if (gSessionData->perf.isSetup()) {
+ if (gSessionData->mPerf.isSetup()) {
mxmlElementSetAttr(captured, "type", "Perf");
}
mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION);
diff --git a/daemon/Child.cpp b/daemon/Child.cpp
index a19e9cf..551ec6b 100644
--- a/daemon/Child.cpp
+++ b/daemon/Child.cpp
@@ -20,7 +20,6 @@
#include "Driver.h"
#include "DriverSource.h"
#include "ExternalSource.h"
-#include "FtraceSource.h"
#include "LocalCapture.h"
#include "Logging.h"
#include "OlySocket.h"
@@ -35,7 +34,6 @@ static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shar
static Source *primarySource = NULL;
static Source *externalSource = NULL;
static Source *userSpaceSource = NULL;
-static Source *ftraceSource = NULL;
static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
Child* child = NULL; // shared by Child.cpp and main.cpp
@@ -44,7 +42,8 @@ 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);
+ // Something is really wrong, exit immediately
+ _exit(1);
}
fprintf(stderr, "%s", logg->getLastError());
@@ -67,8 +66,9 @@ void handleException() {
}
}
- if (gSessionData->mLocalCapture)
+ if (gSessionData->mLocalCapture) {
cleanUp();
+ }
exit(1);
}
@@ -152,7 +152,6 @@ static void *senderThread(void *) {
while (!externalSource->isDone() ||
(userSpaceSource != NULL && !userSpaceSource->isDone()) ||
- (ftraceSource != NULL && !ftraceSource->isDone()) ||
!primarySource->isDone()) {
sem_wait(&senderSem);
@@ -160,9 +159,6 @@ static void *senderThread(void *) {
if (userSpaceSource != NULL) {
userSpaceSource->write(sender);
}
- if (ftraceSource != NULL) {
- ftraceSource->write(sender);
- }
primarySource->write(sender);
}
@@ -213,9 +209,6 @@ void Child::endSession() {
if (userSpaceSource != NULL) {
userSpaceSource->interrupt();
}
- if (ftraceSource != NULL) {
- ftraceSource->interrupt();
- }
sem_post(&haltPipeline);
}
@@ -240,7 +233,7 @@ void Child::run() {
{ ConfigurationXML configuration; }
// Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
- if (!gSessionData->perf.isSetup()) {
+ if (!gSessionData->mPerf.isSetup()) {
primarySource = new DriverSource(&senderSem, &startProfile);
} else {
primarySource = new PerfSource(&senderSem, &startProfile);
@@ -279,25 +272,24 @@ void Child::run() {
free(xmlString);
}
- if (gSessionData->kmod.isMaliCapture() && (gSessionData->mSampleRate == 0)) {
+ if (gSessionData->mKmod.isMaliCapture() && (gSessionData->mSampleRate == 0)) {
logg->logError("Mali counters are not supported with Sample Rate: None.");
handleException();
}
// Initialize ftrace source before child as it's slow and dependens on nothing else
// If initialized later, us gator with ftrace has time sync issues
- if (gSessionData->ftraceDriver.countersEnabled()) {
- ftraceSource = new FtraceSource(&senderSem);
- if (!ftraceSource->prepare()) {
- logg->logError("Unable to prepare userspace source for capture");
- handleException();
- }
- ftraceSource->start();
+ // Must be initialized before senderThread is started as senderThread checks externalSource
+ externalSource = new ExternalSource(&senderSem);
+ if (!externalSource->prepare()) {
+ logg->logError("Unable to prepare external source for capture");
+ handleException();
}
+ externalSource->start();
// Must be after session XML is parsed
if (!primarySource->prepare()) {
- if (gSessionData->perf.isSetup()) {
+ if (gSessionData->mPerf.isSetup()) {
logg->logError("Unable to communicate with the perf API, please ensure that CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER are enabled. Please refer to README_Streamline.txt for more information.");
} else {
logg->logError("Unable to prepare gator driver for capture");
@@ -308,14 +300,6 @@ void Child::run() {
// Sender thread shall be halted until it is signaled for one shot mode
sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
- // Must be initialized before senderThread is started as senderThread checks externalSource
- externalSource = new ExternalSource(&senderSem);
- if (!externalSource->prepare()) {
- logg->logError("Unable to prepare external source for capture");
- handleException();
- }
- externalSource->start();
-
// Create the duration, stop, and sender threads
bool thread_creation_success = true;
if (gSessionData->mDuration > 0 && pthread_create(&durationThreadID, NULL, durationThread, NULL)) {
@@ -327,8 +311,8 @@ void Child::run() {
}
bool startUSSource = false;
- for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
- if (gSessionData->usDrivers[i]->countersEnabled()) {
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->mUsDrivers); ++i) {
+ if (gSessionData->mUsDrivers[i]->countersEnabled()) {
startUSSource = true;
}
}
@@ -360,9 +344,6 @@ void Child::run() {
primarySource->run();
// Wait for the other threads to exit
- if (ftraceSource != NULL) {
- ftraceSource->join();
- }
if (userSpaceSource != NULL) {
userSpaceSource->join();
}
@@ -384,7 +365,6 @@ void Child::run() {
logg->logMessage("Profiling ended.");
- delete ftraceSource;
delete userSpaceSource;
delete externalSource;
delete primarySource;
diff --git a/daemon/Command.cpp b/daemon/Command.cpp
index 0a6e3b9..22f8be7 100644
--- a/daemon/Command.cpp
+++ b/daemon/Command.cpp
@@ -9,6 +9,7 @@
#include "Command.h"
#include <fcntl.h>
+#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <sys/prctl.h>
@@ -23,14 +24,14 @@
#include "Logging.h"
#include "SessionData.h"
-static int getUid(const char *const name, char *const shPath, const char *const tmpDir) {
+static int getUid(const char *const name, const char *const tmpDir, uid_t *const uid) {
// Lookups may fail when using a different libc or a statically compiled executable
char gatorTemp[32];
snprintf(gatorTemp, sizeof(gatorTemp), "%s/gator_temp", tmpDir);
const int fd = open(gatorTemp, 600, O_CREAT | O_CLOEXEC);
if (fd < 0) {
- return -1;
+ return false;
}
close(fd);
@@ -43,15 +44,7 @@ static int getUid(const char *const name, char *const shPath, const char *const
handleException();
}
if (pid == 0) {
- char cargv1[] = "-c";
- char *cargv[] = {
- shPath,
- cargv1,
- cmd,
- NULL,
- };
-
- execv(cargv[0], cargv);
+ execlp("sh", "sh", "-c", cmd, NULL);
exit(-1);
}
while ((waitpid(pid, NULL, 0) < 0) && (errno == EINTR));
@@ -62,38 +55,42 @@ static int getUid(const char *const name, char *const shPath, const char *const
result = st.st_uid;
}
unlink(gatorTemp);
- return result;
+ *uid = result;
+ return true;
}
-static int getUid(const char *const name) {
+static bool getUid(const char *const name, uid_t *const uid, gid_t *const gid) {
// Look up the username
struct passwd *const user = getpwnam(name);
if (user != NULL) {
- return user->pw_uid;
+ *uid = user->pw_uid;
+ *gid = user->pw_gid;
+ return true;
}
+ // Unable to get the user without getpwanm, so create a unique uid by adding a fixed number to the pid
+ *gid = 0x484560f8 + getpid();
// Are we on Linux
- char cargv0l[] = "/bin/sh";
- if ((access(cargv0l, X_OK) == 0) && (access("/tmp", W_OK) == 0)) {
- return getUid(name, cargv0l, "/tmp");
+ if (access("/tmp", W_OK) == 0) {
+ return getUid(name, "/tmp", uid);
}
// Are we on android
- char cargv0a[] = "/system/bin/sh";
- if ((access(cargv0a, X_OK) == 0) && (access("/data", W_OK) == 0)) {
- return getUid(name, cargv0a, "/data");
+ if (access("/data", W_OK) == 0) {
+ return getUid(name, "/data", uid);
}
- return -1;
+ return false;
}
void *commandThread(void *) {
prctl(PR_SET_NAME, (unsigned long)&"gatord-command", 0, 0, 0);
const char *const name = gSessionData->mCaptureUser == NULL ? "nobody" : gSessionData->mCaptureUser;
- const int uid = getUid(name);
- if (uid < 0) {
+ uid_t uid;
+ gid_t gid;
+ if (!getUid(name, &uid, &gid)) {
logg->logError("Unable to look up the user %s, please double check that the user exists", name);
handleException();
}
@@ -113,16 +110,6 @@ void *commandThread(void *) {
handleException();
}
if (pid == 0) {
- char cargv0l[] = "/bin/sh";
- char cargv0a[] = "/system/bin/sh";
- char cargv1[] = "-c";
- char *cargv[] = {
- cargv0l,
- cargv1,
- gSessionData->mCaptureCommand,
- NULL,
- };
-
buf[0] = '\0';
close(pipefd[0]);
@@ -132,8 +119,16 @@ void *commandThread(void *) {
goto fail_exit;
}
- if (setuid(uid) != 0) {
- snprintf(buf, sizeof(buf), "setuid failed");
+ if (setgroups(1, &gid) != 0) {
+ snprintf(buf, sizeof(buf), "setgroups failed");
+ goto fail_exit;
+ }
+ if (setresgid(gid, gid, gid) != 0) {
+ snprintf(buf, sizeof(buf), "setresgid failed");
+ goto fail_exit;
+ }
+ if (setresuid(uid, uid, uid) != 0) {
+ snprintf(buf, sizeof(buf), "setresuid failed");
goto fail_exit;
}
@@ -145,9 +140,7 @@ void *commandThread(void *) {
}
}
- execv(cargv[0], cargv);
- cargv[0] = cargv0a;
- execv(cargv[0], cargv);
+ execlp("sh", "sh", "-c", gSessionData->mCaptureCommand, NULL);
snprintf(buf, sizeof(buf), "execv failed");
fail_exit:
diff --git a/daemon/Config.h b/daemon/Config.h
index eb31556..3c6752e 100644
--- a/daemon/Config.h
+++ b/daemon/Config.h
@@ -9,12 +9,19 @@
#ifndef CONFIG_H
#define CONFIG_H
+#define STRIFY2(ARG) #ARG
+#define STRIFY(ARG) STRIFY2(ARG)
+
#define ARRAY_LENGTH(A) static_cast<int>(sizeof(A)/sizeof((A)[0]))
#define ACCESS_ONCE(x) (*(volatile typeof(x)*)&(x))
#define MAX_PERFORMANCE_COUNTERS 50
#define NR_CPUS 32
+// If debugfs is not mounted at /sys/kernel/debug, update TRACING_PATH
+#define TRACING_PATH "/sys/kernel/debug/tracing"
+#define EVENTS_PATH TRACING_PATH "/events"
+
template<typename T>
static inline T min(const T a, const T b) {
return (a < b ? a : b);
diff --git a/daemon/ConfigurationXML.cpp b/daemon/ConfigurationXML.cpp
index be224a4..b433811 100644
--- a/daemon/ConfigurationXML.cpp
+++ b/daemon/ConfigurationXML.cpp
@@ -68,8 +68,10 @@ int ConfigurationXML::parse(const char* configurationXML) {
mxml_node_t *tree, *node;
int ret;
- // clear counter overflow
- gSessionData->mCounterOverflow = 0;
+ if (gSessionData->mCountersError != NULL) {
+ free(gSessionData->mCountersError);
+ gSessionData->mCountersError = NULL;
+ }
gSessionData->mIsEBS = false;
mIndex = 0;
@@ -98,6 +100,14 @@ int ConfigurationXML::parse(const char* configurationXML) {
mxmlDelete(tree);
+ if (gSessionData->mCountersError == NULL && mIndex > MAX_PERFORMANCE_COUNTERS) {
+ if (asprintf(&gSessionData->mCountersError, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, mIndex) <= 0) {
+ logg->logError("asprintf failed");
+ handleException();
+ }
+ }
+ gSessionData->mCcnDriver.validateCounters();
+
return ret;
}
@@ -149,7 +159,6 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
// handle all other performance counters
if (mIndex >= MAX_PERFORMANCE_COUNTERS) {
mIndex++;
- gSessionData->mCounterOverflow = mIndex;
return;
}
diff --git a/daemon/DiskIODriver.cpp b/daemon/DiskIODriver.cpp
index af62bb9..bd18bbd 100644
--- a/daemon/DiskIODriver.cpp
+++ b/daemon/DiskIODriver.cpp
@@ -53,7 +53,7 @@ DiskIODriver::~DiskIODriver() {
void DiskIODriver::readEvents(mxml_node_t *const) {
// Only for use with perf
- if (!gSessionData->perf.isSetup()) {
+ if (!gSessionData->mPerf.isSetup()) {
return;
}
diff --git a/daemon/DriverSource.cpp b/daemon/DriverSource.cpp
index 34920ce..caa956f 100644
--- a/daemon/DriverSource.cpp
+++ b/daemon/DriverSource.cpp
@@ -28,33 +28,8 @@
extern Child *child;
DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL), mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) {
- int driver_version = 0;
-
mBuffer = new Buffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem);
- if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
- logg->logError("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(
- "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(
- "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();
- }
- }
+ checkVersion();
int enable = -1;
if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) {
@@ -85,6 +60,35 @@ DriverSource::~DriverSource() {
}
}
+void DriverSource::checkVersion() {
+ int driverVersion = 0;
+
+ if (readIntDriver("/dev/gator/version", &driverVersion) == -1) {
+ logg->logError("Error reading gator driver version");
+ handleException();
+ }
+
+ // Verify the driver version matches the daemon version
+ if (driverVersion != PROTOCOL_VERSION) {
+ if ((driverVersion > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
+ // One of the mismatched versions is development version
+ logg->logError(
+ "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", driverVersion, PROTOCOL_VERSION);
+ handleException();
+ } else {
+ // Release version mismatch
+ logg->logError(
+ "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
+ ">> Please upgrade the driver and daemon to the latest versions.", driverVersion, PROTOCOL_VERSION);
+ handleException();
+ }
+ }
+}
+
bool DriverSource::prepare() {
// Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, mBufferSize);
diff --git a/daemon/DriverSource.h b/daemon/DriverSource.h
index 32d983d..971a4d9 100644
--- a/daemon/DriverSource.h
+++ b/daemon/DriverSource.h
@@ -29,6 +29,7 @@ public:
bool isDone();
void write(Sender *sender);
+ static void checkVersion();
static int readIntDriver(const char *fullpath, int *value);
static int readInt64Driver(const char *fullpath, int64_t *value);
static int writeDriver(const char *fullpath, const char *data);
diff --git a/daemon/EventsXML.cpp b/daemon/EventsXML.cpp
index cec08d5..d8044d8 100644
--- a/daemon/EventsXML.cpp
+++ b/daemon/EventsXML.cpp
@@ -50,7 +50,7 @@ mxml_node_t *EventsXML::getTree() {
// Load the provided or default events xml
if (gSessionData->mEventsXMLPath) {
strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
- fl = fopen(path, "r");
+ fl = fopen_cloexec(path, "r");
if (fl) {
xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
fclose(fl);
@@ -63,7 +63,7 @@ mxml_node_t *EventsXML::getTree() {
// Append additional events XML
if (gSessionData->mEventsXMLAppend) {
- fl = fopen(gSessionData->mEventsXMLAppend, "r");
+ fl = fopen_cloexec(gSessionData->mEventsXMLAppend, "r");
if (fl == NULL) {
logg->logError("Unable to open additional events XML %s", gSessionData->mEventsXMLAppend);
handleException();
diff --git a/daemon/ExternalDriver.cpp b/daemon/ExternalDriver.cpp
new file mode 100644
index 0000000..c1b7983
--- /dev/null
+++ b/daemon/ExternalDriver.cpp
@@ -0,0 +1,269 @@
+/**
+ * Copyright (C) ARM Limited 2010-2015. 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 "ExternalDriver.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "Buffer.h"
+#include "Logging.h"
+#include "OlySocket.h"
+#include "SessionData.h"
+
+static const char MALI_UTGARD_SETUP[] = "\0mali-utgard-setup";
+static const char SETUP_VERSION[] = "ANNOTATE_SETUP 1\n";
+static const size_t HEADER_SIZE = 1 + sizeof(uint32_t);
+
+#define HEADER_ERROR 0x80
+#define HEADER_ACK 0x81
+#define HEADER_REQUEST_COUNTERS 0x82
+#define HEADER_COUNTERS 0x83
+#define HEADER_ENABLE_COUNTERS 0x84
+#define HEADER_START 0x85
+
+static uint32_t readLEInt(char *const buf)
+{
+ size_t i;
+ uint32_t v;
+
+ v = 0;
+ for (i = 0; i < sizeof(v); ++i)
+ v |= (uint32_t)buf[i] << 8*i;
+
+ return v;
+}
+
+static int readPackedInt(char *const buf, const size_t bufSize, size_t *const pos, uint64_t *const l)
+{
+ uint8_t shift = 0;
+ uint8_t b = ~0;
+
+ *l = 0;
+ while ((b & 0x80) != 0) {
+ if (*pos >= bufSize) {
+ return -1;
+ }
+ b = buf[*pos];
+ *pos += 1;
+ *l |= (uint64_t)(b & 0x7f) << shift;
+ shift += 7;
+ }
+
+ if (shift < 8*sizeof(*l) && (b & 0x40) != 0) {
+ *l |= -(1 << shift);
+ }
+
+ return 0;
+}
+
+class ExternalCounter : public DriverCounter {
+public:
+ ExternalCounter(DriverCounter *next, const char *name, int cores) : DriverCounter(next, name), mCores(cores), mEvent(-1) {}
+
+ ~ExternalCounter() {
+ }
+
+ int getCores() const { return mCores; }
+ void setEvent(const int event) { mEvent = event; }
+ int getEvent() const { return mEvent; }
+
+private:
+ const int mCores;
+ int mEvent;
+
+ // Intentionally undefined
+ ExternalCounter(const ExternalCounter &);
+ ExternalCounter &operator=(const ExternalCounter &);
+};
+
+ExternalDriver::ExternalDriver() : mUds(-1), mQueried(false), mStarted(false) {
+}
+
+bool ExternalDriver::connect() const {
+ if (mUds < 0) {
+ mUds = OlySocket::connect(MALI_UTGARD_SETUP, sizeof(MALI_UTGARD_SETUP));
+ if (mUds >= 0 && !writeAll(mUds, SETUP_VERSION, sizeof(SETUP_VERSION) - 1)) {
+ logg->logError("Unable to send setup version");
+ handleException();
+ }
+ }
+ return mUds >= 0;
+}
+
+void ExternalDriver::disconnect() {
+ if (mUds >= 0) {
+ close(mUds);
+ mUds = -1;
+ mStarted = false;
+ }
+}
+
+void ExternalDriver::query() const {
+ if (mQueried) {
+ return;
+ }
+ // Only try once even if it fails otherwise not all the possible counters may be shown
+ mQueried = true;
+
+ char *const buf = gSessionData->mSharedData->mMaliUtgardCounters;
+ const size_t bufSize = sizeof(gSessionData->mSharedData->mMaliUtgardCounters);
+ size_t size = 0;
+
+ if (!connect()) {
+ size = gSessionData->mSharedData->mMaliUtgardCountersSize;
+ logg->logMessage("Unable to connect, using cached version; size: %zi", size);
+ } else {
+ gSessionData->mSharedData->mMaliUtgardCountersSize = 0;
+
+ buf[0] = HEADER_REQUEST_COUNTERS;
+ size_t pos = HEADER_SIZE;
+ Buffer::writeLEInt((unsigned char *)(buf + 1), pos);
+ if (!writeAll(mUds, buf, pos)) {
+ logg->logError("Unable to send request counters message");
+ handleException();
+ }
+
+ if (!readAll(mUds, buf, HEADER_SIZE) || buf[0] != (char)HEADER_COUNTERS) {
+ logg->logError("Unable to read request counters response header");
+ handleException();
+ }
+ size = readLEInt(buf + 1);
+ if (size > bufSize || !readAll(mUds, buf, size - HEADER_SIZE)) {
+ logg->logError("Unable to read request counters response");
+ handleException();
+ }
+
+ size -= HEADER_SIZE;
+ gSessionData->mSharedData->mMaliUtgardCountersSize = size;
+ logg->logMessage("Requested counters; size: %zi", size);
+ }
+
+ size_t pos = 0;
+ while (pos < size) {
+ size_t begin = pos;
+ char *name = NULL;
+ uint64_t cores = -1;
+ while (pos < size && buf[pos] != '\0') {
+ ++pos;
+ }
+ if (pos > begin) {
+ name = strndup(buf + begin, pos - begin);
+ }
+ if (pos < size && buf[pos] == '\0') {
+ ++pos;
+ }
+ ;
+ if (name != NULL && readPackedInt(buf, bufSize, &pos, &cores) == 0) {
+ // Cheat so that this can be 'const'
+ ((ExternalDriver *)(this))->setCounters(new ExternalCounter(getCounters(), name, cores));
+ }
+ }
+
+ if (pos != size) {
+ logg->logError("Unable to parse request counters response");
+ handleException();
+ }
+}
+
+void ExternalDriver::start() {
+ if (!connect()) {
+ return;
+ }
+
+ if (mStarted) {
+ return;
+ }
+ // Only start once
+ mStarted = true;
+
+ char buf[1<<12];
+ int pos;
+
+ buf[0] = HEADER_ENABLE_COUNTERS;
+ pos = HEADER_SIZE;
+ for (ExternalCounter *counter = static_cast<ExternalCounter *>(getCounters()); counter != NULL; counter = static_cast<ExternalCounter *>(counter->getNext())) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ size_t nameLen = strlen(counter->getName());
+ if (pos + nameLen + 1 + 2*Buffer::MAXSIZE_PACK32 > sizeof(buf)) {
+ logg->logError("Unable to enable counters, message is too large");
+ handleException();
+ }
+ memcpy(buf + pos, counter->getName(), nameLen + 1);
+ pos += nameLen + 1;
+ Buffer::packInt(buf, sizeof(buf), pos, counter->getEvent());
+ Buffer::packInt(buf, sizeof(buf), pos, counter->getKey());
+ }
+ Buffer::writeLEInt((unsigned char *)(buf + 1), pos);
+ if (!writeAll(mUds, buf, pos)) {
+ logg->logError("Unable to send enable counters message");
+ handleException();
+ }
+
+ size_t size = 0;
+ if (!readAll(mUds, buf, HEADER_SIZE) || buf[0] != (char)HEADER_ACK) {
+ logg->logError("Unable to read enable counters response header");
+ handleException();
+ }
+ size = readLEInt(buf + 1);
+ if (size != HEADER_SIZE) {
+ logg->logError("Unable to parse enable counters response");
+ handleException();
+ }
+
+ buf[0] = HEADER_START;
+ pos = HEADER_SIZE;
+ // ns/sec / samples/sec = ns/sample
+ // For sample rate of none, sample every 100ms
+ Buffer::packInt(buf, sizeof(buf), pos, NS_PER_S / (gSessionData->mSampleRate == 0 ? 10 : gSessionData->mSampleRate));
+ Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mLiveRate);
+ Buffer::writeLEInt((unsigned char *)(buf + 1), pos);
+ if (!writeAll(mUds, buf, pos)) {
+ logg->logError("Unable to send start message");
+ handleException();
+ }
+
+ size = 0;
+ if (!readAll(mUds, buf, HEADER_SIZE) || buf[0] != (char)HEADER_ACK) {
+ logg->logError("Unable to read start response header");
+ handleException();
+ }
+ size = readLEInt(buf + 1);
+ if (size != HEADER_SIZE) {
+ logg->logError("Unable to parse start response");
+ handleException();
+ }
+}
+
+bool ExternalDriver::claimCounter(const Counter &counter) const {
+ query();
+ return super::claimCounter(counter);
+}
+
+void ExternalDriver::setupCounter(Counter &counter) {
+ ExternalCounter *const externalCounter = static_cast<ExternalCounter *>(findCounter(counter));
+ if (externalCounter == NULL) {
+ counter.setEnabled(false);
+ return;
+ }
+ externalCounter->setEnabled(true);
+ counter.setKey(externalCounter->getKey());
+ if (counter.getEvent() != -1) {
+ externalCounter->setEvent(counter.getEvent());
+ }
+ if (externalCounter->getCores() > 0) {
+ counter.setCores(externalCounter->getCores());
+ }
+}
+
+void ExternalDriver::resetCounters() {
+ query();
+ super::resetCounters();
+}
diff --git a/daemon/ExternalDriver.h b/daemon/ExternalDriver.h
new file mode 100644
index 0000000..d88f9e1
--- /dev/null
+++ b/daemon/ExternalDriver.h
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) ARM Limited 2010-2015. 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 EXTERNALDRIVER_H
+#define EXTERNALDRIVER_H
+
+#include "Driver.h"
+
+class ExternalDriver : public SimpleDriver {
+public:
+ ExternalDriver();
+
+ bool claimCounter(const Counter &counter) const;
+ void resetCounters();
+ void setupCounter(Counter &counter);
+
+ void start();
+
+ void disconnect();
+
+private:
+ typedef SimpleDriver super;
+
+ bool connect() const;
+ void query() const;
+
+ mutable int mUds;
+ mutable bool mQueried;
+ bool mStarted;
+
+ // Intentionally unimplemented
+ ExternalDriver(const ExternalDriver &);
+ ExternalDriver &operator=(const ExternalDriver &);
+};
+
+#endif // EXTERNALDRIVER_H
diff --git a/daemon/ExternalSource.cpp b/daemon/ExternalSource.cpp
index 8d71b6d..e87fb9e 100644
--- a/daemon/ExternalSource.cpp
+++ b/daemon/ExternalSource.cpp
@@ -13,6 +13,7 @@
#include <unistd.h>
#include "Child.h"
+#include "DriverSource.h"
#include "Logging.h"
#include "OlySocket.h"
#include "SessionData.h"
@@ -26,25 +27,10 @@ static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n";
static const char MALI_GRAPHICS[] = "\0mali_thirdparty_server";
static const char MALI_GRAPHICS_STARTUP[] = "\0mali_thirdparty_client";
static const char MALI_GRAPHICS_V1[] = "MALI_GRAPHICS 1\n";
+static const char MALI_UTGARD_STARTUP[] = "\0mali-utgard-startup";
+static const char FTRACE_V1[] = "FTRACE 1\n";
-static bool setNonblock(const int fd) {
- int flags;
-
- flags = fcntl(fd, F_GETFL);
- if (flags < 0) {
- logg->logMessage("fcntl getfl failed");
- return false;
- }
-
- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
- logg->logMessage("fcntl setfl failed");
- return false;
- }
-
- return true;
-}
-
-ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mAnnotate(8083), mAnnotateUds(STREAMLINE_ANNOTATE, sizeof(STREAMLINE_ANNOTATE), true), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) {
+ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mUtgardStartupUds(MALI_UTGARD_STARTUP, sizeof(MALI_UTGARD_STARTUP)), mAnnotate(8083), mAnnotateUds(STREAMLINE_ANNOTATE, sizeof(STREAMLINE_ANNOTATE), true), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1), mFtraceFd(-1) {
sem_init(&mBufferSem, 0, 0);
}
@@ -91,7 +77,7 @@ bool ExternalSource::connectMali() {
}
bool ExternalSource::connectMve() {
- if (!gSessionData->maliVideo.countersEnabled()) {
+ if (!gSessionData->mMaliVideo.countersEnabled()) {
return true;
}
@@ -100,7 +86,7 @@ bool ExternalSource::connectMve() {
return false;
}
- if (!gSessionData->maliVideo.start(mMveUds)) {
+ if (!gSessionData->mMaliVideo.start(mMveUds)) {
return false;
}
@@ -109,10 +95,27 @@ bool ExternalSource::connectMve() {
return true;
}
+void ExternalSource::connectFtrace() {
+ if (!gSessionData->mFtraceDriver.isSupported()) {
+ return;
+ }
+
+ gSessionData->mFtraceDriver.prepare();
+
+ mFtraceFd = open(TRACING_PATH "/trace_pipe", O_RDONLY | O_CLOEXEC);
+ if (mFtraceFd < 0) {
+ logg->logError("Unable to open trace_pipe");
+ handleException();
+ }
+
+ configureConnection(mFtraceFd, FTRACE_V1, sizeof(FTRACE_V1));
+}
+
bool ExternalSource::prepare() {
if (!mMonitor.init() ||
!setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd()) ||
!setNonblock(mMaliStartupUds.getFd()) || !mMonitor.add(mMaliStartupUds.getFd()) ||
+ !setNonblock(mUtgardStartupUds.getFd()) || !mMonitor.add(mUtgardStartupUds.getFd()) ||
!setNonblock(mAnnotate.getFd()) || !mMonitor.add(mAnnotate.getFd()) ||
!setNonblock(mAnnotateUds.getFd()) || !mMonitor.add(mAnnotateUds.getFd()) ||
false) {
@@ -121,6 +124,8 @@ bool ExternalSource::prepare() {
connectMali();
connectMve();
+ connectFtrace();
+ gSessionData->mExternalDriver.start();
return true;
}
@@ -147,6 +152,30 @@ void ExternalSource::run() {
logg->logMessage("Writing to annotate pipe failed");
}
+ if (mFtraceFd >= 0) {
+ gSessionData->mAtraceDriver.start();
+
+ if (DriverSource::writeDriver(TRACING_PATH "/tracing_on", "1") != 0) {
+ logg->logError("Unable to turn ftrace on");
+ handleException();
+ }
+ }
+
+ // Wait until monotonicStarted is set before sending data
+ int64_t monotonicStarted = 0;
+ while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
+ usleep(10);
+
+ if (gSessionData->mPerf.isSetup()) {
+ monotonicStarted = gSessionData->mMonotonicStarted;
+ } else {
+ if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
+ logg->logError("Error reading gator driver start time");
+ handleException();
+ }
+ }
+ }
+
while (gSessionData->mSessionIsActive) {
struct epoll_event events[16];
// Clear any pending sem posts
@@ -179,6 +208,13 @@ void ExternalSource::run() {
logg->logError("Unable to configure incoming Mali graphics connection");
handleException();
}
+ } else if (fd == mUtgardStartupUds.getFd()) {
+ // Mali Utgard says it's alive
+ int client = mUtgardStartupUds.acceptConnection();
+ // Don't read from this connection, configure utgard and expect them to reconnect with annotations
+ close(client);
+ gSessionData->mExternalDriver.disconnect();
+ gSessionData->mExternalDriver.start();
} else if (fd == mAnnotate.getFd()) {
int client = mAnnotate.acceptConnection();
if (!setNonblock(client) || !mMonitor.add(client)) {
@@ -243,8 +279,14 @@ void ExternalSource::run() {
mBuffer.setDone();
+ if (mFtraceFd >= 0) {
+ gSessionData->mFtraceDriver.stop();
+ gSessionData->mAtraceDriver.stop();
+ close(mFtraceFd);
+ }
+
if (mMveUds >= 0) {
- gSessionData->maliVideo.stop(mMveUds);
+ gSessionData->mMaliVideo.stop(mMveUds);
}
mInterruptFd = -1;
diff --git a/daemon/ExternalSource.h b/daemon/ExternalSource.h
index 25ae7cd..69d16af 100644
--- a/daemon/ExternalSource.h
+++ b/daemon/ExternalSource.h
@@ -34,17 +34,20 @@ private:
void configureConnection(const int fd, const char *const handshake, size_t size);
bool connectMali();
bool connectMve();
+ void connectFtrace();
sem_t mBufferSem;
Buffer mBuffer;
Monitor mMonitor;
OlyServerSocket mMveStartupUds;
OlyServerSocket mMaliStartupUds;
+ OlyServerSocket mUtgardStartupUds;
OlyServerSocket mAnnotate;
OlyServerSocket mAnnotateUds;
int mInterruptFd;
int mMaliUds;
int mMveUds;
+ int mFtraceFd;
// Intentionally unimplemented
ExternalSource(const ExternalSource &);
diff --git a/daemon/FtraceDriver.cpp b/daemon/FtraceDriver.cpp
index 98bd0a5..7c57cfc 100644
--- a/daemon/FtraceDriver.cpp
+++ b/daemon/FtraceDriver.cpp
@@ -10,22 +10,25 @@
#include <regex.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "Config.h"
#include "DriverSource.h"
#include "Logging.h"
+#include "SessionData.h"
#include "Setup.h"
class FtraceCounter : public DriverCounter {
public:
- FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable);
+ FtraceCounter(DriverCounter *next, char *name, const char *enable);
~FtraceCounter();
void prepare();
- int read(const char *const line, int64_t *values);
void stop();
private:
- regex_t mReg;
char *const mEnable;
int mWasEnabled;
@@ -34,18 +37,10 @@ private:
FtraceCounter &operator=(const FtraceCounter &);
};
-FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable) : DriverCounter(next, name), mEnable(enable == NULL ? NULL : strdup(enable)) {
- int result = regcomp(&mReg, regex, REG_EXTENDED);
- if (result != 0) {
- char buf[128];
- regerror(result, &mReg, buf, sizeof(buf));
- logg->logError("Invalid regex '%s': %s", regex, buf);
- handleException();
- }
+FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *enable) : DriverCounter(next, name), mEnable(enable == NULL ? NULL : strdup(enable)) {
}
FtraceCounter::~FtraceCounter() {
- regfree(&mReg);
if (mEnable != NULL) {
free(mEnable);
}
@@ -57,7 +52,7 @@ void FtraceCounter::prepare() {
}
char buf[1<<10];
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
+ snprintf(buf, sizeof(buf), EVENTS_PATH "/%s/enable", mEnable);
if ((DriverSource::readIntDriver(buf, &mWasEnabled) != 0) ||
(DriverSource::writeDriver(buf, 1) != 0)) {
logg->logError("Unable to read or write to %s", buf);
@@ -65,43 +60,17 @@ void FtraceCounter::prepare() {
}
}
-int FtraceCounter::read(const char *const line, int64_t *values) {
- regmatch_t match[2];
- int result = regexec(&mReg, line, 2, match, 0);
- if (result != 0) {
- // No match
- return 0;
- }
-
- int64_t value;
- if (match[1].rm_so < 0) {
- value = 1;
- } else {
- errno = 0;
- value = strtoll(line + match[1].rm_so, NULL, 0);
- if (errno != 0) {
- logg->logError("Parsing %s failed: %s", getName(), strerror(errno));
- handleException();
- }
- }
-
- values[0] = getKey();
- values[1] = value;
-
- return 1;
-}
-
void FtraceCounter::stop() {
if (mEnable == NULL) {
return;
}
char buf[1<<10];
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
+ snprintf(buf, sizeof(buf), EVENTS_PATH "/%s/enable", mEnable);
DriverSource::writeDriver(buf, mWasEnabled);
}
-FtraceDriver::FtraceDriver() : mValues(NULL) {
+FtraceDriver::FtraceDriver() : mValues(NULL), mSupported(false), mTracingOn(0) {
}
FtraceDriver::~FtraceDriver() {
@@ -118,10 +87,20 @@ void FtraceDriver::readEvents(mxml_node_t *const xml) {
// The perf clock was added in 3.10
if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 10, 0)) {
+ mSupported = false;
logg->logMessage("Unsupported kernel version, to use ftrace please upgrade to Linux 3.10 or later");
return;
}
+ // Is debugfs or tracefs available?
+ if (access(TRACING_PATH, R_OK) != 0) {
+ mSupported = false;
+ logg->logMessage("Unable to locate the tracing directory, disabling ftrace");
+ return;
+ }
+
+ mSupported = true;
+
mxml_node_t *node = xml;
int count = 0;
while (true) {
@@ -143,20 +122,28 @@ void FtraceDriver::readEvents(mxml_node_t *const xml) {
logg->logError("The regex counter %s is missing the required regex attribute", counter);
handleException();
}
- bool addCounter = true;
+
+ const char *tracepoint = mxmlElementGetAttr(node, "tracepoint");
const char *enable = mxmlElementGetAttr(node, "enable");
+ if (enable == NULL) {
+ enable = tracepoint;
+ }
+ if (gSessionData->mPerf.isSetup() && tracepoint != NULL) {
+ logg->logMessage("Not using ftrace for counter %s", counter);
+ continue;
+ }
if (enable != NULL) {
char buf[1<<10];
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", enable);
+ snprintf(buf, sizeof(buf), EVENTS_PATH "/%s/enable", enable);
if (access(buf, W_OK) != 0) {
logg->logMessage("Disabling counter %s, %s not found", counter, buf);
- addCounter = false;
+ continue;
}
}
- if (addCounter) {
- setCounters(new FtraceCounter(getCounters(), strdup(counter), regex, enable));
- ++count;
- }
+
+ logg->logMessage("Using ftrace for %s", counter);
+ setCounters(new FtraceCounter(getCounters(), strdup(counter), enable));
+ ++count;
}
mValues = new int64_t[2*count];
@@ -169,23 +156,37 @@ void FtraceDriver::prepare() {
}
counter->prepare();
}
-}
-int FtraceDriver::read(const char *line, int64_t **buf) {
- int count = 0;
+ if (DriverSource::readIntDriver(TRACING_PATH "/tracing_on", &mTracingOn)) {
+ logg->logError("Unable to read if ftrace is enabled");
+ handleException();
+ }
- for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
- if (!counter->isEnabled()) {
- continue;
+ if (DriverSource::writeDriver(TRACING_PATH "/tracing_on", "0") != 0) {
+ logg->logError("Unable to turn ftrace off before truncating the buffer");
+ handleException();
+ }
+
+ {
+ int fd;
+ fd = open(TRACING_PATH "/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
+ if (fd < 0) {
+ logg->logError("Unable truncate ftrace buffer: %s", strerror(errno));
+ handleException();
}
- count += counter->read(line, mValues + 2*count);
+ close(fd);
}
- *buf = mValues;
- return count;
+ if (DriverSource::writeDriver(TRACING_PATH "/trace_clock", "perf") != 0) {
+ logg->logError("Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
+ handleException();
+ }
}
void FtraceDriver::stop() {
+ DriverSource::writeDriver(TRACING_PATH "/tracing_on", mTracingOn);
+ DriverSource::writeDriver(TRACING_PATH "/trace_clock", "local");
+
for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
if (!counter->isEnabled()) {
continue;
diff --git a/daemon/FtraceDriver.h b/daemon/FtraceDriver.h
index b79dc91..6e592d7 100644
--- a/daemon/FtraceDriver.h
+++ b/daemon/FtraceDriver.h
@@ -19,11 +19,14 @@ public:
void readEvents(mxml_node_t *const xml);
void prepare();
- int read(const char *line, int64_t **buf);
void stop();
+ bool isSupported() const { return mSupported; }
+
private:
int64_t *mValues;
+ bool mSupported;
+ int mTracingOn;
// Intentionally unimplemented
FtraceDriver(const FtraceDriver &);
diff --git a/daemon/FtraceSource.cpp b/daemon/FtraceSource.cpp
deleted file mode 100644
index 14a48b3..0000000
--- a/daemon/FtraceSource.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2010-2015. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "FtraceSource.h"
-
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#include "Child.h"
-#include "DriverSource.h"
-#include "Logging.h"
-#include "SessionData.h"
-
-extern Child *child;
-
-static void handler(int signum)
-{
- (void)signum;
-};
-
-FtraceSource::FtraceSource(sem_t *senderSem) : mFtraceFh(NULL), mBuffer(0, FRAME_BLOCK_COUNTER, 128*1024, senderSem), mTid(-1), mTracingOn(0) {
-}
-
-FtraceSource::~FtraceSource() {
-}
-
-bool FtraceSource::prepare() {
- {
- struct sigaction act;
- act.sa_handler = handler;
- act.sa_flags = (int)SA_RESETHAND;
- if (sigaction(SIGUSR1, &act, NULL) != 0) {
- logg->logError("sigaction failed: %s\n", strerror(errno));
- handleException();
- }
- }
-
- gSessionData->ftraceDriver.prepare();
-
- if (DriverSource::readIntDriver("/sys/kernel/debug/tracing/tracing_on", &mTracingOn)) {
- logg->logError("Unable to read if ftrace is enabled");
- handleException();
- }
-
- if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "0") != 0) {
- logg->logError("Unable to turn ftrace off before truncating the buffer");
- handleException();
- }
-
- {
- int fd;
- fd = open("/sys/kernel/debug/tracing/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
- if (fd < 0) {
- logg->logError("Unable truncate ftrace buffer: %s", strerror(errno));
- handleException();
- }
- close(fd);
- }
-
- if (DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "perf") != 0) {
- logg->logError("Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
- handleException();
- }
-
- mFtraceFh = fopen_cloexec("/sys/kernel/debug/tracing/trace_pipe", "rb");
- if (mFtraceFh == NULL) {
- logg->logError("Unable to open trace_pipe");
- handleException();
- }
-
- return true;
-}
-
-void FtraceSource::run() {
- prctl(PR_SET_NAME, (unsigned long)&"gatord-ftrace", 0, 0, 0);
- mTid = syscall(__NR_gettid);
-
- if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "1") != 0) {
- logg->logError("Unable to turn ftrace on");
- handleException();
- }
-
- // Wait until monotonicStarted is set before sending data
- int64_t monotonicStarted = 0;
- while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
- usleep(10);
-
- if (gSessionData->perf.isSetup()) {
- monotonicStarted = gSessionData->mMonotonicStarted;
- } else {
- if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
- logg->logError("Error reading gator driver start time");
- handleException();
- }
- }
- }
-
- while (gSessionData->mSessionIsActive) {
- char buf[1<<12];
-
- if (fgets(buf, sizeof(buf), mFtraceFh) == NULL) {
- if (errno == EINTR) {
- // Interrupted by interrupt - likely user request to terminate
- break;
- }
- logg->logError("Unable read trace data: %s", strerror(errno));
- handleException();
- }
-
- const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted;
-
- char *const colon = strstr(buf, ": ");
- if (colon == NULL) {
- if (strstr(buf, " [LOST ") != NULL) {
- logg->logError("Ftrace events lost, aborting the capture. It is recommended to discard this report and collect a new capture. If this error occurs often, please reduce the number of ftrace counters selected or the amount of ftrace events generated.");
- } else {
- logg->logError("Unable to find colon: %s", buf);
- }
- handleException();
- }
- *colon = '\0';
-
- char *const space = strrchr(buf, ' ');
- if (space == NULL) {
- logg->logError("Unable to find space: %s", buf);
- handleException();
- }
- *colon = ':';
-
- int64_t *data = NULL;
- int count = gSessionData->ftraceDriver.read(colon + 2, &data);
- if (count > 0) {
- errno = 0;
- const long long time = strtod(space, NULL) * 1000000000;
- if (errno != 0) {
- logg->logError("Unable to parse time: %s", strerror(errno));
- handleException();
- }
- mBuffer.event64(-1, time);
-
- for (int i = 0; i < count; ++i) {
- mBuffer.event64(data[2*i + 0], data[2*i + 1]);
- }
-
- mBuffer.check(currTime);
-
- if (gSessionData->mOneShot && gSessionData->mSessionIsActive && (mBuffer.bytesAvailable() <= 0)) {
- logg->logMessage("One shot (ftrace)");
- child->endSession();
- }
- }
-
- }
-
- mBuffer.setDone();
-
- DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", mTracingOn);
- fclose(mFtraceFh);
- DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "local");
- gSessionData->ftraceDriver.stop();
-}
-
-void FtraceSource::interrupt() {
- // Closing the underlying file handle does not result in the read on the ftrace file handle to return, so send a signal to the thread
- syscall(__NR_tgkill, getpid(), mTid, SIGUSR1);
-}
-
-bool FtraceSource::isDone() {
- return mBuffer.isDone();
-}
-
-void FtraceSource::write(Sender *sender) {
- // Don't send ftrace data until the summary packet is sent so that monotonic delta is available
- if (!gSessionData->mSentSummary) {
- return;
- }
- if (!mBuffer.isDone()) {
- mBuffer.write(sender);
- }
-}
diff --git a/daemon/FtraceSource.h b/daemon/FtraceSource.h
deleted file mode 100644
index bc068d2..0000000
--- a/daemon/FtraceSource.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Copyright (C) ARM Limited 2010-2015. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef FTRACESOURCE_H
-#define FTRACESOURCE_H
-
-#include <semaphore.h>
-#include <stdio.h>
-
-#include "Buffer.h"
-#include "Source.h"
-
-class FtraceSource : public Source {
-public:
- FtraceSource(sem_t *senderSem);
- ~FtraceSource();
-
- bool prepare();
- void run();
- void interrupt();
-
- bool isDone();
- void write(Sender *sender);
-
-private:
- void waitFor(const int bytes);
-
- FILE *mFtraceFh;
- Buffer mBuffer;
- int mTid;
- int mTracingOn;
-
- // Intentionally unimplemented
- FtraceSource(const FtraceSource &);
- FtraceSource &operator=(const FtraceSource &);
-};
-
-#endif // FTRACESOURCE_H
diff --git a/daemon/MaliVideoDriver.cpp b/daemon/MaliVideoDriver.cpp
index 2db332d..209a2d3 100644
--- a/daemon/MaliVideoDriver.cpp
+++ b/daemon/MaliVideoDriver.cpp
@@ -58,6 +58,7 @@ MaliVideoDriver::~MaliVideoDriver() {
}
void MaliVideoDriver::readEvents(mxml_node_t *const xml) {
+ // Always create the counters as /dev/mv500 may show up after gatord starts
mxml_node_t *node = xml;
while (true) {
node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
@@ -82,12 +83,22 @@ void MaliVideoDriver::readEvents(mxml_node_t *const xml) {
int MaliVideoDriver::writeCounters(mxml_node_t *root) const {
if (access("/dev/mv500", F_OK) != 0) {
+ // Don't show the counters in counter configuration
return 0;
}
return super::writeCounters(root);
}
+bool MaliVideoDriver::claimCounter(const Counter &counter) const {
+ if (access("/dev/mv500", F_OK) != 0) {
+ // Don't add the counters to captured XML
+ return 0;
+ }
+
+ return super::claimCounter(counter);
+}
+
void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos) {
// size
int numEnabled = 0;
@@ -104,20 +115,6 @@ void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const
}
}
-static bool writeAll(const int mveUds, const char *const buf, const int pos) {
- int written = 0;
- while (written < pos) {
- size_t bytes = ::write(mveUds, buf + written, pos - written);
- if (bytes <= 0) {
- logg->logMessage("write failed");
- return false;
- }
- written += bytes;
- }
-
- return true;
-}
-
bool MaliVideoDriver::start(const int mveUds) {
char buf[256];
int pos = 0;
@@ -146,7 +143,7 @@ bool MaliVideoDriver::start(const int mveUds) {
// data_protocol_version
Buffer::packInt(buf, sizeof(buf), pos, 1);
// sample_rate - convert samples/second to ms/sample
- Buffer::packInt(buf, sizeof(buf), pos, 1000/gSessionData->mSampleRate);
+ Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mSampleRate/1000);
// live_rate - convert ns/flush to ms/flush
Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mLiveRate/1000000);
@@ -183,7 +180,6 @@ void MaliVideoDriver::stop(const int mveUds) {
buf[pos++] = 'T';
buf[pos++] = 'O';
buf[pos++] = 'P';
- marshalEnable(MVCT_COUNTER, buf, sizeof(buf), pos);
writeAll(mveUds, buf, pos);
diff --git a/daemon/MaliVideoDriver.h b/daemon/MaliVideoDriver.h
index 35b0558..fd01b1b 100644
--- a/daemon/MaliVideoDriver.h
+++ b/daemon/MaliVideoDriver.h
@@ -30,6 +30,7 @@ public:
void readEvents(mxml_node_t *const root);
int writeCounters(mxml_node_t *root) const;
+ bool claimCounter(const Counter &counter) const;
bool start(const int mveUds);
void stop(const int mveUds);
diff --git a/daemon/MemInfoDriver.cpp b/daemon/MemInfoDriver.cpp
index 6818b97..4c0b051 100644
--- a/daemon/MemInfoDriver.cpp
+++ b/daemon/MemInfoDriver.cpp
@@ -44,7 +44,7 @@ MemInfoDriver::~MemInfoDriver() {
void MemInfoDriver::readEvents(mxml_node_t *const) {
// Only for use with perf
- if (!gSessionData->perf.isSetup()) {
+ if (!gSessionData->mPerf.isSetup()) {
return;
}
diff --git a/daemon/NetDriver.cpp b/daemon/NetDriver.cpp
index 56b25e0..ab36211 100644
--- a/daemon/NetDriver.cpp
+++ b/daemon/NetDriver.cpp
@@ -52,7 +52,7 @@ NetDriver::~NetDriver() {
void NetDriver::readEvents(mxml_node_t *const) {
// Only for use with perf
- if (!gSessionData->perf.isSetup()) {
+ if (!gSessionData->mPerf.isSetup()) {
return;
}
diff --git a/daemon/PerfDriver.cpp b/daemon/PerfDriver.cpp
index 796ee75..e5f8aaa 100644
--- a/daemon/PerfDriver.cpp
+++ b/daemon/PerfDriver.cpp
@@ -56,9 +56,9 @@ static const struct gator_cpu gator_cpus[] = {
{ 0x51049, "KraitSIM", "Krait", 4 },
{ 0x5104d, "Krait", "Krait", 4 },
{ 0x5106f, "Krait S4 Pro", "Krait", 4 },
- { 0x41d03, "Cortex-A53", "ARM_Cortex-A53", 6 },
- { 0x41d07, "Cortex-A57", "ARM_Cortex-A57", 6 },
- { 0x41d08, "Cortex-A72", "ARM_Cortex-A72", 6 },
+ { 0x41d03, "Cortex-A53", "ARMv8_Cortex_A53", 6 },
+ { 0x41d07, "Cortex-A57", "ARMv8_Cortex_A57", 6 },
+ { 0x41d08, "Cortex-A72", "ARMv8_Cortex_A72", 6 },
};
static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
@@ -75,14 +75,14 @@ struct uncore_counter {
static const struct uncore_counter uncore_counters[] = {
{ "CCI_400", "CCI_400", 4, true },
- { "CCI_400-r1", "CCI_400-r1", 4, true },
+ { "CCI_400_r1", "CCI_400_r1", 4, true },
{ "CCI_500", "CCI_500", 8, false },
{ "ccn", "ARM_CCN_5XX", 8, true },
};
class PerfCounter : public DriverCounter {
public:
- PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, uint64_t sampleType, uint64_t flags) : DriverCounter(next, name), mType(type), mConfig(config), mSampleType(sampleType), mFlags(flags), mCount(0) {}
+ PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, uint64_t sampleType, uint64_t flags, const int count) : DriverCounter(next, name), mType(type), mConfig(config), mSampleType(sampleType), mFlags(flags), mCount(count) {}
~PerfCounter() {
}
@@ -93,13 +93,14 @@ public:
uint64_t getConfig() const { return mConfig; }
void setConfig(const uint64_t config) { mConfig = config; }
uint64_t getSampleType() const { return mSampleType; }
+ void setSampleType(uint64_t sampleType) { mSampleType = sampleType; }
uint64_t getFlags() const { return mFlags; }
virtual void read(Buffer *const, const int) {}
private:
const uint32_t mType;
uint64_t mConfig;
- const uint64_t mSampleType;
+ uint64_t mSampleType;
const uint64_t mFlags;
int mCount;
@@ -110,7 +111,7 @@ private:
class CPUFreqDriver : public PerfCounter {
public:
- CPUFreqDriver(DriverCounter *next, uint64_t id) : PerfCounter(next, "Linux_power_cpu_freq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU) {}
+ CPUFreqDriver(DriverCounter *next, uint64_t id) : PerfCounter(next, "Linux_power_cpu_freq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU, 1) {}
void read(Buffer *const buffer, const int cpu) {
char buf[64];
@@ -135,17 +136,35 @@ PerfDriver::PerfDriver() : mIsSetup(false), mLegacySupport(false) {
PerfDriver::~PerfDriver() {
}
+class PerfTracepoint {
+public:
+ PerfTracepoint(PerfTracepoint *const next, const DriverCounter *const counter, const char *const tracepoint) : mNext(next), mCounter(counter), mTracepoint(tracepoint) {}
+
+ PerfTracepoint *getNext() const { return mNext; }
+ const DriverCounter *getCounter() const { return mCounter; }
+ const char *getTracepoint() const { return mTracepoint; }
+
+private:
+ PerfTracepoint *const mNext;
+ const DriverCounter *const mCounter;
+ const char *const mTracepoint;
+
+ // Intentionally undefined
+ PerfTracepoint(const PerfTracepoint &);
+ PerfTracepoint &operator=(const PerfTracepoint &);
+};
+
void PerfDriver::addCpuCounters(const char *const counterName, const int type, const int numCounters) {
int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
char *name = new char[len];
snprintf(name, len, "%s_ccnt", counterName);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
for (int j = 0; j < numCounters; ++j) {
len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
name = new char[len];
snprintf(name, len, "%s_cnt%d", counterName, j);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
}
@@ -157,14 +176,60 @@ void PerfDriver::addUncoreCounters(const char *const counterName, const int type
len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
name = new char[len];
snprintf(name, len, "%s_ccnt", counterName);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0, 0));
}
for (int j = 0; j < numCounters; ++j) {
len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
name = new char[len];
snprintf(name, len, "%s_cnt%d", counterName, j);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0, 0));
+ }
+}
+
+void PerfDriver::readEvents(mxml_node_t *const xml) {
+ mxml_node_t *node = xml;
+ DynBuf printb;
+
+ // Only for use with perf
+ if (!isSetup()) {
+ return;
+ }
+
+ while (true) {
+ node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
+ if (node == NULL) {
+ break;
+ }
+ const char *counter = mxmlElementGetAttr(node, "counter");
+ if (counter == NULL) {
+ continue;
+ }
+
+ if (strncmp(counter, "ftrace_", 7) != 0) {
+ continue;
+ }
+
+ const char *tracepoint = mxmlElementGetAttr(node, "tracepoint");
+ if (tracepoint == NULL) {
+ const char *regex = mxmlElementGetAttr(node, "regex");
+ if (regex == NULL) {
+ logg->logError("The tracepoint counter %s is missing the required tracepoint attribute", counter);
+ handleException();
+ } else {
+ logg->logMessage("Not using perf for counter %s", counter);
+ continue;
+ }
+ }
+
+ const char *arg = mxmlElementGetAttr(node, "arg");
+
+ long long id = getTracepointId(tracepoint, &printb);
+ if (id >= 0) {
+ logg->logMessage("Using perf for %s", counter);
+ setCounters(new PerfCounter(getCounters(), strdup(counter), PERF_TYPE_TRACEPOINT, id, arg == NULL ? 0 : PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU, 1));
+ mTracepoints = new PerfTracepoint(mTracepoints, getCounters(), strdup(tracepoint));
+ }
}
}
@@ -197,6 +262,7 @@ bool PerfDriver::setup() {
struct dirent *dirent;
while ((dirent = readdir(dir)) != NULL) {
+ logg->logMessage("perf pmu: %s", dirent->d_name);
for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
const struct gator_cpu *const gator_cpu = &gator_cpus[i];
@@ -217,7 +283,7 @@ bool PerfDriver::setup() {
}
foundCpu = true;
- logg->logMessage("Adding cpu counters for %s", gator_cpu->pmnc_name);
+ logg->logMessage("Adding cpu counters for %s with type %i", gator_cpu->pmnc_name, type);
addCpuCounters(gator_cpu->pmnc_name, type, gator_cpu->pmnc_counters);
}
@@ -233,7 +299,7 @@ bool PerfDriver::setup() {
continue;
}
- logg->logMessage("Adding uncore counters for %s", uncore_counters[i].gatorName);
+ logg->logMessage("Adding uncore counters for %s with type %i", uncore_counters[i].gatorName, type);
addUncoreCounters(uncore_counters[i].gatorName, type, uncore_counters[i].count, uncore_counters[i].hasCyclesCounter);
}
}
@@ -264,25 +330,25 @@ bool PerfDriver::setup() {
id = getTracepointId("irq/softirq_exit", &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
id = getTracepointId("irq/irq_handler_exit", &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
id = getTracepointId(SCHED_SWITCH, &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
id = getTracepointId(CPU_FREQUENCY, &printb);
- if (id >= 0) {
+ if (id >= 0 && access("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq", R_OK) == 0) {
setCounters(new CPUFreqDriver(getCounters(), id));
}
- setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, 0, 0));
+ setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, 0, 0, 0));
//Linux_cpu_wait_io
@@ -300,6 +366,12 @@ bool PerfDriver::summary(Buffer *const buffer) {
char buf[512];
snprintf(buf, sizeof(buf), "%s %s %s %s %s GNU/Linux", utsname.sysname, utsname.nodename, utsname.release, utsname.version, utsname.machine);
+ long pageSize = sysconf(_SC_PAGESIZE);
+ if (pageSize < 0) {
+ logg->logMessage("sysconf _SC_PAGESIZE failed");
+ return false;
+ }
+
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
logg->logMessage("clock_gettime failed");
@@ -311,7 +383,7 @@ bool PerfDriver::summary(Buffer *const buffer) {
gSessionData->mMonotonicStarted = monotonicStarted;
const uint64_t currTime = 0;//getTime() - gSessionData->mMonotonicStarted;
- buffer->summary(currTime, timestamp, monotonicStarted, monotonicStarted, buf);
+ buffer->summary(currTime, timestamp, monotonicStarted, monotonicStarted, buf, pageSize);
for (int i = 0; i < gSessionData->mCores; ++i) {
coreName(currTime, buffer, i);
@@ -322,27 +394,28 @@ bool PerfDriver::summary(Buffer *const buffer) {
}
void PerfDriver::coreName(const uint64_t currTime, Buffer *const buffer, const int cpu) {
+ const SharedData *const sharedData = gSessionData->mSharedData;
// Don't send information on a cpu we know nothing about
- if (gSessionData->mCpuIds[cpu] == -1) {
+ if (sharedData->mCpuIds[cpu] == -1) {
return;
}
int j;
for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) {
- if (gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
+ if (gator_cpus[j].cpuid == sharedData->mCpuIds[cpu]) {
break;
}
}
- if (j < ARRAY_LENGTH(gator_cpus) && gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
- buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], gator_cpus[j].core_name);
+ if (j < ARRAY_LENGTH(gator_cpus) && gator_cpus[j].cpuid == sharedData->mCpuIds[cpu]) {
+ buffer->coreName(currTime, cpu, sharedData->mCpuIds[cpu], gator_cpus[j].core_name);
} else {
char buf[32];
- if (gSessionData->mCpuIds[cpu] == -1) {
+ if (sharedData->mCpuIds[cpu] == -1) {
snprintf(buf, sizeof(buf), "Unknown");
} else {
- snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[cpu]);
+ snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", sharedData->mCpuIds[cpu]);
}
- buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], buf);
+ buffer->coreName(currTime, cpu, sharedData->mCpuIds[cpu], buf);
}
}
@@ -357,27 +430,22 @@ void PerfDriver::setupCounter(Counter &counter) {
if (counter.getEvent() != -1) {
perfCounter->setConfig(counter.getEvent());
}
- perfCounter->setCount(counter.getCount());
+ if (counter.getCount() > 0) {
+ // EBS
+ perfCounter->setCount(counter.getCount());
+ // Collect samples
+ perfCounter->setSampleType(perfCounter->getSampleType() | PERF_SAMPLE_TID | PERF_SAMPLE_IP);
+ }
perfCounter->setEnabled(true);
counter.setKey(perfCounter->getKey());
}
bool PerfDriver::enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const {
for (PerfCounter *counter = static_cast<PerfCounter *>(getCounters()); counter != NULL; counter = static_cast<PerfCounter *>(counter->getNext())) {
- if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
- int count = counter->getCount();
- uint64_t sampleType = counter->getSampleType();
- if (sampleType & PERF_SAMPLE_RAW) {
- // If raw is enabled, every sample is needed
- count = 1;
- }
- if (!group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), count,
- // use getCount instead of count as EBS counters need TID and IP but RAW tracepoints don't
- (counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0) | sampleType,
- counter->getFlags())) {
- logg->logMessage("PerfGroup::add failed");
- return false;
- }
+ if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED) &&
+ !group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), counter->getSampleType(), counter->getFlags())) {
+ logg->logMessage("PerfGroup::add failed");
+ return false;
}
}
@@ -393,6 +461,38 @@ void PerfDriver::read(Buffer *const buffer, const int cpu) {
}
}
+static bool sendTracepointFormat(const uint64_t currTime, Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
+ if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
+ logg->logMessage("DynBuf::printf failed");
+ return false;
+ }
+ if (!b->read(printb->getBuf())) {
+ logg->logMessage("DynBuf::read failed");
+ return false;
+ }
+ buffer->marshalFormat(currTime, b->getLength(), b->getBuf());
+
+ return true;
+}
+
+bool PerfDriver::sendTracepointFormats(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b) {
+ if (
+ !sendTracepointFormat(currTime, buffer, SCHED_SWITCH, printb, b) ||
+ !sendTracepointFormat(currTime, buffer, CPU_IDLE, printb, b) ||
+ !sendTracepointFormat(currTime, buffer, CPU_FREQUENCY, printb, b) ||
+ false) {
+ return false;
+ }
+
+ for (PerfTracepoint *tracepoint = mTracepoints; tracepoint != NULL; tracepoint = tracepoint->getNext()) {
+ if (tracepoint->getCounter()->isEnabled() && !sendTracepointFormat(currTime, buffer, tracepoint->getTracepoint(), printb, b)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
long long PerfDriver::getTracepointId(const char *const name, DynBuf *const printb) {
if (!printb->printf(EVENTS_PATH "/%s/id", name)) {
logg->logMessage("DynBuf::printf failed");
@@ -401,7 +501,7 @@ long long PerfDriver::getTracepointId(const char *const name, DynBuf *const prin
int64_t result;
if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) {
- logg->logMessage("DriverSource::readInt64Driver failed");
+ logg->logMessage("Unable to read tracepoint id for %s", printb->getBuf());
return -1;
}
diff --git a/daemon/PerfDriver.h b/daemon/PerfDriver.h
index 95b42bf..a38fcde 100644
--- a/daemon/PerfDriver.h
+++ b/daemon/PerfDriver.h
@@ -13,10 +13,6 @@
#include "Driver.h"
-// If debugfs is not mounted at /sys/kernel/debug, update DEBUGFS_PATH
-#define DEBUGFS_PATH "/sys/kernel/debug"
-#define EVENTS_PATH DEBUGFS_PATH "/tracing/events"
-
#define SCHED_SWITCH "sched/sched_switch"
#define CPU_IDLE "power/cpu_idle"
#define CPU_FREQUENCY "power/cpu_frequency"
@@ -24,6 +20,7 @@
class Buffer;
class DynBuf;
class PerfGroup;
+class PerfTracepoint;
class PerfDriver : public SimpleDriver {
public:
@@ -32,6 +29,7 @@ public:
bool getLegacySupport() const { return mLegacySupport; }
+ void readEvents(mxml_node_t *const xml);
bool setup();
bool summary(Buffer *const buffer);
void coreName(const uint64_t currTime, Buffer *const buffer, const int cpu);
@@ -41,6 +39,7 @@ public:
bool enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const;
void read(Buffer *const buffer, const int cpu);
+ bool sendTracepointFormats(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b);
static long long getTracepointId(const char *const name, DynBuf *const printb);
@@ -50,6 +49,7 @@ private:
bool mIsSetup;
bool mLegacySupport;
+ PerfTracepoint *mTracepoints;
// Intentionally undefined
PerfDriver(const PerfDriver &);
diff --git a/daemon/PerfGroup.cpp b/daemon/PerfGroup.cpp
index cfc62e4..9b71531 100644
--- a/daemon/PerfGroup.cpp
+++ b/daemon/PerfGroup.cpp
@@ -10,6 +10,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
@@ -23,12 +24,11 @@
#include "SessionData.h"
static const int schedSwitchKey = getEventKey();
-static const int clockKey = getEventKey();
#define DEFAULT_PEA_ARGS(pea, additionalSampleType) \
pea.size = sizeof(pea); \
/* Emit time, read_format below, group leader id, and raw tracepoint info */ \
- pea.sample_type = (gSessionData->perf.getLegacySupport() \
+ pea.sample_type = (gSessionData->mPerf.getLegacySupport() \
? PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_ID \
: PERF_SAMPLE_IDENTIFIER ) | PERF_SAMPLE_TIME | additionalSampleType; \
/* Emit emit value in group format */ \
@@ -132,7 +132,7 @@ bool PerfGroup::createCpuGroup(const uint64_t currTime, Buffer *const buffer) {
return false;
}
- if (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && doAdd(currTime, buffer, clockKey, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU) < 0) {
+ if (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && doAdd(currTime, buffer, INT_MAX-PERF_TYPE_HARDWARE, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU) < 0) {
return false;
}
@@ -152,8 +152,7 @@ bool PerfGroup::add(const uint64_t currTime, Buffer *const buffer, const int key
} else {
// Non-CPU PMUs are sampled every 100ms for Sample Rate: None and EBS, otherwise they would never be sampled
const uint64_t timeout = gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS ? 1000000000UL / gSessionData->mSampleRate : 100000000UL;
- // PERF_SAMPLE_TID | PERF_SAMPLE_IP aren't helpful on non-CPU or 'uncore' PMUs - which CPU is the right one to sample? But removing it causes problems, remove it later.
- mLeaders[effectiveType] = doAdd(currTime, buffer, clockKey, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, timeout, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_LEADER);
+ mLeaders[effectiveType] = doAdd(currTime, buffer, INT_MAX-effectiveType, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, timeout, PERF_SAMPLE_READ, PERF_GROUP_LEADER);
if (mLeaders[effectiveType] < 0) {
return false;
}
@@ -194,16 +193,12 @@ int PerfGroup::prepareCPU(const int cpu, Monitor *const monitor) {
// The core is offline
return PG_CPU_OFFLINE;
}
-#ifndef USE_STRICTER_CHECK
- continue;
-#else
if (errno == ENOENT) {
// This event doesn't apply to this CPU but should apply to a different one, ex bL
continue;
}
logg->logMessage("perf_event_open failed");
return PG_FAILURE;
-#endif
}
if (!mPb->useFd(cpu, mFds[offset])) {
@@ -236,7 +231,7 @@ static bool readAndSend(const uint64_t currTime, Buffer *const buffer, const int
int PerfGroup::onlineCPU(const uint64_t currTime, const int cpu, const bool enable, Buffer *const buffer) {
bool addedEvents = false;
- if (!gSessionData->perf.getLegacySupport()) {
+ if (!gSessionData->mPerf.getLegacySupport()) {
int idCount = 0;
int coreKeys[ARRAY_LENGTH(mKeys)];
__u64 ids[ARRAY_LENGTH(mKeys)];
diff --git a/daemon/PerfSource.cpp b/daemon/PerfSource.cpp
index 2c45de8..9f34bbd 100644
--- a/daemon/PerfSource.cpp
+++ b/daemon/PerfSource.cpp
@@ -33,20 +33,6 @@ extern Child *child;
static const int cpuIdleKey = getEventKey();
-static bool sendTracepointFormat(const uint64_t currTime, Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
- if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
- logg->logMessage("DynBuf::printf failed");
- return false;
- }
- if (!b->read(printb->getBuf())) {
- logg->logMessage("DynBuf::read failed");
- return false;
- }
- buffer->marshalFormat(currTime, b->getLength(), b->getBuf());
-
- return true;
-}
-
static void *syncFunc(void *arg)
{
struct timespec ts;
@@ -160,17 +146,14 @@ bool PerfSource::prepare() {
|| !mUEvent.init()
|| !mMonitor.add(mUEvent.getFd())
- || !sendTracepointFormat(currTime, mBuffer, SCHED_SWITCH, &printb, &b1)
-
|| (cpuIdleId = PerfDriver::getTracepointId(CPU_IDLE, &printb)) < 0
- || !sendTracepointFormat(currTime, mBuffer, CPU_IDLE, &printb, &b1)
- || !sendTracepointFormat(currTime, mBuffer, CPU_FREQUENCY, &printb, &b1)
+ || !gSessionData->mPerf.sendTracepointFormats(currTime, mBuffer, &printb, &b1)
|| !mCountersGroup.createCpuGroup(currTime, mBuffer)
|| !mCountersGroup.add(currTime, mBuffer, cpuIdleKey, PERF_TYPE_TRACEPOINT, cpuIdleId, 1, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU)
- || !gSessionData->perf.enable(currTime, &mCountersGroup, mBuffer)
+ || !gSessionData->mPerf.enable(currTime, &mCountersGroup, mBuffer)
|| 0) {
logg->logMessage("perf setup failed, are you running Linux 3.4 or later?");
return false;
@@ -194,7 +177,7 @@ bool PerfSource::prepare() {
}
// Send the summary right before the start so that the monotonic delta is close to the start time
- if (!gSessionData->perf.summary(&mSummary)) {
+ if (!gSessionData->mPerf.summary(&mSummary)) {
logg->logError("PerfDriver::summary failed");
handleException();
}
@@ -283,7 +266,7 @@ void PerfSource::run() {
mBuffer->perfCounterHeader(currTime);
for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
- gSessionData->perf.read(mBuffer, cpu);
+ gSessionData->mPerf.read(mBuffer, cpu);
}
mBuffer->perfCounterFooter(currTime);
@@ -396,7 +379,7 @@ bool PerfSource::handleUEvent(const uint64_t currTime) {
} else if (err == PG_SUCCESS) {
if (mCountersGroup.onlineCPU(currTime, cpu, true, mBuffer) > 0) {
mBuffer->perfCounterHeader(currTime);
- gSessionData->perf.read(mBuffer, cpu);
+ gSessionData->mPerf.read(mBuffer, cpu);
mBuffer->perfCounterFooter(currTime);
ret = true;
}
@@ -404,7 +387,7 @@ bool PerfSource::handleUEvent(const uint64_t currTime) {
mBuffer->commit(currTime);
gSessionData->readCpuInfo();
- gSessionData->perf.coreName(currTime, &mSummary, cpu);
+ gSessionData->mPerf.coreName(currTime, &mSummary, cpu);
mSummary.commit(currTime);
return ret;
} else if (strcmp(result.mAction, "offline") == 0) {
diff --git a/daemon/Proc.cpp b/daemon/Proc.cpp
index 4ba59b6..ffe1a78 100644
--- a/daemon/Proc.cpp
+++ b/daemon/Proc.cpp
@@ -72,12 +72,7 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti
const int err = b->readlink(printb->getBuf());
const char *image;
if (err == 0) {
- image = strrchr(b->getBuf(), '/');
- if (image == NULL) {
- image = b->getBuf();
- } else {
- ++image;
- }
+ image = b->getBuf();
} else if (err == -ENOENT) {
// readlink /proc/[pid]/exe returns ENOENT for kernel threads
image = "\0";
@@ -88,7 +83,7 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti
// Android apps are run by app_process but the cmdline is changed to reference the actual app name
// On 64-bit android app_process can be app_process32 or app_process64
- if (strncmp(image, APP_PROCESS, sizeof(APP_PROCESS) - 1) != 0) {
+ if (strstr(image, APP_PROCESS) == NULL) {
return image;
}
diff --git a/daemon/Sender.cpp b/daemon/Sender.cpp
index d7ad757..71ddfce 100644
--- a/daemon/Sender.cpp
+++ b/daemon/Sender.cpp
@@ -44,7 +44,15 @@ Sender::Sender(OlySocket* socket) {
logg->logMessage("Completed magic sequence");
}
- pthread_mutex_init(&mSendMutex, NULL);
+ pthread_mutexattr_t attr;
+ if (pthread_mutexattr_init(&attr) != 0 ||
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0 ||
+ pthread_mutex_init(&mSendMutex, &attr) != 0 ||
+ pthread_mutexattr_destroy(&attr) != 0 ||
+ false) {
+ logg->logError("Unable to setup mutex");
+ handleException();
+ }
}
Sender::~Sender() {
@@ -78,7 +86,10 @@ void Sender::writeData(const char* data, int length, int type) {
}
// Multiple threads call writeData()
- pthread_mutex_lock(&mSendMutex);
+ if (pthread_mutex_lock(&mSendMutex) != 0) {
+ logg->logError("pthread_mutex_lock failed");
+ handleException();
+ }
// Send data over the socket connection
if (mDataSocket) {
@@ -100,7 +111,7 @@ void Sender::writeData(const char* data, int length, int type) {
const int chunkSize = 100*1000 * alarmDuration / 8;
int pos = 0;
while (true) {
- mDataSocket->send((const char*)data + pos, min(length - pos, chunkSize));
+ mDataSocket->send(data + pos, min(length - pos, chunkSize));
pos += chunkSize;
if (pos >= length) {
break;
@@ -125,5 +136,8 @@ void Sender::writeData(const char* data, int length, int type) {
}
}
- pthread_mutex_unlock(&mSendMutex);
+ if (pthread_mutex_unlock(&mSendMutex) != 0) {
+ logg->logError("pthread_mutex_unlock failed");
+ handleException();
+ }
}
diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp
index 2b661bd..42917c0 100644
--- a/daemon/SessionData.cpp
+++ b/daemon/SessionData.cpp
@@ -25,33 +25,40 @@
SessionData* gSessionData = NULL;
+SharedData::SharedData() : mMaliUtgardCountersSize(0) {
+ memset(mCpuIds, -1, sizeof(mCpuIds));
+}
+
SessionData::SessionData() {
- usDrivers[0] = new HwmonDriver();
- usDrivers[1] = new FSDriver();
- usDrivers[2] = new MemInfoDriver();
- usDrivers[3] = new NetDriver();
- usDrivers[4] = new DiskIODriver();
+ mUsDrivers[0] = new HwmonDriver();
+ mUsDrivers[1] = new FSDriver();
+ mUsDrivers[2] = new MemInfoDriver();
+ mUsDrivers[3] = new NetDriver();
+ mUsDrivers[4] = new DiskIODriver();
initialize();
}
SessionData::~SessionData() {
}
+// Needed to use placement new
+inline void *operator new(size_t, void *ptr) { return ptr; }
+
void SessionData::initialize() {
+ mSharedData = (SharedData *)mmap(NULL, sizeof(*mSharedData), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (mSharedData == MAP_FAILED) {
+ logg->logError("Unable to mmap shared memory for cpuids");
+ handleException();
+ }
+ // Use placement new to construct but not allocate the object
+ new ((char *)mSharedData) SharedData();
+
mWaitingOnCommand = false;
mSessionIsActive = false;
mLocalCapture = false;
mOneShot = false;
mSentSummary = false;
mAllowCommands = false;
- const size_t cpuIdSize = sizeof(int)*NR_CPUS;
- // Share mCpuIds across all instances of gatord
- mCpuIds = (int *)mmap(NULL, cpuIdSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- if (mCpuIds == MAP_FAILED) {
- logg->logError("Unable to mmap shared memory for cpuids");
- handleException();
- }
- memset(mCpuIds, -1, cpuIdSize);
strcpy(mCoreName, CORE_NAME_UNKNOWN);
readModel();
readCpuInfo();
@@ -83,11 +90,11 @@ void SessionData::parseSessionXML(char* xmlString) {
// Set session data values - use prime numbers just below the desired value to reduce the chance of events firing at the same time
if (strcmp(session.parameters.sample_rate, "high") == 0) {
- mSampleRate = 9973; // 10000
+ mSampleRate = 10007; // 10000
} else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
- mSampleRate = 997; // 1000
+ mSampleRate = 1009; // 1000
} else if (strcmp(session.parameters.sample_rate, "low") == 0) {
- mSampleRate = 97; // 100
+ mSampleRate = 101; // 100
} else if (strcmp(session.parameters.sample_rate, "none") == 0) {
mSampleRate = 0;
} else {
@@ -126,7 +133,7 @@ void SessionData::parseSessionXML(char* xmlString) {
}
void SessionData::readModel() {
- FILE *fh = fopen("/proc/device-tree/model", "rb");
+ FILE *fh = fopen_cloexec("/proc/device-tree/model", "rb");
if (fh == NULL) {
return;
}
@@ -157,7 +164,7 @@ void SessionData::readCpuInfo() {
char temp[256]; // arbitrarily large amount
mMaxCpuId = -1;
- FILE *f = fopen("/proc/cpuinfo", "r");
+ FILE *f = fopen_cloexec("/proc/cpuinfo", "r");
if (f == NULL) {
logg->logMessage("Error opening /proc/cpuinfo\n"
"The core name in the captured xml file will be 'unknown'.");
@@ -169,17 +176,19 @@ void SessionData::readCpuInfo() {
while (fgets(temp, sizeof(temp), f)) {
const size_t len = strlen(temp);
+ if (len > 0) {
+ // Replace the line feed with a null
+ temp[len - 1] = '\0';
+ }
+
+ logg->logMessage("cpuinfo: %s", temp);
+
if (len == 1) {
// New section, clear the processor. Streamline will not know the cpus if the pre Linux 3.8 format of cpuinfo is encountered but also that no incorrect information will be transmitted.
processor = -1;
continue;
}
- if (len > 0) {
- // Replace the line feed with a null
- temp[len - 1] = '\0';
- }
-
const bool foundHardware = !foundCoreName && strstr(temp, "Hardware") != 0;
const bool foundCPUImplementer = strstr(temp, "CPU implementer") != 0;
const bool foundCPUPart = strstr(temp, "CPU part") != 0;
@@ -204,7 +213,7 @@ void SessionData::readCpuInfo() {
if (processor >= NR_CPUS) {
logg->logMessage("Too many processors, please increase NR_CPUS");
} else if (processor >= 0) {
- setImplementer(mCpuIds[processor], implementer);
+ setImplementer(mSharedData->mCpuIds[processor], implementer);
} else {
setImplementer(mMaxCpuId, implementer);
}
@@ -215,7 +224,7 @@ void SessionData::readCpuInfo() {
if (processor >= NR_CPUS) {
logg->logMessage("Too many processors, please increase NR_CPUS");
} else if (processor >= 0) {
- setPart(mCpuIds[processor], cpuId);
+ setPart(mSharedData->mCpuIds[processor], cpuId);
} else {
setPart(mMaxCpuId, cpuId);
}
@@ -229,8 +238,8 @@ void SessionData::readCpuInfo() {
// If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId
for (int i = 0; i < NR_CPUS; ++i) {
- if (mCpuIds[i] > mMaxCpuId) {
- mMaxCpuId = mCpuIds[i];
+ if (mSharedData->mCpuIds[i] > mMaxCpuId) {
+ mMaxCpuId = mSharedData->mCpuIds[i];
}
}
@@ -290,3 +299,48 @@ FILE *fopen_cloexec(const char *path, const char *mode) {
}
return fh;
}
+
+bool setNonblock(const int fd) {
+ int flags;
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags < 0) {
+ logg->logMessage("fcntl getfl failed");
+ return false;
+ }
+
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
+ logg->logMessage("fcntl setfl failed");
+ return false;
+ }
+
+ return true;
+}
+
+bool writeAll(const int fd, const void *const buf, const size_t pos) {
+ size_t written = 0;
+ while (written < pos) {
+ ssize_t bytes = write(fd, (const uint8_t *)buf + written, pos - written);
+ if (bytes <= 0) {
+ logg->logMessage("write failed");
+ return false;
+ }
+ written += bytes;
+ }
+
+ return true;
+}
+
+bool readAll(const int fd, void *const buf, const size_t count) {
+ size_t pos = 0;
+ while (pos < count) {
+ ssize_t bytes = read(fd, (uint8_t *)buf + pos, count - pos);
+ if (bytes <= 0) {
+ logg->logMessage("read failed");
+ return false;
+ }
+ pos += bytes;
+ }
+
+ return true;
+}
diff --git a/daemon/SessionData.h b/daemon/SessionData.h
index d0c8900..12432d0 100644
--- a/daemon/SessionData.h
+++ b/daemon/SessionData.h
@@ -11,14 +11,17 @@
#include <stdint.h>
+#include "AtraceDriver.h"
+#include "CCNDriver.h"
#include "Config.h"
#include "Counter.h"
+#include "ExternalDriver.h"
#include "FtraceDriver.h"
#include "KMod.h"
#include "MaliVideoDriver.h"
#include "PerfDriver.h"
-#define PROTOCOL_VERSION 21
+#define PROTOCOL_VERSION 22
// Differentiates development versions (timestamp) from release versions
#define PROTOCOL_DEV 1000
@@ -31,22 +34,41 @@ struct ImageLinkList {
struct ImageLinkList *next;
};
+class SharedData {
+public:
+ SharedData();
+
+ int mCpuIds[NR_CPUS];
+ size_t mMaliUtgardCountersSize;
+ char mMaliUtgardCounters[1<<12];
+
+private:
+ // Intentionally unimplemented
+ SharedData(const SharedData &);
+ SharedData &operator=(const SharedData &);
+};
+
class SessionData {
public:
static const size_t MAX_STRING_LEN = 80;
SessionData();
~SessionData();
- void initialize();
void parseSessionXML(char* xmlString);
void readModel();
void readCpuInfo();
- PolledDriver *usDrivers[5];
- KMod kmod;
- PerfDriver perf;
- MaliVideoDriver maliVideo;
- FtraceDriver ftraceDriver;
+ SharedData *mSharedData;
+
+ PolledDriver *mUsDrivers[5];
+ KMod mKmod;
+ PerfDriver mPerf;
+ MaliVideoDriver mMaliVideo;
+ // Intentionally above FtraceDriver as drivers are initialized in reverse order AtraceDriver references AtraceDriver
+ AtraceDriver mAtraceDriver;
+ FtraceDriver mFtraceDriver;
+ ExternalDriver mExternalDriver;
+ CCNDriver mCcnDriver;
char mCoreName[MAX_STRING_LEN];
struct ImageLinkList *mImages;
@@ -78,15 +100,16 @@ public:
int mDuration;
int mCores;
int mPageSize;
- int *mCpuIds;
int mMaxCpuId;
int mAnnotateStart;
// PMU Counters
- int mCounterOverflow;
+ char *mCountersError;
Counter mCounters[MAX_PERFORMANCE_COUNTERS];
private:
+ void initialize();
+
// Intentionally unimplemented
SessionData(const SessionData &);
SessionData &operator=(const SessionData &);
@@ -99,5 +122,8 @@ uint64_t getTime();
int getEventKey();
int pipe_cloexec(int pipefd[2]);
FILE *fopen_cloexec(const char *path, const char *mode);
+bool setNonblock(const int fd);
+bool writeAll(const int fd, const void *const buf, const size_t pos);
+bool readAll(const int fd, void *const buf, const size_t count);
#endif // SESSION_DATA_H
diff --git a/daemon/Setup.cpp b/daemon/Setup.cpp
index 7dd83ce..524a702 100644
--- a/daemon/Setup.cpp
+++ b/daemon/Setup.cpp
@@ -153,30 +153,34 @@ void update(const char *const gatorPath) {
handleException();
}
- if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(2, 6, 32)) {
- logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
- handleException();
- }
-
if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(3, 4, 0)) {
- logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device.");
+ logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
handleException();
}
if (geteuid() != 0) {
- printf(GATOR_MSG "trying sudo\n");
- execlp("sudo", "sudo", gatorPath, "-u", NULL);
- // Streamline will provide the password if needed
-
- printf(GATOR_MSG "trying su\n");
char buf[1<<10];
+ snprintf(buf, sizeof(buf),
+ "which sudo &&"
+ "("
+ "sudo -n %1$s -u ||"
+ "("
+ "echo " GATOR_MSG "trying sudo;"
+ // Streamline will provide the password
+ "sudo %1$s -u"
+ ")"
+ ") || ("
+ "echo " GATOR_MSG "trying su;"
/*
* Different versions of su handle additional -c command line options differently and expect the
* arguments in different ways. Try both ways wrapped in a shell.
*
* Then invoke another shell after su as it avoids odd failures on some Android systems
*/
- snprintf(buf, sizeof(buf), "su -c \"sh -c '%s -u'\" || su -c sh -c '%s -u'", gatorPath, gatorPath);
+ "su -c \"sh -c '%1$s -u'\" ||"
+ "su -c sh -c '%1$s -u'"
+ ")",
+ gatorPath);
execlp("sh", "sh", "-c", buf, NULL);
// Streamline will provide the password if needed
@@ -228,6 +232,11 @@ void update(const char *const gatorPath) {
umount("/dev/gator");
syscall(__NR_delete_module, "gator", O_NONBLOCK);
+ if (access("/sys/module/gator", F_OK) == 0) {
+ logg->logError(GATOR_ERROR "Unable to unload gator.ko, the gator module may be built into the kernel or gator.ko cannot be unloaded. Rebooting the device may resolve the issue.");
+ handleException();
+ }
+
rename("gatord", "gatord.old");
rename("gator.ko", "gator.ko.old");
@@ -314,8 +323,7 @@ void update(const char *const gatorPath) {
close(pipefd[1]);
const ssize_t bytes = read(pipefd[0], buf, sizeof(buf));
if (bytes > 0) {
- logg->logError("%s", buf);
- handleException();
+ printf("%s\n", buf);
}
close(pipefd[0]);
diff --git a/daemon/StreamlineSetup.cpp b/daemon/StreamlineSetup.cpp
index e37f271..66d1f4e 100644
--- a/daemon/StreamlineSetup.cpp
+++ b/daemon/StreamlineSetup.cpp
@@ -75,8 +75,8 @@ StreamlineSetup::StreamlineSetup(OlySocket* s) {
free(data);
}
- if (gSessionData->mCounterOverflow > 0) {
- logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
+ if (gSessionData->mCountersError != NULL) {
+ logg->logError("%s", gSessionData->mCountersError);
handleException();
}
}
@@ -197,7 +197,7 @@ void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
header[0] = type;
Buffer::writeLEInt(header + 1, length);
mSocket->send((char*)&header, sizeof(header));
- mSocket->send((const char*)data, length);
+ mSocket->send(data, length);
}
void StreamlineSetup::sendEvents() {
@@ -265,8 +265,8 @@ void StreamlineSetup::writeConfiguration(char* xml) {
// Re-populate gSessionData with the configuration, as it has now changed
{ ConfigurationXML configuration; }
- if (gSessionData->mCounterOverflow > 0) {
- logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
+ if (gSessionData->mCountersError != NULL) {
+ logg->logError("%s", gSessionData->mCountersError);
handleException();
}
}
diff --git a/daemon/UserSpaceSource.cpp b/daemon/UserSpaceSource.cpp
index f58f828..1036312 100644
--- a/daemon/UserSpaceSource.cpp
+++ b/daemon/UserSpaceSource.cpp
@@ -34,15 +34,15 @@ bool UserSpaceSource::prepare() {
void UserSpaceSource::run() {
prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
- for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
- gSessionData->usDrivers[i]->start();
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->mUsDrivers); ++i) {
+ gSessionData->mUsDrivers[i]->start();
}
int64_t monotonicStarted = 0;
while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
usleep(10);
- if (gSessionData->perf.isSetup()) {
+ if (gSessionData->mPerf.isSetup()) {
monotonicStarted = gSessionData->mMonotonicStarted;
} else {
if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
@@ -64,8 +64,8 @@ void UserSpaceSource::run() {
}
if (mBuffer.eventHeader(currTime)) {
- for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
- gSessionData->usDrivers[i]->read(&mBuffer);
+ for (int i = 0; i < ARRAY_LENGTH(gSessionData->mUsDrivers); ++i) {
+ gSessionData->mUsDrivers[i]->read(&mBuffer);
}
// Only check after writing all counters so that time and corresponding counters appear in the same frame
mBuffer.check(currTime);
diff --git a/daemon/defaults.xml b/daemon/defaults.xml
index 31b127c..9adde32 100644
--- a/daemon/defaults.xml
+++ b/daemon/defaults.xml
@@ -34,21 +34,21 @@
<configuration counter="ARMv7_Cortex_A17_cnt1" event="0x16"/>
<configuration counter="ARMv7_Cortex_A17_cnt2" event="0x10"/>
<configuration counter="ARMv7_Cortex_A17_cnt3" event="0x19"/>
- <configuration counter="ARM_Cortex-A53_ccnt" event="0x11"/>
- <configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/>
- <configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/>
- <configuration counter="ARM_Cortex-A53_cnt2" event="0x10"/>
- <configuration counter="ARM_Cortex-A53_cnt3" event="0x19"/>
- <configuration counter="ARM_Cortex-A57_ccnt" event="0x11"/>
- <configuration counter="ARM_Cortex-A57_cnt0" event="0x8"/>
- <configuration counter="ARM_Cortex-A57_cnt1" event="0x16"/>
- <configuration counter="ARM_Cortex-A57_cnt2" event="0x10"/>
- <configuration counter="ARM_Cortex-A57_cnt3" event="0x19"/>
- <configuration counter="ARM_Cortex-A72_ccnt" event="0x11"/>
- <configuration counter="ARM_Cortex-A72_cnt0" event="0x8"/>
- <configuration counter="ARM_Cortex-A72_cnt1" event="0x16"/>
- <configuration counter="ARM_Cortex-A72_cnt2" event="0x10"/>
- <configuration counter="ARM_Cortex-A72_cnt3" event="0x19"/>
+ <configuration counter="ARMv8_Cortex_A53_ccnt" event="0x11"/>
+ <configuration counter="ARMv8_Cortex_A53_cnt0" event="0x8"/>
+ <configuration counter="ARMv8_Cortex_A53_cnt1" event="0x16"/>
+ <configuration counter="ARMv8_Cortex_A53_cnt2" event="0x10"/>
+ <configuration counter="ARMv8_Cortex_A53_cnt3" event="0x19"/>
+ <configuration counter="ARMv8_Cortex_A57_ccnt" event="0x11"/>
+ <configuration counter="ARMv8_Cortex_A57_cnt0" event="0x8"/>
+ <configuration counter="ARMv8_Cortex_A57_cnt1" event="0x16"/>
+ <configuration counter="ARMv8_Cortex_A57_cnt2" event="0x10"/>
+ <configuration counter="ARMv8_Cortex_A57_cnt3" event="0x19"/>
+ <configuration counter="ARMv8_Cortex_A72_ccnt" event="0x11"/>
+ <configuration counter="ARMv8_Cortex_A72_cnt0" event="0x8"/>
+ <configuration counter="ARMv8_Cortex_A72_cnt1" event="0x16"/>
+ <configuration counter="ARMv8_Cortex_A72_cnt2" event="0x10"/>
+ <configuration counter="ARMv8_Cortex_A72_cnt3" event="0x19"/>
<configuration counter="Scorpion_ccnt" event="0xff"/>
<configuration counter="Scorpion_cnt0" event="0x08"/>
<configuration counter="Scorpion_cnt1" event="0x10"/>
diff --git a/daemon/events-CCI-400.xml b/daemon/events-CCI-400.xml
index 40d91e5..0dd72c0 100644
--- a/daemon/events-CCI-400.xml
+++ b/daemon/events-CCI-400.xml
@@ -41,9 +41,9 @@
<event event="0x19" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
<event event="0x1a" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase MIx_W_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
</category>
- <counter_set name="CCI_400-r1_cnt" count="4"/>
- <category name="CCI-400" counter_set="CCI_400-r1_cnt" per_cpu="no">
- <event counter="CCI_400-r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
+ <counter_set name="CCI_400_r1_cnt" count="4"/>
+ <category name="CCI-400" counter_set="CCI_400_r1_cnt" per_cpu="no">
+ <event counter="CCI_400_r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
<option_set name="Slave">
<option event_delta="0x00" name="S0" description="Slave interface 0"/>
<option event_delta="0x20" name="S1" description="Slave interface 1"/>
diff --git a/daemon/events-Cortex-A53.xml b/daemon/events-Cortex-A53.xml
index acdfe4e..c15cbd8 100644
--- a/daemon/events-Cortex-A53.xml
+++ b/daemon/events-Cortex-A53.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex-A53_cnt" count="6"/>
- <category name="Cortex-A53" counter_set="ARM_Cortex-A53_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex-A53_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv8_Cortex_A53_cnt" count="6"/>
+ <category name="Cortex-A53" counter_set="ARMv8_Cortex_A53_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv8_Cortex_A53_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Software increment. The register is 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"/>
diff --git a/daemon/events-Cortex-A57.xml b/daemon/events-Cortex-A57.xml
index 1da23e7..d1e97c3 100644
--- a/daemon/events-Cortex-A57.xml
+++ b/daemon/events-Cortex-A57.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex-A57_cnt" count="6"/>
- <category name="Cortex-A57" counter_set="ARM_Cortex-A57_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex-A57_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv8_Cortex_A57_cnt" count="6"/>
+ <category name="Cortex-A57" counter_set="ARMv8_Cortex_A57_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv8_Cortex_A57_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A72.xml b/daemon/events-Cortex-A72.xml
index 31c9cf3..683d0ae 100644
--- a/daemon/events-Cortex-A72.xml
+++ b/daemon/events-Cortex-A72.xml
@@ -1,6 +1,6 @@
- <counter_set name="ARM_Cortex_A72_cnt" count="6"/>
- <category name="Cortex-A72" counter_set="ARM_Cortex_A72_cnt" per_cpu="yes" supports_event_based_sampling="yes">
- <event counter="ARM_Cortex_A72_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <counter_set name="ARMv8_Cortex_A72_cnt" count="6"/>
+ <category name="Cortex-A72" counter_set="ARMv8_Cortex_A72_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARMv8_Cortex_A72_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Mali-4xx.xml b/daemon/events-Mali-4xx.xml
index 801dd28..e2f4405 100644
--- a/daemon/events-Mali-4xx.xml
+++ b/daemon/events-Mali-4xx.xml
@@ -243,3 +243,14 @@
<event counter="ARM_Mali-4xx_SW_39" title="Geometry Statistics" name="Strip Lines" description="Number of lines passed to GLES using the mode GL_LINE_STRIP."/>
<event counter="ARM_Mali-4xx_SW_40" title="Geometry Statistics" name="Loop Lines" description="Number of lines passed to GLES using the mode GL_LINE_LOOP."/>
</category>
+ <category name="ARM_Mali-4xx_Total_alloc_pages" per_cpu="no">
+ <event counter="ARM_Mali-4xx_Total_alloc_pages" title="Mali GPU Alloc" name="pages" class="absolute" display="average" average_selection="yes" description="Total number of allocated pages"/>
+ </category>
+ <category name="Mali-4xx Session Memory usage" per_cpu="no">
+ <event counter="ARM_Mali-4xx_vertex_index_buffer" title="Mali Memory" name="Vertex and Index buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Vertex and index input"/>
+ <event counter="ARM_Mali-4xx_texture_buffer" title="Mali Memory" name="Texture buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Texture data"/>
+ <event counter="ARM_Mali-4xx_varying_buffer" title="Mali Memory" name="Varying buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Varying buffer"/>
+ <event counter="ARM_Mali-4xx_render_target" title="Mali Memory" name="Render target buffer" units="B" dclass="absolute" display="average" average_selection="yes" description="Render target buffer"/>
+ <event counter="ARM_Mali-4xx_plbu_heap" title="Mali Memory" name="Plbu heap" units="B" dclass="absolute" display="average" average_selection="yes" description="The memory to store commands from PLBU when Slave tilelist memory isn't enough"/>
+ <event counter="ARM_Mali-4xx_slave_tilelist" title="Mali Memory" name="Slave tilelist" units="B" dclass="absolute" display="average" average_selection="yes" description="Slave tilelist memory"/>
+ </category>
diff --git a/daemon/events-Mali-Midgard_hw.xml b/daemon/events-Mali-Midgard_hw.xml
index e8f0cb0..802db8b 100644
--- a/daemon/events-Mali-Midgard_hw.xml
+++ b/daemon/events-Mali-Midgard_hw.xml
@@ -44,8 +44,8 @@
<event counter="ARM_Mali-Midgard_FRAG_THREADS" title="Mali Core Threads" name="Fragment threads" description="Number of fragment threads started"/>
<event counter="ARM_Mali-Midgard_FRAG_DUMMY_THREADS" title="Mali Core Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
- <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS quads" description="Number of threads doing late ZS test"/>
- <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS quads" description="Number of threads killed by late ZS test"/>
+ <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
+ <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
<event counter="ARM_Mali-Midgard_FRAG_THREADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
<event counter="ARM_Mali-Midgard_FRAG_THREADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
diff --git a/daemon/events-Mali-T82x_hw.xml b/daemon/events-Mali-T82x_hw.xml
index 5caa464..994c8b1 100644
--- a/daemon/events-Mali-T82x_hw.xml
+++ b/daemon/events-Mali-T82x_hw.xml
@@ -1,108 +1,108 @@
-
- <category name="Mali Job Manager" per_cpu="no">
-
- <event counter="ARM_Mali-T82x_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles GPU active"/>
- <event counter="ARM_Mali-T82x_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles GPU interrupt pending"/>
- <event counter="ARM_Mali-T82x_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) active"/>
- <event counter="ARM_Mali-T82x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
- <event counter="ARM_Mali-T82x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
-
- <event counter="ARM_Mali-T82x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
- <event counter="ARM_Mali-T82x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
- <event counter="ARM_Mali-T82x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
-
- <event counter="ARM_Mali-T82x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
- <event counter="ARM_Mali-T82x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
- <event counter="ARM_Mali-T82x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
-
- </category>
-
- <category name="Mali Tiler" per_cpu="no">
-
- <event counter="ARM_Mali-T82x_TI_ACTIVE" title="Mali Tiler Cycles" name="Tiler cycles" description="Number of cycles Tiler active"/>
-
- <event counter="ARM_Mali-T82x_TI_POLYGONS" title="Mali Tiler Primitives" name="Polygons" description="Number of polygons processed"/>
- <event counter="ARM_Mali-T82x_TI_QUADS" title="Mali Tiler Primitives" name="Quads" description="Number of quads processed"/>
- <event counter="ARM_Mali-T82x_TI_TRIANGLES" title="Mali Tiler Primitives" name="Triangles" description="Number of triangles processed"/>
- <event counter="ARM_Mali-T82x_TI_LINES" title="Mali Tiler Primitives" name="Lines" description="Number of lines processed"/>
- <event counter="ARM_Mali-T82x_TI_POINTS" title="Mali Tiler Primitives" name="Points" description="Number of points processed"/>
-
- <event counter="ARM_Mali-T82x_TI_FRONT_FACING" title="Mali Tiler Culling" name="Front facing prims" description="Number of front facing primitives"/>
- <event counter="ARM_Mali-T82x_TI_BACK_FACING" title="Mali Tiler Culling" name="Back facing prims" description="Number of back facing primitives"/>
- <event counter="ARM_Mali-T82x_TI_PRIM_VISIBLE" title="Mali Tiler Culling" name="Visible prims" description="Number of visible primitives"/>
- <event counter="ARM_Mali-T82x_TI_PRIM_CULLED" title="Mali Tiler Culling" name="Culled prims" description="Number of culled primitives"/>
- <event counter="ARM_Mali-T82x_TI_PRIM_CLIPPED" title="Mali Tiler Culling" name="Clipped prims" description="Number of clipped primitives"/>
-
- </category>
-
- <category name="Mali Shader Core" per_cpu="no">
-
- <event counter="ARM_Mali-T82x_TRIPIPE_ACTIVE" title="Mali Core Cycles" name="Tripipe cycles" description="Number of cycles tripipe was active"/>
- <event counter="ARM_Mali-T82x_FRAG_ACTIVE" title="Mali Core Cycles" name="Fragment cycles" description="Number of cycles fragment processing was active"/>
- <event counter="ARM_Mali-T82x_COMPUTE_ACTIVE" title="Mali Core Cycles" name="Compute cycles" description="Number of cycles vertex\compute processing was active"/>
- <event counter="ARM_Mali-T82x_FRAG_CYCLES_NO_TILE" title="Mali Core Cycles" name="Fragment cycles waiting for tile" description="Number of cycles spent waiting for a physical tile buffer"/>
- <event counter="ARM_Mali-T82x_FRAG_CYCLES_FPKQ_ACTIVE" title="Mali Core Cycles" name="Fragment cycles pre-pipe buffer not empty" description="Number of cycles the pre-pipe queue contains quads"/>
-
- <event counter="ARM_Mali-T82x_FRAG_THREADS" title="Mali Fragment Threads" name="Fragment threads" description="Number of fragment threads started"/>
- <event counter="ARM_Mali-T82x_FRAG_DUMMY_THREADS" title="Mali Fragment Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
- <event counter="ARM_Mali-T82x_FRAG_THREADS_LZS_TEST" title="Mali Fragment Threads" name="Fragment threads doing late ZS" description="Number of threads doing late ZS test"/>
- <event counter="ARM_Mali-T82x_FRAG_THREADS_LZS_KILLED" title="Mali Fragment Threads" name="Fragment threads killed late ZS" description="Number of threads killed by late ZS test"/>
-
- <event counter="ARM_Mali-T82x_COMPUTE_TASKS" title="Mali Compute Tasks" name="Compute tasks" description="Number of compute tasks"/>
- <event counter="ARM_Mali-T82x_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads" description="Number of compute threads started"/>
-
- <event counter="ARM_Mali-T82x_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
- <event counter="ARM_Mali-T82x_FRAG_PRIMITIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
-
- <event counter="ARM_Mali-T82x_FRAG_QUADS_RAST" title="Mali Fragment Quads" name="Quads rasterized" description="Number of quads rasterized"/>
- <event counter="ARM_Mali-T82x_FRAG_QUADS_EZS_TEST" title="Mali Fragment Quads" name="Quads doing early ZS" description="Number of quads doing early ZS test"/>
- <event counter="ARM_Mali-T82x_FRAG_QUADS_EZS_KILLED" title="Mali Fragment Quads" name="Quads killed early Z" description="Number of quads killed by early ZS test"/>
-
- <event counter="ARM_Mali-T82x_FRAG_NUM_TILES" title="Mali Fragment Tasks" name="Tiles rendered" description="Number of tiles rendered"/>
- <event counter="ARM_Mali-T82x_FRAG_TRANS_ELIM" title="Mali Fragment Tasks" name="Tile writes killed by TE" description="Number of tile writes skipped by transaction elimination"/>
-
- <event counter="ARM_Mali-T82x_ARITH_WORDS" title="Mali Arithmetic Pipe" name="A instructions" description="Number of batched instructions executed by the A-pipe (normalized per pipe)"/>
-
- <event counter="ARM_Mali-T82x_LS_WORDS" title="Mali Load/Store Pipe" name="LS instructions" description="Number of instructions completed by the LS-pipe"/>
- <event counter="ARM_Mali-T82x_LS_ISSUES" title="Mali Load/Store Pipe" name="LS instruction issues" description="Number of instructions issued to the LS-pipe, including restarts"/>
-
- <event counter="ARM_Mali-T82x_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>
- <event counter="ARM_Mali-T82x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
- <event counter="ARM_Mali-T82x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
-
- <event counter="ARM_Mali-T82x_LSC_READ_OP" title="Mali Load/Store Cache Reads" name="Read operations" description="Number of read operations in the Load/Store cache"/>
- <event counter="ARM_Mali-T82x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
-
- <event counter="ARM_Mali-T82x_LSC_WRITE_OP" title="Mali Load/Store Cache Writes" name="Write operations" description="Number of write operations in the Load/Store cache"/>
- <event counter="ARM_Mali-T82x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
-
- <event counter="ARM_Mali-T82x_LSC_ATOMIC_OP" title="Mali Load/Store Cache Atomics" name="Atomic operations" description="Number of atomic operations in the Load/Store cache"/>
- <event counter="ARM_Mali-T82x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
-
- <event counter="ARM_Mali-T82x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
- <event counter="ARM_Mali-T82x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
-
- <event counter="ARM_Mali-T82x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
-
- </category>
-
- <category name="Mali L2 Cache" per_cpu="no">
-
- <event counter="ARM_Mali-T82x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>
- <event counter="ARM_Mali-T82x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
- <event counter="ARM_Mali-T82x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
-
- <event counter="ARM_Mali-T82x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
- <event counter="ARM_Mali-T82x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
- <event counter="ARM_Mali-T82x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>
-
- <event counter="ARM_Mali-T82x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
- <event counter="ARM_Mali-T82x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T82x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
- <event counter="ARM_Mali-T82x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
-
- <event counter="ARM_Mali-T82x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
- <event counter="ARM_Mali-T82x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T82x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
-
- </category>
+
+ <category name="Mali Job Manager" per_cpu="no">
+
+ <event counter="ARM_Mali-T82x_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles GPU active"/>
+ <event counter="ARM_Mali-T82x_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles GPU interrupt pending"/>
+ <event counter="ARM_Mali-T82x_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) active"/>
+ <event counter="ARM_Mali-T82x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
+ <event counter="ARM_Mali-T82x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
+
+ <event counter="ARM_Mali-T82x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
+ <event counter="ARM_Mali-T82x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
+ <event counter="ARM_Mali-T82x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-T82x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
+ <event counter="ARM_Mali-T82x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
+ <event counter="ARM_Mali-T82x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
+
+ </category>
+
+ <category name="Mali Tiler" per_cpu="no">
+
+ <event counter="ARM_Mali-T82x_TI_ACTIVE" title="Mali Tiler Cycles" name="Tiler cycles" description="Number of cycles Tiler active"/>
+
+ <event counter="ARM_Mali-T82x_TI_POLYGONS" title="Mali Tiler Primitives" name="Polygons" description="Number of polygons processed"/>
+ <event counter="ARM_Mali-T82x_TI_QUADS" title="Mali Tiler Primitives" name="Quads" description="Number of quads processed"/>
+ <event counter="ARM_Mali-T82x_TI_TRIANGLES" title="Mali Tiler Primitives" name="Triangles" description="Number of triangles processed"/>
+ <event counter="ARM_Mali-T82x_TI_LINES" title="Mali Tiler Primitives" name="Lines" description="Number of lines processed"/>
+ <event counter="ARM_Mali-T82x_TI_POINTS" title="Mali Tiler Primitives" name="Points" description="Number of points processed"/>
+
+ <event counter="ARM_Mali-T82x_TI_FRONT_FACING" title="Mali Tiler Culling" name="Front facing prims" description="Number of front facing primitives"/>
+ <event counter="ARM_Mali-T82x_TI_BACK_FACING" title="Mali Tiler Culling" name="Back facing prims" description="Number of back facing primitives"/>
+ <event counter="ARM_Mali-T82x_TI_PRIM_VISIBLE" title="Mali Tiler Culling" name="Visible prims" description="Number of visible primitives"/>
+ <event counter="ARM_Mali-T82x_TI_PRIM_CULLED" title="Mali Tiler Culling" name="Culled prims" description="Number of culled primitives"/>
+ <event counter="ARM_Mali-T82x_TI_PRIM_CLIPPED" title="Mali Tiler Culling" name="Clipped prims" description="Number of clipped primitives"/>
+
+ </category>
+
+ <category name="Mali Shader Core" per_cpu="no">
+
+ <event counter="ARM_Mali-T82x_TRIPIPE_ACTIVE" title="Mali Core Cycles" name="Tripipe cycles" description="Number of cycles tripipe was active"/>
+ <event counter="ARM_Mali-T82x_FRAG_ACTIVE" title="Mali Core Cycles" name="Fragment cycles" description="Number of cycles fragment processing was active"/>
+ <event counter="ARM_Mali-T82x_COMPUTE_ACTIVE" title="Mali Core Cycles" name="Compute cycles" description="Number of cycles vertex\compute processing was active"/>
+ <event counter="ARM_Mali-T82x_FRAG_CYCLES_NO_TILE" title="Mali Core Cycles" name="Fragment cycles waiting for tile" description="Number of cycles spent waiting for a physical tile buffer"/>
+ <event counter="ARM_Mali-T82x_FRAG_CYCLES_FPKQ_ACTIVE" title="Mali Core Cycles" name="Fragment cycles pre-pipe buffer not empty" description="Number of cycles the pre-pipe queue contains quads"/>
+
+ <event counter="ARM_Mali-T82x_FRAG_THREADS" title="Mali Fragment Threads" name="Fragment threads" description="Number of fragment threads started"/>
+ <event counter="ARM_Mali-T82x_FRAG_DUMMY_THREADS" title="Mali Fragment Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
+ <event counter="ARM_Mali-T82x_FRAG_THREADS_LZS_TEST" title="Mali Fragment Threads" name="Fragment threads doing late ZS" description="Number of threads doing late ZS test"/>
+ <event counter="ARM_Mali-T82x_FRAG_THREADS_LZS_KILLED" title="Mali Fragment Threads" name="Fragment threads killed late ZS" description="Number of threads killed by late ZS test"/>
+
+ <event counter="ARM_Mali-T82x_COMPUTE_TASKS" title="Mali Compute Tasks" name="Compute tasks" description="Number of compute tasks"/>
+ <event counter="ARM_Mali-T82x_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads" description="Number of compute threads started"/>
+
+ <event counter="ARM_Mali-T82x_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
+ <event counter="ARM_Mali-T82x_FRAG_PRIMITIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
+
+ <event counter="ARM_Mali-T82x_FRAG_QUADS_RAST" title="Mali Fragment Quads" name="Quads rasterized" description="Number of quads rasterized"/>
+ <event counter="ARM_Mali-T82x_FRAG_QUADS_EZS_TEST" title="Mali Fragment Quads" name="Quads doing early ZS" description="Number of quads doing early ZS test"/>
+ <event counter="ARM_Mali-T82x_FRAG_QUADS_EZS_KILLED" title="Mali Fragment Quads" name="Quads killed early Z" description="Number of quads killed by early ZS test"/>
+
+ <event counter="ARM_Mali-T82x_FRAG_NUM_TILES" title="Mali Fragment Tasks" name="Tiles rendered" description="Number of tiles rendered"/>
+ <event counter="ARM_Mali-T82x_FRAG_TRANS_ELIM" title="Mali Fragment Tasks" name="Tile writes killed by TE" description="Number of tile writes skipped by transaction elimination"/>
+
+ <event counter="ARM_Mali-T82x_ARITH_WORDS" title="Mali Arithmetic Pipe" name="A instructions" description="Number of batched instructions executed by the A-pipe (normalized per pipe)"/>
+
+ <event counter="ARM_Mali-T82x_LS_WORDS" title="Mali Load/Store Pipe" name="LS instructions" description="Number of instructions completed by the LS-pipe"/>
+ <event counter="ARM_Mali-T82x_LS_ISSUES" title="Mali Load/Store Pipe" name="LS instruction issues" description="Number of instructions issued to the LS-pipe, including restarts"/>
+
+ <event counter="ARM_Mali-T82x_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>
+ <event counter="ARM_Mali-T82x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
+ <event counter="ARM_Mali-T82x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
+
+ <event counter="ARM_Mali-T82x_LSC_READ_OP" title="Mali Load/Store Cache Reads" name="Read operations" description="Number of read operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T82x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T82x_LSC_WRITE_OP" title="Mali Load/Store Cache Writes" name="Write operations" description="Number of write operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T82x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T82x_LSC_ATOMIC_OP" title="Mali Load/Store Cache Atomics" name="Atomic operations" description="Number of atomic operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T82x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T82x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
+ <event counter="ARM_Mali-T82x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T82x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
+
+ </category>
+
+ <category name="Mali L2 Cache" per_cpu="no">
+
+ <event counter="ARM_Mali-T82x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T82x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
+ <event counter="ARM_Mali-T82x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
+
+ <event counter="ARM_Mali-T82x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
+ <event counter="ARM_Mali-T82x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
+ <event counter="ARM_Mali-T82x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+
+ <event counter="ARM_Mali-T82x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
+ <event counter="ARM_Mali-T82x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T82x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
+ <event counter="ARM_Mali-T82x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
+
+ <event counter="ARM_Mali-T82x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
+ <event counter="ARM_Mali-T82x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T82x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+
+ </category>
diff --git a/daemon/events-Mali-V500.xml b/daemon/events-Mali-V500.xml
index 89bc7f4..bc2d6aa 100644
--- a/daemon/events-Mali-V500.xml
+++ b/daemon/events-Mali-V500.xml
@@ -25,6 +25,6 @@
<event counter="ARM_Mali-V500_evn2" title="MVE-V500 Frames" name="Frame Processed" description="Generated when the MVE has finished processing a frame"/>
<event counter="ARM_Mali-V500_evn3" title="MVE-V500 Output" name="Output buffer received" description="Generated when an an output buffer is returned to us from the MVE"/>
<event counter="ARM_Mali-V500_evn4" title="MVE-V500 Input" name="Input buffer received" description="Generated when we an input buffer is returned to us from the MVE"/>
- <event counter="ARM_Mali-V500_act0" title="MVE-V500 Parsed" name="Activity" class="activity" activity1="activity" activity_color1="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" cores="8" description="Mali-V500 Activity"/>
- <event counter="ARM_Mali-V500_act1" title="MVE-V500 Piped" name="Activity" class="activity" activity1="activity" activity_color1="0x0000ff00" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" cores="8" description="Mali-V500 Activity"/>
+ <event counter="ARM_Mali-V500_act0" title="MVE-V500 Parsed" name="Activity" class="activity" activity1="activity" activity_color1="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" per_cpu="yes" cores="8" description="Mali-V500 Activity"/>
+ <event counter="ARM_Mali-V500_act1" title="MVE-V500 Piped" name="Activity" class="activity" activity1="activity" activity_color1="0x0000ff00" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" per_cpu="yes" cores="8" description="Mali-V500 Activity"/>
</category>
diff --git a/daemon/events-atrace.xml b/daemon/events-atrace.xml
new file mode 100644
index 0000000..432b6af
--- /dev/null
+++ b/daemon/events-atrace.xml
@@ -0,0 +1,19 @@
+ <category name="Atrace">
+ <event counter="atrace_graphics" flag="0x2" title="Atrace" name="Graphics" description="Graphics"/>
+ <event counter="atrace_input" flag="0x4" title="Atrace" name="Input" description="Input"/>
+ <event counter="atrace_view" flag="0x8" title="Atrace" name="View" description="View"/>
+ <event counter="atrace_webview" flag="0x10" title="Atrace" name="Webview" description="Webview"/>
+ <event counter="atrace_window_manager" flag="0x20" title="Atrace" name="Window manager" description="Window manager"/>
+ <event counter="atrace_activity_manager" flag="0x40" title="Atrace" name="Activity manager" description="Activity manager"/>
+ <event counter="atrace_sync_manager" flag="0x80" title="Atrace" name="Sync manager" description="Sync manager"/>
+ <event counter="atrace_audio" flag="0x100" title="Atrace" name="Audio" description="Audio"/>
+ <event counter="atrace_video" flag="0x200" title="Atrace" name="Video" description="Video"/>
+ <event counter="atrace_camera" flag="0x400" title="Atrace" name="Camera" description="Camera"/>
+ <event counter="atrace_hal" flag="0x800" title="Atrace" name="Hal" description="Hal"/>
+ <event counter="atrace_app" flag="0x1000" title="Atrace" name="App" description="App"/>
+ <event counter="atrace_resources" flag="0x2000" title="Atrace" name="Resources" description="Resources"/>
+ <event counter="atrace_dalvik" flag="0x4000" title="Atrace" name="Dalvik" description="Dalvik"/>
+ <event counter="atrace_rs" flag="0x8000" title="Atrace" name="Rs" description="Rs"/>
+ <event counter="atrace_bionic" flag="0x10000" title="Atrace" name="Bionic" description="Bionic"/>
+ <event counter="atrace_power" flag="0x20000" title="Atrace" name="Power" description="Power"/>
+ </category>
diff --git a/daemon/events-ftrace.xml b/daemon/events-ftrace.xml
index ae5529f..17fad17 100644
--- a/daemon/events-ftrace.xml
+++ b/daemon/events-ftrace.xml
@@ -1,22 +1,24 @@
<category name="Ftrace">
<!--
- Ftrace counters require Linux 3.10 or later. If you do you see ftrace counters in counter configuration, please check your Linux version.
+ ftrace counters require Linux 3.10 or later; if you do not see ftrace counters in counter configuration, please check your Linux version
'counter' attribute must start with ftrace_ and be unique
the regex item in () is the value shown or, if the parentheses are missing, the number of regex matches is counted
'enable' (optional) is the ftrace event to enable associated with the gator event
+ 'tracepoint' (optional) same meaning as enable, but will use perf instead of ftrace when using user space gator
+ 'arg' (optional) used in conjunction with 'tracepoint' to specify the value to show otherwise the number of tracepoint events is counted
-->
<!--
- <event counter="ftrace_trace_marker_numbers" title="ftrace" name="trace_marker" regex="^tracing_mark_write: ([0-9]+)\s$" class="absolute" description="Numbers written to /sys/kernel/debug/tracing/trace_marker, ex: echo 42 > /sys/kernel/debug/tracing/trace_marker"/>
+ <event counter="ftrace_trace_marker_numbers" title="ftrace" name="trace_marker" regex="^tracing_mark_write: ([0-9]+)$" class="absolute" description="Numbers written to /sys/kernel/debug/tracing/trace_marker, ex: echo 42 > /sys/kernel/debug/tracing/trace_marker"/>
-->
<!-- ftrace counters -->
- <event counter="ftrace_kmem_kmalloc" title="Kmem" name="kmalloc" regex="^kmalloc:.* bytes_alloc=([0-9]+) " enable="kmem/kmalloc" class="incident" description="Number of bytes allocated in the kernel using kmalloc"/>
- <event counter="ftrace_ext4_ext4_da_write" title="Ext4" name="ext4_da_write" regex="^ext4_da_write_end:.* len ([0-9]+) " enable="ext4/ext4_da_write_end" class="incident" description="Number of bytes written to an ext4 filesystem"/>
- <event counter="ftrace_f2fs_f2fs_write" title="F2FS" name="f2fs_write" regex="^f2fs_write_end:.* len ([0-9]+), " enable="f2fs/f2fs_write_end" class="incident" description="Number of bytes written to an f2fs filesystem"/>
- <event counter="ftrace_power_clock_set_rate" title="Power" name="clock_set_rate" regex="^clock_set_rate:.* state=([0-9]+) " enable="power/clock_set_rate" class="absolute" description="Clock rate state"/>
+ <event counter="ftrace_kmem_kmalloc" title="Kmem" name="kmalloc" regex="^kmalloc:.* bytes_alloc=([0-9]+) " tracepoint="kmem/kmalloc" arg="bytes_alloc" class="incident" description="Number of bytes allocated in the kernel using kmalloc"/>
+ <event counter="ftrace_ext4_ext4_da_write" title="Ext4" name="ext4_da_write" regex="^ext4_da_write_end:.* len ([0-9]+) " tracepoint="ext4/ext4_da_write_end" arg="len" class="incident" description="Number of bytes written to an ext4 filesystem"/>
+ <event counter="ftrace_f2fs_f2fs_write" title="F2FS" name="f2fs_write" regex="^f2fs_write_end:.* len ([0-9]+), " tracepoint="f2fs/f2fs_write_end" arg="len" class="incident" description="Number of bytes written to an f2fs filesystem"/>
+ <event counter="ftrace_power_clock_set_rate" title="Power" name="clock_set_rate" regex="^clock_set_rate:.* state=([0-9]+) " tracepoint="power/clock_set_rate" arg="state" class="absolute" description="Clock rate state"/>
<!-- counting ftrace counters -->
- <event counter="ftrace_block_block_rq_complete" title="Block" name="block_rq_complete" regex="^block_rq_complete: " enable="block/block_rq_complete" class="delta" description="Number of block IO operations completed by device driver"/>
- <event counter="ftrace_block_block_rq_issue" title="Block" name="block_rq_issue" regex="^block_rq_issue: " enable="block/block_rq_issue" class="delta" description="Number of block IO operations issued to device driver"/>
- <event counter="ftrace_power_cpu_idle" title="Power" name="cpu_idle" regex="^cpu_idle: " enable="power/cpu_idle" class="delta" description="Number of times cpu_idle is entered or exited"/>
+ <event counter="ftrace_block_block_rq_complete" title="Block" name="block_rq_complete" regex="^block_rq_complete: " tracepoint="block/block_rq_complete" class="delta" description="Number of block IO operations completed by device driver"/>
+ <event counter="ftrace_block_block_rq_issue" title="Block" name="block_rq_issue" regex="^block_rq_issue: " tracepoint="block/block_rq_issue" class="delta" description="Number of block IO operations issued to device driver"/>
+ <event counter="ftrace_power_cpu_idle" title="Power" name="cpu_idle" regex="^cpu_idle: " tracepoint="power/cpu_idle" class="delta" description="Number of times cpu_idle is entered or exited"/>
</category>
diff --git a/daemon/k/perf_event.3.12.h b/daemon/k/perf_event.3.12.h
deleted file mode 100644
index e886c48..0000000
--- a/daemon/k/perf_event.3.12.h
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * Performance events:
- *
- * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
- * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
- * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra
- *
- * Data type definitions, declarations, prototypes.
- *
- * Started by: Thomas Gleixner and Ingo Molnar
- *
- * For licencing details see kernel-base/COPYING
- */
-#ifndef _LINUX_PERF_EVENT_H
-#define _LINUX_PERF_EVENT_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <asm/byteorder.h>
-
-/*
- * User-space ABI bits:
- */
-
-/*
- * attr.type
- */
-enum perf_type_id {
- PERF_TYPE_HARDWARE = 0,
- PERF_TYPE_SOFTWARE = 1,
- PERF_TYPE_TRACEPOINT = 2,
- PERF_TYPE_HW_CACHE = 3,
- PERF_TYPE_RAW = 4,
- PERF_TYPE_BREAKPOINT = 5,
-
- PERF_TYPE_MAX, /* non-ABI */
-};
-
-/*
- * Generalized performance event event_id types, used by the
- * attr.event_id parameter of the sys_perf_event_open()
- * syscall:
- */
-enum perf_hw_id {
- /*
- * Common hardware events, generalized by the kernel:
- */
- PERF_COUNT_HW_CPU_CYCLES = 0,
- PERF_COUNT_HW_INSTRUCTIONS = 1,
- PERF_COUNT_HW_CACHE_REFERENCES = 2,
- PERF_COUNT_HW_CACHE_MISSES = 3,
- PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
- PERF_COUNT_HW_BRANCH_MISSES = 5,
- PERF_COUNT_HW_BUS_CYCLES = 6,
- PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
- PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
- PERF_COUNT_HW_REF_CPU_CYCLES = 9,
-
- PERF_COUNT_HW_MAX, /* non-ABI */
-};
-
-/*
- * Generalized hardware cache events:
- *
- * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
- * { read, write, prefetch } x
- * { accesses, misses }
- */
-enum perf_hw_cache_id {
- PERF_COUNT_HW_CACHE_L1D = 0,
- PERF_COUNT_HW_CACHE_L1I = 1,
- PERF_COUNT_HW_CACHE_LL = 2,
- PERF_COUNT_HW_CACHE_DTLB = 3,
- PERF_COUNT_HW_CACHE_ITLB = 4,
- PERF_COUNT_HW_CACHE_BPU = 5,
- PERF_COUNT_HW_CACHE_NODE = 6,
-
- PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
-};
-
-enum perf_hw_cache_op_id {
- PERF_COUNT_HW_CACHE_OP_READ = 0,
- PERF_COUNT_HW_CACHE_OP_WRITE = 1,
- PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
-
- PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
-};
-
-enum perf_hw_cache_op_result_id {
- PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
- PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
-
- PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
-};
-
-/*
- * Special "software" events provided by the kernel, even if the hardware
- * does not support performance events. These events measure various
- * physical and sw events of the kernel (and allow the profiling of them as
- * well):
- */
-enum perf_sw_ids {
- PERF_COUNT_SW_CPU_CLOCK = 0,
- PERF_COUNT_SW_TASK_CLOCK = 1,
- PERF_COUNT_SW_PAGE_FAULTS = 2,
- PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
- PERF_COUNT_SW_CPU_MIGRATIONS = 4,
- PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
- PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
- PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
- PERF_COUNT_SW_EMULATION_FAULTS = 8,
- PERF_COUNT_SW_DUMMY = 9,
-
- PERF_COUNT_SW_MAX, /* non-ABI */
-};
-
-/*
- * Bits that can be set in attr.sample_type to request information
- * in the overflow packets.
- */
-enum perf_event_sample_format {
- PERF_SAMPLE_IP = 1U << 0,
- PERF_SAMPLE_TID = 1U << 1,
- PERF_SAMPLE_TIME = 1U << 2,
- PERF_SAMPLE_ADDR = 1U << 3,
- PERF_SAMPLE_READ = 1U << 4,
- PERF_SAMPLE_CALLCHAIN = 1U << 5,
- PERF_SAMPLE_ID = 1U << 6,
- PERF_SAMPLE_CPU = 1U << 7,
- PERF_SAMPLE_PERIOD = 1U << 8,
- PERF_SAMPLE_STREAM_ID = 1U << 9,
- PERF_SAMPLE_RAW = 1U << 10,
- PERF_SAMPLE_BRANCH_STACK = 1U << 11,
- PERF_SAMPLE_REGS_USER = 1U << 12,
- PERF_SAMPLE_STACK_USER = 1U << 13,
- PERF_SAMPLE_WEIGHT = 1U << 14,
- PERF_SAMPLE_DATA_SRC = 1U << 15,
- PERF_SAMPLE_IDENTIFIER = 1U << 16,
-
- PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */
-};
-
-/*
- * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
- *
- * If the user does not pass priv level information via branch_sample_type,
- * the kernel uses the event's priv level. Branch and event priv levels do
- * not have to match. Branch priv level is checked for permissions.
- *
- * The branch types can be combined, however BRANCH_ANY covers all types
- * of branches and therefore it supersedes all the other types.
- */
-enum perf_branch_sample_type {
- PERF_SAMPLE_BRANCH_USER = 1U << 0, /* user branches */
- PERF_SAMPLE_BRANCH_KERNEL = 1U << 1, /* kernel branches */
- PERF_SAMPLE_BRANCH_HV = 1U << 2, /* hypervisor branches */
-
- PERF_SAMPLE_BRANCH_ANY = 1U << 3, /* any branch types */
- PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 4, /* any call branch */
- PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 5, /* any return branch */
- PERF_SAMPLE_BRANCH_IND_CALL = 1U << 6, /* indirect calls */
- PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */
- PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */
- PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */
-
- PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */
-};
-
-#define PERF_SAMPLE_BRANCH_PLM_ALL \
- (PERF_SAMPLE_BRANCH_USER|\
- PERF_SAMPLE_BRANCH_KERNEL|\
- PERF_SAMPLE_BRANCH_HV)
-
-/*
- * Values to determine ABI of the registers dump.
- */
-enum perf_sample_regs_abi {
- PERF_SAMPLE_REGS_ABI_NONE = 0,
- PERF_SAMPLE_REGS_ABI_32 = 1,
- PERF_SAMPLE_REGS_ABI_64 = 2,
-};
-
-/*
- * The format of the data returned by read() on a perf event fd,
- * as specified by attr.read_format:
- *
- * struct read_format {
- * { u64 value;
- * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
- * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
- * { u64 id; } && PERF_FORMAT_ID
- * } && !PERF_FORMAT_GROUP
- *
- * { u64 nr;
- * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
- * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
- * { u64 value;
- * { u64 id; } && PERF_FORMAT_ID
- * } cntr[nr];
- * } && PERF_FORMAT_GROUP
- * };
- */
-enum perf_event_read_format {
- PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
- PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
- PERF_FORMAT_ID = 1U << 2,
- PERF_FORMAT_GROUP = 1U << 3,
-
- PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
-};
-
-#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
-#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */
-#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
-#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
- /* add: sample_stack_user */
-
-/*
- * Hardware event_id to monitor via a performance monitoring event:
- */
-struct perf_event_attr {
-
- /*
- * Major type: hardware/software/tracepoint/etc.
- */
- __u32 type;
-
- /*
- * Size of the attr structure, for fwd/bwd compat.
- */
- __u32 size;
-
- /*
- * Type specific configuration information.
- */
- __u64 config;
-
- union {
- __u64 sample_period;
- __u64 sample_freq;
- };
-
- __u64 sample_type;
- __u64 read_format;
-
- __u64 disabled : 1, /* off by default */
- inherit : 1, /* children inherit it */
- pinned : 1, /* must always be on PMU */
- exclusive : 1, /* only group on PMU */
- exclude_user : 1, /* don't count user */
- exclude_kernel : 1, /* ditto kernel */
- exclude_hv : 1, /* ditto hypervisor */
- exclude_idle : 1, /* don't count when idle */
- mmap : 1, /* include mmap data */
- comm : 1, /* include comm data */
- freq : 1, /* use freq, not period */
- inherit_stat : 1, /* per task counts */
- enable_on_exec : 1, /* next exec enables */
- task : 1, /* trace fork/exit */
- watermark : 1, /* wakeup_watermark */
- /*
- * precise_ip:
- *
- * 0 - SAMPLE_IP can have arbitrary skid
- * 1 - SAMPLE_IP must have constant skid
- * 2 - SAMPLE_IP requested to have 0 skid
- * 3 - SAMPLE_IP must have 0 skid
- *
- * See also PERF_RECORD_MISC_EXACT_IP
- */
- precise_ip : 2, /* skid constraint */
- mmap_data : 1, /* non-exec mmap data */
- sample_id_all : 1, /* sample_type all events */
-
- exclude_host : 1, /* don't count in host */
- exclude_guest : 1, /* don't count in guest */
-
- exclude_callchain_kernel : 1, /* exclude kernel callchains */
- exclude_callchain_user : 1, /* exclude user callchains */
- mmap2 : 1, /* include mmap with inode data */
-
- __reserved_1 : 40;
-
- union {
- __u32 wakeup_events; /* wakeup every n events */
- __u32 wakeup_watermark; /* bytes before wakeup */
- };
-
- __u32 bp_type;
- union {
- __u64 bp_addr;
- __u64 config1; /* extension of config */
- };
- union {
- __u64 bp_len;
- __u64 config2; /* extension of config1 */
- };
- __u64 branch_sample_type; /* enum perf_branch_sample_type */
-
- /*
- * Defines set of user regs to dump on samples.
- * See asm/perf_regs.h for details.
- */
- __u64 sample_regs_user;
-
- /*
- * Defines size of the user stack to dump on samples.
- */
- __u32 sample_stack_user;
-
- /* Align to u64. */
- __u32 __reserved_2;
-};
-
-#define perf_flags(attr) (*(&(attr)->read_format + 1))
-
-/*
- * Ioctls that can be done on a perf event fd:
- */
-#define PERF_EVENT_IOC_ENABLE _IO ('$', 0)
-#define PERF_EVENT_IOC_DISABLE _IO ('$', 1)
-#define PERF_EVENT_IOC_REFRESH _IO ('$', 2)
-#define PERF_EVENT_IOC_RESET _IO ('$', 3)
-#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64)
-#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
-#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
-#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
-
-enum perf_event_ioc_flags {
- PERF_IOC_FLAG_GROUP = 1U << 0,
-};
-
-/*
- * Structure of the page that can be mapped via mmap
- */
-struct perf_event_mmap_page {
- __u32 version; /* version number of this structure */
- __u32 compat_version; /* lowest version this is compat with */
-
- /*
- * Bits needed to read the hw events in user-space.
- *
- * u32 seq, time_mult, time_shift, idx, width;
- * u64 count, enabled, running;
- * u64 cyc, time_offset;
- * s64 pmc = 0;
- *
- * do {
- * seq = pc->lock;
- * barrier()
- *
- * enabled = pc->time_enabled;
- * running = pc->time_running;
- *
- * if (pc->cap_usr_time && enabled != running) {
- * cyc = rdtsc();
- * time_offset = pc->time_offset;
- * time_mult = pc->time_mult;
- * time_shift = pc->time_shift;
- * }
- *
- * idx = pc->index;
- * count = pc->offset;
- * if (pc->cap_usr_rdpmc && idx) {
- * width = pc->pmc_width;
- * pmc = rdpmc(idx - 1);
- * }
- *
- * barrier();
- * } while (pc->lock != seq);
- *
- * NOTE: for obvious reason this only works on self-monitoring
- * processes.
- */
- __u32 lock; /* seqlock for synchronization */
- __u32 index; /* hardware event identifier */
- __s64 offset; /* add to hardware event value */
- __u64 time_enabled; /* time event active */
- __u64 time_running; /* time event on cpu */
- union {
- __u64 capabilities;
- struct {
- __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
- cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */
-
- cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */
- cap_user_time : 1, /* The time_* fields are used */
- cap_user_time_zero : 1, /* The time_zero field is used */
- cap_____res : 59;
- };
- };
-
- /*
- * If cap_usr_rdpmc this field provides the bit-width of the value
- * read using the rdpmc() or equivalent instruction. This can be used
- * to sign extend the result like:
- *
- * pmc <<= 64 - width;
- * pmc >>= 64 - width; // signed shift right
- * count += pmc;
- */
- __u16 pmc_width;
-
- /*
- * If cap_usr_time the below fields can be used to compute the time
- * delta since time_enabled (in ns) using rdtsc or similar.
- *
- * u64 quot, rem;
- * u64 delta;
- *
- * quot = (cyc >> time_shift);
- * rem = cyc & ((1 << time_shift) - 1);
- * delta = time_offset + quot * time_mult +
- * ((rem * time_mult) >> time_shift);
- *
- * Where time_offset,time_mult,time_shift and cyc are read in the
- * seqcount loop described above. This delta can then be added to
- * enabled and possible running (if idx), improving the scaling:
- *
- * enabled += delta;
- * if (idx)
- * running += delta;
- *
- * quot = count / running;
- * rem = count % running;
- * count = quot * enabled + (rem * enabled) / running;
- */
- __u16 time_shift;
- __u32 time_mult;
- __u64 time_offset;
- /*
- * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
- * from sample timestamps.
- *
- * time = timestamp - time_zero;
- * quot = time / time_mult;
- * rem = time % time_mult;
- * cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
- *
- * And vice versa:
- *
- * quot = cyc >> time_shift;
- * rem = cyc & ((1 << time_shift) - 1);
- * timestamp = time_zero + quot * time_mult +
- * ((rem * time_mult) >> time_shift);
- */
- __u64 time_zero;
- __u32 size; /* Header size up to __reserved[] fields. */
-
- /*
- * Hole for extension of the self monitor capabilities
- */
-
- __u8 __reserved[118*8+4]; /* align to 1k. */
-
- /*
- * Control data for the mmap() data buffer.
- *
- * User-space reading the @data_head value should issue an smp_rmb(),
- * after reading this value.
- *
- * When the mapping is PROT_WRITE the @data_tail value should be
- * written by userspace to reflect the last read data, after issueing
- * an smp_mb() to separate the data read from the ->data_tail store.
- * In this case the kernel will not over-write unread data.
- *
- * See perf_output_put_handle() for the data ordering.
- */
- __u64 data_head; /* head in the data section */
- __u64 data_tail; /* user-space written tail */
-};
-
-#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
-#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
-#define PERF_RECORD_MISC_KERNEL (1 << 0)
-#define PERF_RECORD_MISC_USER (2 << 0)
-#define PERF_RECORD_MISC_HYPERVISOR (3 << 0)
-#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0)
-#define PERF_RECORD_MISC_GUEST_USER (5 << 0)
-
-#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
-/*
- * Indicates that the content of PERF_SAMPLE_IP points to
- * the actual instruction that triggered the event. See also
- * perf_event_attr::precise_ip.
- */
-#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
-/*
- * Reserve the last bit to indicate some extended misc field
- */
-#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15)
-
-struct perf_event_header {
- __u32 type;
- __u16 misc;
- __u16 size;
-};
-
-enum perf_event_type {
-
- /*
- * If perf_event_attr.sample_id_all is set then all event types will
- * have the sample_type selected fields related to where/when
- * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
- * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
- * just after the perf_event_header and the fields already present for
- * the existing fields, i.e. at the end of the payload. That way a newer
- * perf.data file will be supported by older perf tools, with these new
- * optional fields being ignored.
- *
- * struct sample_id {
- * { u32 pid, tid; } && PERF_SAMPLE_TID
- * { u64 time; } && PERF_SAMPLE_TIME
- * { u64 id; } && PERF_SAMPLE_ID
- * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
- * { u32 cpu, res; } && PERF_SAMPLE_CPU
- * { u64 id; } && PERF_SAMPLE_IDENTIFIER
- * } && perf_event_attr::sample_id_all
- *
- * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The
- * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
- * relative to header.size.
- */
-
- /*
- * The MMAP events record the PROT_EXEC mappings so that we can
- * correlate userspace IPs to code. They have the following structure:
- *
- * struct {
- * struct perf_event_header header;
- *
- * u32 pid, tid;
- * u64 addr;
- * u64 len;
- * u64 pgoff;
- * char filename[];
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_MMAP = 1,
-
- /*
- * struct {
- * struct perf_event_header header;
- * u64 id;
- * u64 lost;
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_LOST = 2,
-
- /*
- * struct {
- * struct perf_event_header header;
- *
- * u32 pid, tid;
- * char comm[];
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_COMM = 3,
-
- /*
- * struct {
- * struct perf_event_header header;
- * u32 pid, ppid;
- * u32 tid, ptid;
- * u64 time;
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_EXIT = 4,
-
- /*
- * struct {
- * struct perf_event_header header;
- * u64 time;
- * u64 id;
- * u64 stream_id;
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_THROTTLE = 5,
- PERF_RECORD_UNTHROTTLE = 6,
-
- /*
- * struct {
- * struct perf_event_header header;
- * u32 pid, ppid;
- * u32 tid, ptid;
- * u64 time;
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_FORK = 7,
-
- /*
- * struct {
- * struct perf_event_header header;
- * u32 pid, tid;
- *
- * struct read_format values;
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_READ = 8,
-
- /*
- * struct {
- * struct perf_event_header header;
- *
- * #
- * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
- * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
- * # is fixed relative to header.
- * #
- *
- * { u64 id; } && PERF_SAMPLE_IDENTIFIER
- * { u64 ip; } && PERF_SAMPLE_IP
- * { u32 pid, tid; } && PERF_SAMPLE_TID
- * { u64 time; } && PERF_SAMPLE_TIME
- * { u64 addr; } && PERF_SAMPLE_ADDR
- * { u64 id; } && PERF_SAMPLE_ID
- * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
- * { u32 cpu, res; } && PERF_SAMPLE_CPU
- * { u64 period; } && PERF_SAMPLE_PERIOD
- *
- * { struct read_format values; } && PERF_SAMPLE_READ
- *
- * { u64 nr,
- * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
- *
- * #
- * # The RAW record below is opaque data wrt the ABI
- * #
- * # That is, the ABI doesn't make any promises wrt to
- * # the stability of its content, it may vary depending
- * # on event, hardware, kernel version and phase of
- * # the moon.
- * #
- * # In other words, PERF_SAMPLE_RAW contents are not an ABI.
- * #
- *
- * { u32 size;
- * char data[size];}&& PERF_SAMPLE_RAW
- *
- * { u64 nr;
- * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
- *
- * { u64 abi; # enum perf_sample_regs_abi
- * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
- *
- * { u64 size;
- * char data[size];
- * u64 dyn_size; } && PERF_SAMPLE_STACK_USER
- *
- * { u64 weight; } && PERF_SAMPLE_WEIGHT
- * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
- * };
- */
- PERF_RECORD_SAMPLE = 9,
-
- /*
- * The MMAP2 records are an augmented version of MMAP, they add
- * maj, min, ino numbers to be used to uniquely identify each mapping
- *
- * struct {
- * struct perf_event_header header;
- *
- * u32 pid, tid;
- * u64 addr;
- * u64 len;
- * u64 pgoff;
- * u32 maj;
- * u32 min;
- * u64 ino;
- * u64 ino_generation;
- * char filename[];
- * struct sample_id sample_id;
- * };
- */
- PERF_RECORD_MMAP2 = 10,
-
- PERF_RECORD_MAX, /* non-ABI */
-};
-
-#define PERF_MAX_STACK_DEPTH 127
-
-enum perf_callchain_context {
- PERF_CONTEXT_HV = (__u64)-32,
- PERF_CONTEXT_KERNEL = (__u64)-128,
- PERF_CONTEXT_USER = (__u64)-512,
-
- PERF_CONTEXT_GUEST = (__u64)-2048,
- PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176,
- PERF_CONTEXT_GUEST_USER = (__u64)-2560,
-
- PERF_CONTEXT_MAX = (__u64)-4095,
-};
-
-#define PERF_FLAG_FD_NO_GROUP (1U << 0)
-#define PERF_FLAG_FD_OUTPUT (1U << 1)
-#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */
-
-union perf_mem_data_src {
- __u64 val;
- struct {
- __u64 mem_op:5, /* type of opcode */
- mem_lvl:14, /* memory hierarchy level */
- mem_snoop:5, /* snoop mode */
- mem_lock:2, /* lock instr */
- mem_dtlb:7, /* tlb access */
- mem_rsvd:31;
- };
-};
-
-/* type of opcode (load/store/prefetch,code) */
-#define PERF_MEM_OP_NA 0x01 /* not available */
-#define PERF_MEM_OP_LOAD 0x02 /* load instruction */
-#define PERF_MEM_OP_STORE 0x04 /* store instruction */
-#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */
-#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */
-#define PERF_MEM_OP_SHIFT 0
-
-/* memory hierarchy (memory level, hit or miss) */
-#define PERF_MEM_LVL_NA 0x01 /* not available */
-#define PERF_MEM_LVL_HIT 0x02 /* hit level */
-#define PERF_MEM_LVL_MISS 0x04 /* miss level */
-#define PERF_MEM_LVL_L1 0x08 /* L1 */
-#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */
-#define PERF_MEM_LVL_L2 0x20 /* L2 */
-#define PERF_MEM_LVL_L3 0x40 /* L3 */
-#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */
-#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */
-#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */
-#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */
-#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */
-#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */
-#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */
-#define PERF_MEM_LVL_SHIFT 5
-
-/* snoop mode */
-#define PERF_MEM_SNOOP_NA 0x01 /* not available */
-#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */
-#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */
-#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */
-#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */
-#define PERF_MEM_SNOOP_SHIFT 19
-
-/* locked instruction */
-#define PERF_MEM_LOCK_NA 0x01 /* not available */
-#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */
-#define PERF_MEM_LOCK_SHIFT 24
-
-/* TLB access */
-#define PERF_MEM_TLB_NA 0x01 /* not available */
-#define PERF_MEM_TLB_HIT 0x02 /* hit level */
-#define PERF_MEM_TLB_MISS 0x04 /* miss level */
-#define PERF_MEM_TLB_L1 0x08 /* L1 */
-#define PERF_MEM_TLB_L2 0x10 /* L2 */
-#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/
-#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
-#define PERF_MEM_TLB_SHIFT 26
-
-#define PERF_MEM_S(a, s) \
- (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
-
-/*
- * single taken branch record layout:
- *
- * from: source instruction (may not always be a branch insn)
- * to: branch target
- * mispred: branch target was mispredicted
- * predicted: branch target was predicted
- *
- * support for mispred, predicted is optional. In case it
- * is not supported mispred = predicted = 0.
- *
- * in_tx: running in a hardware transaction
- * abort: aborting a hardware transaction
- */
-struct perf_branch_entry {
- __u64 from;
- __u64 to;
- __u64 mispred:1, /* target mispredicted */
- predicted:1,/* target predicted */
- in_tx:1, /* in transaction */
- abort:1, /* transaction abort */
- reserved:60;
-};
-
-#endif /* _LINUX_PERF_EVENT_H */
diff --git a/daemon/k/perf_event.h b/daemon/k/perf_event.h
index e5dff8c..e886c48 120000..100644
--- a/daemon/k/perf_event.h
+++ b/daemon/k/perf_event.h
@@ -1 +1,792 @@
-perf_event.3.12.h \ No newline at end of file
+/*
+ * Performance events:
+ *
+ * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
+ * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra
+ *
+ * Data type definitions, declarations, prototypes.
+ *
+ * Started by: Thomas Gleixner and Ingo Molnar
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+#ifndef _LINUX_PERF_EVENT_H
+#define _LINUX_PERF_EVENT_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/byteorder.h>
+
+/*
+ * User-space ABI bits:
+ */
+
+/*
+ * attr.type
+ */
+enum perf_type_id {
+ PERF_TYPE_HARDWARE = 0,
+ PERF_TYPE_SOFTWARE = 1,
+ PERF_TYPE_TRACEPOINT = 2,
+ PERF_TYPE_HW_CACHE = 3,
+ PERF_TYPE_RAW = 4,
+ PERF_TYPE_BREAKPOINT = 5,
+
+ PERF_TYPE_MAX, /* non-ABI */
+};
+
+/*
+ * Generalized performance event event_id types, used by the
+ * attr.event_id parameter of the sys_perf_event_open()
+ * syscall:
+ */
+enum perf_hw_id {
+ /*
+ * Common hardware events, generalized by the kernel:
+ */
+ PERF_COUNT_HW_CPU_CYCLES = 0,
+ PERF_COUNT_HW_INSTRUCTIONS = 1,
+ PERF_COUNT_HW_CACHE_REFERENCES = 2,
+ PERF_COUNT_HW_CACHE_MISSES = 3,
+ PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
+ PERF_COUNT_HW_BRANCH_MISSES = 5,
+ PERF_COUNT_HW_BUS_CYCLES = 6,
+ PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
+ PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
+ PERF_COUNT_HW_REF_CPU_CYCLES = 9,
+
+ PERF_COUNT_HW_MAX, /* non-ABI */
+};
+
+/*
+ * Generalized hardware cache events:
+ *
+ * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
+ * { read, write, prefetch } x
+ * { accesses, misses }
+ */
+enum perf_hw_cache_id {
+ PERF_COUNT_HW_CACHE_L1D = 0,
+ PERF_COUNT_HW_CACHE_L1I = 1,
+ PERF_COUNT_HW_CACHE_LL = 2,
+ PERF_COUNT_HW_CACHE_DTLB = 3,
+ PERF_COUNT_HW_CACHE_ITLB = 4,
+ PERF_COUNT_HW_CACHE_BPU = 5,
+ PERF_COUNT_HW_CACHE_NODE = 6,
+
+ PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
+};
+
+enum perf_hw_cache_op_id {
+ PERF_COUNT_HW_CACHE_OP_READ = 0,
+ PERF_COUNT_HW_CACHE_OP_WRITE = 1,
+ PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
+
+ PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
+};
+
+enum perf_hw_cache_op_result_id {
+ PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
+ PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
+
+ PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
+};
+
+/*
+ * Special "software" events provided by the kernel, even if the hardware
+ * does not support performance events. These events measure various
+ * physical and sw events of the kernel (and allow the profiling of them as
+ * well):
+ */
+enum perf_sw_ids {
+ PERF_COUNT_SW_CPU_CLOCK = 0,
+ PERF_COUNT_SW_TASK_CLOCK = 1,
+ PERF_COUNT_SW_PAGE_FAULTS = 2,
+ PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
+ PERF_COUNT_SW_CPU_MIGRATIONS = 4,
+ PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
+ PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
+ PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
+ PERF_COUNT_SW_EMULATION_FAULTS = 8,
+ PERF_COUNT_SW_DUMMY = 9,
+
+ PERF_COUNT_SW_MAX, /* non-ABI */
+};
+
+/*
+ * Bits that can be set in attr.sample_type to request information
+ * in the overflow packets.
+ */
+enum perf_event_sample_format {
+ PERF_SAMPLE_IP = 1U << 0,
+ PERF_SAMPLE_TID = 1U << 1,
+ PERF_SAMPLE_TIME = 1U << 2,
+ PERF_SAMPLE_ADDR = 1U << 3,
+ PERF_SAMPLE_READ = 1U << 4,
+ PERF_SAMPLE_CALLCHAIN = 1U << 5,
+ PERF_SAMPLE_ID = 1U << 6,
+ PERF_SAMPLE_CPU = 1U << 7,
+ PERF_SAMPLE_PERIOD = 1U << 8,
+ PERF_SAMPLE_STREAM_ID = 1U << 9,
+ PERF_SAMPLE_RAW = 1U << 10,
+ PERF_SAMPLE_BRANCH_STACK = 1U << 11,
+ PERF_SAMPLE_REGS_USER = 1U << 12,
+ PERF_SAMPLE_STACK_USER = 1U << 13,
+ PERF_SAMPLE_WEIGHT = 1U << 14,
+ PERF_SAMPLE_DATA_SRC = 1U << 15,
+ PERF_SAMPLE_IDENTIFIER = 1U << 16,
+
+ PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */
+};
+
+/*
+ * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
+ *
+ * If the user does not pass priv level information via branch_sample_type,
+ * the kernel uses the event's priv level. Branch and event priv levels do
+ * not have to match. Branch priv level is checked for permissions.
+ *
+ * The branch types can be combined, however BRANCH_ANY covers all types
+ * of branches and therefore it supersedes all the other types.
+ */
+enum perf_branch_sample_type {
+ PERF_SAMPLE_BRANCH_USER = 1U << 0, /* user branches */
+ PERF_SAMPLE_BRANCH_KERNEL = 1U << 1, /* kernel branches */
+ PERF_SAMPLE_BRANCH_HV = 1U << 2, /* hypervisor branches */
+
+ PERF_SAMPLE_BRANCH_ANY = 1U << 3, /* any branch types */
+ PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 4, /* any call branch */
+ PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 5, /* any return branch */
+ PERF_SAMPLE_BRANCH_IND_CALL = 1U << 6, /* indirect calls */
+ PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */
+ PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */
+ PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */
+
+ PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */
+};
+
+#define PERF_SAMPLE_BRANCH_PLM_ALL \
+ (PERF_SAMPLE_BRANCH_USER|\
+ PERF_SAMPLE_BRANCH_KERNEL|\
+ PERF_SAMPLE_BRANCH_HV)
+
+/*
+ * Values to determine ABI of the registers dump.
+ */
+enum perf_sample_regs_abi {
+ PERF_SAMPLE_REGS_ABI_NONE = 0,
+ PERF_SAMPLE_REGS_ABI_32 = 1,
+ PERF_SAMPLE_REGS_ABI_64 = 2,
+};
+
+/*
+ * The format of the data returned by read() on a perf event fd,
+ * as specified by attr.read_format:
+ *
+ * struct read_format {
+ * { u64 value;
+ * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
+ * { u64 id; } && PERF_FORMAT_ID
+ * } && !PERF_FORMAT_GROUP
+ *
+ * { u64 nr;
+ * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
+ * { u64 value;
+ * { u64 id; } && PERF_FORMAT_ID
+ * } cntr[nr];
+ * } && PERF_FORMAT_GROUP
+ * };
+ */
+enum perf_event_read_format {
+ PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
+ PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
+ PERF_FORMAT_ID = 1U << 2,
+ PERF_FORMAT_GROUP = 1U << 3,
+
+ PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
+};
+
+#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
+#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */
+#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
+#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
+ /* add: sample_stack_user */
+
+/*
+ * Hardware event_id to monitor via a performance monitoring event:
+ */
+struct perf_event_attr {
+
+ /*
+ * Major type: hardware/software/tracepoint/etc.
+ */
+ __u32 type;
+
+ /*
+ * Size of the attr structure, for fwd/bwd compat.
+ */
+ __u32 size;
+
+ /*
+ * Type specific configuration information.
+ */
+ __u64 config;
+
+ union {
+ __u64 sample_period;
+ __u64 sample_freq;
+ };
+
+ __u64 sample_type;
+ __u64 read_format;
+
+ __u64 disabled : 1, /* off by default */
+ inherit : 1, /* children inherit it */
+ pinned : 1, /* must always be on PMU */
+ exclusive : 1, /* only group on PMU */
+ exclude_user : 1, /* don't count user */
+ exclude_kernel : 1, /* ditto kernel */
+ exclude_hv : 1, /* ditto hypervisor */
+ exclude_idle : 1, /* don't count when idle */
+ mmap : 1, /* include mmap data */
+ comm : 1, /* include comm data */
+ freq : 1, /* use freq, not period */
+ inherit_stat : 1, /* per task counts */
+ enable_on_exec : 1, /* next exec enables */
+ task : 1, /* trace fork/exit */
+ watermark : 1, /* wakeup_watermark */
+ /*
+ * precise_ip:
+ *
+ * 0 - SAMPLE_IP can have arbitrary skid
+ * 1 - SAMPLE_IP must have constant skid
+ * 2 - SAMPLE_IP requested to have 0 skid
+ * 3 - SAMPLE_IP must have 0 skid
+ *
+ * See also PERF_RECORD_MISC_EXACT_IP
+ */
+ precise_ip : 2, /* skid constraint */
+ mmap_data : 1, /* non-exec mmap data */
+ sample_id_all : 1, /* sample_type all events */
+
+ exclude_host : 1, /* don't count in host */
+ exclude_guest : 1, /* don't count in guest */
+
+ exclude_callchain_kernel : 1, /* exclude kernel callchains */
+ exclude_callchain_user : 1, /* exclude user callchains */
+ mmap2 : 1, /* include mmap with inode data */
+
+ __reserved_1 : 40;
+
+ union {
+ __u32 wakeup_events; /* wakeup every n events */
+ __u32 wakeup_watermark; /* bytes before wakeup */
+ };
+
+ __u32 bp_type;
+ union {
+ __u64 bp_addr;
+ __u64 config1; /* extension of config */
+ };
+ union {
+ __u64 bp_len;
+ __u64 config2; /* extension of config1 */
+ };
+ __u64 branch_sample_type; /* enum perf_branch_sample_type */
+
+ /*
+ * Defines set of user regs to dump on samples.
+ * See asm/perf_regs.h for details.
+ */
+ __u64 sample_regs_user;
+
+ /*
+ * Defines size of the user stack to dump on samples.
+ */
+ __u32 sample_stack_user;
+
+ /* Align to u64. */
+ __u32 __reserved_2;
+};
+
+#define perf_flags(attr) (*(&(attr)->read_format + 1))
+
+/*
+ * Ioctls that can be done on a perf event fd:
+ */
+#define PERF_EVENT_IOC_ENABLE _IO ('$', 0)
+#define PERF_EVENT_IOC_DISABLE _IO ('$', 1)
+#define PERF_EVENT_IOC_REFRESH _IO ('$', 2)
+#define PERF_EVENT_IOC_RESET _IO ('$', 3)
+#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64)
+#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
+#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
+#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
+
+enum perf_event_ioc_flags {
+ PERF_IOC_FLAG_GROUP = 1U << 0,
+};
+
+/*
+ * Structure of the page that can be mapped via mmap
+ */
+struct perf_event_mmap_page {
+ __u32 version; /* version number of this structure */
+ __u32 compat_version; /* lowest version this is compat with */
+
+ /*
+ * Bits needed to read the hw events in user-space.
+ *
+ * u32 seq, time_mult, time_shift, idx, width;
+ * u64 count, enabled, running;
+ * u64 cyc, time_offset;
+ * s64 pmc = 0;
+ *
+ * do {
+ * seq = pc->lock;
+ * barrier()
+ *
+ * enabled = pc->time_enabled;
+ * running = pc->time_running;
+ *
+ * if (pc->cap_usr_time && enabled != running) {
+ * cyc = rdtsc();
+ * time_offset = pc->time_offset;
+ * time_mult = pc->time_mult;
+ * time_shift = pc->time_shift;
+ * }
+ *
+ * idx = pc->index;
+ * count = pc->offset;
+ * if (pc->cap_usr_rdpmc && idx) {
+ * width = pc->pmc_width;
+ * pmc = rdpmc(idx - 1);
+ * }
+ *
+ * barrier();
+ * } while (pc->lock != seq);
+ *
+ * NOTE: for obvious reason this only works on self-monitoring
+ * processes.
+ */
+ __u32 lock; /* seqlock for synchronization */
+ __u32 index; /* hardware event identifier */
+ __s64 offset; /* add to hardware event value */
+ __u64 time_enabled; /* time event active */
+ __u64 time_running; /* time event on cpu */
+ union {
+ __u64 capabilities;
+ struct {
+ __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
+ cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */
+
+ cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */
+ cap_user_time : 1, /* The time_* fields are used */
+ cap_user_time_zero : 1, /* The time_zero field is used */
+ cap_____res : 59;
+ };
+ };
+
+ /*
+ * If cap_usr_rdpmc this field provides the bit-width of the value
+ * read using the rdpmc() or equivalent instruction. This can be used
+ * to sign extend the result like:
+ *
+ * pmc <<= 64 - width;
+ * pmc >>= 64 - width; // signed shift right
+ * count += pmc;
+ */
+ __u16 pmc_width;
+
+ /*
+ * If cap_usr_time the below fields can be used to compute the time
+ * delta since time_enabled (in ns) using rdtsc or similar.
+ *
+ * u64 quot, rem;
+ * u64 delta;
+ *
+ * quot = (cyc >> time_shift);
+ * rem = cyc & ((1 << time_shift) - 1);
+ * delta = time_offset + quot * time_mult +
+ * ((rem * time_mult) >> time_shift);
+ *
+ * Where time_offset,time_mult,time_shift and cyc are read in the
+ * seqcount loop described above. This delta can then be added to
+ * enabled and possible running (if idx), improving the scaling:
+ *
+ * enabled += delta;
+ * if (idx)
+ * running += delta;
+ *
+ * quot = count / running;
+ * rem = count % running;
+ * count = quot * enabled + (rem * enabled) / running;
+ */
+ __u16 time_shift;
+ __u32 time_mult;
+ __u64 time_offset;
+ /*
+ * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
+ * from sample timestamps.
+ *
+ * time = timestamp - time_zero;
+ * quot = time / time_mult;
+ * rem = time % time_mult;
+ * cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
+ *
+ * And vice versa:
+ *
+ * quot = cyc >> time_shift;
+ * rem = cyc & ((1 << time_shift) - 1);
+ * timestamp = time_zero + quot * time_mult +
+ * ((rem * time_mult) >> time_shift);
+ */
+ __u64 time_zero;
+ __u32 size; /* Header size up to __reserved[] fields. */
+
+ /*
+ * Hole for extension of the self monitor capabilities
+ */
+
+ __u8 __reserved[118*8+4]; /* align to 1k. */
+
+ /*
+ * Control data for the mmap() data buffer.
+ *
+ * User-space reading the @data_head value should issue an smp_rmb(),
+ * after reading this value.
+ *
+ * When the mapping is PROT_WRITE the @data_tail value should be
+ * written by userspace to reflect the last read data, after issueing
+ * an smp_mb() to separate the data read from the ->data_tail store.
+ * In this case the kernel will not over-write unread data.
+ *
+ * See perf_output_put_handle() for the data ordering.
+ */
+ __u64 data_head; /* head in the data section */
+ __u64 data_tail; /* user-space written tail */
+};
+
+#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
+#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
+#define PERF_RECORD_MISC_KERNEL (1 << 0)
+#define PERF_RECORD_MISC_USER (2 << 0)
+#define PERF_RECORD_MISC_HYPERVISOR (3 << 0)
+#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0)
+#define PERF_RECORD_MISC_GUEST_USER (5 << 0)
+
+#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
+/*
+ * Indicates that the content of PERF_SAMPLE_IP points to
+ * the actual instruction that triggered the event. See also
+ * perf_event_attr::precise_ip.
+ */
+#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
+/*
+ * Reserve the last bit to indicate some extended misc field
+ */
+#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15)
+
+struct perf_event_header {
+ __u32 type;
+ __u16 misc;
+ __u16 size;
+};
+
+enum perf_event_type {
+
+ /*
+ * If perf_event_attr.sample_id_all is set then all event types will
+ * have the sample_type selected fields related to where/when
+ * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
+ * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
+ * just after the perf_event_header and the fields already present for
+ * the existing fields, i.e. at the end of the payload. That way a newer
+ * perf.data file will be supported by older perf tools, with these new
+ * optional fields being ignored.
+ *
+ * struct sample_id {
+ * { u32 pid, tid; } && PERF_SAMPLE_TID
+ * { u64 time; } && PERF_SAMPLE_TIME
+ * { u64 id; } && PERF_SAMPLE_ID
+ * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
+ * { u32 cpu, res; } && PERF_SAMPLE_CPU
+ * { u64 id; } && PERF_SAMPLE_IDENTIFIER
+ * } && perf_event_attr::sample_id_all
+ *
+ * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The
+ * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
+ * relative to header.size.
+ */
+
+ /*
+ * The MMAP events record the PROT_EXEC mappings so that we can
+ * correlate userspace IPs to code. They have the following structure:
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * char filename[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_MMAP = 1,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u64 id;
+ * u64 lost;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_LOST = 2,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * char comm[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_COMM = 3,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, ppid;
+ * u32 tid, ptid;
+ * u64 time;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_EXIT = 4,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u64 time;
+ * u64 id;
+ * u64 stream_id;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_THROTTLE = 5,
+ PERF_RECORD_UNTHROTTLE = 6,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, ppid;
+ * u32 tid, ptid;
+ * u64 time;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_FORK = 7,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, tid;
+ *
+ * struct read_format values;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_READ = 8,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ *
+ * #
+ * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
+ * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
+ * # is fixed relative to header.
+ * #
+ *
+ * { u64 id; } && PERF_SAMPLE_IDENTIFIER
+ * { u64 ip; } && PERF_SAMPLE_IP
+ * { u32 pid, tid; } && PERF_SAMPLE_TID
+ * { u64 time; } && PERF_SAMPLE_TIME
+ * { u64 addr; } && PERF_SAMPLE_ADDR
+ * { u64 id; } && PERF_SAMPLE_ID
+ * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
+ * { u32 cpu, res; } && PERF_SAMPLE_CPU
+ * { u64 period; } && PERF_SAMPLE_PERIOD
+ *
+ * { struct read_format values; } && PERF_SAMPLE_READ
+ *
+ * { u64 nr,
+ * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
+ *
+ * #
+ * # The RAW record below is opaque data wrt the ABI
+ * #
+ * # That is, the ABI doesn't make any promises wrt to
+ * # the stability of its content, it may vary depending
+ * # on event, hardware, kernel version and phase of
+ * # the moon.
+ * #
+ * # In other words, PERF_SAMPLE_RAW contents are not an ABI.
+ * #
+ *
+ * { u32 size;
+ * char data[size];}&& PERF_SAMPLE_RAW
+ *
+ * { u64 nr;
+ * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+ *
+ * { u64 abi; # enum perf_sample_regs_abi
+ * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
+ *
+ * { u64 size;
+ * char data[size];
+ * u64 dyn_size; } && PERF_SAMPLE_STACK_USER
+ *
+ * { u64 weight; } && PERF_SAMPLE_WEIGHT
+ * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
+ * };
+ */
+ PERF_RECORD_SAMPLE = 9,
+
+ /*
+ * The MMAP2 records are an augmented version of MMAP, they add
+ * maj, min, ino numbers to be used to uniquely identify each mapping
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * u32 maj;
+ * u32 min;
+ * u64 ino;
+ * u64 ino_generation;
+ * char filename[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_MMAP2 = 10,
+
+ PERF_RECORD_MAX, /* non-ABI */
+};
+
+#define PERF_MAX_STACK_DEPTH 127
+
+enum perf_callchain_context {
+ PERF_CONTEXT_HV = (__u64)-32,
+ PERF_CONTEXT_KERNEL = (__u64)-128,
+ PERF_CONTEXT_USER = (__u64)-512,
+
+ PERF_CONTEXT_GUEST = (__u64)-2048,
+ PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176,
+ PERF_CONTEXT_GUEST_USER = (__u64)-2560,
+
+ PERF_CONTEXT_MAX = (__u64)-4095,
+};
+
+#define PERF_FLAG_FD_NO_GROUP (1U << 0)
+#define PERF_FLAG_FD_OUTPUT (1U << 1)
+#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */
+
+union perf_mem_data_src {
+ __u64 val;
+ struct {
+ __u64 mem_op:5, /* type of opcode */
+ mem_lvl:14, /* memory hierarchy level */
+ mem_snoop:5, /* snoop mode */
+ mem_lock:2, /* lock instr */
+ mem_dtlb:7, /* tlb access */
+ mem_rsvd:31;
+ };
+};
+
+/* type of opcode (load/store/prefetch,code) */
+#define PERF_MEM_OP_NA 0x01 /* not available */
+#define PERF_MEM_OP_LOAD 0x02 /* load instruction */
+#define PERF_MEM_OP_STORE 0x04 /* store instruction */
+#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */
+#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */
+#define PERF_MEM_OP_SHIFT 0
+
+/* memory hierarchy (memory level, hit or miss) */
+#define PERF_MEM_LVL_NA 0x01 /* not available */
+#define PERF_MEM_LVL_HIT 0x02 /* hit level */
+#define PERF_MEM_LVL_MISS 0x04 /* miss level */
+#define PERF_MEM_LVL_L1 0x08 /* L1 */
+#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */
+#define PERF_MEM_LVL_L2 0x20 /* L2 */
+#define PERF_MEM_LVL_L3 0x40 /* L3 */
+#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */
+#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */
+#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */
+#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */
+#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */
+#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */
+#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */
+#define PERF_MEM_LVL_SHIFT 5
+
+/* snoop mode */
+#define PERF_MEM_SNOOP_NA 0x01 /* not available */
+#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */
+#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */
+#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */
+#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */
+#define PERF_MEM_SNOOP_SHIFT 19
+
+/* locked instruction */
+#define PERF_MEM_LOCK_NA 0x01 /* not available */
+#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */
+#define PERF_MEM_LOCK_SHIFT 24
+
+/* TLB access */
+#define PERF_MEM_TLB_NA 0x01 /* not available */
+#define PERF_MEM_TLB_HIT 0x02 /* hit level */
+#define PERF_MEM_TLB_MISS 0x04 /* miss level */
+#define PERF_MEM_TLB_L1 0x08 /* L1 */
+#define PERF_MEM_TLB_L2 0x10 /* L2 */
+#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/
+#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
+#define PERF_MEM_TLB_SHIFT 26
+
+#define PERF_MEM_S(a, s) \
+ (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
+
+/*
+ * single taken branch record layout:
+ *
+ * from: source instruction (may not always be a branch insn)
+ * to: branch target
+ * mispred: branch target was mispredicted
+ * predicted: branch target was predicted
+ *
+ * support for mispred, predicted is optional. In case it
+ * is not supported mispred = predicted = 0.
+ *
+ * in_tx: running in a hardware transaction
+ * abort: aborting a hardware transaction
+ */
+struct perf_branch_entry {
+ __u64 from;
+ __u64 to;
+ __u64 mispred:1, /* target mispredicted */
+ predicted:1,/* target predicted */
+ in_tx:1, /* in transaction */
+ abort:1, /* transaction abort */
+ reserved:60;
+};
+
+#endif /* _LINUX_PERF_EVENT_H */
diff --git a/daemon/main.cpp b/daemon/main.cpp
index c68a892..95e179e 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -20,8 +20,8 @@
#include <unistd.h>
#include "AnnotateListener.h"
-#include "CCNDriver.h"
#include "Child.h"
+#include "DriverSource.h"
#include "EventsXML.h"
#include "Logging.h"
#include "Monitor.h"
@@ -297,15 +297,10 @@ static bool setupFilesystem(char* module) {
}
// Load driver
- bool success = init_module(location);
- if (!success) {
- logg->logMessage("init_module failed, trying insmod");
- snprintf(command, sizeof(command), "insmod %s >/dev/null 2>&1", location);
- if (system(command) != 0) {
- logg->logMessage("Unable to load gator.ko driver with command: %s", command);
- logg->logError("Unable to load (insmod) gator.ko driver:\n >>> gator.ko must be built against the current kernel version & configuration\n >>> See dmesg for more details");
- handleException();
- }
+ if (!init_module(location)) {
+ logg->logMessage("Unable to load gator.ko driver with command: %s", command);
+ logg->logError("Unable to load (insmod) gator.ko driver:\n >>> gator.ko must be built against the current kernel version & configuration\n >>> See dmesg for more details");
+ handleException();
}
if (mountGatorFS() == -1) {
@@ -323,10 +318,7 @@ static int shutdownFilesystem() {
}
if (driverRunningAtStart == false) {
if (syscall(__NR_delete_module, "gator", O_NONBLOCK) != 0) {
- logg->logMessage("delete_module failed, trying rmmod");
- if (system("rmmod gator >/dev/null 2>&1") != 0) {
- return -1;
- }
+ return -1;
}
}
@@ -496,16 +488,13 @@ int main(int argc, char** argv) {
// e.g. it may not be the group leader when launched as 'sudo gatord'
setsid();
- // Set up global thread-safe logging
+ // Set up global thread-safe logging
logg = new Logging(hasDebugFlag(argc, argv));
// Global data class
gSessionData = new SessionData();
// Set up global utility class
util = new OlyUtility();
- // Initialize drivers
- new CCNDriver();
-
prctl(PR_SET_NAME, (unsigned long)&"gatord-main", 0, 0, 0);
pthread_mutex_init(&numSessions_mutex, NULL);
@@ -535,9 +524,11 @@ int main(int argc, char** argv) {
}
// Call before setting up the SIGCHLD handler, as system() spawns child processes
- if (!setupFilesystem(cmdline.module)) {
+ if (setupFilesystem(cmdline.module)) {
+ DriverSource::checkVersion();
+ } else {
logg->logMessage("Unable to set up gatorfs, trying perf");
- if (!gSessionData->perf.setup()) {
+ if (!gSessionData->mPerf.setup()) {
logg->logError(
"Unable to locate gator.ko driver:\n"
" >>> gator.ko should be co-located with gatord in the same directory\n"
diff --git a/daemon/notify/COPYING b/daemon/notify/COPYING
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/daemon/notify/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/daemon/notify/Makefile b/daemon/notify/Makefile
new file mode 100644
index 0000000..0d8f041
--- /dev/null
+++ b/daemon/notify/Makefile
@@ -0,0 +1,24 @@
+ifneq ($(SDKDIR),)
+
+# Find the oldest SDK Platform installed >= 16
+SDK_PLATFORM := $(shell ls -d $(SDKDIR)/platforms/android-1[6-9] $(SDKDIR)/platforms/android-[2-9][0-9] | head -1)
+# Find the newest SDK Build-tools
+SDK_BUILD_TOOLS := $(shell ls -d $(SDKDIR)/build-tools/* | tail -1)
+
+all: notify.dex
+
+notify.dex: Notify.java
+ javac -cp $(SDK_PLATFORM)/data/layoutlib.jar -source 1.6 -target 1.6 $^
+ $(SDK_BUILD_TOOLS)/dx --dex --output=$@ $(^:%.java=%.class)
+
+else
+
+all:
+ $(error Please specify SDKDIR as the location to the Android SDK)
+
+endif
+
+.PHONY: clean
+
+clean:
+ rm -f *~ *.class *.dex
diff --git a/daemon/notify/Notify.java b/daemon/notify/Notify.java
new file mode 100644
index 0000000..9702451
--- /dev/null
+++ b/daemon/notify/Notify.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) ARM Limited 2015. 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.
+ */
+
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+public class Notify {
+ public static void main(String[] args) throws RemoteException {
+ for (String service : ServiceManager.listServices()) {
+ IBinder b = ServiceManager.checkService(service);
+ if (b != null) {
+ Parcel p = null;
+ try {
+ p = Parcel.obtain();
+ b.transact(IBinder.SYSPROPS_TRANSACTION, p, null, 0);
+ } finally {
+ if (p != null) {
+ p.recycle();
+ }
+ }
+ }
+ }
+ }
+}