atrace.cpp revision ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9
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>
267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis#include <zlib.h>
27fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
28ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
29ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
30fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Command line options */
31fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic int g_traceDurationSeconds = 5;
32fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceSchedSwitch = false;
33cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool g_traceCpuFrequency = false;
343169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool g_traceCpuIdle = false;
35ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool g_traceDisk = false;
36cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool g_traceGovernorLoad = false;
37fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceWorkqueue = false;
38fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false;
39cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false;
41fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
42fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */
43fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false;
44fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
45fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */
46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath =
47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
49cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath =
50cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
51cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
52fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath =
53fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
54fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
55fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath =
56fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
58cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_cpuFreqEnablePath =
59cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
60cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
613169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic const char* k_cpuIdleEnablePath =
623169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
633169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
64cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_governorLoadEnablePath =
65cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
66cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
67fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath =
68fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
69fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
70ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic const char* k_diskEnablePaths[] = {
71ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
72ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
73ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
74ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
75ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown};
76ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
77fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath =
78fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
79fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
80fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath =
81fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace";
82fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
83fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath =
84fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
85fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
86fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful.
87fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str)
88fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
89fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int fd = open(filename, O_WRONLY);
90fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (fd == -1) {
91fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
92fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
93fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
96fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
97fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ssize_t len = strlen(str);
98fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (write(fd, str, len) != len) {
99fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
100fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
101fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = false;
102fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
103fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
104fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(fd);
105fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
106fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
107fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(filename, enable ? "1" : "0");
113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
115ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
116ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
117ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
118ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    bool result = true;
119ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    for (size_t i = 0; i < count; i++) {
120ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        result &= setKernelOptionEnable(filenames[i], enable);
121ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    }
122ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    return result;
123ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
124ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up.
127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
130fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
131fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
132fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching.
133fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
134fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
135fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_schedSwitchEnablePath, enable);
136fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
137fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
138cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the CPU clock frequency.
139cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setCpuFrequencyTracingEnable(bool enable)
140cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
141cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    return setKernelOptionEnable(k_cpuFreqEnablePath, enable);
142cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
143cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
1443169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis// Enable or disable tracing of CPU idle events.
1453169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool setCpuIdleTracingEnable(bool enable)
1463169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{
1473169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
1483169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis}
1493169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
150cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of
151cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// the CPU load.
152cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable)
153cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
154cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    return setKernelOptionEnable(k_governorLoadEnablePath, enable);
155cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
156cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
157fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues.
158fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
159fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
160fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
161fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
162fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
163ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable tracing of disk I/O.
164ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setDiskTracingEnabled(bool enable)
165ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
166ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
167ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
168ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
169fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing.
170fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable)
171fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
172fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
173fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
174fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
175fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace.
176fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace()
177fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
178fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = creat(k_tracePath, 0);
179fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
180fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
181fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
182fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
183fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
184fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
185fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
186fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
187fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return true;
188fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
189fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
190cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
191cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
192cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
193cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    char str[32] = "1";
194cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    int len;
195cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    if (size < 1) {
196cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis        size = 1;
197cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    }
198cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    snprintf(str, 32, "%d", size);
199cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
200cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
201cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
202fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
203fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock.
204fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable)
205fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
206fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
207fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
208fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
209fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis// Check whether a file exists.
210fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennisstatic bool fileExists(const char* filename) {
211fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis    return access(filename, F_OK) != -1;
212fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis}
213fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis
214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel.
215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool startTrace()
216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
219fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set up the tracing options.
220fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
221fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
222cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    ok &= setCpuFrequencyTracingEnable(g_traceCpuFrequency);
2233169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
224fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis    if (fileExists(k_governorLoadEnablePath) || g_traceGovernorLoad) {
225fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis        ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
226fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis    }
227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
228ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    ok &= setDiskTracingEnabled(g_traceDisk);
229cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setGlobalClockEnable(true);
231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
232fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Enable tracing.
233fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTracingEnabled(true);
234fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
235fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (!ok) {
236fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error: unable to start trace\n");
237fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
238fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
239fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
240fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
241fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel.
243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void stopTrace()
244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Disable tracing.
246fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTracingEnabled(false);
247fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
248fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set the options back to their defaults.
249fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTraceOverwriteEnable(true);
250fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setSchedSwitchTracingEnable(false);
251cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    setCpuFrequencyTracingEnable(false);
252fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis    if (fileExists(k_governorLoadEnablePath)) {
253fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis        setGovernorLoadTracingEnable(false);
254fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis    }
255fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setWorkqueueTracingEnabled(false);
256fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setGlobalClockEnable(false);
257cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
258cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
259cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // clear the trace before we've read it.
260fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
261fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
262fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout.
263fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace()
264fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
265fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
266fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
267fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
268fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
269fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return;
270fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
271fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    if (g_compress) {
2737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        z_stream zs;
2747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        uint8_t *in, *out;
2757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        int result, flush;
2767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
2777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        bzero(&zs, sizeof(zs));
2787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
2797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
2807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
2817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            close(traceFD);
2827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            return;
2837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
2847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
2857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        const size_t bufSize = 64*1024;
2867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        in = (uint8_t*)malloc(bufSize);
2877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        out = (uint8_t*)malloc(bufSize);
2887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        flush = Z_NO_FLUSH;
2897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
2907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.next_out = out;
2917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.avail_out = bufSize;
2927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
2937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        do {
2947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
2957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_in == 0) {
2967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // More input is needed.
2977b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = read(traceFD, in, bufSize);
2987b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if (result < 0) {
2997b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
3007b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
3017b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END;
3027b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
3037b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else if (result == 0) {
3047b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    flush = Z_FINISH;
3057b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else {
3067b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.next_in = in;
3077b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_in = result;
3087b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
3097b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3107b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3117b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_out == 0) {
3127b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // Need to write the output.
3137b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
3147b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if ((size_t)result < bufSize) {
3157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
3167b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
3177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END; // skip deflate error message
3187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_out = bufSize; // skip the final write
3197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
3207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
3217b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.next_out = out;
3227b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.avail_out = bufSize;
3237b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3247b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3257b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
3267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_STREAM_END) {
3287b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
3297b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3307b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3317b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (zs.avail_out < bufSize) {
3327b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            size_t bytes = bufSize - zs.avail_out;
3337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            result = write(STDOUT_FILENO, out, bytes);
3347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if ((size_t)result < bytes) {
3357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
3367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                        strerror(errno), errno);
3377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateEnd(&zs);
3417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
3427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
3437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(in);
3467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(out);
3477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    } else {
3487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        ssize_t sent = 0;
3497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
3507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (sent == -1) {
3517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
3527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    errno);
3537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
354fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
355fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
356fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
357fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
358fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
359fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr.
360fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd)
361fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
362fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
363fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "options include:\n"
364cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
365fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -c              trace into a circular buffer\n"
366ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown                    "  -d              trace disk I/O\n"
367cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -f              trace CPU frequency changes\n"
368cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -l              trace CPU frequency governor load\n"
369fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -s              trace the kernel scheduler switches\n"
370fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
3717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    "  -w              trace the kernel workqueue\n"
3727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    "  -z              compress the trace dump\n");
373fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
374fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
375fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) {
376fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    g_traceAborted = true;
377fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
378fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
379fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() {
380fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    struct sigaction sa;
381fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigemptyset(&sa.sa_mask);
382fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_flags = 0;
383fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_handler = handleSignal;
384fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGHUP, &sa, NULL);
385fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGINT, &sa, NULL);
386fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGQUIT, &sa, NULL);
387fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGTERM, &sa, NULL);
388fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
389fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
390fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv)
391fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
392fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
393fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        showHelp(argv[0]);
394fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        exit(0);
395fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
396fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
397fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (getuid() != 0) {
398fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error: %s must be run as root.", argv[0]);
399cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis        exit(1);
400fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
401fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
402fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    for (;;) {
403fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        int ret;
404fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
405ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        ret = getopt(argc, argv, "b:cidflst:wz");
406fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
407fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ret < 0) {
408fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
409fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
410fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
411fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        switch(ret) {
412cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'b':
413cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
414cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
415cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
416fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'c':
417fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceOverwrite = true;
418fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
419fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4203169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis            case 'i':
4213169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis                g_traceCpuIdle = true;
4223169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis            break;
4233169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
424cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'l':
425cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceGovernorLoad = true;
426cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
427cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
428ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown            case 'd':
429ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown                g_traceDisk = true;
430ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown            break;
431ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
432cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'f':
433cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceCpuFrequency = true;
434cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
435cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
436fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 's':
437fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceSchedSwitch = true;
438fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
439fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
440fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 't':
441fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceDurationSeconds = atoi(optarg);
442fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
443fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
444fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'w':
445fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceWorkqueue = true;
446fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
447fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            case 'z':
4497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                g_compress = true;
4507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            break;
4517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
452fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            default:
453cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                fprintf(stderr, "\n");
454fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                showHelp(argv[0]);
455fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                exit(-1);
456fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
457fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
458fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
459fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
460fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    registerSigHandler();
461fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
462fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = startTrace();
463fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
464fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (ok) {
465fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        printf("capturing trace...");
466fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fflush(stdout);
467fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
468fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // We clear the trace after starting it because tracing gets enabled for
469fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
470fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
471fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
472fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // another.
473fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = clearTrace();
474fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
475fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ok) {
476fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            // Sleep to allow the trace to be captured.
477fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            struct timespec timeLeft;
478fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
479fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_nsec = 0;
480fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            do {
481fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                if (g_traceAborted) {
482fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    break;
483fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                }
484fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
485fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
486fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
487fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
488fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Stop the trace and restore the default settings.
489fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    stopTrace();
490fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
491fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (ok) {
492fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (!g_traceAborted) {
493fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf(" done\nTRACE:\n");
494fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
495fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            dumpTrace();
496fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        } else {
497fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf("\ntrace aborted.\n");
498fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
499fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
500fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        clearTrace();
501fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    } else {
502fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "unable to start tracing\n");
503fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
504fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
505cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Reset the trace buffer size to 1.
506cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    setTraceBufferSizeKB(1);
507cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
508fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return g_traceAborted ? 1 : 0;
509fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
510