atrace.c revision 83fdbb05c39b030ef1e5b3a7db79c617114c20f4
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
58bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_cpuFreqEnablePath =
59bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
60bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
61585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic const char* k_cpuIdleEnablePath =
62585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
63585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
64bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_governorLoadEnablePath =
65bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
66bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
676b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_workqueueEnablePath =
686b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
696b995818535af84c4a6829af7733684861f20144Jamie Gennis
7083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic const char* k_diskEnablePaths[] = {
7183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
7283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
7383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
7483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
7583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown};
7683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
776b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOnPath =
786b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
796b995818535af84c4a6829af7733684861f20144Jamie Gennis
806b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracePath =
816b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace";
826b995818535af84c4a6829af7733684861f20144Jamie Gennis
836b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceMarkerPath =
846b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
856b995818535af84c4a6829af7733684861f20144Jamie Gennis
866b995818535af84c4a6829af7733684861f20144Jamie Gennis// Write a string to a file, returning true if the write was successful.
876b995818535af84c4a6829af7733684861f20144Jamie Gennisbool writeStr(const char* filename, const char* str)
886b995818535af84c4a6829af7733684861f20144Jamie Gennis{
896b995818535af84c4a6829af7733684861f20144Jamie Gennis    int fd = open(filename, O_WRONLY);
906b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (fd == -1) {
916b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
926b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
936b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
946b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
956b995818535af84c4a6829af7733684861f20144Jamie Gennis
966b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
976b995818535af84c4a6829af7733684861f20144Jamie Gennis    ssize_t len = strlen(str);
986b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (write(fd, str, len) != len) {
996b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
1006b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1016b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = false;
1026b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1036b995818535af84c4a6829af7733684861f20144Jamie Gennis
1046b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(fd);
1056b995818535af84c4a6829af7733684861f20144Jamie Gennis
1066b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
1076b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1086b995818535af84c4a6829af7733684861f20144Jamie Gennis
1096b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
1106b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
1116b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1126b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(filename, enable ? "1" : "0");
1136b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1146b995818535af84c4a6829af7733684861f20144Jamie Gennis
11583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
11683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
11783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{
11883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    bool result = true;
11983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    for (size_t i = 0; i < count; i++) {
12083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        result &= setKernelOptionEnable(filenames[i], enable);
12183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    }
12283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    return result;
12383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown}
12483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
1256b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
1266b995818535af84c4a6829af7733684861f20144Jamie Gennis// will cause tracing to stop once the trace buffers have filled up.
1276b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
1286b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1296b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
1306b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1316b995818535af84c4a6829af7733684861f20144Jamie Gennis
1326b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel scheduler switching.
1336b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
1346b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1356b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_schedSwitchEnablePath, enable);
1366b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1376b995818535af84c4a6829af7733684861f20144Jamie Gennis
138bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the CPU clock frequency.
139bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setCpuFrequencyTracingEnable(bool enable)
140bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
141bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return setKernelOptionEnable(k_cpuFreqEnablePath, enable);
142bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
143bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
144585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis// Enable or disable tracing of CPU idle events.
145585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic bool setCpuIdleTracingEnable(bool enable)
146585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis{
147585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
148585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis}
149585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
150bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of
151bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// the CPU load.
152bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable)
153bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
154bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return setKernelOptionEnable(k_governorLoadEnablePath, enable);
155bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
156bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
1576b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel workqueues.
1586b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
1596b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1606b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
1616b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1626b995818535af84c4a6829af7733684861f20144Jamie Gennis
16383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable tracing of disk I/O.
16483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setDiskTracingEnabled(bool enable)
16583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{
16683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
16783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown}
16883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
1696b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable kernel tracing.
1706b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTracingEnabled(bool enable)
1716b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1726b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
1736b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1746b995818535af84c4a6829af7733684861f20144Jamie Gennis
1756b995818535af84c4a6829af7733684861f20144Jamie Gennis// Clear the contents of the kernel trace.
1766b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool clearTrace()
1776b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1786b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = creat(k_tracePath, 0);
1796b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
1806b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
1816b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1826b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
1836b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1846b995818535af84c4a6829af7733684861f20144Jamie Gennis
1856b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
1866b995818535af84c4a6829af7733684861f20144Jamie Gennis
1876b995818535af84c4a6829af7733684861f20144Jamie Gennis    return true;
1886b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1896b995818535af84c4a6829af7733684861f20144Jamie Gennis
190bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
191bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
192bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
193bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    char str[32] = "1";
194bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    int len;
195bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    if (size < 1) {
196bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis        size = 1;
197bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    }
198bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    snprintf(str, 32, "%d", size);
199bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
200bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
201bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
2026b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
2036b995818535af84c4a6829af7733684861f20144Jamie Gennis// clock will result in the kernel using a per-CPU local clock.
2046b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setGlobalClockEnable(bool enable)
2056b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2066b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
2076b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2086b995818535af84c4a6829af7733684861f20144Jamie Gennis
209416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis// Check whether a file exists.
210416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennisstatic bool fileExists(const char* filename) {
211416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    return access(filename, F_OK) != -1;
212416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis}
213416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis
2146b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable tracing in the kernel.
2156b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool startTrace()
2166b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2176b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
2186b995818535af84c4a6829af7733684861f20144Jamie Gennis
2196b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Set up the tracing options.
2206b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
2216b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
222bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    ok &= setCpuFrequencyTracingEnable(g_traceCpuFrequency);
223585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis    ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
224416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    if (fileExists(k_governorLoadEnablePath) || g_traceGovernorLoad) {
225416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis        ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
226416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    }
2276b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
22883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown    ok &= setDiskTracingEnabled(g_traceDisk);
229bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
2306b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setGlobalClockEnable(true);
2316b995818535af84c4a6829af7733684861f20144Jamie Gennis
2326b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Enable tracing.
2336b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTracingEnabled(true);
2346b995818535af84c4a6829af7733684861f20144Jamie Gennis
2356b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (!ok) {
2366b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error: unable to start trace\n");
2376b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2386b995818535af84c4a6829af7733684861f20144Jamie Gennis
2396b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
2406b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2416b995818535af84c4a6829af7733684861f20144Jamie Gennis
2426b995818535af84c4a6829af7733684861f20144Jamie Gennis// Disable tracing in the kernel.
2436b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void stopTrace()
2446b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2456b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Disable tracing.
2466b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTracingEnabled(false);
2476b995818535af84c4a6829af7733684861f20144Jamie Gennis
2486b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Set the options back to their defaults.
2496b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTraceOverwriteEnable(true);
2506b995818535af84c4a6829af7733684861f20144Jamie Gennis    setSchedSwitchTracingEnable(false);
251bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    setCpuFrequencyTracingEnable(false);
252416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    if (fileExists(k_governorLoadEnablePath)) {
253416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis        setGovernorLoadTracingEnable(false);
254416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    }
2556b995818535af84c4a6829af7733684861f20144Jamie Gennis    setWorkqueueTracingEnabled(false);
2566b995818535af84c4a6829af7733684861f20144Jamie Gennis    setGlobalClockEnable(false);
257bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
258bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
259bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // clear the trace before we've read it.
2606b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2616b995818535af84c4a6829af7733684861f20144Jamie Gennis
2626b995818535af84c4a6829af7733684861f20144Jamie Gennis// Read the current kernel trace and write it to stdout.
2636b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void dumpTrace()
2646b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2656b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
2666b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
2676b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
2686b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
2696b995818535af84c4a6829af7733684861f20144Jamie Gennis        return;
2706b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2716b995818535af84c4a6829af7733684861f20144Jamie Gennis
272eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis    if (g_compress) {
273eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        z_stream zs;
274eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        uint8_t *in, *out;
275eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        int result, flush;
276eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
277eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        bzero(&zs, sizeof(zs));
278eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
279eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_OK) {
280eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
281eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            close(traceFD);
282eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            return;
283eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
284eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
285eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        const size_t bufSize = 64*1024;
286eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        in = (uint8_t*)malloc(bufSize);
287eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        out = (uint8_t*)malloc(bufSize);
288eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        flush = Z_NO_FLUSH;
289eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
290eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        zs.next_out = out;
291eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        zs.avail_out = bufSize;
292eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
293eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        do {
294eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
295eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if (zs.avail_in == 0) {
296eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                // More input is needed.
297eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                result = read(traceFD, in, bufSize);
298eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                if (result < 0) {
299eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
300eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                            strerror(errno), errno);
301eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    result = Z_STREAM_END;
302eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    break;
303eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                } else if (result == 0) {
304eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    flush = Z_FINISH;
305eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                } else {
306eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.next_in = in;
307eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.avail_in = result;
308eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                }
309eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
310eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
311eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if (zs.avail_out == 0) {
312eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                // Need to write the output.
313eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
314eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                if ((size_t)result < bufSize) {
315eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
316eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                            strerror(errno), errno);
317eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    result = Z_STREAM_END; // skip deflate error message
318eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    zs.avail_out = bufSize; // skip the final write
319eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    break;
320eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                }
321eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                zs.next_out = out;
322eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                zs.avail_out = bufSize;
323eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
324eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
325eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
326eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
327eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_STREAM_END) {
328eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
329eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
330eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
331eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (zs.avail_out < bufSize) {
332eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            size_t bytes = bufSize - zs.avail_out;
333eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            result = write(STDOUT_FILENO, out, bytes);
334eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            if ((size_t)result < bytes) {
335eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
336eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                        strerror(errno), errno);
337eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            }
338eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
339eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
340eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        result = deflateEnd(&zs);
341eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (result != Z_OK) {
342eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
343eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
344eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
345eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        free(in);
346eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        free(out);
347eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis    } else {
348eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        ssize_t sent = 0;
349eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
350eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        if (sent == -1) {
351eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
352eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    errno);
353eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis        }
3546b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
3556b995818535af84c4a6829af7733684861f20144Jamie Gennis
3566b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
3576b995818535af84c4a6829af7733684861f20144Jamie Gennis}
3586b995818535af84c4a6829af7733684861f20144Jamie Gennis
3596b995818535af84c4a6829af7733684861f20144Jamie Gennis// Print the command usage help to stderr.
3606b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void showHelp(const char *cmd)
3616b995818535af84c4a6829af7733684861f20144Jamie Gennis{
3626b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
3636b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "options include:\n"
364bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
3656b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -c              trace into a circular buffer\n"
36683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown                    "  -d              trace disk I/O\n"
367bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -f              trace CPU frequency changes\n"
368bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -l              trace CPU frequency governor load\n"
3696b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -s              trace the kernel scheduler switches\n"
3706b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
371eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    "  -w              trace the kernel workqueue\n"
372eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                    "  -z              compress the trace dump\n");
3736b995818535af84c4a6829af7733684861f20144Jamie Gennis}
3746b995818535af84c4a6829af7733684861f20144Jamie Gennis
3756b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void handleSignal(int signo) {
3766b995818535af84c4a6829af7733684861f20144Jamie Gennis    g_traceAborted = true;
3776b995818535af84c4a6829af7733684861f20144Jamie Gennis}
3786b995818535af84c4a6829af7733684861f20144Jamie Gennis
3796b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void registerSigHandler() {
3806b995818535af84c4a6829af7733684861f20144Jamie Gennis    struct sigaction sa;
3816b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigemptyset(&sa.sa_mask);
3826b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_flags = 0;
3836b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_handler = handleSignal;
3846b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGHUP, &sa, NULL);
3856b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGINT, &sa, NULL);
3866b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGQUIT, &sa, NULL);
3876b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGTERM, &sa, NULL);
3886b995818535af84c4a6829af7733684861f20144Jamie Gennis}
3896b995818535af84c4a6829af7733684861f20144Jamie Gennis
3906b995818535af84c4a6829af7733684861f20144Jamie Gennisint main(int argc, char **argv)
3916b995818535af84c4a6829af7733684861f20144Jamie Gennis{
3926b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
3936b995818535af84c4a6829af7733684861f20144Jamie Gennis        showHelp(argv[0]);
3946b995818535af84c4a6829af7733684861f20144Jamie Gennis        exit(0);
3956b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
3966b995818535af84c4a6829af7733684861f20144Jamie Gennis
3976b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (getuid() != 0) {
3986b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error: %s must be run as root.", argv[0]);
399bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis        exit(1);
4006b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
4016b995818535af84c4a6829af7733684861f20144Jamie Gennis
4026b995818535af84c4a6829af7733684861f20144Jamie Gennis    for (;;) {
4036b995818535af84c4a6829af7733684861f20144Jamie Gennis        int ret;
4046b995818535af84c4a6829af7733684861f20144Jamie Gennis
40583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown        ret = getopt(argc, argv, "b:cidflst:wz");
4066b995818535af84c4a6829af7733684861f20144Jamie Gennis
4076b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ret < 0) {
4086b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4096b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
4106b995818535af84c4a6829af7733684861f20144Jamie Gennis
4116b995818535af84c4a6829af7733684861f20144Jamie Gennis        switch(ret) {
412bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'b':
413bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
414bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
415bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
4166b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'c':
4176b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceOverwrite = true;
4186b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4196b995818535af84c4a6829af7733684861f20144Jamie Gennis
420585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis            case 'i':
421585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis                g_traceCpuIdle = true;
422585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis            break;
423585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis
424bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'l':
425bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceGovernorLoad = true;
426bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
427bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
42883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown            case 'd':
42983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown                g_traceDisk = true;
43083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown            break;
43183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown
432bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'f':
433bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceCpuFrequency = true;
434bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
435bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
4366b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 's':
4376b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceSchedSwitch = true;
4386b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4396b995818535af84c4a6829af7733684861f20144Jamie Gennis
4406b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 't':
4416b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceDurationSeconds = atoi(optarg);
4426b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4436b995818535af84c4a6829af7733684861f20144Jamie Gennis
4446b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'w':
4456b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceWorkqueue = true;
4466b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4476b995818535af84c4a6829af7733684861f20144Jamie Gennis
448eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            case 'z':
449eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis                g_compress = true;
450eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis            break;
451eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis
4526b995818535af84c4a6829af7733684861f20144Jamie Gennis            default:
453bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                fprintf(stderr, "\n");
4546b995818535af84c4a6829af7733684861f20144Jamie Gennis                showHelp(argv[0]);
4556b995818535af84c4a6829af7733684861f20144Jamie Gennis                exit(-1);
4566b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
4576b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
4586b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
4596b995818535af84c4a6829af7733684861f20144Jamie Gennis
4606b995818535af84c4a6829af7733684861f20144Jamie Gennis    registerSigHandler();
4616b995818535af84c4a6829af7733684861f20144Jamie Gennis
4626b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = startTrace();
4636b995818535af84c4a6829af7733684861f20144Jamie Gennis
4646b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
4656b995818535af84c4a6829af7733684861f20144Jamie Gennis        printf("capturing trace...");
4666b995818535af84c4a6829af7733684861f20144Jamie Gennis        fflush(stdout);
4676b995818535af84c4a6829af7733684861f20144Jamie Gennis
4686b995818535af84c4a6829af7733684861f20144Jamie Gennis        // We clear the trace after starting it because tracing gets enabled for
4696b995818535af84c4a6829af7733684861f20144Jamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
4706b995818535af84c4a6829af7733684861f20144Jamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
4716b995818535af84c4a6829af7733684861f20144Jamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
4726b995818535af84c4a6829af7733684861f20144Jamie Gennis        // another.
4736b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = clearTrace();
4746b995818535af84c4a6829af7733684861f20144Jamie Gennis
4756b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ok) {
4766b995818535af84c4a6829af7733684861f20144Jamie Gennis            // Sleep to allow the trace to be captured.
4776b995818535af84c4a6829af7733684861f20144Jamie Gennis            struct timespec timeLeft;
4786b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
4796b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_nsec = 0;
4806b995818535af84c4a6829af7733684861f20144Jamie Gennis            do {
4816b995818535af84c4a6829af7733684861f20144Jamie Gennis                if (g_traceAborted) {
4826b995818535af84c4a6829af7733684861f20144Jamie Gennis                    break;
4836b995818535af84c4a6829af7733684861f20144Jamie Gennis                }
4846b995818535af84c4a6829af7733684861f20144Jamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
4856b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
4866b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
4876b995818535af84c4a6829af7733684861f20144Jamie Gennis
4886b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Stop the trace and restore the default settings.
4896b995818535af84c4a6829af7733684861f20144Jamie Gennis    stopTrace();
4906b995818535af84c4a6829af7733684861f20144Jamie Gennis
4916b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
4926b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (!g_traceAborted) {
4936b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf(" done\nTRACE:\n");
4946b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
4956b995818535af84c4a6829af7733684861f20144Jamie Gennis            dumpTrace();
4966b995818535af84c4a6829af7733684861f20144Jamie Gennis        } else {
4976b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf("\ntrace aborted.\n");
4986b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
4996b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
5006b995818535af84c4a6829af7733684861f20144Jamie Gennis        clearTrace();
5016b995818535af84c4a6829af7733684861f20144Jamie Gennis    } else {
5026b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "unable to start tracing\n");
5036b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
5046b995818535af84c4a6829af7733684861f20144Jamie Gennis
505bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // Reset the trace buffer size to 1.
506bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    setTraceBufferSizeKB(1);
507bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
5086b995818535af84c4a6829af7733684861f20144Jamie Gennis    return g_traceAborted ? 1 : 0;
5096b995818535af84c4a6829af7733684861f20144Jamie Gennis}
510