gator: Version 5.21.1
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / FtraceSource.cpp
1 /**
2  * Copyright (C) ARM Limited 2010-2015. All rights reserved.
3  *
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
17 #include "Child.h"
18 #include "DriverSource.h"
19 #include "Logging.h"
20 #include "SessionData.h"
21
22 extern Child *child;
23
24 static void handler(int signum)
25 {
26         (void)signum;
27 };
28
29 FtraceSource::FtraceSource(sem_t *senderSem) : mFtraceFh(NULL), mBuffer(0, FRAME_BLOCK_COUNTER, 128*1024, senderSem), mTid(-1), mTracingOn(0) {
30 }
31
32 FtraceSource::~FtraceSource() {
33 }
34
35 bool 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) {
41                         logg->logError("sigaction failed: %s\n", strerror(errno));
42                         handleException();
43                 }
44         }
45
46         gSessionData->ftraceDriver.prepare();
47
48         if (DriverSource::readIntDriver("/sys/kernel/debug/tracing/tracing_on", &mTracingOn)) {
49                 logg->logError("Unable to read if ftrace is enabled");
50                 handleException();
51         }
52
53         if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "0") != 0) {
54                 logg->logError("Unable to turn ftrace off before truncating the buffer");
55                 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) {
62                         logg->logError("Unable truncate ftrace buffer: %s", strerror(errno));
63                         handleException();
64                 }
65                 close(fd);
66         }
67
68         if (DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "perf") != 0) {
69                 logg->logError("Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
70                 handleException();
71         }
72
73         mFtraceFh = fopen_cloexec("/sys/kernel/debug/tracing/trace_pipe", "rb");
74         if (mFtraceFh == NULL) {
75                 logg->logError("Unable to open trace_pipe");
76                 handleException();
77         }
78
79         return true;
80 }
81
82 void 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) {
87                 logg->logError("Unable to turn ftrace on");
88                 handleException();
89         }
90
91         // 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
106         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                         }
114                         logg->logError("Unable read trace data: %s", strerror(errno));
115                         handleException();
116                 }
117
118                 const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted;
119
120                 char *const colon = strstr(buf, ": ");
121                 if (colon == NULL) {
122                         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                         }
127                         handleException();
128                 }
129                 *colon = '\0';
130
131                 char *const space = strrchr(buf, ' ');
132                 if (space == NULL) {
133                         logg->logError("Unable to find space: %s", buf);
134                         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) {
144                                 logg->logError("Unable to parse time: %s", strerror(errno));
145                                 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);
154
155                         if (gSessionData->mOneShot && gSessionData->mSessionIsActive && (mBuffer.bytesAvailable() <= 0)) {
156                                 logg->logMessage("One shot (ftrace)");
157                                 child->endSession();
158                         }
159                 }
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");
168         gSessionData->ftraceDriver.stop();
169 }
170
171 void 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
176 bool FtraceSource::isDone() {
177         return mBuffer.isDone();
178 }
179
180 void 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 }