blob: 5885738e9d53098dc09efafeca6c76dc27a56a6f [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>
44
45using namespace android;
46
47#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
48
sergeyv4144eff2016-04-28 11:40:04 -070049#define MAX_SYS_FILES 10
50#define MAX_PACKAGES 16
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080051
52const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
sergeyv4144eff2016-04-28 11:40:04 -070053
54const char* k_traceAppsNumberProperty = "debug.atrace.app_number";
55const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d";
sergeyvdb404152016-05-02 19:26:07 -070056const char* k_coreServiceCategory = "core_services";
57const char* k_coreServicesProp = "ro.atrace.core.services";
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080058
59typedef enum { OPT, REQ } requiredness ;
60
61struct TracingCategory {
62 // The name identifying the category.
63 const char* name;
64
65 // A longer description of the category.
66 const char* longname;
67
68 // The userland tracing tags that the category enables.
69 uint64_t tags;
70
71 // The fname==NULL terminated list of /sys/ files that the category
72 // enables.
73 struct {
74 // Whether the file must be writable in order to enable the tracing
75 // category.
76 requiredness required;
77
78 // The path to the enable file.
79 const char* path;
80 } sysfiles[MAX_SYS_FILES];
81};
82
83/* Tracing categories */
84static const TracingCategory k_categories[] = {
Jamie Gennisb2a89e32013-03-11 19:37:53 -070085 { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
86 { "input", "Input", ATRACE_TAG_INPUT, { } },
87 { "view", "View System", ATRACE_TAG_VIEW, { } },
88 { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
89 { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
90 { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
Patrick Auchter70ec2942014-09-30 15:38:30 -050091 { "sm", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -070092 { "audio", "Audio", ATRACE_TAG_AUDIO, { } },
93 { "video", "Video", ATRACE_TAG_VIDEO, { } },
94 { "camera", "Camera", ATRACE_TAG_CAMERA, { } },
95 { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
Jeff Brown3200b0b2014-08-14 19:24:47 -070096 { "app", "Application", ATRACE_TAG_APP, { } },
Dianne Hackborn9380d782013-04-12 14:52:35 -070097 { "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } },
Jamie Genniseff2e8d2013-05-07 15:20:39 -070098 { "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } },
Tim Murrayf0f28412013-05-23 14:39:42 -070099 { "rs", "RenderScript", ATRACE_TAG_RS, { } },
Brigid Smith750aa972014-05-28 14:23:24 -0700100 { "bionic", "Bionic C Library", ATRACE_TAG_BIONIC, { } },
Jeff Brown3200b0b2014-08-14 19:24:47 -0700101 { "power", "Power Management", ATRACE_TAG_POWER, { } },
Todd Kennedy01e111b2015-07-31 14:36:20 -0700102 { "pm", "Package Manager", ATRACE_TAG_PACKAGE_MANAGER, { } },
Yasuhiro Matsuda7cc49772015-07-01 01:46:25 +0900103 { "ss", "System Server", ATRACE_TAG_SYSTEM_SERVER, { } },
Greg Hackmannbbd7d992014-12-01 14:43:34 -0800104 { "database", "Database", ATRACE_TAG_DATABASE, { } },
Felipe Leme0f97c1d2016-09-07 11:33:26 -0700105 { "network", "Network", ATRACE_TAG_NETWORK, { } },
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.
536static bool setAppCmdlineProperty(const char* cmdline)
537{
sergeyv4144eff2016-04-28 11:40:04 -0700538 char buf[PROPERTY_KEY_MAX];
539 int i = 0;
540 const char* start = cmdline;
541 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{
590 int fd = open(k_ftraceFilterPath, O_RDONLY);
591 if (fd == -1) {
592 fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
593 strerror(errno), errno);
594 return false;
595 }
596
597 char buf[4097];
598 ssize_t n = read(fd, buf, 4096);
599 close(fd);
600 if (n == -1) {
601 fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
602 strerror(errno), errno);
603 return false;
604 }
605
606 buf[n] = '\0';
607 String8 funcList = String8::format("\n%s", buf);
608
609 // Make sure that every function listed in funcs is in the list we just
Thomas Buhota2c22872016-01-27 09:44:31 +0100610 // read from the kernel, except for wildcard inputs.
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700611 bool ok = true;
612 char* myFuncs = strdup(funcs);
613 char* func = strtok(myFuncs, ",");
614 while (func) {
Thomas Buhota2c22872016-01-27 09:44:31 +0100615 if (!strchr(func, '*')) {
616 String8 fancyFunc = String8::format("\n%s\n", func);
617 bool found = funcList.find(fancyFunc.string(), 0) >= 0;
618 if (!found || func[0] == '\0') {
619 fprintf(stderr, "error: \"%s\" is not a valid kernel function "
620 "to trace.\n", func);
621 ok = false;
622 }
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700623 }
624 func = strtok(NULL, ",");
625 }
626 free(myFuncs);
627
628 return ok;
629}
630
631// Set the comma separated list of functions that the kernel is to trace.
632static bool setKernelTraceFuncs(const char* funcs)
633{
634 bool ok = true;
635
636 if (funcs == NULL || funcs[0] == '\0') {
637 // Disable kernel function tracing.
Jamie Gennis6f6f3f72013-03-27 15:50:30 -0700638 if (fileIsWritable(k_currentTracerPath)) {
639 ok &= writeStr(k_currentTracerPath, "nop");
640 }
641 if (fileIsWritable(k_ftraceFilterPath)) {
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700642 ok &= truncateFile(k_ftraceFilterPath);
643 }
644 } else {
645 // Enable kernel function tracing.
646 ok &= writeStr(k_currentTracerPath, "function_graph");
647 ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
648 ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
649 ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
650 ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
651
652 // Set the requested filter functions.
653 ok &= truncateFile(k_ftraceFilterPath);
654 char* myFuncs = strdup(funcs);
655 char* func = strtok(myFuncs, ",");
656 while (func) {
657 ok &= appendStr(k_ftraceFilterPath, func);
658 func = strtok(NULL, ",");
659 }
660 free(myFuncs);
661
662 // Verify that the set functions are being traced.
663 if (ok) {
664 ok &= verifyKernelTraceFuncs(funcs);
665 }
666 }
667
668 return ok;
669}
670
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900671static bool setCategoryEnable(const char* name, bool enable)
672{
673 for (int i = 0; i < NELEM(k_categories); i++) {
674 const TracingCategory& c = k_categories[i];
675 if (strcmp(name, c.name) == 0) {
676 if (isCategorySupported(c)) {
677 g_categoryEnables[i] = enable;
678 return true;
679 } else {
680 if (isCategorySupportedForRoot(c)) {
681 fprintf(stderr, "error: category \"%s\" requires root "
682 "privileges.\n", name);
683 } else {
684 fprintf(stderr, "error: category \"%s\" is not supported "
685 "on this device.\n", name);
686 }
687 return false;
688 }
689 }
690 }
691 fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
692 return false;
693}
694
695static bool setCategoriesEnableFromFile(const char* categories_file)
696{
697 if (!categories_file) {
698 return true;
699 }
700 Tokenizer* tokenizer = NULL;
701 if (Tokenizer::open(String8(categories_file), &tokenizer) != NO_ERROR) {
702 return false;
703 }
704 bool ok = true;
705 while (!tokenizer->isEol()) {
706 String8 token = tokenizer->nextToken(" ");
707 if (token.isEmpty()) {
708 tokenizer->skipDelimiters(" ");
709 continue;
710 }
711 ok &= setCategoryEnable(token.string(), true);
712 }
713 delete tokenizer;
714 return ok;
715}
716
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700717// Set all the kernel tracing settings to the desired state for this trace
718// capture.
719static bool setUpTrace()
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800720{
721 bool ok = true;
722
723 // Set up the tracing options.
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900724 ok &= setCategoriesEnableFromFile(g_categoriesFile);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800725 ok &= setTraceOverwriteEnable(g_traceOverwrite);
726 ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
727 ok &= setGlobalClockEnable(true);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700728 ok &= setPrintTgidEnableIfPresent(true);
729 ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800730
731 // Set up the tags property.
732 uint64_t tags = 0;
733 for (int i = 0; i < NELEM(k_categories); i++) {
734 if (g_categoryEnables[i]) {
735 const TracingCategory &c = k_categories[i];
736 tags |= c.tags;
737 }
738 }
739 ok &= setTagsProperty(tags);
sergeyvdb404152016-05-02 19:26:07 -0700740
741 bool coreServicesTagEnabled = false;
742 for (int i = 0; i < NELEM(k_categories); i++) {
743 if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
744 coreServicesTagEnabled = g_categoryEnables[i];
745 }
746 }
747
748 std::string packageList(g_debugAppCmdLine);
749 if (coreServicesTagEnabled) {
750 char value[PROPERTY_VALUE_MAX];
751 property_get(k_coreServicesProp, value, "");
752 if (!packageList.empty()) {
753 packageList += ",";
754 }
755 packageList += value;
756 }
757 ok &= setAppCmdlineProperty(packageList.data());
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700758 ok &= pokeBinderServices();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800759
760 // Disable all the sysfs enables. This is done as a separate loop from
761 // the enables to allow the same enable to exist in multiple categories.
762 ok &= disableKernelTraceEvents();
763
764 // Enable all the sysfs enables that are in an enabled category.
765 for (int i = 0; i < NELEM(k_categories); i++) {
766 if (g_categoryEnables[i]) {
767 const TracingCategory &c = k_categories[i];
768 for (int j = 0; j < MAX_SYS_FILES; j++) {
769 const char* path = c.sysfiles[j].path;
770 bool required = c.sysfiles[j].required == REQ;
771 if (path != NULL) {
772 if (fileIsWritable(path)) {
773 ok &= setKernelOptionEnable(path, true);
774 } else if (required) {
775 fprintf(stderr, "error writing file %s\n", path);
776 ok = false;
777 }
778 }
779 }
780 }
781 }
782
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800783 return ok;
784}
785
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700786// Reset all the kernel tracing settings to their default state.
787static void cleanUpTrace()
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800788{
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800789 // Disable all tracing that we're able to.
790 disableKernelTraceEvents();
791
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700792 // Reset the system properties.
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800793 setTagsProperty(0);
sergeyv4144eff2016-04-28 11:40:04 -0700794 clearAppProperties();
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700795 pokeBinderServices();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800796
797 // Set the options back to their defaults.
798 setTraceOverwriteEnable(true);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700799 setTraceBufferSizeKB(1);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800800 setGlobalClockEnable(false);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700801 setPrintTgidEnableIfPresent(false);
802 setKernelTraceFuncs(NULL);
803}
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800804
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700805
806// Enable tracing in the kernel.
807static bool startTrace()
808{
809 return setTracingEnabled(true);
810}
811
812// Disable tracing in the kernel.
813static void stopTrace()
814{
815 setTracingEnabled(false);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800816}
817
Martijn Coenend9535872015-11-26 10:00:55 +0100818// Read data from the tracing pipe and forward to stdout
819static void streamTrace()
820{
821 char trace_data[4096];
822 int traceFD = open(k_traceStreamPath, O_RDWR);
823 if (traceFD == -1) {
824 fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath,
825 strerror(errno), errno);
826 return;
827 }
828 while (!g_traceAborted) {
829 ssize_t bytes_read = read(traceFD, trace_data, 4096);
830 if (bytes_read > 0) {
831 write(STDOUT_FILENO, trace_data, bytes_read);
832 fflush(stdout);
833 } else {
834 if (!g_traceAborted) {
835 fprintf(stderr, "read returned %zd bytes err %d (%s)\n",
836 bytes_read, errno, strerror(errno));
837 }
838 break;
839 }
840 }
841}
842
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800843// Read the current kernel trace and write it to stdout.
John Reck40b26b42016-03-30 09:44:36 -0700844static void dumpTrace(int outFd)
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800845{
John Reck6c8ac922016-03-28 11:25:30 -0700846 ALOGI("Dumping trace");
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800847 int traceFD = open(k_tracePath, O_RDWR);
848 if (traceFD == -1) {
849 fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
850 strerror(errno), errno);
851 return;
852 }
853
854 if (g_compress) {
855 z_stream zs;
856 uint8_t *in, *out;
857 int result, flush;
858
Elliott Hughes3da5d232015-01-25 08:35:20 -0800859 memset(&zs, 0, sizeof(zs));
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800860 result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
861 if (result != Z_OK) {
862 fprintf(stderr, "error initializing zlib: %d\n", result);
863 close(traceFD);
864 return;
865 }
866
867 const size_t bufSize = 64*1024;
868 in = (uint8_t*)malloc(bufSize);
869 out = (uint8_t*)malloc(bufSize);
870 flush = Z_NO_FLUSH;
871
872 zs.next_out = out;
873 zs.avail_out = bufSize;
874
875 do {
876
877 if (zs.avail_in == 0) {
878 // More input is needed.
879 result = read(traceFD, in, bufSize);
880 if (result < 0) {
881 fprintf(stderr, "error reading trace: %s (%d)\n",
882 strerror(errno), errno);
883 result = Z_STREAM_END;
884 break;
885 } else if (result == 0) {
886 flush = Z_FINISH;
887 } else {
888 zs.next_in = in;
889 zs.avail_in = result;
890 }
891 }
892
893 if (zs.avail_out == 0) {
894 // Need to write the output.
John Reck40b26b42016-03-30 09:44:36 -0700895 result = write(outFd, out, bufSize);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800896 if ((size_t)result < bufSize) {
897 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
898 strerror(errno), errno);
899 result = Z_STREAM_END; // skip deflate error message
900 zs.avail_out = bufSize; // skip the final write
901 break;
902 }
903 zs.next_out = out;
904 zs.avail_out = bufSize;
905 }
906
907 } while ((result = deflate(&zs, flush)) == Z_OK);
908
909 if (result != Z_STREAM_END) {
910 fprintf(stderr, "error deflating trace: %s\n", zs.msg);
911 }
912
913 if (zs.avail_out < bufSize) {
914 size_t bytes = bufSize - zs.avail_out;
John Reck40b26b42016-03-30 09:44:36 -0700915 result = write(outFd, out, bytes);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800916 if ((size_t)result < bytes) {
917 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
918 strerror(errno), errno);
919 }
920 }
921
922 result = deflateEnd(&zs);
923 if (result != Z_OK) {
924 fprintf(stderr, "error cleaning up zlib: %d\n", result);
925 }
926
927 free(in);
928 free(out);
929 } else {
930 ssize_t sent = 0;
John Reck40b26b42016-03-30 09:44:36 -0700931 while ((sent = sendfile(outFd, traceFD, NULL, 64*1024*1024)) > 0);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800932 if (sent == -1) {
933 fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
934 errno);
935 }
936 }
937
938 close(traceFD);
939}
940
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700941static void handleSignal(int /*signo*/)
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800942{
943 if (!g_nohup) {
944 g_traceAborted = true;
945 }
946}
947
948static void registerSigHandler()
949{
950 struct sigaction sa;
951 sigemptyset(&sa.sa_mask);
952 sa.sa_flags = 0;
953 sa.sa_handler = handleSignal;
954 sigaction(SIGHUP, &sa, NULL);
955 sigaction(SIGINT, &sa, NULL);
956 sigaction(SIGQUIT, &sa, NULL);
957 sigaction(SIGTERM, &sa, NULL);
958}
959
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800960static void listSupportedCategories()
961{
962 for (int i = 0; i < NELEM(k_categories); i++) {
963 const TracingCategory& c = k_categories[i];
964 if (isCategorySupported(c)) {
965 printf(" %10s - %s\n", c.name, c.longname);
966 }
967 }
968}
969
970// Print the command usage help to stderr.
971static void showHelp(const char *cmd)
972{
973 fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
974 fprintf(stderr, "options include:\n"
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700975 " -a appname enable app-level tracing for a comma "
976 "separated list of cmdlines\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800977 " -b N use a trace buffer size of N KB\n"
978 " -c trace into a circular buffer\n"
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +0900979 " -f filename use the categories written in a file as space-separated\n"
980 " values in a line\n"
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700981 " -k fname,... trace the listed kernel functions\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800982 " -n ignore signals\n"
983 " -s N sleep for N seconds before tracing [default 0]\n"
984 " -t N trace for N seconds [defualt 5]\n"
985 " -z compress the trace dump\n"
986 " --async_start start circular trace and return immediatly\n"
987 " --async_dump dump the current contents of circular trace buffer\n"
988 " --async_stop stop tracing and dump the current contents of circular\n"
989 " trace buffer\n"
Martijn Coenend9535872015-11-26 10:00:55 +0100990 " --stream stream trace to stdout as it enters the trace buffer\n"
991 " Note: this can take significant CPU time, and is best\n"
992 " used for measuring things that are not affected by\n"
993 " CPU performance, like pagecache usage.\n"
Jamie Gennis92573f12012-12-07 16:29:03 -0800994 " --list_categories\n"
995 " list the available tracing categories\n"
John Reck40b26b42016-03-30 09:44:36 -0700996 " -o filename write the trace to the specified file instead\n"
997 " of stdout.\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800998 );
999}
1000
1001int main(int argc, char **argv)
1002{
1003 bool async = false;
1004 bool traceStart = true;
1005 bool traceStop = true;
1006 bool traceDump = true;
Martijn Coenend9535872015-11-26 10:00:55 +01001007 bool traceStream = false;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001008
1009 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
1010 showHelp(argv[0]);
1011 exit(0);
1012 }
1013
1014 for (;;) {
1015 int ret;
1016 int option_index = 0;
1017 static struct option long_options[] = {
1018 {"async_start", no_argument, 0, 0 },
1019 {"async_stop", no_argument, 0, 0 },
1020 {"async_dump", no_argument, 0, 0 },
1021 {"list_categories", no_argument, 0, 0 },
Martijn Coenend9535872015-11-26 10:00:55 +01001022 {"stream", no_argument, 0, 0 },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001023 { 0, 0, 0, 0 }
1024 };
1025
John Reck40b26b42016-03-30 09:44:36 -07001026 ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001027 long_options, &option_index);
1028
1029 if (ret < 0) {
1030 for (int i = optind; i < argc; i++) {
1031 if (!setCategoryEnable(argv[i], true)) {
1032 fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
1033 exit(1);
1034 }
1035 }
1036 break;
1037 }
1038
1039 switch(ret) {
Jamie Gennisf7f29c82013-03-27 15:50:58 -07001040 case 'a':
1041 g_debugAppCmdLine = optarg;
1042 break;
1043
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001044 case 'b':
1045 g_traceBufferSizeKB = atoi(optarg);
1046 break;
1047
1048 case 'c':
1049 g_traceOverwrite = true;
1050 break;
1051
Yasuhiro Matsuda46c51fb2015-06-29 19:20:39 +09001052 case 'f':
1053 g_categoriesFile = optarg;
1054 break;
1055
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001056 case 'k':
1057 g_kernelTraceFuncs = optarg;
Jamie Gennis6f6f3f72013-03-27 15:50:30 -07001058 break;
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001059
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001060 case 'n':
1061 g_nohup = true;
Jamie Gennis6f6f3f72013-03-27 15:50:30 -07001062 break;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001063
1064 case 's':
1065 g_initialSleepSecs = atoi(optarg);
1066 break;
1067
1068 case 't':
1069 g_traceDurationSeconds = atoi(optarg);
1070 break;
1071
1072 case 'z':
1073 g_compress = true;
1074 break;
1075
John Reck40b26b42016-03-30 09:44:36 -07001076 case 'o':
1077 g_outputFile = optarg;
1078 break;
1079
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001080 case 0:
1081 if (!strcmp(long_options[option_index].name, "async_start")) {
1082 async = true;
1083 traceStop = false;
1084 traceDump = false;
1085 g_traceOverwrite = true;
1086 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
1087 async = true;
John Reck4ba2b632015-05-15 10:00:34 -07001088 traceStart = false;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001089 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
1090 async = true;
1091 traceStart = false;
1092 traceStop = false;
Martijn Coenend9535872015-11-26 10:00:55 +01001093 } else if (!strcmp(long_options[option_index].name, "stream")) {
1094 traceStream = true;
1095 traceDump = false;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001096 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
1097 listSupportedCategories();
1098 exit(0);
1099 }
Jamie Gennis6f6f3f72013-03-27 15:50:30 -07001100 break;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001101
1102 default:
1103 fprintf(stderr, "\n");
1104 showHelp(argv[0]);
1105 exit(-1);
1106 break;
1107 }
1108 }
1109
1110 registerSigHandler();
1111
1112 if (g_initialSleepSecs > 0) {
1113 sleep(g_initialSleepSecs);
1114 }
1115
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001116 bool ok = true;
1117 ok &= setUpTrace();
1118 ok &= startTrace();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001119
1120 if (ok && traceStart) {
Martijn Coenend9535872015-11-26 10:00:55 +01001121 if (!traceStream) {
1122 printf("capturing trace...");
1123 fflush(stdout);
1124 }
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001125
1126 // We clear the trace after starting it because tracing gets enabled for
1127 // each CPU individually in the kernel. Having the beginning of the trace
1128 // contain entries from only one CPU can cause "begin" entries without a
1129 // matching "end" entry to show up if a task gets migrated from one CPU to
1130 // another.
1131 ok = clearTrace();
1132
Martijn Coenen0bcd97a2015-07-15 14:25:23 +02001133 writeClockSyncMarker();
Martijn Coenend9535872015-11-26 10:00:55 +01001134 if (ok && !async && !traceStream) {
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001135 // Sleep to allow the trace to be captured.
1136 struct timespec timeLeft;
1137 timeLeft.tv_sec = g_traceDurationSeconds;
1138 timeLeft.tv_nsec = 0;
1139 do {
1140 if (g_traceAborted) {
1141 break;
1142 }
1143 } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
1144 }
Martijn Coenend9535872015-11-26 10:00:55 +01001145
1146 if (traceStream) {
1147 streamTrace();
1148 }
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001149 }
1150
1151 // Stop the trace and restore the default settings.
1152 if (traceStop)
1153 stopTrace();
1154
1155 if (ok && traceDump) {
1156 if (!g_traceAborted) {
John Reck40b26b42016-03-30 09:44:36 -07001157 printf(" done\n");
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001158 fflush(stdout);
John Reck40b26b42016-03-30 09:44:36 -07001159 int outFd = STDOUT_FILENO;
1160 if (g_outputFile) {
1161 outFd = open(g_outputFile, O_WRONLY | O_CREAT);
1162 }
1163 if (outFd == -1) {
1164 printf("Failed to open '%s', err=%d", g_outputFile, errno);
1165 } else {
1166 dprintf(outFd, "TRACE:\n");
1167 dumpTrace(outFd);
1168 if (g_outputFile) {
1169 close(outFd);
1170 }
1171 }
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001172 } else {
1173 printf("\ntrace aborted.\n");
1174 fflush(stdout);
1175 }
1176 clearTrace();
1177 } else if (!ok) {
1178 fprintf(stderr, "unable to start tracing\n");
1179 }
1180
1181 // Reset the trace buffer size to 1.
1182 if (traceStop)
Jamie Gennise9b8cfb2013-03-12 16:00:10 -07001183 cleanUpTrace();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001184
1185 return g_traceAborted ? 1 : 0;
1186}