static const char* k_schedSwitchEnablePath =
"/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
+static const char* k_schedWakeupEnablePath =
+ "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
+
static const char* k_cpuFreqEnablePath =
"/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
// Enable or disable tracing of the kernel scheduler switching.
static bool setSchedSwitchTracingEnable(bool enable)
{
- return setKernelOptionEnable(k_schedSwitchEnablePath, enable);
+ bool ok = true;
+ ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
+ ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
+ return ok;
}
// Enable or disable tracing of the CPU clock frequency.
}
// Enable tracing in the kernel.
-static bool startTrace()
+static bool startTrace(bool isRoot)
{
bool ok = true;
- // Set up the tracing options.
+ // Set up the tracing options that don't require root.
ok &= setTraceOverwriteEnable(g_traceOverwrite);
ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
ok &= setCpuFrequencyTracingEnable(g_traceCpuFrequency);
if (fileExists(k_governorLoadEnablePath) || g_traceGovernorLoad) {
ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
}
- ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
- ok &= setDiskTracingEnabled(g_traceDisk);
ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
ok &= setGlobalClockEnable(true);
+ // Set up the tracing options that do require root. The options that
+ // require root should have errored out earlier if we're not running as
+ // root.
+ if (isRoot) {
+ ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
+ ok &= setDiskTracingEnabled(g_traceDisk);
+ }
+
// Enable tracing.
ok &= setTracingEnabled(true);
}
// Disable tracing in the kernel.
-static void stopTrace()
+static void stopTrace(bool isRoot)
{
// Disable tracing.
setTracingEnabled(false);
if (fileExists(k_governorLoadEnablePath)) {
setGovernorLoadTracingEnable(false);
}
- setWorkqueueTracingEnabled(false);
setGlobalClockEnable(false);
+ if (isRoot) {
+ setWorkqueueTracingEnabled(false);
+ setDiskTracingEnabled(false);
+ }
+
// Note that we can't reset the trace buffer size here because that would
// clear the trace before we've read it.
}
int main(int argc, char **argv)
{
+ bool isRoot = (getuid() == 0);
+
if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
showHelp(argv[0]);
exit(0);
}
- if (getuid() != 0) {
- fprintf(stderr, "error: %s must be run as root.", argv[0]);
- exit(1);
- }
-
for (;;) {
int ret;
break;
case 'd':
+ if (!isRoot) {
+ fprintf(stderr, "error: tracing disk activity requires root privileges\n");
+ exit(1);
+ }
g_traceDisk = true;
break;
break;
case 'w':
+ if (!isRoot) {
+ fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
+ exit(1);
+ }
g_traceWorkqueue = true;
break;
registerSigHandler();
- bool ok = startTrace();
+ bool ok = startTrace(isRoot);
if (ok) {
printf("capturing trace...");
}
// Stop the trace and restore the default settings.
- stopTrace();
+ stopTrace(isRoot);
if (ok) {
if (!g_traceAborted) {