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