atrace.cpp revision 4edbd078cddcc1cbe59156a0e7ece01de75156e0
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> 194edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling#include <getopt.h> 20fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <signal.h> 21fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdarg.h> 22fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdbool.h> 23fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdio.h> 24fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdlib.h> 25fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <sys/sendfile.h> 26fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <time.h> 277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis#include <zlib.h> 28fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 29ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) 30ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 31fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Command line options */ 32fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic int g_traceDurationSeconds = 5; 33fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceSchedSwitch = false; 3499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool g_traceFrequency = false; 3599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool g_traceBusUtilization = false; 363169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool g_traceCpuIdle = false; 37ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool g_traceDisk = false; 38cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool g_traceGovernorLoad = false; 399ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic bool g_traceSync = false; 40fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceWorkqueue = false; 41fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false; 42cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048; 437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false; 4431be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic bool g_nohup = false; 4531be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic int g_initialSleepSecs = 0; 46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */ 48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false; 49fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 50fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */ 51fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath = 52fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace_clock"; 53fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 54cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath = 55cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/buffer_size_kb"; 56cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath = 58fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/options/overwrite"; 59fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 60fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath = 61fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_switch/enable"; 62fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 634b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic const char* k_schedWakeupEnablePath = 644b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable"; 654b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 6699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char* k_memoryBusEnablePath = 6799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling "/sys/kernel/debug/tracing/events/memory_bus/enable"; 6899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 69cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_cpuFreqEnablePath = 70cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable"; 71cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 7299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char *k_clockSetRateEnablePath = 7399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable"; 7499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 753169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic const char* k_cpuIdleEnablePath = 763169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_idle/enable"; 773169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 78cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_governorLoadEnablePath = 79cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable"; 80cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 819ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic const char* k_syncEnablePath = 829ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling "/sys/kernel/debug/tracing/events/sync/enable"; 839ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling 84fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath = 85fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/events/workqueue/enable"; 86fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 87ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic const char* k_diskEnablePaths[] = { 88ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable", 89ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable", 90ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable", 91ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable", 92ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}; 93ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath = 95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/tracing_on"; 96fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 97fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath = 98fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace"; 99fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 100fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath = 101fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace_marker"; 102fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 103e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists. 104e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) { 105e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return access(filename, F_OK) != -1; 106e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis} 107e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis 108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful. 109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str) 110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int fd = open(filename, O_WRONLY); 112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (fd == -1) { 113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", filename, 114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 115fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return false; 116fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 117fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 118fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = true; 119fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ssize_t len = strlen(str); 120fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (write(fd, str, len) != len) { 121fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error writing to %s: %s (%d)\n", filename, 122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok = false; 124fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(fd); 127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return ok; 129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 130fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 131fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file. 132fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable) 133fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 134fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return writeStr(filename, enable ? "1" : "0"); 135fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 136fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 137ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file. 138ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable) 139ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{ 140ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown bool result = true; 141ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown for (size_t i = 0; i < count; i++) { 142ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown result &= setKernelOptionEnable(filenames[i], enable); 143ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown } 144ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown return result; 145ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown} 146ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 147fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers. Disabling this 148fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up. 149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable) 150fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 151fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable); 152fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 153fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 154fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching. 155fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable) 156fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 1574b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool ok = true; 1584b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable); 1594b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable); 1604b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis return ok; 161fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 162fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 16399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling// Enable or disable tracing of the Bus utilization. 16499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setBusUtilizationTracingEnable(bool enable) 16599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling{ 166e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis bool ok = true, oneSet = false; 16799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling // these can be platform specific so make sure that at least 16899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling // one succeeds. 169e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_memoryBusEnablePath)) { 170e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable); 171e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis oneSet |= ok; 172e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 173e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return ok && (oneSet || !enable); 17499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling} 17599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 176cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the CPU clock frequency. 17799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setFrequencyTracingEnable(bool enable) 178cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 17999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling bool ok = true; 18099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable); 181e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_clockSetRateEnablePath)) { 182e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable); 183e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 18499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling return ok; 185cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 186cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 1873169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis// Enable or disable tracing of CPU idle events. 1883169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool setCpuIdleTracingEnable(bool enable) 1893169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{ 1903169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis return setKernelOptionEnable(k_cpuIdleEnablePath, enable); 1913169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis} 1923169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 193cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of 194cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// the CPU load. 195cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable) 196cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 197e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis bool ok = true; 198e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_governorLoadEnablePath) || enable) { 199e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable); 200e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 201e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return ok; 202cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 203cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 2049ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling// Enable or disable tracing of sync timelines and waits. 2059ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic bool setSyncTracingEnabled(bool enable) 2069ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling{ 2079ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling bool ok = true; 2089ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling if (fileExists(k_syncEnablePath) || enable) { 2099ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling ok &= setKernelOptionEnable(k_syncEnablePath, enable); 2109ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling } 2119ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling return ok; 2129ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling} 2139ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling 214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues. 215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable) 216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_workqueueEnablePath, enable); 218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 219fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 220ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable tracing of disk I/O. 221ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setDiskTracingEnabled(bool enable) 222ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{ 223ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable); 224ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown} 225ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 226fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing. 227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable) 228fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 229fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_tracingOnPath, enable); 230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 232fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace. 233fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace() 234fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 235fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int traceFD = creat(k_tracePath, 0); 236fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (traceFD == -1) { 237fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath, 238fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 239fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return false; 240fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 241fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(traceFD); 243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return true; 245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 246fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 247cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes. 248cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size) 249cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 250cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis char str[32] = "1"; 251cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis int len; 252cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis if (size < 1) { 253cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis size = 1; 254cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis } 255cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis snprintf(str, 32, "%d", size); 256cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis return writeStr(k_traceBufferSizePath, str); 257cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 258cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 259fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock. Disabling the global 260fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock. 261fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable) 262fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 263fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return writeStr(k_traceClockPath, enable ? "global" : "local"); 264fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 265fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 266fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel. 2674b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic bool startTrace(bool isRoot) 268fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 269fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = true; 270fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 2714b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // Set up the tracing options that don't require root. 272fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setTraceOverwriteEnable(g_traceOverwrite); 273fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch); 27499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling ok &= setFrequencyTracingEnable(g_traceFrequency); 2753169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis ok &= setCpuIdleTracingEnable(g_traceCpuIdle); 276e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad); 277cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis ok &= setTraceBufferSizeKB(g_traceBufferSizeKB); 278fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setGlobalClockEnable(true); 279fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 2804b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // Set up the tracing options that do require root. The options that 2814b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // require root should have errored out earlier if we're not running as 2824b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // root. 2834b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (isRoot) { 284e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setBusUtilizationTracingEnable(g_traceBusUtilization); 2859ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling ok &= setSyncTracingEnabled(g_traceSync); 2864b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setWorkqueueTracingEnabled(g_traceWorkqueue); 2874b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setDiskTracingEnabled(g_traceDisk); 2884b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 2894b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 290fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Enable tracing. 291fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setTracingEnabled(true); 292fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 293fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (!ok) { 294fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error: unable to start trace\n"); 295fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 296fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 297fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return ok; 298fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 299fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 300fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel. 3014b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic void stopTrace(bool isRoot) 302fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 303fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Disable tracing. 304fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setTracingEnabled(false); 305fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 306fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Set the options back to their defaults. 307fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setTraceOverwriteEnable(true); 308fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setSchedSwitchTracingEnable(false); 30999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling setFrequencyTracingEnable(false); 310e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis setGovernorLoadTracingEnable(false); 311fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setGlobalClockEnable(false); 312cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 3134b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (isRoot) { 314e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis setBusUtilizationTracingEnable(false); 3159ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling setSyncTracingEnabled(false); 3164b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis setWorkqueueTracingEnabled(false); 3174b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis setDiskTracingEnabled(false); 3184b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 3194b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 320cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // Note that we can't reset the trace buffer size here because that would 321cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // clear the trace before we've read it. 322fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 323fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 324fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout. 325fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace() 326fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 327fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int traceFD = open(k_tracePath, O_RDWR); 328fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (traceFD == -1) { 329fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath, 330fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 331fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return; 332fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 333fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 3347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (g_compress) { 3357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis z_stream zs; 3367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis uint8_t *in, *out; 3377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis int result, flush; 3387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis bzero(&zs, sizeof(zs)); 3407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = deflateInit(&zs, Z_DEFAULT_COMPRESSION); 3417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_OK) { 3427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error initializing zlib: %d\n", result); 3437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis close(traceFD); 3447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis return; 3457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis const size_t bufSize = 64*1024; 3487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis in = (uint8_t*)malloc(bufSize); 3497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis out = (uint8_t*)malloc(bufSize); 3507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis flush = Z_NO_FLUSH; 3517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_out = out; 3537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; 3547b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3557b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis do { 3567b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3577b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_in == 0) { 3587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis // More input is needed. 3597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = read(traceFD, in, bufSize); 3607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result < 0) { 3617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error reading trace: %s (%d)\n", 3627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = Z_STREAM_END; 3647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 3657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else if (result == 0) { 3667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis flush = Z_FINISH; 3677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else { 3687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_in = in; 3697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_in = result; 3707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_out == 0) { 3747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis // Need to write the output. 3757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = write(STDOUT_FILENO, out, bufSize); 3767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if ((size_t)result < bufSize) { 3777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 3787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = Z_STREAM_END; // skip deflate error message 3807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; // skip the final write 3817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 3827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_out = out; 3847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; 3857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } while ((result = deflate(&zs, flush)) == Z_OK); 3887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_STREAM_END) { 3907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error deflating trace: %s\n", zs.msg); 3917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_out < bufSize) { 3947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis size_t bytes = bufSize - zs.avail_out; 3957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = write(STDOUT_FILENO, out, bytes); 3967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if ((size_t)result < bytes) { 3977b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 3987b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3997b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 4007b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 4017b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 4027b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = deflateEnd(&zs); 4037b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_OK) { 4047b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error cleaning up zlib: %d\n", result); 4057b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 4067b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 4077b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis free(in); 4087b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis free(out); 4097b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else { 4107b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis ssize_t sent = 0; 4117b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0); 4127b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (sent == -1) { 4137b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno), 4147b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis errno); 4157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 416fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 417fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 418fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(traceFD); 419fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 420fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 421fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr. 422fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd) 423fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 424fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "usage: %s [options]\n", cmd); 425fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "options include:\n" 426cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -b N use a trace buffer size of N KB\n" 427fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -c trace into a circular buffer\n" 428ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown " -d trace disk I/O\n" 42999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling " -f trace clock frequency changes\n" 430cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -l trace CPU frequency governor load\n" 431fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -s trace the kernel scheduler switches\n" 432fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -t N trace for N seconds [defualt 5]\n" 43399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling " -u trace bus utilization\n" 4347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis " -w trace the kernel workqueue\n" 4359ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling " -y trace sync timelines and waits\n" 4364edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling " -z compress the trace dump\n" 4374edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling " --async_start start circular trace and return immediatly\n", 4384edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling " --async_dump dump the current contents of circular trace buffer\n", 4394edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling " --async_stop stop tracing and dump the current contents of circular\n", 4404edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling " trace buffer\n", 4414edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling ); 442fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 443fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 444fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) { 44531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten if (!g_nohup) { 44631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten g_traceAborted = true; 44731be80f02cddda55e75614884038fa4645b694cdGlenn Kasten } 448fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 449fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 450fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() { 451fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis struct sigaction sa; 452fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigemptyset(&sa.sa_mask); 453fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sa.sa_flags = 0; 454fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sa.sa_handler = handleSignal; 455fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGHUP, &sa, NULL); 456fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGINT, &sa, NULL); 457fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGQUIT, &sa, NULL); 458fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGTERM, &sa, NULL); 459fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 460fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 461fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv) 462fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 4634b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool isRoot = (getuid() == 0); 4644edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling bool async = false; 4654edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling bool traceStart = true; 4664edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling bool traceStop = true; 4674edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling bool traceDump = true; 4684b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 469fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (argc == 2 && 0 == strcmp(argv[1], "--help")) { 470fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis showHelp(argv[0]); 471fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis exit(0); 472fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 473fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 474fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis for (;;) { 475fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int ret; 4764edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling int option_index = 0; 4774edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling static struct option long_options[] = { 4784edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling {"async_start", no_argument, 0, 0 }, 4794edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling {"async_stop", no_argument, 0, 0 }, 4804edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling {"async_dump", no_argument, 0, 0 }, 4814edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling {0, 0, 0, 0 } 4824edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling }; 483fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 4844edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling ret = getopt_long(argc, argv, "b:cidflst:uwyznS:", 4854edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling long_options, &option_index); 486fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 487fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ret < 0) { 488fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 489fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 490fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 491fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis switch(ret) { 492cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'b': 493cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceBufferSizeKB = atoi(optarg); 494cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 495cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 496fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 'c': 497fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceOverwrite = true; 498fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 499fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 5003169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis case 'i': 5013169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis g_traceCpuIdle = true; 5023169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis break; 5033169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 504cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'l': 505cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceGovernorLoad = true; 506cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 507cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 508ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown case 'd': 5094b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (!isRoot) { 5104b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis fprintf(stderr, "error: tracing disk activity requires root privileges\n"); 5114b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis exit(1); 5124b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 513ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown g_traceDisk = true; 514ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown break; 515ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 516cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'f': 51799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling g_traceFrequency = true; 518cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 519cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 52031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten case 'n': 52131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten g_nohup = true; 52231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten break; 52331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten 524fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 's': 525fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceSchedSwitch = true; 526fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 527fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 52831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten case 'S': 52931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten g_initialSleepSecs = atoi(optarg); 53031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten break; 53131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten 532fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 't': 533fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceDurationSeconds = atoi(optarg); 534fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 535fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 53699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling case 'u': 53799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling if (!isRoot) { 53899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling fprintf(stderr, "error: tracing bus utilization requires root privileges\n"); 53999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling exit(1); 54099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling } 54199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling g_traceBusUtilization = true; 54299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling break; 54399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 544fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 'w': 5454b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (!isRoot) { 5464b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis fprintf(stderr, "error: tracing kernel work queues requires root privileges\n"); 5474b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis exit(1); 5484b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 549fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceWorkqueue = true; 550fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 551fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 5529ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling case 'y': 5539ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling if (!isRoot) { 5549ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling fprintf(stderr, "error: tracing sync requires root privileges\n"); 5559ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling exit(1); 5569ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling } 5579ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling g_traceSync = true; 5589ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling break; 5599ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling 5607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis case 'z': 5617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis g_compress = true; 5627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 5637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 5644edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling case 0: 5654edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling if (!strcmp(long_options[option_index].name, "async_start")) { 5664edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling async = true; 5674edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling traceStop = false; 5684edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling traceDump = false; 5694edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling g_traceOverwrite = true; 5704edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling } else if (!strcmp(long_options[option_index].name, "async_stop")) { 5714edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling async = true; 5724edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling traceStop = false; 5734edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling } else if (!strcmp(long_options[option_index].name, "async_dump")) { 5744edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling async = true; 5754edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling traceStart = false; 5764edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling traceStop = false; 5774edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling } 5784edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling break; 5794edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling 580fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis default: 581cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis fprintf(stderr, "\n"); 582fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis showHelp(argv[0]); 583fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis exit(-1); 584fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 585fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 586fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 587fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 588fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis registerSigHandler(); 589fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 59031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten if (g_initialSleepSecs > 0) { 59131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten sleep(g_initialSleepSecs); 59231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten } 59331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten 5944b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool ok = startTrace(isRoot); 595fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 5964edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling if (ok && traceStart) { 597fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf("capturing trace..."); 598fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 599fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 600fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // We clear the trace after starting it because tracing gets enabled for 601fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // each CPU individually in the kernel. Having the beginning of the trace 602fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // contain entries from only one CPU can cause "begin" entries without a 603fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // matching "end" entry to show up if a task gets migrated from one CPU to 604fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // another. 605fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok = clearTrace(); 606fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 6074edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling if (ok && !async) { 608fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Sleep to allow the trace to be captured. 609fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis struct timespec timeLeft; 610fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis timeLeft.tv_sec = g_traceDurationSeconds; 611fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis timeLeft.tv_nsec = 0; 612fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis do { 613fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (g_traceAborted) { 614fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 615fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 616fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR); 617fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 618fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 619fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 620fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Stop the trace and restore the default settings. 6214edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling if (traceStop) 6224edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling stopTrace(isRoot); 623fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 6244edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling if (ok && traceDump) { 625fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (!g_traceAborted) { 626fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf(" done\nTRACE:\n"); 627fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 628fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis dumpTrace(); 629fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } else { 630fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf("\ntrace aborted.\n"); 631fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 632fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 633fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis clearTrace(); 6344edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling } else if (!ok) { 635fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "unable to start tracing\n"); 636fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 637fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 638cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // Reset the trace buffer size to 1. 6394edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling if (traceStop) 6404edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling setTraceBufferSizeKB(1); 641cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 642fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return g_traceAborted ? 1 : 0; 643fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 644