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