atrace.cpp revision 31be80f02cddda55e75614884038fa4645b694cd
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;
3399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool g_traceFrequency = false;
3499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool g_traceBusUtilization = false;
353169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool g_traceCpuIdle = false;
36ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool g_traceDisk = false;
37cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool g_traceGovernorLoad = false;
38fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceWorkqueue = false;
39fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false;
40cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false;
4231be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic bool g_nohup = false;
4331be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic int g_initialSleepSecs = 0;
44fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
45fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */
46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false;
47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */
49fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath =
50fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
51fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
52cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath =
53cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
54cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
55fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath =
56fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
58fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath =
59fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
60fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
614b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic const char* k_schedWakeupEnablePath =
624b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
634b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
6499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char* k_memoryBusEnablePath =
6599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    "/sys/kernel/debug/tracing/events/memory_bus/enable";
6699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
67cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_cpuFreqEnablePath =
68cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
69cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
7099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char *k_clockSetRateEnablePath =
7199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable";
7299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
733169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic const char* k_cpuIdleEnablePath =
743169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
753169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
76cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_governorLoadEnablePath =
77cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
78cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
79fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath =
80fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
81fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
82ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic const char* k_diskEnablePaths[] = {
83ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
84ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
85ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
86ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
87ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown};
88ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
89fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath =
90fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
91fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
92fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath =
93fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace";
94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath =
96fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
97fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
98e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists.
99e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) {
100e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return access(filename, F_OK) != -1;
101e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis}
102e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis
103fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful.
104fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str)
105fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
106fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int fd = open(filename, O_WRONLY);
107fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (fd == -1) {
108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ssize_t len = strlen(str);
115fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (write(fd, str, len) != len) {
116fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
117fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
118fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = false;
119fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
120fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
121fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(fd);
122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
124fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(filename, enable ? "1" : "0");
130fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
131fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
132ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
133ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
134ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
135ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    bool result = true;
136ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    for (size_t i = 0; i < count; i++) {
137ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        result &= setKernelOptionEnable(filenames[i], enable);
138ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    }
139ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    return result;
140ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
141ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
142fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
143fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up.
144fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
145fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
146fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
147fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
148fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching.
150fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
151fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
1524b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool ok = true;
1534b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
1544b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
1554b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    return ok;
156fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
157fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
15899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling// Enable or disable tracing of the Bus utilization.
15999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setBusUtilizationTracingEnable(bool enable)
16099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling{
161e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    bool ok = true, oneSet = false;
16299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    // these can be platform specific so make sure that at least
16399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    // one succeeds.
164e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_memoryBusEnablePath)) {
165e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable);
166e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        oneSet |= ok;
167e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
168e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok && (oneSet || !enable);
16999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling}
17099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
171cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the CPU clock frequency.
17299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setFrequencyTracingEnable(bool enable)
173cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
17499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    bool ok = true;
17599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable);
176e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_clockSetRateEnablePath)) {
177e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable);
178e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
17999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    return ok;
180cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
181cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
1823169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis// Enable or disable tracing of CPU idle events.
1833169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool setCpuIdleTracingEnable(bool enable)
1843169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{
1853169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
1863169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis}
1873169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
188cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of
189cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// the CPU load.
190cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable)
191cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
192e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    bool ok = true;
193e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_governorLoadEnablePath) || enable) {
194e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable);
195e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
196e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok;
197cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
198cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
199fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues.
200fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
201fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
202fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
203fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
204fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
205ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable tracing of disk I/O.
206ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setDiskTracingEnabled(bool enable)
207ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
208ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
209ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
210ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
211fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing.
212fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable)
213fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace.
218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace()
219fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
220fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = creat(k_tracePath, 0);
221fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
222fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
223fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
224fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
225fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
226fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
228fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
229fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return true;
230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
232cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
233cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
234cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
235cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    char str[32] = "1";
236cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    int len;
237cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    if (size < 1) {
238cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis        size = 1;
239cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    }
240cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    snprintf(str, 32, "%d", size);
241cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
242cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
243cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock.
246fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable)
247fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
248fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
249fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
250fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
251fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel.
2524b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic bool startTrace(bool isRoot)
253fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
254fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
255fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2564b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // Set up the tracing options that don't require root.
257fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
258fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
25999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    ok &= setFrequencyTracingEnable(g_traceFrequency);
2603169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
261e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
262cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
263fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setGlobalClockEnable(true);
264fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2654b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // Set up the tracing options that do require root.  The options that
2664b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // require root should have errored out earlier if we're not running as
2674b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // root.
2684b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    if (isRoot) {
269e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setBusUtilizationTracingEnable(g_traceBusUtilization);
2704b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
2714b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        ok &= setDiskTracingEnabled(g_traceDisk);
2724b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
2734b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
274fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Enable tracing.
275fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTracingEnabled(true);
276fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
277fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (!ok) {
278fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error: unable to start trace\n");
279fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
280fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
281fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
282fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
283fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
284fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel.
2854b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic void stopTrace(bool isRoot)
286fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
287fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Disable tracing.
288fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTracingEnabled(false);
289fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
290fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set the options back to their defaults.
291fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTraceOverwriteEnable(true);
292fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setSchedSwitchTracingEnable(false);
29399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    setFrequencyTracingEnable(false);
294e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    setGovernorLoadTracingEnable(false);
295fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setGlobalClockEnable(false);
296cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
2974b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    if (isRoot) {
298e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        setBusUtilizationTracingEnable(false);
2994b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        setWorkqueueTracingEnabled(false);
3004b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        setDiskTracingEnabled(false);
3014b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
3024b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
303cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
304cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // clear the trace before we've read it.
305fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
306fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
307fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout.
308fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace()
309fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
310fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
311fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
312fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
313fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
314fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return;
315fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
316fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
3177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    if (g_compress) {
3187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        z_stream zs;
3197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        uint8_t *in, *out;
3207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        int result, flush;
3217b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3227b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        bzero(&zs, sizeof(zs));
3237b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
3247b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
3257b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
3267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            close(traceFD);
3277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            return;
3287b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3297b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3307b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        const size_t bufSize = 64*1024;
3317b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        in = (uint8_t*)malloc(bufSize);
3327b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        out = (uint8_t*)malloc(bufSize);
3337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        flush = Z_NO_FLUSH;
3347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.next_out = out;
3367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.avail_out = bufSize;
3377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        do {
3397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_in == 0) {
3417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // More input is needed.
3427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = read(traceFD, in, bufSize);
3437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if (result < 0) {
3447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
3457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
3467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END;
3477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
3487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else if (result == 0) {
3497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    flush = Z_FINISH;
3507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else {
3517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.next_in = in;
3527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_in = result;
3537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
3547b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3557b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3567b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_out == 0) {
3577b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // Need to write the output.
3587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
3597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if ((size_t)result < bufSize) {
3607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
3617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
3627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END; // skip deflate error message
3637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_out = bufSize; // skip the final write
3647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
3657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
3667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.next_out = out;
3677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.avail_out = bufSize;
3687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
3717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_STREAM_END) {
3737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
3747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (zs.avail_out < bufSize) {
3777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            size_t bytes = bufSize - zs.avail_out;
3787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            result = write(STDOUT_FILENO, out, bytes);
3797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if ((size_t)result < bytes) {
3807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
3817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                        strerror(errno), errno);
3827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateEnd(&zs);
3867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
3877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
3887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(in);
3917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(out);
3927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    } else {
3937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        ssize_t sent = 0;
3947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
3957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (sent == -1) {
3967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
3977b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    errno);
3987b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
399fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
400fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
401fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
402fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
403fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
404fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr.
405fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd)
406fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
407fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
408fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "options include:\n"
409cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
410fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -c              trace into a circular buffer\n"
411ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown                    "  -d              trace disk I/O\n"
41299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    "  -f              trace clock frequency changes\n"
413cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -l              trace CPU frequency governor load\n"
414fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -s              trace the kernel scheduler switches\n"
415fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
41699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    "  -u              trace bus utilization\n"
4177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    "  -w              trace the kernel workqueue\n"
4187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    "  -z              compress the trace dump\n");
419fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
420fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
421fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) {
42231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (!g_nohup) {
42331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        g_traceAborted = true;
42431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
425fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
426fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
427fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() {
428fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    struct sigaction sa;
429fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigemptyset(&sa.sa_mask);
430fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_flags = 0;
431fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_handler = handleSignal;
432fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGHUP, &sa, NULL);
433fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGINT, &sa, NULL);
434fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGQUIT, &sa, NULL);
435fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGTERM, &sa, NULL);
436fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
437fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
438fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv)
439fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
4404b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool isRoot = (getuid() == 0);
4414b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
442fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
443fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        showHelp(argv[0]);
444fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        exit(0);
445fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
446fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
447fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    for (;;) {
448fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        int ret;
449fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
45031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        ret = getopt(argc, argv, "b:cidflst:uwznS:");
451fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
452fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ret < 0) {
453fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
454fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
455fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
456fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        switch(ret) {
457cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'b':
458cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
459cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
460cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
461fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'c':
462fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceOverwrite = true;
463fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
464fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4653169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis            case 'i':
4663169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis                g_traceCpuIdle = true;
4673169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis            break;
4683169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
469cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'l':
470cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceGovernorLoad = true;
471cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
472cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
473ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown            case 'd':
4744b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                if (!isRoot) {
4754b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    fprintf(stderr, "error: tracing disk activity requires root privileges\n");
4764b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    exit(1);
4774b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                }
478ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown                g_traceDisk = true;
479ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown            break;
480ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
481cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'f':
48299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                g_traceFrequency = true;
483cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
484cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
48531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            case 'n':
48631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_nohup = true;
48731be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                break;
48831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
489fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 's':
490fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceSchedSwitch = true;
491fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
492fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
49331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            case 'S':
49431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_initialSleepSecs = atoi(optarg);
49531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            break;
49631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
497fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 't':
498fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceDurationSeconds = atoi(optarg);
499fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
500fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
50199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling            case 'u':
50299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                if (!isRoot) {
50399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    fprintf(stderr, "error: tracing bus utilization requires root privileges\n");
50499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    exit(1);
50599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                }
50699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                g_traceBusUtilization = true;
50799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling            break;
50899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
509fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'w':
5104b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                if (!isRoot) {
5114b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
5124b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    exit(1);
5134b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                }
514fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceWorkqueue = true;
515fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
516fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            case 'z':
5187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                g_compress = true;
5197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            break;
5207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
521fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            default:
522cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                fprintf(stderr, "\n");
523fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                showHelp(argv[0]);
524fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                exit(-1);
525fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
526fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
527fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
528fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
529fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    registerSigHandler();
530fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
53131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (g_initialSleepSecs > 0) {
53231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        sleep(g_initialSleepSecs);
53331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
53431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
5354b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool ok = startTrace(isRoot);
536fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
537fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (ok) {
538fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        printf("capturing trace...");
539fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fflush(stdout);
540fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
541fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // We clear the trace after starting it because tracing gets enabled for
542fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
543fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
544fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
545fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // another.
546fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = clearTrace();
547fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
548fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ok) {
549fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            // Sleep to allow the trace to be captured.
550fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            struct timespec timeLeft;
551fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
552fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_nsec = 0;
553fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            do {
554fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                if (g_traceAborted) {
555fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    break;
556fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                }
557fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
558fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
559fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
560fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
561fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Stop the trace and restore the default settings.
5624b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    stopTrace(isRoot);
563fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
564fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (ok) {
565fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (!g_traceAborted) {
566fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf(" done\nTRACE:\n");
567fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
568fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            dumpTrace();
569fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        } else {
570fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf("\ntrace aborted.\n");
571fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
572fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
573fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        clearTrace();
574fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    } else {
575fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "unable to start tracing\n");
576fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
577fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
578cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Reset the trace buffer size to 1.
579cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    setTraceBufferSizeKB(1);
580cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
581fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return g_traceAborted ? 1 : 0;
582fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
583