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 <stdint.h> |
| 8 |
| 9 #include "file_utils.h" |
| 10 #include "logging.h" |
| 11 #include "procfs_utils.h" |
| 12 |
| 13 AtraceProcessDump::AtraceProcessDump() { |
| 14 self_pid_ = static_cast<int>(getpid()); |
| 15 } |
| 16 |
| 17 AtraceProcessDump::~AtraceProcessDump() { |
| 18 } |
| 19 |
| 20 void AtraceProcessDump::RunAndPrintJson(FILE* stream) { |
| 21 out_ = stream; |
| 22 |
| 23 fprintf(out_, "{\"start_ts\": \"%llu\", \"snapshots\":[\n", |
| 24 time_utils::GetTimestamp()); |
| 25 |
| 26 CHECK(dump_timer_); |
| 27 dump_timer_->Start(); |
| 28 for (int dump_number = 0; dump_number < dump_count_; dump_number++) { |
| 29 if (dump_number > 0) { |
| 30 if (!dump_timer_->Wait()) |
| 31 break; // Interrupted by signal. |
| 32 fprintf(out_, ",\n"); |
| 33 } |
| 34 TakeGlobalSnapshot(); |
| 35 SerializeSnapshot(); |
| 36 fflush(out_); |
| 37 } |
| 38 fprintf(out_, "],\n"); |
| 39 SerializePersistentProcessInfo(); |
| 40 fprintf(out_, "}\n"); |
| 41 fflush(out_); |
| 42 Cleanup(); |
| 43 } |
| 44 |
| 45 void AtraceProcessDump::Stop() { |
| 46 CHECK(dump_timer_); |
| 47 dump_timer_->Stop(); |
| 48 } |
| 49 |
| 50 void AtraceProcessDump::TakeGlobalSnapshot() { |
| 51 snapshot_.clear(); |
| 52 snapshot_timestamp_ = time_utils::GetTimestamp(); |
| 53 |
| 54 file_utils::ForEachPidInProcPath("/proc", [this](int pid) { |
| 55 // Skip if not regognized as a process. |
| 56 if (!UpdatePersistentProcessInfo(pid)) |
| 57 return; |
| 58 const ProcessInfo* process = processes_[pid].get(); |
| 59 // Snapshot can't be obtained for kernel workers. |
| 60 if (process->in_kernel) |
| 61 return; |
| 62 |
| 63 ProcessSnapshot* process_snapshot = new ProcessSnapshot(); |
| 64 snapshot_[pid] = std::unique_ptr<ProcessSnapshot>(process_snapshot); |
| 65 |
| 66 process_snapshot->pid = pid; |
| 67 procfs_utils::ReadOomStats(process_snapshot); |
| 68 procfs_utils::ReadPageFaultsAndCpuTimeStats(process_snapshot); |
| 69 |
| 70 if (ShouldTakeFullDump(process)) { |
| 71 process_snapshot->memory.ReadFullStats(pid); |
| 72 } else { |
| 73 process_snapshot->memory.ReadLightStats(pid); |
| 74 } |
| 75 if (graphics_stats_ && process->is_app) { |
| 76 process_snapshot->memory.ReadGpuStats(pid); |
| 77 } |
| 78 }); |
| 79 } |
| 80 |
| 81 bool AtraceProcessDump::UpdatePersistentProcessInfo(int pid) { |
| 82 if (!processes_.count(pid)) { |
| 83 if (procfs_utils::ReadTgid(pid) != pid) |
| 84 return false; |
| 85 processes_[pid] = procfs_utils::ReadProcessInfo(pid); |
| 86 } |
| 87 ProcessInfo* process = processes_[pid].get(); |
| 88 procfs_utils::ReadProcessThreads(process); |
| 89 |
| 90 if (full_dump_mode_ == FullDumpMode::kOnlyWhitelisted && |
| 91 full_dump_whitelist_.count(process->name)) { |
| 92 full_dump_whitelisted_pids_.insert(pid); |
| 93 } |
| 94 return true; |
| 95 } |
| 96 |
| 97 bool AtraceProcessDump::ShouldTakeFullDump(const ProcessInfo* process) { |
| 98 if (full_dump_mode_ == FullDumpMode::kAllProcesses) |
| 99 return !process->in_kernel && (process->pid != self_pid_); |
| 100 if (full_dump_mode_ == FullDumpMode::kAllJavaApps) |
| 101 return process->is_app; |
| 102 if (full_dump_mode_ == FullDumpMode::kDisabled) |
| 103 return false; |
| 104 return full_dump_whitelisted_pids_.count(process->pid) > 0; |
| 105 } |
| 106 |
| 107 void AtraceProcessDump::SerializeSnapshot() { |
| 108 fprintf(out_, "{\"ts\":\"%llu\",\"memdump\":{\n", snapshot_timestamp_); |
| 109 for (auto it = snapshot_.begin(); it != snapshot_.end();) { |
| 110 const ProcessSnapshot* process = it->second.get(); |
| 111 const ProcessMemoryStats* mem = &process->memory; |
| 112 fprintf(out_, "\"%d\":{", process->pid); |
| 113 |
| 114 fprintf(out_, "\"vm\":%llu,\"rss\":%llu", |
| 115 mem->virt_kb(), mem->rss_kb()); |
| 116 |
| 117 fprintf(out_, ",\"oom_sc\":%d,\"oom_sc_adj\":%d" |
| 118 ",\"min_flt\":%lu,\"maj_flt\":%lu" |
| 119 ",\"utime\":%lu,\"stime\":%lu", |
| 120 process->oom_score, process->oom_score_adj, |
| 121 process->minor_faults, process->major_faults, |
| 122 process->utime, process->stime); |
| 123 |
| 124 if (mem->full_stats_available()) { |
| 125 fprintf(out_, ",\"pss\":%llu,\"swp\":%llu" |
| 126 ",\"pc\":%llu,\"pd\":%llu,\"sc\":%llu,\"sd\":%llu", |
| 127 mem->pss_kb(), mem->swapped_kb(), |
| 128 mem->private_clean_kb(), mem->private_dirty_kb(), |
| 129 mem->shared_clean_kb(), mem->shared_dirty_kb()); |
| 130 } |
| 131 |
| 132 if (mem->gpu_stats_available()) { |
| 133 fprintf(out_, ",\"gpu_egl\":%llu,\"gpu_egl_pss\":%llu" |
| 134 ",\"gpu_gl\":%llu,\"gpu_gl_pss\":%llu" |
| 135 ",\"gpu_etc\":%llu,\"gpu_etc_pss\":%llu", |
| 136 mem->gpu_graphics_kb(), mem->gpu_graphics_pss_kb(), |
| 137 mem->gpu_gl_kb(), mem->gpu_gl_pss_kb(), |
| 138 mem->gpu_other_kb(), mem->gpu_other_pss_kb()); |
| 139 } |
| 140 |
| 141 // Memory maps are too heavy to serialize. Enable only in whitelisting mode. |
| 142 if (print_smaps_ && |
| 143 full_dump_mode_ == FullDumpMode::kOnlyWhitelisted && |
| 144 mem->full_stats_available() && |
| 145 full_dump_whitelisted_pids_.count(process->pid)) { |
| 146 |
| 147 fprintf(out_, ", \"mmaps\":["); |
| 148 size_t n_mmaps = mem->mmaps_count(); |
| 149 for (size_t k = 0; k < n_mmaps; ++k) { |
| 150 const ProcessMemoryStats::MmapInfo* mm = mem->mmap(k); |
| 151 fprintf(out_, |
| 152 "{\"vm\":\"%llx-%llx\",\"file\":\"%s\",\"flags\":\"%s\"," |
| 153 "\"pss\":%llu,\"rss\":%llu,\"swp\":%llu," |
| 154 "\"pc\":%llu,\"pd\":%llu," |
| 155 "\"sc\":%llu,\"sd\":%llu}", |
| 156 mm->start_addr, mm->end_addr, mm->mapped_file, mm->prot_flags, |
| 157 mm->pss_kb, mm->rss_kb, mm->swapped_kb, |
| 158 mm->private_clean_kb, mm->private_dirty_kb, |
| 159 mm->shared_clean_kb, mm->shared_dirty_kb); |
| 160 if (k < n_mmaps - 1) |
| 161 fprintf(out_, ", "); |
| 162 } |
| 163 fprintf(out_, "]"); |
| 164 } |
| 165 |
| 166 if (++it != snapshot_.end()) |
| 167 fprintf(out_, "},\n"); |
| 168 else |
| 169 fprintf(out_, "}}\n"); |
| 170 } |
| 171 fprintf(out_, "}"); |
| 172 } |
| 173 |
| 174 void AtraceProcessDump::SerializePersistentProcessInfo() { |
| 175 fprintf(out_, "\"processes\":{"); |
| 176 for (auto it = processes_.begin(); it != processes_.end();) { |
| 177 const ProcessInfo* process = it->second.get(); |
| 178 fprintf(out_, "\"%d\":{", process->pid); |
| 179 fprintf(out_, "\"name\":\"%s\"", process->name); |
| 180 |
| 181 if (!process->in_kernel) { |
| 182 fprintf(out_, ",\"exe\":\"%s\",", process->exe); |
| 183 fprintf(out_, "\"threads\":{\n"); |
| 184 const auto threads = &process->threads; |
| 185 for (auto thread_it = threads->begin(); thread_it != threads->end();) { |
| 186 const ThreadInfo* thread = &(thread_it->second); |
| 187 fprintf(out_, "\"%d\":{", thread->tid); |
| 188 fprintf(out_, "\"name\":\"%s\"", thread->name); |
| 189 |
| 190 if (++thread_it != threads->end()) |
| 191 fprintf(out_, "},\n"); |
| 192 else |
| 193 fprintf(out_, "}\n"); |
| 194 } |
| 195 fprintf(out_, "}"); |
| 196 } |
| 197 |
| 198 if (++it != processes_.end()) |
| 199 fprintf(out_, "},\n"); |
| 200 else |
| 201 fprintf(out_, "}\n"); |
| 202 } |
| 203 fprintf(out_, "}"); |
| 204 } |
| 205 |
| 206 void AtraceProcessDump::Cleanup() { |
| 207 processes_.clear(); |
| 208 snapshot_.clear(); |
| 209 full_dump_whitelisted_pids_.clear(); |
| 210 dump_timer_ = nullptr; |
| 211 } |
OLD | NEW |