1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/ftrace_reader/ftrace_procfs.h"
18
19 #include <string.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include <fstream>
25 #include <sstream>
26 #include <string>
27
28 #include "perfetto/base/file_utils.h"
29 #include "perfetto/base/logging.h"
30 #include "perfetto/base/utils.h"
31
32 namespace perfetto {
33
34 // Reading /trace produces human readable trace output.
35 // Writing to this file clears all trace buffers for all CPUS.
36
37 // Writing to /trace_marker file injects an event into the trace buffer.
38
39 // Reading /tracing_on returns 1/0 if tracing is enabled/disabled.
40 // Writing 1/0 to this file enables/disables tracing.
41 // Disabling tracing with this file prevents further writes but
42 // does not clear the buffer.
43
44 namespace {
45
KernelLogWrite(const char * s)46 void KernelLogWrite(const char* s) {
47 PERFETTO_DCHECK(*s && s[strlen(s) - 1] == '\n');
48 if (FtraceProcfs::g_kmesg_fd != -1)
49 base::ignore_result(write(FtraceProcfs::g_kmesg_fd, s, strlen(s)));
50 }
51
52 } // namespace
53
54 // static
55 int FtraceProcfs::g_kmesg_fd = -1; // Set by ProbesMain() in probes.cc .
56
57 // static
Create(const std::string & root)58 std::unique_ptr<FtraceProcfs> FtraceProcfs::Create(const std::string& root) {
59 if (!CheckRootPath(root)) {
60 return nullptr;
61 }
62 return std::unique_ptr<FtraceProcfs>(new FtraceProcfs(root));
63 }
64
FtraceProcfs(const std::string & root)65 FtraceProcfs::FtraceProcfs(const std::string& root) : root_(root) {}
66 FtraceProcfs::~FtraceProcfs() = default;
67
EnableEvent(const std::string & group,const std::string & name)68 bool FtraceProcfs::EnableEvent(const std::string& group,
69 const std::string& name) {
70 std::string path = root_ + "events/" + group + "/" + name + "/enable";
71 return WriteToFile(path, "1");
72 }
73
DisableEvent(const std::string & group,const std::string & name)74 bool FtraceProcfs::DisableEvent(const std::string& group,
75 const std::string& name) {
76 std::string path = root_ + "events/" + group + "/" + name + "/enable";
77 return WriteToFile(path, "0");
78 }
79
DisableAllEvents()80 bool FtraceProcfs::DisableAllEvents() {
81 std::string path = root_ + "events/enable";
82 return WriteToFile(path, "0");
83 }
84
ReadEventFormat(const std::string & group,const std::string & name) const85 std::string FtraceProcfs::ReadEventFormat(const std::string& group,
86 const std::string& name) const {
87 std::string path = root_ + "events/" + group + "/" + name + "/format";
88 return ReadFileIntoString(path);
89 }
90
ReadCpuStats(size_t cpu) const91 std::string FtraceProcfs::ReadCpuStats(size_t cpu) const {
92 std::string path = root_ + "per_cpu/cpu" + std::to_string(cpu) + "/stats";
93 return ReadFileIntoString(path);
94 }
95
NumberOfCpus() const96 size_t FtraceProcfs::NumberOfCpus() const {
97 static size_t num_cpus = static_cast<size_t>(sysconf(_SC_NPROCESSORS_CONF));
98 return num_cpus;
99 }
100
ClearTrace()101 void FtraceProcfs::ClearTrace() {
102 std::string path = root_ + "trace";
103 PERFETTO_CHECK(ClearFile(path)); // Could not clear.
104 }
105
WriteTraceMarker(const std::string & str)106 bool FtraceProcfs::WriteTraceMarker(const std::string& str) {
107 std::string path = root_ + "trace_marker";
108 return WriteToFile(path, str);
109 }
110
SetCpuBufferSizeInPages(size_t pages)111 bool FtraceProcfs::SetCpuBufferSizeInPages(size_t pages) {
112 if (pages * base::kPageSize > 1 * 1024 * 1024 * 1024) {
113 PERFETTO_ELOG("Tried to set the per CPU buffer size to more than 1gb.");
114 return false;
115 }
116 std::string path = root_ + "buffer_size_kb";
117 return WriteNumberToFile(path, pages * (base::kPageSize / 1024ul));
118 }
119
EnableTracing()120 bool FtraceProcfs::EnableTracing() {
121 KernelLogWrite("perfetto: enabled ftrace\n");
122 std::string path = root_ + "tracing_on";
123 return WriteToFile(path, "1");
124 }
125
DisableTracing()126 bool FtraceProcfs::DisableTracing() {
127 KernelLogWrite("perfetto: disabled ftrace\n");
128 std::string path = root_ + "tracing_on";
129 return WriteToFile(path, "0");
130 }
131
SetTracingOn(bool enable)132 bool FtraceProcfs::SetTracingOn(bool enable) {
133 return enable ? EnableTracing() : DisableTracing();
134 }
135
IsTracingEnabled()136 bool FtraceProcfs::IsTracingEnabled() {
137 std::string path = root_ + "tracing_on";
138 return ReadOneCharFromFile(path) == '1';
139 }
140
SetClock(const std::string & clock_name)141 bool FtraceProcfs::SetClock(const std::string& clock_name) {
142 std::string path = root_ + "trace_clock";
143 return WriteToFile(path, clock_name);
144 }
145
GetClock()146 std::string FtraceProcfs::GetClock() {
147 std::string path = root_ + "trace_clock";
148 std::string s = ReadFileIntoString(path);
149
150 size_t start = s.find('[');
151 if (start == std::string::npos)
152 return "";
153
154 size_t end = s.find(']', start);
155 if (end == std::string::npos)
156 return "";
157
158 return s.substr(start + 1, end - start - 1);
159 }
160
AvailableClocks()161 std::set<std::string> FtraceProcfs::AvailableClocks() {
162 std::string path = root_ + "trace_clock";
163 std::string s = ReadFileIntoString(path);
164 std::set<std::string> names;
165
166 size_t start = 0;
167 size_t end = 0;
168
169 while (true) {
170 end = s.find(' ', start);
171 if (end == std::string::npos)
172 end = s.size();
173 if (start == end)
174 break;
175
176 std::string name = s.substr(start, end - start);
177
178 if (name[0] == '[')
179 name = name.substr(1, name.size() - 2);
180
181 names.insert(name);
182
183 if (end == s.size())
184 break;
185
186 start = end + 1;
187 }
188
189 return names;
190 }
191
WriteNumberToFile(const std::string & path,size_t value)192 bool FtraceProcfs::WriteNumberToFile(const std::string& path, size_t value) {
193 // 2^65 requires 20 digits to write.
194 char buf[21];
195 int res = snprintf(buf, 21, "%zu", value);
196 if (res < 0 || res >= 21)
197 return false;
198 return WriteToFile(path, std::string(buf));
199 }
200
WriteToFile(const std::string & path,const std::string & str)201 bool FtraceProcfs::WriteToFile(const std::string& path,
202 const std::string& str) {
203 base::ScopedFile fd = base::OpenFile(path, O_WRONLY);
204 if (!fd)
205 return false;
206 ssize_t written = PERFETTO_EINTR(write(fd.get(), str.c_str(), str.length()));
207 ssize_t length = static_cast<ssize_t>(str.length());
208 // This should either fail or write fully.
209 PERFETTO_CHECK(written == length || written == -1);
210 return written == length;
211 }
212
OpenPipeForCpu(size_t cpu)213 base::ScopedFile FtraceProcfs::OpenPipeForCpu(size_t cpu) {
214 std::string path =
215 root_ + "per_cpu/cpu" + std::to_string(cpu) + "/trace_pipe_raw";
216 return base::OpenFile(path, O_RDONLY | O_NONBLOCK);
217 }
218
ReadOneCharFromFile(const std::string & path)219 char FtraceProcfs::ReadOneCharFromFile(const std::string& path) {
220 base::ScopedFile fd = base::OpenFile(path, O_RDONLY);
221 PERFETTO_CHECK(fd);
222 char result = '\0';
223 ssize_t bytes = PERFETTO_EINTR(read(fd.get(), &result, 1));
224 PERFETTO_CHECK(bytes == 1 || bytes == -1);
225 return result;
226 }
227
ClearFile(const std::string & path)228 bool FtraceProcfs::ClearFile(const std::string& path) {
229 base::ScopedFile fd = base::OpenFile(path, O_WRONLY | O_TRUNC);
230 return !!fd;
231 }
232
ReadFileIntoString(const std::string & path) const233 std::string FtraceProcfs::ReadFileIntoString(const std::string& path) const {
234 // You can't seek or stat the procfs files on Android.
235 // The vast majority (884/886) of format files are under 4k.
236 std::string str;
237 str.reserve(4096);
238 if (!base::ReadFile(path, &str))
239 return "";
240 return str;
241 }
242
243 // static
CheckRootPath(const std::string & root)244 bool FtraceProcfs::CheckRootPath(const std::string& root) {
245 base::ScopedFile fd = base::OpenFile(root + "trace", O_RDONLY);
246 return static_cast<bool>(fd);
247 }
248
249 } // namespace perfetto
250