16b995818535af84c4a6829af7733684861f20144Jamie Gennis/* 26b995818535af84c4a6829af7733684861f20144Jamie Gennis * Copyright (C) 2012 The Android Open Source Project 36b995818535af84c4a6829af7733684861f20144Jamie Gennis * 46b995818535af84c4a6829af7733684861f20144Jamie Gennis * Licensed under the Apache License, Version 2.0 (the "License"); 56b995818535af84c4a6829af7733684861f20144Jamie Gennis * you may not use this file except in compliance with the License. 66b995818535af84c4a6829af7733684861f20144Jamie Gennis * You may obtain a copy of the License at 76b995818535af84c4a6829af7733684861f20144Jamie Gennis * 86b995818535af84c4a6829af7733684861f20144Jamie Gennis * http://www.apache.org/licenses/LICENSE-2.0 96b995818535af84c4a6829af7733684861f20144Jamie Gennis * 106b995818535af84c4a6829af7733684861f20144Jamie Gennis * Unless required by applicable law or agreed to in writing, software 116b995818535af84c4a6829af7733684861f20144Jamie Gennis * distributed under the License is distributed on an "AS IS" BASIS, 126b995818535af84c4a6829af7733684861f20144Jamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136b995818535af84c4a6829af7733684861f20144Jamie Gennis * See the License for the specific language governing permissions and 146b995818535af84c4a6829af7733684861f20144Jamie Gennis * limitations under the License. 156b995818535af84c4a6829af7733684861f20144Jamie Gennis */ 166b995818535af84c4a6829af7733684861f20144Jamie Gennis 176b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <errno.h> 186b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <fcntl.h> 196b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <signal.h> 206b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdarg.h> 216b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdbool.h> 226b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdio.h> 236b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <stdlib.h> 246b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <sys/sendfile.h> 256b995818535af84c4a6829af7733684861f20144Jamie Gennis#include <time.h> 26eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis#include <zlib.h> 276b995818535af84c4a6829af7733684861f20144Jamie Gennis 2883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) 2983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown 306b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Command line options */ 316b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic int g_traceDurationSeconds = 5; 326b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceSchedSwitch = false; 33a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool g_traceFrequency = false; 34a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool g_traceBusUtilization = false; 35585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic bool g_traceCpuIdle = false; 3683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool g_traceDisk = false; 37bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool g_traceGovernorLoad = false; 383f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gillingstatic bool g_traceSync = false; 396b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceWorkqueue = false; 406b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceOverwrite = false; 41bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic int g_traceBufferSizeKB = 2048; 42eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennisstatic bool g_compress = false; 43a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kastenstatic bool g_nohup = false; 44a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kastenstatic int g_initialSleepSecs = 0; 456b995818535af84c4a6829af7733684861f20144Jamie Gennis 466b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Global state */ 476b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool g_traceAborted = false; 486b995818535af84c4a6829af7733684861f20144Jamie Gennis 496b995818535af84c4a6829af7733684861f20144Jamie Gennis/* Sys file paths */ 506b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceClockPath = 516b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/trace_clock"; 526b995818535af84c4a6829af7733684861f20144Jamie Gennis 53bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_traceBufferSizePath = 54bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis "/sys/kernel/debug/tracing/buffer_size_kb"; 55bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 566b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOverwriteEnablePath = 576b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/options/overwrite"; 586b995818535af84c4a6829af7733684861f20144Jamie Gennis 596b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_schedSwitchEnablePath = 606b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_switch/enable"; 616b995818535af84c4a6829af7733684861f20144Jamie Gennis 62b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic const char* k_schedWakeupEnablePath = 63b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable"; 64b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis 65a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic const char* k_memoryBusEnablePath = 66a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling "/sys/kernel/debug/tracing/events/memory_bus/enable"; 67a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling 68bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_cpuFreqEnablePath = 69bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable"; 70bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 71a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic const char *k_clockSetRateEnablePath = 72a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable"; 73a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling 74585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic const char* k_cpuIdleEnablePath = 75585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis "/sys/kernel/debug/tracing/events/power/cpu_idle/enable"; 76585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis 77bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic const char* k_governorLoadEnablePath = 78bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable"; 79bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 803f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gillingstatic const char* k_syncEnablePath = 813f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling "/sys/kernel/debug/tracing/events/sync/enable"; 823f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling 836b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_workqueueEnablePath = 846b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/events/workqueue/enable"; 856b995818535af84c4a6829af7733684861f20144Jamie Gennis 8683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic const char* k_diskEnablePaths[] = { 8783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable", 8883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable", 8983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable", 9083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable", 9183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown}; 9283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown 936b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracingOnPath = 946b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/tracing_on"; 956b995818535af84c4a6829af7733684861f20144Jamie Gennis 966b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_tracePath = 976b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/trace"; 986b995818535af84c4a6829af7733684861f20144Jamie Gennis 996b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic const char* k_traceMarkerPath = 1006b995818535af84c4a6829af7733684861f20144Jamie Gennis "/sys/kernel/debug/tracing/trace_marker"; 1016b995818535af84c4a6829af7733684861f20144Jamie Gennis 10224505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis// Check whether a file exists. 10324505a5826d7c5cf89f3da85058befd671a73444Jamie Gennisstatic bool fileExists(const char* filename) { 10424505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis return access(filename, F_OK) != -1; 10524505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis} 10624505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis 1076b995818535af84c4a6829af7733684861f20144Jamie Gennis// Write a string to a file, returning true if the write was successful. 1086b995818535af84c4a6829af7733684861f20144Jamie Gennisbool writeStr(const char* filename, const char* str) 1096b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 1106b995818535af84c4a6829af7733684861f20144Jamie Gennis int fd = open(filename, O_WRONLY); 1116b995818535af84c4a6829af7733684861f20144Jamie Gennis if (fd == -1) { 1126b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", filename, 1136b995818535af84c4a6829af7733684861f20144Jamie Gennis strerror(errno), errno); 1146b995818535af84c4a6829af7733684861f20144Jamie Gennis return false; 1156b995818535af84c4a6829af7733684861f20144Jamie Gennis } 1166b995818535af84c4a6829af7733684861f20144Jamie Gennis 1176b995818535af84c4a6829af7733684861f20144Jamie Gennis bool ok = true; 1186b995818535af84c4a6829af7733684861f20144Jamie Gennis ssize_t len = strlen(str); 1196b995818535af84c4a6829af7733684861f20144Jamie Gennis if (write(fd, str, len) != len) { 1206b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "error writing to %s: %s (%d)\n", filename, 1216b995818535af84c4a6829af7733684861f20144Jamie Gennis strerror(errno), errno); 1226b995818535af84c4a6829af7733684861f20144Jamie Gennis ok = false; 1236b995818535af84c4a6829af7733684861f20144Jamie Gennis } 1246b995818535af84c4a6829af7733684861f20144Jamie Gennis 1256b995818535af84c4a6829af7733684861f20144Jamie Gennis close(fd); 1266b995818535af84c4a6829af7733684861f20144Jamie Gennis 1276b995818535af84c4a6829af7733684861f20144Jamie Gennis return ok; 1286b995818535af84c4a6829af7733684861f20144Jamie Gennis} 1296b995818535af84c4a6829af7733684861f20144Jamie Gennis 1306b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file. 1316b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable) 1326b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 1336b995818535af84c4a6829af7733684861f20144Jamie Gennis return writeStr(filename, enable ? "1" : "0"); 1346b995818535af84c4a6829af7733684861f20144Jamie Gennis} 1356b995818535af84c4a6829af7733684861f20144Jamie Gennis 13683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file. 13783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable) 13883fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{ 13983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown bool result = true; 14083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown for (size_t i = 0; i < count; i++) { 14183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown result &= setKernelOptionEnable(filenames[i], enable); 14283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown } 14383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown return result; 14483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown} 14583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown 1466b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable overwriting of the kernel trace buffers. Disabling this 1476b995818535af84c4a6829af7733684861f20144Jamie Gennis// will cause tracing to stop once the trace buffers have filled up. 1486b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTraceOverwriteEnable(bool enable) 1496b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 1506b995818535af84c4a6829af7733684861f20144Jamie Gennis return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable); 1516b995818535af84c4a6829af7733684861f20144Jamie Gennis} 1526b995818535af84c4a6829af7733684861f20144Jamie Gennis 1536b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel scheduler switching. 1546b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setSchedSwitchTracingEnable(bool enable) 1556b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 156b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis bool ok = true; 157b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable); 158b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable); 159b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis return ok; 1606b995818535af84c4a6829af7733684861f20144Jamie Gennis} 1616b995818535af84c4a6829af7733684861f20144Jamie Gennis 162a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling// Enable or disable tracing of the Bus utilization. 163a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool setBusUtilizationTracingEnable(bool enable) 164a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling{ 16524505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis bool ok = true, oneSet = false; 166a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling // these can be platform specific so make sure that at least 167a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling // one succeeds. 16824505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis if (fileExists(k_memoryBusEnablePath)) { 16924505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable); 17024505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis oneSet |= ok; 17124505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis } 17224505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis return ok && (oneSet || !enable); 173a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling} 174a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling 175bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the CPU clock frequency. 176a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gillingstatic bool setFrequencyTracingEnable(bool enable) 177bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{ 178a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling bool ok = true; 179a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable); 18024505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis if (fileExists(k_clockSetRateEnablePath)) { 18124505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable); 18224505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis } 183a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling return ok; 184bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis} 185bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 186585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis// Enable or disable tracing of CPU idle events. 187585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennisstatic bool setCpuIdleTracingEnable(bool enable) 188585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis{ 189585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis return setKernelOptionEnable(k_cpuIdleEnablePath, enable); 190585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis} 191585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis 192bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Enable or disable tracing of the interactive CPU frequency governor's idea of 193bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// the CPU load. 194bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setGovernorLoadTracingEnable(bool enable) 195bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{ 19624505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis bool ok = true; 19724505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis if (fileExists(k_governorLoadEnablePath) || enable) { 19824505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable); 19924505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis } 20024505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis return ok; 201bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis} 202bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 2033f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling// Enable or disable tracing of sync timelines and waits. 2043f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gillingstatic bool setSyncTracingEnabled(bool enable) 2053f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling{ 2063f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling bool ok = true; 2073f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling if (fileExists(k_syncEnablePath) || enable) { 2083f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling ok &= setKernelOptionEnable(k_syncEnablePath, enable); 2093f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling } 2103f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling return ok; 2113f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling} 2123f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling 2136b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable tracing of the kernel workqueues. 2146b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setWorkqueueTracingEnabled(bool enable) 2156b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 2166b995818535af84c4a6829af7733684861f20144Jamie Gennis return setKernelOptionEnable(k_workqueueEnablePath, enable); 2176b995818535af84c4a6829af7733684861f20144Jamie Gennis} 2186b995818535af84c4a6829af7733684861f20144Jamie Gennis 21983fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown// Enable or disable tracing of disk I/O. 22083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brownstatic bool setDiskTracingEnabled(bool enable) 22183fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown{ 22283fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable); 22383fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown} 22483fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown 2256b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable kernel tracing. 2266b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setTracingEnabled(bool enable) 2276b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 2286b995818535af84c4a6829af7733684861f20144Jamie Gennis return setKernelOptionEnable(k_tracingOnPath, enable); 2296b995818535af84c4a6829af7733684861f20144Jamie Gennis} 2306b995818535af84c4a6829af7733684861f20144Jamie Gennis 2316b995818535af84c4a6829af7733684861f20144Jamie Gennis// Clear the contents of the kernel trace. 2326b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool clearTrace() 2336b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 2346b995818535af84c4a6829af7733684861f20144Jamie Gennis int traceFD = creat(k_tracePath, 0); 2356b995818535af84c4a6829af7733684861f20144Jamie Gennis if (traceFD == -1) { 2366b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath, 2376b995818535af84c4a6829af7733684861f20144Jamie Gennis strerror(errno), errno); 2386b995818535af84c4a6829af7733684861f20144Jamie Gennis return false; 2396b995818535af84c4a6829af7733684861f20144Jamie Gennis } 2406b995818535af84c4a6829af7733684861f20144Jamie Gennis 2416b995818535af84c4a6829af7733684861f20144Jamie Gennis close(traceFD); 2426b995818535af84c4a6829af7733684861f20144Jamie Gennis 2436b995818535af84c4a6829af7733684861f20144Jamie Gennis return true; 2446b995818535af84c4a6829af7733684861f20144Jamie Gennis} 2456b995818535af84c4a6829af7733684861f20144Jamie Gennis 246bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes. 247bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennisstatic bool setTraceBufferSizeKB(int size) 248bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis{ 249bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis char str[32] = "1"; 250bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis int len; 251bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis if (size < 1) { 252bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis size = 1; 253bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis } 254bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis snprintf(str, 32, "%d", size); 255bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis return writeStr(k_traceBufferSizePath, str); 256bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis} 257bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 2586b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable or disable the kernel's use of the global clock. Disabling the global 2596b995818535af84c4a6829af7733684861f20144Jamie Gennis// clock will result in the kernel using a per-CPU local clock. 2606b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic bool setGlobalClockEnable(bool enable) 2616b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 2626b995818535af84c4a6829af7733684861f20144Jamie Gennis return writeStr(k_traceClockPath, enable ? "global" : "local"); 2636b995818535af84c4a6829af7733684861f20144Jamie Gennis} 2646b995818535af84c4a6829af7733684861f20144Jamie Gennis 2656b995818535af84c4a6829af7733684861f20144Jamie Gennis// Enable tracing in the kernel. 266b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic bool startTrace(bool isRoot) 2676b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 2686b995818535af84c4a6829af7733684861f20144Jamie Gennis bool ok = true; 2696b995818535af84c4a6829af7733684861f20144Jamie Gennis 270b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis // Set up the tracing options that don't require root. 2716b995818535af84c4a6829af7733684861f20144Jamie Gennis ok &= setTraceOverwriteEnable(g_traceOverwrite); 2726b995818535af84c4a6829af7733684861f20144Jamie Gennis ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch); 273a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling ok &= setFrequencyTracingEnable(g_traceFrequency); 274585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis ok &= setCpuIdleTracingEnable(g_traceCpuIdle); 27524505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad); 276bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis ok &= setTraceBufferSizeKB(g_traceBufferSizeKB); 2776b995818535af84c4a6829af7733684861f20144Jamie Gennis ok &= setGlobalClockEnable(true); 2786b995818535af84c4a6829af7733684861f20144Jamie Gennis 279b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis // Set up the tracing options that do require root. The options that 280b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis // require root should have errored out earlier if we're not running as 281b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis // root. 282b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis if (isRoot) { 28324505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis ok &= setBusUtilizationTracingEnable(g_traceBusUtilization); 2843f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling ok &= setSyncTracingEnabled(g_traceSync); 285b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis ok &= setWorkqueueTracingEnabled(g_traceWorkqueue); 286b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis ok &= setDiskTracingEnabled(g_traceDisk); 287b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis } 288b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis 2896b995818535af84c4a6829af7733684861f20144Jamie Gennis // Enable tracing. 2906b995818535af84c4a6829af7733684861f20144Jamie Gennis ok &= setTracingEnabled(true); 2916b995818535af84c4a6829af7733684861f20144Jamie Gennis 2926b995818535af84c4a6829af7733684861f20144Jamie Gennis if (!ok) { 2936b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "error: unable to start trace\n"); 2946b995818535af84c4a6829af7733684861f20144Jamie Gennis } 2956b995818535af84c4a6829af7733684861f20144Jamie Gennis 2966b995818535af84c4a6829af7733684861f20144Jamie Gennis return ok; 2976b995818535af84c4a6829af7733684861f20144Jamie Gennis} 2986b995818535af84c4a6829af7733684861f20144Jamie Gennis 2996b995818535af84c4a6829af7733684861f20144Jamie Gennis// Disable tracing in the kernel. 300b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennisstatic void stopTrace(bool isRoot) 3016b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 3026b995818535af84c4a6829af7733684861f20144Jamie Gennis // Disable tracing. 3036b995818535af84c4a6829af7733684861f20144Jamie Gennis setTracingEnabled(false); 3046b995818535af84c4a6829af7733684861f20144Jamie Gennis 3056b995818535af84c4a6829af7733684861f20144Jamie Gennis // Set the options back to their defaults. 3066b995818535af84c4a6829af7733684861f20144Jamie Gennis setTraceOverwriteEnable(true); 3076b995818535af84c4a6829af7733684861f20144Jamie Gennis setSchedSwitchTracingEnable(false); 308a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling setFrequencyTracingEnable(false); 30924505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis setGovernorLoadTracingEnable(false); 3106b995818535af84c4a6829af7733684861f20144Jamie Gennis setGlobalClockEnable(false); 311bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 312b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis if (isRoot) { 31324505a5826d7c5cf89f3da85058befd671a73444Jamie Gennis setBusUtilizationTracingEnable(false); 3143f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling setSyncTracingEnabled(false); 315b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis setWorkqueueTracingEnabled(false); 316b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis setDiskTracingEnabled(false); 317b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis } 318b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis 319bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis // Note that we can't reset the trace buffer size here because that would 320bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis // clear the trace before we've read it. 3216b995818535af84c4a6829af7733684861f20144Jamie Gennis} 3226b995818535af84c4a6829af7733684861f20144Jamie Gennis 3236b995818535af84c4a6829af7733684861f20144Jamie Gennis// Read the current kernel trace and write it to stdout. 3246b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void dumpTrace() 3256b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 3266b995818535af84c4a6829af7733684861f20144Jamie Gennis int traceFD = open(k_tracePath, O_RDWR); 3276b995818535af84c4a6829af7733684861f20144Jamie Gennis if (traceFD == -1) { 3286b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath, 3296b995818535af84c4a6829af7733684861f20144Jamie Gennis strerror(errno), errno); 3306b995818535af84c4a6829af7733684861f20144Jamie Gennis return; 3316b995818535af84c4a6829af7733684861f20144Jamie Gennis } 3326b995818535af84c4a6829af7733684861f20144Jamie Gennis 333eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (g_compress) { 334eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis z_stream zs; 335eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis uint8_t *in, *out; 336eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis int result, flush; 337eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 338eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis bzero(&zs, sizeof(zs)); 339eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = deflateInit(&zs, Z_DEFAULT_COMPRESSION); 340eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (result != Z_OK) { 341eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error initializing zlib: %d\n", result); 342eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis close(traceFD); 343eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis return; 344eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 345eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 346eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis const size_t bufSize = 64*1024; 347eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis in = (uint8_t*)malloc(bufSize); 348eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis out = (uint8_t*)malloc(bufSize); 349eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis flush = Z_NO_FLUSH; 350eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 351eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.next_out = out; 352eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.avail_out = bufSize; 353eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 354eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis do { 355eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 356eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (zs.avail_in == 0) { 357eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis // More input is needed. 358eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = read(traceFD, in, bufSize); 359eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (result < 0) { 360eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error reading trace: %s (%d)\n", 361eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis strerror(errno), errno); 362eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = Z_STREAM_END; 363eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis break; 364eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } else if (result == 0) { 365eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis flush = Z_FINISH; 366eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } else { 367eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.next_in = in; 368eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.avail_in = result; 369eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 370eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 371eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 372eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (zs.avail_out == 0) { 373eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis // Need to write the output. 374eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = write(STDOUT_FILENO, out, bufSize); 375eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if ((size_t)result < bufSize) { 376eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 377eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis strerror(errno), errno); 378eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = Z_STREAM_END; // skip deflate error message 379eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.avail_out = bufSize; // skip the final write 380eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis break; 381eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 382eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.next_out = out; 383eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis zs.avail_out = bufSize; 384eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 385eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 386eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } while ((result = deflate(&zs, flush)) == Z_OK); 387eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 388eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (result != Z_STREAM_END) { 389eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error deflating trace: %s\n", zs.msg); 390eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 391eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 392eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (zs.avail_out < bufSize) { 393eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis size_t bytes = bufSize - zs.avail_out; 394eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = write(STDOUT_FILENO, out, bytes); 395eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if ((size_t)result < bytes) { 396eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error writing deflated trace: %s (%d)\n", 397eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis strerror(errno), errno); 398eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 399eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 400eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 401eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis result = deflateEnd(&zs); 402eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (result != Z_OK) { 403eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error cleaning up zlib: %d\n", result); 404eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 405eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 406eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis free(in); 407eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis free(out); 408eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } else { 409eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis ssize_t sent = 0; 410eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0); 411eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis if (sent == -1) { 412eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno), 413eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis errno); 414eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis } 4156b995818535af84c4a6829af7733684861f20144Jamie Gennis } 4166b995818535af84c4a6829af7733684861f20144Jamie Gennis 4176b995818535af84c4a6829af7733684861f20144Jamie Gennis close(traceFD); 4186b995818535af84c4a6829af7733684861f20144Jamie Gennis} 4196b995818535af84c4a6829af7733684861f20144Jamie Gennis 4206b995818535af84c4a6829af7733684861f20144Jamie Gennis// Print the command usage help to stderr. 4216b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void showHelp(const char *cmd) 4226b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 4236b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "usage: %s [options]\n", cmd); 4246b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "options include:\n" 425bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis " -b N use a trace buffer size of N KB\n" 4266b995818535af84c4a6829af7733684861f20144Jamie Gennis " -c trace into a circular buffer\n" 42783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown " -d trace disk I/O\n" 428a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling " -f trace clock frequency changes\n" 429bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis " -l trace CPU frequency governor load\n" 4306b995818535af84c4a6829af7733684861f20144Jamie Gennis " -s trace the kernel scheduler switches\n" 4316b995818535af84c4a6829af7733684861f20144Jamie Gennis " -t N trace for N seconds [defualt 5]\n" 432a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling " -u trace bus utilization\n" 433eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis " -w trace the kernel workqueue\n" 4343f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling " -y trace sync timelines and waits\n" 435eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis " -z compress the trace dump\n"); 4366b995818535af84c4a6829af7733684861f20144Jamie Gennis} 4376b995818535af84c4a6829af7733684861f20144Jamie Gennis 4386b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void handleSignal(int signo) { 439a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten if (!g_nohup) { 440a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten g_traceAborted = true; 441a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten } 4426b995818535af84c4a6829af7733684861f20144Jamie Gennis} 4436b995818535af84c4a6829af7733684861f20144Jamie Gennis 4446b995818535af84c4a6829af7733684861f20144Jamie Gennisstatic void registerSigHandler() { 4456b995818535af84c4a6829af7733684861f20144Jamie Gennis struct sigaction sa; 4466b995818535af84c4a6829af7733684861f20144Jamie Gennis sigemptyset(&sa.sa_mask); 4476b995818535af84c4a6829af7733684861f20144Jamie Gennis sa.sa_flags = 0; 4486b995818535af84c4a6829af7733684861f20144Jamie Gennis sa.sa_handler = handleSignal; 4496b995818535af84c4a6829af7733684861f20144Jamie Gennis sigaction(SIGHUP, &sa, NULL); 4506b995818535af84c4a6829af7733684861f20144Jamie Gennis sigaction(SIGINT, &sa, NULL); 4516b995818535af84c4a6829af7733684861f20144Jamie Gennis sigaction(SIGQUIT, &sa, NULL); 4526b995818535af84c4a6829af7733684861f20144Jamie Gennis sigaction(SIGTERM, &sa, NULL); 4536b995818535af84c4a6829af7733684861f20144Jamie Gennis} 4546b995818535af84c4a6829af7733684861f20144Jamie Gennis 4556b995818535af84c4a6829af7733684861f20144Jamie Gennisint main(int argc, char **argv) 4566b995818535af84c4a6829af7733684861f20144Jamie Gennis{ 457b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis bool isRoot = (getuid() == 0); 458b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis 4596b995818535af84c4a6829af7733684861f20144Jamie Gennis if (argc == 2 && 0 == strcmp(argv[1], "--help")) { 4606b995818535af84c4a6829af7733684861f20144Jamie Gennis showHelp(argv[0]); 4616b995818535af84c4a6829af7733684861f20144Jamie Gennis exit(0); 4626b995818535af84c4a6829af7733684861f20144Jamie Gennis } 4636b995818535af84c4a6829af7733684861f20144Jamie Gennis 4646b995818535af84c4a6829af7733684861f20144Jamie Gennis for (;;) { 4656b995818535af84c4a6829af7733684861f20144Jamie Gennis int ret; 4666b995818535af84c4a6829af7733684861f20144Jamie Gennis 4673f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling ret = getopt(argc, argv, "b:cidflst:uwyznS:"); 4686b995818535af84c4a6829af7733684861f20144Jamie Gennis 4696b995818535af84c4a6829af7733684861f20144Jamie Gennis if (ret < 0) { 4706b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 4716b995818535af84c4a6829af7733684861f20144Jamie Gennis } 4726b995818535af84c4a6829af7733684861f20144Jamie Gennis 4736b995818535af84c4a6829af7733684861f20144Jamie Gennis switch(ret) { 474bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis case 'b': 475bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis g_traceBufferSizeKB = atoi(optarg); 476bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis break; 477bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 4786b995818535af84c4a6829af7733684861f20144Jamie Gennis case 'c': 4796b995818535af84c4a6829af7733684861f20144Jamie Gennis g_traceOverwrite = true; 4806b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 4816b995818535af84c4a6829af7733684861f20144Jamie Gennis 482585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis case 'i': 483585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis g_traceCpuIdle = true; 484585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis break; 485585c219b9b7c2e89b8db6707cacdaf29c362e7baJamie Gennis 486bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis case 'l': 487bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis g_traceGovernorLoad = true; 488bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis break; 489bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 49083fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown case 'd': 491b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis if (!isRoot) { 492b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis fprintf(stderr, "error: tracing disk activity requires root privileges\n"); 493b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis exit(1); 494b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis } 49583fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown g_traceDisk = true; 49683fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown break; 49783fdbb05c39b030ef1e5b3a7db79c617114c20f4Jeff Brown 498bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis case 'f': 499a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling g_traceFrequency = true; 500bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis break; 501bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 502a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten case 'n': 503a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten g_nohup = true; 504a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten break; 505a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten 5066b995818535af84c4a6829af7733684861f20144Jamie Gennis case 's': 5076b995818535af84c4a6829af7733684861f20144Jamie Gennis g_traceSchedSwitch = true; 5086b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 5096b995818535af84c4a6829af7733684861f20144Jamie Gennis 510a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten case 'S': 511a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten g_initialSleepSecs = atoi(optarg); 512a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten break; 513a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten 5146b995818535af84c4a6829af7733684861f20144Jamie Gennis case 't': 5156b995818535af84c4a6829af7733684861f20144Jamie Gennis g_traceDurationSeconds = atoi(optarg); 5166b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 5176b995818535af84c4a6829af7733684861f20144Jamie Gennis 518a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling case 'u': 519a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling if (!isRoot) { 520a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling fprintf(stderr, "error: tracing bus utilization requires root privileges\n"); 521a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling exit(1); 522a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling } 523a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling g_traceBusUtilization = true; 524a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling break; 525a404a7e9bb05f4c1b0c9312d10a4c96c6cbdfcc9Erik Gilling 5266b995818535af84c4a6829af7733684861f20144Jamie Gennis case 'w': 527b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis if (!isRoot) { 528b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis fprintf(stderr, "error: tracing kernel work queues requires root privileges\n"); 529b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis exit(1); 530b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis } 5316b995818535af84c4a6829af7733684861f20144Jamie Gennis g_traceWorkqueue = true; 5326b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 5336b995818535af84c4a6829af7733684861f20144Jamie Gennis 5343f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling case 'y': 5353f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling if (!isRoot) { 5363f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling fprintf(stderr, "error: tracing sync requires root privileges\n"); 5373f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling exit(1); 5383f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling } 5393f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling g_traceSync = true; 5403f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling break; 5413f91534edf98d2a385c8fa29839cdd15a69f21d3Erik Gilling 542eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis case 'z': 543eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis g_compress = true; 544eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis break; 545eb213e7201b7288df2d2ec7e785349d993828bd3Jamie Gennis 5466b995818535af84c4a6829af7733684861f20144Jamie Gennis default: 547bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis fprintf(stderr, "\n"); 5486b995818535af84c4a6829af7733684861f20144Jamie Gennis showHelp(argv[0]); 5496b995818535af84c4a6829af7733684861f20144Jamie Gennis exit(-1); 5506b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 5516b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5526b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5536b995818535af84c4a6829af7733684861f20144Jamie Gennis 5546b995818535af84c4a6829af7733684861f20144Jamie Gennis registerSigHandler(); 5556b995818535af84c4a6829af7733684861f20144Jamie Gennis 556a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten if (g_initialSleepSecs > 0) { 557a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten sleep(g_initialSleepSecs); 558a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten } 559a09aa3eaad6ed5432ee13c764c67e67f7f43cac9Glenn Kasten 560b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis bool ok = startTrace(isRoot); 5616b995818535af84c4a6829af7733684861f20144Jamie Gennis 5626b995818535af84c4a6829af7733684861f20144Jamie Gennis if (ok) { 5636b995818535af84c4a6829af7733684861f20144Jamie Gennis printf("capturing trace..."); 5646b995818535af84c4a6829af7733684861f20144Jamie Gennis fflush(stdout); 5656b995818535af84c4a6829af7733684861f20144Jamie Gennis 5666b995818535af84c4a6829af7733684861f20144Jamie Gennis // We clear the trace after starting it because tracing gets enabled for 5676b995818535af84c4a6829af7733684861f20144Jamie Gennis // each CPU individually in the kernel. Having the beginning of the trace 5686b995818535af84c4a6829af7733684861f20144Jamie Gennis // contain entries from only one CPU can cause "begin" entries without a 5696b995818535af84c4a6829af7733684861f20144Jamie Gennis // matching "end" entry to show up if a task gets migrated from one CPU to 5706b995818535af84c4a6829af7733684861f20144Jamie Gennis // another. 5716b995818535af84c4a6829af7733684861f20144Jamie Gennis ok = clearTrace(); 5726b995818535af84c4a6829af7733684861f20144Jamie Gennis 5736b995818535af84c4a6829af7733684861f20144Jamie Gennis if (ok) { 5746b995818535af84c4a6829af7733684861f20144Jamie Gennis // Sleep to allow the trace to be captured. 5756b995818535af84c4a6829af7733684861f20144Jamie Gennis struct timespec timeLeft; 5766b995818535af84c4a6829af7733684861f20144Jamie Gennis timeLeft.tv_sec = g_traceDurationSeconds; 5776b995818535af84c4a6829af7733684861f20144Jamie Gennis timeLeft.tv_nsec = 0; 5786b995818535af84c4a6829af7733684861f20144Jamie Gennis do { 5796b995818535af84c4a6829af7733684861f20144Jamie Gennis if (g_traceAborted) { 5806b995818535af84c4a6829af7733684861f20144Jamie Gennis break; 5816b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5826b995818535af84c4a6829af7733684861f20144Jamie Gennis } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR); 5836b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5846b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5856b995818535af84c4a6829af7733684861f20144Jamie Gennis 5866b995818535af84c4a6829af7733684861f20144Jamie Gennis // Stop the trace and restore the default settings. 587b9314021ee1ccaa62eb115e8e0188f482a950f3bJamie Gennis stopTrace(isRoot); 5886b995818535af84c4a6829af7733684861f20144Jamie Gennis 5896b995818535af84c4a6829af7733684861f20144Jamie Gennis if (ok) { 5906b995818535af84c4a6829af7733684861f20144Jamie Gennis if (!g_traceAborted) { 5916b995818535af84c4a6829af7733684861f20144Jamie Gennis printf(" done\nTRACE:\n"); 5926b995818535af84c4a6829af7733684861f20144Jamie Gennis fflush(stdout); 5936b995818535af84c4a6829af7733684861f20144Jamie Gennis dumpTrace(); 5946b995818535af84c4a6829af7733684861f20144Jamie Gennis } else { 5956b995818535af84c4a6829af7733684861f20144Jamie Gennis printf("\ntrace aborted.\n"); 5966b995818535af84c4a6829af7733684861f20144Jamie Gennis fflush(stdout); 5976b995818535af84c4a6829af7733684861f20144Jamie Gennis } 5986b995818535af84c4a6829af7733684861f20144Jamie Gennis clearTrace(); 5996b995818535af84c4a6829af7733684861f20144Jamie Gennis } else { 6006b995818535af84c4a6829af7733684861f20144Jamie Gennis fprintf(stderr, "unable to start tracing\n"); 6016b995818535af84c4a6829af7733684861f20144Jamie Gennis } 6026b995818535af84c4a6829af7733684861f20144Jamie Gennis 603bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis // Reset the trace buffer size to 1. 604bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis setTraceBufferSizeKB(1); 605bc275ffc13e8c4e29ec08354c80a55df567dbab3Jamie Gennis 6066b995818535af84c4a6829af7733684861f20144Jamie Gennis return g_traceAborted ? 1 : 0; 6076b995818535af84c4a6829af7733684861f20144Jamie Gennis} 608