Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "atrace_process_dump.h" | |
| 6 | |
| 7 #include <sys/time.h> | |
| 8 #include <sys/timerfd.h> | |
| 9 #include <stdint.h> | |
| 10 | |
| 11 #include <memory> | |
| 12 #include <sstream> | |
| 13 | |
| 14 #include "logging.h" | |
| 15 | |
| 16 void AtraceProcessDump::SetFullDumpConfig(const std::string& config) { | |
| 17 self_pid_ = (int) getpid(); | |
|
Primiano Tucci (use gerrit)
2017/06/26 10:07:19
static_cast<int>(getpid()). c-style cast are not a
| |
| 18 if (config == "all") { | |
| 19 full_dump_all_ = true; | |
| 20 } else if (config == "apps") { | |
| 21 full_dump_apps_ = true; | |
| 22 } else { | |
| 23 full_dump_whitelist_.clear(); | |
| 24 std::istringstream ss(config); | |
| 25 std::string entry; | |
| 26 while (std::getline(ss, entry, ',')) { | |
| 27 full_dump_whitelist_.insert(entry); | |
| 28 } | |
| 29 } | |
| 30 } | |
| 31 | |
| 32 void AtraceProcessDump::SerializeSnapshot( | |
| 33 const InstantProcessInfo* snapshot, const std::set<int>& smaps_pids) { | |
| 34 | |
| 35 fprintf(out_, "{\"ts\":\"%llu\",\"memdump\":{\n", snapshot->timestamp()); | |
| 36 const InstantProcessInfo::ProcessSnapshotMap* processes = | |
| 37 snapshot->processes(); | |
| 38 for (auto pit = processes->begin(); pit != processes->end();) { | |
|
Primiano Tucci (use gerrit)
2017/06/26 10:07:20
I thought this was a typo (pit -> pid) but then re
| |
| 39 const InstantProcessInfo::ProcessSnapshot* process = pit->second.get(); | |
| 40 const ProcessMemoryStats* mem = &process->memory; | |
| 41 fprintf(out_, "\"%d\":{", process->pid); | |
| 42 | |
| 43 fprintf(out_, "\"vm\":%llu,\"rss\":%llu", | |
| 44 mem->virt_kb(), mem->rss_kb()); | |
| 45 | |
| 46 fprintf(out_, ",\"oom_sc\":%d,\"oom_sc_adj\":%d" | |
| 47 ",\"min_flt\":%lu,\"maj_flt\":%lu" | |
| 48 ",\"utime\":%lu,\"stime\":%lu", | |
| 49 process->oom_score, process->oom_score_adj, | |
| 50 process->minor_faults, process->major_faults, | |
| 51 process->utime, process->stime); | |
| 52 | |
| 53 if (mem->full_stats_available()) { | |
| 54 fprintf(out_, ",\"pss\":%llu,\"swp\":%llu" | |
| 55 ",\"pc\":%llu,\"pd\":%llu,\"sc\":%llu,\"sd\":%llu", | |
| 56 mem->pss_kb(), mem->swapped_kb(), | |
| 57 mem->private_clean_kb(), mem->private_dirty_kb(), | |
| 58 mem->shared_clean_kb(), mem->shared_dirty_kb()); | |
| 59 } | |
| 60 | |
| 61 if (mem->gpu_stats_available()) { | |
| 62 fprintf(out_, ",\"gpu_egl\":%llu,\"gpu_egl_pss\":%llu" | |
| 63 ",\"gpu_gl\":%llu,\"gpu_gl_pss\":%llu" | |
| 64 ",\"gpu_etc\":%llu,\"gpu_etc_pss\":%llu", | |
| 65 mem->gpu_graphics_kb(), mem->gpu_graphics_pss_kb(), | |
| 66 mem->gpu_gl_kb(), mem->gpu_gl_pss_kb(), | |
| 67 mem->gpu_other_kb(), mem->gpu_other_pss_kb()); | |
| 68 } | |
| 69 | |
| 70 if (mem->full_stats_available() && smaps_pids.count(process->pid)) { | |
| 71 fprintf(out_, ", \"mmaps\":["); | |
| 72 size_t n_mmaps = mem->mmaps_count(); | |
| 73 for (size_t k = 0; k < n_mmaps; ++k) { | |
| 74 const ProcessMemoryStats::MmapInfo* mm = mem->mmap(k); | |
| 75 fprintf(out_, | |
| 76 "{\"vm\":\"%llx-%llx\",\"file\":\"%s\",\"flags\":\"%s\"," | |
| 77 "\"pss\":%llu,\"rss\":%llu,\"swp\":%llu," | |
| 78 "\"pc\":%llu,\"pd\":%llu," | |
| 79 "\"sc\":%llu,\"sd\":%llu}", | |
| 80 mm->start_addr, mm->end_addr, mm->mapped_file, mm->prot_flags, | |
| 81 mm->pss_kb, mm->rss_kb, mm->swapped_kb, | |
| 82 mm->private_clean_kb, mm->private_dirty_kb, | |
| 83 mm->shared_clean_kb, mm->shared_dirty_kb); | |
| 84 if (k < n_mmaps - 1) | |
| 85 fprintf(out_, ", "); | |
| 86 } | |
| 87 fprintf(out_, "]"); | |
| 88 } | |
| 89 | |
| 90 // TODO(kraynov): Return OOM numbers. | |
| 91 | |
| 92 ++pit; | |
| 93 if (pit != processes->end()) { | |
| 94 fprintf(out_, "},\n"); | |
| 95 } else { | |
| 96 fprintf(out_, "}}\n"); | |
| 97 } | |
| 98 } | |
| 99 fprintf(out_, "}"); | |
| 100 } | |
| 101 | |
| 102 void AtraceProcessDump::SerializeProcessInfo( | |
| 103 const PersistentProcessInfo::ProcessMap* processes) { | |
| 104 | |
| 105 fprintf(out_, "\"processes\":{"); | |
| 106 for (auto pit = processes->begin(); pit != processes->end();) { | |
| 107 const PersistentProcessInfo::ProcessInfo* process = pit->second.get(); | |
| 108 fprintf(out_, "\"%d\":{", process->pid); | |
| 109 fprintf(out_, "\"name\":\"%s\"", process->name.c_str()); | |
| 110 | |
| 111 if (!process->in_kernel) { | |
| 112 fprintf(out_, ",\"exe\":\"%s\",", process->exe.c_str()); | |
| 113 fprintf(out_, "\"threads\":{\n"); | |
| 114 const PersistentProcessInfo::ThreadMap* threads = &process->threads; | |
| 115 for (auto tit = threads->begin(); tit != threads->end();) { | |
| 116 const PersistentProcessInfo::ThreadInfo* thread = tit->second.get(); | |
| 117 fprintf(out_, "\"%d\":{", thread->tid); | |
| 118 fprintf(out_, "\"name\":\"%s\"", thread->name.c_str()); | |
| 119 | |
| 120 ++tit; | |
| 121 if (tit != threads->end()) { | |
| 122 fprintf(out_, "},\n"); | |
| 123 } else { | |
| 124 fprintf(out_, "}\n"); | |
| 125 } | |
| 126 } | |
| 127 fprintf(out_, "}"); | |
| 128 } | |
| 129 | |
| 130 ++pit; | |
| 131 if (pit != processes->end()) { | |
| 132 fprintf(out_, "},\n"); | |
| 133 } else { | |
| 134 fprintf(out_, "}\n"); | |
| 135 } | |
| 136 } | |
| 137 fprintf(out_, "}"); | |
| 138 } | |
| 139 | |
| 140 void AtraceProcessDump::RunAndPrintJson(FILE* stream) { | |
| 141 using ProcessInfo = PersistentProcessInfo::ProcessInfo; | |
| 142 out_ = stream; | |
| 143 | |
| 144 std::set<int> smaps_pids; | |
| 145 std::unique_ptr<ProcessDumpManager> mgr(new ProcessDumpManager()); | |
|
Primiano Tucci (use gerrit)
2017/06/26 10:07:19
Copy/pasting to what I said in the previous review
| |
| 146 mgr->SetFullDumpPredicate([this](const ProcessInfo* process) -> bool { | |
| 147 if (full_dump_all_) | |
| 148 return !process->in_kernel && (process->pid != self_pid_); | |
| 149 if (full_dump_apps_) | |
| 150 return process->is_app; | |
| 151 if (full_dump_whitelist_.empty()) | |
| 152 return false; | |
| 153 return full_dump_whitelist_.count(process->name) > 0; | |
| 154 }); | |
| 155 if (graphics_stats_) | |
| 156 mgr->EnableGraphicsStats(); | |
| 157 | |
| 158 SetupTimer(); | |
| 159 fprintf(out_, "{\"start_ts\": \"%llu\", \"snapshots\":[\n", GetTimestamp()); | |
| 160 for (int dump_number = 0; dump_number < dump_count_; dump_number++) { | |
| 161 if (dump_number > 0) { | |
| 162 fprintf(out_, ",\n"); | |
| 163 if (!WaitForTimer()) | |
| 164 break; // Interrupted by signal. | |
| 165 } | |
| 166 mgr->TakeSnapshot(); | |
| 167 | |
| 168 // Smaps are too heavy to serialize. Using only in whitelist mode. | |
| 169 if (print_smaps_ && !full_dump_whitelist_.empty()) { | |
| 170 smaps_pids.clear(); | |
| 171 auto processes = mgr->all_processes(); | |
| 172 for (auto pit = processes->begin(); pit != processes->end(); ++pit) { | |
| 173 if (full_dump_whitelist_.count(pit->second->name)) | |
| 174 smaps_pids.insert(pit->second->pid); | |
| 175 } | |
| 176 } | |
| 177 SerializeSnapshot(mgr->last_snapshot(), smaps_pids); | |
| 178 fflush(out_); | |
| 179 } | |
| 180 fprintf(out_, "],\n"); | |
| 181 SerializeProcessInfo(mgr->all_processes()); | |
| 182 CloseTimer(); | |
| 183 | |
| 184 fprintf(out_, "}\n"); | |
| 185 fclose(out_); | |
| 186 } | |
| 187 | |
| 188 void AtraceProcessDump::SetupTimer() { | |
| 189 timer_fd_ = timerfd_create(CLOCK_MONOTONIC, 0); | |
| 190 CHECK(timer_fd_ >= 0); | |
| 191 int sec = dump_interval_ms_ / 1000; | |
| 192 int nsec = (dump_interval_ms_ % 1000) * 1000000; | |
| 193 struct itimerspec ts = {}; | |
| 194 ts.it_value.tv_nsec = nsec; | |
| 195 ts.it_value.tv_sec = sec; | |
| 196 ts.it_interval.tv_nsec = nsec; | |
| 197 ts.it_interval.tv_sec = sec; | |
| 198 CHECK(timerfd_settime(timer_fd_, 0, &ts, nullptr) == 0); | |
| 199 } | |
| 200 | |
| 201 bool AtraceProcessDump::WaitForTimer() { | |
| 202 uint64_t stub = 0; | |
| 203 int res = read(timer_fd_, &stub, sizeof(stub)); | |
| 204 if (res < 0 && errno == EBADF) | |
| 205 return false; // Received SIGINT/SIGTERM signal. | |
| 206 CHECK(res > 0); | |
| 207 return true; | |
| 208 } | |
| 209 | |
| 210 void AtraceProcessDump::CloseTimer() { | |
| 211 if (timer_fd_ < 0) | |
| 212 return; | |
| 213 close(timer_fd_); | |
| 214 timer_fd_ = 0; | |
| 215 } | |
| OLD | NEW |