aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2013-08-19 11:01:10 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-08-26 15:51:31 -0400
commitc24ff998fc420891f17d73acab6766823d492175 (patch)
tree9dd2767d9c6d961d89eb58b60d15c7189efc5812 /tools/perf
parente3e1a54fce81ee045dd152deb5435b136cb0b75f (diff)
perf trace: Implement -o/--output filename
To output all 'trace' output to a filename, just like 'strace -ofile' Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-6q1homkwoayhmoq64y5vhel6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-trace.txt4
-rw-r--r--tools/perf/builtin-trace.c134
2 files changed, 90 insertions, 48 deletions
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 3b3552a8959e..2794efce47a1 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -30,6 +30,10 @@ OPTIONS
30--expr:: 30--expr::
31 List of events to show, currently only syscall names. 31 List of events to show, currently only syscall names.
32 32
33-o::
34--output=::
35 Output file name.
36
33-p:: 37-p::
34--pid=:: 38--pid=::
35 Record events on existing process ID (comma separated list). 39 Record events on existing process ID (comma separated list).
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 120fdfb3d920..42353165472a 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -63,7 +63,7 @@ static size_t fprintf_duration(unsigned long t, FILE *fp)
63 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration); 63 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
64 else 64 else
65 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration); 65 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
66 return printed + fprintf(stdout, "): "); 66 return printed + fprintf(fp, "): ");
67} 67}
68 68
69struct thread_trace { 69struct thread_trace {
@@ -80,7 +80,7 @@ static struct thread_trace *thread_trace__new(void)
80 return zalloc(sizeof(struct thread_trace)); 80 return zalloc(sizeof(struct thread_trace));
81} 81}
82 82
83static struct thread_trace *thread__trace(struct thread *thread) 83static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
84{ 84{
85 struct thread_trace *ttrace; 85 struct thread_trace *ttrace;
86 86
@@ -98,12 +98,13 @@ static struct thread_trace *thread__trace(struct thread *thread)
98 98
99 return ttrace; 99 return ttrace;
100fail: 100fail:
101 color_fprintf(stdout, PERF_COLOR_RED, 101 color_fprintf(fp, PERF_COLOR_RED,
102 "WARNING: not enough memory, dropping samples!\n"); 102 "WARNING: not enough memory, dropping samples!\n");
103 return NULL; 103 return NULL;
104} 104}
105 105
106struct trace { 106struct trace {
107 struct perf_tool tool;
107 int audit_machine; 108 int audit_machine;
108 struct { 109 struct {
109 int max; 110 int max;
@@ -112,6 +113,7 @@ struct trace {
112 struct perf_record_opts opts; 113 struct perf_record_opts opts;
113 struct machine host; 114 struct machine host;
114 u64 base_time; 115 u64 base_time;
116 FILE *output;
115 struct strlist *ev_qualifier; 117 struct strlist *ev_qualifier;
116 unsigned long nr_events; 118 unsigned long nr_events;
117 bool sched; 119 bool sched;
@@ -151,13 +153,14 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
151 return printed; 153 return printed;
152} 154}
153 155
154static int trace__process_event(struct machine *machine, union perf_event *event) 156static int trace__process_event(struct trace *trace, struct machine *machine,
157 union perf_event *event)
155{ 158{
156 int ret = 0; 159 int ret = 0;
157 160
158 switch (event->header.type) { 161 switch (event->header.type) {
159 case PERF_RECORD_LOST: 162 case PERF_RECORD_LOST:
160 color_fprintf(stdout, PERF_COLOR_RED, 163 color_fprintf(trace->output, PERF_COLOR_RED,
161 "LOST %" PRIu64 " events!\n", event->lost.lost); 164 "LOST %" PRIu64 " events!\n", event->lost.lost);
162 ret = machine__process_lost_event(machine, event); 165 ret = machine__process_lost_event(machine, event);
163 default: 166 default:
@@ -168,12 +171,13 @@ static int trace__process_event(struct machine *machine, union perf_event *event
168 return ret; 171 return ret;
169} 172}
170 173
171static int trace__tool_process(struct perf_tool *tool __maybe_unused, 174static int trace__tool_process(struct perf_tool *tool,
172 union perf_event *event, 175 union perf_event *event,
173 struct perf_sample *sample __maybe_unused, 176 struct perf_sample *sample __maybe_unused,
174 struct machine *machine) 177 struct machine *machine)
175{ 178{
176 return trace__process_event(machine, event); 179 struct trace *trace = container_of(tool, struct trace, tool);
180 return trace__process_event(trace, machine, event);
177} 181}
178 182
179static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) 183static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
@@ -187,11 +191,11 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
187 machine__create_kernel_maps(&trace->host); 191 machine__create_kernel_maps(&trace->host);
188 192
189 if (perf_target__has_task(&trace->opts.target)) { 193 if (perf_target__has_task(&trace->opts.target)) {
190 err = perf_event__synthesize_thread_map(NULL, evlist->threads, 194 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
191 trace__tool_process, 195 trace__tool_process,
192 &trace->host); 196 &trace->host);
193 } else { 197 } else {
194 err = perf_event__synthesize_threads(NULL, trace__tool_process, 198 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
195 &trace->host); 199 &trace->host);
196 } 200 }
197 201
@@ -288,7 +292,7 @@ static struct syscall *trace__syscall_info(struct trace *trace,
288 int id = perf_evsel__intval(evsel, sample, "id"); 292 int id = perf_evsel__intval(evsel, sample, "id");
289 293
290 if (id < 0) { 294 if (id < 0) {
291 printf("Invalid syscall %d id, skipping...\n", id); 295 fprintf(trace->output, "Invalid syscall %d id, skipping...\n", id);
292 return NULL; 296 return NULL;
293 } 297 }
294 298
@@ -302,10 +306,10 @@ static struct syscall *trace__syscall_info(struct trace *trace,
302 return &trace->syscalls.table[id]; 306 return &trace->syscalls.table[id];
303 307
304out_cant_read: 308out_cant_read:
305 printf("Problems reading syscall %d", id); 309 fprintf(trace->output, "Problems reading syscall %d", id);
306 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL) 310 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
307 printf("(%s)", trace->syscalls.table[id].name); 311 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
308 puts(" information"); 312 fputs(" information", trace->output);
309 return NULL; 313 return NULL;
310} 314}
311 315
@@ -326,13 +330,13 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
326 return 0; 330 return 0;
327 331
328 thread = machine__findnew_thread(&trace->host, sample->tid); 332 thread = machine__findnew_thread(&trace->host, sample->tid);
329 ttrace = thread__trace(thread); 333 ttrace = thread__trace(thread, trace->output);
330 if (ttrace == NULL) 334 if (ttrace == NULL)
331 return -1; 335 return -1;
332 336
333 args = perf_evsel__rawptr(evsel, sample, "args"); 337 args = perf_evsel__rawptr(evsel, sample, "args");
334 if (args == NULL) { 338 if (args == NULL) {
335 printf("Problems reading syscall arguments\n"); 339 fprintf(trace->output, "Problems reading syscall arguments\n");
336 return -1; 340 return -1;
337 } 341 }
338 342
@@ -352,8 +356,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
352 356
353 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 357 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
354 if (!trace->duration_filter) { 358 if (!trace->duration_filter) {
355 trace__fprintf_entry_head(trace, thread, 1, sample->time, stdout); 359 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
356 printf("%-70s\n", ttrace->entry_str); 360 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
357 } 361 }
358 } else 362 } else
359 ttrace->entry_pending = true; 363 ttrace->entry_pending = true;
@@ -377,7 +381,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
377 return 0; 381 return 0;
378 382
379 thread = machine__findnew_thread(&trace->host, sample->tid); 383 thread = machine__findnew_thread(&trace->host, sample->tid);
380 ttrace = thread__trace(thread); 384 ttrace = thread__trace(thread, trace->output);
381 if (ttrace == NULL) 385 if (ttrace == NULL)
382 return -1; 386 return -1;
383 387
@@ -394,14 +398,14 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
394 } else if (trace->duration_filter) 398 } else if (trace->duration_filter)
395 goto out; 399 goto out;
396 400
397 trace__fprintf_entry_head(trace, thread, duration, sample->time, stdout); 401 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
398 402
399 if (ttrace->entry_pending) { 403 if (ttrace->entry_pending) {
400 printf("%-70s", ttrace->entry_str); 404 fprintf(trace->output, "%-70s", ttrace->entry_str);
401 } else { 405 } else {
402 printf(" ... ["); 406 fprintf(trace->output, " ... [");
403 color_fprintf(stdout, PERF_COLOR_YELLOW, "continued"); 407 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
404 printf("]: %s()", sc->name); 408 fprintf(trace->output, "]: %s()", sc->name);
405 } 409 }
406 410
407 if (ret < 0 && sc->fmt && sc->fmt->errmsg) { 411 if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
@@ -409,13 +413,13 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
409 const char *emsg = strerror_r(-ret, bf, sizeof(bf)), 413 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
410 *e = audit_errno_to_name(-ret); 414 *e = audit_errno_to_name(-ret);
411 415
412 printf(") = -1 %s %s", e, emsg); 416 fprintf(trace->output, ") = -1 %s %s", e, emsg);
413 } else if (ret == 0 && sc->fmt && sc->fmt->timeout) 417 } else if (ret == 0 && sc->fmt && sc->fmt->timeout)
414 printf(") = 0 Timeout"); 418 fprintf(trace->output, ") = 0 Timeout");
415 else 419 else
416 printf(") = %d", ret); 420 fprintf(trace->output, ") = %d", ret);
417 421
418 putchar('\n'); 422 fputc('\n', trace->output);
419out: 423out:
420 ttrace->entry_pending = false; 424 ttrace->entry_pending = false;
421 425
@@ -428,7 +432,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs
428 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 432 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
429 double runtime_ms = (double)runtime / NSEC_PER_MSEC; 433 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
430 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid); 434 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
431 struct thread_trace *ttrace = thread__trace(thread); 435 struct thread_trace *ttrace = thread__trace(thread, trace->output);
432 436
433 if (ttrace == NULL) 437 if (ttrace == NULL)
434 goto out_dump; 438 goto out_dump;
@@ -438,7 +442,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs
438 return 0; 442 return 0;
439 443
440out_dump: 444out_dump:
441 printf("%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n", 445 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
442 evsel->name, 446 evsel->name,
443 perf_evsel__strval(evsel, sample, "comm"), 447 perf_evsel__strval(evsel, sample, "comm"),
444 (pid_t)perf_evsel__intval(evsel, sample, "pid"), 448 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
@@ -456,32 +460,32 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
456 const bool forks = argc > 0; 460 const bool forks = argc > 0;
457 461
458 if (evlist == NULL) { 462 if (evlist == NULL) {
459 printf("Not enough memory to run!\n"); 463 fprintf(trace->output, "Not enough memory to run!\n");
460 goto out; 464 goto out;
461 } 465 }
462 466
463 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || 467 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
464 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { 468 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
465 printf("Couldn't read the raw_syscalls tracepoints information!\n"); 469 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
466 goto out_delete_evlist; 470 goto out_delete_evlist;
467 } 471 }
468 472
469 if (trace->sched && 473 if (trace->sched &&
470 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 474 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
471 trace__sched_stat_runtime)) { 475 trace__sched_stat_runtime)) {
472 printf("Couldn't read the sched_stat_runtime tracepoint information!\n"); 476 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
473 goto out_delete_evlist; 477 goto out_delete_evlist;
474 } 478 }
475 479
476 err = perf_evlist__create_maps(evlist, &trace->opts.target); 480 err = perf_evlist__create_maps(evlist, &trace->opts.target);
477 if (err < 0) { 481 if (err < 0) {
478 printf("Problems parsing the target to trace, check your options!\n"); 482 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
479 goto out_delete_evlist; 483 goto out_delete_evlist;
480 } 484 }
481 485
482 err = trace__symbols_init(trace, evlist); 486 err = trace__symbols_init(trace, evlist);
483 if (err < 0) { 487 if (err < 0) {
484 printf("Problems initializing symbol libraries!\n"); 488 fprintf(trace->output, "Problems initializing symbol libraries!\n");
485 goto out_delete_maps; 489 goto out_delete_maps;
486 } 490 }
487 491
@@ -494,20 +498,20 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
494 err = perf_evlist__prepare_workload(evlist, &trace->opts.target, 498 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
495 argv, false, false); 499 argv, false, false);
496 if (err < 0) { 500 if (err < 0) {
497 printf("Couldn't run the workload!\n"); 501 fprintf(trace->output, "Couldn't run the workload!\n");
498 goto out_delete_maps; 502 goto out_delete_maps;
499 } 503 }
500 } 504 }
501 505
502 err = perf_evlist__open(evlist); 506 err = perf_evlist__open(evlist);
503 if (err < 0) { 507 if (err < 0) {
504 printf("Couldn't create the events: %s\n", strerror(errno)); 508 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
505 goto out_delete_maps; 509 goto out_delete_maps;
506 } 510 }
507 511
508 err = perf_evlist__mmap(evlist, UINT_MAX, false); 512 err = perf_evlist__mmap(evlist, UINT_MAX, false);
509 if (err < 0) { 513 if (err < 0) {
510 printf("Couldn't mmap the events: %s\n", strerror(errno)); 514 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
511 goto out_close_evlist; 515 goto out_close_evlist;
512 } 516 }
513 517
@@ -532,7 +536,7 @@ again:
532 536
533 err = perf_evlist__parse_sample(evlist, event, &sample); 537 err = perf_evlist__parse_sample(evlist, event, &sample);
534 if (err) { 538 if (err) {
535 printf("Can't parse sample, err = %d, skipping...\n", err); 539 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
536 continue; 540 continue;
537 } 541 }
538 542
@@ -540,18 +544,18 @@ again:
540 trace->base_time = sample.time; 544 trace->base_time = sample.time;
541 545
542 if (type != PERF_RECORD_SAMPLE) { 546 if (type != PERF_RECORD_SAMPLE) {
543 trace__process_event(&trace->host, event); 547 trace__process_event(trace, &trace->host, event);
544 continue; 548 continue;
545 } 549 }
546 550
547 evsel = perf_evlist__id2evsel(evlist, sample.id); 551 evsel = perf_evlist__id2evsel(evlist, sample.id);
548 if (evsel == NULL) { 552 if (evsel == NULL) {
549 printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); 553 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
550 continue; 554 continue;
551 } 555 }
552 556
553 if (sample.raw_data == NULL) { 557 if (sample.raw_data == NULL) {
554 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 558 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
555 perf_evsel__name(evsel), sample.tid, 559 perf_evsel__name(evsel), sample.tid,
556 sample.cpu, sample.raw_size); 560 sample.cpu, sample.raw_size);
557 continue; 561 continue;
@@ -640,6 +644,23 @@ static int trace__set_duration(const struct option *opt, const char *str,
640 return 0; 644 return 0;
641} 645}
642 646
647static int trace__open_output(struct trace *trace, const char *filename)
648{
649 struct stat st;
650
651 if (!stat(filename, &st) && st.st_size) {
652 char oldname[PATH_MAX];
653
654 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
655 unlink(oldname);
656 rename(filename, oldname);
657 }
658
659 trace->output = fopen(filename, "w");
660
661 return trace->output == NULL ? -errno : 0;
662}
663
643int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 664int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
644{ 665{
645 const char * const trace_usage[] = { 666 const char * const trace_usage[] = {
@@ -662,11 +683,14 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
662 .no_delay = true, 683 .no_delay = true,
663 .mmap_pages = 1024, 684 .mmap_pages = 1024,
664 }, 685 },
686 .output = stdout,
665 }; 687 };
688 const char *output_name = NULL;
666 const char *ev_qualifier_str = NULL; 689 const char *ev_qualifier_str = NULL;
667 const struct option trace_options[] = { 690 const struct option trace_options[] = {
668 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", 691 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
669 "list of events to trace"), 692 "list of events to trace"),
693 OPT_STRING('o', "output", &output_name, "file", "output file name"),
670 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid", 694 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
671 "trace events on existing process id"), 695 "trace events on existing process id"),
672 OPT_STRING(0, "tid", &trace.opts.target.tid, "tid", 696 OPT_STRING(0, "tid", &trace.opts.target.tid, "tid",
@@ -692,26 +716,36 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
692 716
693 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 717 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
694 718
719 if (output_name != NULL) {
720 err = trace__open_output(&trace, output_name);
721 if (err < 0) {
722 perror("failed to create output file");
723 goto out;
724 }
725 }
726
695 if (ev_qualifier_str != NULL) { 727 if (ev_qualifier_str != NULL) {
696 trace.ev_qualifier = strlist__new(true, ev_qualifier_str); 728 trace.ev_qualifier = strlist__new(true, ev_qualifier_str);
697 if (trace.ev_qualifier == NULL) { 729 if (trace.ev_qualifier == NULL) {
698 puts("Not enough memory to parse event qualifier"); 730 fputs("Not enough memory to parse event qualifier",
699 return -ENOMEM; 731 trace.output);
732 err = -ENOMEM;
733 goto out_close;
700 } 734 }
701 } 735 }
702 736
703 err = perf_target__validate(&trace.opts.target); 737 err = perf_target__validate(&trace.opts.target);
704 if (err) { 738 if (err) {
705 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 739 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
706 printf("%s", bf); 740 fprintf(trace.output, "%s", bf);
707 return err; 741 goto out_close;
708 } 742 }
709 743
710 err = perf_target__parse_uid(&trace.opts.target); 744 err = perf_target__parse_uid(&trace.opts.target);
711 if (err) { 745 if (err) {
712 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 746 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
713 printf("%s", bf); 747 fprintf(trace.output, "%s", bf);
714 return err; 748 goto out_close;
715 } 749 }
716 750
717 if (!argc && perf_target__none(&trace.opts.target)) 751 if (!argc && perf_target__none(&trace.opts.target))
@@ -720,7 +754,11 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
720 err = trace__run(&trace, argc, argv); 754 err = trace__run(&trace, argc, argv);
721 755
722 if (trace.sched && !err) 756 if (trace.sched && !err)
723 trace__fprintf_thread_summary(&trace, stdout); 757 trace__fprintf_thread_summary(&trace, trace.output);
724 758
759out_close:
760 if (output_name != NULL)
761 fclose(trace.output);
762out:
725 return err; 763 return err;
726} 764}