blob: b9ee0ef1a8db65b5deb2ae1ea5d674799164796e [file] [log] [blame]
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
John Reck40b26b42016-03-30 09:44:36 -070017 #define LOG_TAG "atrace"
18
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080019#include <errno.h>
20#include <fcntl.h>
21#include <getopt.h>
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -070022#include <inttypes.h>
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080023#include <signal.h>
24#include <stdarg.h>
25#include <stdbool.h>
26#include <stdio.h>
27#include <stdlib.h>
Elliott Hughes3da5d232015-01-25 08:35:20 -080028#include <string.h>
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080029#include <sys/sendfile.h>
30#include <time.h>
Martijn Coenend9535872015-11-26 10:00:55 +010031#include <unistd.h>
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080032#include <zlib.h>
33
34#include <binder/IBinder.h>
35#include <binder/IServiceManager.h>
36#include <binder/Parcel.h>
37
38#include <cutils/properties.h>
39
40#include <utils/String8.h>
John Reck469a1942015-03-26 15:31:35 -070041#include <utils/Timers.h>
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +090042#include <utils/Tokenizer.h>
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080043#include <utils/Trace.h>
Stephane Gasparinid8419c22016-03-02 13:45:15 +010044#include <android-base/file.h>
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080045
46using namespace android;
47
48#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
49
sergeyv4144eff2016-04-28 11:40:04 -070050#define MAX_SYS_FILES 10
51#define MAX_PACKAGES 16
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080052
53const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
sergeyv4144eff2016-04-28 11:40:04 -070054
55const char* k_traceAppsNumberProperty = "debug.atrace.app_number";
56const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d";
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080057
58typedef enum { OPT, REQ } requiredness ;
59
60struct TracingCategory {
61 // The name identifying the category.
62 const char* name;
63
64 // A longer description of the category.
65 const char* longname;
66
67 // The userland tracing tags that the category enables.
68 uint64_t tags;
69
70 // The fname==NULL terminated list of /sys/ files that the category
71 // enables.
72 struct {
73 // Whether the file must be writable in order to enable the tracing
74 // category.
75 requiredness required;
76
77 // The path to the enable file.
78 const char* path;
79 } sysfiles[MAX_SYS_FILES];
80};
81
82/* Tracing categories */
83static const TracingCategory k_categories[] = {
Jamie Gennisb2a89e32013-03-11 19:37:53 -070084 { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
85 { "input", "Input", ATRACE_TAG_INPUT, { } },
86 { "view", "View System", ATRACE_TAG_VIEW, { } },
87 { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
88 { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
89 { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
Patrick Auchter70ec2942014-09-30 15:38:30 -050090 { "sm", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -070091 { "audio", "Audio", ATRACE_TAG_AUDIO, { } },
92 { "video", "Video", ATRACE_TAG_VIDEO, { } },
93 { "camera", "Camera", ATRACE_TAG_CAMERA, { } },
94 { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
Jeff Brown3200b0b2014-08-14 19:24:47 -070095 { "app", "Application", ATRACE_TAG_APP, { } },
Dianne Hackborn9380d782013-04-12 14:52:35 -070096 { "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } },
Jamie Genniseff2e8d2013-05-07 15:20:39 -070097 { "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } },
Tim Murrayf0f28412013-05-23 14:39:42 -070098 { "rs", "RenderScript", ATRACE_TAG_RS, { } },
Brigid Smith750aa972014-05-28 14:23:24 -070099 { "bionic", "Bionic C Library", ATRACE_TAG_BIONIC, { } },
Jeff Brown3200b0b2014-08-14 19:24:47 -0700100 { "power", "Power Management", ATRACE_TAG_POWER, { } },
Todd Kennedy01e111b2015-07-31 14:36:20 -0700101 { "pm", "Package Manager", ATRACE_TAG_PACKAGE_MANAGER, { } },
Yasuhiro Matsuda7cc49772015-07-01 01:46:25 +0900102 { "ss", "System Server", ATRACE_TAG_SYSTEM_SERVER, { } },
Greg Hackmannbbd7d992014-12-01 14:43:34 -0800103 { "database", "Database", ATRACE_TAG_DATABASE, { } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700104 { "sched", "CPU Scheduling", 0, {
105 { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
106 { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
Riley Andrews5672bb72015-11-19 13:31:17 -0800107 { OPT, "/sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable" },
Ruchi Kandoicfe500d2015-11-23 13:47:20 -0800108 { OPT, "/sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800109 } },
Dan Willemsenf440d392014-04-11 15:44:09 -0700110 { "irq", "IRQ Events", 0, {
111 { REQ, "/sys/kernel/debug/tracing/events/irq/enable" },
Riley Andrews412e4f62015-11-02 21:01:34 -0800112 { OPT, "/sys/kernel/debug/tracing/events/ipi/enable" },
Dan Willemsenf440d392014-04-11 15:44:09 -0700113 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700114 { "freq", "CPU Frequency", 0, {
115 { REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
116 { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
Ruchi Kandoiffcc7112015-11-19 18:32:00 -0800117 { OPT, "/sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800118 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700119 { "membus", "Memory Bus Utilization", 0, {
120 { REQ, "/sys/kernel/debug/tracing/events/memory_bus/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800121 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700122 { "idle", "CPU Idle", 0, {
123 { REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800124 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700125 { "disk", "Disk I/O", 0, {
Greg Hackmanne80d32c2014-11-20 12:59:44 -0800126 { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" },
127 { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" },
128 { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" },
129 { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" },
130 { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" },
131 { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" },
132 { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
133 { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700134 { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
135 { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800136 } },
Ken Sumralld3fa5612013-07-03 12:32:03 -0700137 { "mmc", "eMMC commands", 0, {
138 { REQ, "/sys/kernel/debug/tracing/events/mmc/enable" },
139 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700140 { "load", "CPU Load", 0, {
141 { REQ, "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800142 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700143 { "sync", "Synchronization", 0, {
144 { REQ, "/sys/kernel/debug/tracing/events/sync/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800145 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700146 { "workq", "Kernel Workqueues", 0, {
147 { REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800148 } },
Colin Cross580407f2014-08-18 15:22:13 -0700149 { "memreclaim", "Kernel Memory Reclaim", 0, {
150 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
151 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
152 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
153 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
154 } },
Aaron Schulmanc2c6ecd2015-02-25 08:37:09 -0800155 { "regulators", "Voltage and Current Regulators", 0, {
156 { REQ, "/sys/kernel/debug/tracing/events/regulator/enable" },
157 } },
Scott Bauerae473362015-06-08 16:32:36 -0700158 { "binder_driver", "Binder Kernel driver", 0, {
159 { REQ, "/sys/kernel/debug/tracing/events/binder/binder_transaction/enable" },
160 { REQ, "/sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable" },
161 } },
162 { "binder_lock", "Binder global lock trace", 0, {
163 { REQ, "/sys/kernel/debug/tracing/events/binder/binder_lock/enable" },
164 { REQ, "/sys/kernel/debug/tracing/events/binder/binder_locked/enable" },
165 { REQ, "/sys/kernel/debug/tracing/events/binder/binder_unlock/enable" },
166 } },
Martijn Coenen70481612015-10-23 13:57:05 +0200167 { "pagecache", "Page cache", 0, {
168 { REQ, "/sys/kernel/debug/tracing/events/filemap/enable" },
169 } },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800170};
171
172/* Command line options */
173static int g_traceDurationSeconds = 5;
174static bool g_traceOverwrite = false;
175static int g_traceBufferSizeKB = 2048;
176static bool g_compress = false;
177static bool g_nohup = false;
178static int g_initialSleepSecs = 0;
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900179static const char* g_categoriesFile = NULL;
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700180static const char* g_kernelTraceFuncs = NULL;
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700181static const char* g_debugAppCmdLine = "";
John Reck40b26b42016-03-30 09:44:36 -0700182static const char* g_outputFile = nullptr;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800183
184/* Global state */
185static bool g_traceAborted = false;
186static bool g_categoryEnables[NELEM(k_categories)] = {};
187
188/* Sys file paths */
189static const char* k_traceClockPath =
190 "/sys/kernel/debug/tracing/trace_clock";
191
192static const char* k_traceBufferSizePath =
193 "/sys/kernel/debug/tracing/buffer_size_kb";
194
195static const char* k_tracingOverwriteEnablePath =
196 "/sys/kernel/debug/tracing/options/overwrite";
197
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700198static const char* k_currentTracerPath =
199 "/sys/kernel/debug/tracing/current_tracer";
200
201static const char* k_printTgidPath =
202 "/sys/kernel/debug/tracing/options/print-tgid";
203
204static const char* k_funcgraphAbsTimePath =
205 "/sys/kernel/debug/tracing/options/funcgraph-abstime";
206
207static const char* k_funcgraphCpuPath =
208 "/sys/kernel/debug/tracing/options/funcgraph-cpu";
209
210static const char* k_funcgraphProcPath =
211 "/sys/kernel/debug/tracing/options/funcgraph-proc";
212
213static const char* k_funcgraphFlatPath =
214 "/sys/kernel/debug/tracing/options/funcgraph-flat";
215
216static const char* k_funcgraphDurationPath =
217 "/sys/kernel/debug/tracing/options/funcgraph-duration";
218
219static const char* k_ftraceFilterPath =
220 "/sys/kernel/debug/tracing/set_ftrace_filter";
221
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800222static const char* k_tracingOnPath =
223 "/sys/kernel/debug/tracing/tracing_on";
224
225static const char* k_tracePath =
226 "/sys/kernel/debug/tracing/trace";
227
Martijn Coenend9535872015-11-26 10:00:55 +0100228static const char* k_traceStreamPath =
229 "/sys/kernel/debug/tracing/trace_pipe";
230
John Reck469a1942015-03-26 15:31:35 -0700231static const char* k_traceMarkerPath =
232 "/sys/kernel/debug/tracing/trace_marker";
233
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800234// Check whether a file exists.
235static bool fileExists(const char* filename) {
236 return access(filename, F_OK) != -1;
237}
238
239// Check whether a file is writable.
240static bool fileIsWritable(const char* filename) {
241 return access(filename, W_OK) != -1;
242}
243
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700244// Truncate a file.
245static bool truncateFile(const char* path)
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800246{
Jamie Gennis43122e72013-03-21 14:06:31 -0700247 // This uses creat rather than truncate because some of the debug kernel
248 // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
249 // calls to truncate, but they are cleared by calls to creat.
250 int traceFD = creat(path, 0);
251 if (traceFD == -1) {
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700252 fprintf(stderr, "error truncating %s: %s (%d)\n", path,
Jamie Gennis43122e72013-03-21 14:06:31 -0700253 strerror(errno), errno);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700254 return false;
255 }
256
Jamie Gennis43122e72013-03-21 14:06:31 -0700257 close(traceFD);
258
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700259 return true;
260}
261
262static bool _writeStr(const char* filename, const char* str, int flags)
263{
264 int fd = open(filename, flags);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800265 if (fd == -1) {
266 fprintf(stderr, "error opening %s: %s (%d)\n", filename,
267 strerror(errno), errno);
268 return false;
269 }
270
271 bool ok = true;
272 ssize_t len = strlen(str);
273 if (write(fd, str, len) != len) {
274 fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
275 strerror(errno), errno);
276 ok = false;
277 }
278
279 close(fd);
280
281 return ok;
282}
283
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700284// Write a string to a file, returning true if the write was successful.
285static bool writeStr(const char* filename, const char* str)
286{
287 return _writeStr(filename, str, O_WRONLY);
288}
289
290// Append a string to a file, returning true if the write was successful.
291static bool appendStr(const char* filename, const char* str)
292{
293 return _writeStr(filename, str, O_APPEND|O_WRONLY);
294}
295
John Reck469a1942015-03-26 15:31:35 -0700296static void writeClockSyncMarker()
297{
298 char buffer[128];
Martijn Coenen0bcd97a2015-07-15 14:25:23 +0200299 int len = 0;
300 int fd = open(k_traceMarkerPath, O_WRONLY);
301 if (fd == -1) {
302 fprintf(stderr, "error opening %s: %s (%d)\n", k_traceMarkerPath,
303 strerror(errno), errno);
304 return;
305 }
John Reck469a1942015-03-26 15:31:35 -0700306 float now_in_seconds = systemTime(CLOCK_MONOTONIC) / 1000000000.0f;
Martijn Coenen0bcd97a2015-07-15 14:25:23 +0200307
308 len = snprintf(buffer, 128, "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
309 if (write(fd, buffer, len) != len) {
310 fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
311 }
312
313 int64_t realtime_in_ms = systemTime(CLOCK_REALTIME) / 1000000;
314 len = snprintf(buffer, 128, "trace_event_clock_sync: realtime_ts=%" PRId64 "\n", realtime_in_ms);
315 if (write(fd, buffer, len) != len) {
316 fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
317 }
318
319 close(fd);
John Reck469a1942015-03-26 15:31:35 -0700320}
321
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800322// Enable or disable a kernel option by writing a "1" or a "0" into a /sys
323// file.
324static bool setKernelOptionEnable(const char* filename, bool enable)
325{
326 return writeStr(filename, enable ? "1" : "0");
327}
328
329// Check whether the category is supported on the device with the current
330// rootness. A category is supported only if all its required /sys/ files are
331// writable and if enabling the category will enable one or more tracing tags
332// or /sys/ files.
333static bool isCategorySupported(const TracingCategory& category)
334{
335 bool ok = category.tags != 0;
336 for (int i = 0; i < MAX_SYS_FILES; i++) {
337 const char* path = category.sysfiles[i].path;
338 bool req = category.sysfiles[i].required == REQ;
339 if (path != NULL) {
340 if (req) {
341 if (!fileIsWritable(path)) {
342 return false;
343 } else {
344 ok = true;
345 }
346 } else {
347 ok |= fileIsWritable(path);
348 }
349 }
350 }
351 return ok;
352}
353
354// Check whether the category would be supported on the device if the user
355// were root. This function assumes that root is able to write to any file
356// that exists. It performs the same logic as isCategorySupported, but it
357// uses file existance rather than writability in the /sys/ file checks.
358static bool isCategorySupportedForRoot(const TracingCategory& category)
359{
360 bool ok = category.tags != 0;
361 for (int i = 0; i < MAX_SYS_FILES; i++) {
362 const char* path = category.sysfiles[i].path;
363 bool req = category.sysfiles[i].required == REQ;
364 if (path != NULL) {
365 if (req) {
366 if (!fileExists(path)) {
367 return false;
368 } else {
369 ok = true;
370 }
371 } else {
372 ok |= fileExists(path);
373 }
374 }
375 }
376 return ok;
377}
378
379// Enable or disable overwriting of the kernel trace buffers. Disabling this
380// will cause tracing to stop once the trace buffers have filled up.
381static bool setTraceOverwriteEnable(bool enable)
382{
383 return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
384}
385
386// Enable or disable kernel tracing.
387static bool setTracingEnabled(bool enable)
388{
389 return setKernelOptionEnable(k_tracingOnPath, enable);
390}
391
392// Clear the contents of the kernel trace.
393static bool clearTrace()
394{
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700395 return truncateFile(k_tracePath);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800396}
397
398// Set the size of the kernel's trace buffer in kilobytes.
399static bool setTraceBufferSizeKB(int size)
400{
401 char str[32] = "1";
402 int len;
403 if (size < 1) {
404 size = 1;
405 }
406 snprintf(str, 32, "%d", size);
407 return writeStr(k_traceBufferSizePath, str);
408}
409
Colin Crossb1ce49b2014-08-20 14:28:47 -0700410// Read the trace_clock sysfs file and return true if it matches the requested
411// value. The trace_clock file format is:
412// local [global] counter uptime perf
413static bool isTraceClock(const char *mode)
414{
415 int fd = open(k_traceClockPath, O_RDONLY);
416 if (fd == -1) {
417 fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath,
418 strerror(errno), errno);
419 return false;
420 }
421
422 char buf[4097];
423 ssize_t n = read(fd, buf, 4096);
424 close(fd);
425 if (n == -1) {
426 fprintf(stderr, "error reading %s: %s (%d)\n", k_traceClockPath,
427 strerror(errno), errno);
428 return false;
429 }
430 buf[n] = '\0';
431
432 char *start = strchr(buf, '[');
433 if (start == NULL) {
434 return false;
435 }
436 start++;
437
438 char *end = strchr(start, ']');
439 if (end == NULL) {
440 return false;
441 }
442 *end = '\0';
443
444 return strcmp(mode, start) == 0;
445}
446
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800447// Enable or disable the kernel's use of the global clock. Disabling the global
448// clock will result in the kernel using a per-CPU local clock.
Colin Crossb1ce49b2014-08-20 14:28:47 -0700449// Any write to the trace_clock sysfs file will reset the buffer, so only
450// update it if the requested value is not the current value.
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800451static bool setGlobalClockEnable(bool enable)
452{
Colin Crossb1ce49b2014-08-20 14:28:47 -0700453 const char *clock = enable ? "global" : "local";
454
455 if (isTraceClock(clock)) {
456 return true;
457 }
458
459 return writeStr(k_traceClockPath, clock);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800460}
461
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700462static bool setPrintTgidEnableIfPresent(bool enable)
463{
464 if (fileExists(k_printTgidPath)) {
465 return setKernelOptionEnable(k_printTgidPath, enable);
466 }
467 return true;
468}
469
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800470// Poke all the binder-enabled processes in the system to get them to re-read
471// their system properties.
472static bool pokeBinderServices()
473{
474 sp<IServiceManager> sm = defaultServiceManager();
475 Vector<String16> services = sm->listServices();
476 for (size_t i = 0; i < services.size(); i++) {
477 sp<IBinder> obj = sm->checkService(services[i]);
478 if (obj != NULL) {
479 Parcel data;
480 if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
481 NULL, 0) != OK) {
482 if (false) {
483 // XXX: For some reason this fails on tablets trying to
484 // poke the "phone" service. It's not clear whether some
485 // are expected to fail.
486 String8 svc(services[i]);
487 fprintf(stderr, "error poking binder service %s\n",
488 svc.string());
489 return false;
490 }
491 }
492 }
493 }
494 return true;
495}
496
497// Set the trace tags that userland tracing uses, and poke the running
498// processes to pick up the new value.
499static bool setTagsProperty(uint64_t tags)
500{
sergeyv4144eff2016-04-28 11:40:04 -0700501 char buf[PROPERTY_VALUE_MAX];
502 snprintf(buf, sizeof(buf), "%#" PRIx64, tags);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800503 if (property_set(k_traceTagsProperty, buf) < 0) {
504 fprintf(stderr, "error setting trace tags system property\n");
505 return false;
506 }
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700507 return true;
508}
509
sergeyv4144eff2016-04-28 11:40:04 -0700510static void clearAppProperties()
511{
512 char buf[PROPERTY_KEY_MAX];
513 for (int i = 0; i < MAX_PACKAGES; i++) {
514 snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
515 if (property_set(buf, "") < 0) {
516 fprintf(stderr, "failed to clear system property: %s\n", buf);
517 }
518 }
519 if (property_set(k_traceAppsNumberProperty, "") < 0) {
520 fprintf(stderr, "failed to clear system property: %s",
521 k_traceAppsNumberProperty);
522 }
523}
524
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700525// Set the system property that indicates which apps should perform
526// application-level tracing.
527static bool setAppCmdlineProperty(const char* cmdline)
528{
sergeyv4144eff2016-04-28 11:40:04 -0700529 char buf[PROPERTY_KEY_MAX];
530 int i = 0;
531 const char* start = cmdline;
532 while (start != NULL) {
533 if (i == MAX_PACKAGES) {
534 fprintf(stderr, "error: only 16 packages could be traced at once\n");
535 clearAppProperties();
536 return false;
537 }
538 char* end = strchr(start, ',');
539 if (end != NULL) {
540 *end = '\0';
541 end++;
542 }
543 snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
544 if (property_set(buf, start) < 0) {
545 fprintf(stderr, "error setting trace app %d property to %s\n", i, buf);
546 clearAppProperties();
547 return false;
548 }
549 start = end;
550 i++;
551 }
552
553 snprintf(buf, sizeof(buf), "%d", i);
554 if (property_set(k_traceAppsNumberProperty, buf) < 0) {
555 fprintf(stderr, "error setting trace app number property to %s\n", buf);
556 clearAppProperties();
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700557 return false;
558 }
559 return true;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800560}
561
562// Disable all /sys/ enable files.
563static bool disableKernelTraceEvents() {
564 bool ok = true;
565 for (int i = 0; i < NELEM(k_categories); i++) {
566 const TracingCategory &c = k_categories[i];
567 for (int j = 0; j < MAX_SYS_FILES; j++) {
568 const char* path = c.sysfiles[j].path;
569 if (path != NULL && fileIsWritable(path)) {
570 ok &= setKernelOptionEnable(path, false);
571 }
572 }
573 }
574 return ok;
575}
576
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700577// Verify that the comma separated list of functions are being traced by the
578// kernel.
579static bool verifyKernelTraceFuncs(const char* funcs)
580{
Stephane Gasparinid8419c22016-03-02 13:45:15 +0100581 std::string buf;
582 if (!android::base::ReadFileToString(k_ftraceFilterPath, &buf)) {
583 fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700584 strerror(errno), errno);
Stephane Gasparinid8419c22016-03-02 13:45:15 +0100585 return false;
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700586 }
587
Stephane Gasparinid8419c22016-03-02 13:45:15 +0100588 String8 funcList = String8::format("\n%s",buf.c_str());
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700589
590 // Make sure that every function listed in funcs is in the list we just
Thomas Buhota2c22872016-01-27 09:44:31 +0100591 // read from the kernel, except for wildcard inputs.
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700592 bool ok = true;
593 char* myFuncs = strdup(funcs);
594 char* func = strtok(myFuncs, ",");
595 while (func) {
Thomas Buhota2c22872016-01-27 09:44:31 +0100596 if (!strchr(func, '*')) {
597 String8 fancyFunc = String8::format("\n%s\n", func);
598 bool found = funcList.find(fancyFunc.string(), 0) >= 0;
599 if (!found || func[0] == '\0') {
600 fprintf(stderr, "error: \"%s\" is not a valid kernel function "
601 "to trace.\n", func);
602 ok = false;
603 }
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700604 }
605 func = strtok(NULL, ",");
606 }
607 free(myFuncs);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700608 return ok;
609}
610
611// Set the comma separated list of functions that the kernel is to trace.
612static bool setKernelTraceFuncs(const char* funcs)
613{
614 bool ok = true;
615
616 if (funcs == NULL || funcs[0] == '\0') {
617 // Disable kernel function tracing.
Jamie Gennis6f6f3f72013-03-27 15:50:30 -0700618 if (fileIsWritable(k_currentTracerPath)) {
619 ok &= writeStr(k_currentTracerPath, "nop");
620 }
621 if (fileIsWritable(k_ftraceFilterPath)) {
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700622 ok &= truncateFile(k_ftraceFilterPath);
623 }
624 } else {
625 // Enable kernel function tracing.
626 ok &= writeStr(k_currentTracerPath, "function_graph");
627 ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
628 ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
629 ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
630 ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
631
632 // Set the requested filter functions.
633 ok &= truncateFile(k_ftraceFilterPath);
634 char* myFuncs = strdup(funcs);
635 char* func = strtok(myFuncs, ",");
636 while (func) {
637 ok &= appendStr(k_ftraceFilterPath, func);
638 func = strtok(NULL, ",");
639 }
640 free(myFuncs);
641
642 // Verify that the set functions are being traced.
643 if (ok) {
644 ok &= verifyKernelTraceFuncs(funcs);
645 }
646 }
647
648 return ok;
649}
650
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900651static bool setCategoryEnable(const char* name, bool enable)
652{
653 for (int i = 0; i < NELEM(k_categories); i++) {
654 const TracingCategory& c = k_categories[i];
655 if (strcmp(name, c.name) == 0) {
656 if (isCategorySupported(c)) {
657 g_categoryEnables[i] = enable;
658 return true;
659 } else {
660 if (isCategorySupportedForRoot(c)) {
661 fprintf(stderr, "error: category \"%s\" requires root "
662 "privileges.\n", name);
663 } else {
664 fprintf(stderr, "error: category \"%s\" is not supported "
665 "on this device.\n", name);
666 }
667 return false;
668 }
669 }
670 }
671 fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
672 return false;
673}
674
675static bool setCategoriesEnableFromFile(const char* categories_file)
676{
677 if (!categories_file) {
678 return true;
679 }
680 Tokenizer* tokenizer = NULL;
681 if (Tokenizer::open(String8(categories_file), &tokenizer) != NO_ERROR) {
682 return false;
683 }
684 bool ok = true;
685 while (!tokenizer->isEol()) {
686 String8 token = tokenizer->nextToken(" ");
687 if (token.isEmpty()) {
688 tokenizer->skipDelimiters(" ");
689 continue;
690 }
691 ok &= setCategoryEnable(token.string(), true);
692 }
693 delete tokenizer;
694 return ok;
695}
696
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700697// Set all the kernel tracing settings to the desired state for this trace
698// capture.
699static bool setUpTrace()
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800700{
701 bool ok = true;
702
703 // Set up the tracing options.
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900704 ok &= setCategoriesEnableFromFile(g_categoriesFile);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800705 ok &= setTraceOverwriteEnable(g_traceOverwrite);
706 ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
707 ok &= setGlobalClockEnable(true);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700708 ok &= setPrintTgidEnableIfPresent(true);
709 ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800710
711 // Set up the tags property.
712 uint64_t tags = 0;
713 for (int i = 0; i < NELEM(k_categories); i++) {
714 if (g_categoryEnables[i]) {
715 const TracingCategory &c = k_categories[i];
716 tags |= c.tags;
717 }
718 }
719 ok &= setTagsProperty(tags);
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700720 ok &= setAppCmdlineProperty(g_debugAppCmdLine);
721 ok &= pokeBinderServices();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800722
723 // Disable all the sysfs enables. This is done as a separate loop from
724 // the enables to allow the same enable to exist in multiple categories.
725 ok &= disableKernelTraceEvents();
726
727 // Enable all the sysfs enables that are in an enabled category.
728 for (int i = 0; i < NELEM(k_categories); i++) {
729 if (g_categoryEnables[i]) {
730 const TracingCategory &c = k_categories[i];
731 for (int j = 0; j < MAX_SYS_FILES; j++) {
732 const char* path = c.sysfiles[j].path;
733 bool required = c.sysfiles[j].required == REQ;
734 if (path != NULL) {
735 if (fileIsWritable(path)) {
736 ok &= setKernelOptionEnable(path, true);
737 } else if (required) {
738 fprintf(stderr, "error writing file %s\n", path);
739 ok = false;
740 }
741 }
742 }
743 }
744 }
745
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800746 return ok;
747}
748
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700749// Reset all the kernel tracing settings to their default state.
750static void cleanUpTrace()
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800751{
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800752 // Disable all tracing that we're able to.
753 disableKernelTraceEvents();
754
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700755 // Reset the system properties.
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800756 setTagsProperty(0);
sergeyv4144eff2016-04-28 11:40:04 -0700757 clearAppProperties();
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700758 pokeBinderServices();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800759
760 // Set the options back to their defaults.
761 setTraceOverwriteEnable(true);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700762 setTraceBufferSizeKB(1);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800763 setGlobalClockEnable(false);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700764 setPrintTgidEnableIfPresent(false);
765 setKernelTraceFuncs(NULL);
766}
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800767
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700768
769// Enable tracing in the kernel.
770static bool startTrace()
771{
772 return setTracingEnabled(true);
773}
774
775// Disable tracing in the kernel.
776static void stopTrace()
777{
778 setTracingEnabled(false);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800779}
780
Martijn Coenend9535872015-11-26 10:00:55 +0100781// Read data from the tracing pipe and forward to stdout
782static void streamTrace()
783{
784 char trace_data[4096];
785 int traceFD = open(k_traceStreamPath, O_RDWR);
786 if (traceFD == -1) {
787 fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath,
788 strerror(errno), errno);
789 return;
790 }
791 while (!g_traceAborted) {
792 ssize_t bytes_read = read(traceFD, trace_data, 4096);
793 if (bytes_read > 0) {
794 write(STDOUT_FILENO, trace_data, bytes_read);
795 fflush(stdout);
796 } else {
797 if (!g_traceAborted) {
798 fprintf(stderr, "read returned %zd bytes err %d (%s)\n",
799 bytes_read, errno, strerror(errno));
800 }
801 break;
802 }
803 }
804}
805
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800806// Read the current kernel trace and write it to stdout.
John Reck40b26b42016-03-30 09:44:36 -0700807static void dumpTrace(int outFd)
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800808{
John Reck6c8ac922016-03-28 11:25:30 -0700809 ALOGI("Dumping trace");
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800810 int traceFD = open(k_tracePath, O_RDWR);
811 if (traceFD == -1) {
812 fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
813 strerror(errno), errno);
814 return;
815 }
816
817 if (g_compress) {
818 z_stream zs;
819 uint8_t *in, *out;
820 int result, flush;
821
Elliott Hughes3da5d232015-01-25 08:35:20 -0800822 memset(&zs, 0, sizeof(zs));
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800823 result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
824 if (result != Z_OK) {
825 fprintf(stderr, "error initializing zlib: %d\n", result);
826 close(traceFD);
827 return;
828 }
829
830 const size_t bufSize = 64*1024;
831 in = (uint8_t*)malloc(bufSize);
832 out = (uint8_t*)malloc(bufSize);
833 flush = Z_NO_FLUSH;
834
835 zs.next_out = out;
836 zs.avail_out = bufSize;
837
838 do {
839
840 if (zs.avail_in == 0) {
841 // More input is needed.
842 result = read(traceFD, in, bufSize);
843 if (result < 0) {
844 fprintf(stderr, "error reading trace: %s (%d)\n",
845 strerror(errno), errno);
846 result = Z_STREAM_END;
847 break;
848 } else if (result == 0) {
849 flush = Z_FINISH;
850 } else {
851 zs.next_in = in;
852 zs.avail_in = result;
853 }
854 }
855
856 if (zs.avail_out == 0) {
857 // Need to write the output.
John Reck40b26b42016-03-30 09:44:36 -0700858 result = write(outFd, out, bufSize);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800859 if ((size_t)result < bufSize) {
860 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
861 strerror(errno), errno);
862 result = Z_STREAM_END; // skip deflate error message
863 zs.avail_out = bufSize; // skip the final write
864 break;
865 }
866 zs.next_out = out;
867 zs.avail_out = bufSize;
868 }
869
870 } while ((result = deflate(&zs, flush)) == Z_OK);
871
872 if (result != Z_STREAM_END) {
873 fprintf(stderr, "error deflating trace: %s\n", zs.msg);
874 }
875
876 if (zs.avail_out < bufSize) {
877 size_t bytes = bufSize - zs.avail_out;
John Reck40b26b42016-03-30 09:44:36 -0700878 result = write(outFd, out, bytes);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800879 if ((size_t)result < bytes) {
880 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
881 strerror(errno), errno);
882 }
883 }
884
885 result = deflateEnd(&zs);
886 if (result != Z_OK) {
887 fprintf(stderr, "error cleaning up zlib: %d\n", result);
888 }
889
890 free(in);
891 free(out);
892 } else {
893 ssize_t sent = 0;
John Reck40b26b42016-03-30 09:44:36 -0700894 while ((sent = sendfile(outFd, traceFD, NULL, 64*1024*1024)) > 0);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800895 if (sent == -1) {
896 fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
897 errno);
898 }
899 }
900
901 close(traceFD);
902}
903
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700904static void handleSignal(int /*signo*/)
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800905{
906 if (!g_nohup) {
907 g_traceAborted = true;
908 }
909}
910
911static void registerSigHandler()
912{
913 struct sigaction sa;
914 sigemptyset(&sa.sa_mask);
915 sa.sa_flags = 0;
916 sa.sa_handler = handleSignal;
917 sigaction(SIGHUP, &sa, NULL);
918 sigaction(SIGINT, &sa, NULL);
919 sigaction(SIGQUIT, &sa, NULL);
920 sigaction(SIGTERM, &sa, NULL);
921}
922
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800923static void listSupportedCategories()
924{
925 for (int i = 0; i < NELEM(k_categories); i++) {
926 const TracingCategory& c = k_categories[i];
927 if (isCategorySupported(c)) {
928 printf(" %10s - %s\n", c.name, c.longname);
929 }
930 }
931}
932
933// Print the command usage help to stderr.
934static void showHelp(const char *cmd)
935{
936 fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
937 fprintf(stderr, "options include:\n"
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700938 " -a appname enable app-level tracing for a comma "
939 "separated list of cmdlines\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800940 " -b N use a trace buffer size of N KB\n"
941 " -c trace into a circular buffer\n"
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900942 " -f filename use the categories written in a file as space-separated\n"
943 " values in a line\n"
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700944 " -k fname,... trace the listed kernel functions\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800945 " -n ignore signals\n"
946 " -s N sleep for N seconds before tracing [default 0]\n"
947 " -t N trace for N seconds [defualt 5]\n"
948 " -z compress the trace dump\n"
949 " --async_start start circular trace and return immediatly\n"
950 " --async_dump dump the current contents of circular trace buffer\n"
951 " --async_stop stop tracing and dump the current contents of circular\n"
952 " trace buffer\n"
Martijn Coenend9535872015-11-26 10:00:55 +0100953 " --stream stream trace to stdout as it enters the trace buffer\n"
954 " Note: this can take significant CPU time, and is best\n"
955 " used for measuring things that are not affected by\n"
956 " CPU performance, like pagecache usage.\n"
Jamie Gennis92573f12012-12-07 16:29:03 -0800957 " --list_categories\n"
958 " list the available tracing categories\n"
John Reck40b26b42016-03-30 09:44:36 -0700959 " -o filename write the trace to the specified file instead\n"
960 " of stdout.\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800961 );
962}
963
964int main(int argc, char **argv)
965{
966 bool async = false;
967 bool traceStart = true;
968 bool traceStop = true;
969 bool traceDump = true;
Martijn Coenend9535872015-11-26 10:00:55 +0100970 bool traceStream = false;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800971
972 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
973 showHelp(argv[0]);
974 exit(0);
975 }
976
977 for (;;) {
978 int ret;
979 int option_index = 0;
980 static struct option long_options[] = {
981 {"async_start", no_argument, 0, 0 },
982 {"async_stop", no_argument, 0, 0 },
983 {"async_dump", no_argument, 0, 0 },
984 {"list_categories", no_argument, 0, 0 },
Martijn Coenend9535872015-11-26 10:00:55 +0100985 {"stream", no_argument, 0, 0 },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800986 { 0, 0, 0, 0 }
987 };
988
John Reck40b26b42016-03-30 09:44:36 -0700989 ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800990 long_options, &option_index);
991
992 if (ret < 0) {
993 for (int i = optind; i < argc; i++) {
994 if (!setCategoryEnable(argv[i], true)) {
995 fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
996 exit(1);
997 }
998 }
999 break;
1000 }
1001
1002 switch(ret) {
Jamie Gennisf7f29c82013-03-27 15:50:58 -07001003 case 'a':
1004 g_debugAppCmdLine = optarg;
1005 break;
1006
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001007 case 'b':
1008 g_traceBufferSizeKB = atoi(optarg);
1009 break;
1010
1011 case 'c':
1012 g_traceOverwrite = true;
1013 break;
1014
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +09001015 case 'f':
1016 g_categoriesFile = optarg;
1017 break;
1018
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001019 case 'k':
1020 g_kernelTraceFuncs = optarg;
Jamie Gennis6f6f3f72013-03-27 15:50:30 -07001021 break;
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001022
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001023 case 'n':
1024 g_nohup = true;
Jamie Gennis6f6f3f72013-03-27 15:50:30 -07001025 break;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001026
1027 case 's':
1028 g_initialSleepSecs = atoi(optarg);
1029 break;
1030
1031 case 't':
1032 g_traceDurationSeconds = atoi(optarg);
1033 break;
1034
1035 case 'z':
1036 g_compress = true;
1037 break;
1038
John Reck40b26b42016-03-30 09:44:36 -07001039 case 'o':
1040 g_outputFile = optarg;
1041 break;
1042
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001043 case 0:
1044 if (!strcmp(long_options[option_index].name, "async_start")) {
1045 async = true;
1046 traceStop = false;
1047 traceDump = false;
1048 g_traceOverwrite = true;
1049 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
1050 async = true;
John Reck4ba2b632015-05-15 10:00:34 -07001051 traceStart = false;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001052 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
1053 async = true;
1054 traceStart = false;
1055 traceStop = false;
Martijn Coenend9535872015-11-26 10:00:55 +01001056 } else if (!strcmp(long_options[option_index].name, "stream")) {
1057 traceStream = true;
1058 traceDump = false;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001059 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
1060 listSupportedCategories();
1061 exit(0);
1062 }
Jamie Gennis6f6f3f72013-03-27 15:50:30 -07001063 break;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001064
1065 default:
1066 fprintf(stderr, "\n");
1067 showHelp(argv[0]);
1068 exit(-1);
1069 break;
1070 }
1071 }
1072
1073 registerSigHandler();
1074
1075 if (g_initialSleepSecs > 0) {
1076 sleep(g_initialSleepSecs);
1077 }
1078
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001079 bool ok = true;
1080 ok &= setUpTrace();
1081 ok &= startTrace();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001082
1083 if (ok && traceStart) {
Martijn Coenend9535872015-11-26 10:00:55 +01001084 if (!traceStream) {
1085 printf("capturing trace...");
1086 fflush(stdout);
1087 }
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001088
1089 // We clear the trace after starting it because tracing gets enabled for
1090 // each CPU individually in the kernel. Having the beginning of the trace
1091 // contain entries from only one CPU can cause "begin" entries without a
1092 // matching "end" entry to show up if a task gets migrated from one CPU to
1093 // another.
1094 ok = clearTrace();
1095
Martijn Coenen0bcd97a2015-07-15 14:25:23 +02001096 writeClockSyncMarker();
Martijn Coenend9535872015-11-26 10:00:55 +01001097 if (ok && !async && !traceStream) {
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001098 // Sleep to allow the trace to be captured.
1099 struct timespec timeLeft;
1100 timeLeft.tv_sec = g_traceDurationSeconds;
1101 timeLeft.tv_nsec = 0;
1102 do {
1103 if (g_traceAborted) {
1104 break;
1105 }
1106 } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
1107 }
Martijn Coenend9535872015-11-26 10:00:55 +01001108
1109 if (traceStream) {
1110 streamTrace();
1111 }
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001112 }
1113
1114 // Stop the trace and restore the default settings.
1115 if (traceStop)
1116 stopTrace();
1117
1118 if (ok && traceDump) {
1119 if (!g_traceAborted) {
John Reck40b26b42016-03-30 09:44:36 -07001120 printf(" done\n");
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001121 fflush(stdout);
John Reck40b26b42016-03-30 09:44:36 -07001122 int outFd = STDOUT_FILENO;
1123 if (g_outputFile) {
George Burgess IV48443342016-05-04 19:42:00 -07001124 outFd = open(g_outputFile, O_WRONLY | O_CREAT, 0644);
John Reck40b26b42016-03-30 09:44:36 -07001125 }
1126 if (outFd == -1) {
1127 printf("Failed to open '%s', err=%d", g_outputFile, errno);
1128 } else {
1129 dprintf(outFd, "TRACE:\n");
1130 dumpTrace(outFd);
1131 if (g_outputFile) {
1132 close(outFd);
1133 }
1134 }
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001135 } else {
1136 printf("\ntrace aborted.\n");
1137 fflush(stdout);
1138 }
1139 clearTrace();
1140 } else if (!ok) {
1141 fprintf(stderr, "unable to start tracing\n");
1142 }
1143
1144 // Reset the trace buffer size to 1.
1145 if (traceStop)
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001146 cleanUpTrace();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001147
1148 return g_traceAborted ? 1 : 0;
1149}