Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(239)

Side by Side Diff: systrace/atrace_helper/jni/main.cc

Issue 2946033002: Android systrace: Optimize memory dumps. (Closed)
Patch Set: tiny fix Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « systrace/atrace_helper/jni/logging.h ('k') | systrace/atrace_helper/jni/process_info.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <dirent.h>
6 #include <signal.h> 5 #include <signal.h>
7 #include <stdio.h> 6 #include <stdio.h>
8 #include <stdlib.h> 7 #include <stdlib.h>
9 #include <string.h> 8 #include <string.h>
10 #include <sys/time.h>
11 #include <sys/timerfd.h>
12 #include <sys/types.h>
13 9
14 #include <limits> 10 #include <limits>
15 #include <memory> 11 #include <memory>
12 #include <set>
13 #include <string>
14 #include <sstream>
16 15
17 #include "file_utils.h" 16 #include "atrace_process_dump.h"
18 #include "logging.h" 17 #include "logging.h"
19 #include "process_info.h"
20 18
21 namespace { 19 namespace {
22 20
23 using ProcessMap = std::map<int, std::unique_ptr<ProcessInfo>>; 21 std::unique_ptr<AtraceProcessDump> g_prog;
24 22
25 int g_timer; 23 void ParseFullDumpConfig(const std::string& config, AtraceProcessDump* prog) {
26 24 using FullDumpMode = AtraceProcessDump::FullDumpMode;
27 std::unique_ptr<ProcessMap> CollectStatsForAllProcs(bool full_mem_stats, 25 if (config == "all") {
28 bool gpu_mem_stats) { 26 prog->set_full_dump_mode(FullDumpMode::kAllProcesses);
29 std::unique_ptr<ProcessMap> procs(new ProcessMap()); 27 } else if (config == "apps") {
30 file_utils::ForEachPidInProcPath("/proc", 28 prog->set_full_dump_mode(FullDumpMode::kAllJavaApps);
31 [&procs, full_mem_stats, gpu_mem_stats](int pid) { 29 } else {
32 30 std::set<std::string> whitelist;
33 if (!ProcessInfo::IsProcess(pid)) 31 std::istringstream ss(config);
32 std::string entry;
33 while (std::getline(ss, entry, ',')) {
34 whitelist.insert(entry);
35 }
36 if (whitelist.empty())
34 return; 37 return;
35 CHECK(procs->count(pid) == 0); 38 prog->set_full_dump_mode(FullDumpMode::kOnlyWhitelisted);
36 std::unique_ptr<ProcessInfo> pinfo(new ProcessInfo(pid)); 39 prog->set_full_dump_whitelist(whitelist);
37 if (!(pinfo->ReadProcessName() && pinfo->ReadThreadNames() &&
38 pinfo->ReadOOMStats() && pinfo->ReadPageFaultsAndCPUTimeStats()))
39 return;
40
41 if (full_mem_stats) {
42 if (!pinfo->memory()->ReadFullStats())
43 return;
44 } else {
45 if (!pinfo->memory()->ReadLightStats())
46 return;
47 }
48 if (gpu_mem_stats) {
49 // It might fail on some devices.
50 pinfo->memory()->ReadMemtrackStats();
51 }
52 (*procs)[pid] = std::move(pinfo);
53 });
54 return procs;
55 }
56
57 void SerializeSnapshot(const ProcessMap& procs,
58 FILE* stream,
59 bool full_mem_stats,
60 bool gpu_mem_stats) {
61 struct timespec ts = {};
62 CHECK(clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0);
63 fprintf(stream, "{\n");
64 fprintf(stream, " \"ts\": %lu,\n",
65 (ts.tv_sec * 1000 + ts.tv_nsec / 1000000ul));
66 fprintf(stream, " \"processes\": [\n");
67 for (auto it = procs.begin(); it != procs.end();) {
68 int pid = it->first;
69 const ProcessInfo& pinfo = *it->second;
70 fprintf(stream, " {\"pid\": %d, \"name\": \"%s\", \"exe\": \"%s\"", pid,
71 pinfo.name(), pinfo.exe());
72 fprintf(stream, ", \"threads\": [");
73 for (auto t = pinfo.threads()->begin(); t != pinfo.threads()->end();) {
74 fprintf(stream, "{\"tid\": %d, \"name\":\"%s\"", t->first,
75 t->second->name);
76 t++;
77 fprintf(stream, t != pinfo.threads()->end() ? "}, " : "}");
78 }
79 fprintf(stream, "]");
80
81 const ProcessMemoryStats* mem_info = pinfo.memory();
82 fprintf(stream, ", \"mem\": {\"vm\": %llu, \"rss\": %llu",
83 mem_info->virt_kb(), mem_info->rss_kb());
84 if (full_mem_stats) {
85 fprintf(stream,
86 ", \"pss\": %llu, \"swp\": %llu, \"pc\": %llu, \"pd\": %llu, "
87 "\"sc\": %llu, \"sd\": %llu",
88 mem_info->pss_kb(), mem_info->swapped_kb(),
89 mem_info->private_clean_kb(), mem_info->private_dirty_kb(),
90 mem_info->shared_clean_kb(), mem_info->shared_dirty_kb());
91 }
92 if (gpu_mem_stats) {
93 fprintf(stream,
94 ", \"gpu\": %llu, \"gpu_pss\": %llu"
95 ", \"gpu_gl\": %llu, \"gpu_gl_pss\": %llu"
96 ", \"gpu_etc\": %llu, \"gpu_etc_pss\": %llu",
97 mem_info->gpu_graphics_kb(), mem_info->gpu_graphics_pss_kb(),
98 mem_info->gpu_gl_kb(), mem_info->gpu_gl_pss_kb(),
99 mem_info->gpu_other_kb(), mem_info->gpu_other_pss_kb());
100 }
101 fprintf(stream, "}");
102
103 fprintf(stream,
104 ", \"oom\": {\"adj\": %d, \"score_adj\": %d, \"score\": %d}",
105 pinfo.oom_adj(), pinfo.oom_score_adj(), pinfo.oom_score());
106 fprintf(stream,
107 ", \"stat\": {\"minflt\": %lu, \"majflt\": %lu, "
108 "\"utime\": %lu, \"stime\": %lu }",
109 pinfo.minflt(), pinfo.majflt(), pinfo.utime(), pinfo.stime());
110 fprintf(stream, "}");
111 it++;
112 fprintf(stream, it != procs.end() ? ",\n" : "\n");
113 } 40 }
114 fprintf(stream, " ]\n");
115 fprintf(stream, "}\n");
116 } 41 }
117 42
118 } // namespace 43 } // namespace
119 44
120 int main(int argc, char** argv) { 45 int main(int argc, char** argv) {
121 bool background = false; 46 bool background = false;
122 int dump_interval_ms = 5000; 47 int dump_interval_ms = 5000;
123 char out_file[PATH_MAX] = {}; 48 char out_file[PATH_MAX] = {};
124 bool dump_to_file = false; 49 bool dump_to_file = false;
125 bool full_mem_stats = false;
126 bool gpu_mem_stats = false;
127 int count = std::numeric_limits<int>::max(); 50 int count = std::numeric_limits<int>::max();
51
52 AtraceProcessDump* prog = new AtraceProcessDump();
53 g_prog = std::unique_ptr<AtraceProcessDump>(prog);
54
55 if (geteuid()) {
56 fprintf(stderr, "Must run as root\n");
57 exit(EXIT_FAILURE);
58 }
59
128 int opt; 60 int opt;
129 while ((opt = getopt(argc, argv, "bmgt:o:c:")) != -1) { 61 while ((opt = getopt(argc, argv, "bm:gst:o:c:")) != -1) {
130 switch (opt) { 62 switch (opt) {
131 case 'b': 63 case 'b':
132 background = true; 64 background = true;
133 break; 65 break;
134 case 'm': 66 case 'm':
135 full_mem_stats = true; 67 ParseFullDumpConfig(optarg, prog);
136 break; 68 break;
137 case 'g': 69 case 'g':
138 gpu_mem_stats = true; 70 prog->enable_graphics_stats();
71 break;
72 case 's':
73 prog->enable_print_smaps();
139 break; 74 break;
140 case 't': 75 case 't':
141 dump_interval_ms = atoi(optarg); 76 dump_interval_ms = atoi(optarg);
142 CHECK(dump_interval_ms > 0); 77 CHECK(dump_interval_ms > 0);
143 break; 78 break;
144 case 'c': 79 case 'c':
145 count = atoi(optarg); 80 count = atoi(optarg);
146 CHECK(count > 0); 81 CHECK(count > 0);
147 break; 82 break;
148 case 'o': 83 case 'o':
149 strncpy(out_file, optarg, sizeof(out_file)); 84 strncpy(out_file, optarg, sizeof(out_file));
150 dump_to_file = true; 85 dump_to_file = true;
151 break; 86 break;
152 default: 87 default:
153 fprintf(stderr, 88 fprintf(stderr,
154 "Usage: %s [-b] [-m] [-g] [-t dump_interval_ms] " 89 "Usage: %s [-b] [-m full_dump_filter] [-g] [-s] "
90 "[-t dump_interval_ms] "
155 "[-c dumps_count] [-o out.json]\n", 91 "[-c dumps_count] [-o out.json]\n",
156 argv[0]); 92 argv[0]);
157 exit(EXIT_FAILURE); 93 exit(EXIT_FAILURE);
158 } 94 }
159 } 95 }
160 96
161 if (geteuid()) { 97 prog->set_dump_count(count);
162 fprintf(stderr, "Must run as root\n"); 98 prog->set_dump_interval(dump_interval_ms);
163 exit(EXIT_FAILURE);
164 }
165 99
166 FILE* out_stream = stdout; 100 FILE* out_stream = stdout;
167 char tmp_file[PATH_MAX]; 101 char tmp_file[PATH_MAX];
168 if (dump_to_file) { 102 if (dump_to_file) {
169 unlink(out_file); 103 unlink(out_file);
170 sprintf(tmp_file, "%s.tmp", out_file); 104 sprintf(tmp_file, "%s.tmp", out_file);
171 out_stream = fopen(tmp_file, "w"); 105 out_stream = fopen(tmp_file, "w");
172 CHECK(out_stream); 106 CHECK(out_stream);
173 } 107 }
174 108
175 if (background) { 109 if (background) {
176 if (!dump_to_file) { 110 if (!dump_to_file) {
177 fprintf(stderr, "-b requires -o for output dump path\n"); 111 fprintf(stderr, "-b requires -o for output dump path.\n");
178 exit(EXIT_FAILURE); 112 exit(EXIT_FAILURE);
179 } 113 }
180 printf("Continuing in background. kill -TERM to terminate the daemon.\n"); 114 printf("Continuing in background. kill -TERM to terminate the daemon.\n");
181 CHECK(daemon(0 /* nochdir */, 0 /* noclose */) == 0); 115 CHECK(daemon(0 /* nochdir */, 0 /* noclose */) == 0);
182 } 116 }
183 117
184 g_timer = timerfd_create(CLOCK_MONOTONIC, 0); 118 auto on_exit = [](int) { g_prog->Stop(); };
185 CHECK(g_timer >= 0);
186 struct itimerspec ts = {};
187 ts.it_value.tv_nsec = 1; // Get the first snapshot immediately.
188 ts.it_interval.tv_nsec = (dump_interval_ms % 1000) * 1000000ul;
189 ts.it_interval.tv_sec = dump_interval_ms / 1000;
190 CHECK(timerfd_settime(g_timer, 0, &ts, nullptr) == 0);
191
192 // Closing the g_timer fd on SIGINT/SIGTERM will cause the read() below to
193 // unblock and fail with EBADF, hence allowing the loop below to finalize
194 // the file and exit.
195 auto on_exit = [](int) { close(g_timer); };
196 signal(SIGINT, on_exit); 119 signal(SIGINT, on_exit);
197 signal(SIGTERM, on_exit); 120 signal(SIGTERM, on_exit);
198 121
199 fprintf(out_stream, "{\"snapshots\": [\n"); 122 prog->RunAndPrintJson(out_stream);
200 bool is_first_snapshot = true; 123 fclose(out_stream);
201 for (; count > 0; count--) {
202 uint64_t missed = 0;
203 int res = read(g_timer, &missed, sizeof(missed));
204 if (res < 0 && errno == EBADF)
205 break; // Received SIGINT/SIGTERM signal.
206 CHECK(res > 0);
207 if (!is_first_snapshot)
208 fprintf(out_stream, ",");
209 is_first_snapshot = false;
210 124
211 std::unique_ptr<ProcessMap> procs =
212 CollectStatsForAllProcs(full_mem_stats, gpu_mem_stats);
213 SerializeSnapshot(*procs, out_stream, full_mem_stats, gpu_mem_stats);
214 fflush(out_stream);
215 }
216 fprintf(out_stream, "]}\n");
217 fclose(out_stream);
218 if (dump_to_file) 125 if (dump_to_file)
219 rename(tmp_file, out_file); 126 rename(tmp_file, out_file);
220 } 127 }
OLDNEW
« no previous file with comments | « systrace/atrace_helper/jni/logging.h ('k') | systrace/atrace_helper/jni/process_info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698