blob: 14a48b3b870cf54d906ff1ea9029cf406d708bac [file] [log] [blame]
Jon Medhurst96b56152014-10-30 18:01:15 +00001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2010-2015. All rights reserved.
Jon Medhurst96b56152014-10-30 18:01:15 +00003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "FtraceSource.h"
10
11#include <fcntl.h>
12#include <signal.h>
13#include <sys/prctl.h>
14#include <sys/syscall.h>
15#include <unistd.h>
16
Jon Medhurstb1d07442015-05-08 12:04:18 +010017#include "Child.h"
Jon Medhurst96b56152014-10-30 18:01:15 +000018#include "DriverSource.h"
19#include "Logging.h"
20#include "SessionData.h"
21
Jon Medhurstb1d07442015-05-08 12:04:18 +010022extern Child *child;
23
Jon Medhurst96b56152014-10-30 18:01:15 +000024static void handler(int signum)
25{
26 (void)signum;
27};
28
29FtraceSource::FtraceSource(sem_t *senderSem) : mFtraceFh(NULL), mBuffer(0, FRAME_BLOCK_COUNTER, 128*1024, senderSem), mTid(-1), mTracingOn(0) {
30}
31
32FtraceSource::~FtraceSource() {
33}
34
35bool FtraceSource::prepare() {
36 {
37 struct sigaction act;
38 act.sa_handler = handler;
39 act.sa_flags = (int)SA_RESETHAND;
40 if (sigaction(SIGUSR1, &act, NULL) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010041 logg->logError("sigaction failed: %s\n", strerror(errno));
Jon Medhurst96b56152014-10-30 18:01:15 +000042 handleException();
43 }
44 }
45
Jon Medhurstb1d07442015-05-08 12:04:18 +010046 gSessionData->ftraceDriver.prepare();
47
Jon Medhurst96b56152014-10-30 18:01:15 +000048 if (DriverSource::readIntDriver("/sys/kernel/debug/tracing/tracing_on", &mTracingOn)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010049 logg->logError("Unable to read if ftrace is enabled");
Jon Medhurst96b56152014-10-30 18:01:15 +000050 handleException();
51 }
52
53 if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "0") != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010054 logg->logError("Unable to turn ftrace off before truncating the buffer");
Jon Medhurst96b56152014-10-30 18:01:15 +000055 handleException();
56 }
57
58 {
59 int fd;
60 fd = open("/sys/kernel/debug/tracing/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
61 if (fd < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010062 logg->logError("Unable truncate ftrace buffer: %s", strerror(errno));
Jon Medhurst96b56152014-10-30 18:01:15 +000063 handleException();
64 }
65 close(fd);
66 }
67
68 if (DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "perf") != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010069 logg->logError("Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
Jon Medhurst96b56152014-10-30 18:01:15 +000070 handleException();
71 }
72
73 mFtraceFh = fopen_cloexec("/sys/kernel/debug/tracing/trace_pipe", "rb");
74 if (mFtraceFh == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010075 logg->logError("Unable to open trace_pipe");
Jon Medhurst96b56152014-10-30 18:01:15 +000076 handleException();
77 }
78
79 return true;
80}
81
82void FtraceSource::run() {
83 prctl(PR_SET_NAME, (unsigned long)&"gatord-ftrace", 0, 0, 0);
84 mTid = syscall(__NR_gettid);
85
86 if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "1") != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010087 logg->logError("Unable to turn ftrace on");
Jon Medhurst96b56152014-10-30 18:01:15 +000088 handleException();
89 }
90
Jon Medhurstb1d07442015-05-08 12:04:18 +010091 // Wait until monotonicStarted is set before sending data
92 int64_t monotonicStarted = 0;
93 while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
94 usleep(10);
95
96 if (gSessionData->perf.isSetup()) {
97 monotonicStarted = gSessionData->mMonotonicStarted;
98 } else {
99 if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
100 logg->logError("Error reading gator driver start time");
101 handleException();
102 }
103 }
104 }
105
Jon Medhurst96b56152014-10-30 18:01:15 +0000106 while (gSessionData->mSessionIsActive) {
107 char buf[1<<12];
108
109 if (fgets(buf, sizeof(buf), mFtraceFh) == NULL) {
110 if (errno == EINTR) {
111 // Interrupted by interrupt - likely user request to terminate
112 break;
113 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100114 logg->logError("Unable read trace data: %s", strerror(errno));
Jon Medhurst96b56152014-10-30 18:01:15 +0000115 handleException();
116 }
117
Jon Medhurstb1d07442015-05-08 12:04:18 +0100118 const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted;
Jon Medhurst96b56152014-10-30 18:01:15 +0000119
120 char *const colon = strstr(buf, ": ");
121 if (colon == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100122 if (strstr(buf, " [LOST ") != NULL) {
123 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.");
124 } else {
125 logg->logError("Unable to find colon: %s", buf);
126 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000127 handleException();
128 }
129 *colon = '\0';
130
131 char *const space = strrchr(buf, ' ');
132 if (space == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100133 logg->logError("Unable to find space: %s", buf);
Jon Medhurst96b56152014-10-30 18:01:15 +0000134 handleException();
135 }
136 *colon = ':';
137
138 int64_t *data = NULL;
139 int count = gSessionData->ftraceDriver.read(colon + 2, &data);
140 if (count > 0) {
141 errno = 0;
142 const long long time = strtod(space, NULL) * 1000000000;
143 if (errno != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100144 logg->logError("Unable to parse time: %s", strerror(errno));
Jon Medhurst96b56152014-10-30 18:01:15 +0000145 handleException();
146 }
147 mBuffer.event64(-1, time);
148
149 for (int i = 0; i < count; ++i) {
150 mBuffer.event64(data[2*i + 0], data[2*i + 1]);
151 }
152
153 mBuffer.check(currTime);
Jon Medhurstb1d07442015-05-08 12:04:18 +0100154
155 if (gSessionData->mOneShot && gSessionData->mSessionIsActive && (mBuffer.bytesAvailable() <= 0)) {
156 logg->logMessage("One shot (ftrace)");
157 child->endSession();
158 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000159 }
160
161 }
162
163 mBuffer.setDone();
164
165 DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", mTracingOn);
166 fclose(mFtraceFh);
167 DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "local");
Jon Medhurstb1d07442015-05-08 12:04:18 +0100168 gSessionData->ftraceDriver.stop();
Jon Medhurst96b56152014-10-30 18:01:15 +0000169}
170
171void FtraceSource::interrupt() {
172 // 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
173 syscall(__NR_tgkill, getpid(), mTid, SIGUSR1);
174}
175
176bool FtraceSource::isDone() {
177 return mBuffer.isDone();
178}
179
180void FtraceSource::write(Sender *sender) {
181 // Don't send ftrace data until the summary packet is sent so that monotonic delta is available
182 if (!gSessionData->mSentSummary) {
183 return;
184 }
185 if (!mBuffer.isDone()) {
186 mBuffer.write(sender);
187 }
188}