diff options
Diffstat (limited to 'catapult/systrace/atrace_helper/jni/main.cc')
-rw-r--r-- | catapult/systrace/atrace_helper/jni/main.cc | 177 |
1 files changed, 56 insertions, 121 deletions
diff --git a/catapult/systrace/atrace_helper/jni/main.cc b/catapult/systrace/atrace_helper/jni/main.cc index e6f1fe19..764b573a 100644 --- a/catapult/systrace/atrace_helper/jni/main.cc +++ b/catapult/systrace/atrace_helper/jni/main.cc @@ -2,119 +2,81 @@ // 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) { - std::unique_ptr<ProcessMap> procs(new ProcessMap()); - file_utils::ForEachPidInProcPath("/proc", [&procs, full_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; - } - (*procs)[pid] = std::move(pinfo); - }); - return procs; -} - -void SerializeSnapshot(const ProcessMap& procs, - FILE* stream, - bool full_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->rss_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()); +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); } - 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 int main(int argc, char** argv) { + if (argc == 2 && !strcmp(argv[1], "--echo-ts")) { + // Used by clock sync marker to correct the difference between + // Linux monotonic clocks on the device and host. + printf("%llu\n", time_utils::GetTimestamp()); + return 0; + } + bool background = false; int dump_interval_ms = 5000; char out_file[PATH_MAX] = {}; bool dump_to_file = false; - bool full_mem_stats = false; - int count = std::numeric_limits<int>::max(); + int count = -1; + + 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, "bmt: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': + prog->enable_graphics_stats(); + break; + case 's': + prog->enable_print_smaps(); break; case 't': dump_interval_ms = atoi(optarg); @@ -130,17 +92,16 @@ int main(int argc, char** argv) { break; default: fprintf(stderr, - "Usage: %s [-b] [-t dump_interval_ms] [-c dumps_count] " - "[-o out.json]\n", + "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->SetDumpInterval(dump_interval_ms); FILE* out_stream = stdout; char tmp_file[PATH_MAX]; @@ -153,46 +114,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); - SerializeSnapshot(*procs, out_stream, full_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); } |