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