159 lines
4.2 KiB
C++
159 lines
4.2 KiB
C++
/**
|
|
* 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);
|
|
}
|
|
}
|