OSDN Git Service

06e9744fb39564c5fa9e747e4fdbf5f39be303e3
[android-x86/frameworks-native.git] / cmds / atrace / atrace.cpp
1 /*
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
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <getopt.h>
20 #include <signal.h>
21 #include <stdarg.h>
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/sendfile.h>
26 #include <time.h>
27 #include <zlib.h>
28
29 #include <binder/IBinder.h>
30 #include <binder/IServiceManager.h>
31 #include <binder/Parcel.h>
32
33 #include <cutils/properties.h>
34
35 #include <utils/String8.h>
36 #include <utils/Trace.h>
37
38 using namespace android;
39
40 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
41
42 enum { MAX_SYS_FILES = 8 };
43
44 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
45 const char* k_traceAppCmdlineProperty = "debug.atrace.app_cmdlines";
46
47 typedef enum { OPT, REQ } requiredness  ;
48
49 struct TracingCategory {
50     // The name identifying the category.
51     const char* name;
52
53     // A longer description of the category.
54     const char* longname;
55
56     // The userland tracing tags that the category enables.
57     uint64_t tags;
58
59     // The fname==NULL terminated list of /sys/ files that the category
60     // enables.
61     struct {
62         // Whether the file must be writable in order to enable the tracing
63         // category.
64         requiredness required;
65
66         // The path to the enable file.
67         const char* path;
68     } sysfiles[MAX_SYS_FILES];
69 };
70
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" },
87     } },
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" },
91     } },
92     { "membus",     "Memory Bus Utilization", 0, {
93         { REQ,      "/sys/kernel/debug/tracing/events/memory_bus/enable" },
94     } },
95     { "idle",       "CPU Idle",         0, {
96         { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
97     } },
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" },
103     } },
104     { "load",       "CPU Load",         0, {
105         { REQ,      "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
106     } },
107     { "sync",       "Synchronization",  0, {
108         { REQ,      "/sys/kernel/debug/tracing/events/sync/enable" },
109     } },
110     { "workq",      "Kernel Workqueues", 0, {
111         { REQ,      "/sys/kernel/debug/tracing/events/workqueue/enable" },
112     } },
113 };
114
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 = "";
124
125 /* Global state */
126 static bool g_traceAborted = false;
127 static bool g_categoryEnables[NELEM(k_categories)] = {};
128
129 /* Sys file paths */
130 static const char* k_traceClockPath =
131     "/sys/kernel/debug/tracing/trace_clock";
132
133 static const char* k_traceBufferSizePath =
134     "/sys/kernel/debug/tracing/buffer_size_kb";
135
136 static const char* k_tracingOverwriteEnablePath =
137     "/sys/kernel/debug/tracing/options/overwrite";
138
139 static const char* k_currentTracerPath =
140     "/sys/kernel/debug/tracing/current_tracer";
141
142 static const char* k_printTgidPath =
143     "/sys/kernel/debug/tracing/options/print-tgid";
144
145 static const char* k_funcgraphAbsTimePath =
146     "/sys/kernel/debug/tracing/options/funcgraph-abstime";
147
148 static const char* k_funcgraphCpuPath =
149     "/sys/kernel/debug/tracing/options/funcgraph-cpu";
150
151 static const char* k_funcgraphProcPath =
152     "/sys/kernel/debug/tracing/options/funcgraph-proc";
153
154 static const char* k_funcgraphFlatPath =
155     "/sys/kernel/debug/tracing/options/funcgraph-flat";
156
157 static const char* k_funcgraphDurationPath =
158     "/sys/kernel/debug/tracing/options/funcgraph-duration";
159
160 static const char* k_ftraceFilterPath =
161     "/sys/kernel/debug/tracing/set_ftrace_filter";
162
163 static const char* k_tracingOnPath =
164     "/sys/kernel/debug/tracing/tracing_on";
165
166 static const char* k_tracePath =
167     "/sys/kernel/debug/tracing/trace";
168
169 // Check whether a file exists.
170 static bool fileExists(const char* filename) {
171     return access(filename, F_OK) != -1;
172 }
173
174 // Check whether a file is writable.
175 static bool fileIsWritable(const char* filename) {
176     return access(filename, W_OK) != -1;
177 }
178
179 // Truncate a file.
180 static bool truncateFile(const char* path)
181 {
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);
186     if (traceFD == -1) {
187         fprintf(stderr, "error truncating %s: %s (%d)\n", path,
188             strerror(errno), errno);
189         return false;
190     }
191
192     close(traceFD);
193
194     return true;
195 }
196
197 static bool _writeStr(const char* filename, const char* str, int flags)
198 {
199     int fd = open(filename, flags);
200     if (fd == -1) {
201         fprintf(stderr, "error opening %s: %s (%d)\n", filename,
202                 strerror(errno), errno);
203         return false;
204     }
205
206     bool ok = true;
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);
211         ok = false;
212     }
213
214     close(fd);
215
216     return ok;
217 }
218
219 // Write a string to a file, returning true if the write was successful.
220 static bool writeStr(const char* filename, const char* str)
221 {
222     return _writeStr(filename, str, O_WRONLY);
223 }
224
225 // Append a string to a file, returning true if the write was successful.
226 static bool appendStr(const char* filename, const char* str)
227 {
228     return _writeStr(filename, str, O_APPEND|O_WRONLY);
229 }
230
231 // Enable or disable a kernel option by writing a "1" or a "0" into a /sys
232 // file.
233 static bool setKernelOptionEnable(const char* filename, bool enable)
234 {
235     return writeStr(filename, enable ? "1" : "0");
236 }
237
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
241 // or /sys/ files.
242 static bool isCategorySupported(const TracingCategory& category)
243 {
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;
248         if (path != NULL) {
249             if (req) {
250                 if (!fileIsWritable(path)) {
251                     return false;
252                 } else {
253                     ok = true;
254                 }
255             } else {
256                 ok |= fileIsWritable(path);
257             }
258         }
259     }
260     return ok;
261 }
262
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)
268 {
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;
273         if (path != NULL) {
274             if (req) {
275                 if (!fileExists(path)) {
276                     return false;
277                 } else {
278                     ok = true;
279                 }
280             } else {
281                 ok |= fileExists(path);
282             }
283         }
284     }
285     return ok;
286 }
287
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)
291 {
292     return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
293 }
294
295 // Enable or disable kernel tracing.
296 static bool setTracingEnabled(bool enable)
297 {
298     return setKernelOptionEnable(k_tracingOnPath, enable);
299 }
300
301 // Clear the contents of the kernel trace.
302 static bool clearTrace()
303 {
304     return truncateFile(k_tracePath);
305 }
306
307 // Set the size of the kernel's trace buffer in kilobytes.
308 static bool setTraceBufferSizeKB(int size)
309 {
310     char str[32] = "1";
311     int len;
312     if (size < 1) {
313         size = 1;
314     }
315     snprintf(str, 32, "%d", size);
316     return writeStr(k_traceBufferSizePath, str);
317 }
318
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)
322 {
323     return writeStr(k_traceClockPath, enable ? "global" : "local");
324 }
325
326 static bool setPrintTgidEnableIfPresent(bool enable)
327 {
328     if (fileExists(k_printTgidPath)) {
329         return setKernelOptionEnable(k_printTgidPath, enable);
330     }
331     return true;
332 }
333
334 // Poke all the binder-enabled processes in the system to get them to re-read
335 // their system properties.
336 static bool pokeBinderServices()
337 {
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]);
342         if (obj != NULL) {
343             Parcel data;
344             if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
345                     NULL, 0) != OK) {
346                 if (false) {
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",
352                         svc.string());
353                     return false;
354                 }
355             }
356         }
357     }
358     return true;
359 }
360
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)
364 {
365     char buf[64];
366     snprintf(buf, 64, "%#llx", tags);
367     if (property_set(k_traceTagsProperty, buf) < 0) {
368         fprintf(stderr, "error setting trace tags system property\n");
369         return false;
370     }
371     return true;
372 }
373
374 // Set the system property that indicates which apps should perform
375 // application-level tracing.
376 static bool setAppCmdlineProperty(const char* cmdline)
377 {
378     if (property_set(k_traceAppCmdlineProperty, cmdline) < 0) {
379         fprintf(stderr, "error setting trace app system property\n");
380         return false;
381     }
382     return true;
383 }
384
385 // Disable all /sys/ enable files.
386 static bool disableKernelTraceEvents() {
387     bool ok = true;
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);
394             }
395         }
396     }
397     return ok;
398 }
399
400 // Verify that the comma separated list of functions are being traced by the
401 // kernel.
402 static bool verifyKernelTraceFuncs(const char* funcs)
403 {
404     int fd = open(k_ftraceFilterPath, O_RDONLY);
405     if (fd == -1) {
406         fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
407             strerror(errno), errno);
408         return false;
409     }
410
411     char buf[4097];
412     ssize_t n = read(fd, buf, 4096);
413     close(fd);
414     if (n == -1) {
415         fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
416             strerror(errno), errno);
417         return false;
418     }
419
420     buf[n] = '\0';
421     String8 funcList = String8::format("\n%s", buf);
422
423     // Make sure that every function listed in funcs is in the list we just
424     // read from the kernel.
425     bool ok = true;
426     char* myFuncs = strdup(funcs);
427     char* func = strtok(myFuncs, ",");
428     while (func) {
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);
434             ok = false;
435         }
436         func = strtok(NULL, ",");
437     }
438     free(myFuncs);
439
440     return ok;
441 }
442
443 // Set the comma separated list of functions that the kernel is to trace.
444 static bool setKernelTraceFuncs(const char* funcs)
445 {
446     bool ok = true;
447
448     if (funcs == NULL || funcs[0] == '\0') {
449         // Disable kernel function tracing.
450         if (fileIsWritable(k_currentTracerPath)) {
451             ok &= writeStr(k_currentTracerPath, "nop");
452         }
453         if (fileIsWritable(k_ftraceFilterPath)) {
454             ok &= truncateFile(k_ftraceFilterPath);
455         }
456     } else {
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);
463
464         // Set the requested filter functions.
465         ok &= truncateFile(k_ftraceFilterPath);
466         char* myFuncs = strdup(funcs);
467         char* func = strtok(myFuncs, ",");
468         while (func) {
469             ok &= appendStr(k_ftraceFilterPath, func);
470             func = strtok(NULL, ",");
471         }
472         free(myFuncs);
473
474         // Verify that the set functions are being traced.
475         if (ok) {
476             ok &= verifyKernelTraceFuncs(funcs);
477         }
478     }
479
480     return ok;
481 }
482
483 // Set all the kernel tracing settings to the desired state for this trace
484 // capture.
485 static bool setUpTrace()
486 {
487     bool ok = true;
488
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);
495
496     // Set up the tags property.
497     uint64_t tags = 0;
498     for (int i = 0; i < NELEM(k_categories); i++) {
499         if (g_categoryEnables[i]) {
500             const TracingCategory &c = k_categories[i];
501             tags |= c.tags;
502         }
503     }
504     ok &= setTagsProperty(tags);
505     ok &= setAppCmdlineProperty(g_debugAppCmdLine);
506     ok &= pokeBinderServices();
507
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();
511
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;
519                 if (path != NULL) {
520                     if (fileIsWritable(path)) {
521                         ok &= setKernelOptionEnable(path, true);
522                     } else if (required) {
523                         fprintf(stderr, "error writing file %s\n", path);
524                         ok = false;
525                     }
526                 }
527             }
528         }
529     }
530
531     return ok;
532 }
533
534 // Reset all the kernel tracing settings to their default state.
535 static void cleanUpTrace()
536 {
537     // Disable all tracing that we're able to.
538     disableKernelTraceEvents();
539
540     // Reset the system properties.
541     setTagsProperty(0);
542     setAppCmdlineProperty("");
543     pokeBinderServices();
544
545     // Set the options back to their defaults.
546     setTraceOverwriteEnable(true);
547     setTraceBufferSizeKB(1);
548     setGlobalClockEnable(false);
549     setPrintTgidEnableIfPresent(false);
550     setKernelTraceFuncs(NULL);
551 }
552
553
554 // Enable tracing in the kernel.
555 static bool startTrace()
556 {
557     return setTracingEnabled(true);
558 }
559
560 // Disable tracing in the kernel.
561 static void stopTrace()
562 {
563     setTracingEnabled(false);
564 }
565
566 // Read the current kernel trace and write it to stdout.
567 static void dumpTrace()
568 {
569     int traceFD = open(k_tracePath, O_RDWR);
570     if (traceFD == -1) {
571         fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
572                 strerror(errno), errno);
573         return;
574     }
575
576     if (g_compress) {
577         z_stream zs;
578         uint8_t *in, *out;
579         int result, flush;
580
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);
585             close(traceFD);
586             return;
587         }
588
589         const size_t bufSize = 64*1024;
590         in = (uint8_t*)malloc(bufSize);
591         out = (uint8_t*)malloc(bufSize);
592         flush = Z_NO_FLUSH;
593
594         zs.next_out = out;
595         zs.avail_out = bufSize;
596
597         do {
598
599             if (zs.avail_in == 0) {
600                 // More input is needed.
601                 result = read(traceFD, in, bufSize);
602                 if (result < 0) {
603                     fprintf(stderr, "error reading trace: %s (%d)\n",
604                             strerror(errno), errno);
605                     result = Z_STREAM_END;
606                     break;
607                 } else if (result == 0) {
608                     flush = Z_FINISH;
609                 } else {
610                     zs.next_in = in;
611                     zs.avail_in = result;
612                 }
613             }
614
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
623                     break;
624                 }
625                 zs.next_out = out;
626                 zs.avail_out = bufSize;
627             }
628
629         } while ((result = deflate(&zs, flush)) == Z_OK);
630
631         if (result != Z_STREAM_END) {
632             fprintf(stderr, "error deflating trace: %s\n", zs.msg);
633         }
634
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);
641             }
642         }
643
644         result = deflateEnd(&zs);
645         if (result != Z_OK) {
646             fprintf(stderr, "error cleaning up zlib: %d\n", result);
647         }
648
649         free(in);
650         free(out);
651     } else {
652         ssize_t sent = 0;
653         while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
654         if (sent == -1) {
655             fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
656                     errno);
657         }
658     }
659
660     close(traceFD);
661 }
662
663 static void handleSignal(int signo)
664 {
665     if (!g_nohup) {
666         g_traceAborted = true;
667     }
668 }
669
670 static void registerSigHandler()
671 {
672     struct sigaction sa;
673     sigemptyset(&sa.sa_mask);
674     sa.sa_flags = 0;
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);
680 }
681
682 static bool setCategoryEnable(const char* name, bool enable)
683 {
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;
689                 return true;
690             } else {
691                 if (isCategorySupportedForRoot(c)) {
692                     fprintf(stderr, "error: category \"%s\" requires root "
693                             "privileges.\n", name);
694                 } else {
695                     fprintf(stderr, "error: category \"%s\" is not supported "
696                             "on this device.\n", name);
697                 }
698                 return false;
699             }
700         }
701     }
702     fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
703     return false;
704 }
705
706 static void listSupportedCategories()
707 {
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);
712         }
713     }
714 }
715
716 // Print the command usage help to stderr.
717 static void showHelp(const char *cmd)
718 {
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"
733                     "                    trace buffer\n"
734                     "  --list_categories\n"
735                     "                  list the available tracing categories\n"
736             );
737 }
738
739 int main(int argc, char **argv)
740 {
741     bool async = false;
742     bool traceStart = true;
743     bool traceStop = true;
744     bool traceDump = true;
745
746     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
747         showHelp(argv[0]);
748         exit(0);
749     }
750
751     for (;;) {
752         int ret;
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 },
759             {           0,                0, 0,  0 }
760         };
761
762         ret = getopt_long(argc, argv, "a:b:ck:ns:t:z",
763                           long_options, &option_index);
764
765         if (ret < 0) {
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]);
769                     exit(1);
770                 }
771             }
772             break;
773         }
774
775         switch(ret) {
776             case 'a':
777                 g_debugAppCmdLine = optarg;
778             break;
779
780             case 'b':
781                 g_traceBufferSizeKB = atoi(optarg);
782             break;
783
784             case 'c':
785                 g_traceOverwrite = true;
786             break;
787
788             case 'k':
789                 g_kernelTraceFuncs = optarg;
790             break;
791
792             case 'n':
793                 g_nohup = true;
794             break;
795
796             case 's':
797                 g_initialSleepSecs = atoi(optarg);
798             break;
799
800             case 't':
801                 g_traceDurationSeconds = atoi(optarg);
802             break;
803
804             case 'z':
805                 g_compress = true;
806             break;
807
808             case 0:
809                 if (!strcmp(long_options[option_index].name, "async_start")) {
810                     async = true;
811                     traceStop = false;
812                     traceDump = false;
813                     g_traceOverwrite = true;
814                 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
815                     async = true;
816                     traceStop = false;
817                 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
818                     async = true;
819                     traceStart = false;
820                     traceStop = false;
821                 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
822                     listSupportedCategories();
823                     exit(0);
824                 }
825             break;
826
827             default:
828                 fprintf(stderr, "\n");
829                 showHelp(argv[0]);
830                 exit(-1);
831             break;
832         }
833     }
834
835     registerSigHandler();
836
837     if (g_initialSleepSecs > 0) {
838         sleep(g_initialSleepSecs);
839     }
840
841     bool ok = true;
842     ok &= setUpTrace();
843     ok &= startTrace();
844
845     if (ok && traceStart) {
846         printf("capturing trace...");
847         fflush(stdout);
848
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
853         // another.
854         ok = clearTrace();
855
856         if (ok && !async) {
857             // Sleep to allow the trace to be captured.
858             struct timespec timeLeft;
859             timeLeft.tv_sec = g_traceDurationSeconds;
860             timeLeft.tv_nsec = 0;
861             do {
862                 if (g_traceAborted) {
863                     break;
864                 }
865             } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
866         }
867     }
868
869     // Stop the trace and restore the default settings.
870     if (traceStop)
871         stopTrace();
872
873     if (ok && traceDump) {
874         if (!g_traceAborted) {
875             printf(" done\nTRACE:\n");
876             fflush(stdout);
877             dumpTrace();
878         } else {
879             printf("\ntrace aborted.\n");
880             fflush(stdout);
881         }
882         clearTrace();
883     } else if (!ok) {
884         fprintf(stderr, "unable to start tracing\n");
885     }
886
887     // Reset the trace buffer size to 1.
888     if (traceStop)
889         cleanUpTrace();
890
891     return g_traceAborted ? 1 : 0;
892 }