diff options
Diffstat (limited to 'daemon/FtraceDriver.cpp')
-rw-r--r-- | daemon/FtraceDriver.cpp | 115 |
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; |