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