atrace.cpp revision ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9
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; 33cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool g_traceCpuFrequency = false; 343169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool g_traceCpuIdle = false; 35ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool g_traceDisk = false; 36cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool g_traceGovernorLoad = false; 37fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceWorkqueue = false; 38fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false; 39cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048; 407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false; 41fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 42fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */ 43fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false; 44fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 45fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */ 46fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath = 47fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace_clock"; 48fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 49cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath = 50cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/buffer_size_kb"; 51cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 52fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath = 53fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/options/overwrite"; 54fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 55fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_schedSwitchEnablePath = 56fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_switch/enable"; 57fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 58cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_cpuFreqEnablePath = 59cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable"; 60cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 613169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic const char* k_cpuIdleEnablePath = 623169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_idle/enable"; 633169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 64cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_governorLoadEnablePath = 65cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable"; 66cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 67fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_workqueueEnablePath = 68fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/events/workqueue/enable"; 69fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 70ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic const char* k_diskEnablePaths[] = { 71ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable", 72ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable", 73ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable", 74ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable", 75ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}; 76ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 77fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath = 78fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/tracing_on"; 79fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 80fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath = 81fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace"; 82fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 83fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceMarkerPath = 84fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis "/sys/kernel/debug/tracing/trace_marker"; 85fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 86fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful. 87fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisbool writeStr(const char* filename, const char* str) 88fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 89fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int fd = open(filename, O_WRONLY); 90fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (fd == -1) { 91fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", filename, 92fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 93fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return false; 94fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 95fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 96fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = true; 97fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ssize_t len = strlen(str); 98fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (write(fd, str, len) != len) { 99fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error writing to %s: %s (%d)\n", filename, 100fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 101fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok = false; 102fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 103fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 104fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(fd); 105fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 106fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return ok; 107fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 108fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 109fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file. 110fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable) 111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return writeStr(filename, enable ? "1" : "0"); 113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 115ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file. 116ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable) 117ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{ 118ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown bool result = true; 119ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown for (size_t i = 0; i < count; i++) { 120ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown result &= setKernelOptionEnable(filenames[i], enable); 121ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown } 122ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown return result; 123ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown} 124ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable overwriting of the kernel trace buffers. Disabling this 126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// will cause tracing to stop once the trace buffers have filled up. 127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTraceOverwriteEnable(bool enable) 128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable); 130fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 131fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 132fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel scheduler switching. 133fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable) 134fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 135fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_schedSwitchEnablePath, enable); 136fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 137fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 138cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the CPU clock frequency. 139cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setCpuFrequencyTracingEnable(bool enable) 140cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 141cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis return setKernelOptionEnable(k_cpuFreqEnablePath, enable); 142cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 143cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 1443169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis// Enable or disable tracing of CPU idle events. 1453169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennisstatic bool setCpuIdleTracingEnable(bool enable) 1463169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{ 1473169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis return setKernelOptionEnable(k_cpuIdleEnablePath, enable); 1483169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis} 1493169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 150cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of 151cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// the CPU load. 152cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable) 153cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 154cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis return setKernelOptionEnable(k_governorLoadEnablePath, enable); 155cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 156cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 157fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable tracing of the kernel workqueues. 158fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable) 159fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 160fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_workqueueEnablePath, enable); 161fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 162fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 163ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown// Enable or disable tracing of disk I/O. 164ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brownstatic bool setDiskTracingEnabled(bool enable) 165ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{ 166ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable); 167ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown} 168ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 169fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing. 170fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable) 171fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 172fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return setKernelOptionEnable(k_tracingOnPath, enable); 173fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 174fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 175fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace. 176fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace() 177fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 178fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int traceFD = creat(k_tracePath, 0); 179fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (traceFD == -1) { 180fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath, 181fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 182fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return false; 183fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 184fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 185fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(traceFD); 186fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 187fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return true; 188fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 189fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 190cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes. 191cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size) 192cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{ 193cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis char str[32] = "1"; 194cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis int len; 195cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis if (size < 1) { 196cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis size = 1; 197cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis } 198cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis snprintf(str, 32, "%d", size); 199cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis return writeStr(k_traceBufferSizePath, str); 200cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis} 201cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 202fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock. Disabling the global 203fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock. 204fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable) 205fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 206fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return writeStr(k_traceClockPath, enable ? "global" : "local"); 207fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 208fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 209fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis// Check whether a file exists. 210fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennisstatic bool fileExists(const char* filename) { 211fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis return access(filename, F_OK) != -1; 212fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis} 213fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis 214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel. 215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool startTrace() 216fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 217fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = true; 218fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 219fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Set up the tracing options. 220fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setTraceOverwriteEnable(g_traceOverwrite); 221fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch); 222cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis ok &= setCpuFrequencyTracingEnable(g_traceCpuFrequency); 2233169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis ok &= setCpuIdleTracingEnable(g_traceCpuIdle); 224fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis if (fileExists(k_governorLoadEnablePath) || g_traceGovernorLoad) { 225fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad); 226fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis } 227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setWorkqueueTracingEnabled(g_traceWorkqueue); 228ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown ok &= setDiskTracingEnabled(g_traceDisk); 229cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis ok &= setTraceBufferSizeKB(g_traceBufferSizeKB); 230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setGlobalClockEnable(true); 231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 232fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Enable tracing. 233fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok &= setTracingEnabled(true); 234fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 235fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (!ok) { 236fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error: unable to start trace\n"); 237fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 238fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 239fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return ok; 240fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 241fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel. 243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void stopTrace() 244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Disable tracing. 246fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setTracingEnabled(false); 247fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 248fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Set the options back to their defaults. 249fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setTraceOverwriteEnable(true); 250fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setSchedSwitchTracingEnable(false); 251cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis setCpuFrequencyTracingEnable(false); 252fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis if (fileExists(k_governorLoadEnablePath)) { 253fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis setGovernorLoadTracingEnable(false); 254fe312b98f747d7818ce865fb5b12b805f2ce9a9bJamie Gennis } 255fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setWorkqueueTracingEnabled(false); 256fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis setGlobalClockEnable(false); 257cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 258cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // Note that we can't reset the trace buffer size here because that would 259cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // clear the trace before we've read it. 260fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 261fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 262fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout. 263fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace() 264fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 265fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int traceFD = open(k_tracePath, O_RDWR); 266fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (traceFD == -1) { 267fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath, 268fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis strerror(errno), errno); 269fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return; 270fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 271fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 2727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (g_compress) { 2737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis z_stream zs; 2747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis uint8_t *in, *out; 2757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis int result, flush; 2767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 2777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis bzero(&zs, sizeof(zs)); 2787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = deflateInit(&zs, Z_DEFAULT_COMPRESSION); 2797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_OK) { 2807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error initializing zlib: %d\n", result); 2817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis close(traceFD); 2827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis return; 2837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 2847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 2857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis const size_t bufSize = 64*1024; 2867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis in = (uint8_t*)malloc(bufSize); 2877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis out = (uint8_t*)malloc(bufSize); 2887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis flush = Z_NO_FLUSH; 2897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 2907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_out = out; 2917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; 2927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 2937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis do { 2947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 2957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_in == 0) { 2967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis // More input is needed. 2977b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = read(traceFD, in, bufSize); 2987b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result < 0) { 2997b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error reading trace: %s (%d)\n", 3007b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3017b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = Z_STREAM_END; 3027b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 3037b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else if (result == 0) { 3047b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis flush = Z_FINISH; 3057b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else { 3067b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_in = in; 3077b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_in = result; 3087b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3097b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3107b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3117b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_out == 0) { 3127b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis // Need to write the output. 3137b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = write(STDOUT_FILENO, out, bufSize); 3147b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if ((size_t)result < bufSize) { 3157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 3167b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = Z_STREAM_END; // skip deflate error message 3187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; // skip the final write 3197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 3207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3217b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.next_out = out; 3227b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis zs.avail_out = bufSize; 3237b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3247b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3257b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } while ((result = deflate(&zs, flush)) == Z_OK); 3267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_STREAM_END) { 3287b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error deflating trace: %s\n", zs.msg); 3297b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3307b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3317b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (zs.avail_out < bufSize) { 3327b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis size_t bytes = bufSize - zs.avail_out; 3337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = write(STDOUT_FILENO, out, bytes); 3347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if ((size_t)result < bytes) { 3357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 3367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis strerror(errno), errno); 3377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis result = deflateEnd(&zs); 3417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (result != Z_OK) { 3427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error cleaning up zlib: %d\n", result); 3437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 3447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 3457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis free(in); 3467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis free(out); 3477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } else { 3487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis ssize_t sent = 0; 3497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0); 3507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis if (sent == -1) { 3517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno), 3527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis errno); 3537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis } 354fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 355fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 356fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis close(traceFD); 357fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 358fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 359fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Print the command usage help to stderr. 360fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void showHelp(const char *cmd) 361fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 362fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "usage: %s [options]\n", cmd); 363fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "options include:\n" 364cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -b N use a trace buffer size of N KB\n" 365fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -c trace into a circular buffer\n" 366ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown " -d trace disk I/O\n" 367cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -f trace CPU frequency changes\n" 368cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis " -l trace CPU frequency governor load\n" 369fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -s trace the kernel scheduler switches\n" 370fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis " -t N trace for N seconds [defualt 5]\n" 3717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis " -w trace the kernel workqueue\n" 3727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis " -z compress the trace dump\n"); 373fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 374fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 375fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void handleSignal(int signo) { 376fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceAborted = true; 377fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 378fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 379fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void registerSigHandler() { 380fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis struct sigaction sa; 381fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigemptyset(&sa.sa_mask); 382fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sa.sa_flags = 0; 383fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sa.sa_handler = handleSignal; 384fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGHUP, &sa, NULL); 385fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGINT, &sa, NULL); 386fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGQUIT, &sa, NULL); 387fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis sigaction(SIGTERM, &sa, NULL); 388fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 389fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 390fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv) 391fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{ 392fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (argc == 2 && 0 == strcmp(argv[1], "--help")) { 393fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis showHelp(argv[0]); 394fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis exit(0); 395fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 396fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 397fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (getuid() != 0) { 398fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "error: %s must be run as root.", argv[0]); 399cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis exit(1); 400fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 401fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 402fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis for (;;) { 403fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis int ret; 404fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 405ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown ret = getopt(argc, argv, "b:cidflst:wz"); 406fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 407fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ret < 0) { 408fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 409fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 410fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 411fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis switch(ret) { 412cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'b': 413cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceBufferSizeKB = atoi(optarg); 414cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 415cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 416fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 'c': 417fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceOverwrite = true; 418fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 419fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 4203169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis case 'i': 4213169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis g_traceCpuIdle = true; 4223169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis break; 4233169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis 424cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'l': 425cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceGovernorLoad = true; 426cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 427cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 428ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown case 'd': 429ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown g_traceDisk = true; 430ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown break; 431ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown 432cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis case 'f': 433cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis g_traceCpuFrequency = true; 434cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis break; 435cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 436fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 's': 437fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceSchedSwitch = true; 438fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 439fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 440fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 't': 441fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceDurationSeconds = atoi(optarg); 442fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 443fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 444fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis case 'w': 445fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis g_traceWorkqueue = true; 446fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 447fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 4487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis case 'z': 4497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis g_compress = true; 4507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis break; 4517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis 452fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis default: 453cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis fprintf(stderr, "\n"); 454fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis showHelp(argv[0]); 455fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis exit(-1); 456fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 457fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 458fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 459fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 460fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis registerSigHandler(); 461fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 462fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis bool ok = startTrace(); 463fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 464fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 465fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf("capturing trace..."); 466fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 467fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 468fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // We clear the trace after starting it because tracing gets enabled for 469fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // each CPU individually in the kernel. Having the beginning of the trace 470fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // contain entries from only one CPU can cause "begin" entries without a 471fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // matching "end" entry to show up if a task gets migrated from one CPU to 472fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // another. 473fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis ok = clearTrace(); 474fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 475fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 476fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Sleep to allow the trace to be captured. 477fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis struct timespec timeLeft; 478fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis timeLeft.tv_sec = g_traceDurationSeconds; 479fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis timeLeft.tv_nsec = 0; 480fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis do { 481fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (g_traceAborted) { 482fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis break; 483fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 484fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR); 485fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 486fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 487fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 488fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis // Stop the trace and restore the default settings. 489fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis stopTrace(); 490fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 491fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (ok) { 492fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis if (!g_traceAborted) { 493fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf(" done\nTRACE:\n"); 494fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 495fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis dumpTrace(); 496fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } else { 497fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis printf("\ntrace aborted.\n"); 498fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fflush(stdout); 499fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 500fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis clearTrace(); 501fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } else { 502fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis fprintf(stderr, "unable to start tracing\n"); 503fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis } 504fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis 505cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis // Reset the trace buffer size to 1. 506cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis setTraceBufferSizeKB(1); 507cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis 508fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis return g_traceAborted ? 1 : 0; 509fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis} 510