blob: 08eff9e2528c70fccfcd0f32ff312d28dbfaa462 [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";
sergeyvdb404152016-05-02 19:26:07 -070057const char* k_coreServiceCategory = "core_services";
58const char* k_coreServicesProp = "ro.atrace.core.services";
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080059
60typedef enum { OPT, REQ } requiredness ;
61
62struct TracingCategory {
63 // The name identifying the category.
64 const char* name;
65
66 // A longer description of the category.
67 const char* longname;
68
69 // The userland tracing tags that the category enables.
70 uint64_t tags;
71
72 // The fname==NULL terminated list of /sys/ files that the category
73 // enables.
74 struct {
75 // Whether the file must be writable in order to enable the tracing
76 // category.
77 requiredness required;
78
79 // The path to the enable file.
80 const char* path;
81 } sysfiles[MAX_SYS_FILES];
82};
83
84/* Tracing categories */
85static const TracingCategory k_categories[] = {
Jamie Gennisb2a89e32013-03-11 19:37:53 -070086 { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
87 { "input", "Input", ATRACE_TAG_INPUT, { } },
88 { "view", "View System", ATRACE_TAG_VIEW, { } },
89 { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
90 { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
91 { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
Patrick Auchter70ec2942014-09-30 15:38:30 -050092 { "sm", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -070093 { "audio", "Audio", ATRACE_TAG_AUDIO, { } },
94 { "video", "Video", ATRACE_TAG_VIDEO, { } },
95 { "camera", "Camera", ATRACE_TAG_CAMERA, { } },
96 { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
Jeff Brown3200b0b2014-08-14 19:24:47 -070097 { "app", "Application", ATRACE_TAG_APP, { } },
Dianne Hackborn9380d782013-04-12 14:52:35 -070098 { "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } },
Jamie Genniseff2e8d2013-05-07 15:20:39 -070099 { "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } },
Tim Murrayf0f28412013-05-23 14:39:42 -0700100 { "rs", "RenderScript", ATRACE_TAG_RS, { } },
Brigid Smith750aa972014-05-28 14:23:24 -0700101 { "bionic", "Bionic C Library", ATRACE_TAG_BIONIC, { } },
Jeff Brown3200b0b2014-08-14 19:24:47 -0700102 { "power", "Power Management", ATRACE_TAG_POWER, { } },
Todd Kennedy01e111b2015-07-31 14:36:20 -0700103 { "pm", "Package Manager", ATRACE_TAG_PACKAGE_MANAGER, { } },
Yasuhiro Matsuda7cc49772015-07-01 01:46:25 +0900104 { "ss", "System Server", ATRACE_TAG_SYSTEM_SERVER, { } },
Greg Hackmannbbd7d992014-12-01 14:43:34 -0800105 { "database", "Database", ATRACE_TAG_DATABASE, { } },
sergeyvdb404152016-05-02 19:26:07 -0700106 { k_coreServiceCategory, "Core services", 0, { } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700107 { "sched", "CPU Scheduling", 0, {
108 { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
109 { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
Riley Andrews5672bb72015-11-19 13:31:17 -0800110 { OPT, "/sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable" },
Ruchi Kandoicfe500d2015-11-23 13:47:20 -0800111 { OPT, "/sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800112 } },
Dan Willemsenf440d392014-04-11 15:44:09 -0700113 { "irq", "IRQ Events", 0, {
114 { REQ, "/sys/kernel/debug/tracing/events/irq/enable" },
Riley Andrews412e4f62015-11-02 21:01:34 -0800115 { OPT, "/sys/kernel/debug/tracing/events/ipi/enable" },
Dan Willemsenf440d392014-04-11 15:44:09 -0700116 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700117 { "freq", "CPU Frequency", 0, {
118 { REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
119 { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
Ruchi Kandoiffcc7112015-11-19 18:32:00 -0800120 { OPT, "/sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800121 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700122 { "membus", "Memory Bus Utilization", 0, {
123 { REQ, "/sys/kernel/debug/tracing/events/memory_bus/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800124 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700125 { "idle", "CPU Idle", 0, {
126 { REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800127 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700128 { "disk", "Disk I/O", 0, {
Greg Hackmanne80d32c2014-11-20 12:59:44 -0800129 { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" },
130 { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" },
131 { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" },
132 { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" },
133 { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" },
134 { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" },
135 { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
136 { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700137 { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
138 { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800139 } },
Ken Sumralld3fa5612013-07-03 12:32:03 -0700140 { "mmc", "eMMC commands", 0, {
141 { REQ, "/sys/kernel/debug/tracing/events/mmc/enable" },
142 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700143 { "load", "CPU Load", 0, {
144 { REQ, "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800145 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700146 { "sync", "Synchronization", 0, {
147 { REQ, "/sys/kernel/debug/tracing/events/sync/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800148 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700149 { "workq", "Kernel Workqueues", 0, {
150 { REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800151 } },
Colin Cross580407f2014-08-18 15:22:13 -0700152 { "memreclaim", "Kernel Memory Reclaim", 0, {
153 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
154 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
155 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
156 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
157 } },
Aaron Schulmanc2c6ecd2015-02-25 08:37:09 -0800158 { "regulators", "Voltage and Current Regulators", 0, {
159 { REQ, "/sys/kernel/debug/tracing/events/regulator/enable" },
160 } },
Scott Bauerae473362015-06-08 16:32:36 -0700161 { "binder_driver", "Binder Kernel driver", 0, {
162 { REQ, "/sys/kernel/debug/tracing/events/binder/binder_transaction/enable" },
163 { REQ, "/sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable" },
164 } },
165 { "binder_lock", "Binder global lock trace", 0, {
166 { REQ, "/sys/kernel/debug/tracing/events/binder/binder_lock/enable" },
167 { REQ, "/sys/kernel/debug/tracing/events/binder/binder_locked/enable" },
168 { REQ, "/sys/kernel/debug/tracing/events/binder/binder_unlock/enable" },
169 } },
Martijn Coenen70481612015-10-23 13:57:05 +0200170 { "pagecache", "Page cache", 0, {
171 { REQ, "/sys/kernel/debug/tracing/events/filemap/enable" },
172 } },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800173};
174
175/* Command line options */
176static int g_traceDurationSeconds = 5;
177static bool g_traceOverwrite = false;
178static int g_traceBufferSizeKB = 2048;
179static bool g_compress = false;
180static bool g_nohup = false;
181static int g_initialSleepSecs = 0;
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900182static const char* g_categoriesFile = NULL;
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700183static const char* g_kernelTraceFuncs = NULL;
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700184static const char* g_debugAppCmdLine = "";
John Reck40b26b42016-03-30 09:44:36 -0700185static const char* g_outputFile = nullptr;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800186
187/* Global state */
188static bool g_traceAborted = false;
189static bool g_categoryEnables[NELEM(k_categories)] = {};
190
191/* Sys file paths */
192static const char* k_traceClockPath =
193 "/sys/kernel/debug/tracing/trace_clock";
194
195static const char* k_traceBufferSizePath =
196 "/sys/kernel/debug/tracing/buffer_size_kb";
197
198static const char* k_tracingOverwriteEnablePath =
199 "/sys/kernel/debug/tracing/options/overwrite";
200
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700201static const char* k_currentTracerPath =
202 "/sys/kernel/debug/tracing/current_tracer";
203
204static const char* k_printTgidPath =
205 "/sys/kernel/debug/tracing/options/print-tgid";
206
207static const char* k_funcgraphAbsTimePath =
208 "/sys/kernel/debug/tracing/options/funcgraph-abstime";
209
210static const char* k_funcgraphCpuPath =
211 "/sys/kernel/debug/tracing/options/funcgraph-cpu";
212
213static const char* k_funcgraphProcPath =
214 "/sys/kernel/debug/tracing/options/funcgraph-proc";
215
216static const char* k_funcgraphFlatPath =
217 "/sys/kernel/debug/tracing/options/funcgraph-flat";
218
219static const char* k_funcgraphDurationPath =
220 "/sys/kernel/debug/tracing/options/funcgraph-duration";
221
222static const char* k_ftraceFilterPath =
223 "/sys/kernel/debug/tracing/set_ftrace_filter";
224
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800225static const char* k_tracingOnPath =
226 "/sys/kernel/debug/tracing/tracing_on";
227
228static const char* k_tracePath =
229 "/sys/kernel/debug/tracing/trace";
230
Martijn Coenend9535872015-11-26 10:00:55 +0100231static const char* k_traceStreamPath =
232 "/sys/kernel/debug/tracing/trace_pipe";
233
John Reck469a1942015-03-26 15:31:35 -0700234static const char* k_traceMarkerPath =
235 "/sys/kernel/debug/tracing/trace_marker";
236
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800237// Check whether a file exists.
238static bool fileExists(const char* filename) {
239 return access(filename, F_OK) != -1;
240}
241
242// Check whether a file is writable.
243static bool fileIsWritable(const char* filename) {
244 return access(filename, W_OK) != -1;
245}
246
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700247// Truncate a file.
248static bool truncateFile(const char* path)
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800249{
Jamie Gennis43122e72013-03-21 14:06:31 -0700250 // This uses creat rather than truncate because some of the debug kernel
251 // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
252 // calls to truncate, but they are cleared by calls to creat.
253 int traceFD = creat(path, 0);
254 if (traceFD == -1) {
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700255 fprintf(stderr, "error truncating %s: %s (%d)\n", path,
Jamie Gennis43122e72013-03-21 14:06:31 -0700256 strerror(errno), errno);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700257 return false;
258 }
259
Jamie Gennis43122e72013-03-21 14:06:31 -0700260 close(traceFD);
261
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700262 return true;
263}
264
265static bool _writeStr(const char* filename, const char* str, int flags)
266{
267 int fd = open(filename, flags);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800268 if (fd == -1) {
269 fprintf(stderr, "error opening %s: %s (%d)\n", filename,
270 strerror(errno), errno);
271 return false;
272 }
273
274 bool ok = true;
275 ssize_t len = strlen(str);
276 if (write(fd, str, len) != len) {
277 fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
278 strerror(errno), errno);
279 ok = false;
280 }
281
282 close(fd);
283
284 return ok;
285}
286
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700287// Write a string to a file, returning true if the write was successful.
288static bool writeStr(const char* filename, const char* str)
289{
290 return _writeStr(filename, str, O_WRONLY);
291}
292
293// Append a string to a file, returning true if the write was successful.
294static bool appendStr(const char* filename, const char* str)
295{
296 return _writeStr(filename, str, O_APPEND|O_WRONLY);
297}
298
John Reck469a1942015-03-26 15:31:35 -0700299static void writeClockSyncMarker()
300{
301 char buffer[128];
Martijn Coenen0bcd97a2015-07-15 14:25:23 +0200302 int len = 0;
303 int fd = open(k_traceMarkerPath, O_WRONLY);
304 if (fd == -1) {
305 fprintf(stderr, "error opening %s: %s (%d)\n", k_traceMarkerPath,
306 strerror(errno), errno);
307 return;
308 }
John Reck469a1942015-03-26 15:31:35 -0700309 float now_in_seconds = systemTime(CLOCK_MONOTONIC) / 1000000000.0f;
Martijn Coenen0bcd97a2015-07-15 14:25:23 +0200310
311 len = snprintf(buffer, 128, "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
312 if (write(fd, buffer, len) != len) {
313 fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
314 }
315
316 int64_t realtime_in_ms = systemTime(CLOCK_REALTIME) / 1000000;
317 len = snprintf(buffer, 128, "trace_event_clock_sync: realtime_ts=%" PRId64 "\n", realtime_in_ms);
318 if (write(fd, buffer, len) != len) {
319 fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
320 }
321
322 close(fd);
John Reck469a1942015-03-26 15:31:35 -0700323}
324
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800325// Enable or disable a kernel option by writing a "1" or a "0" into a /sys
326// file.
327static bool setKernelOptionEnable(const char* filename, bool enable)
328{
329 return writeStr(filename, enable ? "1" : "0");
330}
331
332// Check whether the category is supported on the device with the current
333// rootness. A category is supported only if all its required /sys/ files are
334// writable and if enabling the category will enable one or more tracing tags
335// or /sys/ files.
336static bool isCategorySupported(const TracingCategory& category)
337{
sergeyvdb404152016-05-02 19:26:07 -0700338 if (strcmp(category.name, k_coreServiceCategory) == 0) {
339 char value[PROPERTY_VALUE_MAX];
340 property_get(k_coreServicesProp, value, "");
341 return strlen(value) != 0;
342 }
343
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800344 bool ok = category.tags != 0;
345 for (int i = 0; i < MAX_SYS_FILES; i++) {
346 const char* path = category.sysfiles[i].path;
347 bool req = category.sysfiles[i].required == REQ;
348 if (path != NULL) {
349 if (req) {
350 if (!fileIsWritable(path)) {
351 return false;
352 } else {
353 ok = true;
354 }
355 } else {
356 ok |= fileIsWritable(path);
357 }
358 }
359 }
360 return ok;
361}
362
363// Check whether the category would be supported on the device if the user
364// were root. This function assumes that root is able to write to any file
365// that exists. It performs the same logic as isCategorySupported, but it
366// uses file existance rather than writability in the /sys/ file checks.
367static bool isCategorySupportedForRoot(const TracingCategory& category)
368{
369 bool ok = category.tags != 0;
370 for (int i = 0; i < MAX_SYS_FILES; i++) {
371 const char* path = category.sysfiles[i].path;
372 bool req = category.sysfiles[i].required == REQ;
373 if (path != NULL) {
374 if (req) {
375 if (!fileExists(path)) {
376 return false;
377 } else {
378 ok = true;
379 }
380 } else {
381 ok |= fileExists(path);
382 }
383 }
384 }
385 return ok;
386}
387
388// Enable or disable overwriting of the kernel trace buffers. Disabling this
389// will cause tracing to stop once the trace buffers have filled up.
390static bool setTraceOverwriteEnable(bool enable)
391{
392 return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
393}
394
395// Enable or disable kernel tracing.
396static bool setTracingEnabled(bool enable)
397{
398 return setKernelOptionEnable(k_tracingOnPath, enable);
399}
400
401// Clear the contents of the kernel trace.
402static bool clearTrace()
403{
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700404 return truncateFile(k_tracePath);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800405}
406
407// Set the size of the kernel's trace buffer in kilobytes.
408static bool setTraceBufferSizeKB(int size)
409{
410 char str[32] = "1";
411 int len;
412 if (size < 1) {
413 size = 1;
414 }
415 snprintf(str, 32, "%d", size);
416 return writeStr(k_traceBufferSizePath, str);
417}
418
Colin Crossb1ce49b2014-08-20 14:28:47 -0700419// Read the trace_clock sysfs file and return true if it matches the requested
420// value. The trace_clock file format is:
421// local [global] counter uptime perf
422static bool isTraceClock(const char *mode)
423{
424 int fd = open(k_traceClockPath, O_RDONLY);
425 if (fd == -1) {
426 fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath,
427 strerror(errno), errno);
428 return false;
429 }
430
431 char buf[4097];
432 ssize_t n = read(fd, buf, 4096);
433 close(fd);
434 if (n == -1) {
435 fprintf(stderr, "error reading %s: %s (%d)\n", k_traceClockPath,
436 strerror(errno), errno);
437 return false;
438 }
439 buf[n] = '\0';
440
441 char *start = strchr(buf, '[');
442 if (start == NULL) {
443 return false;
444 }
445 start++;
446
447 char *end = strchr(start, ']');
448 if (end == NULL) {
449 return false;
450 }
451 *end = '\0';
452
453 return strcmp(mode, start) == 0;
454}
455
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800456// Enable or disable the kernel's use of the global clock. Disabling the global
457// clock will result in the kernel using a per-CPU local clock.
Colin Crossb1ce49b2014-08-20 14:28:47 -0700458// Any write to the trace_clock sysfs file will reset the buffer, so only
459// update it if the requested value is not the current value.
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800460static bool setGlobalClockEnable(bool enable)
461{
Colin Crossb1ce49b2014-08-20 14:28:47 -0700462 const char *clock = enable ? "global" : "local";
463
464 if (isTraceClock(clock)) {
465 return true;
466 }
467
468 return writeStr(k_traceClockPath, clock);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800469}
470
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700471static bool setPrintTgidEnableIfPresent(bool enable)
472{
473 if (fileExists(k_printTgidPath)) {
474 return setKernelOptionEnable(k_printTgidPath, enable);
475 }
476 return true;
477}
478
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800479// Poke all the binder-enabled processes in the system to get them to re-read
480// their system properties.
481static bool pokeBinderServices()
482{
483 sp<IServiceManager> sm = defaultServiceManager();
484 Vector<String16> services = sm->listServices();
485 for (size_t i = 0; i < services.size(); i++) {
486 sp<IBinder> obj = sm->checkService(services[i]);
487 if (obj != NULL) {
488 Parcel data;
489 if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
490 NULL, 0) != OK) {
491 if (false) {
492 // XXX: For some reason this fails on tablets trying to
493 // poke the "phone" service. It's not clear whether some
494 // are expected to fail.
495 String8 svc(services[i]);
496 fprintf(stderr, "error poking binder service %s\n",
497 svc.string());
498 return false;
499 }
500 }
501 }
502 }
503 return true;
504}
505
506// Set the trace tags that userland tracing uses, and poke the running
507// processes to pick up the new value.
508static bool setTagsProperty(uint64_t tags)
509{
sergeyv4144eff2016-04-28 11:40:04 -0700510 char buf[PROPERTY_VALUE_MAX];
511 snprintf(buf, sizeof(buf), "%#" PRIx64, tags);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800512 if (property_set(k_traceTagsProperty, buf) < 0) {
513 fprintf(stderr, "error setting trace tags system property\n");
514 return false;
515 }
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700516 return true;
517}
518
sergeyv4144eff2016-04-28 11:40:04 -0700519static void clearAppProperties()
520{
521 char buf[PROPERTY_KEY_MAX];
522 for (int i = 0; i < MAX_PACKAGES; i++) {
523 snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
524 if (property_set(buf, "") < 0) {
525 fprintf(stderr, "failed to clear system property: %s\n", buf);
526 }
527 }
528 if (property_set(k_traceAppsNumberProperty, "") < 0) {
529 fprintf(stderr, "failed to clear system property: %s",
530 k_traceAppsNumberProperty);
531 }
532}
533
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700534// Set the system property that indicates which apps should perform
535// application-level tracing.
Dan Austin09a79872016-05-31 13:27:03 -0700536static bool setAppCmdlineProperty(char* cmdline)
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700537{
sergeyv4144eff2016-04-28 11:40:04 -0700538 char buf[PROPERTY_KEY_MAX];
539 int i = 0;
Dan Austin09a79872016-05-31 13:27:03 -0700540 char* start = cmdline;
sergeyv4144eff2016-04-28 11:40:04 -0700541 while (start != NULL) {
542 if (i == MAX_PACKAGES) {
543 fprintf(stderr, "error: only 16 packages could be traced at once\n");
544 clearAppProperties();
545 return false;
546 }
547 char* end = strchr(start, ',');
548 if (end != NULL) {
549 *end = '\0';
550 end++;
551 }
552 snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
553 if (property_set(buf, start) < 0) {
554 fprintf(stderr, "error setting trace app %d property to %s\n", i, buf);
555 clearAppProperties();
556 return false;
557 }
558 start = end;
559 i++;
560 }
561
562 snprintf(buf, sizeof(buf), "%d", i);
563 if (property_set(k_traceAppsNumberProperty, buf) < 0) {
564 fprintf(stderr, "error setting trace app number property to %s\n", buf);
565 clearAppProperties();
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700566 return false;
567 }
568 return true;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800569}
570
571// Disable all /sys/ enable files.
572static bool disableKernelTraceEvents() {
573 bool ok = true;
574 for (int i = 0; i < NELEM(k_categories); i++) {
575 const TracingCategory &c = k_categories[i];
576 for (int j = 0; j < MAX_SYS_FILES; j++) {
577 const char* path = c.sysfiles[j].path;
578 if (path != NULL && fileIsWritable(path)) {
579 ok &= setKernelOptionEnable(path, false);
580 }
581 }
582 }
583 return ok;
584}
585
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700586// Verify that the comma separated list of functions are being traced by the
587// kernel.
588static bool verifyKernelTraceFuncs(const char* funcs)
589{
Stephane Gasparinid8419c22016-03-02 13:45:15 +0100590 std::string buf;
591 if (!android::base::ReadFileToString(k_ftraceFilterPath, &buf)) {
592 fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700593 strerror(errno), errno);
Stephane Gasparinid8419c22016-03-02 13:45:15 +0100594 return false;
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700595 }
596
Stephane Gasparinid8419c22016-03-02 13:45:15 +0100597 String8 funcList = String8::format("\n%s",buf.c_str());
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700598
599 // Make sure that every function listed in funcs is in the list we just
Thomas Buhota2c22872016-01-27 09:44:31 +0100600 // read from the kernel, except for wildcard inputs.
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700601 bool ok = true;
602 char* myFuncs = strdup(funcs);
603 char* func = strtok(myFuncs, ",");
604 while (func) {
Thomas Buhota2c22872016-01-27 09:44:31 +0100605 if (!strchr(func, '*')) {
606 String8 fancyFunc = String8::format("\n%s\n", func);
607 bool found = funcList.find(fancyFunc.string(), 0) >= 0;
608 if (!found || func[0] == '\0') {
609 fprintf(stderr, "error: \"%s\" is not a valid kernel function "
610 "to trace.\n", func);
611 ok = false;
612 }
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700613 }
614 func = strtok(NULL, ",");
615 }
616 free(myFuncs);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700617 return ok;
618}
619
620// Set the comma separated list of functions that the kernel is to trace.
621static bool setKernelTraceFuncs(const char* funcs)
622{
623 bool ok = true;
624
625 if (funcs == NULL || funcs[0] == '\0') {
626 // Disable kernel function tracing.
Jamie Gennis6f6f3f72013-03-27 15:50:30 -0700627 if (fileIsWritable(k_currentTracerPath)) {
628 ok &= writeStr(k_currentTracerPath, "nop");
629 }
630 if (fileIsWritable(k_ftraceFilterPath)) {
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700631 ok &= truncateFile(k_ftraceFilterPath);
632 }
633 } else {
634 // Enable kernel function tracing.
635 ok &= writeStr(k_currentTracerPath, "function_graph");
636 ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
637 ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
638 ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
639 ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
640
641 // Set the requested filter functions.
642 ok &= truncateFile(k_ftraceFilterPath);
643 char* myFuncs = strdup(funcs);
644 char* func = strtok(myFuncs, ",");
645 while (func) {
646 ok &= appendStr(k_ftraceFilterPath, func);
647 func = strtok(NULL, ",");
648 }
649 free(myFuncs);
650
651 // Verify that the set functions are being traced.
652 if (ok) {
653 ok &= verifyKernelTraceFuncs(funcs);
654 }
655 }
656
657 return ok;
658}
659
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900660static bool setCategoryEnable(const char* name, bool enable)
661{
662 for (int i = 0; i < NELEM(k_categories); i++) {
663 const TracingCategory& c = k_categories[i];
664 if (strcmp(name, c.name) == 0) {
665 if (isCategorySupported(c)) {
666 g_categoryEnables[i] = enable;
667 return true;
668 } else {
669 if (isCategorySupportedForRoot(c)) {
670 fprintf(stderr, "error: category \"%s\" requires root "
671 "privileges.\n", name);
672 } else {
673 fprintf(stderr, "error: category \"%s\" is not supported "
674 "on this device.\n", name);
675 }
676 return false;
677 }
678 }
679 }
680 fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
681 return false;
682}
683
684static bool setCategoriesEnableFromFile(const char* categories_file)
685{
686 if (!categories_file) {
687 return true;
688 }
689 Tokenizer* tokenizer = NULL;
690 if (Tokenizer::open(String8(categories_file), &tokenizer) != NO_ERROR) {
691 return false;
692 }
693 bool ok = true;
694 while (!tokenizer->isEol()) {
695 String8 token = tokenizer->nextToken(" ");
696 if (token.isEmpty()) {
697 tokenizer->skipDelimiters(" ");
698 continue;
699 }
700 ok &= setCategoryEnable(token.string(), true);
701 }
702 delete tokenizer;
703 return ok;
704}
705
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700706// Set all the kernel tracing settings to the desired state for this trace
707// capture.
708static bool setUpTrace()
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800709{
710 bool ok = true;
711
712 // Set up the tracing options.
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900713 ok &= setCategoriesEnableFromFile(g_categoriesFile);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800714 ok &= setTraceOverwriteEnable(g_traceOverwrite);
715 ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
716 ok &= setGlobalClockEnable(true);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700717 ok &= setPrintTgidEnableIfPresent(true);
718 ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800719
720 // Set up the tags property.
721 uint64_t tags = 0;
722 for (int i = 0; i < NELEM(k_categories); i++) {
723 if (g_categoryEnables[i]) {
724 const TracingCategory &c = k_categories[i];
725 tags |= c.tags;
726 }
727 }
728 ok &= setTagsProperty(tags);
sergeyvdb404152016-05-02 19:26:07 -0700729
730 bool coreServicesTagEnabled = false;
731 for (int i = 0; i < NELEM(k_categories); i++) {
732 if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
733 coreServicesTagEnabled = g_categoryEnables[i];
734 }
735 }
736
737 std::string packageList(g_debugAppCmdLine);
738 if (coreServicesTagEnabled) {
739 char value[PROPERTY_VALUE_MAX];
740 property_get(k_coreServicesProp, value, "");
741 if (!packageList.empty()) {
742 packageList += ",";
743 }
744 packageList += value;
745 }
Dan Austin09a79872016-05-31 13:27:03 -0700746 ok &= setAppCmdlineProperty(&packageList[0]);
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700747 ok &= pokeBinderServices();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800748
749 // Disable all the sysfs enables. This is done as a separate loop from
750 // the enables to allow the same enable to exist in multiple categories.
751 ok &= disableKernelTraceEvents();
752
753 // Enable all the sysfs enables that are in an enabled category.
754 for (int i = 0; i < NELEM(k_categories); i++) {
755 if (g_categoryEnables[i]) {
756 const TracingCategory &c = k_categories[i];
757 for (int j = 0; j < MAX_SYS_FILES; j++) {
758 const char* path = c.sysfiles[j].path;
759 bool required = c.sysfiles[j].required == REQ;
760 if (path != NULL) {
761 if (fileIsWritable(path)) {
762 ok &= setKernelOptionEnable(path, true);
763 } else if (required) {
764 fprintf(stderr, "error writing file %s\n", path);
765 ok = false;
766 }
767 }
768 }
769 }
770 }
771
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800772 return ok;
773}
774
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700775// Reset all the kernel tracing settings to their default state.
776static void cleanUpTrace()
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800777{
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800778 // Disable all tracing that we're able to.
779 disableKernelTraceEvents();
780
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700781 // Reset the system properties.
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800782 setTagsProperty(0);
sergeyv4144eff2016-04-28 11:40:04 -0700783 clearAppProperties();
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700784 pokeBinderServices();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800785
786 // Set the options back to their defaults.
787 setTraceOverwriteEnable(true);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700788 setTraceBufferSizeKB(1);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800789 setGlobalClockEnable(false);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700790 setPrintTgidEnableIfPresent(false);
791 setKernelTraceFuncs(NULL);
792}
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800793
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700794
795// Enable tracing in the kernel.
796static bool startTrace()
797{
798 return setTracingEnabled(true);
799}
800
801// Disable tracing in the kernel.
802static void stopTrace()
803{
804 setTracingEnabled(false);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800805}
806
Martijn Coenend9535872015-11-26 10:00:55 +0100807// Read data from the tracing pipe and forward to stdout
808static void streamTrace()
809{
810 char trace_data[4096];
811 int traceFD = open(k_traceStreamPath, O_RDWR);
812 if (traceFD == -1) {
813 fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath,
814 strerror(errno), errno);
815 return;
816 }
817 while (!g_traceAborted) {
818 ssize_t bytes_read = read(traceFD, trace_data, 4096);
819 if (bytes_read > 0) {
820 write(STDOUT_FILENO, trace_data, bytes_read);
821 fflush(stdout);
822 } else {
823 if (!g_traceAborted) {
824 fprintf(stderr, "read returned %zd bytes err %d (%s)\n",
825 bytes_read, errno, strerror(errno));
826 }
827 break;
828 }
829 }
830}
831
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800832// Read the current kernel trace and write it to stdout.
John Reck40b26b42016-03-30 09:44:36 -0700833static void dumpTrace(int outFd)
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800834{
John Reck6c8ac922016-03-28 11:25:30 -0700835 ALOGI("Dumping trace");
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800836 int traceFD = open(k_tracePath, O_RDWR);
837 if (traceFD == -1) {
838 fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
839 strerror(errno), errno);
840 return;
841 }
842
843 if (g_compress) {
844 z_stream zs;
845 uint8_t *in, *out;
846 int result, flush;
847
Elliott Hughes3da5d232015-01-25 08:35:20 -0800848 memset(&zs, 0, sizeof(zs));
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800849 result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
850 if (result != Z_OK) {
851 fprintf(stderr, "error initializing zlib: %d\n", result);
852 close(traceFD);
853 return;
854 }
855
856 const size_t bufSize = 64*1024;
857 in = (uint8_t*)malloc(bufSize);
858 out = (uint8_t*)malloc(bufSize);
859 flush = Z_NO_FLUSH;
860
861 zs.next_out = out;
862 zs.avail_out = bufSize;
863
864 do {
865
866 if (zs.avail_in == 0) {
867 // More input is needed.
868 result = read(traceFD, in, bufSize);
869 if (result < 0) {
870 fprintf(stderr, "error reading trace: %s (%d)\n",
871 strerror(errno), errno);
872 result = Z_STREAM_END;
873 break;
874 } else if (result == 0) {
875 flush = Z_FINISH;
876 } else {
877 zs.next_in = in;
878 zs.avail_in = result;
879 }
880 }
881
882 if (zs.avail_out == 0) {
883 // Need to write the output.
John Reck40b26b42016-03-30 09:44:36 -0700884 result = write(outFd, out, bufSize);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800885 if ((size_t)result < bufSize) {
886 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
887 strerror(errno), errno);
888 result = Z_STREAM_END; // skip deflate error message
889 zs.avail_out = bufSize; // skip the final write
890 break;
891 }
892 zs.next_out = out;
893 zs.avail_out = bufSize;
894 }
895
896 } while ((result = deflate(&zs, flush)) == Z_OK);
897
898 if (result != Z_STREAM_END) {
899 fprintf(stderr, "error deflating trace: %s\n", zs.msg);
900 }
901
902 if (zs.avail_out < bufSize) {
903 size_t bytes = bufSize - zs.avail_out;
John Reck40b26b42016-03-30 09:44:36 -0700904 result = write(outFd, out, bytes);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800905 if ((size_t)result < bytes) {
906 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
907 strerror(errno), errno);
908 }
909 }
910
911 result = deflateEnd(&zs);
912 if (result != Z_OK) {
913 fprintf(stderr, "error cleaning up zlib: %d\n", result);
914 }
915
916 free(in);
917 free(out);
918 } else {
919 ssize_t sent = 0;
John Reck40b26b42016-03-30 09:44:36 -0700920 while ((sent = sendfile(outFd, traceFD, NULL, 64*1024*1024)) > 0);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800921 if (sent == -1) {
922 fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
923 errno);
924 }
925 }
926
927 close(traceFD);
928}
929
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700930static void handleSignal(int /*signo*/)
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800931{
932 if (!g_nohup) {
933 g_traceAborted = true;
934 }
935}
936
937static void registerSigHandler()
938{
939 struct sigaction sa;
940 sigemptyset(&sa.sa_mask);
941 sa.sa_flags = 0;
942 sa.sa_handler = handleSignal;
943 sigaction(SIGHUP, &sa, NULL);
944 sigaction(SIGINT, &sa, NULL);
945 sigaction(SIGQUIT, &sa, NULL);
946 sigaction(SIGTERM, &sa, NULL);
947}
948
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800949static void listSupportedCategories()
950{
951 for (int i = 0; i < NELEM(k_categories); i++) {
952 const TracingCategory& c = k_categories[i];
953 if (isCategorySupported(c)) {
954 printf(" %10s - %s\n", c.name, c.longname);
955 }
956 }
957}
958
959// Print the command usage help to stderr.
960static void showHelp(const char *cmd)
961{
962 fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
963 fprintf(stderr, "options include:\n"
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700964 " -a appname enable app-level tracing for a comma "
965 "separated list of cmdlines\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800966 " -b N use a trace buffer size of N KB\n"
967 " -c trace into a circular buffer\n"
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900968 " -f filename use the categories written in a file as space-separated\n"
969 " values in a line\n"
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700970 " -k fname,... trace the listed kernel functions\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800971 " -n ignore signals\n"
972 " -s N sleep for N seconds before tracing [default 0]\n"
973 " -t N trace for N seconds [defualt 5]\n"
974 " -z compress the trace dump\n"
975 " --async_start start circular trace and return immediatly\n"
976 " --async_dump dump the current contents of circular trace buffer\n"
977 " --async_stop stop tracing and dump the current contents of circular\n"
978 " trace buffer\n"
Martijn Coenend9535872015-11-26 10:00:55 +0100979 " --stream stream trace to stdout as it enters the trace buffer\n"
980 " Note: this can take significant CPU time, and is best\n"
981 " used for measuring things that are not affected by\n"
982 " CPU performance, like pagecache usage.\n"
Jamie Gennis92573f12012-12-07 16:29:03 -0800983 " --list_categories\n"
984 " list the available tracing categories\n"
John Reck40b26b42016-03-30 09:44:36 -0700985 " -o filename write the trace to the specified file instead\n"
986 " of stdout.\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800987 );
988}
989
990int main(int argc, char **argv)
991{
992 bool async = false;
993 bool traceStart = true;
994 bool traceStop = true;
995 bool traceDump = true;
Martijn Coenend9535872015-11-26 10:00:55 +0100996 bool traceStream = false;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800997
998 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
999 showHelp(argv[0]);
1000 exit(0);
1001 }
1002
1003 for (;;) {
1004 int ret;
1005 int option_index = 0;
1006 static struct option long_options[] = {
1007 {"async_start", no_argument, 0, 0 },
1008 {"async_stop", no_argument, 0, 0 },
1009 {"async_dump", no_argument, 0, 0 },
1010 {"list_categories", no_argument, 0, 0 },
Martijn Coenend9535872015-11-26 10:00:55 +01001011 {"stream", no_argument, 0, 0 },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001012 { 0, 0, 0, 0 }
1013 };
1014
John Reck40b26b42016-03-30 09:44:36 -07001015 ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001016 long_options, &option_index);
1017
1018 if (ret < 0) {
1019 for (int i = optind; i < argc; i++) {
1020 if (!setCategoryEnable(argv[i], true)) {
1021 fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
1022 exit(1);
1023 }
1024 }
1025 break;
1026 }
1027
1028 switch(ret) {
Jamie Gennisf7f29c82013-03-27 15:50:58 -07001029 case 'a':
1030 g_debugAppCmdLine = optarg;
1031 break;
1032
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001033 case 'b':
1034 g_traceBufferSizeKB = atoi(optarg);
1035 break;
1036
1037 case 'c':
1038 g_traceOverwrite = true;
1039 break;
1040
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +09001041 case 'f':
1042 g_categoriesFile = optarg;
1043 break;
1044
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001045 case 'k':
1046 g_kernelTraceFuncs = optarg;
Jamie Gennis6f6f3f72013-03-27 15:50:30 -07001047 break;
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001048
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001049 case 'n':
1050 g_nohup = true;
Jamie Gennis6f6f3f72013-03-27 15:50:30 -07001051 break;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001052
1053 case 's':
1054 g_initialSleepSecs = atoi(optarg);
1055 break;
1056
1057 case 't':
1058 g_traceDurationSeconds = atoi(optarg);
1059 break;
1060
1061 case 'z':
1062 g_compress = true;
1063 break;
1064
John Reck40b26b42016-03-30 09:44:36 -07001065 case 'o':
1066 g_outputFile = optarg;
1067 break;
1068
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001069 case 0:
1070 if (!strcmp(long_options[option_index].name, "async_start")) {
1071 async = true;
1072 traceStop = false;
1073 traceDump = false;
1074 g_traceOverwrite = true;
1075 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
1076 async = true;
John Reck4ba2b632015-05-15 10:00:34 -07001077 traceStart = false;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001078 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
1079 async = true;
1080 traceStart = false;
1081 traceStop = false;
Martijn Coenend9535872015-11-26 10:00:55 +01001082 } else if (!strcmp(long_options[option_index].name, "stream")) {
1083 traceStream = true;
1084 traceDump = false;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001085 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
1086 listSupportedCategories();
1087 exit(0);
1088 }
Jamie Gennis6f6f3f72013-03-27 15:50:30 -07001089 break;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001090
1091 default:
1092 fprintf(stderr, "\n");
1093 showHelp(argv[0]);
1094 exit(-1);
1095 break;
1096 }
1097 }
1098
1099 registerSigHandler();
1100
1101 if (g_initialSleepSecs > 0) {
1102 sleep(g_initialSleepSecs);
1103 }
1104
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001105 bool ok = true;
1106 ok &= setUpTrace();
1107 ok &= startTrace();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001108
1109 if (ok && traceStart) {
Martijn Coenend9535872015-11-26 10:00:55 +01001110 if (!traceStream) {
1111 printf("capturing trace...");
1112 fflush(stdout);
1113 }
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001114
1115 // We clear the trace after starting it because tracing gets enabled for
1116 // each CPU individually in the kernel. Having the beginning of the trace
1117 // contain entries from only one CPU can cause "begin" entries without a
1118 // matching "end" entry to show up if a task gets migrated from one CPU to
1119 // another.
1120 ok = clearTrace();
1121
Martijn Coenen0bcd97a2015-07-15 14:25:23 +02001122 writeClockSyncMarker();
Martijn Coenend9535872015-11-26 10:00:55 +01001123 if (ok && !async && !traceStream) {
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001124 // Sleep to allow the trace to be captured.
1125 struct timespec timeLeft;
1126 timeLeft.tv_sec = g_traceDurationSeconds;
1127 timeLeft.tv_nsec = 0;
1128 do {
1129 if (g_traceAborted) {
1130 break;
1131 }
1132 } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
1133 }
Martijn Coenend9535872015-11-26 10:00:55 +01001134
1135 if (traceStream) {
1136 streamTrace();
1137 }
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001138 }
1139
1140 // Stop the trace and restore the default settings.
1141 if (traceStop)
1142 stopTrace();
1143
1144 if (ok && traceDump) {
1145 if (!g_traceAborted) {
John Reck40b26b42016-03-30 09:44:36 -07001146 printf(" done\n");
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001147 fflush(stdout);
John Reck40b26b42016-03-30 09:44:36 -07001148 int outFd = STDOUT_FILENO;
1149 if (g_outputFile) {
George Burgess IV48443342016-05-04 19:42:00 -07001150 outFd = open(g_outputFile, O_WRONLY | O_CREAT, 0644);
John Reck40b26b42016-03-30 09:44:36 -07001151 }
1152 if (outFd == -1) {
1153 printf("Failed to open '%s', err=%d", g_outputFile, errno);
1154 } else {
1155 dprintf(outFd, "TRACE:\n");
1156 dumpTrace(outFd);
1157 if (g_outputFile) {
1158 close(outFd);
1159 }
1160 }
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001161 } else {
1162 printf("\ntrace aborted.\n");
1163 fflush(stdout);
1164 }
1165 clearTrace();
1166 } else if (!ok) {
1167 fprintf(stderr, "unable to start tracing\n");
1168 }
1169
1170 // Reset the trace buffer size to 1.
1171 if (traceStop)
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001172 cleanUpTrace();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001173
1174 return g_traceAborted ? 1 : 0;
1175}