atrace.c revision 6b995818535af84c4a6829af7733684861f20144
16b995818535af84c4a6829af7733684861f20144Jamie Gennis/*
26b995818535af84c4a6829af7733684861f20144Jamie Gennis * Copyright (C) 2012 The Android Open Source Project
36b995818535af84c4a6829af7733684861f20144Jamie Gennis *
46b995818535af84c4a6829af7733684861f20144Jamie Gennis * Licensed under the Apache License, Version 2.0 (the "License");
56b995818535af84c4a6829af7733684861f20144Jamie Gennis * you may not use this file except in compliance with the License.
66b995818535af84c4a6829af7733684861f20144Jamie Gennis * You may obtain a copy of the License at
76b995818535af84c4a6829af7733684861f20144Jamie Gennis *
86b995818535af84c4a6829af7733684861f20144Jamie Gennis *      http://www.apache.org/licenses/LICENSE-2.0
96b995818535af84c4a6829af7733684861f20144Jamie Gennis *
106b995818535af84c4a6829af7733684861f20144Jamie Gennis * Unless required by applicable law or agreed to in writing, software
116b995818535af84c4a6829af7733684861f20144Jamie Gennis * distributed under the License is distributed on an "AS IS" BASIS,
126b995818535af84c4a6829af7733684861f20144Jamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136b995818535af84c4a6829af7733684861f20144Jamie Gennis * See the License for the specific language governing permissions and
146b995818535af84c4a6829af7733684861f20144Jamie Gennis * limitations under the License.
156b995818535af84c4a6829af7733684861f20144Jamie Gennis */
166b995818535af84c4a6829af7733684861f20144Jamie Gennis
176b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <errno.h>
186b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <fcntl.h>
196b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <signal.h>
206b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdarg.h>
216b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdbool.h>
226b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdio.h>
236b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdlib.h>
246b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <sys/sendfile.h>
256b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <time.h>
266b995818535af84c4a6829af7733684861f20144Jamie Gennis
276b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Command line options */
286b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic int g_traceDurationSeconds = 5;
296b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceSchedSwitch = false;
306b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceWorkqueue = false;
316b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceOverwrite = false;
326b995818535af84c4a6829af7733684861f20144Jamie Gennis
336b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Global state */
346b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceAborted = false;
356b995818535af84c4a6829af7733684861f20144Jamie Gennis
366b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Sys file paths */
376b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceClockPath =
386b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
396b995818535af84c4a6829af7733684861f20144Jamie Gennis
406b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOverwriteEnablePath =
416b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
426b995818535af84c4a6829af7733684861f20144Jamie Gennis
436b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_schedSwitchEnablePath =
446b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
456b995818535af84c4a6829af7733684861f20144Jamie Gennis
466b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_workqueueEnablePath =
476b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
486b995818535af84c4a6829af7733684861f20144Jamie Gennis
496b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOnPath =
506b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
516b995818535af84c4a6829af7733684861f20144Jamie Gennis
526b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracePath =
536b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace";
546b995818535af84c4a6829af7733684861f20144Jamie Gennis
556b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceMarkerPath =
566b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
576b995818535af84c4a6829af7733684861f20144Jamie Gennis
586b995818535af84c4a6829af7733684861f20144Jamie Gennis// Write a string to a file, returning true if the write was successful.
596b995818535af84c4a6829af7733684861f20144Jamie Gennisbool writeStr(const char* filename, const char* str)
606b995818535af84c4a6829af7733684861f20144Jamie Gennis{
616b995818535af84c4a6829af7733684861f20144Jamie Gennis    int fd = open(filename, O_WRONLY);
626b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (fd == -1) {
636b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
646b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
656b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
666b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
676b995818535af84c4a6829af7733684861f20144Jamie Gennis
686b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
696b995818535af84c4a6829af7733684861f20144Jamie Gennis    ssize_t len = strlen(str);
706b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (write(fd, str, len) != len) {
716b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
726b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
736b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = false;
746b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
756b995818535af84c4a6829af7733684861f20144Jamie Gennis
766b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(fd);
776b995818535af84c4a6829af7733684861f20144Jamie Gennis
786b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
796b995818535af84c4a6829af7733684861f20144Jamie Gennis}
806b995818535af84c4a6829af7733684861f20144Jamie Gennis
816b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
826b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
836b995818535af84c4a6829af7733684861f20144Jamie Gennis{
846b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(filename, enable ? "1" : "0");
856b995818535af84c4a6829af7733684861f20144Jamie Gennis}
866b995818535af84c4a6829af7733684861f20144Jamie Gennis
876b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
886b995818535af84c4a6829af7733684861f20144Jamie Gennis// will cause tracing to stop once the trace buffers have filled up.
896b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
906b995818535af84c4a6829af7733684861f20144Jamie Gennis{
916b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
926b995818535af84c4a6829af7733684861f20144Jamie Gennis}
936b995818535af84c4a6829af7733684861f20144Jamie Gennis
946b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel scheduler switching.
956b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
966b995818535af84c4a6829af7733684861f20144Jamie Gennis{
976b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_schedSwitchEnablePath, enable);
986b995818535af84c4a6829af7733684861f20144Jamie Gennis}
996b995818535af84c4a6829af7733684861f20144Jamie Gennis
1006b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel workqueues.
1016b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
1026b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1036b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
1046b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1056b995818535af84c4a6829af7733684861f20144Jamie Gennis
1066b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable kernel tracing.
1076b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTracingEnabled(bool enable)
1086b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1096b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
1106b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1116b995818535af84c4a6829af7733684861f20144Jamie Gennis
1126b995818535af84c4a6829af7733684861f20144Jamie Gennis// Clear the contents of the kernel trace.
1136b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool clearTrace()
1146b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1156b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = creat(k_tracePath, 0);
1166b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
1176b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
1186b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1196b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
1206b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1216b995818535af84c4a6829af7733684861f20144Jamie Gennis
1226b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
1236b995818535af84c4a6829af7733684861f20144Jamie Gennis
1246b995818535af84c4a6829af7733684861f20144Jamie Gennis    return true;
1256b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1266b995818535af84c4a6829af7733684861f20144Jamie Gennis
1276b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
1286b995818535af84c4a6829af7733684861f20144Jamie Gennis// clock will result in the kernel using a per-CPU local clock.
1296b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setGlobalClockEnable(bool enable)
1306b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1316b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
1326b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1336b995818535af84c4a6829af7733684861f20144Jamie Gennis
1346b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable tracing in the kernel.
1356b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool startTrace()
1366b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1376b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
1386b995818535af84c4a6829af7733684861f20144Jamie Gennis
1396b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Set up the tracing options.
1406b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
1416b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
1426b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
1436b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setGlobalClockEnable(true);
1446b995818535af84c4a6829af7733684861f20144Jamie Gennis
1456b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Enable tracing.
1466b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTracingEnabled(true);
1476b995818535af84c4a6829af7733684861f20144Jamie Gennis
1486b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (!ok) {
1496b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error: unable to start trace\n");
1506b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1516b995818535af84c4a6829af7733684861f20144Jamie Gennis
1526b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
1536b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1546b995818535af84c4a6829af7733684861f20144Jamie Gennis
1556b995818535af84c4a6829af7733684861f20144Jamie Gennis// Disable tracing in the kernel.
1566b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void stopTrace()
1576b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1586b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Disable tracing.
1596b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTracingEnabled(false);
1606b995818535af84c4a6829af7733684861f20144Jamie Gennis
1616b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Set the options back to their defaults.
1626b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTraceOverwriteEnable(true);
1636b995818535af84c4a6829af7733684861f20144Jamie Gennis    setSchedSwitchTracingEnable(false);
1646b995818535af84c4a6829af7733684861f20144Jamie Gennis    setWorkqueueTracingEnabled(false);
1656b995818535af84c4a6829af7733684861f20144Jamie Gennis    setGlobalClockEnable(false);
1666b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1676b995818535af84c4a6829af7733684861f20144Jamie Gennis
1686b995818535af84c4a6829af7733684861f20144Jamie Gennis// Read the current kernel trace and write it to stdout.
1696b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void dumpTrace()
1706b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1716b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
1726b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
1736b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
1746b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1756b995818535af84c4a6829af7733684861f20144Jamie Gennis        return;
1766b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1776b995818535af84c4a6829af7733684861f20144Jamie Gennis
1786b995818535af84c4a6829af7733684861f20144Jamie Gennis    ssize_t sent = 0;
1796b995818535af84c4a6829af7733684861f20144Jamie Gennis    while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
1806b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (sent == -1) {
1816b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
1826b995818535af84c4a6829af7733684861f20144Jamie Gennis                errno);
1836b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1846b995818535af84c4a6829af7733684861f20144Jamie Gennis
1856b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
1866b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1876b995818535af84c4a6829af7733684861f20144Jamie Gennis
1886b995818535af84c4a6829af7733684861f20144Jamie Gennis// Print the command usage help to stderr.
1896b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void showHelp(const char *cmd)
1906b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1916b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
1926b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "options include:\n"
1936b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -c              trace into a circular buffer\n"
1946b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -s              trace the kernel scheduler switches\n"
1956b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
1966b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -w              trace the kernel workqueue\n");
1976b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1986b995818535af84c4a6829af7733684861f20144Jamie Gennis
1996b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void handleSignal(int signo) {
2006b995818535af84c4a6829af7733684861f20144Jamie Gennis    g_traceAborted = true;
2016b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2026b995818535af84c4a6829af7733684861f20144Jamie Gennis
2036b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void registerSigHandler() {
2046b995818535af84c4a6829af7733684861f20144Jamie Gennis    struct sigaction sa;
2056b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigemptyset(&sa.sa_mask);
2066b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_flags = 0;
2076b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_handler = handleSignal;
2086b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGHUP, &sa, NULL);
2096b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGINT, &sa, NULL);
2106b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGQUIT, &sa, NULL);
2116b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGTERM, &sa, NULL);
2126b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2136b995818535af84c4a6829af7733684861f20144Jamie Gennis
2146b995818535af84c4a6829af7733684861f20144Jamie Gennisint main(int argc, char **argv)
2156b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2166b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
2176b995818535af84c4a6829af7733684861f20144Jamie Gennis        showHelp(argv[0]);
2186b995818535af84c4a6829af7733684861f20144Jamie Gennis        exit(0);
2196b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2206b995818535af84c4a6829af7733684861f20144Jamie Gennis
2216b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (getuid() != 0) {
2226b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error: %s must be run as root.", argv[0]);
2236b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2246b995818535af84c4a6829af7733684861f20144Jamie Gennis
2256b995818535af84c4a6829af7733684861f20144Jamie Gennis    for (;;) {
2266b995818535af84c4a6829af7733684861f20144Jamie Gennis        int ret;
2276b995818535af84c4a6829af7733684861f20144Jamie Gennis
2286b995818535af84c4a6829af7733684861f20144Jamie Gennis        ret = getopt(argc, argv, "cst:w");
2296b995818535af84c4a6829af7733684861f20144Jamie Gennis
2306b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ret < 0) {
2316b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
2326b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
2336b995818535af84c4a6829af7733684861f20144Jamie Gennis
2346b995818535af84c4a6829af7733684861f20144Jamie Gennis        switch(ret) {
2356b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'c':
2366b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceOverwrite = true;
2376b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
2386b995818535af84c4a6829af7733684861f20144Jamie Gennis
2396b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 's':
2406b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceSchedSwitch = true;
2416b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
2426b995818535af84c4a6829af7733684861f20144Jamie Gennis
2436b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 't':
2446b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceDurationSeconds = atoi(optarg);
2456b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
2466b995818535af84c4a6829af7733684861f20144Jamie Gennis
2476b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'w':
2486b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceWorkqueue = true;
2496b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
2506b995818535af84c4a6829af7733684861f20144Jamie Gennis
2516b995818535af84c4a6829af7733684861f20144Jamie Gennis            default:
2526b995818535af84c4a6829af7733684861f20144Jamie Gennis                showHelp(argv[0]);
2536b995818535af84c4a6829af7733684861f20144Jamie Gennis                exit(-1);
2546b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
2556b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
2566b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2576b995818535af84c4a6829af7733684861f20144Jamie Gennis
2586b995818535af84c4a6829af7733684861f20144Jamie Gennis    registerSigHandler();
2596b995818535af84c4a6829af7733684861f20144Jamie Gennis
2606b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = startTrace();
2616b995818535af84c4a6829af7733684861f20144Jamie Gennis
2626b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
2636b995818535af84c4a6829af7733684861f20144Jamie Gennis        printf("capturing trace...");
2646b995818535af84c4a6829af7733684861f20144Jamie Gennis        fflush(stdout);
2656b995818535af84c4a6829af7733684861f20144Jamie Gennis
2666b995818535af84c4a6829af7733684861f20144Jamie Gennis        // We clear the trace after starting it because tracing gets enabled for
2676b995818535af84c4a6829af7733684861f20144Jamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
2686b995818535af84c4a6829af7733684861f20144Jamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
2696b995818535af84c4a6829af7733684861f20144Jamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
2706b995818535af84c4a6829af7733684861f20144Jamie Gennis        // another.
2716b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = clearTrace();
2726b995818535af84c4a6829af7733684861f20144Jamie Gennis
2736b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ok) {
2746b995818535af84c4a6829af7733684861f20144Jamie Gennis            // Sleep to allow the trace to be captured.
2756b995818535af84c4a6829af7733684861f20144Jamie Gennis            struct timespec timeLeft;
2766b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
2776b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_nsec = 0;
2786b995818535af84c4a6829af7733684861f20144Jamie Gennis            do {
2796b995818535af84c4a6829af7733684861f20144Jamie Gennis                if (g_traceAborted) {
2806b995818535af84c4a6829af7733684861f20144Jamie Gennis                    break;
2816b995818535af84c4a6829af7733684861f20144Jamie Gennis                }
2826b995818535af84c4a6829af7733684861f20144Jamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
2836b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
2846b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2856b995818535af84c4a6829af7733684861f20144Jamie Gennis
2866b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Stop the trace and restore the default settings.
2876b995818535af84c4a6829af7733684861f20144Jamie Gennis    stopTrace();
2886b995818535af84c4a6829af7733684861f20144Jamie Gennis
2896b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
2906b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (!g_traceAborted) {
2916b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf(" done\nTRACE:\n");
2926b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
2936b995818535af84c4a6829af7733684861f20144Jamie Gennis            dumpTrace();
2946b995818535af84c4a6829af7733684861f20144Jamie Gennis        } else {
2956b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf("\ntrace aborted.\n");
2966b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
2976b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
2986b995818535af84c4a6829af7733684861f20144Jamie Gennis        clearTrace();
2996b995818535af84c4a6829af7733684861f20144Jamie Gennis    } else {
3006b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "unable to start tracing\n");
3016b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
3026b995818535af84c4a6829af7733684861f20144Jamie Gennis
3036b995818535af84c4a6829af7733684861f20144Jamie Gennis    return g_traceAborted ? 1 : 0;
3046b995818535af84c4a6829af7733684861f20144Jamie Gennis}
305