atrace.cpp revision 3200b0bf507936ecf43784191880e4e91c54568c
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 <inttypes.h> 21#include <signal.h> 22#include <stdarg.h> 23#include <stdbool.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <sys/sendfile.h> 27#include <time.h> 28#include <zlib.h> 29 30#include <binder/IBinder.h> 31#include <binder/IServiceManager.h> 32#include <binder/Parcel.h> 33 34#include <cutils/properties.h> 35 36#include <utils/String8.h> 37#include <utils/Trace.h> 38 39using namespace android; 40 41#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) 42 43enum { MAX_SYS_FILES = 10 }; 44 45const char* k_traceTagsProperty = "debug.atrace.tags.enableflags"; 46const char* k_traceAppCmdlineProperty = "debug.atrace.app_cmdlines"; 47 48typedef enum { OPT, REQ } requiredness ; 49 50struct TracingCategory { 51 // The name identifying the category. 52 const char* name; 53 54 // A longer description of the category. 55 const char* longname; 56 57 // The userland tracing tags that the category enables. 58 uint64_t tags; 59 60 // The fname==NULL terminated list of /sys/ files that the category 61 // enables. 62 struct { 63 // Whether the file must be writable in order to enable the tracing 64 // category. 65 requiredness required; 66 67 // The path to the enable file. 68 const char* path; 69 } sysfiles[MAX_SYS_FILES]; 70}; 71 72/* Tracing categories */ 73static const TracingCategory k_categories[] = { 74 { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } }, 75 { "input", "Input", ATRACE_TAG_INPUT, { } }, 76 { "view", "View System", ATRACE_TAG_VIEW, { } }, 77 { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } }, 78 { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } }, 79 { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } }, 80 { "sync", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } }, 81 { "audio", "Audio", ATRACE_TAG_AUDIO, { } }, 82 { "video", "Video", ATRACE_TAG_VIDEO, { } }, 83 { "camera", "Camera", ATRACE_TAG_CAMERA, { } }, 84 { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } }, 85 { "app", "Application", ATRACE_TAG_APP, { } }, 86 { "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } }, 87 { "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } }, 88 { "rs", "RenderScript", ATRACE_TAG_RS, { } }, 89 { "bionic", "Bionic C Library", ATRACE_TAG_BIONIC, { } }, 90 { "power", "Power Management", ATRACE_TAG_POWER, { } }, 91 { "sched", "CPU Scheduling", 0, { 92 { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" }, 93 { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" }, 94 } }, 95 { "freq", "CPU Frequency", 0, { 96 { REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" }, 97 { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" }, 98 } }, 99 { "membus", "Memory Bus Utilization", 0, { 100 { REQ, "/sys/kernel/debug/tracing/events/memory_bus/enable" }, 101 } }, 102 { "idle", "CPU Idle", 0, { 103 { REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" }, 104 } }, 105 { "disk", "Disk I/O", 0, { 106 { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" }, 107 { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" }, 108 { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" }, 109 { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" }, 110 { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" }, 111 { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" }, 112 { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" }, 113 { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" }, 114 { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" }, 115 { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" }, 116 } }, 117 { "mmc", "eMMC commands", 0, { 118 { REQ, "/sys/kernel/debug/tracing/events/mmc/enable" }, 119 } }, 120 { "load", "CPU Load", 0, { 121 { REQ, "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" }, 122 } }, 123 { "sync", "Synchronization", 0, { 124 { REQ, "/sys/kernel/debug/tracing/events/sync/enable" }, 125 } }, 126 { "workq", "Kernel Workqueues", 0, { 127 { REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" }, 128 } }, 129}; 130 131/* Command line options */ 132static int g_traceDurationSeconds = 5; 133static bool g_traceOverwrite = false; 134static int g_traceBufferSizeKB = 2048; 135static bool g_compress = false; 136static bool g_nohup = false; 137static int g_initialSleepSecs = 0; 138static const char* g_kernelTraceFuncs = NULL; 139static const char* g_debugAppCmdLine = ""; 140 141/* Global state */ 142static bool g_traceAborted = false; 143static bool g_categoryEnables[NELEM(k_categories)] = {}; 144 145/* Sys file paths */ 146static const char* k_traceClockPath = 147 "/sys/kernel/debug/tracing/trace_clock"; 148 149static const char* k_traceBufferSizePath = 150 "/sys/kernel/debug/tracing/buffer_size_kb"; 151 152static const char* k_tracingOverwriteEnablePath = 153 "/sys/kernel/debug/tracing/options/overwrite"; 154 155static const char* k_currentTracerPath = 156 "/sys/kernel/debug/tracing/current_tracer"; 157 158static const char* k_printTgidPath = 159 "/sys/kernel/debug/tracing/options/print-tgid"; 160 161static const char* k_funcgraphAbsTimePath = 162 "/sys/kernel/debug/tracing/options/funcgraph-abstime"; 163 164static const char* k_funcgraphCpuPath = 165 "/sys/kernel/debug/tracing/options/funcgraph-cpu"; 166 167static const char* k_funcgraphProcPath = 168 "/sys/kernel/debug/tracing/options/funcgraph-proc"; 169 170static const char* k_funcgraphFlatPath = 171 "/sys/kernel/debug/tracing/options/funcgraph-flat"; 172 173static const char* k_funcgraphDurationPath = 174 "/sys/kernel/debug/tracing/options/funcgraph-duration"; 175 176static const char* k_ftraceFilterPath = 177 "/sys/kernel/debug/tracing/set_ftrace_filter"; 178 179static const char* k_tracingOnPath = 180 "/sys/kernel/debug/tracing/tracing_on"; 181 182static const char* k_tracePath = 183 "/sys/kernel/debug/tracing/trace"; 184 185// Check whether a file exists. 186static bool fileExists(const char* filename) { 187 return access(filename, F_OK) != -1; 188} 189 190// Check whether a file is writable. 191static bool fileIsWritable(const char* filename) { 192 return access(filename, W_OK) != -1; 193} 194 195// Truncate a file. 196static bool truncateFile(const char* path) 197{ 198 // This uses creat rather than truncate because some of the debug kernel 199 // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by 200 // calls to truncate, but they are cleared by calls to creat. 201 int traceFD = creat(path, 0); 202 if (traceFD == -1) { 203 fprintf(stderr, "error truncating %s: %s (%d)\n", path, 204 strerror(errno), errno); 205 return false; 206 } 207 208 close(traceFD); 209 210 return true; 211} 212 213static bool _writeStr(const char* filename, const char* str, int flags) 214{ 215 int fd = open(filename, flags); 216 if (fd == -1) { 217 fprintf(stderr, "error opening %s: %s (%d)\n", filename, 218 strerror(errno), errno); 219 return false; 220 } 221 222 bool ok = true; 223 ssize_t len = strlen(str); 224 if (write(fd, str, len) != len) { 225 fprintf(stderr, "error writing to %s: %s (%d)\n", filename, 226 strerror(errno), errno); 227 ok = false; 228 } 229 230 close(fd); 231 232 return ok; 233} 234 235// Write a string to a file, returning true if the write was successful. 236static bool writeStr(const char* filename, const char* str) 237{ 238 return _writeStr(filename, str, O_WRONLY); 239} 240 241// Append a string to a file, returning true if the write was successful. 242static bool appendStr(const char* filename, const char* str) 243{ 244 return _writeStr(filename, str, O_APPEND|O_WRONLY); 245} 246 247// Enable or disable a kernel option by writing a "1" or a "0" into a /sys 248// file. 249static bool setKernelOptionEnable(const char* filename, bool enable) 250{ 251 return writeStr(filename, enable ? "1" : "0"); 252} 253 254// Check whether the category is supported on the device with the current 255// rootness. A category is supported only if all its required /sys/ files are 256// writable and if enabling the category will enable one or more tracing tags 257// or /sys/ files. 258static bool isCategorySupported(const TracingCategory& category) 259{ 260 bool ok = category.tags != 0; 261 for (int i = 0; i < MAX_SYS_FILES; i++) { 262 const char* path = category.sysfiles[i].path; 263 bool req = category.sysfiles[i].required == REQ; 264 if (path != NULL) { 265 if (req) { 266 if (!fileIsWritable(path)) { 267 return false; 268 } else { 269 ok = true; 270 } 271 } else { 272 ok |= fileIsWritable(path); 273 } 274 } 275 } 276 return ok; 277} 278 279// Check whether the category would be supported on the device if the user 280// were root. This function assumes that root is able to write to any file 281// that exists. It performs the same logic as isCategorySupported, but it 282// uses file existance rather than writability in the /sys/ file checks. 283static bool isCategorySupportedForRoot(const TracingCategory& category) 284{ 285 bool ok = category.tags != 0; 286 for (int i = 0; i < MAX_SYS_FILES; i++) { 287 const char* path = category.sysfiles[i].path; 288 bool req = category.sysfiles[i].required == REQ; 289 if (path != NULL) { 290 if (req) { 291 if (!fileExists(path)) { 292 return false; 293 } else { 294 ok = true; 295 } 296 } else { 297 ok |= fileExists(path); 298 } 299 } 300 } 301 return ok; 302} 303 304// Enable or disable overwriting of the kernel trace buffers. Disabling this 305// will cause tracing to stop once the trace buffers have filled up. 306static bool setTraceOverwriteEnable(bool enable) 307{ 308 return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable); 309} 310 311// Enable or disable kernel tracing. 312static bool setTracingEnabled(bool enable) 313{ 314 return setKernelOptionEnable(k_tracingOnPath, enable); 315} 316 317// Clear the contents of the kernel trace. 318static bool clearTrace() 319{ 320 return truncateFile(k_tracePath); 321} 322 323// Set the size of the kernel's trace buffer in kilobytes. 324static bool setTraceBufferSizeKB(int size) 325{ 326 char str[32] = "1"; 327 int len; 328 if (size < 1) { 329 size = 1; 330 } 331 snprintf(str, 32, "%d", size); 332 return writeStr(k_traceBufferSizePath, str); 333} 334 335// Enable or disable the kernel's use of the global clock. Disabling the global 336// clock will result in the kernel using a per-CPU local clock. 337static bool setGlobalClockEnable(bool enable) 338{ 339 return writeStr(k_traceClockPath, enable ? "global" : "local"); 340} 341 342static bool setPrintTgidEnableIfPresent(bool enable) 343{ 344 if (fileExists(k_printTgidPath)) { 345 return setKernelOptionEnable(k_printTgidPath, enable); 346 } 347 return true; 348} 349 350// Poke all the binder-enabled processes in the system to get them to re-read 351// their system properties. 352static bool pokeBinderServices() 353{ 354 sp<IServiceManager> sm = defaultServiceManager(); 355 Vector<String16> services = sm->listServices(); 356 for (size_t i = 0; i < services.size(); i++) { 357 sp<IBinder> obj = sm->checkService(services[i]); 358 if (obj != NULL) { 359 Parcel data; 360 if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data, 361 NULL, 0) != OK) { 362 if (false) { 363 // XXX: For some reason this fails on tablets trying to 364 // poke the "phone" service. It's not clear whether some 365 // are expected to fail. 366 String8 svc(services[i]); 367 fprintf(stderr, "error poking binder service %s\n", 368 svc.string()); 369 return false; 370 } 371 } 372 } 373 } 374 return true; 375} 376 377// Set the trace tags that userland tracing uses, and poke the running 378// processes to pick up the new value. 379static bool setTagsProperty(uint64_t tags) 380{ 381 char buf[64]; 382 snprintf(buf, 64, "%#" PRIx64, tags); 383 if (property_set(k_traceTagsProperty, buf) < 0) { 384 fprintf(stderr, "error setting trace tags system property\n"); 385 return false; 386 } 387 return true; 388} 389 390// Set the system property that indicates which apps should perform 391// application-level tracing. 392static bool setAppCmdlineProperty(const char* cmdline) 393{ 394 if (property_set(k_traceAppCmdlineProperty, cmdline) < 0) { 395 fprintf(stderr, "error setting trace app system property\n"); 396 return false; 397 } 398 return true; 399} 400 401// Disable all /sys/ enable files. 402static bool disableKernelTraceEvents() { 403 bool ok = true; 404 for (int i = 0; i < NELEM(k_categories); i++) { 405 const TracingCategory &c = k_categories[i]; 406 for (int j = 0; j < MAX_SYS_FILES; j++) { 407 const char* path = c.sysfiles[j].path; 408 if (path != NULL && fileIsWritable(path)) { 409 ok &= setKernelOptionEnable(path, false); 410 } 411 } 412 } 413 return ok; 414} 415 416// Verify that the comma separated list of functions are being traced by the 417// kernel. 418static bool verifyKernelTraceFuncs(const char* funcs) 419{ 420 int fd = open(k_ftraceFilterPath, O_RDONLY); 421 if (fd == -1) { 422 fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath, 423 strerror(errno), errno); 424 return false; 425 } 426 427 char buf[4097]; 428 ssize_t n = read(fd, buf, 4096); 429 close(fd); 430 if (n == -1) { 431 fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath, 432 strerror(errno), errno); 433 return false; 434 } 435 436 buf[n] = '\0'; 437 String8 funcList = String8::format("\n%s", buf); 438 439 // Make sure that every function listed in funcs is in the list we just 440 // read from the kernel. 441 bool ok = true; 442 char* myFuncs = strdup(funcs); 443 char* func = strtok(myFuncs, ","); 444 while (func) { 445 String8 fancyFunc = String8::format("\n%s\n", func); 446 bool found = funcList.find(fancyFunc.string(), 0) >= 0; 447 if (!found || func[0] == '\0') { 448 fprintf(stderr, "error: \"%s\" is not a valid kernel function " 449 "to trace.\n", func); 450 ok = false; 451 } 452 func = strtok(NULL, ","); 453 } 454 free(myFuncs); 455 456 return ok; 457} 458 459// Set the comma separated list of functions that the kernel is to trace. 460static bool setKernelTraceFuncs(const char* funcs) 461{ 462 bool ok = true; 463 464 if (funcs == NULL || funcs[0] == '\0') { 465 // Disable kernel function tracing. 466 if (fileIsWritable(k_currentTracerPath)) { 467 ok &= writeStr(k_currentTracerPath, "nop"); 468 } 469 if (fileIsWritable(k_ftraceFilterPath)) { 470 ok &= truncateFile(k_ftraceFilterPath); 471 } 472 } else { 473 // Enable kernel function tracing. 474 ok &= writeStr(k_currentTracerPath, "function_graph"); 475 ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true); 476 ok &= setKernelOptionEnable(k_funcgraphCpuPath, true); 477 ok &= setKernelOptionEnable(k_funcgraphProcPath, true); 478 ok &= setKernelOptionEnable(k_funcgraphFlatPath, true); 479 480 // Set the requested filter functions. 481 ok &= truncateFile(k_ftraceFilterPath); 482 char* myFuncs = strdup(funcs); 483 char* func = strtok(myFuncs, ","); 484 while (func) { 485 ok &= appendStr(k_ftraceFilterPath, func); 486 func = strtok(NULL, ","); 487 } 488 free(myFuncs); 489 490 // Verify that the set functions are being traced. 491 if (ok) { 492 ok &= verifyKernelTraceFuncs(funcs); 493 } 494 } 495 496 return ok; 497} 498 499// Set all the kernel tracing settings to the desired state for this trace 500// capture. 501static bool setUpTrace() 502{ 503 bool ok = true; 504 505 // Set up the tracing options. 506 ok &= setTraceOverwriteEnable(g_traceOverwrite); 507 ok &= setTraceBufferSizeKB(g_traceBufferSizeKB); 508 ok &= setGlobalClockEnable(true); 509 ok &= setPrintTgidEnableIfPresent(true); 510 ok &= setKernelTraceFuncs(g_kernelTraceFuncs); 511 512 // Set up the tags property. 513 uint64_t tags = 0; 514 for (int i = 0; i < NELEM(k_categories); i++) { 515 if (g_categoryEnables[i]) { 516 const TracingCategory &c = k_categories[i]; 517 tags |= c.tags; 518 } 519 } 520 ok &= setTagsProperty(tags); 521 ok &= setAppCmdlineProperty(g_debugAppCmdLine); 522 ok &= pokeBinderServices(); 523 524 // Disable all the sysfs enables. This is done as a separate loop from 525 // the enables to allow the same enable to exist in multiple categories. 526 ok &= disableKernelTraceEvents(); 527 528 // Enable all the sysfs enables that are in an enabled category. 529 for (int i = 0; i < NELEM(k_categories); i++) { 530 if (g_categoryEnables[i]) { 531 const TracingCategory &c = k_categories[i]; 532 for (int j = 0; j < MAX_SYS_FILES; j++) { 533 const char* path = c.sysfiles[j].path; 534 bool required = c.sysfiles[j].required == REQ; 535 if (path != NULL) { 536 if (fileIsWritable(path)) { 537 ok &= setKernelOptionEnable(path, true); 538 } else if (required) { 539 fprintf(stderr, "error writing file %s\n", path); 540 ok = false; 541 } 542 } 543 } 544 } 545 } 546 547 return ok; 548} 549 550// Reset all the kernel tracing settings to their default state. 551static void cleanUpTrace() 552{ 553 // Disable all tracing that we're able to. 554 disableKernelTraceEvents(); 555 556 // Reset the system properties. 557 setTagsProperty(0); 558 setAppCmdlineProperty(""); 559 pokeBinderServices(); 560 561 // Set the options back to their defaults. 562 setTraceOverwriteEnable(true); 563 setTraceBufferSizeKB(1); 564 setGlobalClockEnable(false); 565 setPrintTgidEnableIfPresent(false); 566 setKernelTraceFuncs(NULL); 567} 568 569 570// Enable tracing in the kernel. 571static bool startTrace() 572{ 573 return setTracingEnabled(true); 574} 575 576// Disable tracing in the kernel. 577static void stopTrace() 578{ 579 setTracingEnabled(false); 580} 581 582// Read the current kernel trace and write it to stdout. 583static void dumpTrace() 584{ 585 int traceFD = open(k_tracePath, O_RDWR); 586 if (traceFD == -1) { 587 fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath, 588 strerror(errno), errno); 589 return; 590 } 591 592 if (g_compress) { 593 z_stream zs; 594 uint8_t *in, *out; 595 int result, flush; 596 597 bzero(&zs, sizeof(zs)); 598 result = deflateInit(&zs, Z_DEFAULT_COMPRESSION); 599 if (result != Z_OK) { 600 fprintf(stderr, "error initializing zlib: %d\n", result); 601 close(traceFD); 602 return; 603 } 604 605 const size_t bufSize = 64*1024; 606 in = (uint8_t*)malloc(bufSize); 607 out = (uint8_t*)malloc(bufSize); 608 flush = Z_NO_FLUSH; 609 610 zs.next_out = out; 611 zs.avail_out = bufSize; 612 613 do { 614 615 if (zs.avail_in == 0) { 616 // More input is needed. 617 result = read(traceFD, in, bufSize); 618 if (result < 0) { 619 fprintf(stderr, "error reading trace: %s (%d)\n", 620 strerror(errno), errno); 621 result = Z_STREAM_END; 622 break; 623 } else if (result == 0) { 624 flush = Z_FINISH; 625 } else { 626 zs.next_in = in; 627 zs.avail_in = result; 628 } 629 } 630 631 if (zs.avail_out == 0) { 632 // Need to write the output. 633 result = write(STDOUT_FILENO, out, bufSize); 634 if ((size_t)result < bufSize) { 635 fprintf(stderr, "error writing deflated trace: %s (%d)\n", 636 strerror(errno), errno); 637 result = Z_STREAM_END; // skip deflate error message 638 zs.avail_out = bufSize; // skip the final write 639 break; 640 } 641 zs.next_out = out; 642 zs.avail_out = bufSize; 643 } 644 645 } while ((result = deflate(&zs, flush)) == Z_OK); 646 647 if (result != Z_STREAM_END) { 648 fprintf(stderr, "error deflating trace: %s\n", zs.msg); 649 } 650 651 if (zs.avail_out < bufSize) { 652 size_t bytes = bufSize - zs.avail_out; 653 result = write(STDOUT_FILENO, out, bytes); 654 if ((size_t)result < bytes) { 655 fprintf(stderr, "error writing deflated trace: %s (%d)\n", 656 strerror(errno), errno); 657 } 658 } 659 660 result = deflateEnd(&zs); 661 if (result != Z_OK) { 662 fprintf(stderr, "error cleaning up zlib: %d\n", result); 663 } 664 665 free(in); 666 free(out); 667 } else { 668 ssize_t sent = 0; 669 while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0); 670 if (sent == -1) { 671 fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno), 672 errno); 673 } 674 } 675 676 close(traceFD); 677} 678 679static void handleSignal(int /*signo*/) 680{ 681 if (!g_nohup) { 682 g_traceAborted = true; 683 } 684} 685 686static void registerSigHandler() 687{ 688 struct sigaction sa; 689 sigemptyset(&sa.sa_mask); 690 sa.sa_flags = 0; 691 sa.sa_handler = handleSignal; 692 sigaction(SIGHUP, &sa, NULL); 693 sigaction(SIGINT, &sa, NULL); 694 sigaction(SIGQUIT, &sa, NULL); 695 sigaction(SIGTERM, &sa, NULL); 696} 697 698static bool setCategoryEnable(const char* name, bool enable) 699{ 700 for (int i = 0; i < NELEM(k_categories); i++) { 701 const TracingCategory& c = k_categories[i]; 702 if (strcmp(name, c.name) == 0) { 703 if (isCategorySupported(c)) { 704 g_categoryEnables[i] = enable; 705 return true; 706 } else { 707 if (isCategorySupportedForRoot(c)) { 708 fprintf(stderr, "error: category \"%s\" requires root " 709 "privileges.\n", name); 710 } else { 711 fprintf(stderr, "error: category \"%s\" is not supported " 712 "on this device.\n", name); 713 } 714 return false; 715 } 716 } 717 } 718 fprintf(stderr, "error: unknown tracing category \"%s\"\n", name); 719 return false; 720} 721 722static void listSupportedCategories() 723{ 724 for (int i = 0; i < NELEM(k_categories); i++) { 725 const TracingCategory& c = k_categories[i]; 726 if (isCategorySupported(c)) { 727 printf(" %10s - %s\n", c.name, c.longname); 728 } 729 } 730} 731 732// Print the command usage help to stderr. 733static void showHelp(const char *cmd) 734{ 735 fprintf(stderr, "usage: %s [options] [categories...]\n", cmd); 736 fprintf(stderr, "options include:\n" 737 " -a appname enable app-level tracing for a comma " 738 "separated list of cmdlines\n" 739 " -b N use a trace buffer size of N KB\n" 740 " -c trace into a circular buffer\n" 741 " -k fname,... trace the listed kernel functions\n" 742 " -n ignore signals\n" 743 " -s N sleep for N seconds before tracing [default 0]\n" 744 " -t N trace for N seconds [defualt 5]\n" 745 " -z compress the trace dump\n" 746 " --async_start start circular trace and return immediatly\n" 747 " --async_dump dump the current contents of circular trace buffer\n" 748 " --async_stop stop tracing and dump the current contents of circular\n" 749 " trace buffer\n" 750 " --list_categories\n" 751 " list the available tracing categories\n" 752 ); 753} 754 755int main(int argc, char **argv) 756{ 757 bool async = false; 758 bool traceStart = true; 759 bool traceStop = true; 760 bool traceDump = true; 761 762 if (argc == 2 && 0 == strcmp(argv[1], "--help")) { 763 showHelp(argv[0]); 764 exit(0); 765 } 766 767 for (;;) { 768 int ret; 769 int option_index = 0; 770 static struct option long_options[] = { 771 {"async_start", no_argument, 0, 0 }, 772 {"async_stop", no_argument, 0, 0 }, 773 {"async_dump", no_argument, 0, 0 }, 774 {"list_categories", no_argument, 0, 0 }, 775 { 0, 0, 0, 0 } 776 }; 777 778 ret = getopt_long(argc, argv, "a:b:ck:ns:t:z", 779 long_options, &option_index); 780 781 if (ret < 0) { 782 for (int i = optind; i < argc; i++) { 783 if (!setCategoryEnable(argv[i], true)) { 784 fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]); 785 exit(1); 786 } 787 } 788 break; 789 } 790 791 switch(ret) { 792 case 'a': 793 g_debugAppCmdLine = optarg; 794 break; 795 796 case 'b': 797 g_traceBufferSizeKB = atoi(optarg); 798 break; 799 800 case 'c': 801 g_traceOverwrite = true; 802 break; 803 804 case 'k': 805 g_kernelTraceFuncs = optarg; 806 break; 807 808 case 'n': 809 g_nohup = true; 810 break; 811 812 case 's': 813 g_initialSleepSecs = atoi(optarg); 814 break; 815 816 case 't': 817 g_traceDurationSeconds = atoi(optarg); 818 break; 819 820 case 'z': 821 g_compress = true; 822 break; 823 824 case 0: 825 if (!strcmp(long_options[option_index].name, "async_start")) { 826 async = true; 827 traceStop = false; 828 traceDump = false; 829 g_traceOverwrite = true; 830 } else if (!strcmp(long_options[option_index].name, "async_stop")) { 831 async = true; 832 traceStop = false; 833 } else if (!strcmp(long_options[option_index].name, "async_dump")) { 834 async = true; 835 traceStart = false; 836 traceStop = false; 837 } else if (!strcmp(long_options[option_index].name, "list_categories")) { 838 listSupportedCategories(); 839 exit(0); 840 } 841 break; 842 843 default: 844 fprintf(stderr, "\n"); 845 showHelp(argv[0]); 846 exit(-1); 847 break; 848 } 849 } 850 851 registerSigHandler(); 852 853 if (g_initialSleepSecs > 0) { 854 sleep(g_initialSleepSecs); 855 } 856 857 bool ok = true; 858 ok &= setUpTrace(); 859 ok &= startTrace(); 860 861 if (ok && traceStart) { 862 printf("capturing trace..."); 863 fflush(stdout); 864 865 // We clear the trace after starting it because tracing gets enabled for 866 // each CPU individually in the kernel. Having the beginning of the trace 867 // contain entries from only one CPU can cause "begin" entries without a 868 // matching "end" entry to show up if a task gets migrated from one CPU to 869 // another. 870 ok = clearTrace(); 871 872 if (ok && !async) { 873 // Sleep to allow the trace to be captured. 874 struct timespec timeLeft; 875 timeLeft.tv_sec = g_traceDurationSeconds; 876 timeLeft.tv_nsec = 0; 877 do { 878 if (g_traceAborted) { 879 break; 880 } 881 } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR); 882 } 883 } 884 885 // Stop the trace and restore the default settings. 886 if (traceStop) 887 stopTrace(); 888 889 if (ok && traceDump) { 890 if (!g_traceAborted) { 891 printf(" done\nTRACE:\n"); 892 fflush(stdout); 893 dumpTrace(); 894 } else { 895 printf("\ntrace aborted.\n"); 896 fflush(stdout); 897 } 898 clearTrace(); 899 } else if (!ok) { 900 fprintf(stderr, "unable to start tracing\n"); 901 } 902 903 // Reset the trace buffer size to 1. 904 if (traceStop) 905 cleanUpTrace(); 906 907 return g_traceAborted ? 1 : 0; 908} 909