| Index: systrace/atrace_helper/jni/main.cc
|
| diff --git a/systrace/atrace_helper/jni/main.cc b/systrace/atrace_helper/jni/main.cc
|
| index 63f4d4f4540e2c586d8b48be4992be942de353c5..1731623cf3506800aa88c4896462c703a98bd9f6 100644
|
| --- a/systrace/atrace_helper/jni/main.cc
|
| +++ b/systrace/atrace_helper/jni/main.cc
|
| @@ -2,117 +2,42 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include <dirent.h>
|
| #include <signal.h>
|
| #include <stdio.h>
|
| #include <stdlib.h>
|
| #include <string.h>
|
| -#include <sys/time.h>
|
| -#include <sys/timerfd.h>
|
| -#include <sys/types.h>
|
|
|
| #include <limits>
|
| #include <memory>
|
| +#include <set>
|
| +#include <string>
|
| +#include <sstream>
|
|
|
| -#include "file_utils.h"
|
| +#include "atrace_process_dump.h"
|
| #include "logging.h"
|
| -#include "process_info.h"
|
|
|
| namespace {
|
|
|
| -using ProcessMap = std::map<int, std::unique_ptr<ProcessInfo>>;
|
| -
|
| -int g_timer;
|
| -
|
| -std::unique_ptr<ProcessMap> CollectStatsForAllProcs(bool full_mem_stats,
|
| - bool gpu_mem_stats) {
|
| - std::unique_ptr<ProcessMap> procs(new ProcessMap());
|
| - file_utils::ForEachPidInProcPath("/proc",
|
| - [&procs, full_mem_stats, gpu_mem_stats](int pid) {
|
| -
|
| - if (!ProcessInfo::IsProcess(pid))
|
| - return;
|
| - CHECK(procs->count(pid) == 0);
|
| - std::unique_ptr<ProcessInfo> pinfo(new ProcessInfo(pid));
|
| - if (!(pinfo->ReadProcessName() && pinfo->ReadThreadNames() &&
|
| - pinfo->ReadOOMStats() && pinfo->ReadPageFaultsAndCPUTimeStats()))
|
| - return;
|
| -
|
| - if (full_mem_stats) {
|
| - if (!pinfo->memory()->ReadFullStats())
|
| - return;
|
| - } else {
|
| - if (!pinfo->memory()->ReadLightStats())
|
| - return;
|
| - }
|
| - if (gpu_mem_stats) {
|
| - // It might fail on some devices.
|
| - pinfo->memory()->ReadMemtrackStats();
|
| +std::unique_ptr<AtraceProcessDump> g_prog;
|
| +
|
| +void ParseFullDumpConfig(const std::string& config, AtraceProcessDump* prog) {
|
| + using FullDumpMode = AtraceProcessDump::FullDumpMode;
|
| + if (config == "all") {
|
| + prog->set_full_dump_mode(FullDumpMode::kAllProcesses);
|
| + } else if (config == "apps") {
|
| + prog->set_full_dump_mode(FullDumpMode::kAllJavaApps);
|
| + } else {
|
| + std::set<std::string> whitelist;
|
| + std::istringstream ss(config);
|
| + std::string entry;
|
| + while (std::getline(ss, entry, ',')) {
|
| + whitelist.insert(entry);
|
| }
|
| - (*procs)[pid] = std::move(pinfo);
|
| - });
|
| - return procs;
|
| -}
|
| -
|
| -void SerializeSnapshot(const ProcessMap& procs,
|
| - FILE* stream,
|
| - bool full_mem_stats,
|
| - bool gpu_mem_stats) {
|
| - struct timespec ts = {};
|
| - CHECK(clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0);
|
| - fprintf(stream, "{\n");
|
| - fprintf(stream, " \"ts\": %lu,\n",
|
| - (ts.tv_sec * 1000 + ts.tv_nsec / 1000000ul));
|
| - fprintf(stream, " \"processes\": [\n");
|
| - for (auto it = procs.begin(); it != procs.end();) {
|
| - int pid = it->first;
|
| - const ProcessInfo& pinfo = *it->second;
|
| - fprintf(stream, " {\"pid\": %d, \"name\": \"%s\", \"exe\": \"%s\"", pid,
|
| - pinfo.name(), pinfo.exe());
|
| - fprintf(stream, ", \"threads\": [");
|
| - for (auto t = pinfo.threads()->begin(); t != pinfo.threads()->end();) {
|
| - fprintf(stream, "{\"tid\": %d, \"name\":\"%s\"", t->first,
|
| - t->second->name);
|
| - t++;
|
| - fprintf(stream, t != pinfo.threads()->end() ? "}, " : "}");
|
| - }
|
| - fprintf(stream, "]");
|
| -
|
| - const ProcessMemoryStats* mem_info = pinfo.memory();
|
| - fprintf(stream, ", \"mem\": {\"vm\": %llu, \"rss\": %llu",
|
| - mem_info->virt_kb(), mem_info->rss_kb());
|
| - if (full_mem_stats) {
|
| - fprintf(stream,
|
| - ", \"pss\": %llu, \"swp\": %llu, \"pc\": %llu, \"pd\": %llu, "
|
| - "\"sc\": %llu, \"sd\": %llu",
|
| - mem_info->pss_kb(), mem_info->swapped_kb(),
|
| - mem_info->private_clean_kb(), mem_info->private_dirty_kb(),
|
| - mem_info->shared_clean_kb(), mem_info->shared_dirty_kb());
|
| - }
|
| - if (gpu_mem_stats) {
|
| - fprintf(stream,
|
| - ", \"gpu\": %llu, \"gpu_pss\": %llu"
|
| - ", \"gpu_gl\": %llu, \"gpu_gl_pss\": %llu"
|
| - ", \"gpu_etc\": %llu, \"gpu_etc_pss\": %llu",
|
| - mem_info->gpu_graphics_kb(), mem_info->gpu_graphics_pss_kb(),
|
| - mem_info->gpu_gl_kb(), mem_info->gpu_gl_pss_kb(),
|
| - mem_info->gpu_other_kb(), mem_info->gpu_other_pss_kb());
|
| - }
|
| - fprintf(stream, "}");
|
| -
|
| - fprintf(stream,
|
| - ", \"oom\": {\"adj\": %d, \"score_adj\": %d, \"score\": %d}",
|
| - pinfo.oom_adj(), pinfo.oom_score_adj(), pinfo.oom_score());
|
| - fprintf(stream,
|
| - ", \"stat\": {\"minflt\": %lu, \"majflt\": %lu, "
|
| - "\"utime\": %lu, \"stime\": %lu }",
|
| - pinfo.minflt(), pinfo.majflt(), pinfo.utime(), pinfo.stime());
|
| - fprintf(stream, "}");
|
| - it++;
|
| - fprintf(stream, it != procs.end() ? ",\n" : "\n");
|
| + if (whitelist.empty())
|
| + return;
|
| + prog->set_full_dump_mode(FullDumpMode::kOnlyWhitelisted);
|
| + prog->set_full_dump_whitelist(whitelist);
|
| }
|
| - fprintf(stream, " ]\n");
|
| - fprintf(stream, "}\n");
|
| }
|
|
|
| } // namespace
|
| @@ -122,20 +47,30 @@ int main(int argc, char** argv) {
|
| int dump_interval_ms = 5000;
|
| char out_file[PATH_MAX] = {};
|
| bool dump_to_file = false;
|
| - bool full_mem_stats = false;
|
| - bool gpu_mem_stats = false;
|
| int count = std::numeric_limits<int>::max();
|
| +
|
| + AtraceProcessDump* prog = new AtraceProcessDump();
|
| + g_prog = std::unique_ptr<AtraceProcessDump>(prog);
|
| +
|
| + if (geteuid()) {
|
| + fprintf(stderr, "Must run as root\n");
|
| + exit(EXIT_FAILURE);
|
| + }
|
| +
|
| int opt;
|
| - while ((opt = getopt(argc, argv, "bmgt:o:c:")) != -1) {
|
| + while ((opt = getopt(argc, argv, "bm:gst:o:c:")) != -1) {
|
| switch (opt) {
|
| case 'b':
|
| background = true;
|
| break;
|
| case 'm':
|
| - full_mem_stats = true;
|
| + ParseFullDumpConfig(optarg, prog);
|
| break;
|
| case 'g':
|
| - gpu_mem_stats = true;
|
| + prog->enable_graphics_stats();
|
| + break;
|
| + case 's':
|
| + prog->enable_print_smaps();
|
| break;
|
| case 't':
|
| dump_interval_ms = atoi(optarg);
|
| @@ -151,17 +86,16 @@ int main(int argc, char** argv) {
|
| break;
|
| default:
|
| fprintf(stderr,
|
| - "Usage: %s [-b] [-m] [-g] [-t dump_interval_ms] "
|
| + "Usage: %s [-b] [-m full_dump_filter] [-g] [-s] "
|
| + "[-t dump_interval_ms] "
|
| "[-c dumps_count] [-o out.json]\n",
|
| argv[0]);
|
| exit(EXIT_FAILURE);
|
| }
|
| }
|
|
|
| - if (geteuid()) {
|
| - fprintf(stderr, "Must run as root\n");
|
| - exit(EXIT_FAILURE);
|
| - }
|
| + prog->set_dump_count(count);
|
| + prog->set_dump_interval(dump_interval_ms);
|
|
|
| FILE* out_stream = stdout;
|
| char tmp_file[PATH_MAX];
|
| @@ -174,47 +108,20 @@ int main(int argc, char** argv) {
|
|
|
| if (background) {
|
| if (!dump_to_file) {
|
| - fprintf(stderr, "-b requires -o for output dump path\n");
|
| + fprintf(stderr, "-b requires -o for output dump path.\n");
|
| exit(EXIT_FAILURE);
|
| }
|
| printf("Continuing in background. kill -TERM to terminate the daemon.\n");
|
| CHECK(daemon(0 /* nochdir */, 0 /* noclose */) == 0);
|
| }
|
|
|
| - g_timer = timerfd_create(CLOCK_MONOTONIC, 0);
|
| - CHECK(g_timer >= 0);
|
| - struct itimerspec ts = {};
|
| - ts.it_value.tv_nsec = 1; // Get the first snapshot immediately.
|
| - ts.it_interval.tv_nsec = (dump_interval_ms % 1000) * 1000000ul;
|
| - ts.it_interval.tv_sec = dump_interval_ms / 1000;
|
| - CHECK(timerfd_settime(g_timer, 0, &ts, nullptr) == 0);
|
| -
|
| - // Closing the g_timer fd on SIGINT/SIGTERM will cause the read() below to
|
| - // unblock and fail with EBADF, hence allowing the loop below to finalize
|
| - // the file and exit.
|
| - auto on_exit = [](int) { close(g_timer); };
|
| + auto on_exit = [](int) { g_prog->Stop(); };
|
| signal(SIGINT, on_exit);
|
| signal(SIGTERM, on_exit);
|
|
|
| - fprintf(out_stream, "{\"snapshots\": [\n");
|
| - bool is_first_snapshot = true;
|
| - for (; count > 0; count--) {
|
| - uint64_t missed = 0;
|
| - int res = read(g_timer, &missed, sizeof(missed));
|
| - if (res < 0 && errno == EBADF)
|
| - break; // Received SIGINT/SIGTERM signal.
|
| - CHECK(res > 0);
|
| - if (!is_first_snapshot)
|
| - fprintf(out_stream, ",");
|
| - is_first_snapshot = false;
|
| -
|
| - std::unique_ptr<ProcessMap> procs =
|
| - CollectStatsForAllProcs(full_mem_stats, gpu_mem_stats);
|
| - SerializeSnapshot(*procs, out_stream, full_mem_stats, gpu_mem_stats);
|
| - fflush(out_stream);
|
| - }
|
| - fprintf(out_stream, "]}\n");
|
| + prog->RunAndPrintJson(out_stream);
|
| fclose(out_stream);
|
| +
|
| if (dump_to_file)
|
| rename(tmp_file, out_file);
|
| }
|
|
|