diff options
Diffstat (limited to 'tools/gator/daemon/FtraceSource.cpp')
-rw-r--r-- | tools/gator/daemon/FtraceSource.cpp | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/tools/gator/daemon/FtraceSource.cpp b/tools/gator/daemon/FtraceSource.cpp new file mode 100644 index 000000000000..521633357417 --- /dev/null +++ b/tools/gator/daemon/FtraceSource.cpp @@ -0,0 +1,158 @@ +/** + * Copyright (C) ARM Limited 2010-2014. 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 "DriverSource.h" +#include "Logging.h" +#include "SessionData.h" + +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(__FILE__, __LINE__, "sigaction failed: %s\n", strerror(errno)); + handleException(); + } + } + + if (DriverSource::readIntDriver("/sys/kernel/debug/tracing/tracing_on", &mTracingOn)) { + logg->logError(__FILE__, __LINE__, "Unable to read if ftrace is enabled"); + handleException(); + } + + if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "0") != 0) { + logg->logError(__FILE__, __LINE__, "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(__FILE__, __LINE__, "Unable truncate ftrace buffer: %s", strerror(errno)); + handleException(); + } + close(fd); + } + + if (DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "perf") != 0) { + logg->logError(__FILE__, __LINE__, "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(__FILE__, __LINE__, "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(__FILE__, __LINE__, "Unable to turn ftrace on"); + 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(__FILE__, __LINE__, "Unable read trace data: %s", strerror(errno)); + handleException(); + } + + const uint64_t currTime = getTime(); + + char *const colon = strstr(buf, ": "); + if (colon == NULL) { + logg->logError(__FILE__, __LINE__, "Unable find colon: %s", buf); + handleException(); + } + *colon = '\0'; + + char *const space = strrchr(buf, ' '); + if (space == NULL) { + logg->logError(__FILE__, __LINE__, "Unable 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(__FILE__, __LINE__, "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); + } + + } + + mBuffer.setDone(); + + DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", mTracingOn); + fclose(mFtraceFh); + DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "local"); +} + +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); + } +} |