atrace.cpp revision e8744fd4dce2881c83d69c084b6937d0397ace05
1fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/*
2fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Copyright (C) 2012 The Android Open Source Project
3fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
4fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Licensed under the Apache License, Version 2.0 (the "License");
5fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * you may not use this file except in compliance with the License.
6fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * You may obtain a copy of the License at
7fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
8fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *      http://www.apache.org/licenses/LICENSE-2.0
9fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
10fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Unless required by applicable law or agreed to in writing, software
11fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * distributed under the License is distributed on an "AS IS" BASIS,
12fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * See the License for the specific language governing permissions and
14fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * limitations under the License.
15fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis */
16fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
17fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <errno.h>
18fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <fcntl.h>
19fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <signal.h>
20fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdarg.h>
21fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdbool.h>
22fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdio.h>
23fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdlib.h>
24fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <sys/sendfile.h>
25fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <time.h>
267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis#include <zlib.h>
27fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
28ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
29ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
30fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Command line options */
31fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic int g_traceDurationSeconds = 5;
32fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceSchedSwitch = false;
3399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool g_traceFrequency = false;
3499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool g_traceBusUtilization = false;
353169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool g_traceCpuIdle = false;
36ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool g_traceDisk = false;
37cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool g_traceGovernorLoad = false;
38fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceWorkqueue = false;
39fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false;
40cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false;
42fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
43fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */
44fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false;
45fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */
47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath =
48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
49fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
50cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath =
51cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
52cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
53fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath =
54fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
55fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
56fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath =
57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
58fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
594b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic const char* k_schedWakeupEnablePath =
604b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
614b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
6299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char* k_memoryBusEnablePath =
6399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    "/sys/kernel/debug/tracing/events/memory_bus/enable";
6499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
65cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_cpuFreqEnablePath =
66cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
67cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
6899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char *k_clockSetRateEnablePath =
6999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable";
7099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
713169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic const char* k_cpuIdleEnablePath =
723169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
733169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
74cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_governorLoadEnablePath =
75cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
76cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
77fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath =
78fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
79fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
80ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic const char* k_diskEnablePaths[] = {
81ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
82ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
83ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
84ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
85ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown};
86ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
87fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath =
88fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
89fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
90fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath =
91fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace";
92fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
93fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath =
94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
96e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists.
97e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) {
98e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return access(filename, F_OK) != -1;
99e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis}
100e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis
101fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful.
102fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str)
103fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
104fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int fd = open(filename, O_WRONLY);
105fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (fd == -1) {
106fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
107fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ssize_t len = strlen(str);
113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (write(fd, str, len) != len) {
114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
115fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
116fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = false;
117fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
118fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
119fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(fd);
120fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
121fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
124fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(filename, enable ? "1" : "0");
128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
130ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
131ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
132ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
133ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    bool result = true;
134ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    for (size_t i = 0; i < count; i++) {
135ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown        result &= setKernelOptionEnable(filenames[i], enable);
136ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    }
137ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    return result;
138ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
139ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
140fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
141fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up.
142fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
143fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
144fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
145fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
146fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
147fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching.
148fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
1504b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool ok = true;
1514b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
1524b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
1534b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    return ok;
154fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
155fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
15699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling// Enable or disable tracing of the Bus utilization.
15799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setBusUtilizationTracingEnable(bool enable)
15899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling{
159e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    bool ok = true, oneSet = false;
16099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    // these can be platform specific so make sure that at least
16199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    // one succeeds.
162e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_memoryBusEnablePath)) {
163e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable);
164e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        oneSet |= ok;
165e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
166e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok && (oneSet || !enable);
16799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling}
16899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
169cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the CPU clock frequency.
17099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setFrequencyTracingEnable(bool enable)
171cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
17299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    bool ok = true;
17399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable);
174e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_clockSetRateEnablePath)) {
175e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable);
176e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
17799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    return ok;
178cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
179cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
1803169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis// Enable or disable tracing of CPU idle events.
1813169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool setCpuIdleTracingEnable(bool enable)
1823169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{
1833169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
1843169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis}
1853169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
186cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of
187cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// the CPU load.
188cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable)
189cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
190e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    bool ok = true;
191e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    if (fileExists(k_governorLoadEnablePath) || enable) {
192e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable);
193e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
194e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok;
195cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
196cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
197fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues.
198fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
199fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
200fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
201fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
202fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
203ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable tracing of disk I/O.
204ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setDiskTracingEnabled(bool enable)
205ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
206ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown    return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
207ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
208ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
209fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing.
210fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable)
211fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
212fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
213fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace.
216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace()
217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = creat(k_tracePath, 0);
219fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
220fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
221fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
222fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
223fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
224fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
225fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
226fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return true;
228fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
229fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
230cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
231cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
232cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
233cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    char str[32] = "1";
234cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    int len;
235cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    if (size < 1) {
236cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis        size = 1;
237cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    }
238cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    snprintf(str, 32, "%d", size);
239cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
240cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
241cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock.
244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable)
245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
246fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
247fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
248fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
249fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel.
2504b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic bool startTrace(bool isRoot)
251fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
252fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
253fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2544b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // Set up the tracing options that don't require root.
255fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
256fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
25799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    ok &= setFrequencyTracingEnable(g_traceFrequency);
2583169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis    ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
259e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
260cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
261fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setGlobalClockEnable(true);
262fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2634b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // Set up the tracing options that do require root.  The options that
2644b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // require root should have errored out earlier if we're not running as
2654b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    // root.
2664b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    if (isRoot) {
267e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        ok &= setBusUtilizationTracingEnable(g_traceBusUtilization);
2684b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
2694b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        ok &= setDiskTracingEnabled(g_traceDisk);
2704b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
2714b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
272fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Enable tracing.
273fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTracingEnabled(true);
274fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
275fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (!ok) {
276fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error: unable to start trace\n");
277fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
278fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
279fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
280fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
281fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
282fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel.
2834b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic void stopTrace(bool isRoot)
284fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
285fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Disable tracing.
286fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTracingEnabled(false);
287fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
288fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set the options back to their defaults.
289fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTraceOverwriteEnable(true);
290fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setSchedSwitchTracingEnable(false);
29199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling    setFrequencyTracingEnable(false);
292e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    setGovernorLoadTracingEnable(false);
293fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setGlobalClockEnable(false);
294cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
2954b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    if (isRoot) {
296e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis        setBusUtilizationTracingEnable(false);
2974b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        setWorkqueueTracingEnabled(false);
2984b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis        setDiskTracingEnabled(false);
2994b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
3004b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
301cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
302cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // clear the trace before we've read it.
303fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
304fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
305fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout.
306fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace()
307fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
308fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
309fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
310fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
311fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
312fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return;
313fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
314fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
3157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    if (g_compress) {
3167b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        z_stream zs;
3177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        uint8_t *in, *out;
3187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        int result, flush;
3197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        bzero(&zs, sizeof(zs));
3217b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
3227b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
3237b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
3247b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            close(traceFD);
3257b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            return;
3267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3287b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        const size_t bufSize = 64*1024;
3297b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        in = (uint8_t*)malloc(bufSize);
3307b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        out = (uint8_t*)malloc(bufSize);
3317b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        flush = Z_NO_FLUSH;
3327b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.next_out = out;
3347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.avail_out = bufSize;
3357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        do {
3377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_in == 0) {
3397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // More input is needed.
3407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = read(traceFD, in, bufSize);
3417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if (result < 0) {
3427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
3437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
3447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END;
3457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
3467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else if (result == 0) {
3477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    flush = Z_FINISH;
3487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else {
3497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.next_in = in;
3507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_in = result;
3517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
3527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3547b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_out == 0) {
3557b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // Need to write the output.
3567b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
3577b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if ((size_t)result < bufSize) {
3587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
3597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
3607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END; // skip deflate error message
3617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_out = bufSize; // skip the final write
3627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
3637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
3647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.next_out = out;
3657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.avail_out = bufSize;
3667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
3697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_STREAM_END) {
3717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
3727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (zs.avail_out < bufSize) {
3757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            size_t bytes = bufSize - zs.avail_out;
3767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            result = write(STDOUT_FILENO, out, bytes);
3777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if ((size_t)result < bytes) {
3787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
3797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                        strerror(errno), errno);
3807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
3817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateEnd(&zs);
3847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
3857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
3867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
3877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
3887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(in);
3897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(out);
3907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    } else {
3917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        ssize_t sent = 0;
3927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
3937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (sent == -1) {
3947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
3957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    errno);
3967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
397fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
398fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
399fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
400fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
401fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
402fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr.
403fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd)
404fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
405fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
406fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    fprintf(stderr, "options include:\n"
407cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
408fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -c              trace into a circular buffer\n"
409ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown                    "  -d              trace disk I/O\n"
41099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    "  -f              trace clock frequency changes\n"
411cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                    "  -l              trace CPU frequency governor load\n"
412fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -s              trace the kernel scheduler switches\n"
413fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
41499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    "  -u              trace bus utilization\n"
4157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    "  -w              trace the kernel workqueue\n"
4167b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    "  -z              compress the trace dump\n");
417fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
418fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
419fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) {
420fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    g_traceAborted = true;
421fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
422fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
423fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() {
424fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    struct sigaction sa;
425fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigemptyset(&sa.sa_mask);
426fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_flags = 0;
427fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_handler = handleSignal;
428fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGHUP, &sa, NULL);
429fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGINT, &sa, NULL);
430fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGQUIT, &sa, NULL);
431fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGTERM, &sa, NULL);
432fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
433fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
434fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv)
435fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
4364b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool isRoot = (getuid() == 0);
4374b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
438fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
439fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        showHelp(argv[0]);
440fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        exit(0);
441fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
442fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
443fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    for (;;) {
444fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        int ret;
445fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
44699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling        ret = getopt(argc, argv, "b:cidflst:uwz");
447fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
448fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ret < 0) {
449fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
450fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
451fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
452fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        switch(ret) {
453cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'b':
454cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
455cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
456cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
457fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'c':
458fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceOverwrite = true;
459fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
460fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4613169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis            case 'i':
4623169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis                g_traceCpuIdle = true;
4633169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis            break;
4643169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis
465cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'l':
466cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceGovernorLoad = true;
467cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
468cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
469ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown            case 'd':
4704b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                if (!isRoot) {
4714b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    fprintf(stderr, "error: tracing disk activity requires root privileges\n");
4724b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    exit(1);
4734b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                }
474ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown                g_traceDisk = true;
475ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown            break;
476ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
477cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'f':
47899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                g_traceFrequency = true;
479cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
480cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
481fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 's':
482fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceSchedSwitch = true;
483fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
484fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
485fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 't':
486fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceDurationSeconds = atoi(optarg);
487fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
488fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
48999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling            case 'u':
49099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                if (!isRoot) {
49199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    fprintf(stderr, "error: tracing bus utilization requires root privileges\n");
49299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                    exit(1);
49399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                }
49499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling                g_traceBusUtilization = true;
49599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling            break;
49699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling
497fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'w':
4984b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                if (!isRoot) {
4994b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
5004b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                    exit(1);
5014b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis                }
502fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceWorkqueue = true;
503fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
504fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5057b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            case 'z':
5067b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                g_compress = true;
5077b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            break;
5087b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
509fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            default:
510cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                fprintf(stderr, "\n");
511fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                showHelp(argv[0]);
512fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                exit(-1);
513fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
514fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
515fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
516fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
517fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    registerSigHandler();
518fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5194b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    bool ok = startTrace(isRoot);
520fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
521fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (ok) {
522fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        printf("capturing trace...");
523fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fflush(stdout);
524fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
525fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // We clear the trace after starting it because tracing gets enabled for
526fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
527fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
528fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
529fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // another.
530fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = clearTrace();
531fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
532fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ok) {
533fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            // Sleep to allow the trace to be captured.
534fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            struct timespec timeLeft;
535fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
536fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_nsec = 0;
537fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            do {
538fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                if (g_traceAborted) {
539fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    break;
540fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                }
541fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
542fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
543fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
544fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
545fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Stop the trace and restore the default settings.
5464b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    stopTrace(isRoot);
547fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
548fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (ok) {
549fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (!g_traceAborted) {
550fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf(" done\nTRACE:\n");
551fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
552fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            dumpTrace();
553fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        } else {
554fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf("\ntrace aborted.\n");
555fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
556fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
557fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        clearTrace();
558fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    } else {
559fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "unable to start tracing\n");
560fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
561fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
562cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Reset the trace buffer size to 1.
563cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    setTraceBufferSizeKB(1);
564cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
565fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return g_traceAborted ? 1 : 0;
566fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
567