atrace.cpp revision 4edbd078cddcc1cbe59156a0e7ece01de75156e0
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>
194edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling#include <getopt.h>
20fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <signal.h>
21fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdarg.h>
22fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdbool.h>
23fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdio.h>
24fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdlib.h>
25fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <sys/sendfile.h>
26fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <time.h>
277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis#include <zlib.h>
28fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
29ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
30ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
31fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Command line options */
32fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic int g_traceDurationSeconds = 5;
33fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceSchedSwitch = false;
3499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool g_traceFrequency = false;
3599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool g_traceBusUtilization = false;
363169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool g_traceCpuIdle = false;
37ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool g_traceDisk = false;
38cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool g_traceGovernorLoad = false;
399ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic bool g_traceSync = false;
40fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceWorkqueue = false;
41fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false;
42cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false;
4431be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic bool g_nohup = false;
4531be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic int g_initialSleepSecs = 0;
46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */
48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false;
49fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
50fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */
51fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath =
52fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
53fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
54cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath =
55cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
56cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath =
58fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
59fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
60fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath =
61fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
62fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
634b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic const char* k_schedWakeupEnablePath =
644b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
654b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
6699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char* k_memoryBusEnablePath =
6799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    "/sys/kernel/debug/tracing/events/memory_bus/enable";
6899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
69cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_cpuFreqEnablePath =
70cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
71cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
7299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char *k_clockSetRateEnablePath =
7399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable";
7499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
753169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic const char* k_cpuIdleEnablePath =
763169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
773169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
78cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_governorLoadEnablePath =
79cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
80cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
819ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic const char* k_syncEnablePath =
829ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    "/sys/kernel/debug/tracing/events/sync/enable";
839ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling
84fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath =
85fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
86fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
87ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic const char* k_diskEnablePaths[] = {
88ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
89ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
90ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
91ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
92ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown};
93ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath =
95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
96fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
97fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath =
98fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace";
99fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
100fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath =
101fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
102fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
103e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists.
104e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) {
105e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return access(filename, F_OK) != -1;
106e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis}
107e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis
108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful.
109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str)
110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int fd = open(filename, O_WRONLY);
112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (fd == -1) {
113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
115fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
116fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
117fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
118fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
119fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ssize_t len = strlen(str);
120fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (write(fd, str, len) != len) {
121fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = false;
124fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(fd);
127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
130fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
131fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
132fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
133fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
134fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(filename, enable ? "1" : "0");
135fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
136fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
137ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
138ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
139ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
140ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    bool result = true;
141ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    for (size_t i = 0; i < count; i++) {
142ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        result &= setKernelOptionEnable(filenames[i], enable);
143ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    }
144ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    return result;
145ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
146ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
147fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
148fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up.
149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
150fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
151fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
152fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
153fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
154fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching.
155fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
156fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
1574b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool ok = true;
1584b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
1594b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
1604b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    return ok;
161fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
162fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
16399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling// Enable or disable tracing of the Bus utilization.
16499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setBusUtilizationTracingEnable(bool enable)
16599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling{
166e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    bool ok = true, oneSet = false;
16799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    // these can be platform specific so make sure that at least
16899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    // one succeeds.
169e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_memoryBusEnablePath)) {
170e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable);
171e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        oneSet |= ok;
172e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
173e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok && (oneSet || !enable);
17499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling}
17599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
176cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the CPU clock frequency.
17799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setFrequencyTracingEnable(bool enable)
178cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
17999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    bool ok = true;
18099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable);
181e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_clockSetRateEnablePath)) {
182e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable);
183e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
18499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    return ok;
185cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
186cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
1873169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis// Enable or disable tracing of CPU idle events.
1883169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool setCpuIdleTracingEnable(bool enable)
1893169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{
1903169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
1913169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis}
1923169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
193cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of
194cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// the CPU load.
195cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable)
196cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
197e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    bool ok = true;
198e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_governorLoadEnablePath) || enable) {
199e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable);
200e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
201e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok;
202cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
203cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
2049ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling// Enable or disable tracing of sync timelines and waits.
2059ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic bool setSyncTracingEnabled(bool enable)
2069ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling{
2079ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    bool ok = true;
2089ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    if (fileExists(k_syncEnablePath) || enable) {
2099ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling        ok &= setKernelOptionEnable(k_syncEnablePath, enable);
2109ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    }
2119ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    return ok;
2129ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling}
2139ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling
214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues.
215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
219fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
220ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable tracing of disk I/O.
221ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setDiskTracingEnabled(bool enable)
222ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
223ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
224ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
225ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
226fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing.
227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable)
228fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
229fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
232fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace.
233fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace()
234fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
235fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = creat(k_tracePath, 0);
236fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
237fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
238fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
239fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
240fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
241fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return true;
245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
246fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
247cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
248cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
249cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
250cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    char str[32] = "1";
251cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    int len;
252cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    if (size < 1) {
253cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis        size = 1;
254cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    }
255cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    snprintf(str, 32, "%d", size);
256cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
257cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
258cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
259fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
260fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock.
261fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable)
262fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
263fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
264fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
265fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
266fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel.
2674b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic bool startTrace(bool isRoot)
268fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
269fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
270fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2714b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // Set up the tracing options that don't require root.
272fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
273fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
27499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    ok &= setFrequencyTracingEnable(g_traceFrequency);
2753169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
276e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
277cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
278fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setGlobalClockEnable(true);
279fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2804b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // Set up the tracing options that do require root.  The options that
2814b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // require root should have errored out earlier if we're not running as
2824b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // root.
2834b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    if (isRoot) {
284e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setBusUtilizationTracingEnable(g_traceBusUtilization);
2859ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling        ok &= setSyncTracingEnabled(g_traceSync);
2864b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
2874b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        ok &= setDiskTracingEnabled(g_traceDisk);
2884b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
2894b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
290fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Enable tracing.
291fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTracingEnabled(true);
292fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
293fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (!ok) {
294fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error: unable to start trace\n");
295fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
296fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
297fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
298fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
299fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
300fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel.
3014b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic void stopTrace(bool isRoot)
302fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
303fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Disable tracing.
304fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTracingEnabled(false);
305fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
306fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set the options back to their defaults.
307fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTraceOverwriteEnable(true);
308fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setSchedSwitchTracingEnable(false);
30999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    setFrequencyTracingEnable(false);
310e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    setGovernorLoadTracingEnable(false);
311fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setGlobalClockEnable(false);
312cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
3134b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    if (isRoot) {
314e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        setBusUtilizationTracingEnable(false);
3159ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling        setSyncTracingEnabled(false);
3164b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        setWorkqueueTracingEnabled(false);
3174b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        setDiskTracingEnabled(false);
3184b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
3194b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
320cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
321cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // clear the trace before we've read it.
322fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
323fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
324fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout.
325fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace()
326fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
327fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
328fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
329fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
330fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
331fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return;
332fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
333fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
3347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    if (g_compress) {
3357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        z_stream zs;
3367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        uint8_t *in, *out;
3377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        int result, flush;
3387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        bzero(&zs, sizeof(zs));
3407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
3417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
3427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
3437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            close(traceFD);
3447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            return;
3457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        const size_t bufSize = 64*1024;
3487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        in = (uint8_t*)malloc(bufSize);
3497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        out = (uint8_t*)malloc(bufSize);
3507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        flush = Z_NO_FLUSH;
3517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.next_out = out;
3537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.avail_out = bufSize;
3547b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3557b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        do {
3567b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3577b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_in == 0) {
3587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // More input is needed.
3597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = read(traceFD, in, bufSize);
3607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if (result < 0) {
3617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
3627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
3637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END;
3647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
3657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else if (result == 0) {
3667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    flush = Z_FINISH;
3677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else {
3687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.next_in = in;
3697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_in = result;
3707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
3717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_out == 0) {
3747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // Need to write the output.
3757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
3767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if ((size_t)result < bufSize) {
3777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
3787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
3797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END; // skip deflate error message
3807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_out = bufSize; // skip the final write
3817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
3827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
3837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.next_out = out;
3847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.avail_out = bufSize;
3857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
3887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_STREAM_END) {
3907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
3917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (zs.avail_out < bufSize) {
3947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            size_t bytes = bufSize - zs.avail_out;
3957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            result = write(STDOUT_FILENO, out, bytes);
3967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if ((size_t)result < bytes) {
3977b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
3987b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                        strerror(errno), errno);
3997b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
4007b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
4017b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4027b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateEnd(&zs);
4037b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
4047b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
4057b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
4067b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4077b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(in);
4087b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(out);
4097b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    } else {
4107b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        ssize_t sent = 0;
4117b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
4127b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (sent == -1) {
4137b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
4147b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    errno);
4157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
416fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
417fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
418fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
419fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
420fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
421fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr.
422fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd)
423fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
424fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
425fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "options include:\n"
426cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
427fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -c              trace into a circular buffer\n"
428ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown                    "  -d              trace disk I/O\n"
42999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    "  -f              trace clock frequency changes\n"
430cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -l              trace CPU frequency governor load\n"
431fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -s              trace the kernel scheduler switches\n"
432fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
43399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    "  -u              trace bus utilization\n"
4347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    "  -w              trace the kernel workqueue\n"
4359ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                    "  -y              trace sync timelines and waits\n"
4364edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    "  -z              compress the trace dump\n"
4374edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    "  --async_start   start circular trace and return immediatly\n",
4384edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    "  --async_dump    dump the current contents of circular trace buffer\n",
4394edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    "  --async_stop    stop tracing and dump the current contents of circular\n",
4404edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    "                    trace buffer\n",
4414edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            );
442fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
443fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
444fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) {
44531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (!g_nohup) {
44631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        g_traceAborted = true;
44731be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
448fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
449fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
450fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() {
451fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    struct sigaction sa;
452fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigemptyset(&sa.sa_mask);
453fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_flags = 0;
454fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_handler = handleSignal;
455fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGHUP, &sa, NULL);
456fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGINT, &sa, NULL);
457fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGQUIT, &sa, NULL);
458fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGTERM, &sa, NULL);
459fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
460fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
461fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv)
462fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
4634b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool isRoot = (getuid() == 0);
4644edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool async = false;
4654edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceStart = true;
4664edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceStop = true;
4674edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceDump = true;
4684b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
469fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
470fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        showHelp(argv[0]);
471fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        exit(0);
472fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
473fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
474fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    for (;;) {
475fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        int ret;
4764edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        int option_index = 0;
4774edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        static struct option long_options[] = {
4784edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_start",     no_argument, 0,  0 },
4794edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_stop",      no_argument, 0,  0 },
4804edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_dump",      no_argument, 0,  0 },
4814edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {0,         0,                 0,  0 }
4824edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        };
483fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4844edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        ret = getopt_long(argc, argv, "b:cidflst:uwyznS:",
4854edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                          long_options, &option_index);
486fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
487fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ret < 0) {
488fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
489fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
490fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
491fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        switch(ret) {
492cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'b':
493cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
494cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
495cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
496fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'c':
497fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceOverwrite = true;
498fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
499fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5003169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis            case 'i':
5013169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis                g_traceCpuIdle = true;
5023169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis            break;
5033169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
504cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'l':
505cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceGovernorLoad = true;
506cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
507cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
508ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown            case 'd':
5094b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                if (!isRoot) {
5104b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    fprintf(stderr, "error: tracing disk activity requires root privileges\n");
5114b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    exit(1);
5124b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                }
513ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown                g_traceDisk = true;
514ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown            break;
515ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
516cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'f':
51799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                g_traceFrequency = true;
518cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
519cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
52031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            case 'n':
52131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_nohup = true;
52231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                break;
52331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
524fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 's':
525fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceSchedSwitch = true;
526fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
527fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
52831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            case 'S':
52931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_initialSleepSecs = atoi(optarg);
53031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            break;
53131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
532fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 't':
533fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceDurationSeconds = atoi(optarg);
534fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
535fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
53699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling            case 'u':
53799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                if (!isRoot) {
53899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    fprintf(stderr, "error: tracing bus utilization requires root privileges\n");
53999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    exit(1);
54099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                }
54199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                g_traceBusUtilization = true;
54299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling            break;
54399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
544fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'w':
5454b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                if (!isRoot) {
5464b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
5474b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    exit(1);
5484b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                }
549fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceWorkqueue = true;
550fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
551fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5529ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling            case 'y':
5539ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                if (!isRoot) {
5549ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                    fprintf(stderr, "error: tracing sync requires root privileges\n");
5559ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                    exit(1);
5569ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                }
5579ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                g_traceSync = true;
5589ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling            break;
5599ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling
5607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            case 'z':
5617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                g_compress = true;
5627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            break;
5637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
5644edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            case 0:
5654edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                if (!strcmp(long_options[option_index].name, "async_start")) {
5664edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
5674edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
5684edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceDump = false;
5694edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    g_traceOverwrite = true;
5704edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                } else if (!strcmp(long_options[option_index].name, "async_stop")) {
5714edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
5724edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
5734edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                } else if (!strcmp(long_options[option_index].name, "async_dump")) {
5744edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
5754edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStart = false;
5764edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
5774edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                }
5784edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                break;
5794edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling
580fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            default:
581cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                fprintf(stderr, "\n");
582fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                showHelp(argv[0]);
583fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                exit(-1);
584fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
585fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
586fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
587fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
588fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    registerSigHandler();
589fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
59031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (g_initialSleepSecs > 0) {
59131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        sleep(g_initialSleepSecs);
59231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
59331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
5944b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool ok = startTrace(isRoot);
595fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5964edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (ok && traceStart) {
597fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        printf("capturing trace...");
598fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fflush(stdout);
599fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
600fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // We clear the trace after starting it because tracing gets enabled for
601fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
602fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
603fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
604fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // another.
605fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = clearTrace();
606fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
6074edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        if (ok && !async) {
608fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            // Sleep to allow the trace to be captured.
609fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            struct timespec timeLeft;
610fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
611fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_nsec = 0;
612fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            do {
613fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                if (g_traceAborted) {
614fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    break;
615fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                }
616fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
617fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
618fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
619fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
620fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Stop the trace and restore the default settings.
6214edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (traceStop)
6224edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        stopTrace(isRoot);
623fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
6244edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (ok && traceDump) {
625fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (!g_traceAborted) {
626fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf(" done\nTRACE:\n");
627fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
628fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            dumpTrace();
629fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        } else {
630fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf("\ntrace aborted.\n");
631fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
632fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
633fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        clearTrace();
6344edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    } else if (!ok) {
635fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "unable to start tracing\n");
636fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
637fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
638cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Reset the trace buffer size to 1.
6394edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (traceStop)
6404edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        setTraceBufferSizeKB(1);
641cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
642fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return g_traceAborted ? 1 : 0;
643fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
644