16b995818535af84c4a6829af7733684861f20144Jamie Gennis/*
26b995818535af84c4a6829af7733684861f20144Jamie Gennis * Copyright (C) 2012 The Android Open Source Project
36b995818535af84c4a6829af7733684861f20144Jamie Gennis *
46b995818535af84c4a6829af7733684861f20144Jamie Gennis * Licensed under the Apache License, Version 2.0 (the "License");
56b995818535af84c4a6829af7733684861f20144Jamie Gennis * you may not use this file except in compliance with the License.
66b995818535af84c4a6829af7733684861f20144Jamie Gennis * You may obtain a copy of the License at
76b995818535af84c4a6829af7733684861f20144Jamie Gennis *
86b995818535af84c4a6829af7733684861f20144Jamie Gennis *      http://www.apache.org/licenses/LICENSE-2.0
96b995818535af84c4a6829af7733684861f20144Jamie Gennis *
106b995818535af84c4a6829af7733684861f20144Jamie Gennis * Unless required by applicable law or agreed to in writing, software
116b995818535af84c4a6829af7733684861f20144Jamie Gennis * distributed under the License is distributed on an "AS IS" BASIS,
126b995818535af84c4a6829af7733684861f20144Jamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136b995818535af84c4a6829af7733684861f20144Jamie Gennis * See the License for the specific language governing permissions and
146b995818535af84c4a6829af7733684861f20144Jamie Gennis * limitations under the License.
156b995818535af84c4a6829af7733684861f20144Jamie Gennis */
166b995818535af84c4a6829af7733684861f20144Jamie Gennis
176b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <errno.h>
186b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <fcntl.h>
196b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <signal.h>
206b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdarg.h>
216b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdbool.h>
226b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdio.h>
236b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdlib.h>
246b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <sys/sendfile.h>
256b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <time.h>
26eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis#include <zlib.h>
276b995818535af84c4a6829af7733684861f20144Jamie Gennis
2883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
2983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
306b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Command line options */
316b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic int g_traceDurationSeconds = 5;
326b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceSchedSwitch = false;
33a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool g_traceFrequency = false;
34a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool g_traceBusUtilization = false;
35585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic bool g_traceCpuIdle = false;
3683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool g_traceDisk = false;
37bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool g_traceGovernorLoad = false;
383f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gillingstatic bool g_traceSync = false;
396b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceWorkqueue = false;
406b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceOverwrite = false;
41bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
42eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennisstatic bool g_compress = false;
43a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kastenstatic bool g_nohup = false;
44a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kastenstatic int g_initialSleepSecs = 0;
456b995818535af84c4a6829af7733684861f20144Jamie Gennis
466b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Global state */
476b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceAborted = false;
486b995818535af84c4a6829af7733684861f20144Jamie Gennis
496b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Sys file paths */
506b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceClockPath =
516b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
526b995818535af84c4a6829af7733684861f20144Jamie Gennis
53bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_traceBufferSizePath =
54bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
55bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
566b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOverwriteEnablePath =
576b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
586b995818535af84c4a6829af7733684861f20144Jamie Gennis
596b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_schedSwitchEnablePath =
606b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
616b995818535af84c4a6829af7733684861f20144Jamie Gennis
62b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic const char* k_schedWakeupEnablePath =
63b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
64b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
65a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic const char* k_memoryBusEnablePath =
66a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    "/sys/kernel/debug/tracing/events/memory_bus/enable";
67a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling
68bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_cpuFreqEnablePath =
69bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
70bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
71a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic const char *k_clockSetRateEnablePath =
72a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable";
73a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling
74585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic const char* k_cpuIdleEnablePath =
75585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
76585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
77bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_governorLoadEnablePath =
78bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
79bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
803f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gillingstatic const char* k_syncEnablePath =
813f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling    "/sys/kernel/debug/tracing/events/sync/enable";
823f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling
836b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_workqueueEnablePath =
846b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
856b995818535af84c4a6829af7733684861f20144Jamie Gennis
8683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic const char* k_diskEnablePaths[] = {
8783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
8883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
8983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
9083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
9183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown};
9283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
936b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOnPath =
946b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
956b995818535af84c4a6829af7733684861f20144Jamie Gennis
966b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracePath =
976b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace";
986b995818535af84c4a6829af7733684861f20144Jamie Gennis
996b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceMarkerPath =
1006b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
1016b995818535af84c4a6829af7733684861f20144Jamie Gennis
10224505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis// Check whether a file exists.
10324505a5826d7c5cf89f3da85058befd671a73444Jamie Gennisstatic bool fileExists(const char* filename) {
10424505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    return access(filename, F_OK) != -1;
10524505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis}
10624505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis
1076b995818535af84c4a6829af7733684861f20144Jamie Gennis// Write a string to a file, returning true if the write was successful.
1086b995818535af84c4a6829af7733684861f20144Jamie Gennisbool writeStr(const char* filename, const char* str)
1096b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1106b995818535af84c4a6829af7733684861f20144Jamie Gennis    int fd = open(filename, O_WRONLY);
1116b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (fd == -1) {
1126b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
1136b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1146b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
1156b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1166b995818535af84c4a6829af7733684861f20144Jamie Gennis
1176b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
1186b995818535af84c4a6829af7733684861f20144Jamie Gennis    ssize_t len = strlen(str);
1196b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (write(fd, str, len) != len) {
1206b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
1216b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1226b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = false;
1236b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1246b995818535af84c4a6829af7733684861f20144Jamie Gennis
1256b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(fd);
1266b995818535af84c4a6829af7733684861f20144Jamie Gennis
1276b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
1286b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1296b995818535af84c4a6829af7733684861f20144Jamie Gennis
1306b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
1316b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
1326b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1336b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(filename, enable ? "1" : "0");
1346b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1356b995818535af84c4a6829af7733684861f20144Jamie Gennis
13683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
13783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
13883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{
13983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    bool result = true;
14083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    for (size_t i = 0; i < count; i++) {
14183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        result &= setKernelOptionEnable(filenames[i], enable);
14283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    }
14383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    return result;
14483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown}
14583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
1466b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
1476b995818535af84c4a6829af7733684861f20144Jamie Gennis// will cause tracing to stop once the trace buffers have filled up.
1486b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
1496b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1506b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
1516b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1526b995818535af84c4a6829af7733684861f20144Jamie Gennis
1536b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel scheduler switching.
1546b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
1556b995818535af84c4a6829af7733684861f20144Jamie Gennis{
156b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    bool ok = true;
157b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
158b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
159b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    return ok;
1606b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1616b995818535af84c4a6829af7733684861f20144Jamie Gennis
162a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling// Enable or disable tracing of the Bus utilization.
163a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool setBusUtilizationTracingEnable(bool enable)
164a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling{
16524505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    bool ok = true, oneSet = false;
166a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    // these can be platform specific so make sure that at least
167a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    // one succeeds.
16824505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    if (fileExists(k_memoryBusEnablePath)) {
16924505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis        ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable);
17024505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis        oneSet |= ok;
17124505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    }
17224505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    return ok && (oneSet || !enable);
173a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling}
174a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling
175bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the CPU clock frequency.
176a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool setFrequencyTracingEnable(bool enable)
177bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
178a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    bool ok = true;
179a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable);
18024505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    if (fileExists(k_clockSetRateEnablePath)) {
18124505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis        ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable);
18224505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    }
183a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    return ok;
184bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
185bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
186585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis// Enable or disable tracing of CPU idle events.
187585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic bool setCpuIdleTracingEnable(bool enable)
188585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis{
189585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
190585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis}
191585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
192bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of
193bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// the CPU load.
194bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable)
195bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
19624505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    bool ok = true;
19724505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    if (fileExists(k_governorLoadEnablePath) || enable) {
19824505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis        ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable);
19924505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    }
20024505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    return ok;
201bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
202bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
2033f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling// Enable or disable tracing of sync timelines and waits.
2043f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gillingstatic bool setSyncTracingEnabled(bool enable)
2053f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling{
2063f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling    bool ok = true;
2073f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling    if (fileExists(k_syncEnablePath) || enable) {
2083f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling        ok &= setKernelOptionEnable(k_syncEnablePath, enable);
2093f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling    }
2103f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling    return ok;
2113f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling}
2123f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling
2136b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel workqueues.
2146b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
2156b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2166b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
2176b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2186b995818535af84c4a6829af7733684861f20144Jamie Gennis
21983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable tracing of disk I/O.
22083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setDiskTracingEnabled(bool enable)
22183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{
22283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
22383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown}
22483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
2256b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable kernel tracing.
2266b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTracingEnabled(bool enable)
2276b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2286b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
2296b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2306b995818535af84c4a6829af7733684861f20144Jamie Gennis
2316b995818535af84c4a6829af7733684861f20144Jamie Gennis// Clear the contents of the kernel trace.
2326b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool clearTrace()
2336b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2346b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = creat(k_tracePath, 0);
2356b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
2366b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
2376b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
2386b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
2396b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2406b995818535af84c4a6829af7733684861f20144Jamie Gennis
2416b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
2426b995818535af84c4a6829af7733684861f20144Jamie Gennis
2436b995818535af84c4a6829af7733684861f20144Jamie Gennis    return true;
2446b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2456b995818535af84c4a6829af7733684861f20144Jamie Gennis
246bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
247bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
248bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
249bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    char str[32] = "1";
250bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    int len;
251bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    if (size < 1) {
252bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis        size = 1;
253bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    }
254bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    snprintf(str, 32, "%d", size);
255bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
256bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
257bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
2586b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
2596b995818535af84c4a6829af7733684861f20144Jamie Gennis// clock will result in the kernel using a per-CPU local clock.
2606b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setGlobalClockEnable(bool enable)
2616b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2626b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
2636b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2646b995818535af84c4a6829af7733684861f20144Jamie Gennis
2656b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable tracing in the kernel.
266b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic bool startTrace(bool isRoot)
2676b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2686b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
2696b995818535af84c4a6829af7733684861f20144Jamie Gennis
270b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // Set up the tracing options that don't require root.
2716b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
2726b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
273a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    ok &= setFrequencyTracingEnable(g_traceFrequency);
274585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
27524505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
276bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
2776b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setGlobalClockEnable(true);
2786b995818535af84c4a6829af7733684861f20144Jamie Gennis
279b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // Set up the tracing options that do require root.  The options that
280b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // require root should have errored out earlier if we're not running as
281b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // root.
282b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    if (isRoot) {
28324505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis        ok &= setBusUtilizationTracingEnable(g_traceBusUtilization);
2843f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling        ok &= setSyncTracingEnabled(g_traceSync);
285b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
286b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        ok &= setDiskTracingEnabled(g_traceDisk);
287b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    }
288b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
2896b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Enable tracing.
2906b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTracingEnabled(true);
2916b995818535af84c4a6829af7733684861f20144Jamie Gennis
2926b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (!ok) {
2936b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error: unable to start trace\n");
2946b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2956b995818535af84c4a6829af7733684861f20144Jamie Gennis
2966b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
2976b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2986b995818535af84c4a6829af7733684861f20144Jamie Gennis
2996b995818535af84c4a6829af7733684861f20144Jamie Gennis// Disable tracing in the kernel.
300b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic void stopTrace(bool isRoot)
3016b995818535af84c4a6829af7733684861f20144Jamie Gennis{
3026b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Disable tracing.
3036b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTracingEnabled(false);
3046b995818535af84c4a6829af7733684861f20144Jamie Gennis
3056b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Set the options back to their defaults.
3066b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTraceOverwriteEnable(true);
3076b995818535af84c4a6829af7733684861f20144Jamie Gennis    setSchedSwitchTracingEnable(false);
308a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    setFrequencyTracingEnable(false);
30924505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis    setGovernorLoadTracingEnable(false);
3106b995818535af84c4a6829af7733684861f20144Jamie Gennis    setGlobalClockEnable(false);
311bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
312b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    if (isRoot) {
31324505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis        setBusUtilizationTracingEnable(false);
3143f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling        setSyncTracingEnabled(false);
315b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        setWorkqueueTracingEnabled(false);
316b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        setDiskTracingEnabled(false);
317b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    }
318b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
319bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
320bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // clear the trace before we've read it.
3216b995818535af84c4a6829af7733684861f20144Jamie Gennis}
3226b995818535af84c4a6829af7733684861f20144Jamie Gennis
3236b995818535af84c4a6829af7733684861f20144Jamie Gennis// Read the current kernel trace and write it to stdout.
3246b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void dumpTrace()
3256b995818535af84c4a6829af7733684861f20144Jamie Gennis{
3266b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
3276b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
3286b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
3296b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
3306b995818535af84c4a6829af7733684861f20144Jamie Gennis        return;
3316b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
3326b995818535af84c4a6829af7733684861f20144Jamie Gennis
333eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis    if (g_compress) {
334eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        z_stream zs;
335eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        uint8_t *in, *out;
336eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        int result, flush;
337eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
338eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        bzero(&zs, sizeof(zs));
339eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
340eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_OK) {
341eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
342eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            close(traceFD);
343eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            return;
344eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
345eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
346eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        const size_t bufSize = 64*1024;
347eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        in = (uint8_t*)malloc(bufSize);
348eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        out = (uint8_t*)malloc(bufSize);
349eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        flush = Z_NO_FLUSH;
350eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
351eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        zs.next_out = out;
352eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        zs.avail_out = bufSize;
353eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
354eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        do {
355eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
356eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if (zs.avail_in == 0) {
357eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                // More input is needed.
358eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                result = read(traceFD, in, bufSize);
359eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                if (result < 0) {
360eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
361eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                            strerror(errno), errno);
362eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    result = Z_STREAM_END;
363eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    break;
364eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                } else if (result == 0) {
365eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    flush = Z_FINISH;
366eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                } else {
367eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.next_in = in;
368eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.avail_in = result;
369eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                }
370eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
371eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
372eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if (zs.avail_out == 0) {
373eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                // Need to write the output.
374eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
375eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                if ((size_t)result < bufSize) {
376eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
377eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                            strerror(errno), errno);
378eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    result = Z_STREAM_END; // skip deflate error message
379eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.avail_out = bufSize; // skip the final write
380eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    break;
381eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                }
382eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                zs.next_out = out;
383eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                zs.avail_out = bufSize;
384eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
385eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
386eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
387eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
388eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_STREAM_END) {
389eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
390eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
391eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
392eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (zs.avail_out < bufSize) {
393eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            size_t bytes = bufSize - zs.avail_out;
394eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            result = write(STDOUT_FILENO, out, bytes);
395eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if ((size_t)result < bytes) {
396eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
397eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                        strerror(errno), errno);
398eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
399eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
400eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
401eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        result = deflateEnd(&zs);
402eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_OK) {
403eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
404eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
405eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
406eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        free(in);
407eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        free(out);
408eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis    } else {
409eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        ssize_t sent = 0;
410eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
411eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (sent == -1) {
412eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
413eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    errno);
414eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
4156b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
4166b995818535af84c4a6829af7733684861f20144Jamie Gennis
4176b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
4186b995818535af84c4a6829af7733684861f20144Jamie Gennis}
4196b995818535af84c4a6829af7733684861f20144Jamie Gennis
4206b995818535af84c4a6829af7733684861f20144Jamie Gennis// Print the command usage help to stderr.
4216b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void showHelp(const char *cmd)
4226b995818535af84c4a6829af7733684861f20144Jamie Gennis{
4236b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
4246b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "options include:\n"
425bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
4266b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -c              trace into a circular buffer\n"
42783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown                    "  -d              trace disk I/O\n"
428a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                    "  -f              trace clock frequency changes\n"
429bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -l              trace CPU frequency governor load\n"
4306b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -s              trace the kernel scheduler switches\n"
4316b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
432a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                    "  -u              trace bus utilization\n"
433eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    "  -w              trace the kernel workqueue\n"
4343f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling                    "  -y              trace sync timelines and waits\n"
435eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    "  -z              compress the trace dump\n");
4366b995818535af84c4a6829af7733684861f20144Jamie Gennis}
4376b995818535af84c4a6829af7733684861f20144Jamie Gennis
4386b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void handleSignal(int signo) {
439a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten    if (!g_nohup) {
440a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten        g_traceAborted = true;
441a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten    }
4426b995818535af84c4a6829af7733684861f20144Jamie Gennis}
4436b995818535af84c4a6829af7733684861f20144Jamie Gennis
4446b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void registerSigHandler() {
4456b995818535af84c4a6829af7733684861f20144Jamie Gennis    struct sigaction sa;
4466b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigemptyset(&sa.sa_mask);
4476b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_flags = 0;
4486b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_handler = handleSignal;
4496b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGHUP, &sa, NULL);
4506b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGINT, &sa, NULL);
4516b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGQUIT, &sa, NULL);
4526b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGTERM, &sa, NULL);
4536b995818535af84c4a6829af7733684861f20144Jamie Gennis}
4546b995818535af84c4a6829af7733684861f20144Jamie Gennis
4556b995818535af84c4a6829af7733684861f20144Jamie Gennisint main(int argc, char **argv)
4566b995818535af84c4a6829af7733684861f20144Jamie Gennis{
457b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    bool isRoot = (getuid() == 0);
458b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
4596b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
4606b995818535af84c4a6829af7733684861f20144Jamie Gennis        showHelp(argv[0]);
4616b995818535af84c4a6829af7733684861f20144Jamie Gennis        exit(0);
4626b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
4636b995818535af84c4a6829af7733684861f20144Jamie Gennis
4646b995818535af84c4a6829af7733684861f20144Jamie Gennis    for (;;) {
4656b995818535af84c4a6829af7733684861f20144Jamie Gennis        int ret;
4666b995818535af84c4a6829af7733684861f20144Jamie Gennis
4673f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling        ret = getopt(argc, argv, "b:cidflst:uwyznS:");
4686b995818535af84c4a6829af7733684861f20144Jamie Gennis
4696b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ret < 0) {
4706b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4716b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
4726b995818535af84c4a6829af7733684861f20144Jamie Gennis
4736b995818535af84c4a6829af7733684861f20144Jamie Gennis        switch(ret) {
474bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'b':
475bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
476bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
477bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
4786b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'c':
4796b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceOverwrite = true;
4806b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4816b995818535af84c4a6829af7733684861f20144Jamie Gennis
482585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis            case 'i':
483585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis                g_traceCpuIdle = true;
484585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis            break;
485585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
486bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'l':
487bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceGovernorLoad = true;
488bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
489bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
49083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown            case 'd':
491b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                if (!isRoot) {
492b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    fprintf(stderr, "error: tracing disk activity requires root privileges\n");
493b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    exit(1);
494b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                }
49583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown                g_traceDisk = true;
49683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown            break;
49783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
498bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'f':
499a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                g_traceFrequency = true;
500bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
501bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
502a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten            case 'n':
503a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten                g_nohup = true;
504a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten                break;
505a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten
5066b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 's':
5076b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceSchedSwitch = true;
5086b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
5096b995818535af84c4a6829af7733684861f20144Jamie Gennis
510a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten            case 'S':
511a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten                g_initialSleepSecs = atoi(optarg);
512a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten            break;
513a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten
5146b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 't':
5156b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceDurationSeconds = atoi(optarg);
5166b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
5176b995818535af84c4a6829af7733684861f20144Jamie Gennis
518a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling            case 'u':
519a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                if (!isRoot) {
520a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                    fprintf(stderr, "error: tracing bus utilization requires root privileges\n");
521a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                    exit(1);
522a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                }
523a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                g_traceBusUtilization = true;
524a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling            break;
525a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling
5266b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'w':
527b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                if (!isRoot) {
528b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
529b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    exit(1);
530b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                }
5316b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceWorkqueue = true;
5326b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
5336b995818535af84c4a6829af7733684861f20144Jamie Gennis
5343f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling            case 'y':
5353f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling                if (!isRoot) {
5363f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling                    fprintf(stderr, "error: tracing sync requires root privileges\n");
5373f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling                    exit(1);
5383f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling                }
5393f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling                g_traceSync = true;
5403f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling            break;
5413f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling
542eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            case 'z':
543eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                g_compress = true;
544eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            break;
545eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
5466b995818535af84c4a6829af7733684861f20144Jamie Gennis            default:
547bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                fprintf(stderr, "\n");
5486b995818535af84c4a6829af7733684861f20144Jamie Gennis                showHelp(argv[0]);
5496b995818535af84c4a6829af7733684861f20144Jamie Gennis                exit(-1);
5506b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
5516b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
5526b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
5536b995818535af84c4a6829af7733684861f20144Jamie Gennis
5546b995818535af84c4a6829af7733684861f20144Jamie Gennis    registerSigHandler();
5556b995818535af84c4a6829af7733684861f20144Jamie Gennis
556a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten    if (g_initialSleepSecs > 0) {
557a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten        sleep(g_initialSleepSecs);
558a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten    }
559a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten
560b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    bool ok = startTrace(isRoot);
5616b995818535af84c4a6829af7733684861f20144Jamie Gennis
5626b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
5636b995818535af84c4a6829af7733684861f20144Jamie Gennis        printf("capturing trace...");
5646b995818535af84c4a6829af7733684861f20144Jamie Gennis        fflush(stdout);
5656b995818535af84c4a6829af7733684861f20144Jamie Gennis
5666b995818535af84c4a6829af7733684861f20144Jamie Gennis        // We clear the trace after starting it because tracing gets enabled for
5676b995818535af84c4a6829af7733684861f20144Jamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
5686b995818535af84c4a6829af7733684861f20144Jamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
5696b995818535af84c4a6829af7733684861f20144Jamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
5706b995818535af84c4a6829af7733684861f20144Jamie Gennis        // another.
5716b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = clearTrace();
5726b995818535af84c4a6829af7733684861f20144Jamie Gennis
5736b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ok) {
5746b995818535af84c4a6829af7733684861f20144Jamie Gennis            // Sleep to allow the trace to be captured.
5756b995818535af84c4a6829af7733684861f20144Jamie Gennis            struct timespec timeLeft;
5766b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
5776b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_nsec = 0;
5786b995818535af84c4a6829af7733684861f20144Jamie Gennis            do {
5796b995818535af84c4a6829af7733684861f20144Jamie Gennis                if (g_traceAborted) {
5806b995818535af84c4a6829af7733684861f20144Jamie Gennis                    break;
5816b995818535af84c4a6829af7733684861f20144Jamie Gennis                }
5826b995818535af84c4a6829af7733684861f20144Jamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
5836b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
5846b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
5856b995818535af84c4a6829af7733684861f20144Jamie Gennis
5866b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Stop the trace and restore the default settings.
587b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    stopTrace(isRoot);
5886b995818535af84c4a6829af7733684861f20144Jamie Gennis
5896b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
5906b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (!g_traceAborted) {
5916b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf(" done\nTRACE:\n");
5926b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
5936b995818535af84c4a6829af7733684861f20144Jamie Gennis            dumpTrace();
5946b995818535af84c4a6829af7733684861f20144Jamie Gennis        } else {
5956b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf("\ntrace aborted.\n");
5966b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
5976b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
5986b995818535af84c4a6829af7733684861f20144Jamie Gennis        clearTrace();
5996b995818535af84c4a6829af7733684861f20144Jamie Gennis    } else {
6006b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "unable to start tracing\n");
6016b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
6026b995818535af84c4a6829af7733684861f20144Jamie Gennis
603bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // Reset the trace buffer size to 1.
604bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    setTraceBufferSizeKB(1);
605bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
6066b995818535af84c4a6829af7733684861f20144Jamie Gennis    return g_traceAborted ? 1 : 0;
6076b995818535af84c4a6829af7733684861f20144Jamie Gennis}
608