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