atrace.c revision 416fd36c9f7097a11ea610522ef8297d2b82d27b
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>
266b995818535af84c4a6829af7733684861f20144Jamie Gennis
276b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Command line options */
286b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic int g_traceDurationSeconds = 5;
296b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceSchedSwitch = false;
30bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool g_traceCpuFrequency = false;
31bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool g_traceGovernorLoad = false;
326b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceWorkqueue = false;
336b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceOverwrite = false;
34bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
356b995818535af84c4a6829af7733684861f20144Jamie Gennis
366b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Global state */
376b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceAborted = false;
386b995818535af84c4a6829af7733684861f20144Jamie Gennis
396b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Sys file paths */
406b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceClockPath =
416b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
426b995818535af84c4a6829af7733684861f20144Jamie Gennis
43bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_traceBufferSizePath =
44bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
45bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
466b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOverwriteEnablePath =
476b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
486b995818535af84c4a6829af7733684861f20144Jamie Gennis
496b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_schedSwitchEnablePath =
506b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
516b995818535af84c4a6829af7733684861f20144Jamie Gennis
52bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_cpuFreqEnablePath =
53bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
54bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
55bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_governorLoadEnablePath =
56bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
57bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
586b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_workqueueEnablePath =
596b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/events/workqueue/enable";
606b995818535af84c4a6829af7733684861f20144Jamie Gennis
616b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOnPath =
626b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
636b995818535af84c4a6829af7733684861f20144Jamie Gennis
646b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracePath =
656b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace";
666b995818535af84c4a6829af7733684861f20144Jamie Gennis
676b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceMarkerPath =
686b995818535af84c4a6829af7733684861f20144Jamie Gennis    "/sys/kernel/debug/tracing/trace_marker";
696b995818535af84c4a6829af7733684861f20144Jamie Gennis
706b995818535af84c4a6829af7733684861f20144Jamie Gennis// Write a string to a file, returning true if the write was successful.
716b995818535af84c4a6829af7733684861f20144Jamie Gennisbool writeStr(const char* filename, const char* str)
726b995818535af84c4a6829af7733684861f20144Jamie Gennis{
736b995818535af84c4a6829af7733684861f20144Jamie Gennis    int fd = open(filename, O_WRONLY);
746b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (fd == -1) {
756b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
766b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
776b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
786b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
796b995818535af84c4a6829af7733684861f20144Jamie Gennis
806b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
816b995818535af84c4a6829af7733684861f20144Jamie Gennis    ssize_t len = strlen(str);
826b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (write(fd, str, len) != len) {
836b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
846b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
856b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = false;
866b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
876b995818535af84c4a6829af7733684861f20144Jamie Gennis
886b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(fd);
896b995818535af84c4a6829af7733684861f20144Jamie Gennis
906b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
916b995818535af84c4a6829af7733684861f20144Jamie Gennis}
926b995818535af84c4a6829af7733684861f20144Jamie Gennis
936b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
946b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
956b995818535af84c4a6829af7733684861f20144Jamie Gennis{
966b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(filename, enable ? "1" : "0");
976b995818535af84c4a6829af7733684861f20144Jamie Gennis}
986b995818535af84c4a6829af7733684861f20144Jamie Gennis
996b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
1006b995818535af84c4a6829af7733684861f20144Jamie Gennis// will cause tracing to stop once the trace buffers have filled up.
1016b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
1026b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1036b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
1046b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1056b995818535af84c4a6829af7733684861f20144Jamie Gennis
1066b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel scheduler switching.
1076b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable)
1086b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1096b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_schedSwitchEnablePath, enable);
1106b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1116b995818535af84c4a6829af7733684861f20144Jamie Gennis
112bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the CPU clock frequency.
113bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setCpuFrequencyTracingEnable(bool enable)
114bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
115bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return setKernelOptionEnable(k_cpuFreqEnablePath, enable);
116bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
117bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
118bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of
119bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// the CPU load.
120bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable)
121bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
122bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return setKernelOptionEnable(k_governorLoadEnablePath, enable);
123bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
124bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
1256b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel workqueues.
1266b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable)
1276b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1286b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_workqueueEnablePath, enable);
1296b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1306b995818535af84c4a6829af7733684861f20144Jamie Gennis
1316b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable kernel tracing.
1326b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTracingEnabled(bool enable)
1336b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1346b995818535af84c4a6829af7733684861f20144Jamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
1356b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1366b995818535af84c4a6829af7733684861f20144Jamie Gennis
1376b995818535af84c4a6829af7733684861f20144Jamie Gennis// Clear the contents of the kernel trace.
1386b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool clearTrace()
1396b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1406b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = creat(k_tracePath, 0);
1416b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
1426b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
1436b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
1446b995818535af84c4a6829af7733684861f20144Jamie Gennis        return false;
1456b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1466b995818535af84c4a6829af7733684861f20144Jamie Gennis
1476b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
1486b995818535af84c4a6829af7733684861f20144Jamie Gennis
1496b995818535af84c4a6829af7733684861f20144Jamie Gennis    return true;
1506b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1516b995818535af84c4a6829af7733684861f20144Jamie Gennis
152bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
153bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
154bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{
155bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    char str[32] = "1";
156bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    int len;
157bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    if (size < 1) {
158bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis        size = 1;
159bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    }
160bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    snprintf(str, 32, "%d", size);
161bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
162bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis}
163bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
1646b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
1656b995818535af84c4a6829af7733684861f20144Jamie Gennis// clock will result in the kernel using a per-CPU local clock.
1666b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setGlobalClockEnable(bool enable)
1676b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1686b995818535af84c4a6829af7733684861f20144Jamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
1696b995818535af84c4a6829af7733684861f20144Jamie Gennis}
1706b995818535af84c4a6829af7733684861f20144Jamie Gennis
171416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis// Check whether a file exists.
172416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennisstatic bool fileExists(const char* filename) {
173416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    return access(filename, F_OK) != -1;
174416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis}
175416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis
1766b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable tracing in the kernel.
1776b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool startTrace()
1786b995818535af84c4a6829af7733684861f20144Jamie Gennis{
1796b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = true;
1806b995818535af84c4a6829af7733684861f20144Jamie Gennis
1816b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Set up the tracing options.
1826b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
1836b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
184bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    ok &= setCpuFrequencyTracingEnable(g_traceCpuFrequency);
185416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    if (fileExists(k_governorLoadEnablePath) || g_traceGovernorLoad) {
186416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis        ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
187416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    }
1886b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
189bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
1906b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setGlobalClockEnable(true);
1916b995818535af84c4a6829af7733684861f20144Jamie Gennis
1926b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Enable tracing.
1936b995818535af84c4a6829af7733684861f20144Jamie Gennis    ok &= setTracingEnabled(true);
1946b995818535af84c4a6829af7733684861f20144Jamie Gennis
1956b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (!ok) {
1966b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error: unable to start trace\n");
1976b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
1986b995818535af84c4a6829af7733684861f20144Jamie Gennis
1996b995818535af84c4a6829af7733684861f20144Jamie Gennis    return ok;
2006b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2016b995818535af84c4a6829af7733684861f20144Jamie Gennis
2026b995818535af84c4a6829af7733684861f20144Jamie Gennis// Disable tracing in the kernel.
2036b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void stopTrace()
2046b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2056b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Disable tracing.
2066b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTracingEnabled(false);
2076b995818535af84c4a6829af7733684861f20144Jamie Gennis
2086b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Set the options back to their defaults.
2096b995818535af84c4a6829af7733684861f20144Jamie Gennis    setTraceOverwriteEnable(true);
2106b995818535af84c4a6829af7733684861f20144Jamie Gennis    setSchedSwitchTracingEnable(false);
211bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    setCpuFrequencyTracingEnable(false);
212416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    if (fileExists(k_governorLoadEnablePath)) {
213416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis        setGovernorLoadTracingEnable(false);
214416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis    }
2156b995818535af84c4a6829af7733684861f20144Jamie Gennis    setWorkqueueTracingEnabled(false);
2166b995818535af84c4a6829af7733684861f20144Jamie Gennis    setGlobalClockEnable(false);
217bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
218bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
219bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // clear the trace before we've read it.
2206b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2216b995818535af84c4a6829af7733684861f20144Jamie Gennis
2226b995818535af84c4a6829af7733684861f20144Jamie Gennis// Read the current kernel trace and write it to stdout.
2236b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void dumpTrace()
2246b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2256b995818535af84c4a6829af7733684861f20144Jamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
2266b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (traceFD == -1) {
2276b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
2286b995818535af84c4a6829af7733684861f20144Jamie Gennis                strerror(errno), errno);
2296b995818535af84c4a6829af7733684861f20144Jamie Gennis        return;
2306b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2316b995818535af84c4a6829af7733684861f20144Jamie Gennis
2326b995818535af84c4a6829af7733684861f20144Jamie Gennis    ssize_t sent = 0;
2336b995818535af84c4a6829af7733684861f20144Jamie Gennis    while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
2346b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (sent == -1) {
2356b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
2366b995818535af84c4a6829af7733684861f20144Jamie Gennis                errno);
2376b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2386b995818535af84c4a6829af7733684861f20144Jamie Gennis
2396b995818535af84c4a6829af7733684861f20144Jamie Gennis    close(traceFD);
2406b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2416b995818535af84c4a6829af7733684861f20144Jamie Gennis
2426b995818535af84c4a6829af7733684861f20144Jamie Gennis// Print the command usage help to stderr.
2436b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void showHelp(const char *cmd)
2446b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2456b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "usage: %s [options]\n", cmd);
2466b995818535af84c4a6829af7733684861f20144Jamie Gennis    fprintf(stderr, "options include:\n"
247bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
2486b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -c              trace into a circular buffer\n"
249bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -f              trace CPU frequency changes\n"
250bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                    "  -l              trace CPU frequency governor load\n"
2516b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -s              trace the kernel scheduler switches\n"
2526b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
2536b995818535af84c4a6829af7733684861f20144Jamie Gennis                    "  -w              trace the kernel workqueue\n");
2546b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2556b995818535af84c4a6829af7733684861f20144Jamie Gennis
2566b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void handleSignal(int signo) {
2576b995818535af84c4a6829af7733684861f20144Jamie Gennis    g_traceAborted = true;
2586b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2596b995818535af84c4a6829af7733684861f20144Jamie Gennis
2606b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void registerSigHandler() {
2616b995818535af84c4a6829af7733684861f20144Jamie Gennis    struct sigaction sa;
2626b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigemptyset(&sa.sa_mask);
2636b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_flags = 0;
2646b995818535af84c4a6829af7733684861f20144Jamie Gennis    sa.sa_handler = handleSignal;
2656b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGHUP, &sa, NULL);
2666b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGINT, &sa, NULL);
2676b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGQUIT, &sa, NULL);
2686b995818535af84c4a6829af7733684861f20144Jamie Gennis    sigaction(SIGTERM, &sa, NULL);
2696b995818535af84c4a6829af7733684861f20144Jamie Gennis}
2706b995818535af84c4a6829af7733684861f20144Jamie Gennis
2716b995818535af84c4a6829af7733684861f20144Jamie Gennisint main(int argc, char **argv)
2726b995818535af84c4a6829af7733684861f20144Jamie Gennis{
2736b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
2746b995818535af84c4a6829af7733684861f20144Jamie Gennis        showHelp(argv[0]);
2756b995818535af84c4a6829af7733684861f20144Jamie Gennis        exit(0);
2766b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2776b995818535af84c4a6829af7733684861f20144Jamie Gennis
2786b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (getuid() != 0) {
2796b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "error: %s must be run as root.", argv[0]);
280bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis        exit(1);
2816b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
2826b995818535af84c4a6829af7733684861f20144Jamie Gennis
2836b995818535af84c4a6829af7733684861f20144Jamie Gennis    for (;;) {
2846b995818535af84c4a6829af7733684861f20144Jamie Gennis        int ret;
2856b995818535af84c4a6829af7733684861f20144Jamie Gennis
286bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis        ret = getopt(argc, argv, "b:cflst:w");
2876b995818535af84c4a6829af7733684861f20144Jamie Gennis
2886b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ret < 0) {
2896b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
2906b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
2916b995818535af84c4a6829af7733684861f20144Jamie Gennis
2926b995818535af84c4a6829af7733684861f20144Jamie Gennis        switch(ret) {
293bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'b':
294bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
295bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
296bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
2976b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'c':
2986b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceOverwrite = true;
2996b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
3006b995818535af84c4a6829af7733684861f20144Jamie Gennis
301bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'l':
302bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceGovernorLoad = true;
303bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
304bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
305bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            case 'f':
306bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                g_traceCpuFrequency = true;
307bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis            break;
308bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
3096b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 's':
3106b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceSchedSwitch = true;
3116b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
3126b995818535af84c4a6829af7733684861f20144Jamie Gennis
3136b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 't':
3146b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceDurationSeconds = atoi(optarg);
3156b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
3166b995818535af84c4a6829af7733684861f20144Jamie Gennis
3176b995818535af84c4a6829af7733684861f20144Jamie Gennis            case 'w':
3186b995818535af84c4a6829af7733684861f20144Jamie Gennis                g_traceWorkqueue = true;
3196b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
3206b995818535af84c4a6829af7733684861f20144Jamie Gennis
3216b995818535af84c4a6829af7733684861f20144Jamie Gennis            default:
322bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis                fprintf(stderr, "\n");
3236b995818535af84c4a6829af7733684861f20144Jamie Gennis                showHelp(argv[0]);
3246b995818535af84c4a6829af7733684861f20144Jamie Gennis                exit(-1);
3256b995818535af84c4a6829af7733684861f20144Jamie Gennis            break;
3266b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
3276b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
3286b995818535af84c4a6829af7733684861f20144Jamie Gennis
3296b995818535af84c4a6829af7733684861f20144Jamie Gennis    registerSigHandler();
3306b995818535af84c4a6829af7733684861f20144Jamie Gennis
3316b995818535af84c4a6829af7733684861f20144Jamie Gennis    bool ok = startTrace();
3326b995818535af84c4a6829af7733684861f20144Jamie Gennis
3336b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
3346b995818535af84c4a6829af7733684861f20144Jamie Gennis        printf("capturing trace...");
3356b995818535af84c4a6829af7733684861f20144Jamie Gennis        fflush(stdout);
3366b995818535af84c4a6829af7733684861f20144Jamie Gennis
3376b995818535af84c4a6829af7733684861f20144Jamie Gennis        // We clear the trace after starting it because tracing gets enabled for
3386b995818535af84c4a6829af7733684861f20144Jamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
3396b995818535af84c4a6829af7733684861f20144Jamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
3406b995818535af84c4a6829af7733684861f20144Jamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
3416b995818535af84c4a6829af7733684861f20144Jamie Gennis        // another.
3426b995818535af84c4a6829af7733684861f20144Jamie Gennis        ok = clearTrace();
3436b995818535af84c4a6829af7733684861f20144Jamie Gennis
3446b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (ok) {
3456b995818535af84c4a6829af7733684861f20144Jamie Gennis            // Sleep to allow the trace to be captured.
3466b995818535af84c4a6829af7733684861f20144Jamie Gennis            struct timespec timeLeft;
3476b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
3486b995818535af84c4a6829af7733684861f20144Jamie Gennis            timeLeft.tv_nsec = 0;
3496b995818535af84c4a6829af7733684861f20144Jamie Gennis            do {
3506b995818535af84c4a6829af7733684861f20144Jamie Gennis                if (g_traceAborted) {
3516b995818535af84c4a6829af7733684861f20144Jamie Gennis                    break;
3526b995818535af84c4a6829af7733684861f20144Jamie Gennis                }
3536b995818535af84c4a6829af7733684861f20144Jamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
3546b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
3556b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
3566b995818535af84c4a6829af7733684861f20144Jamie Gennis
3576b995818535af84c4a6829af7733684861f20144Jamie Gennis    // Stop the trace and restore the default settings.
3586b995818535af84c4a6829af7733684861f20144Jamie Gennis    stopTrace();
3596b995818535af84c4a6829af7733684861f20144Jamie Gennis
3606b995818535af84c4a6829af7733684861f20144Jamie Gennis    if (ok) {
3616b995818535af84c4a6829af7733684861f20144Jamie Gennis        if (!g_traceAborted) {
3626b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf(" done\nTRACE:\n");
3636b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
3646b995818535af84c4a6829af7733684861f20144Jamie Gennis            dumpTrace();
3656b995818535af84c4a6829af7733684861f20144Jamie Gennis        } else {
3666b995818535af84c4a6829af7733684861f20144Jamie Gennis            printf("\ntrace aborted.\n");
3676b995818535af84c4a6829af7733684861f20144Jamie Gennis            fflush(stdout);
3686b995818535af84c4a6829af7733684861f20144Jamie Gennis        }
3696b995818535af84c4a6829af7733684861f20144Jamie Gennis        clearTrace();
3706b995818535af84c4a6829af7733684861f20144Jamie Gennis    } else {
3716b995818535af84c4a6829af7733684861f20144Jamie Gennis        fprintf(stderr, "unable to start tracing\n");
3726b995818535af84c4a6829af7733684861f20144Jamie Gennis    }
3736b995818535af84c4a6829af7733684861f20144Jamie Gennis
374bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    // Reset the trace buffer size to 1.
375bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis    setTraceBufferSizeKB(1);
376bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis
3776b995818535af84c4a6829af7733684861f20144Jamie Gennis    return g_traceAborted ? 1 : 0;
3786b995818535af84c4a6829af7733684861f20144Jamie Gennis}
379