aboutsummaryrefslogtreecommitdiff
path: root/daemon/FtraceDriver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/FtraceDriver.cpp')
-rw-r--r--daemon/FtraceDriver.cpp115
1 files changed, 58 insertions, 57 deletions
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;