• 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/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