2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <sys/sendfile.h>
29 #include <binder/IBinder.h>
30 #include <binder/IServiceManager.h>
31 #include <binder/Parcel.h>
33 #include <cutils/properties.h>
35 #include <utils/String8.h>
36 #include <utils/Trace.h>
38 using namespace android;
40 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
42 enum { MAX_SYS_FILES = 8 };
44 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
45 const char* k_traceAppCmdlineProperty = "debug.atrace.app_cmdlines";
47 typedef enum { OPT, REQ } requiredness ;
49 struct TracingCategory {
50 // The name identifying the category.
53 // A longer description of the category.
56 // The userland tracing tags that the category enables.
59 // The fname==NULL terminated list of /sys/ files that the category
62 // Whether the file must be writable in order to enable the tracing
64 requiredness required;
66 // The path to the enable file.
68 } sysfiles[MAX_SYS_FILES];
71 /* Tracing categories */
72 static const TracingCategory k_categories[] = {
73 { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
74 { "input", "Input", ATRACE_TAG_INPUT, { } },
75 { "view", "View System", ATRACE_TAG_VIEW, { } },
76 { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
77 { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
78 { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
79 { "audio", "Audio", ATRACE_TAG_AUDIO, { } },
80 { "video", "Video", ATRACE_TAG_VIDEO, { } },
81 { "camera", "Camera", ATRACE_TAG_CAMERA, { } },
82 { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
83 { "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } },
84 { "sched", "CPU Scheduling", 0, {
85 { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
86 { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
88 { "freq", "CPU Frequency", 0, {
89 { REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
90 { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
92 { "membus", "Memory Bus Utilization", 0, {
93 { REQ, "/sys/kernel/debug/tracing/events/memory_bus/enable" },
95 { "idle", "CPU Idle", 0, {
96 { REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
98 { "disk", "Disk I/O", 0, {
99 { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
100 { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
101 { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
102 { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
104 { "load", "CPU Load", 0, {
105 { REQ, "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
107 { "sync", "Synchronization", 0, {
108 { REQ, "/sys/kernel/debug/tracing/events/sync/enable" },
110 { "workq", "Kernel Workqueues", 0, {
111 { REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" },
115 /* Command line options */
116 static int g_traceDurationSeconds = 5;
117 static bool g_traceOverwrite = false;
118 static int g_traceBufferSizeKB = 2048;
119 static bool g_compress = false;
120 static bool g_nohup = false;
121 static int g_initialSleepSecs = 0;
122 static const char* g_kernelTraceFuncs = NULL;
123 static const char* g_debugAppCmdLine = "";
126 static bool g_traceAborted = false;
127 static bool g_categoryEnables[NELEM(k_categories)] = {};
130 static const char* k_traceClockPath =
131 "/sys/kernel/debug/tracing/trace_clock";
133 static const char* k_traceBufferSizePath =
134 "/sys/kernel/debug/tracing/buffer_size_kb";
136 static const char* k_tracingOverwriteEnablePath =
137 "/sys/kernel/debug/tracing/options/overwrite";
139 static const char* k_currentTracerPath =
140 "/sys/kernel/debug/tracing/current_tracer";
142 static const char* k_printTgidPath =
143 "/sys/kernel/debug/tracing/options/print-tgid";
145 static const char* k_funcgraphAbsTimePath =
146 "/sys/kernel/debug/tracing/options/funcgraph-abstime";
148 static const char* k_funcgraphCpuPath =
149 "/sys/kernel/debug/tracing/options/funcgraph-cpu";
151 static const char* k_funcgraphProcPath =
152 "/sys/kernel/debug/tracing/options/funcgraph-proc";
154 static const char* k_funcgraphFlatPath =
155 "/sys/kernel/debug/tracing/options/funcgraph-flat";
157 static const char* k_funcgraphDurationPath =
158 "/sys/kernel/debug/tracing/options/funcgraph-duration";
160 static const char* k_ftraceFilterPath =
161 "/sys/kernel/debug/tracing/set_ftrace_filter";
163 static const char* k_tracingOnPath =
164 "/sys/kernel/debug/tracing/tracing_on";
166 static const char* k_tracePath =
167 "/sys/kernel/debug/tracing/trace";
169 // Check whether a file exists.
170 static bool fileExists(const char* filename) {
171 return access(filename, F_OK) != -1;
174 // Check whether a file is writable.
175 static bool fileIsWritable(const char* filename) {
176 return access(filename, W_OK) != -1;
180 static bool truncateFile(const char* path)
182 // This uses creat rather than truncate because some of the debug kernel
183 // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
184 // calls to truncate, but they are cleared by calls to creat.
185 int traceFD = creat(path, 0);
187 fprintf(stderr, "error truncating %s: %s (%d)\n", path,
188 strerror(errno), errno);
197 static bool _writeStr(const char* filename, const char* str, int flags)
199 int fd = open(filename, flags);
201 fprintf(stderr, "error opening %s: %s (%d)\n", filename,
202 strerror(errno), errno);
207 ssize_t len = strlen(str);
208 if (write(fd, str, len) != len) {
209 fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
210 strerror(errno), errno);
219 // Write a string to a file, returning true if the write was successful.
220 static bool writeStr(const char* filename, const char* str)
222 return _writeStr(filename, str, O_WRONLY);
225 // Append a string to a file, returning true if the write was successful.
226 static bool appendStr(const char* filename, const char* str)
228 return _writeStr(filename, str, O_APPEND|O_WRONLY);
231 // Enable or disable a kernel option by writing a "1" or a "0" into a /sys
233 static bool setKernelOptionEnable(const char* filename, bool enable)
235 return writeStr(filename, enable ? "1" : "0");
238 // Check whether the category is supported on the device with the current
239 // rootness. A category is supported only if all its required /sys/ files are
240 // writable and if enabling the category will enable one or more tracing tags
242 static bool isCategorySupported(const TracingCategory& category)
244 bool ok = category.tags != 0;
245 for (int i = 0; i < MAX_SYS_FILES; i++) {
246 const char* path = category.sysfiles[i].path;
247 bool req = category.sysfiles[i].required == REQ;
250 if (!fileIsWritable(path)) {
256 ok |= fileIsWritable(path);
263 // Check whether the category would be supported on the device if the user
264 // were root. This function assumes that root is able to write to any file
265 // that exists. It performs the same logic as isCategorySupported, but it
266 // uses file existance rather than writability in the /sys/ file checks.
267 static bool isCategorySupportedForRoot(const TracingCategory& category)
269 bool ok = category.tags != 0;
270 for (int i = 0; i < MAX_SYS_FILES; i++) {
271 const char* path = category.sysfiles[i].path;
272 bool req = category.sysfiles[i].required == REQ;
275 if (!fileExists(path)) {
281 ok |= fileExists(path);
288 // Enable or disable overwriting of the kernel trace buffers. Disabling this
289 // will cause tracing to stop once the trace buffers have filled up.
290 static bool setTraceOverwriteEnable(bool enable)
292 return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
295 // Enable or disable kernel tracing.
296 static bool setTracingEnabled(bool enable)
298 return setKernelOptionEnable(k_tracingOnPath, enable);
301 // Clear the contents of the kernel trace.
302 static bool clearTrace()
304 return truncateFile(k_tracePath);
307 // Set the size of the kernel's trace buffer in kilobytes.
308 static bool setTraceBufferSizeKB(int size)
315 snprintf(str, 32, "%d", size);
316 return writeStr(k_traceBufferSizePath, str);
319 // Enable or disable the kernel's use of the global clock. Disabling the global
320 // clock will result in the kernel using a per-CPU local clock.
321 static bool setGlobalClockEnable(bool enable)
323 return writeStr(k_traceClockPath, enable ? "global" : "local");
326 static bool setPrintTgidEnableIfPresent(bool enable)
328 if (fileExists(k_printTgidPath)) {
329 return setKernelOptionEnable(k_printTgidPath, enable);
334 // Poke all the binder-enabled processes in the system to get them to re-read
335 // their system properties.
336 static bool pokeBinderServices()
338 sp<IServiceManager> sm = defaultServiceManager();
339 Vector<String16> services = sm->listServices();
340 for (size_t i = 0; i < services.size(); i++) {
341 sp<IBinder> obj = sm->checkService(services[i]);
344 if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
347 // XXX: For some reason this fails on tablets trying to
348 // poke the "phone" service. It's not clear whether some
349 // are expected to fail.
350 String8 svc(services[i]);
351 fprintf(stderr, "error poking binder service %s\n",
361 // Set the trace tags that userland tracing uses, and poke the running
362 // processes to pick up the new value.
363 static bool setTagsProperty(uint64_t tags)
366 snprintf(buf, 64, "%#llx", tags);
367 if (property_set(k_traceTagsProperty, buf) < 0) {
368 fprintf(stderr, "error setting trace tags system property\n");
374 // Set the system property that indicates which apps should perform
375 // application-level tracing.
376 static bool setAppCmdlineProperty(const char* cmdline)
378 if (property_set(k_traceAppCmdlineProperty, cmdline) < 0) {
379 fprintf(stderr, "error setting trace app system property\n");
385 // Disable all /sys/ enable files.
386 static bool disableKernelTraceEvents() {
388 for (int i = 0; i < NELEM(k_categories); i++) {
389 const TracingCategory &c = k_categories[i];
390 for (int j = 0; j < MAX_SYS_FILES; j++) {
391 const char* path = c.sysfiles[j].path;
392 if (path != NULL && fileIsWritable(path)) {
393 ok &= setKernelOptionEnable(path, false);
400 // Verify that the comma separated list of functions are being traced by the
402 static bool verifyKernelTraceFuncs(const char* funcs)
404 int fd = open(k_ftraceFilterPath, O_RDONLY);
406 fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
407 strerror(errno), errno);
412 ssize_t n = read(fd, buf, 4096);
415 fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
416 strerror(errno), errno);
421 String8 funcList = String8::format("\n%s", buf);
423 // Make sure that every function listed in funcs is in the list we just
424 // read from the kernel.
426 char* myFuncs = strdup(funcs);
427 char* func = strtok(myFuncs, ",");
429 String8 fancyFunc = String8::format("\n%s\n", func);
430 bool found = funcList.find(fancyFunc.string(), 0) >= 0;
431 if (!found || func[0] == '\0') {
432 fprintf(stderr, "error: \"%s\" is not a valid kernel function "
433 "to trace.\n", func);
436 func = strtok(NULL, ",");
443 // Set the comma separated list of functions that the kernel is to trace.
444 static bool setKernelTraceFuncs(const char* funcs)
448 if (funcs == NULL || funcs[0] == '\0') {
449 // Disable kernel function tracing.
450 if (fileIsWritable(k_currentTracerPath)) {
451 ok &= writeStr(k_currentTracerPath, "nop");
453 if (fileIsWritable(k_ftraceFilterPath)) {
454 ok &= truncateFile(k_ftraceFilterPath);
457 // Enable kernel function tracing.
458 ok &= writeStr(k_currentTracerPath, "function_graph");
459 ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
460 ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
461 ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
462 ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
464 // Set the requested filter functions.
465 ok &= truncateFile(k_ftraceFilterPath);
466 char* myFuncs = strdup(funcs);
467 char* func = strtok(myFuncs, ",");
469 ok &= appendStr(k_ftraceFilterPath, func);
470 func = strtok(NULL, ",");
474 // Verify that the set functions are being traced.
476 ok &= verifyKernelTraceFuncs(funcs);
483 // Set all the kernel tracing settings to the desired state for this trace
485 static bool setUpTrace()
489 // Set up the tracing options.
490 ok &= setTraceOverwriteEnable(g_traceOverwrite);
491 ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
492 ok &= setGlobalClockEnable(true);
493 ok &= setPrintTgidEnableIfPresent(true);
494 ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
496 // Set up the tags property.
498 for (int i = 0; i < NELEM(k_categories); i++) {
499 if (g_categoryEnables[i]) {
500 const TracingCategory &c = k_categories[i];
504 ok &= setTagsProperty(tags);
505 ok &= setAppCmdlineProperty(g_debugAppCmdLine);
506 ok &= pokeBinderServices();
508 // Disable all the sysfs enables. This is done as a separate loop from
509 // the enables to allow the same enable to exist in multiple categories.
510 ok &= disableKernelTraceEvents();
512 // Enable all the sysfs enables that are in an enabled category.
513 for (int i = 0; i < NELEM(k_categories); i++) {
514 if (g_categoryEnables[i]) {
515 const TracingCategory &c = k_categories[i];
516 for (int j = 0; j < MAX_SYS_FILES; j++) {
517 const char* path = c.sysfiles[j].path;
518 bool required = c.sysfiles[j].required == REQ;
520 if (fileIsWritable(path)) {
521 ok &= setKernelOptionEnable(path, true);
522 } else if (required) {
523 fprintf(stderr, "error writing file %s\n", path);
534 // Reset all the kernel tracing settings to their default state.
535 static void cleanUpTrace()
537 // Disable all tracing that we're able to.
538 disableKernelTraceEvents();
540 // Reset the system properties.
542 setAppCmdlineProperty("");
543 pokeBinderServices();
545 // Set the options back to their defaults.
546 setTraceOverwriteEnable(true);
547 setTraceBufferSizeKB(1);
548 setGlobalClockEnable(false);
549 setPrintTgidEnableIfPresent(false);
550 setKernelTraceFuncs(NULL);
554 // Enable tracing in the kernel.
555 static bool startTrace()
557 return setTracingEnabled(true);
560 // Disable tracing in the kernel.
561 static void stopTrace()
563 setTracingEnabled(false);
566 // Read the current kernel trace and write it to stdout.
567 static void dumpTrace()
569 int traceFD = open(k_tracePath, O_RDWR);
571 fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
572 strerror(errno), errno);
581 bzero(&zs, sizeof(zs));
582 result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
583 if (result != Z_OK) {
584 fprintf(stderr, "error initializing zlib: %d\n", result);
589 const size_t bufSize = 64*1024;
590 in = (uint8_t*)malloc(bufSize);
591 out = (uint8_t*)malloc(bufSize);
595 zs.avail_out = bufSize;
599 if (zs.avail_in == 0) {
600 // More input is needed.
601 result = read(traceFD, in, bufSize);
603 fprintf(stderr, "error reading trace: %s (%d)\n",
604 strerror(errno), errno);
605 result = Z_STREAM_END;
607 } else if (result == 0) {
611 zs.avail_in = result;
615 if (zs.avail_out == 0) {
616 // Need to write the output.
617 result = write(STDOUT_FILENO, out, bufSize);
618 if ((size_t)result < bufSize) {
619 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
620 strerror(errno), errno);
621 result = Z_STREAM_END; // skip deflate error message
622 zs.avail_out = bufSize; // skip the final write
626 zs.avail_out = bufSize;
629 } while ((result = deflate(&zs, flush)) == Z_OK);
631 if (result != Z_STREAM_END) {
632 fprintf(stderr, "error deflating trace: %s\n", zs.msg);
635 if (zs.avail_out < bufSize) {
636 size_t bytes = bufSize - zs.avail_out;
637 result = write(STDOUT_FILENO, out, bytes);
638 if ((size_t)result < bytes) {
639 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
640 strerror(errno), errno);
644 result = deflateEnd(&zs);
645 if (result != Z_OK) {
646 fprintf(stderr, "error cleaning up zlib: %d\n", result);
653 while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
655 fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
663 static void handleSignal(int signo)
666 g_traceAborted = true;
670 static void registerSigHandler()
673 sigemptyset(&sa.sa_mask);
675 sa.sa_handler = handleSignal;
676 sigaction(SIGHUP, &sa, NULL);
677 sigaction(SIGINT, &sa, NULL);
678 sigaction(SIGQUIT, &sa, NULL);
679 sigaction(SIGTERM, &sa, NULL);
682 static bool setCategoryEnable(const char* name, bool enable)
684 for (int i = 0; i < NELEM(k_categories); i++) {
685 const TracingCategory& c = k_categories[i];
686 if (strcmp(name, c.name) == 0) {
687 if (isCategorySupported(c)) {
688 g_categoryEnables[i] = enable;
691 if (isCategorySupportedForRoot(c)) {
692 fprintf(stderr, "error: category \"%s\" requires root "
693 "privileges.\n", name);
695 fprintf(stderr, "error: category \"%s\" is not supported "
696 "on this device.\n", name);
702 fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
706 static void listSupportedCategories()
708 for (int i = 0; i < NELEM(k_categories); i++) {
709 const TracingCategory& c = k_categories[i];
710 if (isCategorySupported(c)) {
711 printf(" %10s - %s\n", c.name, c.longname);
716 // Print the command usage help to stderr.
717 static void showHelp(const char *cmd)
719 fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
720 fprintf(stderr, "options include:\n"
721 " -a appname enable app-level tracing for a comma "
722 "separated list of cmdlines\n"
723 " -b N use a trace buffer size of N KB\n"
724 " -c trace into a circular buffer\n"
725 " -k fname,... trace the listed kernel functions\n"
726 " -n ignore signals\n"
727 " -s N sleep for N seconds before tracing [default 0]\n"
728 " -t N trace for N seconds [defualt 5]\n"
729 " -z compress the trace dump\n"
730 " --async_start start circular trace and return immediatly\n"
731 " --async_dump dump the current contents of circular trace buffer\n"
732 " --async_stop stop tracing and dump the current contents of circular\n"
734 " --list_categories\n"
735 " list the available tracing categories\n"
739 int main(int argc, char **argv)
742 bool traceStart = true;
743 bool traceStop = true;
744 bool traceDump = true;
746 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
753 int option_index = 0;
754 static struct option long_options[] = {
755 {"async_start", no_argument, 0, 0 },
756 {"async_stop", no_argument, 0, 0 },
757 {"async_dump", no_argument, 0, 0 },
758 {"list_categories", no_argument, 0, 0 },
762 ret = getopt_long(argc, argv, "a:b:ck:ns:t:z",
763 long_options, &option_index);
766 for (int i = optind; i < argc; i++) {
767 if (!setCategoryEnable(argv[i], true)) {
768 fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
777 g_debugAppCmdLine = optarg;
781 g_traceBufferSizeKB = atoi(optarg);
785 g_traceOverwrite = true;
789 g_kernelTraceFuncs = optarg;
797 g_initialSleepSecs = atoi(optarg);
801 g_traceDurationSeconds = atoi(optarg);
809 if (!strcmp(long_options[option_index].name, "async_start")) {
813 g_traceOverwrite = true;
814 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
817 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
821 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
822 listSupportedCategories();
828 fprintf(stderr, "\n");
835 registerSigHandler();
837 if (g_initialSleepSecs > 0) {
838 sleep(g_initialSleepSecs);
845 if (ok && traceStart) {
846 printf("capturing trace...");
849 // We clear the trace after starting it because tracing gets enabled for
850 // each CPU individually in the kernel. Having the beginning of the trace
851 // contain entries from only one CPU can cause "begin" entries without a
852 // matching "end" entry to show up if a task gets migrated from one CPU to
857 // Sleep to allow the trace to be captured.
858 struct timespec timeLeft;
859 timeLeft.tv_sec = g_traceDurationSeconds;
860 timeLeft.tv_nsec = 0;
862 if (g_traceAborted) {
865 } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
869 // Stop the trace and restore the default settings.
873 if (ok && traceDump) {
874 if (!g_traceAborted) {
875 printf(" done\nTRACE:\n");
879 printf("\ntrace aborted.\n");
884 fprintf(stderr, "unable to start tracing\n");
887 // Reset the trace buffer size to 1.
891 return g_traceAborted ? 1 : 0;