atrace.cpp revision fb31ba69282e34df62005ec63afda2b8ec69533e
1fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/*
2fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Copyright (C) 2012 The Android Open Source Project
3fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
4fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Licensed under the Apache License, Version 2.0 (the "License");
5fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * you may not use this file except in compliance with the License.
6fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * You may obtain a copy of the License at
7fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
8fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *      http://www.apache.org/licenses/LICENSE-2.0
9fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
10fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Unless required by applicable law or agreed to in writing, software
11fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * distributed under the License is distributed on an "AS IS" BASIS,
12fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * See the License for the specific language governing permissions and
14fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * limitations under the License.
15fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis */
16fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
17fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <errno.h>
18fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <fcntl.h>
19fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <signal.h>
20fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdarg.h>
21fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdbool.h>
22fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdio.h>
23fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdlib.h>
24fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <sys/sendfile.h>
25fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <time.h>
26fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
27fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Command line options */
28fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic int g_traceDurationSeconds = 5;
29fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceSchedSwitch = false;
30fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceWorkqueue = false;
31fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false;
32fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
33fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */
34fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false;
35fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
36fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */
37fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath =
38fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
39fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
40fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath =
41fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
42fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
43fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath =
44fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
45fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath =
47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
49fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath =
50fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
51fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
52fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath =
53fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace";
54fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
55fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath =
56fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
58fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful.
59fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str)
60fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
61fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int fd = open(filename, O_WRONLY);
62fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (fd == -1) {
63fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
64fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
65fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
66fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
67fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
68fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
69fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ssize_t len = strlen(str);
70fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (write(fd, str, len) != len) {
71fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
72fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
73fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = false;
74fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
75fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
76fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(fd);
77fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
78fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
79fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
80fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
81fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
82fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
83fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
84fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(filename, enable ? "1" : "0");
85fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
86fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
87fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
88fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up.
89fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
90fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
91fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
92fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
93fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching.
95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
96fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
97fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_schedSwitchEnablePath, enable);
98fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
99fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
100fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues.
101fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
102fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
103fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
104fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
105fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
106fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing.
107fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable)
108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace.
113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace()
114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
115fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = creat(k_tracePath, 0);
116fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
117fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
118fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
119fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
120fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
121fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
124fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return true;
125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock.
129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable)
130fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
131fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
132fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
133fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
134fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel.
135fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool startTrace()
136fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
137fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
138fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
139fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set up the tracing options.
140fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
141fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
142fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
143fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setGlobalClockEnable(true);
144fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
145fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Enable tracing.
146fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTracingEnabled(true);
147fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
148fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (!ok) {
149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error: unable to start trace\n");
150fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
151fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
152fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
153fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
154fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
155fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel.
156fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void stopTrace()
157fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
158fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Disable tracing.
159fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTracingEnabled(false);
160fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
161fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set the options back to their defaults.
162fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTraceOverwriteEnable(true);
163fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setSchedSwitchTracingEnable(false);
164fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setWorkqueueTracingEnabled(false);
165fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setGlobalClockEnable(false);
166fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
167fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
168fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout.
169fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace()
170fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
171fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
172fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
173fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
174fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
175fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return;
176fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
177fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
178fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ssize_t sent = 0;
179fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
180fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (sent == -1) {
181fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
182fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                errno);
183fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
184fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
185fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
186fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
187fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
188fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr.
189fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd)
190fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
191fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
192fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "options include:\n"
193fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -c              trace into a circular buffer\n"
194fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -s              trace the kernel scheduler switches\n"
195fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
196fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -w              trace the kernel workqueue\n");
197fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
198fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
199fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) {
200fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    g_traceAborted = true;
201fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
202fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
203fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() {
204fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    struct sigaction sa;
205fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigemptyset(&sa.sa_mask);
206fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_flags = 0;
207fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_handler = handleSignal;
208fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGHUP, &sa, NULL);
209fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGINT, &sa, NULL);
210fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGQUIT, &sa, NULL);
211fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGTERM, &sa, NULL);
212fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
213fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv)
215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        showHelp(argv[0]);
218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        exit(0);
219fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
220fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
221fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (getuid() != 0) {
222fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error: %s must be run as root.", argv[0]);
223fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
224fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
225fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    for (;;) {
226fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        int ret;
227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
228fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ret = getopt(argc, argv, "cst:w");
229fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ret < 0) {
231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
232fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
233fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
234fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        switch(ret) {
235fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'c':
236fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceOverwrite = true;
237fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
238fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
239fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 's':
240fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceSchedSwitch = true;
241fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 't':
244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceDurationSeconds = atoi(optarg);
245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
246fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
247fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'w':
248fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceWorkqueue = true;
249fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
250fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
251fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            default:
252fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                showHelp(argv[0]);
253fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                exit(-1);
254fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
255fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
256fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
257fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
258fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    registerSigHandler();
259fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
260fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = startTrace();
261fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
262fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (ok) {
263fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        printf("capturing trace...");
264fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fflush(stdout);
265fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
266fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // We clear the trace after starting it because tracing gets enabled for
267fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
268fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
269fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
270fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // another.
271fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = clearTrace();
272fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
273fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ok) {
274fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            // Sleep to allow the trace to be captured.
275fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            struct timespec timeLeft;
276fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
277fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_nsec = 0;
278fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            do {
279fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                if (g_traceAborted) {
280fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    break;
281fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                }
282fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
283fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
284fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
285fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
286fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Stop the trace and restore the default settings.
287fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    stopTrace();
288fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
289fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (ok) {
290fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (!g_traceAborted) {
291fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf(" done\nTRACE:\n");
292fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
293fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            dumpTrace();
294fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        } else {
295fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf("\ntrace aborted.\n");
296fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
297fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
298fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        clearTrace();
299fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    } else {
300fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "unable to start tracing\n");
301fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
302fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
303fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return g_traceAborted ? 1 : 0;
304fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
305