atrace.cpp revision 9ba4baf178bb9dad3912403bfd9aee07c14da33a
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;
389ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic bool g_traceSync = false;
39fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceWorkqueue = false;
40fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false;
41cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false;
4331be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic bool g_nohup = false;
4431be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic int g_initialSleepSecs = 0;
45fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */
47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false;
48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
49fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */
50fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath =
51fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
52fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
53cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath =
54cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
55cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
56fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath =
57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
58fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
59fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath =
60fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
61fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
624b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic const char* k_schedWakeupEnablePath =
634b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
644b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
6599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char* k_memoryBusEnablePath =
6699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    "/sys/kernel/debug/tracing/events/memory_bus/enable";
6799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
68cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_cpuFreqEnablePath =
69cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
70cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
7199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char *k_clockSetRateEnablePath =
7299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable";
7399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
743169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic const char* k_cpuIdleEnablePath =
753169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
763169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
77cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_governorLoadEnablePath =
78cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
79cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
809ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic const char* k_syncEnablePath =
819ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    "/sys/kernel/debug/tracing/events/sync/enable";
829ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling
83fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath =
84fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
85fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
86ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic const char* k_diskEnablePaths[] = {
87ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
88ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
89ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
90ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
91ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown};
92ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
93fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath =
94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
96fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath =
97fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace";
98fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
99fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath =
100fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
101fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
102e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists.
103e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) {
104e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return access(filename, F_OK) != -1;
105e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis}
106e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis
107fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful.
108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str)
109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int fd = open(filename, O_WRONLY);
111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (fd == -1) {
112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
115fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
116fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
117fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
118fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ssize_t len = strlen(str);
119fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (write(fd, str, len) != len) {
120fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
121fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = false;
123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
124fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(fd);
126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
130fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
131fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
132fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
133fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(filename, enable ? "1" : "0");
134fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
135fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
136ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
137ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
138ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
139ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    bool result = true;
140ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    for (size_t i = 0; i < count; i++) {
141ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        result &= setKernelOptionEnable(filenames[i], enable);
142ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    }
143ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    return result;
144ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
145ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
146fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
147fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up.
148fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
150fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
151fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
152fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
153fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching.
154fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
155fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
1564b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool ok = true;
1574b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
1584b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
1594b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    return ok;
160fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
161fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
16299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling// Enable or disable tracing of the Bus utilization.
16399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setBusUtilizationTracingEnable(bool enable)
16499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling{
165e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    bool ok = true, oneSet = false;
16699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    // these can be platform specific so make sure that at least
16799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    // one succeeds.
168e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_memoryBusEnablePath)) {
169e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable);
170e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        oneSet |= ok;
171e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
172e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok && (oneSet || !enable);
17399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling}
17499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
175cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the CPU clock frequency.
17699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setFrequencyTracingEnable(bool enable)
177cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
17899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    bool ok = true;
17999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable);
180e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_clockSetRateEnablePath)) {
181e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable);
182e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
18399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    return ok;
184cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
185cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
1863169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis// Enable or disable tracing of CPU idle events.
1873169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool setCpuIdleTracingEnable(bool enable)
1883169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{
1893169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
1903169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis}
1913169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
192cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of
193cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// the CPU load.
194cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable)
195cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
196e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    bool ok = true;
197e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_governorLoadEnablePath) || enable) {
198e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable);
199e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
200e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok;
201cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
202cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
2039ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling// Enable or disable tracing of sync timelines and waits.
2049ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic bool setSyncTracingEnabled(bool enable)
2059ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling{
2069ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    bool ok = true;
2079ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    if (fileExists(k_syncEnablePath) || enable) {
2089ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling        ok &= setKernelOptionEnable(k_syncEnablePath, enable);
2099ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    }
2109ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    return ok;
2119ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling}
2129ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling
213fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues.
214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
219ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable tracing of disk I/O.
220ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setDiskTracingEnabled(bool enable)
221ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
222ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
223ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
224ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
225fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing.
226fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable)
227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
228fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
229fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace.
232fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace()
233fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
234fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = creat(k_tracePath, 0);
235fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
236fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
237fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
238fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
239fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
240fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
241fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return true;
244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
246cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
247cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
248cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
249cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    char str[32] = "1";
250cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    int len;
251cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    if (size < 1) {
252cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis        size = 1;
253cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    }
254cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    snprintf(str, 32, "%d", size);
255cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
256cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
257cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
258fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
259fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock.
260fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable)
261fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
262fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
263fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
264fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
265fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel.
2664b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic bool startTrace(bool isRoot)
267fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
268fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
269fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2704b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // Set up the tracing options that don't require root.
271fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
272fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
27399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    ok &= setFrequencyTracingEnable(g_traceFrequency);
2743169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
275e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
276cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
277fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setGlobalClockEnable(true);
278fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2794b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // Set up the tracing options that do require root.  The options that
2804b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // require root should have errored out earlier if we're not running as
2814b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // root.
2824b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    if (isRoot) {
283e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setBusUtilizationTracingEnable(g_traceBusUtilization);
2849ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling        ok &= setSyncTracingEnabled(g_traceSync);
2854b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
2864b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        ok &= setDiskTracingEnabled(g_traceDisk);
2874b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
2884b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
289fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Enable tracing.
290fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTracingEnabled(true);
291fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
292fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (!ok) {
293fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error: unable to start trace\n");
294fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
295fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
296fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
297fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
298fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
299fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel.
3004b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic void stopTrace(bool isRoot)
301fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
302fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Disable tracing.
303fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTracingEnabled(false);
304fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
305fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set the options back to their defaults.
306fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTraceOverwriteEnable(true);
307fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setSchedSwitchTracingEnable(false);
30899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    setFrequencyTracingEnable(false);
309e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    setGovernorLoadTracingEnable(false);
310fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setGlobalClockEnable(false);
311cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
3124b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    if (isRoot) {
313e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        setBusUtilizationTracingEnable(false);
3149ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling        setSyncTracingEnabled(false);
3154b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        setWorkqueueTracingEnabled(false);
3164b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        setDiskTracingEnabled(false);
3174b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
3184b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
319cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
320cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // clear the trace before we've read it.
321fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
322fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
323fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout.
324fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace()
325fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
326fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
327fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
328fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
329fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
330fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return;
331fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
332fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
3337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    if (g_compress) {
3347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        z_stream zs;
3357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        uint8_t *in, *out;
3367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        int result, flush;
3377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        bzero(&zs, sizeof(zs));
3397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
3407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
3417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
3427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            close(traceFD);
3437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            return;
3447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        const size_t bufSize = 64*1024;
3477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        in = (uint8_t*)malloc(bufSize);
3487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        out = (uint8_t*)malloc(bufSize);
3497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        flush = Z_NO_FLUSH;
3507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.next_out = out;
3527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.avail_out = bufSize;
3537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3547b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        do {
3557b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3567b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_in == 0) {
3577b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // More input is needed.
3587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = read(traceFD, in, bufSize);
3597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if (result < 0) {
3607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
3617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
3627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END;
3637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
3647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else if (result == 0) {
3657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    flush = Z_FINISH;
3667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else {
3677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.next_in = in;
3687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_in = result;
3697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
3707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_out == 0) {
3737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // Need to write the output.
3747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
3757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if ((size_t)result < bufSize) {
3767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
3777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
3787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END; // skip deflate error message
3797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_out = bufSize; // skip the final write
3807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
3817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
3827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.next_out = out;
3837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.avail_out = bufSize;
3847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
3877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_STREAM_END) {
3897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
3907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (zs.avail_out < bufSize) {
3937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            size_t bytes = bufSize - zs.avail_out;
3947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            result = write(STDOUT_FILENO, out, bytes);
3957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if ((size_t)result < bytes) {
3967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
3977b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                        strerror(errno), errno);
3987b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3997b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
4007b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4017b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateEnd(&zs);
4027b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
4037b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
4047b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
4057b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4067b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(in);
4077b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(out);
4087b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    } else {
4097b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        ssize_t sent = 0;
4107b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
4117b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (sent == -1) {
4127b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
4137b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    errno);
4147b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
415fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
416fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
417fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
418fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
419fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
420fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr.
421fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd)
422fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
423fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
424fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "options include:\n"
425cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
426fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -c              trace into a circular buffer\n"
427ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown                    "  -d              trace disk I/O\n"
42899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    "  -f              trace clock frequency changes\n"
429cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -l              trace CPU frequency governor load\n"
430fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -s              trace the kernel scheduler switches\n"
431fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
43299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    "  -u              trace bus utilization\n"
4337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    "  -w              trace the kernel workqueue\n"
4349ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                    "  -y              trace sync timelines and waits\n"
4357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    "  -z              compress the trace dump\n");
436fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
437fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
438fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) {
43931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (!g_nohup) {
44031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        g_traceAborted = true;
44131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
442fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
443fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
444fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() {
445fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    struct sigaction sa;
446fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigemptyset(&sa.sa_mask);
447fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_flags = 0;
448fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_handler = handleSignal;
449fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGHUP, &sa, NULL);
450fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGINT, &sa, NULL);
451fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGQUIT, &sa, NULL);
452fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGTERM, &sa, NULL);
453fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
454fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
455fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv)
456fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
4574b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool isRoot = (getuid() == 0);
4584b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
459fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
460fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        showHelp(argv[0]);
461fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        exit(0);
462fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
463fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
464fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    for (;;) {
465fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        int ret;
466fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4679ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling        ret = getopt(argc, argv, "b:cidflst:uwyznS:");
468fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
469fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ret < 0) {
470fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
471fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
472fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
473fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        switch(ret) {
474cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'b':
475cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
476cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
477cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
478fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'c':
479fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceOverwrite = true;
480fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
481fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4823169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis            case 'i':
4833169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis                g_traceCpuIdle = true;
4843169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis            break;
4853169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
486cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'l':
487cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceGovernorLoad = true;
488cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
489cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
490ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown            case 'd':
4914b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                if (!isRoot) {
4924b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    fprintf(stderr, "error: tracing disk activity requires root privileges\n");
4934b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    exit(1);
4944b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                }
495ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown                g_traceDisk = true;
496ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown            break;
497ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
498cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'f':
49999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                g_traceFrequency = true;
500cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
501cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
50231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            case 'n':
50331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_nohup = true;
50431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                break;
50531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
506fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 's':
507fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceSchedSwitch = true;
508fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
509fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
51031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            case 'S':
51131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_initialSleepSecs = atoi(optarg);
51231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            break;
51331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
514fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 't':
515fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceDurationSeconds = atoi(optarg);
516fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
517fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
51899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling            case 'u':
51999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                if (!isRoot) {
52099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    fprintf(stderr, "error: tracing bus utilization requires root privileges\n");
52199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    exit(1);
52299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                }
52399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                g_traceBusUtilization = true;
52499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling            break;
52599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
526fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'w':
5274b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                if (!isRoot) {
5284b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
5294b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    exit(1);
5304b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                }
531fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceWorkqueue = true;
532fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
533fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5349ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling            case 'y':
5359ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                if (!isRoot) {
5369ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                    fprintf(stderr, "error: tracing sync requires root privileges\n");
5379ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                    exit(1);
5389ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                }
5399ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling                g_traceSync = true;
5409ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling            break;
5419ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling
5427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            case 'z':
5437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                g_compress = true;
5447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            break;
5457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
546fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            default:
547cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                fprintf(stderr, "\n");
548fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                showHelp(argv[0]);
549fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                exit(-1);
550fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
551fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
552fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
553fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
554fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    registerSigHandler();
555fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
55631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (g_initialSleepSecs > 0) {
55731be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        sleep(g_initialSleepSecs);
55831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
55931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
5604b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool ok = startTrace(isRoot);
561fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
562fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (ok) {
563fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        printf("capturing trace...");
564fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fflush(stdout);
565fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
566fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // We clear the trace after starting it because tracing gets enabled for
567fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
568fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
569fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
570fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // another.
571fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = clearTrace();
572fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
573fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ok) {
574fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            // Sleep to allow the trace to be captured.
575fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            struct timespec timeLeft;
576fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
577fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_nsec = 0;
578fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            do {
579fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                if (g_traceAborted) {
580fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    break;
581fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                }
582fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
583fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
584fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
585fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
586fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Stop the trace and restore the default settings.
5874b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    stopTrace(isRoot);
588fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
589fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (ok) {
590fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (!g_traceAborted) {
591fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf(" done\nTRACE:\n");
592fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
593fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            dumpTrace();
594fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        } else {
595fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf("\ntrace aborted.\n");
596fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
597fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
598fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        clearTrace();
599fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    } else {
600fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "unable to start tracing\n");
601fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
602fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
603cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Reset the trace buffer size to 1.
604cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    setTraceBufferSizeKB(1);
605cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
606fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return g_traceAborted ? 1 : 0;
607fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
608