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