atrace.c revision b9314021ee1ccaa62eb115e8e0188f482a950f3b
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;
33bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool g_traceCpuFrequency = false;
34585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic bool g_traceCpuIdle = false;
3583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool g_traceDisk = false;
36bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool g_traceGovernorLoad = false;
376b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceWorkqueue = false;
386b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceOverwrite = false;
39bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
40eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennisstatic bool g_compress = false;
416b995818535af84c4a6829af7733684861f20144Jamie Gennis
426b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Global state */
436b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceAborted = false;
446b995818535af84c4a6829af7733684861f20144Jamie Gennis
456b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Sys file paths */
466b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceClockPath =
476b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
486b995818535af84c4a6829af7733684861f20144Jamie Gennis
49bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_traceBufferSizePath =
50bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
51bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
526b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOverwriteEnablePath =
536b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
546b995818535af84c4a6829af7733684861f20144Jamie Gennis
556b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_schedSwitchEnablePath =
566b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
576b995818535af84c4a6829af7733684861f20144Jamie Gennis
58b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic const char* k_schedWakeupEnablePath =
59b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
60b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
61bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_cpuFreqEnablePath =
62bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
63bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
64585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic const char* k_cpuIdleEnablePath =
65585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
66585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
67bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_governorLoadEnablePath =
68bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
69bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
706b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_workqueueEnablePath =
716b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
726b995818535af84c4a6829af7733684861f20144Jamie Gennis
7383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic const char* k_diskEnablePaths[] = {
7483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
7583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
7683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
7783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
7883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown};
7983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
806b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOnPath =
816b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
826b995818535af84c4a6829af7733684861f20144Jamie Gennis
836b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracePath =
846b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace";
856b995818535af84c4a6829af7733684861f20144Jamie Gennis
866b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceMarkerPath =
876b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
886b995818535af84c4a6829af7733684861f20144Jamie Gennis
896b995818535af84c4a6829af7733684861f20144Jamie Gennis// Write a string to a file, returning true if the write was successful.
906b995818535af84c4a6829af7733684861f20144Jamie Gennisbool writeStr(const char* filename, const char* str)
916b995818535af84c4a6829af7733684861f20144Jamie Gennis{
926b995818535af84c4a6829af7733684861f20144Jamie Gennis    int fd = open(filename, O_WRONLY);
936b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (fd == -1) {
946b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
956b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
966b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
976b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
986b995818535af84c4a6829af7733684861f20144Jamie Gennis
996b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
1006b995818535af84c4a6829af7733684861f20144Jamie Gennis    ssize_t len = strlen(str);
1016b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (write(fd, str, len) != len) {
1026b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
1036b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1046b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = false;
1056b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1066b995818535af84c4a6829af7733684861f20144Jamie Gennis
1076b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(fd);
1086b995818535af84c4a6829af7733684861f20144Jamie Gennis
1096b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
1106b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1116b995818535af84c4a6829af7733684861f20144Jamie Gennis
1126b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
1136b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
1146b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1156b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(filename, enable ? "1" : "0");
1166b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1176b995818535af84c4a6829af7733684861f20144Jamie Gennis
11883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
11983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
12083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{
12183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    bool result = true;
12283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    for (size_t i = 0; i < count; i++) {
12383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        result &= setKernelOptionEnable(filenames[i], enable);
12483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    }
12583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    return result;
12683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown}
12783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
1286b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
1296b995818535af84c4a6829af7733684861f20144Jamie Gennis// will cause tracing to stop once the trace buffers have filled up.
1306b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
1316b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1326b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
1336b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1346b995818535af84c4a6829af7733684861f20144Jamie Gennis
1356b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel scheduler switching.
1366b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
1376b995818535af84c4a6829af7733684861f20144Jamie Gennis{
138b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    bool ok = true;
139b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
140b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
141b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    return ok;
1426b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1436b995818535af84c4a6829af7733684861f20144Jamie Gennis
144bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the CPU clock frequency.
145bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setCpuFrequencyTracingEnable(bool enable)
146bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
147bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return setKernelOptionEnable(k_cpuFreqEnablePath, enable);
148bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
149bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
150585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis// Enable or disable tracing of CPU idle events.
151585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic bool setCpuIdleTracingEnable(bool enable)
152585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis{
153585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
154585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis}
155585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
156bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of
157bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// the CPU load.
158bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable)
159bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
160bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return setKernelOptionEnable(k_governorLoadEnablePath, enable);
161bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
162bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
1636b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel workqueues.
1646b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
1656b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1666b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
1676b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1686b995818535af84c4a6829af7733684861f20144Jamie Gennis
16983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable tracing of disk I/O.
17083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setDiskTracingEnabled(bool enable)
17183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{
17283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
17383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown}
17483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
1756b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable kernel tracing.
1766b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTracingEnabled(bool enable)
1776b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1786b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
1796b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1806b995818535af84c4a6829af7733684861f20144Jamie Gennis
1816b995818535af84c4a6829af7733684861f20144Jamie Gennis// Clear the contents of the kernel trace.
1826b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool clearTrace()
1836b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1846b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = creat(k_tracePath, 0);
1856b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
1866b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
1876b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1886b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
1896b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1906b995818535af84c4a6829af7733684861f20144Jamie Gennis
1916b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
1926b995818535af84c4a6829af7733684861f20144Jamie Gennis
1936b995818535af84c4a6829af7733684861f20144Jamie Gennis    return true;
1946b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1956b995818535af84c4a6829af7733684861f20144Jamie Gennis
196bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
197bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
198bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
199bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    char str[32] = "1";
200bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    int len;
201bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    if (size < 1) {
202bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis        size = 1;
203bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    }
204bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    snprintf(str, 32, "%d", size);
205bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
206bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
207bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
2086b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
2096b995818535af84c4a6829af7733684861f20144Jamie Gennis// clock will result in the kernel using a per-CPU local clock.
2106b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setGlobalClockEnable(bool enable)
2116b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2126b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
2136b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2146b995818535af84c4a6829af7733684861f20144Jamie Gennis
215416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis// Check whether a file exists.
216416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennisstatic bool fileExists(const char* filename) {
217416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    return access(filename, F_OK) != -1;
218416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis}
219416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis
2206b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable tracing in the kernel.
221b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic bool startTrace(bool isRoot)
2226b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2236b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
2246b995818535af84c4a6829af7733684861f20144Jamie Gennis
225b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // Set up the tracing options that don't require root.
2266b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
2276b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
228bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    ok &= setCpuFrequencyTracingEnable(g_traceCpuFrequency);
229585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
230416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    if (fileExists(k_governorLoadEnablePath) || g_traceGovernorLoad) {
231416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis        ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
232416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    }
233bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
2346b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setGlobalClockEnable(true);
2356b995818535af84c4a6829af7733684861f20144Jamie Gennis
236b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // Set up the tracing options that do require root.  The options that
237b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // require root should have errored out earlier if we're not running as
238b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    // root.
239b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    if (isRoot) {
240b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
241b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        ok &= setDiskTracingEnabled(g_traceDisk);
242b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    }
243b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
2446b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Enable tracing.
2456b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTracingEnabled(true);
2466b995818535af84c4a6829af7733684861f20144Jamie Gennis
2476b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (!ok) {
2486b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error: unable to start trace\n");
2496b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2506b995818535af84c4a6829af7733684861f20144Jamie Gennis
2516b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
2526b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2536b995818535af84c4a6829af7733684861f20144Jamie Gennis
2546b995818535af84c4a6829af7733684861f20144Jamie Gennis// Disable tracing in the kernel.
255b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic void stopTrace(bool isRoot)
2566b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2576b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Disable tracing.
2586b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTracingEnabled(false);
2596b995818535af84c4a6829af7733684861f20144Jamie Gennis
2606b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Set the options back to their defaults.
2616b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTraceOverwriteEnable(true);
2626b995818535af84c4a6829af7733684861f20144Jamie Gennis    setSchedSwitchTracingEnable(false);
263bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    setCpuFrequencyTracingEnable(false);
264416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    if (fileExists(k_governorLoadEnablePath)) {
265416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis        setGovernorLoadTracingEnable(false);
266416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    }
2676b995818535af84c4a6829af7733684861f20144Jamie Gennis    setGlobalClockEnable(false);
268bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
269b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    if (isRoot) {
270b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        setWorkqueueTracingEnabled(false);
271b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis        setDiskTracingEnabled(false);
272b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    }
273b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
274bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
275bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // clear the trace before we've read it.
2766b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2776b995818535af84c4a6829af7733684861f20144Jamie Gennis
2786b995818535af84c4a6829af7733684861f20144Jamie Gennis// Read the current kernel trace and write it to stdout.
2796b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void dumpTrace()
2806b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2816b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
2826b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
2836b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
2846b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
2856b995818535af84c4a6829af7733684861f20144Jamie Gennis        return;
2866b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2876b995818535af84c4a6829af7733684861f20144Jamie Gennis
288eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis    if (g_compress) {
289eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        z_stream zs;
290eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        uint8_t *in, *out;
291eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        int result, flush;
292eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
293eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        bzero(&zs, sizeof(zs));
294eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
295eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_OK) {
296eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
297eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            close(traceFD);
298eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            return;
299eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
300eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
301eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        const size_t bufSize = 64*1024;
302eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        in = (uint8_t*)malloc(bufSize);
303eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        out = (uint8_t*)malloc(bufSize);
304eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        flush = Z_NO_FLUSH;
305eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
306eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        zs.next_out = out;
307eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        zs.avail_out = bufSize;
308eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
309eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        do {
310eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
311eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if (zs.avail_in == 0) {
312eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                // More input is needed.
313eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                result = read(traceFD, in, bufSize);
314eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                if (result < 0) {
315eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
316eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                            strerror(errno), errno);
317eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    result = Z_STREAM_END;
318eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    break;
319eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                } else if (result == 0) {
320eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    flush = Z_FINISH;
321eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                } else {
322eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.next_in = in;
323eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.avail_in = result;
324eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                }
325eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
326eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
327eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if (zs.avail_out == 0) {
328eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                // Need to write the output.
329eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
330eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                if ((size_t)result < bufSize) {
331eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
332eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                            strerror(errno), errno);
333eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    result = Z_STREAM_END; // skip deflate error message
334eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.avail_out = bufSize; // skip the final write
335eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    break;
336eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                }
337eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                zs.next_out = out;
338eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                zs.avail_out = bufSize;
339eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
340eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
341eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
342eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
343eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_STREAM_END) {
344eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
345eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
346eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
347eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (zs.avail_out < bufSize) {
348eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            size_t bytes = bufSize - zs.avail_out;
349eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            result = write(STDOUT_FILENO, out, bytes);
350eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if ((size_t)result < bytes) {
351eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
352eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                        strerror(errno), errno);
353eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
354eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
355eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
356eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        result = deflateEnd(&zs);
357eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_OK) {
358eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
359eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
360eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
361eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        free(in);
362eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        free(out);
363eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis    } else {
364eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        ssize_t sent = 0;
365eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
366eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (sent == -1) {
367eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
368eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    errno);
369eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
3706b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
3716b995818535af84c4a6829af7733684861f20144Jamie Gennis
3726b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
3736b995818535af84c4a6829af7733684861f20144Jamie Gennis}
3746b995818535af84c4a6829af7733684861f20144Jamie Gennis
3756b995818535af84c4a6829af7733684861f20144Jamie Gennis// Print the command usage help to stderr.
3766b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void showHelp(const char *cmd)
3776b995818535af84c4a6829af7733684861f20144Jamie Gennis{
3786b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
3796b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "options include:\n"
380bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
3816b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -c              trace into a circular buffer\n"
38283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown                    "  -d              trace disk I/O\n"
383bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -f              trace CPU frequency changes\n"
384bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -l              trace CPU frequency governor load\n"
3856b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -s              trace the kernel scheduler switches\n"
3866b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
387eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    "  -w              trace the kernel workqueue\n"
388eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    "  -z              compress the trace dump\n");
3896b995818535af84c4a6829af7733684861f20144Jamie Gennis}
3906b995818535af84c4a6829af7733684861f20144Jamie Gennis
3916b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void handleSignal(int signo) {
3926b995818535af84c4a6829af7733684861f20144Jamie Gennis    g_traceAborted = true;
3936b995818535af84c4a6829af7733684861f20144Jamie Gennis}
3946b995818535af84c4a6829af7733684861f20144Jamie Gennis
3956b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void registerSigHandler() {
3966b995818535af84c4a6829af7733684861f20144Jamie Gennis    struct sigaction sa;
3976b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigemptyset(&sa.sa_mask);
3986b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_flags = 0;
3996b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_handler = handleSignal;
4006b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGHUP, &sa, NULL);
4016b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGINT, &sa, NULL);
4026b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGQUIT, &sa, NULL);
4036b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGTERM, &sa, NULL);
4046b995818535af84c4a6829af7733684861f20144Jamie Gennis}
4056b995818535af84c4a6829af7733684861f20144Jamie Gennis
4066b995818535af84c4a6829af7733684861f20144Jamie Gennisint main(int argc, char **argv)
4076b995818535af84c4a6829af7733684861f20144Jamie Gennis{
408b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    bool isRoot = (getuid() == 0);
409b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis
4106b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
4116b995818535af84c4a6829af7733684861f20144Jamie Gennis        showHelp(argv[0]);
4126b995818535af84c4a6829af7733684861f20144Jamie Gennis        exit(0);
4136b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
4146b995818535af84c4a6829af7733684861f20144Jamie Gennis
4156b995818535af84c4a6829af7733684861f20144Jamie Gennis    for (;;) {
4166b995818535af84c4a6829af7733684861f20144Jamie Gennis        int ret;
4176b995818535af84c4a6829af7733684861f20144Jamie Gennis
41883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        ret = getopt(argc, argv, "b:cidflst:wz");
4196b995818535af84c4a6829af7733684861f20144Jamie Gennis
4206b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ret < 0) {
4216b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4226b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
4236b995818535af84c4a6829af7733684861f20144Jamie Gennis
4246b995818535af84c4a6829af7733684861f20144Jamie Gennis        switch(ret) {
425bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'b':
426bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
427bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
428bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
4296b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'c':
4306b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceOverwrite = true;
4316b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4326b995818535af84c4a6829af7733684861f20144Jamie Gennis
433585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis            case 'i':
434585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis                g_traceCpuIdle = true;
435585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis            break;
436585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
437bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'l':
438bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceGovernorLoad = true;
439bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
440bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
44183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown            case 'd':
442b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                if (!isRoot) {
443b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    fprintf(stderr, "error: tracing disk activity requires root privileges\n");
444b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    exit(1);
445b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                }
44683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown                g_traceDisk = true;
44783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown            break;
44883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
449bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'f':
450bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceCpuFrequency = true;
451bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
452bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
4536b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 's':
4546b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceSchedSwitch = true;
4556b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4566b995818535af84c4a6829af7733684861f20144Jamie Gennis
4576b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 't':
4586b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceDurationSeconds = atoi(optarg);
4596b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4606b995818535af84c4a6829af7733684861f20144Jamie Gennis
4616b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'w':
462b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                if (!isRoot) {
463b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
464b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                    exit(1);
465b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis                }
4666b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceWorkqueue = true;
4676b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4686b995818535af84c4a6829af7733684861f20144Jamie Gennis
469eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            case 'z':
470eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                g_compress = true;
471eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            break;
472eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
4736b995818535af84c4a6829af7733684861f20144Jamie Gennis            default:
474bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                fprintf(stderr, "\n");
4756b995818535af84c4a6829af7733684861f20144Jamie Gennis                showHelp(argv[0]);
4766b995818535af84c4a6829af7733684861f20144Jamie Gennis                exit(-1);
4776b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4786b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
4796b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
4806b995818535af84c4a6829af7733684861f20144Jamie Gennis
4816b995818535af84c4a6829af7733684861f20144Jamie Gennis    registerSigHandler();
4826b995818535af84c4a6829af7733684861f20144Jamie Gennis
483b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    bool ok = startTrace(isRoot);
4846b995818535af84c4a6829af7733684861f20144Jamie Gennis
4856b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
4866b995818535af84c4a6829af7733684861f20144Jamie Gennis        printf("capturing trace...");
4876b995818535af84c4a6829af7733684861f20144Jamie Gennis        fflush(stdout);
4886b995818535af84c4a6829af7733684861f20144Jamie Gennis
4896b995818535af84c4a6829af7733684861f20144Jamie Gennis        // We clear the trace after starting it because tracing gets enabled for
4906b995818535af84c4a6829af7733684861f20144Jamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
4916b995818535af84c4a6829af7733684861f20144Jamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
4926b995818535af84c4a6829af7733684861f20144Jamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
4936b995818535af84c4a6829af7733684861f20144Jamie Gennis        // another.
4946b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = clearTrace();
4956b995818535af84c4a6829af7733684861f20144Jamie Gennis
4966b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ok) {
4976b995818535af84c4a6829af7733684861f20144Jamie Gennis            // Sleep to allow the trace to be captured.
4986b995818535af84c4a6829af7733684861f20144Jamie Gennis            struct timespec timeLeft;
4996b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
5006b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_nsec = 0;
5016b995818535af84c4a6829af7733684861f20144Jamie Gennis            do {
5026b995818535af84c4a6829af7733684861f20144Jamie Gennis                if (g_traceAborted) {
5036b995818535af84c4a6829af7733684861f20144Jamie Gennis                    break;
5046b995818535af84c4a6829af7733684861f20144Jamie Gennis                }
5056b995818535af84c4a6829af7733684861f20144Jamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
5066b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
5076b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
5086b995818535af84c4a6829af7733684861f20144Jamie Gennis
5096b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Stop the trace and restore the default settings.
510b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis    stopTrace(isRoot);
5116b995818535af84c4a6829af7733684861f20144Jamie Gennis
5126b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
5136b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (!g_traceAborted) {
5146b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf(" done\nTRACE:\n");
5156b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
5166b995818535af84c4a6829af7733684861f20144Jamie Gennis            dumpTrace();
5176b995818535af84c4a6829af7733684861f20144Jamie Gennis        } else {
5186b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf("\ntrace aborted.\n");
5196b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
5206b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
5216b995818535af84c4a6829af7733684861f20144Jamie Gennis        clearTrace();
5226b995818535af84c4a6829af7733684861f20144Jamie Gennis    } else {
5236b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "unable to start tracing\n");
5246b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
5256b995818535af84c4a6829af7733684861f20144Jamie Gennis
526bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // Reset the trace buffer size to 1.
527bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    setTraceBufferSizeKB(1);
528bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
5296b995818535af84c4a6829af7733684861f20144Jamie Gennis    return g_traceAborted ? 1 : 0;
5306b995818535af84c4a6829af7733684861f20144Jamie Gennis}
531