| Index: systrace/atrace_helper/jni/atrace_process_dump.cc
|
| diff --git a/systrace/atrace_helper/jni/atrace_process_dump.cc b/systrace/atrace_helper/jni/atrace_process_dump.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..63ce70a1a171ec602b23fffc3d3f99fa18df1cad
|
| --- /dev/null
|
| +++ b/systrace/atrace_helper/jni/atrace_process_dump.cc
|
| @@ -0,0 +1,211 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "atrace_process_dump.h"
|
| +
|
| +#include <stdint.h>
|
| +
|
| +#include "file_utils.h"
|
| +#include "logging.h"
|
| +#include "procfs_utils.h"
|
| +
|
| +AtraceProcessDump::AtraceProcessDump() {
|
| + self_pid_ = static_cast<int>(getpid());
|
| +}
|
| +
|
| +AtraceProcessDump::~AtraceProcessDump() {
|
| +}
|
| +
|
| +void AtraceProcessDump::RunAndPrintJson(FILE* stream) {
|
| + out_ = stream;
|
| +
|
| + fprintf(out_, "{\"start_ts\": \"%llu\", \"snapshots\":[\n",
|
| + time_utils::GetTimestamp());
|
| +
|
| + CHECK(dump_timer_);
|
| + dump_timer_->Start();
|
| + for (int dump_number = 0; dump_number < dump_count_; dump_number++) {
|
| + if (dump_number > 0) {
|
| + if (!dump_timer_->Wait())
|
| + break; // Interrupted by signal.
|
| + fprintf(out_, ",\n");
|
| + }
|
| + TakeGlobalSnapshot();
|
| + SerializeSnapshot();
|
| + fflush(out_);
|
| + }
|
| + fprintf(out_, "],\n");
|
| + SerializePersistentProcessInfo();
|
| + fprintf(out_, "}\n");
|
| + fflush(out_);
|
| + Cleanup();
|
| +}
|
| +
|
| +void AtraceProcessDump::Stop() {
|
| + CHECK(dump_timer_);
|
| + dump_timer_->Stop();
|
| +}
|
| +
|
| +void AtraceProcessDump::TakeGlobalSnapshot() {
|
| + snapshot_.clear();
|
| + snapshot_timestamp_ = time_utils::GetTimestamp();
|
| +
|
| + file_utils::ForEachPidInProcPath("/proc", [this](int pid) {
|
| + // Skip if not regognized as a process.
|
| + if (!UpdatePersistentProcessInfo(pid))
|
| + return;
|
| + const ProcessInfo* process = processes_[pid].get();
|
| + // Snapshot can't be obtained for kernel workers.
|
| + if (process->in_kernel)
|
| + return;
|
| +
|
| + ProcessSnapshot* process_snapshot = new ProcessSnapshot();
|
| + snapshot_[pid] = std::unique_ptr<ProcessSnapshot>(process_snapshot);
|
| +
|
| + process_snapshot->pid = pid;
|
| + procfs_utils::ReadOomStats(process_snapshot);
|
| + procfs_utils::ReadPageFaultsAndCpuTimeStats(process_snapshot);
|
| +
|
| + if (ShouldTakeFullDump(process)) {
|
| + process_snapshot->memory.ReadFullStats(pid);
|
| + } else {
|
| + process_snapshot->memory.ReadLightStats(pid);
|
| + }
|
| + if (graphics_stats_ && process->is_app) {
|
| + process_snapshot->memory.ReadGpuStats(pid);
|
| + }
|
| + });
|
| +}
|
| +
|
| +bool AtraceProcessDump::UpdatePersistentProcessInfo(int pid) {
|
| + if (!processes_.count(pid)) {
|
| + if (procfs_utils::ReadTgid(pid) != pid)
|
| + return false;
|
| + processes_[pid] = procfs_utils::ReadProcessInfo(pid);
|
| + }
|
| + ProcessInfo* process = processes_[pid].get();
|
| + procfs_utils::ReadProcessThreads(process);
|
| +
|
| + if (full_dump_mode_ == FullDumpMode::kOnlyWhitelisted &&
|
| + full_dump_whitelist_.count(process->name)) {
|
| + full_dump_whitelisted_pids_.insert(pid);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool AtraceProcessDump::ShouldTakeFullDump(const ProcessInfo* process) {
|
| + if (full_dump_mode_ == FullDumpMode::kAllProcesses)
|
| + return !process->in_kernel && (process->pid != self_pid_);
|
| + if (full_dump_mode_ == FullDumpMode::kAllJavaApps)
|
| + return process->is_app;
|
| + if (full_dump_mode_ == FullDumpMode::kDisabled)
|
| + return false;
|
| + return full_dump_whitelisted_pids_.count(process->pid) > 0;
|
| +}
|
| +
|
| +void AtraceProcessDump::SerializeSnapshot() {
|
| + fprintf(out_, "{\"ts\":\"%llu\",\"memdump\":{\n", snapshot_timestamp_);
|
| + for (auto it = snapshot_.begin(); it != snapshot_.end();) {
|
| + const ProcessSnapshot* process = it->second.get();
|
| + const ProcessMemoryStats* mem = &process->memory;
|
| + fprintf(out_, "\"%d\":{", process->pid);
|
| +
|
| + fprintf(out_, "\"vm\":%llu,\"rss\":%llu",
|
| + mem->virt_kb(), mem->rss_kb());
|
| +
|
| + fprintf(out_, ",\"oom_sc\":%d,\"oom_sc_adj\":%d"
|
| + ",\"min_flt\":%lu,\"maj_flt\":%lu"
|
| + ",\"utime\":%lu,\"stime\":%lu",
|
| + process->oom_score, process->oom_score_adj,
|
| + process->minor_faults, process->major_faults,
|
| + process->utime, process->stime);
|
| +
|
| + if (mem->full_stats_available()) {
|
| + fprintf(out_, ",\"pss\":%llu,\"swp\":%llu"
|
| + ",\"pc\":%llu,\"pd\":%llu,\"sc\":%llu,\"sd\":%llu",
|
| + mem->pss_kb(), mem->swapped_kb(),
|
| + mem->private_clean_kb(), mem->private_dirty_kb(),
|
| + mem->shared_clean_kb(), mem->shared_dirty_kb());
|
| + }
|
| +
|
| + if (mem->gpu_stats_available()) {
|
| + fprintf(out_, ",\"gpu_egl\":%llu,\"gpu_egl_pss\":%llu"
|
| + ",\"gpu_gl\":%llu,\"gpu_gl_pss\":%llu"
|
| + ",\"gpu_etc\":%llu,\"gpu_etc_pss\":%llu",
|
| + mem->gpu_graphics_kb(), mem->gpu_graphics_pss_kb(),
|
| + mem->gpu_gl_kb(), mem->gpu_gl_pss_kb(),
|
| + mem->gpu_other_kb(), mem->gpu_other_pss_kb());
|
| + }
|
| +
|
| + // Memory maps are too heavy to serialize. Enable only in whitelisting mode.
|
| + if (print_smaps_ &&
|
| + full_dump_mode_ == FullDumpMode::kOnlyWhitelisted &&
|
| + mem->full_stats_available() &&
|
| + full_dump_whitelisted_pids_.count(process->pid)) {
|
| +
|
| + fprintf(out_, ", \"mmaps\":[");
|
| + size_t n_mmaps = mem->mmaps_count();
|
| + for (size_t k = 0; k < n_mmaps; ++k) {
|
| + const ProcessMemoryStats::MmapInfo* mm = mem->mmap(k);
|
| + fprintf(out_,
|
| + "{\"vm\":\"%llx-%llx\",\"file\":\"%s\",\"flags\":\"%s\","
|
| + "\"pss\":%llu,\"rss\":%llu,\"swp\":%llu,"
|
| + "\"pc\":%llu,\"pd\":%llu,"
|
| + "\"sc\":%llu,\"sd\":%llu}",
|
| + mm->start_addr, mm->end_addr, mm->mapped_file, mm->prot_flags,
|
| + mm->pss_kb, mm->rss_kb, mm->swapped_kb,
|
| + mm->private_clean_kb, mm->private_dirty_kb,
|
| + mm->shared_clean_kb, mm->shared_dirty_kb);
|
| + if (k < n_mmaps - 1)
|
| + fprintf(out_, ", ");
|
| + }
|
| + fprintf(out_, "]");
|
| + }
|
| +
|
| + if (++it != snapshot_.end())
|
| + fprintf(out_, "},\n");
|
| + else
|
| + fprintf(out_, "}}\n");
|
| + }
|
| + fprintf(out_, "}");
|
| +}
|
| +
|
| +void AtraceProcessDump::SerializePersistentProcessInfo() {
|
| + fprintf(out_, "\"processes\":{");
|
| + for (auto it = processes_.begin(); it != processes_.end();) {
|
| + const ProcessInfo* process = it->second.get();
|
| + fprintf(out_, "\"%d\":{", process->pid);
|
| + fprintf(out_, "\"name\":\"%s\"", process->name);
|
| +
|
| + if (!process->in_kernel) {
|
| + fprintf(out_, ",\"exe\":\"%s\",", process->exe);
|
| + fprintf(out_, "\"threads\":{\n");
|
| + const auto threads = &process->threads;
|
| + for (auto thread_it = threads->begin(); thread_it != threads->end();) {
|
| + const ThreadInfo* thread = &(thread_it->second);
|
| + fprintf(out_, "\"%d\":{", thread->tid);
|
| + fprintf(out_, "\"name\":\"%s\"", thread->name);
|
| +
|
| + if (++thread_it != threads->end())
|
| + fprintf(out_, "},\n");
|
| + else
|
| + fprintf(out_, "}\n");
|
| + }
|
| + fprintf(out_, "}");
|
| + }
|
| +
|
| + if (++it != processes_.end())
|
| + fprintf(out_, "},\n");
|
| + else
|
| + fprintf(out_, "}\n");
|
| + }
|
| + fprintf(out_, "}");
|
| +}
|
| +
|
| +void AtraceProcessDump::Cleanup() {
|
| + processes_.clear();
|
| + snapshot_.clear();
|
| + full_dump_whitelisted_pids_.clear();
|
| + dump_timer_ = nullptr;
|
| +}
|
|
|