atrace.cpp revision e8744fd4dce2881c83d69c084b6937d0397ace05
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; 42fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 43fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */ 44fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false; 45fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */ 47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath = 48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace_clock"; 49fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 50cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath = 51cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/buffer_size_kb"; 52cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 53fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath = 54fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/options/overwrite"; 55fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 56fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath = 57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_switch/enable"; 58fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 594b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic const char* k_schedWakeupEnablePath = 604b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable"; 614b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 6299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char* k_memoryBusEnablePath = 6399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling "/sys/kernel/debug/tracing/events/memory_bus/enable"; 6499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 65cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_cpuFreqEnablePath = 66cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable"; 67cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 6899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char *k_clockSetRateEnablePath = 6999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable"; 7099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 713169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic const char* k_cpuIdleEnablePath = 723169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_idle/enable"; 733169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 74cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_governorLoadEnablePath = 75cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable"; 76cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 77fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath = 78fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/events/workqueue/enable"; 79fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 80ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic const char* k_diskEnablePaths[] = { 81ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable", 82ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable", 83ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable", 84ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable", 85ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}; 86ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 87fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath = 88fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/tracing_on"; 89fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 90fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath = 91fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace"; 92fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 93fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath = 94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace_marker"; 95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 96e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists. 97e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) { 98e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return access(filename, F_OK) != -1; 99e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis} 100e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis 101fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful. 102fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str) 103fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 104fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int fd = open(filename, O_WRONLY); 105fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (fd == -1) { 106fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", filename, 107fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return false; 109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = true; 112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ssize_t len = strlen(str); 113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (write(fd, str, len) != len) { 114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error writing to %s: %s (%d)\n", filename, 115fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 116fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok = false; 117fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 118fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 119fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(fd); 120fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 121fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return ok; 122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 124fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file. 125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable) 126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return writeStr(filename, enable ? "1" : "0"); 128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 130ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file. 131ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable) 132ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{ 133ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown bool result = true; 134ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown for (size_t i = 0; i < count; i++) { 135ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown result &= setKernelOptionEnable(filenames[i], enable); 136ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown } 137ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown return result; 138ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown} 139ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 140fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers. Disabling this 141fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up. 142fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable) 143fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 144fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable); 145fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 146fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 147fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching. 148fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable) 149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 1504b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool ok = true; 1514b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable); 1524b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable); 1534b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis return ok; 154fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 155fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 15699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling// Enable or disable tracing of the Bus utilization. 15799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setBusUtilizationTracingEnable(bool enable) 15899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling{ 159e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis bool ok = true, oneSet = false; 16099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling // these can be platform specific so make sure that at least 16199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling // one succeeds. 162e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_memoryBusEnablePath)) { 163e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable); 164e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis oneSet |= ok; 165e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 166e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return ok && (oneSet || !enable); 16799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling} 16899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 169cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the CPU clock frequency. 17099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setFrequencyTracingEnable(bool enable) 171cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 17299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling bool ok = true; 17399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable); 174e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_clockSetRateEnablePath)) { 175e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable); 176e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 17799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling return ok; 178cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 179cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 1803169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis// Enable or disable tracing of CPU idle events. 1813169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool setCpuIdleTracingEnable(bool enable) 1823169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{ 1833169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis return setKernelOptionEnable(k_cpuIdleEnablePath, enable); 1843169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis} 1853169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 186cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of 187cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// the CPU load. 188cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable) 189cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 190e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis bool ok = true; 191e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_governorLoadEnablePath) || enable) { 192e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable); 193e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 194e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return ok; 195cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 196cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 197fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues. 198fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable) 199fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 200fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_workqueueEnablePath, enable); 201fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 202fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 203ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable tracing of disk I/O. 204ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setDiskTracingEnabled(bool enable) 205ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{ 206ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable); 207ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown} 208ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 209fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing. 210fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable) 211fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 212fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_tracingOnPath, enable); 213fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace. 216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace() 217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int traceFD = creat(k_tracePath, 0); 219fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (traceFD == -1) { 220fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath, 221fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 222fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return false; 223fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 224fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 225fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(traceFD); 226fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return true; 228fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 229fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 230cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes. 231cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size) 232cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 233cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis char str[32] = "1"; 234cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis int len; 235cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis if (size < 1) { 236cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis size = 1; 237cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis } 238cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis snprintf(str, 32, "%d", size); 239cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis return writeStr(k_traceBufferSizePath, str); 240cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 241cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock. Disabling the global 243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock. 244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable) 245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 246fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return writeStr(k_traceClockPath, enable ? "global" : "local"); 247fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 248fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 249fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel. 2504b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic bool startTrace(bool isRoot) 251fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 252fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = true; 253fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 2544b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // Set up the tracing options that don't require root. 255fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setTraceOverwriteEnable(g_traceOverwrite); 256fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch); 25799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling ok &= setFrequencyTracingEnable(g_traceFrequency); 2583169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis ok &= setCpuIdleTracingEnable(g_traceCpuIdle); 259e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad); 260cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis ok &= setTraceBufferSizeKB(g_traceBufferSizeKB); 261fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setGlobalClockEnable(true); 262fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 2634b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // Set up the tracing options that do require root. The options that 2644b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // require root should have errored out earlier if we're not running as 2654b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // root. 2664b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (isRoot) { 267e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setBusUtilizationTracingEnable(g_traceBusUtilization); 2684b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setWorkqueueTracingEnabled(g_traceWorkqueue); 2694b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setDiskTracingEnabled(g_traceDisk); 2704b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 2714b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 272fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Enable tracing. 273fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setTracingEnabled(true); 274fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 275fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (!ok) { 276fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error: unable to start trace\n"); 277fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 278fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 279fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return ok; 280fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 281fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 282fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel. 2834b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic void stopTrace(bool isRoot) 284fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 285fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Disable tracing. 286fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setTracingEnabled(false); 287fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 288fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Set the options back to their defaults. 289fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setTraceOverwriteEnable(true); 290fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setSchedSwitchTracingEnable(false); 29199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling setFrequencyTracingEnable(false); 292e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis setGovernorLoadTracingEnable(false); 293fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setGlobalClockEnable(false); 294cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 2954b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (isRoot) { 296e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis setBusUtilizationTracingEnable(false); 2974b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis setWorkqueueTracingEnabled(false); 2984b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis setDiskTracingEnabled(false); 2994b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 3004b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 301cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // Note that we can't reset the trace buffer size here because that would 302cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // clear the trace before we've read it. 303fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 304fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 305fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout. 306fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace() 307fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 308fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int traceFD = open(k_tracePath, O_RDWR); 309fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (traceFD == -1) { 310fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath, 311fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 312fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return; 313fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 314fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 3157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (g_compress) { 3167b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis z_stream zs; 3177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis uint8_t *in, *out; 3187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis int result, flush; 3197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis bzero(&zs, sizeof(zs)); 3217b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = deflateInit(&zs, Z_DEFAULT_COMPRESSION); 3227b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_OK) { 3237b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error initializing zlib: %d\n", result); 3247b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis close(traceFD); 3257b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis return; 3267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3287b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis const size_t bufSize = 64*1024; 3297b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis in = (uint8_t*)malloc(bufSize); 3307b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis out = (uint8_t*)malloc(bufSize); 3317b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis flush = Z_NO_FLUSH; 3327b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_out = out; 3347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; 3357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis do { 3377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_in == 0) { 3397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis // More input is needed. 3407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = read(traceFD, in, bufSize); 3417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result < 0) { 3427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error reading trace: %s (%d)\n", 3437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = Z_STREAM_END; 3457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 3467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else if (result == 0) { 3477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis flush = Z_FINISH; 3487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else { 3497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_in = in; 3507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_in = result; 3517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3547b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_out == 0) { 3557b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis // Need to write the output. 3567b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = write(STDOUT_FILENO, out, bufSize); 3577b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if ((size_t)result < bufSize) { 3587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 3597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = Z_STREAM_END; // skip deflate error message 3617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; // skip the final write 3627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 3637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_out = out; 3657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; 3667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } while ((result = deflate(&zs, flush)) == Z_OK); 3697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_STREAM_END) { 3717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error deflating trace: %s\n", zs.msg); 3727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_out < bufSize) { 3757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis size_t bytes = bufSize - zs.avail_out; 3767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = write(STDOUT_FILENO, out, bytes); 3777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if ((size_t)result < bytes) { 3787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 3797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = deflateEnd(&zs); 3847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_OK) { 3857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error cleaning up zlib: %d\n", result); 3867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis free(in); 3897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis free(out); 3907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else { 3917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis ssize_t sent = 0; 3927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0); 3937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (sent == -1) { 3947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno), 3957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis errno); 3967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 397fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 398fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 399fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(traceFD); 400fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 401fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 402fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr. 403fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd) 404fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 405fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "usage: %s [options]\n", cmd); 406fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "options include:\n" 407cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -b N use a trace buffer size of N KB\n" 408fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -c trace into a circular buffer\n" 409ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown " -d trace disk I/O\n" 41099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling " -f trace clock frequency changes\n" 411cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -l trace CPU frequency governor load\n" 412fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -s trace the kernel scheduler switches\n" 413fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -t N trace for N seconds [defualt 5]\n" 41499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling " -u trace bus utilization\n" 4157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis " -w trace the kernel workqueue\n" 4167b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis " -z compress the trace dump\n"); 417fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 418fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 419fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) { 420fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceAborted = true; 421fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 422fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 423fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() { 424fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis struct sigaction sa; 425fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigemptyset(&sa.sa_mask); 426fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sa.sa_flags = 0; 427fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sa.sa_handler = handleSignal; 428fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGHUP, &sa, NULL); 429fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGINT, &sa, NULL); 430fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGQUIT, &sa, NULL); 431fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGTERM, &sa, NULL); 432fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 433fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 434fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv) 435fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 4364b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool isRoot = (getuid() == 0); 4374b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 438fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (argc == 2 && 0 == strcmp(argv[1], "--help")) { 439fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis showHelp(argv[0]); 440fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis exit(0); 441fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 442fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 443fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis for (;;) { 444fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int ret; 445fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 44699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling ret = getopt(argc, argv, "b:cidflst:uwz"); 447fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 448fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ret < 0) { 449fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 450fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 451fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 452fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis switch(ret) { 453cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'b': 454cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceBufferSizeKB = atoi(optarg); 455cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 456cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 457fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 'c': 458fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceOverwrite = true; 459fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 460fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 4613169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis case 'i': 4623169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis g_traceCpuIdle = true; 4633169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis break; 4643169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 465cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'l': 466cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceGovernorLoad = true; 467cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 468cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 469ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown case 'd': 4704b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (!isRoot) { 4714b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis fprintf(stderr, "error: tracing disk activity requires root privileges\n"); 4724b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis exit(1); 4734b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 474ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown g_traceDisk = true; 475ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown break; 476ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 477cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'f': 47899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling g_traceFrequency = true; 479cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 480cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 481fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 's': 482fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceSchedSwitch = true; 483fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 484fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 485fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 't': 486fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceDurationSeconds = atoi(optarg); 487fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 488fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 48999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling case 'u': 49099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling if (!isRoot) { 49199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling fprintf(stderr, "error: tracing bus utilization requires root privileges\n"); 49299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling exit(1); 49399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling } 49499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling g_traceBusUtilization = true; 49599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling break; 49699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 497fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 'w': 4984b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (!isRoot) { 4994b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis fprintf(stderr, "error: tracing kernel work queues requires root privileges\n"); 5004b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis exit(1); 5014b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 502fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceWorkqueue = true; 503fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 504fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 5057b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis case 'z': 5067b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis g_compress = true; 5077b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 5087b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 509fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis default: 510cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis fprintf(stderr, "\n"); 511fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis showHelp(argv[0]); 512fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis exit(-1); 513fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 514fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 515fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 516fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 517fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis registerSigHandler(); 518fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 5194b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool ok = startTrace(isRoot); 520fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 521fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 522fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf("capturing trace..."); 523fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 524fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 525fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // We clear the trace after starting it because tracing gets enabled for 526fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // each CPU individually in the kernel. Having the beginning of the trace 527fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // contain entries from only one CPU can cause "begin" entries without a 528fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // matching "end" entry to show up if a task gets migrated from one CPU to 529fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // another. 530fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok = clearTrace(); 531fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 532fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 533fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Sleep to allow the trace to be captured. 534fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis struct timespec timeLeft; 535fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis timeLeft.tv_sec = g_traceDurationSeconds; 536fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis timeLeft.tv_nsec = 0; 537fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis do { 538fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (g_traceAborted) { 539fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 540fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 541fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR); 542fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 543fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 544fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 545fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Stop the trace and restore the default settings. 5464b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis stopTrace(isRoot); 547fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 548fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 549fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (!g_traceAborted) { 550fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf(" done\nTRACE:\n"); 551fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 552fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis dumpTrace(); 553fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } else { 554fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf("\ntrace aborted.\n"); 555fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 556fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 557fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis clearTrace(); 558fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } else { 559fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "unable to start tracing\n"); 560fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 561fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 562cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // Reset the trace buffer size to 1. 563cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis setTraceBufferSizeKB(1); 564cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 565fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return g_traceAborted ? 1 : 0; 566fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 567