atrace.c revision a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9
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;
386b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceWorkqueue = false;
396b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceOverwrite = false;
40bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
41eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennisstatic bool g_compress = false;
426b995818535af84c4a6829af7733684861f20144Jamie Gennis
436b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Global state */
446b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceAborted = false;
456b995818535af84c4a6829af7733684861f20144Jamie Gennis
466b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Sys file paths */
476b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceClockPath =
486b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
496b995818535af84c4a6829af7733684861f20144Jamie Gennis
50bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_traceBufferSizePath =
51bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
52bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
536b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOverwriteEnablePath =
546b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
556b995818535af84c4a6829af7733684861f20144Jamie Gennis
566b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_schedSwitchEnablePath =
576b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
586b995818535af84c4a6829af7733684861f20144Jamie Gennis
59b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic const char* k_schedWakeupEnablePath =
60b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
61b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
62a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic const char* k_memoryBusEnablePath =
63a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    "/sys/kernel/debug/tracing/events/memory_bus/enable";
64a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling
65bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_cpuFreqEnablePath =
66bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
67bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
68a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic const char *k_clockSetRateEnablePath =
69a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable";
70a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling
71585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic const char* k_cpuIdleEnablePath =
72585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
73585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
74bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_governorLoadEnablePath =
75bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
76bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
776b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_workqueueEnablePath =
786b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
796b995818535af84c4a6829af7733684861f20144Jamie Gennis
8083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic const char* k_diskEnablePaths[] = {
8183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
8283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
8383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
8483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
8583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown};
8683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
876b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOnPath =
886b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
896b995818535af84c4a6829af7733684861f20144Jamie Gennis
906b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracePath =
916b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace";
926b995818535af84c4a6829af7733684861f20144Jamie Gennis
936b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceMarkerPath =
946b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
956b995818535af84c4a6829af7733684861f20144Jamie Gennis
966b995818535af84c4a6829af7733684861f20144Jamie Gennis// Write a string to a file, returning true if the write was successful.
976b995818535af84c4a6829af7733684861f20144Jamie Gennisbool writeStr(const char* filename, const char* str)
986b995818535af84c4a6829af7733684861f20144Jamie Gennis{
996b995818535af84c4a6829af7733684861f20144Jamie Gennis    int fd = open(filename, O_WRONLY);
1006b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (fd == -1) {
1016b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
1026b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1036b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
1046b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1056b995818535af84c4a6829af7733684861f20144Jamie Gennis
1066b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
1076b995818535af84c4a6829af7733684861f20144Jamie Gennis    ssize_t len = strlen(str);
1086b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (write(fd, str, len) != len) {
1096b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
1106b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1116b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = false;
1126b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1136b995818535af84c4a6829af7733684861f20144Jamie Gennis
1146b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(fd);
1156b995818535af84c4a6829af7733684861f20144Jamie Gennis
1166b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
1176b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1186b995818535af84c4a6829af7733684861f20144Jamie Gennis
1196b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
1206b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
1216b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1226b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(filename, enable ? "1" : "0");
1236b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1246b995818535af84c4a6829af7733684861f20144Jamie Gennis
12583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
12683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
12783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{
12883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    bool result = true;
12983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    for (size_t i = 0; i < count; i++) {
13083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        result &= setKernelOptionEnable(filenames[i], enable);
13183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    }
13283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    return result;
13383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown}
13483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
1356b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
1366b995818535af84c4a6829af7733684861f20144Jamie Gennis// will cause tracing to stop once the trace buffers have filled up.
1376b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
1386b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1396b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
1406b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1416b995818535af84c4a6829af7733684861f20144Jamie Gennis
1426b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel scheduler switching.
1436b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
1446b995818535af84c4a6829af7733684861f20144Jamie Gennis{
145b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    bool ok = true;
146b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
147b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
148b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    return ok;
1496b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1506b995818535af84c4a6829af7733684861f20144Jamie Gennis
151a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling// Enable or disable tracing of the Bus utilization.
152a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool setBusUtilizationTracingEnable(bool enable)
153a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling{
154a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    bool ok = false;
155a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    // these can be platform specific so make sure that at least
156a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    // one succeeds.
157a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    ok |= setKernelOptionEnable(k_memoryBusEnablePath, enable);
158a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    return ok;
159a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling}
160a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling
161bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the CPU clock frequency.
162a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool setFrequencyTracingEnable(bool enable)
163bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
164a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    bool ok = true;
165a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable);
166a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable);
167a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    return ok;
168bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
169bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
170585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis// Enable or disable tracing of CPU idle events.
171585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic bool setCpuIdleTracingEnable(bool enable)
172585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis{
173585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
174585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis}
175585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
176bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of
177bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// the CPU load.
178bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable)
179bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
180bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return setKernelOptionEnable(k_governorLoadEnablePath, enable);
181bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
182bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
1836b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel workqueues.
1846b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
1856b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1866b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
1876b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1886b995818535af84c4a6829af7733684861f20144Jamie Gennis
18983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable tracing of disk I/O.
19083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setDiskTracingEnabled(bool enable)
19183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{
19283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
19383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown}
19483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
1956b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable kernel tracing.
1966b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTracingEnabled(bool enable)
1976b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1986b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
1996b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2006b995818535af84c4a6829af7733684861f20144Jamie Gennis
2016b995818535af84c4a6829af7733684861f20144Jamie Gennis// Clear the contents of the kernel trace.
2026b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool clearTrace()
2036b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2046b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = creat(k_tracePath, 0);
2056b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
2066b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
2076b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
2086b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
2096b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2106b995818535af84c4a6829af7733684861f20144Jamie Gennis
2116b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
2126b995818535af84c4a6829af7733684861f20144Jamie Gennis
2136b995818535af84c4a6829af7733684861f20144Jamie Gennis    return true;
2146b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2156b995818535af84c4a6829af7733684861f20144Jamie Gennis
216bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
217bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
218bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
219bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    char str[32] = "1";
220bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    int len;
221bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    if (size < 1) {
222bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis        size = 1;
223bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    }
224bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    snprintf(str, 32, "%d", size);
225bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
226bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
227bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
2286b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
2296b995818535af84c4a6829af7733684861f20144Jamie Gennis// clock will result in the kernel using a per-CPU local clock.
2306b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setGlobalClockEnable(bool enable)
2316b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2326b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
2336b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2346b995818535af84c4a6829af7733684861f20144Jamie Gennis
235416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis// Check whether a file exists.
236416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennisstatic bool fileExists(const char* filename) {
237416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    return access(filename, F_OK) != -1;
238416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis}
239416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis
2406b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable tracing in the kernel.
241b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic bool startTrace(bool isRoot)
2426b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2436b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
2446b995818535af84c4a6829af7733684861f20144Jamie Gennis
245b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // Set up the tracing options that don't require root.
2466b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
2476b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
248a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    ok &= setBusUtilizationTracingEnable(g_traceBusUtilization);
249a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    ok &= setFrequencyTracingEnable(g_traceFrequency);
250585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
251416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    if (fileExists(k_governorLoadEnablePath) || g_traceGovernorLoad) {
252416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis        ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
253416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    }
254bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
2556b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setGlobalClockEnable(true);
2566b995818535af84c4a6829af7733684861f20144Jamie Gennis
257b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // Set up the tracing options that do require root.  The options that
258b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // require root should have errored out earlier if we're not running as
259b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // root.
260b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    if (isRoot) {
261b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
262b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        ok &= setDiskTracingEnabled(g_traceDisk);
263b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    }
264b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
2656b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Enable tracing.
2666b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTracingEnabled(true);
2676b995818535af84c4a6829af7733684861f20144Jamie Gennis
2686b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (!ok) {
2696b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error: unable to start trace\n");
2706b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2716b995818535af84c4a6829af7733684861f20144Jamie Gennis
2726b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
2736b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2746b995818535af84c4a6829af7733684861f20144Jamie Gennis
2756b995818535af84c4a6829af7733684861f20144Jamie Gennis// Disable tracing in the kernel.
276b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic void stopTrace(bool isRoot)
2776b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2786b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Disable tracing.
2796b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTracingEnabled(false);
2806b995818535af84c4a6829af7733684861f20144Jamie Gennis
2816b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Set the options back to their defaults.
2826b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTraceOverwriteEnable(true);
2836b995818535af84c4a6829af7733684861f20144Jamie Gennis    setSchedSwitchTracingEnable(false);
284a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    setBusUtilizationTracingEnable(false);
285a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling    setFrequencyTracingEnable(false);
286416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    if (fileExists(k_governorLoadEnablePath)) {
287416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis        setGovernorLoadTracingEnable(false);
288416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    }
2896b995818535af84c4a6829af7733684861f20144Jamie Gennis    setGlobalClockEnable(false);
290bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
291b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    if (isRoot) {
292b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        setWorkqueueTracingEnabled(false);
293b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        setDiskTracingEnabled(false);
294b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    }
295b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
296bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
297bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // clear the trace before we've read it.
2986b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2996b995818535af84c4a6829af7733684861f20144Jamie Gennis
3006b995818535af84c4a6829af7733684861f20144Jamie Gennis// Read the current kernel trace and write it to stdout.
3016b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void dumpTrace()
3026b995818535af84c4a6829af7733684861f20144Jamie Gennis{
3036b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
3046b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
3056b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
3066b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
3076b995818535af84c4a6829af7733684861f20144Jamie Gennis        return;
3086b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
3096b995818535af84c4a6829af7733684861f20144Jamie Gennis
310eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis    if (g_compress) {
311eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        z_stream zs;
312eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        uint8_t *in, *out;
313eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        int result, flush;
314eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
315eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        bzero(&zs, sizeof(zs));
316eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
317eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_OK) {
318eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
319eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            close(traceFD);
320eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            return;
321eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
322eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
323eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        const size_t bufSize = 64*1024;
324eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        in = (uint8_t*)malloc(bufSize);
325eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        out = (uint8_t*)malloc(bufSize);
326eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        flush = Z_NO_FLUSH;
327eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
328eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        zs.next_out = out;
329eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        zs.avail_out = bufSize;
330eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
331eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        do {
332eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
333eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if (zs.avail_in == 0) {
334eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                // More input is needed.
335eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                result = read(traceFD, in, bufSize);
336eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                if (result < 0) {
337eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
338eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                            strerror(errno), errno);
339eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    result = Z_STREAM_END;
340eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    break;
341eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                } else if (result == 0) {
342eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    flush = Z_FINISH;
343eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                } else {
344eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.next_in = in;
345eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.avail_in = result;
346eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                }
347eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
348eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
349eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if (zs.avail_out == 0) {
350eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                // Need to write the output.
351eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
352eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                if ((size_t)result < bufSize) {
353eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
354eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                            strerror(errno), errno);
355eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    result = Z_STREAM_END; // skip deflate error message
356eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.avail_out = bufSize; // skip the final write
357eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    break;
358eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                }
359eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                zs.next_out = out;
360eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                zs.avail_out = bufSize;
361eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
362eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
363eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
364eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
365eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_STREAM_END) {
366eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
367eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
368eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
369eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (zs.avail_out < bufSize) {
370eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            size_t bytes = bufSize - zs.avail_out;
371eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            result = write(STDOUT_FILENO, out, bytes);
372eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if ((size_t)result < bytes) {
373eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
374eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                        strerror(errno), errno);
375eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
376eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
377eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
378eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        result = deflateEnd(&zs);
379eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_OK) {
380eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
381eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
382eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
383eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        free(in);
384eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        free(out);
385eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis    } else {
386eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        ssize_t sent = 0;
387eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
388eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (sent == -1) {
389eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
390eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    errno);
391eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
3926b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
3936b995818535af84c4a6829af7733684861f20144Jamie Gennis
3946b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
3956b995818535af84c4a6829af7733684861f20144Jamie Gennis}
3966b995818535af84c4a6829af7733684861f20144Jamie Gennis
3976b995818535af84c4a6829af7733684861f20144Jamie Gennis// Print the command usage help to stderr.
3986b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void showHelp(const char *cmd)
3996b995818535af84c4a6829af7733684861f20144Jamie Gennis{
4006b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
4016b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "options include:\n"
402bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
4036b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -c              trace into a circular buffer\n"
40483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown                    "  -d              trace disk I/O\n"
405a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                    "  -f              trace clock frequency changes\n"
406bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -l              trace CPU frequency governor load\n"
4076b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -s              trace the kernel scheduler switches\n"
4086b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
409a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                    "  -u              trace bus utilization\n"
410eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    "  -w              trace the kernel workqueue\n"
411eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    "  -z              compress the trace dump\n");
4126b995818535af84c4a6829af7733684861f20144Jamie Gennis}
4136b995818535af84c4a6829af7733684861f20144Jamie Gennis
4146b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void handleSignal(int signo) {
4156b995818535af84c4a6829af7733684861f20144Jamie Gennis    g_traceAborted = true;
4166b995818535af84c4a6829af7733684861f20144Jamie Gennis}
4176b995818535af84c4a6829af7733684861f20144Jamie Gennis
4186b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void registerSigHandler() {
4196b995818535af84c4a6829af7733684861f20144Jamie Gennis    struct sigaction sa;
4206b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigemptyset(&sa.sa_mask);
4216b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_flags = 0;
4226b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_handler = handleSignal;
4236b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGHUP, &sa, NULL);
4246b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGINT, &sa, NULL);
4256b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGQUIT, &sa, NULL);
4266b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGTERM, &sa, NULL);
4276b995818535af84c4a6829af7733684861f20144Jamie Gennis}
4286b995818535af84c4a6829af7733684861f20144Jamie Gennis
4296b995818535af84c4a6829af7733684861f20144Jamie Gennisint main(int argc, char **argv)
4306b995818535af84c4a6829af7733684861f20144Jamie Gennis{
431b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    bool isRoot = (getuid() == 0);
432b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
4336b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
4346b995818535af84c4a6829af7733684861f20144Jamie Gennis        showHelp(argv[0]);
4356b995818535af84c4a6829af7733684861f20144Jamie Gennis        exit(0);
4366b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
4376b995818535af84c4a6829af7733684861f20144Jamie Gennis
4386b995818535af84c4a6829af7733684861f20144Jamie Gennis    for (;;) {
4396b995818535af84c4a6829af7733684861f20144Jamie Gennis        int ret;
4406b995818535af84c4a6829af7733684861f20144Jamie Gennis
441a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling        ret = getopt(argc, argv, "b:cidflst:uwz");
4426b995818535af84c4a6829af7733684861f20144Jamie Gennis
4436b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ret < 0) {
4446b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4456b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
4466b995818535af84c4a6829af7733684861f20144Jamie Gennis
4476b995818535af84c4a6829af7733684861f20144Jamie Gennis        switch(ret) {
448bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'b':
449bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
450bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
451bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
4526b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'c':
4536b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceOverwrite = true;
4546b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4556b995818535af84c4a6829af7733684861f20144Jamie Gennis
456585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis            case 'i':
457585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis                g_traceCpuIdle = true;
458585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis            break;
459585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
460bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'l':
461bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceGovernorLoad = true;
462bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
463bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
46483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown            case 'd':
465b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                if (!isRoot) {
466b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    fprintf(stderr, "error: tracing disk activity requires root privileges\n");
467b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    exit(1);
468b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                }
46983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown                g_traceDisk = true;
47083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown            break;
47183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
472bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'f':
473a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                g_traceFrequency = true;
474bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
475bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
4766b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 's':
4776b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceSchedSwitch = true;
4786b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4796b995818535af84c4a6829af7733684861f20144Jamie Gennis
4806b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 't':
4816b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceDurationSeconds = atoi(optarg);
4826b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4836b995818535af84c4a6829af7733684861f20144Jamie Gennis
484a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling            case 'u':
485a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                if (!isRoot) {
486a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                    fprintf(stderr, "error: tracing bus utilization requires root privileges\n");
487a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                    exit(1);
488a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                }
489a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling                g_traceBusUtilization = true;
490a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling            break;
491a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling
4926b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'w':
493b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                if (!isRoot) {
494b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
495b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    exit(1);
496b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                }
4976b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceWorkqueue = true;
4986b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4996b995818535af84c4a6829af7733684861f20144Jamie Gennis
500eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            case 'z':
501eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                g_compress = true;
502eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            break;
503eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
5046b995818535af84c4a6829af7733684861f20144Jamie Gennis            default:
505bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                fprintf(stderr, "\n");
5066b995818535af84c4a6829af7733684861f20144Jamie Gennis                showHelp(argv[0]);
5076b995818535af84c4a6829af7733684861f20144Jamie Gennis                exit(-1);
5086b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
5096b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
5106b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
5116b995818535af84c4a6829af7733684861f20144Jamie Gennis
5126b995818535af84c4a6829af7733684861f20144Jamie Gennis    registerSigHandler();
5136b995818535af84c4a6829af7733684861f20144Jamie Gennis
514b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    bool ok = startTrace(isRoot);
5156b995818535af84c4a6829af7733684861f20144Jamie Gennis
5166b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
5176b995818535af84c4a6829af7733684861f20144Jamie Gennis        printf("capturing trace...");
5186b995818535af84c4a6829af7733684861f20144Jamie Gennis        fflush(stdout);
5196b995818535af84c4a6829af7733684861f20144Jamie Gennis
5206b995818535af84c4a6829af7733684861f20144Jamie Gennis        // We clear the trace after starting it because tracing gets enabled for
5216b995818535af84c4a6829af7733684861f20144Jamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
5226b995818535af84c4a6829af7733684861f20144Jamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
5236b995818535af84c4a6829af7733684861f20144Jamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
5246b995818535af84c4a6829af7733684861f20144Jamie Gennis        // another.
5256b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = clearTrace();
5266b995818535af84c4a6829af7733684861f20144Jamie Gennis
5276b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ok) {
5286b995818535af84c4a6829af7733684861f20144Jamie Gennis            // Sleep to allow the trace to be captured.
5296b995818535af84c4a6829af7733684861f20144Jamie Gennis            struct timespec timeLeft;
5306b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
5316b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_nsec = 0;
5326b995818535af84c4a6829af7733684861f20144Jamie Gennis            do {
5336b995818535af84c4a6829af7733684861f20144Jamie Gennis                if (g_traceAborted) {
5346b995818535af84c4a6829af7733684861f20144Jamie Gennis                    break;
5356b995818535af84c4a6829af7733684861f20144Jamie Gennis                }
5366b995818535af84c4a6829af7733684861f20144Jamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
5376b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
5386b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
5396b995818535af84c4a6829af7733684861f20144Jamie Gennis
5406b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Stop the trace and restore the default settings.
541b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    stopTrace(isRoot);
5426b995818535af84c4a6829af7733684861f20144Jamie Gennis
5436b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
5446b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (!g_traceAborted) {
5456b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf(" done\nTRACE:\n");
5466b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
5476b995818535af84c4a6829af7733684861f20144Jamie Gennis            dumpTrace();
5486b995818535af84c4a6829af7733684861f20144Jamie Gennis        } else {
5496b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf("\ntrace aborted.\n");
5506b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
5516b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
5526b995818535af84c4a6829af7733684861f20144Jamie Gennis        clearTrace();
5536b995818535af84c4a6829af7733684861f20144Jamie Gennis    } else {
5546b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "unable to start tracing\n");
5556b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
5566b995818535af84c4a6829af7733684861f20144Jamie Gennis
557bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // Reset the trace buffer size to 1.
558bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    setTraceBufferSizeKB(1);
559bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
5606b995818535af84c4a6829af7733684861f20144Jamie Gennis    return g_traceAborted ? 1 : 0;
5616b995818535af84c4a6829af7733684861f20144Jamie Gennis}
562