blob: 2d9b4f84fec8ff8d3ccbba21cf09261d29ea698a [file] [log] [blame]
Jamie Gennisfb31ba62012-02-23 14:16:05 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <errno.h>
18#include <fcntl.h>
19#include <signal.h>
20#include <stdarg.h>
21#include <stdbool.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <sys/sendfile.h>
25#include <time.h>
Jamie Gennis7b5170b2012-04-28 19:06:49 -070026#include <zlib.h>
Jamie Gennisfb31ba62012-02-23 14:16:05 -080027
Jeff Brownac9453d2012-05-22 18:58:46 -070028#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
29
Jamie Gennisfb31ba62012-02-23 14:16:05 -080030/* Command line options */
31static int g_traceDurationSeconds = 5;
32static bool g_traceSchedSwitch = false;
Erik Gilling99be77c2012-09-20 17:55:10 -070033static bool g_traceFrequency = false;
34static bool g_traceBusUtilization = false;
Jamie Gennis31695332012-05-07 17:58:44 -070035static bool g_traceCpuIdle = false;
Jeff Brownac9453d2012-05-22 18:58:46 -070036static bool g_traceDisk = false;
Jamie Genniscc24c8e2012-03-05 19:10:37 -080037static bool g_traceGovernorLoad = false;
Erik Gilling9ba4baf2012-10-17 12:16:01 -070038static bool g_traceSync = false;
Jamie Gennisfb31ba62012-02-23 14:16:05 -080039static bool g_traceWorkqueue = false;
40static bool g_traceOverwrite = false;
Jamie Genniscc24c8e2012-03-05 19:10:37 -080041static int g_traceBufferSizeKB = 2048;
Jamie Gennis7b5170b2012-04-28 19:06:49 -070042static bool g_compress = false;
Glenn Kasten31be80f2012-06-05 16:42:22 -070043static bool g_nohup = false;
44static int g_initialSleepSecs = 0;
Jamie Gennisfb31ba62012-02-23 14:16:05 -080045
46/* Global state */
47static bool g_traceAborted = false;
48
49/* Sys file paths */
50static const char* k_traceClockPath =
51 "/sys/kernel/debug/tracing/trace_clock";
52
Jamie Genniscc24c8e2012-03-05 19:10:37 -080053static const char* k_traceBufferSizePath =
54 "/sys/kernel/debug/tracing/buffer_size_kb";
55
Jamie Gennisfb31ba62012-02-23 14:16:05 -080056static const char* k_tracingOverwriteEnablePath =
57 "/sys/kernel/debug/tracing/options/overwrite";
58
59static const char* k_schedSwitchEnablePath =
60 "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
61
Jamie Gennis4b23eef2012-06-07 16:27:03 -070062static const char* k_schedWakeupEnablePath =
63 "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
64
Erik Gilling99be77c2012-09-20 17:55:10 -070065static const char* k_memoryBusEnablePath =
66 "/sys/kernel/debug/tracing/events/memory_bus/enable";
67
Jamie Genniscc24c8e2012-03-05 19:10:37 -080068static const char* k_cpuFreqEnablePath =
69 "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
70
Erik Gilling99be77c2012-09-20 17:55:10 -070071static const char *k_clockSetRateEnablePath =
72 "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable";
73
Jamie Gennis31695332012-05-07 17:58:44 -070074static const char* k_cpuIdleEnablePath =
75 "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
76
Jamie Genniscc24c8e2012-03-05 19:10:37 -080077static const char* k_governorLoadEnablePath =
78 "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
79
Erik Gilling9ba4baf2012-10-17 12:16:01 -070080static const char* k_syncEnablePath =
81 "/sys/kernel/debug/tracing/events/sync/enable";
82
Jamie Gennisfb31ba62012-02-23 14:16:05 -080083static const char* k_workqueueEnablePath =
84 "/sys/kernel/debug/tracing/events/workqueue/enable";
85
Jeff Brownac9453d2012-05-22 18:58:46 -070086static const char* k_diskEnablePaths[] = {
87 "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
88 "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
89 "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
90 "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
91};
92
Jamie Gennisfb31ba62012-02-23 14:16:05 -080093static const char* k_tracingOnPath =
94 "/sys/kernel/debug/tracing/tracing_on";
95
96static const char* k_tracePath =
97 "/sys/kernel/debug/tracing/trace";
98
99static const char* k_traceMarkerPath =
100 "/sys/kernel/debug/tracing/trace_marker";
101
Jamie Gennise8744fd2012-10-05 16:04:12 -0700102// Check whether a file exists.
103static bool fileExists(const char* filename) {
104 return access(filename, F_OK) != -1;
105}
106
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800107// Write a string to a file, returning true if the write was successful.
108bool writeStr(const char* filename, const char* str)
109{
110 int fd = open(filename, O_WRONLY);
111 if (fd == -1) {
112 fprintf(stderr, "error opening %s: %s (%d)\n", filename,
113 strerror(errno), errno);
114 return false;
115 }
116
117 bool ok = true;
118 ssize_t len = strlen(str);
119 if (write(fd, str, len) != len) {
120 fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
121 strerror(errno), errno);
122 ok = false;
123 }
124
125 close(fd);
126
127 return ok;
128}
129
130// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
131static bool setKernelOptionEnable(const char* filename, bool enable)
132{
133 return writeStr(filename, enable ? "1" : "0");
134}
135
Jeff Brownac9453d2012-05-22 18:58:46 -0700136// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
137static bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
138{
139 bool result = true;
140 for (size_t i = 0; i < count; i++) {
141 result &= setKernelOptionEnable(filenames[i], enable);
142 }
143 return result;
144}
145
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800146// Enable or disable overwriting of the kernel trace buffers. Disabling this
147// will cause tracing to stop once the trace buffers have filled up.
148static bool setTraceOverwriteEnable(bool enable)
149{
150 return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
151}
152
153// Enable or disable tracing of the kernel scheduler switching.
154static bool setSchedSwitchTracingEnable(bool enable)
155{
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700156 bool ok = true;
157 ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
158 ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
159 return ok;
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800160}
161
Erik Gilling99be77c2012-09-20 17:55:10 -0700162// Enable or disable tracing of the Bus utilization.
163static bool setBusUtilizationTracingEnable(bool enable)
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800164{
Jamie Gennise8744fd2012-10-05 16:04:12 -0700165 bool ok = true, oneSet = false;
Erik Gilling99be77c2012-09-20 17:55:10 -0700166 // these can be platform specific so make sure that at least
167 // one succeeds.
Jamie Gennise8744fd2012-10-05 16:04:12 -0700168 if (fileExists(k_memoryBusEnablePath)) {
169 ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable);
170 oneSet |= ok;
171 }
172 return ok && (oneSet || !enable);
Erik Gilling99be77c2012-09-20 17:55:10 -0700173}
174
175// Enable or disable tracing of the CPU clock frequency.
176static bool setFrequencyTracingEnable(bool enable)
177{
178 bool ok = true;
179 ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable);
Jamie Gennise8744fd2012-10-05 16:04:12 -0700180 if (fileExists(k_clockSetRateEnablePath)) {
181 ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable);
182 }
Erik Gilling99be77c2012-09-20 17:55:10 -0700183 return ok;
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800184}
185
Jamie Gennis31695332012-05-07 17:58:44 -0700186// Enable or disable tracing of CPU idle events.
187static bool setCpuIdleTracingEnable(bool enable)
188{
189 return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
190}
191
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800192// Enable or disable tracing of the interactive CPU frequency governor's idea of
193// the CPU load.
194static bool setGovernorLoadTracingEnable(bool enable)
195{
Jamie Gennise8744fd2012-10-05 16:04:12 -0700196 bool ok = true;
197 if (fileExists(k_governorLoadEnablePath) || enable) {
198 ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable);
199 }
200 return ok;
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800201}
202
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700203// Enable or disable tracing of sync timelines and waits.
204static bool setSyncTracingEnabled(bool enable)
205{
206 bool ok = true;
207 if (fileExists(k_syncEnablePath) || enable) {
208 ok &= setKernelOptionEnable(k_syncEnablePath, enable);
209 }
210 return ok;
211}
212
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800213// Enable or disable tracing of the kernel workqueues.
214static bool setWorkqueueTracingEnabled(bool enable)
215{
216 return setKernelOptionEnable(k_workqueueEnablePath, enable);
217}
218
Jeff Brownac9453d2012-05-22 18:58:46 -0700219// Enable or disable tracing of disk I/O.
220static bool setDiskTracingEnabled(bool enable)
221{
222 return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
223}
224
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800225// Enable or disable kernel tracing.
226static bool setTracingEnabled(bool enable)
227{
228 return setKernelOptionEnable(k_tracingOnPath, enable);
229}
230
231// Clear the contents of the kernel trace.
232static bool clearTrace()
233{
234 int traceFD = creat(k_tracePath, 0);
235 if (traceFD == -1) {
236 fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
237 strerror(errno), errno);
238 return false;
239 }
240
241 close(traceFD);
242
243 return true;
244}
245
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800246// Set the size of the kernel's trace buffer in kilobytes.
247static bool setTraceBufferSizeKB(int size)
248{
249 char str[32] = "1";
250 int len;
251 if (size < 1) {
252 size = 1;
253 }
254 snprintf(str, 32, "%d", size);
255 return writeStr(k_traceBufferSizePath, str);
256}
257
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800258// Enable or disable the kernel's use of the global clock. Disabling the global
259// clock will result in the kernel using a per-CPU local clock.
260static bool setGlobalClockEnable(bool enable)
261{
262 return writeStr(k_traceClockPath, enable ? "global" : "local");
263}
264
265// Enable tracing in the kernel.
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700266static bool startTrace(bool isRoot)
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800267{
268 bool ok = true;
269
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700270 // Set up the tracing options that don't require root.
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800271 ok &= setTraceOverwriteEnable(g_traceOverwrite);
272 ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
Erik Gilling99be77c2012-09-20 17:55:10 -0700273 ok &= setFrequencyTracingEnable(g_traceFrequency);
Jamie Gennis31695332012-05-07 17:58:44 -0700274 ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
Jamie Gennise8744fd2012-10-05 16:04:12 -0700275 ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800276 ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800277 ok &= setGlobalClockEnable(true);
278
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700279 // Set up the tracing options that do require root. The options that
280 // require root should have errored out earlier if we're not running as
281 // root.
282 if (isRoot) {
Jamie Gennise8744fd2012-10-05 16:04:12 -0700283 ok &= setBusUtilizationTracingEnable(g_traceBusUtilization);
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700284 ok &= setSyncTracingEnabled(g_traceSync);
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700285 ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
286 ok &= setDiskTracingEnabled(g_traceDisk);
287 }
288
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800289 // Enable tracing.
290 ok &= setTracingEnabled(true);
291
292 if (!ok) {
293 fprintf(stderr, "error: unable to start trace\n");
294 }
295
296 return ok;
297}
298
299// Disable tracing in the kernel.
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700300static void stopTrace(bool isRoot)
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800301{
302 // Disable tracing.
303 setTracingEnabled(false);
304
305 // Set the options back to their defaults.
306 setTraceOverwriteEnable(true);
307 setSchedSwitchTracingEnable(false);
Erik Gilling99be77c2012-09-20 17:55:10 -0700308 setFrequencyTracingEnable(false);
Jamie Gennise8744fd2012-10-05 16:04:12 -0700309 setGovernorLoadTracingEnable(false);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800310 setGlobalClockEnable(false);
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800311
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700312 if (isRoot) {
Jamie Gennise8744fd2012-10-05 16:04:12 -0700313 setBusUtilizationTracingEnable(false);
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700314 setSyncTracingEnabled(false);
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700315 setWorkqueueTracingEnabled(false);
316 setDiskTracingEnabled(false);
317 }
318
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800319 // Note that we can't reset the trace buffer size here because that would
320 // clear the trace before we've read it.
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800321}
322
323// Read the current kernel trace and write it to stdout.
324static void dumpTrace()
325{
326 int traceFD = open(k_tracePath, O_RDWR);
327 if (traceFD == -1) {
328 fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
329 strerror(errno), errno);
330 return;
331 }
332
Jamie Gennis7b5170b2012-04-28 19:06:49 -0700333 if (g_compress) {
334 z_stream zs;
335 uint8_t *in, *out;
336 int result, flush;
337
338 bzero(&zs, sizeof(zs));
339 result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
340 if (result != Z_OK) {
341 fprintf(stderr, "error initializing zlib: %d\n", result);
342 close(traceFD);
343 return;
344 }
345
346 const size_t bufSize = 64*1024;
347 in = (uint8_t*)malloc(bufSize);
348 out = (uint8_t*)malloc(bufSize);
349 flush = Z_NO_FLUSH;
350
351 zs.next_out = out;
352 zs.avail_out = bufSize;
353
354 do {
355
356 if (zs.avail_in == 0) {
357 // More input is needed.
358 result = read(traceFD, in, bufSize);
359 if (result < 0) {
360 fprintf(stderr, "error reading trace: %s (%d)\n",
361 strerror(errno), errno);
362 result = Z_STREAM_END;
363 break;
364 } else if (result == 0) {
365 flush = Z_FINISH;
366 } else {
367 zs.next_in = in;
368 zs.avail_in = result;
369 }
370 }
371
372 if (zs.avail_out == 0) {
373 // Need to write the output.
374 result = write(STDOUT_FILENO, out, bufSize);
375 if ((size_t)result < bufSize) {
376 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
377 strerror(errno), errno);
378 result = Z_STREAM_END; // skip deflate error message
379 zs.avail_out = bufSize; // skip the final write
380 break;
381 }
382 zs.next_out = out;
383 zs.avail_out = bufSize;
384 }
385
386 } while ((result = deflate(&zs, flush)) == Z_OK);
387
388 if (result != Z_STREAM_END) {
389 fprintf(stderr, "error deflating trace: %s\n", zs.msg);
390 }
391
392 if (zs.avail_out < bufSize) {
393 size_t bytes = bufSize - zs.avail_out;
394 result = write(STDOUT_FILENO, out, bytes);
395 if ((size_t)result < bytes) {
396 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
397 strerror(errno), errno);
398 }
399 }
400
401 result = deflateEnd(&zs);
402 if (result != Z_OK) {
403 fprintf(stderr, "error cleaning up zlib: %d\n", result);
404 }
405
406 free(in);
407 free(out);
408 } else {
409 ssize_t sent = 0;
410 while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
411 if (sent == -1) {
412 fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
413 errno);
414 }
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800415 }
416
417 close(traceFD);
418}
419
420// Print the command usage help to stderr.
421static void showHelp(const char *cmd)
422{
423 fprintf(stderr, "usage: %s [options]\n", cmd);
424 fprintf(stderr, "options include:\n"
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800425 " -b N use a trace buffer size of N KB\n"
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800426 " -c trace into a circular buffer\n"
Jeff Brownac9453d2012-05-22 18:58:46 -0700427 " -d trace disk I/O\n"
Erik Gilling99be77c2012-09-20 17:55:10 -0700428 " -f trace clock frequency changes\n"
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800429 " -l trace CPU frequency governor load\n"
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800430 " -s trace the kernel scheduler switches\n"
431 " -t N trace for N seconds [defualt 5]\n"
Erik Gilling99be77c2012-09-20 17:55:10 -0700432 " -u trace bus utilization\n"
Jamie Gennis7b5170b2012-04-28 19:06:49 -0700433 " -w trace the kernel workqueue\n"
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700434 " -y trace sync timelines and waits\n"
Jamie Gennis7b5170b2012-04-28 19:06:49 -0700435 " -z compress the trace dump\n");
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800436}
437
438static void handleSignal(int signo) {
Glenn Kasten31be80f2012-06-05 16:42:22 -0700439 if (!g_nohup) {
440 g_traceAborted = true;
441 }
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800442}
443
444static void registerSigHandler() {
445 struct sigaction sa;
446 sigemptyset(&sa.sa_mask);
447 sa.sa_flags = 0;
448 sa.sa_handler = handleSignal;
449 sigaction(SIGHUP, &sa, NULL);
450 sigaction(SIGINT, &sa, NULL);
451 sigaction(SIGQUIT, &sa, NULL);
452 sigaction(SIGTERM, &sa, NULL);
453}
454
455int main(int argc, char **argv)
456{
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700457 bool isRoot = (getuid() == 0);
458
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800459 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
460 showHelp(argv[0]);
461 exit(0);
462 }
463
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800464 for (;;) {
465 int ret;
466
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700467 ret = getopt(argc, argv, "b:cidflst:uwyznS:");
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800468
469 if (ret < 0) {
470 break;
471 }
472
473 switch(ret) {
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800474 case 'b':
475 g_traceBufferSizeKB = atoi(optarg);
476 break;
477
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800478 case 'c':
479 g_traceOverwrite = true;
480 break;
481
Jamie Gennis31695332012-05-07 17:58:44 -0700482 case 'i':
483 g_traceCpuIdle = true;
484 break;
485
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800486 case 'l':
487 g_traceGovernorLoad = true;
488 break;
489
Jeff Brownac9453d2012-05-22 18:58:46 -0700490 case 'd':
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700491 if (!isRoot) {
492 fprintf(stderr, "error: tracing disk activity requires root privileges\n");
493 exit(1);
494 }
Jeff Brownac9453d2012-05-22 18:58:46 -0700495 g_traceDisk = true;
496 break;
497
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800498 case 'f':
Erik Gilling99be77c2012-09-20 17:55:10 -0700499 g_traceFrequency = true;
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800500 break;
501
Glenn Kasten31be80f2012-06-05 16:42:22 -0700502 case 'n':
503 g_nohup = true;
504 break;
505
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800506 case 's':
507 g_traceSchedSwitch = true;
508 break;
509
Glenn Kasten31be80f2012-06-05 16:42:22 -0700510 case 'S':
511 g_initialSleepSecs = atoi(optarg);
512 break;
513
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800514 case 't':
515 g_traceDurationSeconds = atoi(optarg);
516 break;
517
Erik Gilling99be77c2012-09-20 17:55:10 -0700518 case 'u':
519 if (!isRoot) {
520 fprintf(stderr, "error: tracing bus utilization requires root privileges\n");
521 exit(1);
522 }
523 g_traceBusUtilization = true;
524 break;
525
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800526 case 'w':
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700527 if (!isRoot) {
528 fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
529 exit(1);
530 }
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800531 g_traceWorkqueue = true;
532 break;
533
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700534 case 'y':
535 if (!isRoot) {
536 fprintf(stderr, "error: tracing sync requires root privileges\n");
537 exit(1);
538 }
539 g_traceSync = true;
540 break;
541
Jamie Gennis7b5170b2012-04-28 19:06:49 -0700542 case 'z':
543 g_compress = true;
544 break;
545
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800546 default:
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800547 fprintf(stderr, "\n");
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800548 showHelp(argv[0]);
549 exit(-1);
550 break;
551 }
552 }
553
554 registerSigHandler();
555
Glenn Kasten31be80f2012-06-05 16:42:22 -0700556 if (g_initialSleepSecs > 0) {
557 sleep(g_initialSleepSecs);
558 }
559
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700560 bool ok = startTrace(isRoot);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800561
562 if (ok) {
563 printf("capturing trace...");
564 fflush(stdout);
565
566 // We clear the trace after starting it because tracing gets enabled for
567 // each CPU individually in the kernel. Having the beginning of the trace
568 // contain entries from only one CPU can cause "begin" entries without a
569 // matching "end" entry to show up if a task gets migrated from one CPU to
570 // another.
571 ok = clearTrace();
572
573 if (ok) {
574 // Sleep to allow the trace to be captured.
575 struct timespec timeLeft;
576 timeLeft.tv_sec = g_traceDurationSeconds;
577 timeLeft.tv_nsec = 0;
578 do {
579 if (g_traceAborted) {
580 break;
581 }
582 } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
583 }
584 }
585
586 // Stop the trace and restore the default settings.
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700587 stopTrace(isRoot);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800588
589 if (ok) {
590 if (!g_traceAborted) {
591 printf(" done\nTRACE:\n");
592 fflush(stdout);
593 dumpTrace();
594 } else {
595 printf("\ntrace aborted.\n");
596 fflush(stdout);
597 }
598 clearTrace();
599 } else {
600 fprintf(stderr, "unable to start tracing\n");
601 }
602
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800603 // Reset the trace buffer size to 1.
604 setTraceBufferSizeKB(1);
605
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800606 return g_traceAborted ? 1 : 0;
607}