• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/traced/probes/ftrace/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/logging.h"
29 #include "perfetto/ext/base/file_utils.h"
30 #include "perfetto/ext/base/string_splitter.h"
31 #include "perfetto/ext/base/string_utils.h"
32 #include "perfetto/ext/base/utils.h"
33 
34 namespace perfetto {
35 
36 // Reading /trace produces human readable trace output.
37 // Writing to this file clears all trace buffers for all CPUS.
38 
39 // Writing to /trace_marker file injects an event into the trace buffer.
40 
41 // Reading /tracing_on returns 1/0 if tracing is enabled/disabled.
42 // Writing 1/0 to this file enables/disables tracing.
43 // Disabling tracing with this file prevents further writes but
44 // does not clear the buffer.
45 
46 namespace {
47 
KernelLogWrite(const char * s)48 void KernelLogWrite(const char* s) {
49   PERFETTO_DCHECK(*s && s[strlen(s) - 1] == '\n');
50   if (FtraceProcfs::g_kmesg_fd != -1)
51     base::ignore_result(base::WriteAll(FtraceProcfs::g_kmesg_fd, s, strlen(s)));
52 }
53 
WriteFileInternal(const std::string & path,const std::string & str,int flags)54 bool WriteFileInternal(const std::string& path,
55                        const std::string& str,
56                        int flags) {
57   base::ScopedFile fd = base::OpenFile(path, flags);
58   if (!fd)
59     return false;
60   ssize_t written = base::WriteAll(fd.get(), str.c_str(), str.length());
61   ssize_t length = static_cast<ssize_t>(str.length());
62   // This should either fail or write fully.
63   PERFETTO_CHECK(written == length || written == -1);
64   return written == length;
65 }
66 
67 }  // namespace
68 
69 // static
70 int FtraceProcfs::g_kmesg_fd = -1;  // Set by ProbesMain() in probes.cc .
71 
72 // static
Create(const std::string & root)73 std::unique_ptr<FtraceProcfs> FtraceProcfs::Create(const std::string& root) {
74   if (!CheckRootPath(root)) {
75     return nullptr;
76   }
77   return std::unique_ptr<FtraceProcfs>(new FtraceProcfs(root));
78 }
79 
FtraceProcfs(const std::string & root)80 FtraceProcfs::FtraceProcfs(const std::string& root) : root_(root) {}
81 FtraceProcfs::~FtraceProcfs() = default;
82 
EnableEvent(const std::string & group,const std::string & name)83 bool FtraceProcfs::EnableEvent(const std::string& group,
84                                const std::string& name) {
85   std::string path = root_ + "events/" + group + "/" + name + "/enable";
86   if (WriteToFile(path, "1"))
87     return true;
88   path = root_ + "set_event";
89   return AppendToFile(path, group + ":" + name);
90 }
91 
DisableEvent(const std::string & group,const std::string & name)92 bool FtraceProcfs::DisableEvent(const std::string& group,
93                                 const std::string& name) {
94   std::string path = root_ + "events/" + group + "/" + name + "/enable";
95   if (WriteToFile(path, "0"))
96     return true;
97   path = root_ + "set_event";
98   return AppendToFile(path, "!" + group + ":" + name);
99 }
100 
DisableAllEvents()101 bool FtraceProcfs::DisableAllEvents() {
102   std::string path = root_ + "events/enable";
103   return WriteToFile(path, "0");
104 }
105 
ReadEventFormat(const std::string & group,const std::string & name) const106 std::string FtraceProcfs::ReadEventFormat(const std::string& group,
107                                           const std::string& name) const {
108   std::string path = root_ + "events/" + group + "/" + name + "/format";
109   return ReadFileIntoString(path);
110 }
111 
ReadEnabledEvents()112 std::vector<std::string> FtraceProcfs::ReadEnabledEvents() {
113   std::string path = root_ + "set_event";
114   std::string s = ReadFileIntoString(path);
115   base::StringSplitter ss(s, '\n');
116   std::vector<std::string> events;
117   while (ss.Next()) {
118     std::string event = ss.cur_token();
119     if (event.size() == 0)
120       continue;
121     events.push_back(base::StripChars(event, ":", '/'));
122   }
123   return events;
124 }
125 
ReadPageHeaderFormat() const126 std::string FtraceProcfs::ReadPageHeaderFormat() const {
127   std::string path = root_ + "events/header_page";
128   return ReadFileIntoString(path);
129 }
130 
ReadCpuStats(size_t cpu) const131 std::string FtraceProcfs::ReadCpuStats(size_t cpu) const {
132   std::string path = root_ + "per_cpu/cpu" + std::to_string(cpu) + "/stats";
133   return ReadFileIntoString(path);
134 }
135 
NumberOfCpus() const136 size_t FtraceProcfs::NumberOfCpus() const {
137   static size_t num_cpus = static_cast<size_t>(sysconf(_SC_NPROCESSORS_CONF));
138   return num_cpus;
139 }
140 
ClearTrace()141 void FtraceProcfs::ClearTrace() {
142   std::string path = root_ + "trace";
143   PERFETTO_CHECK(ClearFile(path));  // Could not clear.
144 
145   // Truncating the trace file leads to tracing_reset_online_cpus being called
146   // in the kernel.
147   //
148   // In case some of the CPUs were not online, their buffer needs to be
149   // cleared manually.
150   //
151   // We cannot use PERFETTO_CHECK as we might get a permission denied error
152   // on Android. The permissions to these files are configured in
153   // platform/framework/native/cmds/atrace/atrace.rc.
154   for (size_t cpu = 0; cpu < NumberOfCpus(); cpu++) {
155     if (!ClearFile(root_ + "per_cpu/cpu" + std::to_string(cpu) + "/trace"))
156       PERFETTO_ELOG("Failed to clear buffer for CPU %zd", cpu);
157   }
158 }
159 
WriteTraceMarker(const std::string & str)160 bool FtraceProcfs::WriteTraceMarker(const std::string& str) {
161   std::string path = root_ + "trace_marker";
162   return WriteToFile(path, str);
163 }
164 
SetCpuBufferSizeInPages(size_t pages)165 bool FtraceProcfs::SetCpuBufferSizeInPages(size_t pages) {
166   if (pages * base::kPageSize > 1 * 1024 * 1024 * 1024) {
167     PERFETTO_ELOG("Tried to set the per CPU buffer size to more than 1gb.");
168     return false;
169   }
170   std::string path = root_ + "buffer_size_kb";
171   return WriteNumberToFile(path, pages * (base::kPageSize / 1024ul));
172 }
173 
EnableTracing()174 bool FtraceProcfs::EnableTracing() {
175   KernelLogWrite("perfetto: enabled ftrace\n");
176   PERFETTO_LOG("enabled ftrace");
177   std::string path = root_ + "tracing_on";
178   return WriteToFile(path, "1");
179 }
180 
DisableTracing()181 bool FtraceProcfs::DisableTracing() {
182   KernelLogWrite("perfetto: disabled ftrace\n");
183   PERFETTO_LOG("disabled ftrace");
184   std::string path = root_ + "tracing_on";
185   return WriteToFile(path, "0");
186 }
187 
SetTracingOn(bool enable)188 bool FtraceProcfs::SetTracingOn(bool enable) {
189   return enable ? EnableTracing() : DisableTracing();
190 }
191 
IsTracingEnabled()192 bool FtraceProcfs::IsTracingEnabled() {
193   std::string path = root_ + "tracing_on";
194   char tracing_on = ReadOneCharFromFile(path);
195   if (tracing_on == '\0')
196     PERFETTO_PLOG("Failed to read %s", path.c_str());
197   return tracing_on == '1';
198 }
199 
SetClock(const std::string & clock_name)200 bool FtraceProcfs::SetClock(const std::string& clock_name) {
201   std::string path = root_ + "trace_clock";
202   return WriteToFile(path, clock_name);
203 }
204 
GetClock()205 std::string FtraceProcfs::GetClock() {
206   std::string path = root_ + "trace_clock";
207   std::string s = ReadFileIntoString(path);
208 
209   size_t start = s.find('[');
210   if (start == std::string::npos)
211     return "";
212 
213   size_t end = s.find(']', start);
214   if (end == std::string::npos)
215     return "";
216 
217   return s.substr(start + 1, end - start - 1);
218 }
219 
AvailableClocks()220 std::set<std::string> FtraceProcfs::AvailableClocks() {
221   std::string path = root_ + "trace_clock";
222   std::string s = ReadFileIntoString(path);
223   std::set<std::string> names;
224 
225   size_t start = 0;
226   size_t end = 0;
227 
228   for (;;) {
229     end = s.find(' ', start);
230     if (end == std::string::npos)
231       end = s.size();
232     while (end > start && s[end - 1] == '\n')
233       end--;
234     if (start == end)
235       break;
236 
237     std::string name = s.substr(start, end - start);
238 
239     if (name[0] == '[')
240       name = name.substr(1, name.size() - 2);
241 
242     names.insert(name);
243 
244     if (end == s.size())
245       break;
246 
247     start = end + 1;
248   }
249 
250   return names;
251 }
252 
WriteNumberToFile(const std::string & path,size_t value)253 bool FtraceProcfs::WriteNumberToFile(const std::string& path, size_t value) {
254   // 2^65 requires 20 digits to write.
255   char buf[21];
256   int res = snprintf(buf, 21, "%zu", value);
257   if (res < 0 || res >= 21)
258     return false;
259   return WriteToFile(path, std::string(buf));
260 }
261 
WriteToFile(const std::string & path,const std::string & str)262 bool FtraceProcfs::WriteToFile(const std::string& path,
263                                const std::string& str) {
264   return WriteFileInternal(path, str, O_WRONLY);
265 }
266 
AppendToFile(const std::string & path,const std::string & str)267 bool FtraceProcfs::AppendToFile(const std::string& path,
268                                 const std::string& str) {
269   return WriteFileInternal(path, str, O_WRONLY | O_APPEND);
270 }
271 
OpenPipeForCpu(size_t cpu)272 base::ScopedFile FtraceProcfs::OpenPipeForCpu(size_t cpu) {
273   std::string path =
274       root_ + "per_cpu/cpu" + std::to_string(cpu) + "/trace_pipe_raw";
275   return base::OpenFile(path, O_RDONLY | O_NONBLOCK);
276 }
277 
ReadOneCharFromFile(const std::string & path)278 char FtraceProcfs::ReadOneCharFromFile(const std::string& path) {
279   base::ScopedFile fd = base::OpenFile(path, O_RDONLY);
280   PERFETTO_CHECK(fd);
281   char result = '\0';
282   ssize_t bytes = PERFETTO_EINTR(read(fd.get(), &result, 1));
283   PERFETTO_CHECK(bytes == 1 || bytes == -1);
284   return result;
285 }
286 
ClearFile(const std::string & path)287 bool FtraceProcfs::ClearFile(const std::string& path) {
288   base::ScopedFile fd = base::OpenFile(path, O_WRONLY | O_TRUNC);
289   return !!fd;
290 }
291 
ReadFileIntoString(const std::string & path) const292 std::string FtraceProcfs::ReadFileIntoString(const std::string& path) const {
293   // You can't seek or stat the procfs files on Android.
294   // The vast majority (884/886) of format files are under 4k.
295   std::string str;
296   str.reserve(4096);
297   if (!base::ReadFile(path, &str))
298     return "";
299   return str;
300 }
301 
GetEventNamesForGroup(const std::string & path) const302 const std::set<std::string> FtraceProcfs::GetEventNamesForGroup(
303     const std::string& path) const {
304   std::set<std::string> names;
305   std::string full_path = root_ + path;
306   base::ScopedDir dir(opendir(full_path.c_str()));
307   if (!dir) {
308     PERFETTO_DLOG("Unable to read events from %s", full_path.c_str());
309     return names;
310   }
311   struct dirent* ent;
312   while ((ent = readdir(*dir)) != nullptr) {
313     if (strncmp(ent->d_name, ".", 1) == 0 ||
314         strncmp(ent->d_name, "..", 2) == 0) {
315       continue;
316     }
317     // Check ent is a directory.
318     struct stat statbuf;
319     std::string dir_path = full_path + "/" + ent->d_name;
320     if (stat(dir_path.c_str(), &statbuf) == 0) {
321       if (S_ISDIR(statbuf.st_mode)) {
322         names.insert(ent->d_name);
323       }
324     }
325   }
326   return names;
327 }
328 
329 // static
CheckRootPath(const std::string & root)330 bool FtraceProcfs::CheckRootPath(const std::string& root) {
331   base::ScopedFile fd = base::OpenFile(root + "trace", O_RDONLY);
332   return static_cast<bool>(fd);
333 }
334 
335 }  // namespace perfetto
336