blob: 64f13e4eb550a11fd0ac3e14cb80b9640a3ab710 [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>
Erik Gilling4edbd072012-11-14 15:11:21 -080019#include <getopt.h>
Jamie Gennisfb31ba62012-02-23 14:16:05 -080020#include <signal.h>
21#include <stdarg.h>
22#include <stdbool.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/sendfile.h>
26#include <time.h>
Jamie Gennis7b5170b2012-04-28 19:06:49 -070027#include <zlib.h>
Jamie Gennisfb31ba62012-02-23 14:16:05 -080028
Jeff Brownac9453d2012-05-22 18:58:46 -070029#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
30
Jamie Gennisfb31ba62012-02-23 14:16:05 -080031/* Command line options */
32static int g_traceDurationSeconds = 5;
33static bool g_traceSchedSwitch = false;
Erik Gilling99be77c2012-09-20 17:55:10 -070034static bool g_traceFrequency = false;
35static bool g_traceBusUtilization = false;
Jamie Gennis31695332012-05-07 17:58:44 -070036static bool g_traceCpuIdle = false;
Jeff Brownac9453d2012-05-22 18:58:46 -070037static bool g_traceDisk = false;
Jamie Genniscc24c8e2012-03-05 19:10:37 -080038static bool g_traceGovernorLoad = false;
Erik Gilling9ba4baf2012-10-17 12:16:01 -070039static bool g_traceSync = false;
Jamie Gennisfb31ba62012-02-23 14:16:05 -080040static bool g_traceWorkqueue = false;
41static bool g_traceOverwrite = false;
Jamie Genniscc24c8e2012-03-05 19:10:37 -080042static int g_traceBufferSizeKB = 2048;
Jamie Gennis7b5170b2012-04-28 19:06:49 -070043static bool g_compress = false;
Glenn Kasten31be80f2012-06-05 16:42:22 -070044static bool g_nohup = false;
45static int g_initialSleepSecs = 0;
Jamie Gennisfb31ba62012-02-23 14:16:05 -080046
47/* Global state */
48static bool g_traceAborted = false;
49
50/* Sys file paths */
51static const char* k_traceClockPath =
52 "/sys/kernel/debug/tracing/trace_clock";
53
Jamie Genniscc24c8e2012-03-05 19:10:37 -080054static const char* k_traceBufferSizePath =
55 "/sys/kernel/debug/tracing/buffer_size_kb";
56
Jamie Gennisfb31ba62012-02-23 14:16:05 -080057static const char* k_tracingOverwriteEnablePath =
58 "/sys/kernel/debug/tracing/options/overwrite";
59
60static const char* k_schedSwitchEnablePath =
61 "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
62
Jamie Gennis4b23eef2012-06-07 16:27:03 -070063static const char* k_schedWakeupEnablePath =
64 "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
65
Erik Gilling99be77c2012-09-20 17:55:10 -070066static const char* k_memoryBusEnablePath =
67 "/sys/kernel/debug/tracing/events/memory_bus/enable";
68
Jamie Genniscc24c8e2012-03-05 19:10:37 -080069static const char* k_cpuFreqEnablePath =
70 "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
71
Erik Gilling99be77c2012-09-20 17:55:10 -070072static const char *k_clockSetRateEnablePath =
73 "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable";
74
Jamie Gennis31695332012-05-07 17:58:44 -070075static const char* k_cpuIdleEnablePath =
76 "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
77
Jamie Genniscc24c8e2012-03-05 19:10:37 -080078static const char* k_governorLoadEnablePath =
79 "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
80
Erik Gilling9ba4baf2012-10-17 12:16:01 -070081static const char* k_syncEnablePath =
82 "/sys/kernel/debug/tracing/events/sync/enable";
83
Jamie Gennisfb31ba62012-02-23 14:16:05 -080084static const char* k_workqueueEnablePath =
85 "/sys/kernel/debug/tracing/events/workqueue/enable";
86
Jeff Brownac9453d2012-05-22 18:58:46 -070087static const char* k_diskEnablePaths[] = {
88 "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
89 "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
90 "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
91 "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
92};
93
Jamie Gennisfb31ba62012-02-23 14:16:05 -080094static const char* k_tracingOnPath =
95 "/sys/kernel/debug/tracing/tracing_on";
96
97static const char* k_tracePath =
98 "/sys/kernel/debug/tracing/trace";
99
100static const char* k_traceMarkerPath =
101 "/sys/kernel/debug/tracing/trace_marker";
102
Jamie Gennise8744fd2012-10-05 16:04:12 -0700103// Check whether a file exists.
104static bool fileExists(const char* filename) {
105 return access(filename, F_OK) != -1;
106}
107
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800108// Write a string to a file, returning true if the write was successful.
109bool writeStr(const char* filename, const char* str)
110{
111 int fd = open(filename, O_WRONLY);
112 if (fd == -1) {
113 fprintf(stderr, "error opening %s: %s (%d)\n", filename,
114 strerror(errno), errno);
115 return false;
116 }
117
118 bool ok = true;
119 ssize_t len = strlen(str);
120 if (write(fd, str, len) != len) {
121 fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
122 strerror(errno), errno);
123 ok = false;
124 }
125
126 close(fd);
127
128 return ok;
129}
130
131// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
132static bool setKernelOptionEnable(const char* filename, bool enable)
133{
134 return writeStr(filename, enable ? "1" : "0");
135}
136
Jeff Brownac9453d2012-05-22 18:58:46 -0700137// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
138static bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
139{
140 bool result = true;
141 for (size_t i = 0; i < count; i++) {
142 result &= setKernelOptionEnable(filenames[i], enable);
143 }
144 return result;
145}
146
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800147// Enable or disable overwriting of the kernel trace buffers. Disabling this
148// will cause tracing to stop once the trace buffers have filled up.
149static bool setTraceOverwriteEnable(bool enable)
150{
151 return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
152}
153
154// Enable or disable tracing of the kernel scheduler switching.
155static bool setSchedSwitchTracingEnable(bool enable)
156{
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700157 bool ok = true;
158 ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
159 ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
160 return ok;
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800161}
162
Erik Gilling99be77c2012-09-20 17:55:10 -0700163// Enable or disable tracing of the Bus utilization.
164static bool setBusUtilizationTracingEnable(bool enable)
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800165{
Jamie Gennise8744fd2012-10-05 16:04:12 -0700166 bool ok = true, oneSet = false;
Erik Gilling99be77c2012-09-20 17:55:10 -0700167 // these can be platform specific so make sure that at least
168 // one succeeds.
Jamie Gennise8744fd2012-10-05 16:04:12 -0700169 if (fileExists(k_memoryBusEnablePath)) {
170 ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable);
171 oneSet |= ok;
172 }
173 return ok && (oneSet || !enable);
Erik Gilling99be77c2012-09-20 17:55:10 -0700174}
175
176// Enable or disable tracing of the CPU clock frequency.
177static bool setFrequencyTracingEnable(bool enable)
178{
179 bool ok = true;
180 ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable);
Jamie Gennise8744fd2012-10-05 16:04:12 -0700181 if (fileExists(k_clockSetRateEnablePath)) {
182 ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable);
183 }
Erik Gilling99be77c2012-09-20 17:55:10 -0700184 return ok;
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800185}
186
Jamie Gennis31695332012-05-07 17:58:44 -0700187// Enable or disable tracing of CPU idle events.
188static bool setCpuIdleTracingEnable(bool enable)
189{
190 return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
191}
192
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800193// Enable or disable tracing of the interactive CPU frequency governor's idea of
194// the CPU load.
195static bool setGovernorLoadTracingEnable(bool enable)
196{
Jamie Gennise8744fd2012-10-05 16:04:12 -0700197 bool ok = true;
198 if (fileExists(k_governorLoadEnablePath) || enable) {
199 ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable);
200 }
201 return ok;
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800202}
203
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700204// Enable or disable tracing of sync timelines and waits.
205static bool setSyncTracingEnabled(bool enable)
206{
207 bool ok = true;
208 if (fileExists(k_syncEnablePath) || enable) {
209 ok &= setKernelOptionEnable(k_syncEnablePath, enable);
210 }
211 return ok;
212}
213
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800214// Enable or disable tracing of the kernel workqueues.
215static bool setWorkqueueTracingEnabled(bool enable)
216{
217 return setKernelOptionEnable(k_workqueueEnablePath, enable);
218}
219
Jeff Brownac9453d2012-05-22 18:58:46 -0700220// Enable or disable tracing of disk I/O.
221static bool setDiskTracingEnabled(bool enable)
222{
223 return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
224}
225
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800226// Enable or disable kernel tracing.
227static bool setTracingEnabled(bool enable)
228{
229 return setKernelOptionEnable(k_tracingOnPath, enable);
230}
231
232// Clear the contents of the kernel trace.
233static bool clearTrace()
234{
235 int traceFD = creat(k_tracePath, 0);
236 if (traceFD == -1) {
237 fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
238 strerror(errno), errno);
239 return false;
240 }
241
242 close(traceFD);
243
244 return true;
245}
246
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800247// Set the size of the kernel's trace buffer in kilobytes.
248static bool setTraceBufferSizeKB(int size)
249{
250 char str[32] = "1";
251 int len;
252 if (size < 1) {
253 size = 1;
254 }
255 snprintf(str, 32, "%d", size);
256 return writeStr(k_traceBufferSizePath, str);
257}
258
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800259// Enable or disable the kernel's use of the global clock. Disabling the global
260// clock will result in the kernel using a per-CPU local clock.
261static bool setGlobalClockEnable(bool enable)
262{
263 return writeStr(k_traceClockPath, enable ? "global" : "local");
264}
265
266// Enable tracing in the kernel.
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700267static bool startTrace(bool isRoot)
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800268{
269 bool ok = true;
270
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700271 // Set up the tracing options that don't require root.
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800272 ok &= setTraceOverwriteEnable(g_traceOverwrite);
273 ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
Erik Gilling99be77c2012-09-20 17:55:10 -0700274 ok &= setFrequencyTracingEnable(g_traceFrequency);
Jamie Gennis31695332012-05-07 17:58:44 -0700275 ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
Jamie Gennise8744fd2012-10-05 16:04:12 -0700276 ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800277 ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800278 ok &= setGlobalClockEnable(true);
279
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700280 // Set up the tracing options that do require root. The options that
281 // require root should have errored out earlier if we're not running as
282 // root.
283 if (isRoot) {
Jamie Gennise8744fd2012-10-05 16:04:12 -0700284 ok &= setBusUtilizationTracingEnable(g_traceBusUtilization);
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700285 ok &= setSyncTracingEnabled(g_traceSync);
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700286 ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
287 ok &= setDiskTracingEnabled(g_traceDisk);
288 }
289
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800290 // Enable tracing.
291 ok &= setTracingEnabled(true);
292
293 if (!ok) {
294 fprintf(stderr, "error: unable to start trace\n");
295 }
296
297 return ok;
298}
299
300// Disable tracing in the kernel.
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700301static void stopTrace(bool isRoot)
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800302{
303 // Disable tracing.
304 setTracingEnabled(false);
305
306 // Set the options back to their defaults.
307 setTraceOverwriteEnable(true);
308 setSchedSwitchTracingEnable(false);
Erik Gilling99be77c2012-09-20 17:55:10 -0700309 setFrequencyTracingEnable(false);
Jamie Gennise8744fd2012-10-05 16:04:12 -0700310 setGovernorLoadTracingEnable(false);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800311 setGlobalClockEnable(false);
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800312
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700313 if (isRoot) {
Jamie Gennise8744fd2012-10-05 16:04:12 -0700314 setBusUtilizationTracingEnable(false);
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700315 setSyncTracingEnabled(false);
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700316 setWorkqueueTracingEnabled(false);
317 setDiskTracingEnabled(false);
318 }
319
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800320 // Note that we can't reset the trace buffer size here because that would
321 // clear the trace before we've read it.
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800322}
323
324// Read the current kernel trace and write it to stdout.
325static void dumpTrace()
326{
327 int traceFD = open(k_tracePath, O_RDWR);
328 if (traceFD == -1) {
329 fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
330 strerror(errno), errno);
331 return;
332 }
333
Jamie Gennis7b5170b2012-04-28 19:06:49 -0700334 if (g_compress) {
335 z_stream zs;
336 uint8_t *in, *out;
337 int result, flush;
338
339 bzero(&zs, sizeof(zs));
340 result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
341 if (result != Z_OK) {
342 fprintf(stderr, "error initializing zlib: %d\n", result);
343 close(traceFD);
344 return;
345 }
346
347 const size_t bufSize = 64*1024;
348 in = (uint8_t*)malloc(bufSize);
349 out = (uint8_t*)malloc(bufSize);
350 flush = Z_NO_FLUSH;
351
352 zs.next_out = out;
353 zs.avail_out = bufSize;
354
355 do {
356
357 if (zs.avail_in == 0) {
358 // More input is needed.
359 result = read(traceFD, in, bufSize);
360 if (result < 0) {
361 fprintf(stderr, "error reading trace: %s (%d)\n",
362 strerror(errno), errno);
363 result = Z_STREAM_END;
364 break;
365 } else if (result == 0) {
366 flush = Z_FINISH;
367 } else {
368 zs.next_in = in;
369 zs.avail_in = result;
370 }
371 }
372
373 if (zs.avail_out == 0) {
374 // Need to write the output.
375 result = write(STDOUT_FILENO, out, bufSize);
376 if ((size_t)result < bufSize) {
377 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
378 strerror(errno), errno);
379 result = Z_STREAM_END; // skip deflate error message
380 zs.avail_out = bufSize; // skip the final write
381 break;
382 }
383 zs.next_out = out;
384 zs.avail_out = bufSize;
385 }
386
387 } while ((result = deflate(&zs, flush)) == Z_OK);
388
389 if (result != Z_STREAM_END) {
390 fprintf(stderr, "error deflating trace: %s\n", zs.msg);
391 }
392
393 if (zs.avail_out < bufSize) {
394 size_t bytes = bufSize - zs.avail_out;
395 result = write(STDOUT_FILENO, out, bytes);
396 if ((size_t)result < bytes) {
397 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
398 strerror(errno), errno);
399 }
400 }
401
402 result = deflateEnd(&zs);
403 if (result != Z_OK) {
404 fprintf(stderr, "error cleaning up zlib: %d\n", result);
405 }
406
407 free(in);
408 free(out);
409 } else {
410 ssize_t sent = 0;
411 while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
412 if (sent == -1) {
413 fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
414 errno);
415 }
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800416 }
417
418 close(traceFD);
419}
420
421// Print the command usage help to stderr.
422static void showHelp(const char *cmd)
423{
424 fprintf(stderr, "usage: %s [options]\n", cmd);
425 fprintf(stderr, "options include:\n"
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800426 " -b N use a trace buffer size of N KB\n"
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800427 " -c trace into a circular buffer\n"
Jeff Brownac9453d2012-05-22 18:58:46 -0700428 " -d trace disk I/O\n"
Erik Gilling99be77c2012-09-20 17:55:10 -0700429 " -f trace clock frequency changes\n"
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800430 " -l trace CPU frequency governor load\n"
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800431 " -s trace the kernel scheduler switches\n"
432 " -t N trace for N seconds [defualt 5]\n"
Erik Gilling99be77c2012-09-20 17:55:10 -0700433 " -u trace bus utilization\n"
Jamie Gennis7b5170b2012-04-28 19:06:49 -0700434 " -w trace the kernel workqueue\n"
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700435 " -y trace sync timelines and waits\n"
Erik Gilling4edbd072012-11-14 15:11:21 -0800436 " -z compress the trace dump\n"
Glenn Kasten9284fdd2012-11-14 16:24:27 -0800437 " --async_start start circular trace and return immediatly\n"
438 " --async_dump dump the current contents of circular trace buffer\n"
439 " --async_stop stop tracing and dump the current contents of circular\n"
440 " trace buffer\n"
Erik Gilling4edbd072012-11-14 15:11:21 -0800441 );
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800442}
443
444static void handleSignal(int signo) {
Glenn Kasten31be80f2012-06-05 16:42:22 -0700445 if (!g_nohup) {
446 g_traceAborted = true;
447 }
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800448}
449
450static void registerSigHandler() {
451 struct sigaction sa;
452 sigemptyset(&sa.sa_mask);
453 sa.sa_flags = 0;
454 sa.sa_handler = handleSignal;
455 sigaction(SIGHUP, &sa, NULL);
456 sigaction(SIGINT, &sa, NULL);
457 sigaction(SIGQUIT, &sa, NULL);
458 sigaction(SIGTERM, &sa, NULL);
459}
460
461int main(int argc, char **argv)
462{
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700463 bool isRoot = (getuid() == 0);
Erik Gilling4edbd072012-11-14 15:11:21 -0800464 bool async = false;
465 bool traceStart = true;
466 bool traceStop = true;
467 bool traceDump = true;
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700468
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800469 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
470 showHelp(argv[0]);
471 exit(0);
472 }
473
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800474 for (;;) {
475 int ret;
Erik Gilling4edbd072012-11-14 15:11:21 -0800476 int option_index = 0;
477 static struct option long_options[] = {
478 {"async_start", no_argument, 0, 0 },
479 {"async_stop", no_argument, 0, 0 },
480 {"async_dump", no_argument, 0, 0 },
481 {0, 0, 0, 0 }
482 };
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800483
Erik Gilling4edbd072012-11-14 15:11:21 -0800484 ret = getopt_long(argc, argv, "b:cidflst:uwyznS:",
485 long_options, &option_index);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800486
487 if (ret < 0) {
488 break;
489 }
490
491 switch(ret) {
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800492 case 'b':
493 g_traceBufferSizeKB = atoi(optarg);
494 break;
495
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800496 case 'c':
497 g_traceOverwrite = true;
498 break;
499
Jamie Gennis31695332012-05-07 17:58:44 -0700500 case 'i':
501 g_traceCpuIdle = true;
502 break;
503
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800504 case 'l':
505 g_traceGovernorLoad = true;
506 break;
507
Jeff Brownac9453d2012-05-22 18:58:46 -0700508 case 'd':
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700509 if (!isRoot) {
510 fprintf(stderr, "error: tracing disk activity requires root privileges\n");
511 exit(1);
512 }
Jeff Brownac9453d2012-05-22 18:58:46 -0700513 g_traceDisk = true;
514 break;
515
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800516 case 'f':
Erik Gilling99be77c2012-09-20 17:55:10 -0700517 g_traceFrequency = true;
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800518 break;
519
Glenn Kasten31be80f2012-06-05 16:42:22 -0700520 case 'n':
521 g_nohup = true;
522 break;
523
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800524 case 's':
525 g_traceSchedSwitch = true;
526 break;
527
Glenn Kasten31be80f2012-06-05 16:42:22 -0700528 case 'S':
529 g_initialSleepSecs = atoi(optarg);
530 break;
531
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800532 case 't':
533 g_traceDurationSeconds = atoi(optarg);
534 break;
535
Erik Gilling99be77c2012-09-20 17:55:10 -0700536 case 'u':
537 if (!isRoot) {
538 fprintf(stderr, "error: tracing bus utilization requires root privileges\n");
539 exit(1);
540 }
541 g_traceBusUtilization = true;
542 break;
543
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800544 case 'w':
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700545 if (!isRoot) {
546 fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
547 exit(1);
548 }
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800549 g_traceWorkqueue = true;
550 break;
551
Erik Gilling9ba4baf2012-10-17 12:16:01 -0700552 case 'y':
553 if (!isRoot) {
554 fprintf(stderr, "error: tracing sync requires root privileges\n");
555 exit(1);
556 }
557 g_traceSync = true;
558 break;
559
Jamie Gennis7b5170b2012-04-28 19:06:49 -0700560 case 'z':
561 g_compress = true;
562 break;
563
Erik Gilling4edbd072012-11-14 15:11:21 -0800564 case 0:
565 if (!strcmp(long_options[option_index].name, "async_start")) {
566 async = true;
567 traceStop = false;
568 traceDump = false;
569 g_traceOverwrite = true;
570 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
571 async = true;
572 traceStop = false;
573 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
574 async = true;
575 traceStart = false;
576 traceStop = false;
577 }
578 break;
579
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800580 default:
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800581 fprintf(stderr, "\n");
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800582 showHelp(argv[0]);
583 exit(-1);
584 break;
585 }
586 }
587
588 registerSigHandler();
589
Glenn Kasten31be80f2012-06-05 16:42:22 -0700590 if (g_initialSleepSecs > 0) {
591 sleep(g_initialSleepSecs);
592 }
593
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700594 bool ok = startTrace(isRoot);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800595
Erik Gilling4edbd072012-11-14 15:11:21 -0800596 if (ok && traceStart) {
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800597 printf("capturing trace...");
598 fflush(stdout);
599
600 // We clear the trace after starting it because tracing gets enabled for
601 // each CPU individually in the kernel. Having the beginning of the trace
602 // contain entries from only one CPU can cause "begin" entries without a
603 // matching "end" entry to show up if a task gets migrated from one CPU to
604 // another.
605 ok = clearTrace();
606
Erik Gilling4edbd072012-11-14 15:11:21 -0800607 if (ok && !async) {
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800608 // Sleep to allow the trace to be captured.
609 struct timespec timeLeft;
610 timeLeft.tv_sec = g_traceDurationSeconds;
611 timeLeft.tv_nsec = 0;
612 do {
613 if (g_traceAborted) {
614 break;
615 }
616 } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
617 }
618 }
619
620 // Stop the trace and restore the default settings.
Erik Gilling4edbd072012-11-14 15:11:21 -0800621 if (traceStop)
622 stopTrace(isRoot);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800623
Erik Gilling4edbd072012-11-14 15:11:21 -0800624 if (ok && traceDump) {
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800625 if (!g_traceAborted) {
626 printf(" done\nTRACE:\n");
627 fflush(stdout);
628 dumpTrace();
629 } else {
630 printf("\ntrace aborted.\n");
631 fflush(stdout);
632 }
633 clearTrace();
Erik Gilling4edbd072012-11-14 15:11:21 -0800634 } else if (!ok) {
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800635 fprintf(stderr, "unable to start tracing\n");
636 }
637
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800638 // Reset the trace buffer size to 1.
Erik Gilling4edbd072012-11-14 15:11:21 -0800639 if (traceStop)
640 setTraceBufferSizeKB(1);
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800641
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800642 return g_traceAborted ? 1 : 0;
643}