atrace.cpp revision 9ba4baf178bb9dad3912403bfd9aee07c14da33a
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; 389ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic bool g_traceSync = false; 39fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceWorkqueue = false; 40fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false; 41cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048; 427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false; 4331be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic bool g_nohup = false; 4431be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic int g_initialSleepSecs = 0; 45fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */ 47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false; 48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 49fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */ 50fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath = 51fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace_clock"; 52fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 53cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath = 54cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/buffer_size_kb"; 55cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 56fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath = 57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/options/overwrite"; 58fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 59fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath = 60fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_switch/enable"; 61fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 624b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic const char* k_schedWakeupEnablePath = 634b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable"; 644b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 6599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char* k_memoryBusEnablePath = 6699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling "/sys/kernel/debug/tracing/events/memory_bus/enable"; 6799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 68cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_cpuFreqEnablePath = 69cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable"; 70cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 7199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic const char *k_clockSetRateEnablePath = 7299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable"; 7399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 743169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic const char* k_cpuIdleEnablePath = 753169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_idle/enable"; 763169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 77cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_governorLoadEnablePath = 78cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable"; 79cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 809ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic const char* k_syncEnablePath = 819ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling "/sys/kernel/debug/tracing/events/sync/enable"; 829ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling 83fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath = 84fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/events/workqueue/enable"; 85fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 86ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic const char* k_diskEnablePaths[] = { 87ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable", 88ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable", 89ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable", 90ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable", 91ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}; 92ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 93fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath = 94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/tracing_on"; 95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 96fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath = 97fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace"; 98fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 99fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath = 100fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace_marker"; 101fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 102e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists. 103e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) { 104e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return access(filename, F_OK) != -1; 105e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis} 106e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis 107fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful. 108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str) 109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int fd = open(filename, O_WRONLY); 111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (fd == -1) { 112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", filename, 113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return false; 115fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 116fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 117fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = true; 118fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ssize_t len = strlen(str); 119fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (write(fd, str, len) != len) { 120fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error writing to %s: %s (%d)\n", filename, 121fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok = false; 123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 124fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(fd); 126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return ok; 128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 130fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file. 131fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable) 132fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 133fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return writeStr(filename, enable ? "1" : "0"); 134fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 135fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 136ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file. 137ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable) 138ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{ 139ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown bool result = true; 140ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown for (size_t i = 0; i < count; i++) { 141ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown result &= setKernelOptionEnable(filenames[i], enable); 142ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown } 143ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown return result; 144ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown} 145ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 146fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers. Disabling this 147fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up. 148fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable) 149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 150fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable); 151fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 152fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 153fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching. 154fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable) 155fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 1564b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool ok = true; 1574b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable); 1584b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable); 1594b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis return ok; 160fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 161fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 16299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling// Enable or disable tracing of the Bus utilization. 16399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setBusUtilizationTracingEnable(bool enable) 16499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling{ 165e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis bool ok = true, oneSet = false; 16699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling // these can be platform specific so make sure that at least 16799be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling // one succeeds. 168e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_memoryBusEnablePath)) { 169e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable); 170e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis oneSet |= ok; 171e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 172e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return ok && (oneSet || !enable); 17399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling} 17499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 175cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the CPU clock frequency. 17699be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gillingstatic bool setFrequencyTracingEnable(bool enable) 177cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 17899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling bool ok = true; 17999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable); 180e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_clockSetRateEnablePath)) { 181e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable); 182e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 18399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling return ok; 184cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 185cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 1863169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis// Enable or disable tracing of CPU idle events. 1873169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool setCpuIdleTracingEnable(bool enable) 1883169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{ 1893169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis return setKernelOptionEnable(k_cpuIdleEnablePath, enable); 1903169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis} 1913169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 192cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of 193cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// the CPU load. 194cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable) 195cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 196e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis bool ok = true; 197e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis if (fileExists(k_governorLoadEnablePath) || enable) { 198e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable); 199e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis } 200e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis return ok; 201cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 202cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 2039ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling// Enable or disable tracing of sync timelines and waits. 2049ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gillingstatic bool setSyncTracingEnabled(bool enable) 2059ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling{ 2069ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling bool ok = true; 2079ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling if (fileExists(k_syncEnablePath) || enable) { 2089ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling ok &= setKernelOptionEnable(k_syncEnablePath, enable); 2099ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling } 2109ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling return ok; 2119ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling} 2129ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling 213fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues. 214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable) 215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_workqueueEnablePath, enable); 217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 219ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable tracing of disk I/O. 220ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setDiskTracingEnabled(bool enable) 221ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{ 222ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable); 223ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown} 224ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 225fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing. 226fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable) 227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 228fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_tracingOnPath, enable); 229fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace. 232fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace() 233fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 234fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int traceFD = creat(k_tracePath, 0); 235fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (traceFD == -1) { 236fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath, 237fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 238fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return false; 239fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 240fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 241fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(traceFD); 242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return true; 244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 246cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes. 247cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size) 248cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 249cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis char str[32] = "1"; 250cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis int len; 251cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis if (size < 1) { 252cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis size = 1; 253cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis } 254cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis snprintf(str, 32, "%d", size); 255cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis return writeStr(k_traceBufferSizePath, str); 256cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 257cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 258fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock. Disabling the global 259fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock. 260fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable) 261fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 262fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return writeStr(k_traceClockPath, enable ? "global" : "local"); 263fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 264fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 265fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel. 2664b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic bool startTrace(bool isRoot) 267fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 268fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = true; 269fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 2704b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // Set up the tracing options that don't require root. 271fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setTraceOverwriteEnable(g_traceOverwrite); 272fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch); 27399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling ok &= setFrequencyTracingEnable(g_traceFrequency); 2743169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis ok &= setCpuIdleTracingEnable(g_traceCpuIdle); 275e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad); 276cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis ok &= setTraceBufferSizeKB(g_traceBufferSizeKB); 277fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setGlobalClockEnable(true); 278fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 2794b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // Set up the tracing options that do require root. The options that 2804b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // require root should have errored out earlier if we're not running as 2814b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis // root. 2824b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (isRoot) { 283e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis ok &= setBusUtilizationTracingEnable(g_traceBusUtilization); 2849ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling ok &= setSyncTracingEnabled(g_traceSync); 2854b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setWorkqueueTracingEnabled(g_traceWorkqueue); 2864b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis ok &= setDiskTracingEnabled(g_traceDisk); 2874b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 2884b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 289fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Enable tracing. 290fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setTracingEnabled(true); 291fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 292fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (!ok) { 293fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error: unable to start trace\n"); 294fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 295fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 296fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return ok; 297fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 298fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 299fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel. 3004b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennisstatic void stopTrace(bool isRoot) 301fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 302fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Disable tracing. 303fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setTracingEnabled(false); 304fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 305fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Set the options back to their defaults. 306fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setTraceOverwriteEnable(true); 307fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setSchedSwitchTracingEnable(false); 30899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling setFrequencyTracingEnable(false); 309e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis setGovernorLoadTracingEnable(false); 310fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setGlobalClockEnable(false); 311cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 3124b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (isRoot) { 313e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis setBusUtilizationTracingEnable(false); 3149ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling setSyncTracingEnabled(false); 3154b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis setWorkqueueTracingEnabled(false); 3164b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis setDiskTracingEnabled(false); 3174b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 3184b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 319cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // Note that we can't reset the trace buffer size here because that would 320cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // clear the trace before we've read it. 321fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 322fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 323fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout. 324fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace() 325fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 326fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int traceFD = open(k_tracePath, O_RDWR); 327fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (traceFD == -1) { 328fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath, 329fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 330fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return; 331fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 332fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 3337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (g_compress) { 3347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis z_stream zs; 3357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis uint8_t *in, *out; 3367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis int result, flush; 3377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis bzero(&zs, sizeof(zs)); 3397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = deflateInit(&zs, Z_DEFAULT_COMPRESSION); 3407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_OK) { 3417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error initializing zlib: %d\n", result); 3427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis close(traceFD); 3437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis return; 3447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis const size_t bufSize = 64*1024; 3477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis in = (uint8_t*)malloc(bufSize); 3487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis out = (uint8_t*)malloc(bufSize); 3497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis flush = Z_NO_FLUSH; 3507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_out = out; 3527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; 3537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3547b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis do { 3557b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3567b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_in == 0) { 3577b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis // More input is needed. 3587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = read(traceFD, in, bufSize); 3597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result < 0) { 3607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error reading trace: %s (%d)\n", 3617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = Z_STREAM_END; 3637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 3647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else if (result == 0) { 3657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis flush = Z_FINISH; 3667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else { 3677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_in = in; 3687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_in = result; 3697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_out == 0) { 3737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis // Need to write the output. 3747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = write(STDOUT_FILENO, out, bufSize); 3757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if ((size_t)result < bufSize) { 3767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 3777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = Z_STREAM_END; // skip deflate error message 3797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; // skip the final write 3807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 3817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_out = out; 3837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; 3847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } while ((result = deflate(&zs, flush)) == Z_OK); 3877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_STREAM_END) { 3897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error deflating trace: %s\n", zs.msg); 3907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_out < bufSize) { 3937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis size_t bytes = bufSize - zs.avail_out; 3947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = write(STDOUT_FILENO, out, bytes); 3957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if ((size_t)result < bytes) { 3967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 3977b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3987b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3997b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 4007b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 4017b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = deflateEnd(&zs); 4027b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_OK) { 4037b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error cleaning up zlib: %d\n", result); 4047b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 4057b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 4067b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis free(in); 4077b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis free(out); 4087b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else { 4097b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis ssize_t sent = 0; 4107b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0); 4117b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (sent == -1) { 4127b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno), 4137b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis errno); 4147b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 415fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 416fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 417fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(traceFD); 418fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 419fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 420fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr. 421fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd) 422fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 423fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "usage: %s [options]\n", cmd); 424fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "options include:\n" 425cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -b N use a trace buffer size of N KB\n" 426fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -c trace into a circular buffer\n" 427ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown " -d trace disk I/O\n" 42899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling " -f trace clock frequency changes\n" 429cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -l trace CPU frequency governor load\n" 430fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -s trace the kernel scheduler switches\n" 431fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -t N trace for N seconds [defualt 5]\n" 43299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling " -u trace bus utilization\n" 4337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis " -w trace the kernel workqueue\n" 4349ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling " -y trace sync timelines and waits\n" 4357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis " -z compress the trace dump\n"); 436fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 437fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 438fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) { 43931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten if (!g_nohup) { 44031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten g_traceAborted = true; 44131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten } 442fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 443fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 444fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() { 445fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis struct sigaction sa; 446fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigemptyset(&sa.sa_mask); 447fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sa.sa_flags = 0; 448fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sa.sa_handler = handleSignal; 449fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGHUP, &sa, NULL); 450fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGINT, &sa, NULL); 451fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGQUIT, &sa, NULL); 452fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGTERM, &sa, NULL); 453fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 454fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 455fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv) 456fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 4574b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool isRoot = (getuid() == 0); 4584b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis 459fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (argc == 2 && 0 == strcmp(argv[1], "--help")) { 460fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis showHelp(argv[0]); 461fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis exit(0); 462fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 463fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 464fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis for (;;) { 465fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int ret; 466fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 4679ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling ret = getopt(argc, argv, "b:cidflst:uwyznS:"); 468fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 469fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ret < 0) { 470fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 471fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 472fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 473fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis switch(ret) { 474cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'b': 475cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceBufferSizeKB = atoi(optarg); 476cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 477cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 478fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 'c': 479fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceOverwrite = true; 480fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 481fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 4823169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis case 'i': 4833169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis g_traceCpuIdle = true; 4843169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis break; 4853169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 486cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'l': 487cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceGovernorLoad = true; 488cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 489cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 490ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown case 'd': 4914b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (!isRoot) { 4924b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis fprintf(stderr, "error: tracing disk activity requires root privileges\n"); 4934b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis exit(1); 4944b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 495ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown g_traceDisk = true; 496ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown break; 497ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 498cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'f': 49999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling g_traceFrequency = true; 500cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 501cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 50231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten case 'n': 50331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten g_nohup = true; 50431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten break; 50531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten 506fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 's': 507fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceSchedSwitch = true; 508fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 509fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 51031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten case 'S': 51131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten g_initialSleepSecs = atoi(optarg); 51231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten break; 51331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten 514fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 't': 515fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceDurationSeconds = atoi(optarg); 516fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 517fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 51899be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling case 'u': 51999be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling if (!isRoot) { 52099be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling fprintf(stderr, "error: tracing bus utilization requires root privileges\n"); 52199be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling exit(1); 52299be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling } 52399be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling g_traceBusUtilization = true; 52499be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling break; 52599be77cf00d69a07ad5698b31c56a39f4add0bdfErik Gilling 526fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 'w': 5274b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis if (!isRoot) { 5284b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis fprintf(stderr, "error: tracing kernel work queues requires root privileges\n"); 5294b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis exit(1); 5304b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis } 531fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceWorkqueue = true; 532fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 533fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 5349ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling case 'y': 5359ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling if (!isRoot) { 5369ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling fprintf(stderr, "error: tracing sync requires root privileges\n"); 5379ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling exit(1); 5389ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling } 5399ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling g_traceSync = true; 5409ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling break; 5419ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling 5427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis case 'z': 5437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis g_compress = true; 5447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 5457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 546fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis default: 547cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis fprintf(stderr, "\n"); 548fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis showHelp(argv[0]); 549fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis exit(-1); 550fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 551fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 552fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 553fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 554fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis registerSigHandler(); 555fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 55631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten if (g_initialSleepSecs > 0) { 55731be80f02cddda55e75614884038fa4645b694cdGlenn Kasten sleep(g_initialSleepSecs); 55831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten } 55931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten 5604b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis bool ok = startTrace(isRoot); 561fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 562fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 563fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf("capturing trace..."); 564fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 565fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 566fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // We clear the trace after starting it because tracing gets enabled for 567fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // each CPU individually in the kernel. Having the beginning of the trace 568fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // contain entries from only one CPU can cause "begin" entries without a 569fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // matching "end" entry to show up if a task gets migrated from one CPU to 570fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // another. 571fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok = clearTrace(); 572fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 573fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 574fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Sleep to allow the trace to be captured. 575fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis struct timespec timeLeft; 576fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis timeLeft.tv_sec = g_traceDurationSeconds; 577fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis timeLeft.tv_nsec = 0; 578fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis do { 579fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (g_traceAborted) { 580fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 581fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 582fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR); 583fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 584fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 585fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 586fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Stop the trace and restore the default settings. 5874b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis stopTrace(isRoot); 588fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 589fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 590fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (!g_traceAborted) { 591fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf(" done\nTRACE:\n"); 592fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 593fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis dumpTrace(); 594fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } else { 595fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf("\ntrace aborted.\n"); 596fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 597fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 598fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis clearTrace(); 599fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } else { 600fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "unable to start tracing\n"); 601fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 602fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 603cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // Reset the trace buffer size to 1. 604cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis setTraceBufferSizeKB(1); 605cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 606fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return g_traceAborted ? 1 : 0; 607fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 608