atrace.cpp revision 31be80f02cddda55e75614884038fa4645b694cd
1fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* 2fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Copyright (C) 2012 The Android Open Source Project 3fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * 4fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Licensed under the Apache License, Version 2.0 (the "License"); 5fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * you may not use this file except in compliance with the License. 6fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * You may obtain a copy of the License at 7fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * 8fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * http://www.apache.org/licenses/LICENSE-2.0 9fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * 10fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Unless required by applicable law or agreed to in writing, software 11fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * distributed under the License is distributed on an "AS IS" BASIS, 12fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * See the License for the specific language governing permissions and 14fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * limitations under the License. 15fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis */ 16fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 17fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <errno.h> 18fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <fcntl.h> 19fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <signal.h> 20fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdarg.h> 21fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdbool.h> 22fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdio.h> 23fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdlib.h> 24fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <sys/sendfile.h> 25fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <time.h> 267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis#include <zlib.h> 27fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 28ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) 29ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 30fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Command line options */ 31fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic int g_traceDurationSeconds = 5; 32fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceSchedSwitch = false; 3399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool g_traceFrequency = false; 3499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool g_traceBusUtilization = false; 353169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool g_traceCpuIdle = false; 36ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool g_traceDisk = false; 37cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool g_traceGovernorLoad = false; 38fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceWorkqueue = false; 39fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false; 40cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048; 417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false; 4231be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic bool g_nohup = false; 4331be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic int g_initialSleepSecs = 0; 44fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 45fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */ 46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false; 47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */ 49fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath = 50fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace_clock"; 51fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 52cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath = 53cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/buffer_size_kb"; 54cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 55fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath = 56fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/options/overwrite"; 57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 58fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath = 59fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_switch/enable"; 60fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 614b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic const char* k_schedWakeupEnablePath = 624b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable"; 634b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 6499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char* k_memoryBusEnablePath = 6599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling "/sys/kernel/debug/tracing/events/memory_bus/enable"; 6699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 67cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_cpuFreqEnablePath = 68cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable"; 69cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 7099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char *k_clockSetRateEnablePath = 7199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable"; 7299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 733169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic const char* k_cpuIdleEnablePath = 743169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_idle/enable"; 753169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 76cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_governorLoadEnablePath = 77cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable"; 78cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 79fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath = 80fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/events/workqueue/enable"; 81fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 82ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic const char* k_diskEnablePaths[] = { 83ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable", 84ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable", 85ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable", 86ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable", 87ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}; 88ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 89fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath = 90fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/tracing_on"; 91fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 92fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath = 93fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace"; 94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath = 96fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace_marker"; 97fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 98e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists. 99e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) { 100e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return access(filename, F_OK) != -1; 101e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis} 102e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis 103fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful. 104fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str) 105fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 106fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int fd = open(filename, O_WRONLY); 107fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (fd == -1) { 108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", filename, 109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return false; 111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = true; 114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ssize_t len = strlen(str); 115fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (write(fd, str, len) != len) { 116fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error writing to %s: %s (%d)\n", filename, 117fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 118fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok = false; 119fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 120fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 121fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(fd); 122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return ok; 124fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file. 127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable) 128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return writeStr(filename, enable ? "1" : "0"); 130fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 131fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 132ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file. 133ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable) 134ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{ 135ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown bool result = true; 136ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown for (size_t i = 0; i < count; i++) { 137ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown result &= setKernelOptionEnable(filenames[i], enable); 138ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown } 139ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown return result; 140ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown} 141ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 142fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers. Disabling this 143fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up. 144fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable) 145fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 146fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable); 147fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 148fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching. 150fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable) 151fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 1524b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool ok = true; 1534b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable); 1544b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable); 1554b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis return ok; 156fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 157fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 15899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling// Enable or disable tracing of the Bus utilization. 15999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setBusUtilizationTracingEnable(bool enable) 16099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling{ 161e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis bool ok = true, oneSet = false; 16299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling // these can be platform specific so make sure that at least 16399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling // one succeeds. 164e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_memoryBusEnablePath)) { 165e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable); 166e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis oneSet |= ok; 167e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 168e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return ok && (oneSet || !enable); 16999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling} 17099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 171cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the CPU clock frequency. 17299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setFrequencyTracingEnable(bool enable) 173cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 17499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling bool ok = true; 17599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable); 176e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_clockSetRateEnablePath)) { 177e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable); 178e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 17999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling return ok; 180cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 181cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 1823169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis// Enable or disable tracing of CPU idle events. 1833169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool setCpuIdleTracingEnable(bool enable) 1843169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{ 1853169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis return setKernelOptionEnable(k_cpuIdleEnablePath, enable); 1863169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis} 1873169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 188cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of 189cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// the CPU load. 190cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable) 191cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 192e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis bool ok = true; 193e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_governorLoadEnablePath) || enable) { 194e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable); 195e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 196e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return ok; 197cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 198cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 199fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues. 200fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable) 201fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 202fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_workqueueEnablePath, enable); 203fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 204fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 205ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable tracing of disk I/O. 206ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setDiskTracingEnabled(bool enable) 207ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{ 208ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable); 209ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown} 210ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 211fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing. 212fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable) 213fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_tracingOnPath, enable); 215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace. 218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace() 219fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 220fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int traceFD = creat(k_tracePath, 0); 221fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (traceFD == -1) { 222fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath, 223fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 224fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return false; 225fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 226fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(traceFD); 228fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 229fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return true; 230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 232cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes. 233cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size) 234cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 235cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis char str[32] = "1"; 236cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis int len; 237cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis if (size < 1) { 238cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis size = 1; 239cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis } 240cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis snprintf(str, 32, "%d", size); 241cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis return writeStr(k_traceBufferSizePath, str); 242cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 243cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock. Disabling the global 245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock. 246fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable) 247fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 248fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return writeStr(k_traceClockPath, enable ? "global" : "local"); 249fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 250fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 251fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel. 2524b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic bool startTrace(bool isRoot) 253fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 254fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = true; 255fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 2564b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // Set up the tracing options that don't require root. 257fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setTraceOverwriteEnable(g_traceOverwrite); 258fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch); 25999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling ok &= setFrequencyTracingEnable(g_traceFrequency); 2603169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis ok &= setCpuIdleTracingEnable(g_traceCpuIdle); 261e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad); 262cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis ok &= setTraceBufferSizeKB(g_traceBufferSizeKB); 263fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setGlobalClockEnable(true); 264fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 2654b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // Set up the tracing options that do require root. The options that 2664b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // require root should have errored out earlier if we're not running as 2674b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // root. 2684b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (isRoot) { 269e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setBusUtilizationTracingEnable(g_traceBusUtilization); 2704b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setWorkqueueTracingEnabled(g_traceWorkqueue); 2714b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setDiskTracingEnabled(g_traceDisk); 2724b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 2734b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 274fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Enable tracing. 275fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setTracingEnabled(true); 276fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 277fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (!ok) { 278fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error: unable to start trace\n"); 279fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 280fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 281fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return ok; 282fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 283fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 284fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel. 2854b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic void stopTrace(bool isRoot) 286fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 287fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Disable tracing. 288fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setTracingEnabled(false); 289fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 290fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Set the options back to their defaults. 291fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setTraceOverwriteEnable(true); 292fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setSchedSwitchTracingEnable(false); 29399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling setFrequencyTracingEnable(false); 294e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis setGovernorLoadTracingEnable(false); 295fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setGlobalClockEnable(false); 296cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 2974b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (isRoot) { 298e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis setBusUtilizationTracingEnable(false); 2994b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis setWorkqueueTracingEnabled(false); 3004b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis setDiskTracingEnabled(false); 3014b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 3024b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 303cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // Note that we can't reset the trace buffer size here because that would 304cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // clear the trace before we've read it. 305fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 306fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 307fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout. 308fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace() 309fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 310fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int traceFD = open(k_tracePath, O_RDWR); 311fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (traceFD == -1) { 312fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath, 313fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 314fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return; 315fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 316fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 3177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (g_compress) { 3187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis z_stream zs; 3197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis uint8_t *in, *out; 3207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis int result, flush; 3217b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3227b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis bzero(&zs, sizeof(zs)); 3237b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = deflateInit(&zs, Z_DEFAULT_COMPRESSION); 3247b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_OK) { 3257b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error initializing zlib: %d\n", result); 3267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis close(traceFD); 3277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis return; 3287b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3297b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3307b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis const size_t bufSize = 64*1024; 3317b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis in = (uint8_t*)malloc(bufSize); 3327b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis out = (uint8_t*)malloc(bufSize); 3337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis flush = Z_NO_FLUSH; 3347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_out = out; 3367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; 3377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis do { 3397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_in == 0) { 3417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis // More input is needed. 3427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = read(traceFD, in, bufSize); 3437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result < 0) { 3447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error reading trace: %s (%d)\n", 3457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = Z_STREAM_END; 3477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 3487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else if (result == 0) { 3497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis flush = Z_FINISH; 3507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else { 3517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_in = in; 3527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_in = result; 3537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3547b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3557b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3567b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_out == 0) { 3577b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis // Need to write the output. 3587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = write(STDOUT_FILENO, out, bufSize); 3597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if ((size_t)result < bufSize) { 3607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 3617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = Z_STREAM_END; // skip deflate error message 3637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; // skip the final write 3647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 3657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_out = out; 3677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; 3687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } while ((result = deflate(&zs, flush)) == Z_OK); 3717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_STREAM_END) { 3737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error deflating trace: %s\n", zs.msg); 3747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_out < bufSize) { 3777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis size_t bytes = bufSize - zs.avail_out; 3787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = write(STDOUT_FILENO, out, bytes); 3797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if ((size_t)result < bytes) { 3807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 3817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = deflateEnd(&zs); 3867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_OK) { 3877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error cleaning up zlib: %d\n", result); 3887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis free(in); 3917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis free(out); 3927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else { 3937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis ssize_t sent = 0; 3947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0); 3957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (sent == -1) { 3967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno), 3977b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis errno); 3987b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 399fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 400fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 401fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(traceFD); 402fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 403fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 404fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr. 405fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd) 406fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 407fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "usage: %s [options]\n", cmd); 408fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "options include:\n" 409cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -b N use a trace buffer size of N KB\n" 410fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -c trace into a circular buffer\n" 411ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown " -d trace disk I/O\n" 41299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling " -f trace clock frequency changes\n" 413cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -l trace CPU frequency governor load\n" 414fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -s trace the kernel scheduler switches\n" 415fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -t N trace for N seconds [defualt 5]\n" 41699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling " -u trace bus utilization\n" 4177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis " -w trace the kernel workqueue\n" 4187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis " -z compress the trace dump\n"); 419fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 420fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 421fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) { 42231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten if (!g_nohup) { 42331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten g_traceAborted = true; 42431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten } 425fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 426fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 427fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() { 428fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis struct sigaction sa; 429fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigemptyset(&sa.sa_mask); 430fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sa.sa_flags = 0; 431fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sa.sa_handler = handleSignal; 432fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGHUP, &sa, NULL); 433fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGINT, &sa, NULL); 434fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGQUIT, &sa, NULL); 435fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGTERM, &sa, NULL); 436fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 437fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 438fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv) 439fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 4404b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool isRoot = (getuid() == 0); 4414b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 442fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (argc == 2 && 0 == strcmp(argv[1], "--help")) { 443fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis showHelp(argv[0]); 444fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis exit(0); 445fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 446fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 447fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis for (;;) { 448fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int ret; 449fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 45031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten ret = getopt(argc, argv, "b:cidflst:uwznS:"); 451fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 452fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ret < 0) { 453fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 454fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 455fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 456fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis switch(ret) { 457cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'b': 458cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceBufferSizeKB = atoi(optarg); 459cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 460cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 461fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 'c': 462fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceOverwrite = true; 463fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 464fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 4653169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis case 'i': 4663169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis g_traceCpuIdle = true; 4673169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis break; 4683169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 469cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'l': 470cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceGovernorLoad = true; 471cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 472cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 473ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown case 'd': 4744b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (!isRoot) { 4754b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis fprintf(stderr, "error: tracing disk activity requires root privileges\n"); 4764b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis exit(1); 4774b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 478ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown g_traceDisk = true; 479ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown break; 480ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 481cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'f': 48299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling g_traceFrequency = true; 483cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 484cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 48531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten case 'n': 48631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten g_nohup = true; 48731be80f02cddda55e75614884038fa4645b694cdGlenn Kasten break; 48831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten 489fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 's': 490fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceSchedSwitch = true; 491fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 492fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 49331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten case 'S': 49431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten g_initialSleepSecs = atoi(optarg); 49531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten break; 49631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten 497fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 't': 498fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceDurationSeconds = atoi(optarg); 499fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 500fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 50199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling case 'u': 50299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling if (!isRoot) { 50399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling fprintf(stderr, "error: tracing bus utilization requires root privileges\n"); 50499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling exit(1); 50599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling } 50699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling g_traceBusUtilization = true; 50799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling break; 50899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 509fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 'w': 5104b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (!isRoot) { 5114b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis fprintf(stderr, "error: tracing kernel work queues requires root privileges\n"); 5124b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis exit(1); 5134b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 514fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceWorkqueue = true; 515fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 516fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 5177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis case 'z': 5187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis g_compress = true; 5197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 5207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 521fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis default: 522cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis fprintf(stderr, "\n"); 523fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis showHelp(argv[0]); 524fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis exit(-1); 525fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 526fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 527fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 528fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 529fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis registerSigHandler(); 530fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 53131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten if (g_initialSleepSecs > 0) { 53231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten sleep(g_initialSleepSecs); 53331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten } 53431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten 5354b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool ok = startTrace(isRoot); 536fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 537fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 538fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf("capturing trace..."); 539fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 540fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 541fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // We clear the trace after starting it because tracing gets enabled for 542fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // each CPU individually in the kernel. Having the beginning of the trace 543fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // contain entries from only one CPU can cause "begin" entries without a 544fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // matching "end" entry to show up if a task gets migrated from one CPU to 545fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // another. 546fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok = clearTrace(); 547fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 548fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 549fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Sleep to allow the trace to be captured. 550fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis struct timespec timeLeft; 551fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis timeLeft.tv_sec = g_traceDurationSeconds; 552fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis timeLeft.tv_nsec = 0; 553fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis do { 554fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (g_traceAborted) { 555fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 556fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 557fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR); 558fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 559fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 560fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 561fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Stop the trace and restore the default settings. 5624b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis stopTrace(isRoot); 563fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 564fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 565fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (!g_traceAborted) { 566fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf(" done\nTRACE:\n"); 567fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 568fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis dumpTrace(); 569fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } else { 570fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf("\ntrace aborted.\n"); 571fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 572fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 573fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis clearTrace(); 574fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } else { 575fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "unable to start tracing\n"); 576fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 577fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 578cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // Reset the trace buffer size to 1. 579cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis setTraceBufferSizeKB(1); 580cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 581fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return g_traceAborted ? 1 : 0; 582fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 583