atrace.c revision a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9
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; 33a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool g_traceFrequency = false; 34a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool g_traceBusUtilization = false; 35585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic bool g_traceCpuIdle = false; 3683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool g_traceDisk = false; 37bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool g_traceGovernorLoad = false; 386b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceWorkqueue = false; 396b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceOverwrite = false; 40bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic int g_traceBufferSizeKB = 2048; 41eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennisstatic bool g_compress = false; 426b995818535af84c4a6829af7733684861f20144Jamie Gennis 436b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Global state */ 446b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceAborted = false; 456b995818535af84c4a6829af7733684861f20144Jamie Gennis 466b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Sys file paths */ 476b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceClockPath = 486b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/trace_clock"; 496b995818535af84c4a6829af7733684861f20144Jamie Gennis 50bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_traceBufferSizePath = 51bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis "/sys/kernel/debug/tracing/buffer_size_kb"; 52bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 536b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOverwriteEnablePath = 546b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/options/overwrite"; 556b995818535af84c4a6829af7733684861f20144Jamie Gennis 566b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_schedSwitchEnablePath = 576b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_switch/enable"; 586b995818535af84c4a6829af7733684861f20144Jamie Gennis 59b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic const char* k_schedWakeupEnablePath = 60b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable"; 61b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis 62a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic const char* k_memoryBusEnablePath = 63a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling "/sys/kernel/debug/tracing/events/memory_bus/enable"; 64a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling 65bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_cpuFreqEnablePath = 66bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable"; 67bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 68a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic const char *k_clockSetRateEnablePath = 69a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable"; 70a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling 71585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic const char* k_cpuIdleEnablePath = 72585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_idle/enable"; 73585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis 74bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_governorLoadEnablePath = 75bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable"; 76bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 776b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_workqueueEnablePath = 786b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/events/workqueue/enable"; 796b995818535af84c4a6829af7733684861f20144Jamie Gennis 8083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic const char* k_diskEnablePaths[] = { 8183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable", 8283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable", 8383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable", 8483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable", 8583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown}; 8683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown 876b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOnPath = 886b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/tracing_on"; 896b995818535af84c4a6829af7733684861f20144Jamie Gennis 906b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracePath = 916b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/trace"; 926b995818535af84c4a6829af7733684861f20144Jamie Gennis 936b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceMarkerPath = 946b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/trace_marker"; 956b995818535af84c4a6829af7733684861f20144Jamie Gennis 966b995818535af84c4a6829af7733684861f20144Jamie Gennis// Write a string to a file, returning true if the write was successful. 976b995818535af84c4a6829af7733684861f20144Jamie Gennisbool writeStr(const char* filename, const char* str) 986b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 996b995818535af84c4a6829af7733684861f20144Jamie Gennis int fd = open(filename, O_WRONLY); 1006b995818535af84c4a6829af7733684861f20144Jamie Gennis if (fd == -1) { 1016b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", filename, 1026b995818535af84c4a6829af7733684861f20144Jamie Gennis strerror(errno), errno); 1036b995818535af84c4a6829af7733684861f20144Jamie Gennis return false; 1046b995818535af84c4a6829af7733684861f20144Jamie Gennis } 1056b995818535af84c4a6829af7733684861f20144Jamie Gennis 1066b995818535af84c4a6829af7733684861f20144Jamie Gennis bool ok = true; 1076b995818535af84c4a6829af7733684861f20144Jamie Gennis ssize_t len = strlen(str); 1086b995818535af84c4a6829af7733684861f20144Jamie Gennis if (write(fd, str, len) != len) { 1096b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "error writing to %s: %s (%d)\n", filename, 1106b995818535af84c4a6829af7733684861f20144Jamie Gennis strerror(errno), errno); 1116b995818535af84c4a6829af7733684861f20144Jamie Gennis ok = false; 1126b995818535af84c4a6829af7733684861f20144Jamie Gennis } 1136b995818535af84c4a6829af7733684861f20144Jamie Gennis 1146b995818535af84c4a6829af7733684861f20144Jamie Gennis close(fd); 1156b995818535af84c4a6829af7733684861f20144Jamie Gennis 1166b995818535af84c4a6829af7733684861f20144Jamie Gennis return ok; 1176b995818535af84c4a6829af7733684861f20144Jamie Gennis} 1186b995818535af84c4a6829af7733684861f20144Jamie Gennis 1196b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file. 1206b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable) 1216b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 1226b995818535af84c4a6829af7733684861f20144Jamie Gennis return writeStr(filename, enable ? "1" : "0"); 1236b995818535af84c4a6829af7733684861f20144Jamie Gennis} 1246b995818535af84c4a6829af7733684861f20144Jamie Gennis 12583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file. 12683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable) 12783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{ 12883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown bool result = true; 12983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown for (size_t i = 0; i < count; i++) { 13083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown result &= setKernelOptionEnable(filenames[i], enable); 13183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown } 13283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown return result; 13383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown} 13483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown 1356b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable overwriting of the kernel trace buffers. Disabling this 1366b995818535af84c4a6829af7733684861f20144Jamie Gennis// will cause tracing to stop once the trace buffers have filled up. 1376b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTraceOverwriteEnable(bool enable) 1386b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 1396b995818535af84c4a6829af7733684861f20144Jamie Gennis return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable); 1406b995818535af84c4a6829af7733684861f20144Jamie Gennis} 1416b995818535af84c4a6829af7733684861f20144Jamie Gennis 1426b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel scheduler switching. 1436b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable) 1446b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 145b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis bool ok = true; 146b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable); 147b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable); 148b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis return ok; 1496b995818535af84c4a6829af7733684861f20144Jamie Gennis} 1506b995818535af84c4a6829af7733684861f20144Jamie Gennis 151a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling// Enable or disable tracing of the Bus utilization. 152a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool setBusUtilizationTracingEnable(bool enable) 153a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling{ 154a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling bool ok = false; 155a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling // these can be platform specific so make sure that at least 156a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling // one succeeds. 157a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling ok |= setKernelOptionEnable(k_memoryBusEnablePath, enable); 158a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling return ok; 159a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling} 160a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling 161bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the CPU clock frequency. 162a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool setFrequencyTracingEnable(bool enable) 163bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{ 164a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling bool ok = true; 165a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable); 166a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable); 167a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling return ok; 168bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis} 169bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 170585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis// Enable or disable tracing of CPU idle events. 171585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic bool setCpuIdleTracingEnable(bool enable) 172585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis{ 173585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis return setKernelOptionEnable(k_cpuIdleEnablePath, enable); 174585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis} 175585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis 176bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of 177bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// the CPU load. 178bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable) 179bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{ 180bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis return setKernelOptionEnable(k_governorLoadEnablePath, enable); 181bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis} 182bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 1836b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel workqueues. 1846b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable) 1856b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 1866b995818535af84c4a6829af7733684861f20144Jamie Gennis return setKernelOptionEnable(k_workqueueEnablePath, enable); 1876b995818535af84c4a6829af7733684861f20144Jamie Gennis} 1886b995818535af84c4a6829af7733684861f20144Jamie Gennis 18983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable tracing of disk I/O. 19083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setDiskTracingEnabled(bool enable) 19183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{ 19283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable); 19383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown} 19483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown 1956b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable kernel tracing. 1966b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTracingEnabled(bool enable) 1976b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 1986b995818535af84c4a6829af7733684861f20144Jamie Gennis return setKernelOptionEnable(k_tracingOnPath, enable); 1996b995818535af84c4a6829af7733684861f20144Jamie Gennis} 2006b995818535af84c4a6829af7733684861f20144Jamie Gennis 2016b995818535af84c4a6829af7733684861f20144Jamie Gennis// Clear the contents of the kernel trace. 2026b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool clearTrace() 2036b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 2046b995818535af84c4a6829af7733684861f20144Jamie Gennis int traceFD = creat(k_tracePath, 0); 2056b995818535af84c4a6829af7733684861f20144Jamie Gennis if (traceFD == -1) { 2066b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath, 2076b995818535af84c4a6829af7733684861f20144Jamie Gennis strerror(errno), errno); 2086b995818535af84c4a6829af7733684861f20144Jamie Gennis return false; 2096b995818535af84c4a6829af7733684861f20144Jamie Gennis } 2106b995818535af84c4a6829af7733684861f20144Jamie Gennis 2116b995818535af84c4a6829af7733684861f20144Jamie Gennis close(traceFD); 2126b995818535af84c4a6829af7733684861f20144Jamie Gennis 2136b995818535af84c4a6829af7733684861f20144Jamie Gennis return true; 2146b995818535af84c4a6829af7733684861f20144Jamie Gennis} 2156b995818535af84c4a6829af7733684861f20144Jamie Gennis 216bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes. 217bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setTraceBufferSizeKB(int size) 218bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{ 219bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis char str[32] = "1"; 220bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis int len; 221bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis if (size < 1) { 222bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis size = 1; 223bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis } 224bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis snprintf(str, 32, "%d", size); 225bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis return writeStr(k_traceBufferSizePath, str); 226bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis} 227bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 2286b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable the kernel's use of the global clock. Disabling the global 2296b995818535af84c4a6829af7733684861f20144Jamie Gennis// clock will result in the kernel using a per-CPU local clock. 2306b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setGlobalClockEnable(bool enable) 2316b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 2326b995818535af84c4a6829af7733684861f20144Jamie Gennis return writeStr(k_traceClockPath, enable ? "global" : "local"); 2336b995818535af84c4a6829af7733684861f20144Jamie Gennis} 2346b995818535af84c4a6829af7733684861f20144Jamie Gennis 235416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis// Check whether a file exists. 236416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennisstatic bool fileExists(const char* filename) { 237416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis return access(filename, F_OK) != -1; 238416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis} 239416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis 2406b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable tracing in the kernel. 241b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic bool startTrace(bool isRoot) 2426b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 2436b995818535af84c4a6829af7733684861f20144Jamie Gennis bool ok = true; 2446b995818535af84c4a6829af7733684861f20144Jamie Gennis 245b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis // Set up the tracing options that don't require root. 2466b995818535af84c4a6829af7733684861f20144Jamie Gennis ok &= setTraceOverwriteEnable(g_traceOverwrite); 2476b995818535af84c4a6829af7733684861f20144Jamie Gennis ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch); 248a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling ok &= setBusUtilizationTracingEnable(g_traceBusUtilization); 249a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling ok &= setFrequencyTracingEnable(g_traceFrequency); 250585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis ok &= setCpuIdleTracingEnable(g_traceCpuIdle); 251416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis if (fileExists(k_governorLoadEnablePath) || g_traceGovernorLoad) { 252416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad); 253416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis } 254bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis ok &= setTraceBufferSizeKB(g_traceBufferSizeKB); 2556b995818535af84c4a6829af7733684861f20144Jamie Gennis ok &= setGlobalClockEnable(true); 2566b995818535af84c4a6829af7733684861f20144Jamie Gennis 257b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis // Set up the tracing options that do require root. The options that 258b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis // require root should have errored out earlier if we're not running as 259b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis // root. 260b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis if (isRoot) { 261b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis ok &= setWorkqueueTracingEnabled(g_traceWorkqueue); 262b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis ok &= setDiskTracingEnabled(g_traceDisk); 263b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis } 264b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis 2656b995818535af84c4a6829af7733684861f20144Jamie Gennis // Enable tracing. 2666b995818535af84c4a6829af7733684861f20144Jamie Gennis ok &= setTracingEnabled(true); 2676b995818535af84c4a6829af7733684861f20144Jamie Gennis 2686b995818535af84c4a6829af7733684861f20144Jamie Gennis if (!ok) { 2696b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "error: unable to start trace\n"); 2706b995818535af84c4a6829af7733684861f20144Jamie Gennis } 2716b995818535af84c4a6829af7733684861f20144Jamie Gennis 2726b995818535af84c4a6829af7733684861f20144Jamie Gennis return ok; 2736b995818535af84c4a6829af7733684861f20144Jamie Gennis} 2746b995818535af84c4a6829af7733684861f20144Jamie Gennis 2756b995818535af84c4a6829af7733684861f20144Jamie Gennis// Disable tracing in the kernel. 276b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic void stopTrace(bool isRoot) 2776b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 2786b995818535af84c4a6829af7733684861f20144Jamie Gennis // Disable tracing. 2796b995818535af84c4a6829af7733684861f20144Jamie Gennis setTracingEnabled(false); 2806b995818535af84c4a6829af7733684861f20144Jamie Gennis 2816b995818535af84c4a6829af7733684861f20144Jamie Gennis // Set the options back to their defaults. 2826b995818535af84c4a6829af7733684861f20144Jamie Gennis setTraceOverwriteEnable(true); 2836b995818535af84c4a6829af7733684861f20144Jamie Gennis setSchedSwitchTracingEnable(false); 284a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling setBusUtilizationTracingEnable(false); 285a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling setFrequencyTracingEnable(false); 286416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis if (fileExists(k_governorLoadEnablePath)) { 287416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis setGovernorLoadTracingEnable(false); 288416fd36c9f7097a11ea610522ef8297d2b82d27bJamie Gennis } 2896b995818535af84c4a6829af7733684861f20144Jamie Gennis setGlobalClockEnable(false); 290bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 291b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis if (isRoot) { 292b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis setWorkqueueTracingEnabled(false); 293b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis setDiskTracingEnabled(false); 294b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis } 295b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis 296bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis // Note that we can't reset the trace buffer size here because that would 297bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis // clear the trace before we've read it. 2986b995818535af84c4a6829af7733684861f20144Jamie Gennis} 2996b995818535af84c4a6829af7733684861f20144Jamie Gennis 3006b995818535af84c4a6829af7733684861f20144Jamie Gennis// Read the current kernel trace and write it to stdout. 3016b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void dumpTrace() 3026b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 3036b995818535af84c4a6829af7733684861f20144Jamie Gennis int traceFD = open(k_tracePath, O_RDWR); 3046b995818535af84c4a6829af7733684861f20144Jamie Gennis if (traceFD == -1) { 3056b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath, 3066b995818535af84c4a6829af7733684861f20144Jamie Gennis strerror(errno), errno); 3076b995818535af84c4a6829af7733684861f20144Jamie Gennis return; 3086b995818535af84c4a6829af7733684861f20144Jamie Gennis } 3096b995818535af84c4a6829af7733684861f20144Jamie Gennis 310eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (g_compress) { 311eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis z_stream zs; 312eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis uint8_t *in, *out; 313eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis int result, flush; 314eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 315eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis bzero(&zs, sizeof(zs)); 316eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = deflateInit(&zs, Z_DEFAULT_COMPRESSION); 317eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (result != Z_OK) { 318eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error initializing zlib: %d\n", result); 319eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis close(traceFD); 320eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis return; 321eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 322eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 323eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis const size_t bufSize = 64*1024; 324eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis in = (uint8_t*)malloc(bufSize); 325eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis out = (uint8_t*)malloc(bufSize); 326eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis flush = Z_NO_FLUSH; 327eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 328eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.next_out = out; 329eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.avail_out = bufSize; 330eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 331eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis do { 332eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 333eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (zs.avail_in == 0) { 334eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis // More input is needed. 335eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = read(traceFD, in, bufSize); 336eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (result < 0) { 337eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error reading trace: %s (%d)\n", 338eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis strerror(errno), errno); 339eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = Z_STREAM_END; 340eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis break; 341eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } else if (result == 0) { 342eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis flush = Z_FINISH; 343eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } else { 344eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.next_in = in; 345eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.avail_in = result; 346eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 347eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 348eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 349eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (zs.avail_out == 0) { 350eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis // Need to write the output. 351eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = write(STDOUT_FILENO, out, bufSize); 352eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if ((size_t)result < bufSize) { 353eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 354eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis strerror(errno), errno); 355eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = Z_STREAM_END; // skip deflate error message 356eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.avail_out = bufSize; // skip the final write 357eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis break; 358eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 359eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.next_out = out; 360eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.avail_out = bufSize; 361eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 362eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 363eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } while ((result = deflate(&zs, flush)) == Z_OK); 364eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 365eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (result != Z_STREAM_END) { 366eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error deflating trace: %s\n", zs.msg); 367eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 368eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 369eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (zs.avail_out < bufSize) { 370eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis size_t bytes = bufSize - zs.avail_out; 371eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = write(STDOUT_FILENO, out, bytes); 372eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if ((size_t)result < bytes) { 373eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 374eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis strerror(errno), errno); 375eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 376eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 377eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 378eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = deflateEnd(&zs); 379eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (result != Z_OK) { 380eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error cleaning up zlib: %d\n", result); 381eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 382eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 383eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis free(in); 384eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis free(out); 385eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } else { 386eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis ssize_t sent = 0; 387eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0); 388eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (sent == -1) { 389eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno), 390eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis errno); 391eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 3926b995818535af84c4a6829af7733684861f20144Jamie Gennis } 3936b995818535af84c4a6829af7733684861f20144Jamie Gennis 3946b995818535af84c4a6829af7733684861f20144Jamie Gennis close(traceFD); 3956b995818535af84c4a6829af7733684861f20144Jamie Gennis} 3966b995818535af84c4a6829af7733684861f20144Jamie Gennis 3976b995818535af84c4a6829af7733684861f20144Jamie Gennis// Print the command usage help to stderr. 3986b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void showHelp(const char *cmd) 3996b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 4006b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "usage: %s [options]\n", cmd); 4016b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "options include:\n" 402bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis " -b N use a trace buffer size of N KB\n" 4036b995818535af84c4a6829af7733684861f20144Jamie Gennis " -c trace into a circular buffer\n" 40483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown " -d trace disk I/O\n" 405a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling " -f trace clock frequency changes\n" 406bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis " -l trace CPU frequency governor load\n" 4076b995818535af84c4a6829af7733684861f20144Jamie Gennis " -s trace the kernel scheduler switches\n" 4086b995818535af84c4a6829af7733684861f20144Jamie Gennis " -t N trace for N seconds [defualt 5]\n" 409a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling " -u trace bus utilization\n" 410eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis " -w trace the kernel workqueue\n" 411eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis " -z compress the trace dump\n"); 4126b995818535af84c4a6829af7733684861f20144Jamie Gennis} 4136b995818535af84c4a6829af7733684861f20144Jamie Gennis 4146b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void handleSignal(int signo) { 4156b995818535af84c4a6829af7733684861f20144Jamie Gennis g_traceAborted = true; 4166b995818535af84c4a6829af7733684861f20144Jamie Gennis} 4176b995818535af84c4a6829af7733684861f20144Jamie Gennis 4186b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void registerSigHandler() { 4196b995818535af84c4a6829af7733684861f20144Jamie Gennis struct sigaction sa; 4206b995818535af84c4a6829af7733684861f20144Jamie Gennis sigemptyset(&sa.sa_mask); 4216b995818535af84c4a6829af7733684861f20144Jamie Gennis sa.sa_flags = 0; 4226b995818535af84c4a6829af7733684861f20144Jamie Gennis sa.sa_handler = handleSignal; 4236b995818535af84c4a6829af7733684861f20144Jamie Gennis sigaction(SIGHUP, &sa, NULL); 4246b995818535af84c4a6829af7733684861f20144Jamie Gennis sigaction(SIGINT, &sa, NULL); 4256b995818535af84c4a6829af7733684861f20144Jamie Gennis sigaction(SIGQUIT, &sa, NULL); 4266b995818535af84c4a6829af7733684861f20144Jamie Gennis sigaction(SIGTERM, &sa, NULL); 4276b995818535af84c4a6829af7733684861f20144Jamie Gennis} 4286b995818535af84c4a6829af7733684861f20144Jamie Gennis 4296b995818535af84c4a6829af7733684861f20144Jamie Gennisint main(int argc, char **argv) 4306b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 431b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis bool isRoot = (getuid() == 0); 432b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis 4336b995818535af84c4a6829af7733684861f20144Jamie Gennis if (argc == 2 && 0 == strcmp(argv[1], "--help")) { 4346b995818535af84c4a6829af7733684861f20144Jamie Gennis showHelp(argv[0]); 4356b995818535af84c4a6829af7733684861f20144Jamie Gennis exit(0); 4366b995818535af84c4a6829af7733684861f20144Jamie Gennis } 4376b995818535af84c4a6829af7733684861f20144Jamie Gennis 4386b995818535af84c4a6829af7733684861f20144Jamie Gennis for (;;) { 4396b995818535af84c4a6829af7733684861f20144Jamie Gennis int ret; 4406b995818535af84c4a6829af7733684861f20144Jamie Gennis 441a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling ret = getopt(argc, argv, "b:cidflst:uwz"); 4426b995818535af84c4a6829af7733684861f20144Jamie Gennis 4436b995818535af84c4a6829af7733684861f20144Jamie Gennis if (ret < 0) { 4446b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 4456b995818535af84c4a6829af7733684861f20144Jamie Gennis } 4466b995818535af84c4a6829af7733684861f20144Jamie Gennis 4476b995818535af84c4a6829af7733684861f20144Jamie Gennis switch(ret) { 448bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis case 'b': 449bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis g_traceBufferSizeKB = atoi(optarg); 450bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis break; 451bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 4526b995818535af84c4a6829af7733684861f20144Jamie Gennis case 'c': 4536b995818535af84c4a6829af7733684861f20144Jamie Gennis g_traceOverwrite = true; 4546b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 4556b995818535af84c4a6829af7733684861f20144Jamie Gennis 456585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis case 'i': 457585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis g_traceCpuIdle = true; 458585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis break; 459585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis 460bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis case 'l': 461bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis g_traceGovernorLoad = true; 462bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis break; 463bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 46483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown case 'd': 465b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis if (!isRoot) { 466b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis fprintf(stderr, "error: tracing disk activity requires root privileges\n"); 467b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis exit(1); 468b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis } 46983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown g_traceDisk = true; 47083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown break; 47183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown 472bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis case 'f': 473a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling g_traceFrequency = true; 474bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis break; 475bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 4766b995818535af84c4a6829af7733684861f20144Jamie Gennis case 's': 4776b995818535af84c4a6829af7733684861f20144Jamie Gennis g_traceSchedSwitch = true; 4786b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 4796b995818535af84c4a6829af7733684861f20144Jamie Gennis 4806b995818535af84c4a6829af7733684861f20144Jamie Gennis case 't': 4816b995818535af84c4a6829af7733684861f20144Jamie Gennis g_traceDurationSeconds = atoi(optarg); 4826b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 4836b995818535af84c4a6829af7733684861f20144Jamie Gennis 484a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling case 'u': 485a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling if (!isRoot) { 486a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling fprintf(stderr, "error: tracing bus utilization requires root privileges\n"); 487a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling exit(1); 488a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling } 489a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling g_traceBusUtilization = true; 490a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling break; 491a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling 4926b995818535af84c4a6829af7733684861f20144Jamie Gennis case 'w': 493b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis if (!isRoot) { 494b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis fprintf(stderr, "error: tracing kernel work queues requires root privileges\n"); 495b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis exit(1); 496b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis } 4976b995818535af84c4a6829af7733684861f20144Jamie Gennis g_traceWorkqueue = true; 4986b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 4996b995818535af84c4a6829af7733684861f20144Jamie Gennis 500eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis case 'z': 501eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis g_compress = true; 502eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis break; 503eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 5046b995818535af84c4a6829af7733684861f20144Jamie Gennis default: 505bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis fprintf(stderr, "\n"); 5066b995818535af84c4a6829af7733684861f20144Jamie Gennis showHelp(argv[0]); 5076b995818535af84c4a6829af7733684861f20144Jamie Gennis exit(-1); 5086b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 5096b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5106b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5116b995818535af84c4a6829af7733684861f20144Jamie Gennis 5126b995818535af84c4a6829af7733684861f20144Jamie Gennis registerSigHandler(); 5136b995818535af84c4a6829af7733684861f20144Jamie Gennis 514b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis bool ok = startTrace(isRoot); 5156b995818535af84c4a6829af7733684861f20144Jamie Gennis 5166b995818535af84c4a6829af7733684861f20144Jamie Gennis if (ok) { 5176b995818535af84c4a6829af7733684861f20144Jamie Gennis printf("capturing trace..."); 5186b995818535af84c4a6829af7733684861f20144Jamie Gennis fflush(stdout); 5196b995818535af84c4a6829af7733684861f20144Jamie Gennis 5206b995818535af84c4a6829af7733684861f20144Jamie Gennis // We clear the trace after starting it because tracing gets enabled for 5216b995818535af84c4a6829af7733684861f20144Jamie Gennis // each CPU individually in the kernel. Having the beginning of the trace 5226b995818535af84c4a6829af7733684861f20144Jamie Gennis // contain entries from only one CPU can cause "begin" entries without a 5236b995818535af84c4a6829af7733684861f20144Jamie Gennis // matching "end" entry to show up if a task gets migrated from one CPU to 5246b995818535af84c4a6829af7733684861f20144Jamie Gennis // another. 5256b995818535af84c4a6829af7733684861f20144Jamie Gennis ok = clearTrace(); 5266b995818535af84c4a6829af7733684861f20144Jamie Gennis 5276b995818535af84c4a6829af7733684861f20144Jamie Gennis if (ok) { 5286b995818535af84c4a6829af7733684861f20144Jamie Gennis // Sleep to allow the trace to be captured. 5296b995818535af84c4a6829af7733684861f20144Jamie Gennis struct timespec timeLeft; 5306b995818535af84c4a6829af7733684861f20144Jamie Gennis timeLeft.tv_sec = g_traceDurationSeconds; 5316b995818535af84c4a6829af7733684861f20144Jamie Gennis timeLeft.tv_nsec = 0; 5326b995818535af84c4a6829af7733684861f20144Jamie Gennis do { 5336b995818535af84c4a6829af7733684861f20144Jamie Gennis if (g_traceAborted) { 5346b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 5356b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5366b995818535af84c4a6829af7733684861f20144Jamie Gennis } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR); 5376b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5386b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5396b995818535af84c4a6829af7733684861f20144Jamie Gennis 5406b995818535af84c4a6829af7733684861f20144Jamie Gennis // Stop the trace and restore the default settings. 541b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis stopTrace(isRoot); 5426b995818535af84c4a6829af7733684861f20144Jamie Gennis 5436b995818535af84c4a6829af7733684861f20144Jamie Gennis if (ok) { 5446b995818535af84c4a6829af7733684861f20144Jamie Gennis if (!g_traceAborted) { 5456b995818535af84c4a6829af7733684861f20144Jamie Gennis printf(" done\nTRACE:\n"); 5466b995818535af84c4a6829af7733684861f20144Jamie Gennis fflush(stdout); 5476b995818535af84c4a6829af7733684861f20144Jamie Gennis dumpTrace(); 5486b995818535af84c4a6829af7733684861f20144Jamie Gennis } else { 5496b995818535af84c4a6829af7733684861f20144Jamie Gennis printf("\ntrace aborted.\n"); 5506b995818535af84c4a6829af7733684861f20144Jamie Gennis fflush(stdout); 5516b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5526b995818535af84c4a6829af7733684861f20144Jamie Gennis clearTrace(); 5536b995818535af84c4a6829af7733684861f20144Jamie Gennis } else { 5546b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "unable to start tracing\n"); 5556b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5566b995818535af84c4a6829af7733684861f20144Jamie Gennis 557bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis // Reset the trace buffer size to 1. 558bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis setTraceBufferSizeKB(1); 559bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 5606b995818535af84c4a6829af7733684861f20144Jamie Gennis return g_traceAborted ? 1 : 0; 5616b995818535af84c4a6829af7733684861f20144Jamie Gennis} 562