• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 <signal.h>
18 
19 #include "perfetto/ext/base/file_utils.h"
20 #include "perfetto/ext/base/string_splitter.h"
21 #include "perfetto/ext/base/string_utils.h"
22 #include "perfetto/ext/base/string_writer.h"
23 #include "perfetto/ext/base/unix_task_runner.h"
24 #include "perfetto/ext/base/utils.h"
25 
26 namespace perfetto {
27 namespace {
28 
29 // This dumps the ftrace stats into trace marker every 500ms. This is useful for
30 // debugging overruns over time.
31 
32 base::UnixTaskRunner* g_task_runner = nullptr;
33 
ExtractInt(const char * s)34 uint32_t ExtractInt(const char* s) {
35   for (; *s != '\0'; s++) {
36     if (*s == ':') {
37       return static_cast<uint32_t>(atoi(s + 1));
38     }
39   }
40   return 0;
41 }
42 
NumberOfCpus()43 size_t NumberOfCpus() {
44   static size_t num_cpus = static_cast<size_t>(sysconf(_SC_NPROCESSORS_CONF));
45   return num_cpus;
46 }
47 
ReadFileIntoString(const std::string & path)48 std::string ReadFileIntoString(const std::string& path) {
49   // You can't seek or stat the procfs files on Android.
50   // The vast majority (884/886) of format files are under 4k.
51   std::string str;
52   str.reserve(4096);
53   if (!base::ReadFile(path, &str))
54     return "";
55   return str;
56 }
57 
ReadCpuStats(size_t cpu)58 std::string ReadCpuStats(size_t cpu) {
59   std::string path =
60       "/sys/kernel/debug/tracing/per_cpu/cpu" + std::to_string(cpu) + "/stats";
61   return ReadFileIntoString(path);
62 }
63 
DumpAllCpuStats()64 void DumpAllCpuStats() {
65   base::ScopedFile file(
66       base::OpenFile("/sys/kernel/debug/tracing/trace_marker", O_RDWR));
67   if (!file) {
68     PERFETTO_ELOG("Unable to open trace marker file");
69     g_task_runner->PostDelayedTask(&DumpAllCpuStats, 500);
70     return;
71   }
72 
73   for (uint32_t cpu = 0; cpu < NumberOfCpus(); cpu++) {
74     std::string text = ReadCpuStats(cpu);
75     if (text.empty())
76       continue;
77 
78     char buffer[1024];
79     base::StringSplitter splitter(std::move(text), '\n');
80     while (splitter.Next()) {
81       base::StringWriter writer(buffer, base::ArraySize(buffer));
82       writer.AppendLiteral("C|");
83       writer.AppendInt(getpid());
84       writer.AppendLiteral("|");
85 
86       if (base::StartsWith(splitter.cur_token(), "overrun")) {
87         writer.AppendLiteral("overrun_");
88       } else if (base::StartsWith(splitter.cur_token(), "commit overrun")) {
89         writer.AppendLiteral("commit_overrun_");
90       } else {
91         continue;
92       }
93       writer.AppendInt(cpu);
94       writer.AppendLiteral("|");
95       writer.AppendInt(ExtractInt(splitter.cur_token()));
96       writer.AppendLiteral("\n");
97 
98       auto output = writer.GetStringView();
99       PERFETTO_CHECK(write(*file, output.data(), output.size()) ==
100                      static_cast<ssize_t>(output.size()));
101     }
102   }
103   g_task_runner->PostDelayedTask(&DumpAllCpuStats, 500);
104 }
105 
SetupCtrlCHandler()106 void SetupCtrlCHandler() {
107   // Setup signal handler.
108   struct sigaction sa {};
109 
110 // Glibc headers for sa_sigaction trigger this.
111 #pragma GCC diagnostic push
112 #if defined(__clang__)
113 #pragma GCC diagnostic ignored "-Wdisabled-macro-expansion"
114 #endif
115   sa.sa_handler = [](int) { g_task_runner->Quit(); };
116   sa.sa_flags = static_cast<decltype(sa.sa_flags)>(SA_RESETHAND | SA_RESTART);
117 #pragma GCC diagnostic pop
118   sigaction(SIGINT, &sa, nullptr);
119   sigaction(SIGTERM, &sa, nullptr);
120 }
121 
DumpFtraceStatsMain()122 int DumpFtraceStatsMain() {
123   base::UnixTaskRunner task_runner;
124   g_task_runner = &task_runner;
125   SetupCtrlCHandler();
126   task_runner.PostTask(&DumpAllCpuStats);
127   task_runner.Run();
128   return 0;
129 }
130 
131 }  // namespace
132 }  // namespace perfetto
133 
main(int argc,char ** argv)134 int main(int argc, char** argv) {
135   perfetto::base::ignore_result(argc, argv);
136   return perfetto::DumpFtraceStatsMain();
137 }
138