blob: 890165af856becc24e500c7f9a73fb9bf9be1bde [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;
Jamie Gennisfb31ba62012-02-23 14:16:05 -080038static bool g_traceWorkqueue = false;
39static bool g_traceOverwrite = false;
Jamie Genniscc24c8e2012-03-05 19:10:37 -080040static int g_traceBufferSizeKB = 2048;
Jamie Gennis7b5170b2012-04-28 19:06:49 -070041static bool g_compress = false;
Glenn Kasten31be80f2012-06-05 16:42:22 -070042static bool g_nohup = false;
43static int g_initialSleepSecs = 0;
Jamie Gennisfb31ba62012-02-23 14:16:05 -080044
45/* Global state */
46static bool g_traceAborted = false;
47
48/* Sys file paths */
49static const char* k_traceClockPath =
50 "/sys/kernel/debug/tracing/trace_clock";
51
Jamie Genniscc24c8e2012-03-05 19:10:37 -080052static const char* k_traceBufferSizePath =
53 "/sys/kernel/debug/tracing/buffer_size_kb";
54
Jamie Gennisfb31ba62012-02-23 14:16:05 -080055static const char* k_tracingOverwriteEnablePath =
56 "/sys/kernel/debug/tracing/options/overwrite";
57
58static const char* k_schedSwitchEnablePath =
59 "/sys/kernel/debug/tracing/events/sched/sched_switch/enable";
60
Jamie Gennis4b23eef2012-06-07 16:27:03 -070061static const char* k_schedWakeupEnablePath =
62 "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable";
63
Erik Gilling99be77c2012-09-20 17:55:10 -070064static const char* k_memoryBusEnablePath =
65 "/sys/kernel/debug/tracing/events/memory_bus/enable";
66
Jamie Genniscc24c8e2012-03-05 19:10:37 -080067static const char* k_cpuFreqEnablePath =
68 "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable";
69
Erik Gilling99be77c2012-09-20 17:55:10 -070070static const char *k_clockSetRateEnablePath =
71 "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable";
72
Jamie Gennis31695332012-05-07 17:58:44 -070073static const char* k_cpuIdleEnablePath =
74 "/sys/kernel/debug/tracing/events/power/cpu_idle/enable";
75
Jamie Genniscc24c8e2012-03-05 19:10:37 -080076static const char* k_governorLoadEnablePath =
77 "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable";
78
Jamie Gennisfb31ba62012-02-23 14:16:05 -080079static const char* k_workqueueEnablePath =
80 "/sys/kernel/debug/tracing/events/workqueue/enable";
81
Jeff Brownac9453d2012-05-22 18:58:46 -070082static const char* k_diskEnablePaths[] = {
83 "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable",
84 "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable",
85 "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable",
86 "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable",
87};
88
Jamie Gennisfb31ba62012-02-23 14:16:05 -080089static const char* k_tracingOnPath =
90 "/sys/kernel/debug/tracing/tracing_on";
91
92static const char* k_tracePath =
93 "/sys/kernel/debug/tracing/trace";
94
95static const char* k_traceMarkerPath =
96 "/sys/kernel/debug/tracing/trace_marker";
97
Jamie Gennise8744fd2012-10-05 16:04:12 -070098// Check whether a file exists.
99static bool fileExists(const char* filename) {
100 return access(filename, F_OK) != -1;
101}
102
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800103// Write a string to a file, returning true if the write was successful.
104bool writeStr(const char* filename, const char* str)
105{
106 int fd = open(filename, O_WRONLY);
107 if (fd == -1) {
108 fprintf(stderr, "error opening %s: %s (%d)\n", filename,
109 strerror(errno), errno);
110 return false;
111 }
112
113 bool ok = true;
114 ssize_t len = strlen(str);
115 if (write(fd, str, len) != len) {
116 fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
117 strerror(errno), errno);
118 ok = false;
119 }
120
121 close(fd);
122
123 return ok;
124}
125
126// Enable or disable a kernel option by writing a "1" or a "0" into a /sys file.
127static bool setKernelOptionEnable(const char* filename, bool enable)
128{
129 return writeStr(filename, enable ? "1" : "0");
130}
131
Jeff Brownac9453d2012-05-22 18:58:46 -0700132// Enable or disable a collection of kernel options by writing a "1" or a "0" into each /sys file.
133static bool setMultipleKernelOptionsEnable(const char** filenames, size_t count, bool enable)
134{
135 bool result = true;
136 for (size_t i = 0; i < count; i++) {
137 result &= setKernelOptionEnable(filenames[i], enable);
138 }
139 return result;
140}
141
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800142// Enable or disable overwriting of the kernel trace buffers. Disabling this
143// will cause tracing to stop once the trace buffers have filled up.
144static bool setTraceOverwriteEnable(bool enable)
145{
146 return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
147}
148
149// Enable or disable tracing of the kernel scheduler switching.
150static bool setSchedSwitchTracingEnable(bool enable)
151{
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700152 bool ok = true;
153 ok &= setKernelOptionEnable(k_schedSwitchEnablePath, enable);
154 ok &= setKernelOptionEnable(k_schedWakeupEnablePath, enable);
155 return ok;
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800156}
157
Erik Gilling99be77c2012-09-20 17:55:10 -0700158// Enable or disable tracing of the Bus utilization.
159static bool setBusUtilizationTracingEnable(bool enable)
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800160{
Jamie Gennise8744fd2012-10-05 16:04:12 -0700161 bool ok = true, oneSet = false;
Erik Gilling99be77c2012-09-20 17:55:10 -0700162 // these can be platform specific so make sure that at least
163 // one succeeds.
Jamie Gennise8744fd2012-10-05 16:04:12 -0700164 if (fileExists(k_memoryBusEnablePath)) {
165 ok &= setKernelOptionEnable(k_memoryBusEnablePath, enable);
166 oneSet |= ok;
167 }
168 return ok && (oneSet || !enable);
Erik Gilling99be77c2012-09-20 17:55:10 -0700169}
170
171// Enable or disable tracing of the CPU clock frequency.
172static bool setFrequencyTracingEnable(bool enable)
173{
174 bool ok = true;
175 ok &= setKernelOptionEnable(k_cpuFreqEnablePath, enable);
Jamie Gennise8744fd2012-10-05 16:04:12 -0700176 if (fileExists(k_clockSetRateEnablePath)) {
177 ok &= setKernelOptionEnable(k_clockSetRateEnablePath, enable);
178 }
Erik Gilling99be77c2012-09-20 17:55:10 -0700179 return ok;
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800180}
181
Jamie Gennis31695332012-05-07 17:58:44 -0700182// Enable or disable tracing of CPU idle events.
183static bool setCpuIdleTracingEnable(bool enable)
184{
185 return setKernelOptionEnable(k_cpuIdleEnablePath, enable);
186}
187
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800188// Enable or disable tracing of the interactive CPU frequency governor's idea of
189// the CPU load.
190static bool setGovernorLoadTracingEnable(bool enable)
191{
Jamie Gennise8744fd2012-10-05 16:04:12 -0700192 bool ok = true;
193 if (fileExists(k_governorLoadEnablePath) || enable) {
194 ok &= setKernelOptionEnable(k_governorLoadEnablePath, enable);
195 }
196 return ok;
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800197}
198
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800199// Enable or disable tracing of the kernel workqueues.
200static bool setWorkqueueTracingEnabled(bool enable)
201{
202 return setKernelOptionEnable(k_workqueueEnablePath, enable);
203}
204
Jeff Brownac9453d2012-05-22 18:58:46 -0700205// Enable or disable tracing of disk I/O.
206static bool setDiskTracingEnabled(bool enable)
207{
208 return setMultipleKernelOptionsEnable(k_diskEnablePaths, NELEM(k_diskEnablePaths), enable);
209}
210
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800211// Enable or disable kernel tracing.
212static bool setTracingEnabled(bool enable)
213{
214 return setKernelOptionEnable(k_tracingOnPath, enable);
215}
216
217// Clear the contents of the kernel trace.
218static bool clearTrace()
219{
220 int traceFD = creat(k_tracePath, 0);
221 if (traceFD == -1) {
222 fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
223 strerror(errno), errno);
224 return false;
225 }
226
227 close(traceFD);
228
229 return true;
230}
231
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800232// Set the size of the kernel's trace buffer in kilobytes.
233static bool setTraceBufferSizeKB(int size)
234{
235 char str[32] = "1";
236 int len;
237 if (size < 1) {
238 size = 1;
239 }
240 snprintf(str, 32, "%d", size);
241 return writeStr(k_traceBufferSizePath, str);
242}
243
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800244// Enable or disable the kernel's use of the global clock. Disabling the global
245// clock will result in the kernel using a per-CPU local clock.
246static bool setGlobalClockEnable(bool enable)
247{
248 return writeStr(k_traceClockPath, enable ? "global" : "local");
249}
250
251// Enable tracing in the kernel.
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700252static bool startTrace(bool isRoot)
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800253{
254 bool ok = true;
255
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700256 // Set up the tracing options that don't require root.
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800257 ok &= setTraceOverwriteEnable(g_traceOverwrite);
258 ok &= setSchedSwitchTracingEnable(g_traceSchedSwitch);
Erik Gilling99be77c2012-09-20 17:55:10 -0700259 ok &= setFrequencyTracingEnable(g_traceFrequency);
Jamie Gennis31695332012-05-07 17:58:44 -0700260 ok &= setCpuIdleTracingEnable(g_traceCpuIdle);
Jamie Gennise8744fd2012-10-05 16:04:12 -0700261 ok &= setGovernorLoadTracingEnable(g_traceGovernorLoad);
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800262 ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800263 ok &= setGlobalClockEnable(true);
264
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700265 // Set up the tracing options that do require root. The options that
266 // require root should have errored out earlier if we're not running as
267 // root.
268 if (isRoot) {
Jamie Gennise8744fd2012-10-05 16:04:12 -0700269 ok &= setBusUtilizationTracingEnable(g_traceBusUtilization);
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700270 ok &= setWorkqueueTracingEnabled(g_traceWorkqueue);
271 ok &= setDiskTracingEnabled(g_traceDisk);
272 }
273
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800274 // Enable tracing.
275 ok &= setTracingEnabled(true);
276
277 if (!ok) {
278 fprintf(stderr, "error: unable to start trace\n");
279 }
280
281 return ok;
282}
283
284// Disable tracing in the kernel.
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700285static void stopTrace(bool isRoot)
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800286{
287 // Disable tracing.
288 setTracingEnabled(false);
289
290 // Set the options back to their defaults.
291 setTraceOverwriteEnable(true);
292 setSchedSwitchTracingEnable(false);
Erik Gilling99be77c2012-09-20 17:55:10 -0700293 setFrequencyTracingEnable(false);
Jamie Gennise8744fd2012-10-05 16:04:12 -0700294 setGovernorLoadTracingEnable(false);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800295 setGlobalClockEnable(false);
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800296
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700297 if (isRoot) {
Jamie Gennise8744fd2012-10-05 16:04:12 -0700298 setBusUtilizationTracingEnable(false);
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700299 setWorkqueueTracingEnabled(false);
300 setDiskTracingEnabled(false);
301 }
302
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800303 // Note that we can't reset the trace buffer size here because that would
304 // clear the trace before we've read it.
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800305}
306
307// Read the current kernel trace and write it to stdout.
308static void dumpTrace()
309{
310 int traceFD = open(k_tracePath, O_RDWR);
311 if (traceFD == -1) {
312 fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
313 strerror(errno), errno);
314 return;
315 }
316
Jamie Gennis7b5170b2012-04-28 19:06:49 -0700317 if (g_compress) {
318 z_stream zs;
319 uint8_t *in, *out;
320 int result, flush;
321
322 bzero(&zs, sizeof(zs));
323 result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
324 if (result != Z_OK) {
325 fprintf(stderr, "error initializing zlib: %d\n", result);
326 close(traceFD);
327 return;
328 }
329
330 const size_t bufSize = 64*1024;
331 in = (uint8_t*)malloc(bufSize);
332 out = (uint8_t*)malloc(bufSize);
333 flush = Z_NO_FLUSH;
334
335 zs.next_out = out;
336 zs.avail_out = bufSize;
337
338 do {
339
340 if (zs.avail_in == 0) {
341 // More input is needed.
342 result = read(traceFD, in, bufSize);
343 if (result < 0) {
344 fprintf(stderr, "error reading trace: %s (%d)\n",
345 strerror(errno), errno);
346 result = Z_STREAM_END;
347 break;
348 } else if (result == 0) {
349 flush = Z_FINISH;
350 } else {
351 zs.next_in = in;
352 zs.avail_in = result;
353 }
354 }
355
356 if (zs.avail_out == 0) {
357 // Need to write the output.
358 result = write(STDOUT_FILENO, out, bufSize);
359 if ((size_t)result < bufSize) {
360 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
361 strerror(errno), errno);
362 result = Z_STREAM_END; // skip deflate error message
363 zs.avail_out = bufSize; // skip the final write
364 break;
365 }
366 zs.next_out = out;
367 zs.avail_out = bufSize;
368 }
369
370 } while ((result = deflate(&zs, flush)) == Z_OK);
371
372 if (result != Z_STREAM_END) {
373 fprintf(stderr, "error deflating trace: %s\n", zs.msg);
374 }
375
376 if (zs.avail_out < bufSize) {
377 size_t bytes = bufSize - zs.avail_out;
378 result = write(STDOUT_FILENO, out, bytes);
379 if ((size_t)result < bytes) {
380 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
381 strerror(errno), errno);
382 }
383 }
384
385 result = deflateEnd(&zs);
386 if (result != Z_OK) {
387 fprintf(stderr, "error cleaning up zlib: %d\n", result);
388 }
389
390 free(in);
391 free(out);
392 } else {
393 ssize_t sent = 0;
394 while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
395 if (sent == -1) {
396 fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
397 errno);
398 }
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800399 }
400
401 close(traceFD);
402}
403
404// Print the command usage help to stderr.
405static void showHelp(const char *cmd)
406{
407 fprintf(stderr, "usage: %s [options]\n", cmd);
408 fprintf(stderr, "options include:\n"
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800409 " -b N use a trace buffer size of N KB\n"
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800410 " -c trace into a circular buffer\n"
Jeff Brownac9453d2012-05-22 18:58:46 -0700411 " -d trace disk I/O\n"
Erik Gilling99be77c2012-09-20 17:55:10 -0700412 " -f trace clock frequency changes\n"
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800413 " -l trace CPU frequency governor load\n"
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800414 " -s trace the kernel scheduler switches\n"
415 " -t N trace for N seconds [defualt 5]\n"
Erik Gilling99be77c2012-09-20 17:55:10 -0700416 " -u trace bus utilization\n"
Jamie Gennis7b5170b2012-04-28 19:06:49 -0700417 " -w trace the kernel workqueue\n"
418 " -z compress the trace dump\n");
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800419}
420
421static void handleSignal(int signo) {
Glenn Kasten31be80f2012-06-05 16:42:22 -0700422 if (!g_nohup) {
423 g_traceAborted = true;
424 }
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800425}
426
427static void registerSigHandler() {
428 struct sigaction sa;
429 sigemptyset(&sa.sa_mask);
430 sa.sa_flags = 0;
431 sa.sa_handler = handleSignal;
432 sigaction(SIGHUP, &sa, NULL);
433 sigaction(SIGINT, &sa, NULL);
434 sigaction(SIGQUIT, &sa, NULL);
435 sigaction(SIGTERM, &sa, NULL);
436}
437
438int main(int argc, char **argv)
439{
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700440 bool isRoot = (getuid() == 0);
441
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800442 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
443 showHelp(argv[0]);
444 exit(0);
445 }
446
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800447 for (;;) {
448 int ret;
449
Glenn Kasten31be80f2012-06-05 16:42:22 -0700450 ret = getopt(argc, argv, "b:cidflst:uwznS:");
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800451
452 if (ret < 0) {
453 break;
454 }
455
456 switch(ret) {
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800457 case 'b':
458 g_traceBufferSizeKB = atoi(optarg);
459 break;
460
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800461 case 'c':
462 g_traceOverwrite = true;
463 break;
464
Jamie Gennis31695332012-05-07 17:58:44 -0700465 case 'i':
466 g_traceCpuIdle = true;
467 break;
468
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800469 case 'l':
470 g_traceGovernorLoad = true;
471 break;
472
Jeff Brownac9453d2012-05-22 18:58:46 -0700473 case 'd':
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700474 if (!isRoot) {
475 fprintf(stderr, "error: tracing disk activity requires root privileges\n");
476 exit(1);
477 }
Jeff Brownac9453d2012-05-22 18:58:46 -0700478 g_traceDisk = true;
479 break;
480
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800481 case 'f':
Erik Gilling99be77c2012-09-20 17:55:10 -0700482 g_traceFrequency = true;
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800483 break;
484
Glenn Kasten31be80f2012-06-05 16:42:22 -0700485 case 'n':
486 g_nohup = true;
487 break;
488
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800489 case 's':
490 g_traceSchedSwitch = true;
491 break;
492
Glenn Kasten31be80f2012-06-05 16:42:22 -0700493 case 'S':
494 g_initialSleepSecs = atoi(optarg);
495 break;
496
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800497 case 't':
498 g_traceDurationSeconds = atoi(optarg);
499 break;
500
Erik Gilling99be77c2012-09-20 17:55:10 -0700501 case 'u':
502 if (!isRoot) {
503 fprintf(stderr, "error: tracing bus utilization requires root privileges\n");
504 exit(1);
505 }
506 g_traceBusUtilization = true;
507 break;
508
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800509 case 'w':
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700510 if (!isRoot) {
511 fprintf(stderr, "error: tracing kernel work queues requires root privileges\n");
512 exit(1);
513 }
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800514 g_traceWorkqueue = true;
515 break;
516
Jamie Gennis7b5170b2012-04-28 19:06:49 -0700517 case 'z':
518 g_compress = true;
519 break;
520
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800521 default:
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800522 fprintf(stderr, "\n");
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800523 showHelp(argv[0]);
524 exit(-1);
525 break;
526 }
527 }
528
529 registerSigHandler();
530
Glenn Kasten31be80f2012-06-05 16:42:22 -0700531 if (g_initialSleepSecs > 0) {
532 sleep(g_initialSleepSecs);
533 }
534
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700535 bool ok = startTrace(isRoot);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800536
537 if (ok) {
538 printf("capturing trace...");
539 fflush(stdout);
540
541 // We clear the trace after starting it because tracing gets enabled for
542 // each CPU individually in the kernel. Having the beginning of the trace
543 // contain entries from only one CPU can cause "begin" entries without a
544 // matching "end" entry to show up if a task gets migrated from one CPU to
545 // another.
546 ok = clearTrace();
547
548 if (ok) {
549 // Sleep to allow the trace to be captured.
550 struct timespec timeLeft;
551 timeLeft.tv_sec = g_traceDurationSeconds;
552 timeLeft.tv_nsec = 0;
553 do {
554 if (g_traceAborted) {
555 break;
556 }
557 } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
558 }
559 }
560
561 // Stop the trace and restore the default settings.
Jamie Gennis4b23eef2012-06-07 16:27:03 -0700562 stopTrace(isRoot);
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800563
564 if (ok) {
565 if (!g_traceAborted) {
566 printf(" done\nTRACE:\n");
567 fflush(stdout);
568 dumpTrace();
569 } else {
570 printf("\ntrace aborted.\n");
571 fflush(stdout);
572 }
573 clearTrace();
574 } else {
575 fprintf(stderr, "unable to start tracing\n");
576 }
577
Jamie Genniscc24c8e2012-03-05 19:10:37 -0800578 // Reset the trace buffer size to 1.
579 setTraceBufferSizeKB(1);
580
Jamie Gennisfb31ba62012-02-23 14:16:05 -0800581 return g_traceAborted ? 1 : 0;
582}