Re: [PATCH] perf script: Add script orientation output support for monitored events
From: Arnaldo Carvalho de Melo
Date: Mon Sep 11 2017 - 10:48:47 EST
Em Mon, Aug 28, 2017 at 05:33:54PM +0800, Wind Yu escreveu:
> Introduce a new option to print trace output to files named by the
> monitored events and update perf-script documentation accordingly.
Adding some more people to the CC list, hopefully this can get more
reviews.
I found the "orientation" term vague, perhaps --per-event-dump and do
not use a single letter for something seemingly designed for use in
shell scripts, where having the long option will even help in
documenting that script.
Also the patch is too big and does multiple things, please break it down
into multiple patches, the first could be a preparatory one that makes
all those functions receive the FILE pointer, this first patch would
then just use 'stdout', the next one would be smaller and doing just the
--per-event-dump part.
Also there are other minor things like needlessly casting malloc(), and
that case you should really use asprintf(), that does the allocation +
formatting, as used in other parts in tools/.
Thanks,
- Arnaldo
> Shown below is output of perf script command with the newly introduced
> option.
>
> $perf record -e cycles -e context-switches -ag -- sleep 10
> $perf script -O
> $ls /
> cycles.stacks context-switches.stacks
>
> Without the orientation option, drawing flamegraphs for different events
> is really hard. You can only monitor one event at a time for perf record.
> Using this option, we can get the trace output files named by the monitored
> events, and could draw flamegraphs according to the event's name.
>
> Signed-off-by: Wind Yu <yuzhoujian@xxxxxxxxxxxxxxx>
> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
> Cc: Ingo Molnar <mingo@xxxxxxxxxx>
> Cc: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
> Cc: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx>
> ---
> tools/perf/builtin-script.c | 469 +++++++++++++++++++++++++-------------------
> tools/perf/util/tool.h | 1 +
> 2 files changed, 269 insertions(+), 201 deletions(-)
>
> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
> index 378f76c..45a121b 100644
> --- a/tools/perf/builtin-script.c
> +++ b/tools/perf/builtin-script.c
> @@ -57,6 +57,7 @@
> static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
> static struct perf_stat_config stat_config;
> static int max_blocks;
> +static FILE *orientation_file;
>
> unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
>
> @@ -485,8 +486,8 @@ static int perf_session__check_output_opt(struct perf_session *session)
> return 0;
> }
>
> -static void print_sample_iregs(struct perf_sample *sample,
> - struct perf_event_attr *attr)
> +static void fprint_sample_iregs(struct perf_sample *sample,
> + struct perf_event_attr *attr, FILE *fp)
> {
> struct regs_dump *regs = &sample->intr_regs;
> uint64_t mask = attr->sample_regs_intr;
> @@ -497,13 +498,13 @@ static void print_sample_iregs(struct perf_sample *sample,
>
> for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) {
> u64 val = regs->regs[i++];
> - printf("%5s:0x%"PRIx64" ", perf_reg_name(r), val);
> + fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r), val);
> }
> }
>
> -static void print_sample_start(struct perf_sample *sample,
> +static void fprint_sample_start(struct perf_sample *sample,
> struct thread *thread,
> - struct perf_evsel *evsel)
> + struct perf_evsel *evsel, FILE *fp)
> {
> struct perf_event_attr *attr = &evsel->attr;
> unsigned long secs;
> @@ -511,25 +512,25 @@ static void print_sample_start(struct perf_sample *sample,
>
> if (PRINT_FIELD(COMM)) {
> if (latency_format)
> - printf("%8.8s ", thread__comm_str(thread));
> + fprintf(fp, "%8.8s ", thread__comm_str(thread));
> else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)
> - printf("%s ", thread__comm_str(thread));
> + fprintf(fp, "%s ", thread__comm_str(thread));
> else
> - printf("%16s ", thread__comm_str(thread));
> + fprintf(fp, "%16s ", thread__comm_str(thread));
> }
>
> if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
> - printf("%5d/%-5d ", sample->pid, sample->tid);
> + fprintf(fp, "%5d/%-5d ", sample->pid, sample->tid);
> else if (PRINT_FIELD(PID))
> - printf("%5d ", sample->pid);
> + fprintf(fp, "%5d ", sample->pid);
> else if (PRINT_FIELD(TID))
> - printf("%5d ", sample->tid);
> + fprintf(fp, "%5d ", sample->tid);
>
> if (PRINT_FIELD(CPU)) {
> if (latency_format)
> - printf("%3d ", sample->cpu);
> + fprintf(fp, "%3d ", sample->cpu);
> else
> - printf("[%03d] ", sample->cpu);
> + fprintf(fp, "[%03d] ", sample->cpu);
> }
>
> if (PRINT_FIELD(TIME)) {
> @@ -538,11 +539,11 @@ static void print_sample_start(struct perf_sample *sample,
> nsecs -= secs * NSEC_PER_SEC;
>
> if (nanosecs)
> - printf("%5lu.%09llu: ", secs, nsecs);
> + fprintf(fp, "%5lu.%09llu: ", secs, nsecs);
> else {
> char sample_time[32];
> timestamp__scnprintf_usec(sample->time, sample_time, sizeof(sample_time));
> - printf("%12s: ", sample_time);
> + fprintf(fp, "%12s: ", sample_time);
> }
> }
> }
> @@ -556,9 +557,10 @@ static void print_sample_start(struct perf_sample *sample,
> return br->flags.predicted ? 'P' : 'M';
> }
>
> -static void print_sample_brstack(struct perf_sample *sample,
> +static void fprint_sample_brstack(struct perf_sample *sample,
> struct thread *thread,
> - struct perf_event_attr *attr)
> + struct perf_event_attr *attr,
> + FILE *fp)
> {
> struct branch_stack *br = sample->branch_stack;
> struct addr_location alf, alt;
> @@ -578,21 +580,21 @@ static void print_sample_brstack(struct perf_sample *sample,
> thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt);
> }
>
> - printf("0x%"PRIx64, from);
> + fprintf(fp, "0x%"PRIx64, from);
> if (PRINT_FIELD(DSO)) {
> - printf("(");
> - map__fprintf_dsoname(alf.map, stdout);
> - printf(")");
> + fprintf(fp, "(");
> + map__fprintf_dsoname(alf.map, fp);
> + fprintf(fp, ")");
> }
>
> - printf("/0x%"PRIx64, to);
> + fprintf(fp, "/0x%"PRIx64, to);
> if (PRINT_FIELD(DSO)) {
> - printf("(");
> - map__fprintf_dsoname(alt.map, stdout);
> - printf(")");
> + fprintf(fp, "(");
> + map__fprintf_dsoname(alt.map, fp);
> + fprintf(fp, ")");
> }
>
> - printf("/%c/%c/%c/%d ",
> + fprintf(fp, "/%c/%c/%c/%d ",
> mispred_str( br->entries + i),
> br->entries[i].flags.in_tx? 'X' : '-',
> br->entries[i].flags.abort? 'A' : '-',
> @@ -600,9 +602,10 @@ static void print_sample_brstack(struct perf_sample *sample,
> }
> }
>
> -static void print_sample_brstacksym(struct perf_sample *sample,
> +static void fprint_sample_brstacksym(struct perf_sample *sample,
> struct thread *thread,
> - struct perf_event_attr *attr)
> + struct perf_event_attr *attr,
> + FILE *fp)
> {
> struct branch_stack *br = sample->branch_stack;
> struct addr_location alf, alt;
> @@ -626,20 +629,20 @@ static void print_sample_brstacksym(struct perf_sample *sample,
> if (alt.map)
> alt.sym = map__find_symbol(alt.map, alt.addr);
>
> - symbol__fprintf_symname_offs(alf.sym, &alf, stdout);
> + symbol__fprintf_symname_offs(alf.sym, &alf, fp);
> if (PRINT_FIELD(DSO)) {
> - printf("(");
> - map__fprintf_dsoname(alf.map, stdout);
> - printf(")");
> + fprintf(fp, "(");
> + map__fprintf_dsoname(alf.map, fp);
> + fprintf(fp, ")");
> }
> - putchar('/');
> - symbol__fprintf_symname_offs(alt.sym, &alt, stdout);
> + fputc('/', fp);
> + symbol__fprintf_symname_offs(alt.sym, &alt, fp);
> if (PRINT_FIELD(DSO)) {
> - printf("(");
> - map__fprintf_dsoname(alt.map, stdout);
> - printf(")");
> + fprintf(fp, "(");
> + map__fprintf_dsoname(alt.map, fp);
> + fprintf(fp, ")");
> }
> - printf("/%c/%c/%c/%d ",
> + fprintf(fp, "/%c/%c/%c/%d ",
> mispred_str( br->entries + i),
> br->entries[i].flags.in_tx? 'X' : '-',
> br->entries[i].flags.abort? 'A' : '-',
> @@ -647,9 +650,10 @@ static void print_sample_brstacksym(struct perf_sample *sample,
> }
> }
>
> -static void print_sample_brstackoff(struct perf_sample *sample,
> +static void fprint_sample_brstackoff(struct perf_sample *sample,
> struct thread *thread,
> - struct perf_event_attr *attr)
> + struct perf_event_attr *attr,
> + FILE *fp)
> {
> struct branch_stack *br = sample->branch_stack;
> struct addr_location alf, alt;
> @@ -673,19 +677,19 @@ static void print_sample_brstackoff(struct perf_sample *sample,
> if (alt.map && !alt.map->dso->adjust_symbols)
> to = map__map_ip(alt.map, to);
>
> - printf("0x%"PRIx64, from);
> + fprintf(fp, "0x%"PRIx64, from);
> if (PRINT_FIELD(DSO)) {
> - printf("(");
> - map__fprintf_dsoname(alf.map, stdout);
> - printf(")");
> + fprintf(fp, "(");
> + map__fprintf_dsoname(alf.map, fp);
> + fprintf(fp, ")");
> }
> - printf("/0x%"PRIx64, to);
> + fprintf(fp, "/0x%"PRIx64, to);
> if (PRINT_FIELD(DSO)) {
> - printf("(");
> - map__fprintf_dsoname(alt.map, stdout);
> - printf(")");
> + fprintf(fp, "(");
> + map__fprintf_dsoname(alt.map, fp);
> + fprintf(fp, ")");
> }
> - printf("/%c/%c/%c/%d ",
> + fprintf(fp, "/%c/%c/%c/%d ",
> mispred_str(br->entries + i),
> br->entries[i].flags.in_tx ? 'X' : '-',
> br->entries[i].flags.abort ? 'A' : '-',
> @@ -756,11 +760,11 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
> return len;
> }
>
> -static void print_jump(uint64_t ip, struct branch_entry *en,
> +static void fprint_jump(uint64_t ip, struct branch_entry *en,
> struct perf_insn *x, u8 *inbuf, int len,
> - int insn)
> + int insn, FILE *fp)
> {
> - printf("\t%016" PRIx64 "\t%-30s\t#%s%s%s%s",
> + fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s",
> ip,
> dump_insn(x, ip, inbuf, len, NULL),
> en->flags.predicted ? " PRED" : "",
> @@ -768,16 +772,16 @@ static void print_jump(uint64_t ip, struct branch_entry *en,
> en->flags.in_tx ? " INTX" : "",
> en->flags.abort ? " ABORT" : "");
> if (en->flags.cycles) {
> - printf(" %d cycles", en->flags.cycles);
> + fprintf(fp, " %d cycles", en->flags.cycles);
> if (insn)
> - printf(" %.2f IPC", (float)insn / en->flags.cycles);
> + fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles);
> }
> - putchar('\n');
> + fputc('\n', fp);
> }
>
> -static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu,
> +static void fprint_ip_sym(struct thread *thread, u8 cpumode, int cpu,
> uint64_t addr, struct symbol **lastsym,
> - struct perf_event_attr *attr)
> + struct perf_event_attr *attr, FILE *fp)
> {
> struct addr_location al;
> int off;
> @@ -803,20 +807,21 @@ static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu,
> off = al.addr - al.sym->start;
> else
> off = al.addr - al.map->start - al.sym->start;
> - printf("\t%s", al.sym->name);
> + fprintf(fp, "\t%s", al.sym->name);
> if (off)
> - printf("%+d", off);
> - putchar(':');
> + fprintf(fp, "%+d", off);
> + fputc(':', fp);
> if (PRINT_FIELD(SRCLINE))
> - map__fprintf_srcline(al.map, al.addr, "\t", stdout);
> - putchar('\n');
> + map__fprintf_srcline(al.map, al.addr, "\t", fp);
> + fputc('\n', fp);
> *lastsym = al.sym;
> }
>
> -static void print_sample_brstackinsn(struct perf_sample *sample,
> +static void fprint_sample_brstackinsn(struct perf_sample *sample,
> struct thread *thread,
> struct perf_event_attr *attr,
> - struct machine *machine)
> + struct machine *machine,
> + FILE *fp)
> {
> struct branch_stack *br = sample->branch_stack;
> u64 start, end;
> @@ -835,23 +840,23 @@ static void print_sample_brstackinsn(struct perf_sample *sample,
> x.thread = thread;
> x.cpu = sample->cpu;
>
> - putchar('\n');
> + fputc('\n', fp);
>
> /* Handle first from jump, of which we don't know the entry. */
> len = grab_bb(buffer, br->entries[nr-1].from,
> br->entries[nr-1].from,
> machine, thread, &x.is64bit, &x.cpumode, false);
> if (len > 0) {
> - print_ip_sym(thread, x.cpumode, x.cpu,
> - br->entries[nr - 1].from, &lastsym, attr);
> - print_jump(br->entries[nr - 1].from, &br->entries[nr - 1],
> - &x, buffer, len, 0);
> + fprint_ip_sym(thread, x.cpumode, x.cpu,
> + br->entries[nr - 1].from, &lastsym, attr, fp);
> + fprint_jump(br->entries[nr - 1].from, &br->entries[nr - 1],
> + &x, buffer, len, 0, fp);
> }
>
> /* Print all blocks */
> for (i = nr - 2; i >= 0; i--) {
> if (br->entries[i].from || br->entries[i].to)
> - pr_debug("%d: %" PRIx64 "-%" PRIx64 "\n", i,
> + fprintf(fp, "%d: %" PRIx64 "-%" PRIx64 "\n", i,
> br->entries[i].from,
> br->entries[i].to);
> start = br->entries[i + 1].to;
> @@ -861,7 +866,7 @@ static void print_sample_brstackinsn(struct perf_sample *sample,
> /* Patch up missing kernel transfers due to ring filters */
> if (len == -ENXIO && i > 0) {
> end = br->entries[--i].from;
> - pr_debug("\tpatching up to %" PRIx64 "-%" PRIx64 "\n", start, end);
> + fprintf(fp, "\tpatching up to %" PRIx64 "-%" PRIx64 "\n", start, end);
> len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, false);
> }
> if (len <= 0)
> @@ -871,13 +876,12 @@ static void print_sample_brstackinsn(struct perf_sample *sample,
> for (off = 0;; off += ilen) {
> uint64_t ip = start + off;
>
> - print_ip_sym(thread, x.cpumode, x.cpu, ip, &lastsym, attr);
> + fprint_ip_sym(thread, x.cpumode, x.cpu, ip, &lastsym, attr, fp);
> if (ip == end) {
> - print_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn);
> + fprint_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp);
> break;
> } else {
> - printf("\t%016" PRIx64 "\t%s\n", ip,
> - dump_insn(&x, ip, buffer + off, len - off, &ilen));
> + fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, dump_insn(&x, ip, buffer + off, len - off, &ilen));
> if (ilen == 0)
> break;
> insn++;
> @@ -900,7 +904,7 @@ static void print_sample_brstackinsn(struct perf_sample *sample,
> start = br->entries[0].to;
> end = sample->ip;
> len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true);
> - print_ip_sym(thread, x.cpumode, x.cpu, start, &lastsym, attr);
> + fprint_ip_sym(thread, x.cpumode, x.cpu, start, &lastsym, attr, fp);
> if (len <= 0) {
> /* Print at least last IP if basic block did not work */
> len = grab_bb(buffer, sample->ip, sample->ip,
> @@ -908,25 +912,25 @@ static void print_sample_brstackinsn(struct perf_sample *sample,
> if (len <= 0)
> return;
>
> - printf("\t%016" PRIx64 "\t%s\n", sample->ip,
> + fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip,
> dump_insn(&x, sample->ip, buffer, len, NULL));
> return;
> }
> for (off = 0; off <= end - start; off += ilen) {
> - printf("\t%016" PRIx64 "\t%s\n", start + off,
> + fprintf(fp, "\t%016" PRIx64 "\t%s\n", start + off,
> dump_insn(&x, start + off, buffer + off, len - off, &ilen));
> if (ilen == 0)
> break;
> }
> }
>
> -static void print_sample_addr(struct perf_sample *sample,
> +static void fprint_sample_addr(struct perf_sample *sample,
> struct thread *thread,
> - struct perf_event_attr *attr)
> + struct perf_event_attr *attr, FILE *fp)
> {
> struct addr_location al;
>
> - printf("%16" PRIx64, sample->addr);
> + fprintf(fp, "%16" PRIx64, sample->addr);
>
> if (!sample_addr_correlates_sym(attr))
> return;
> @@ -934,24 +938,25 @@ static void print_sample_addr(struct perf_sample *sample,
> thread__resolve(thread, &al, sample);
>
> if (PRINT_FIELD(SYM)) {
> - printf(" ");
> + fprintf(fp, " ");
> if (PRINT_FIELD(SYMOFFSET))
> - symbol__fprintf_symname_offs(al.sym, &al, stdout);
> + symbol__fprintf_symname_offs(al.sym, &al, fp);
> else
> - symbol__fprintf_symname(al.sym, stdout);
> + symbol__fprintf_symname(al.sym, fp);
> }
>
> if (PRINT_FIELD(DSO)) {
> - printf(" (");
> - map__fprintf_dsoname(al.map, stdout);
> - printf(")");
> + fprintf(fp, " (");
> + map__fprintf_dsoname(al.map, fp);
> + fprintf(fp, ")");
> }
> }
>
> -static void print_sample_callindent(struct perf_sample *sample,
> +static void fprint_sample_callindent(struct perf_sample *sample,
> struct perf_evsel *evsel,
> struct thread *thread,
> - struct addr_location *al)
> + struct addr_location *al,
> + FILE *fp)
> {
> struct perf_event_attr *attr = &evsel->attr;
> size_t depth = thread_stack__depth(thread);
> @@ -986,9 +991,9 @@ static void print_sample_callindent(struct perf_sample *sample,
> }
>
> if (name)
> - len = printf("%*s%s", (int)depth * 4, "", name);
> + len = fprintf(fp, "%*s%s", (int)depth * 4, "", name);
> else if (ip)
> - len = printf("%*s%16" PRIx64, (int)depth * 4, "", ip);
> + len = fprintf(fp, "%*s%16" PRIx64, (int)depth * 4, "", ip);
>
> if (len < 0)
> return;
> @@ -1001,39 +1006,40 @@ static void print_sample_callindent(struct perf_sample *sample,
> spacing = round_up(len + 4, 32);
>
> if (len < spacing)
> - printf("%*s", spacing - len, "");
> + fprintf(fp, "%*s", spacing - len, "");
> }
>
> -static void print_insn(struct perf_sample *sample,
> +static void fprint_insn(struct perf_sample *sample,
> struct perf_event_attr *attr,
> struct thread *thread,
> - struct machine *machine)
> + struct machine *machine, FILE *fp)
> {
> if (PRINT_FIELD(INSNLEN))
> - printf(" ilen: %d", sample->insn_len);
> + fprintf(fp, " ilen: %d", sample->insn_len);
> if (PRINT_FIELD(INSN)) {
> int i;
>
> - printf(" insn:");
> + fprintf(fp, " insn:");
> for (i = 0; i < sample->insn_len; i++)
> - printf(" %02x", (unsigned char)sample->insn[i]);
> + fprintf(fp, " %02x", (unsigned char)sample->insn[i]);
> }
> if (PRINT_FIELD(BRSTACKINSN))
> - print_sample_brstackinsn(sample, thread, attr, machine);
> + fprint_sample_brstackinsn(sample, thread, attr, machine, fp);
> }
>
> -static void print_sample_bts(struct perf_sample *sample,
> +static void fprint_sample_bts(struct perf_sample *sample,
> struct perf_evsel *evsel,
> struct thread *thread,
> struct addr_location *al,
> - struct machine *machine)
> + struct machine *machine,
> + FILE *fp)
> {
> struct perf_event_attr *attr = &evsel->attr;
> unsigned int type = output_type(attr->type);
> bool print_srcline_last = false;
>
> if (PRINT_FIELD(CALLINDENT))
> - print_sample_callindent(sample, evsel, thread, al);
> + fprint_sample_callindent(sample, evsel, thread, al, fp);
>
> /* print branch_from information */
> if (PRINT_FIELD(IP)) {
> @@ -1046,31 +1052,31 @@ static void print_sample_bts(struct perf_sample *sample,
> cursor = &callchain_cursor;
>
> if (cursor == NULL) {
> - putchar(' ');
> + fputc(' ', fp);
> if (print_opts & EVSEL__PRINT_SRCLINE) {
> print_srcline_last = true;
> print_opts &= ~EVSEL__PRINT_SRCLINE;
> }
> } else
> - putchar('\n');
> + fputc('\n', fp);
>
> - sample__fprintf_sym(sample, al, 0, print_opts, cursor, stdout);
> + sample__fprintf_sym(sample, al, 0, print_opts, cursor, fp);
> }
>
> /* print branch_to information */
> if (PRINT_FIELD(ADDR) ||
> ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
> !output[type].user_set)) {
> - printf(" => ");
> - print_sample_addr(sample, thread, attr);
> + fprintf(fp, " => ");
> + fprint_sample_addr(sample, thread, attr, fp);
> }
>
> if (print_srcline_last)
> - map__fprintf_srcline(al->map, al->addr, "\n ", stdout);
> + map__fprintf_srcline(al->map, al->addr, "\n ", fp);
>
> - print_insn(sample, attr, thread, machine);
> + fprint_insn(sample, attr, thread, machine, fp);
>
> - printf("\n");
> + fprintf(fp, "\n");
> }
>
> static struct {
> @@ -1093,7 +1099,7 @@ static void print_sample_bts(struct perf_sample *sample,
> {0, NULL}
> };
>
> -static void print_sample_flags(u32 flags)
> +static void fprint_sample_flags(u32 flags, FILE *fp)
> {
> const char *chars = PERF_IP_FLAG_CHARS;
> const int n = strlen(PERF_IP_FLAG_CHARS);
> @@ -1120,51 +1126,53 @@ static void print_sample_flags(u32 flags)
> str[pos] = 0;
>
> if (name)
> - printf(" %-7s%4s ", name, in_tx ? "(x)" : "");
> + fprintf(fp, " %-7s%4s ", name, in_tx ? "(x)" : "");
> else
> - printf(" %-11s ", str);
> + fprintf(fp, " %-11s ", str);
> }
>
> struct printer_data {
> int line_no;
> bool hit_nul;
> bool is_printable;
> + FILE *fp;
> };
>
> static void
> -print_sample_bpf_output_printer(enum binary_printer_ops op,
> +fprint_sample_bpf_output_printer(enum binary_printer_ops op,
> unsigned int val,
> void *extra)
> {
> unsigned char ch = (unsigned char)val;
> struct printer_data *printer_data = extra;
> + FILE *fp = printer_data->fp;
>
> switch (op) {
> case BINARY_PRINT_DATA_BEGIN:
> - printf("\n");
> + fprintf(fp, "\n");
> break;
> case BINARY_PRINT_LINE_BEGIN:
> - printf("%17s", !printer_data->line_no ? "BPF output:" :
> + fprintf(fp, "%17s", !printer_data->line_no ? "BPF output:" :
> " ");
> break;
> case BINARY_PRINT_ADDR:
> - printf(" %04x:", val);
> + fprintf(fp, " %04x:", val);
> break;
> case BINARY_PRINT_NUM_DATA:
> - printf(" %02x", val);
> + fprintf(fp, " %02x", val);
> break;
> case BINARY_PRINT_NUM_PAD:
> - printf(" ");
> + fprintf(fp, " ");
> break;
> case BINARY_PRINT_SEP:
> - printf(" ");
> + fprintf(fp, " ");
> break;
> case BINARY_PRINT_CHAR_DATA:
> if (printer_data->hit_nul && ch)
> printer_data->is_printable = false;
>
> if (!isprint(ch)) {
> - printf("%c", '.');
> + fprintf(fp, "%c", '.');
>
> if (!printer_data->is_printable)
> break;
> @@ -1174,14 +1182,14 @@ struct printer_data {
> else
> printer_data->is_printable = false;
> } else {
> - printf("%c", ch);
> + fprintf(fp, "%c", ch);
> }
> break;
> case BINARY_PRINT_CHAR_PAD:
> - printf(" ");
> + fprintf(fp, " ");
> break;
> case BINARY_PRINT_LINE_END:
> - printf("\n");
> + fprintf(fp, "\n");
> printer_data->line_no++;
> break;
> case BINARY_PRINT_DATA_END:
> @@ -1190,31 +1198,31 @@ struct printer_data {
> }
> }
>
> -static void print_sample_bpf_output(struct perf_sample *sample)
> +static void fprint_sample_bpf_output(struct perf_sample *sample, FILE *fp)
> {
> unsigned int nr_bytes = sample->raw_size;
> - struct printer_data printer_data = {0, false, true};
> + struct printer_data printer_data = {0, false, true, fp};
>
> print_binary(sample->raw_data, nr_bytes, 8,
> - print_sample_bpf_output_printer, &printer_data);
> + fprint_sample_bpf_output_printer, &printer_data);
>
> if (printer_data.is_printable && printer_data.hit_nul)
> - printf("%17s \"%s\"\n", "BPF string:",
> + fprintf(fp, "%17s \"%s\"\n", "BPF string:",
> (char *)(sample->raw_data));
> }
>
> -static void print_sample_spacing(int len, int spacing)
> +static void fprint_sample_spacing(int len, int spacing, FILE *fp)
> {
> if (len > 0 && len < spacing)
> - printf("%*s", spacing - len, "");
> + fprintf(fp, "%*s", spacing - len, "");
> }
>
> -static void print_sample_pt_spacing(int len)
> +static void fprint_sample_pt_spacing(int len, FILE *fp)
> {
> - print_sample_spacing(len, 34);
> + fprint_sample_spacing(len, 34, fp);
> }
>
> -static void print_sample_synth_ptwrite(struct perf_sample *sample)
> +static void fprint_sample_synth_ptwrite(struct perf_sample *sample, FILE *fp)
> {
> struct perf_synth_intel_ptwrite *data = perf_sample__synth_ptr(sample);
> int len;
> @@ -1222,12 +1230,12 @@ static void print_sample_synth_ptwrite(struct perf_sample *sample)
> if (perf_sample__bad_synth_size(sample, *data))
> return;
>
> - len = printf(" IP: %u payload: %#" PRIx64 " ",
> + len = fprintf(fp, " IP: %u payload: %#" PRIx64 " ",
> data->ip, le64_to_cpu(data->payload));
> - print_sample_pt_spacing(len);
> + fprint_sample_pt_spacing(len, fp);
> }
>
> -static void print_sample_synth_mwait(struct perf_sample *sample)
> +static void fprint_sample_synth_mwait(struct perf_sample *sample, FILE *fp)
> {
> struct perf_synth_intel_mwait *data = perf_sample__synth_ptr(sample);
> int len;
> @@ -1235,12 +1243,12 @@ static void print_sample_synth_mwait(struct perf_sample *sample)
> if (perf_sample__bad_synth_size(sample, *data))
> return;
>
> - len = printf(" hints: %#x extensions: %#x ",
> + len = fprintf(fp, " hints: %#x extensions: %#x ",
> data->hints, data->extensions);
> - print_sample_pt_spacing(len);
> + fprint_sample_pt_spacing(len, fp);
> }
>
> -static void print_sample_synth_pwre(struct perf_sample *sample)
> +static void fprint_sample_synth_pwre(struct perf_sample *sample, FILE *fp)
> {
> struct perf_synth_intel_pwre *data = perf_sample__synth_ptr(sample);
> int len;
> @@ -1248,12 +1256,12 @@ static void print_sample_synth_pwre(struct perf_sample *sample)
> if (perf_sample__bad_synth_size(sample, *data))
> return;
>
> - len = printf(" hw: %u cstate: %u sub-cstate: %u ",
> + len = fprintf(fp, " hw: %u cstate: %u sub-cstate: %u ",
> data->hw, data->cstate, data->subcstate);
> - print_sample_pt_spacing(len);
> + fprint_sample_pt_spacing(len, fp);
> }
>
> -static void print_sample_synth_exstop(struct perf_sample *sample)
> +static void fprint_sample_synth_exstop(struct perf_sample *sample, FILE *fp)
> {
> struct perf_synth_intel_exstop *data = perf_sample__synth_ptr(sample);
> int len;
> @@ -1261,11 +1269,11 @@ static void print_sample_synth_exstop(struct perf_sample *sample)
> if (perf_sample__bad_synth_size(sample, *data))
> return;
>
> - len = printf(" IP: %u ", data->ip);
> - print_sample_pt_spacing(len);
> + len = fprintf(fp, " IP: %u ", data->ip);
> + fprint_sample_pt_spacing(len, fp);
> }
>
> -static void print_sample_synth_pwrx(struct perf_sample *sample)
> +static void fprint_sample_synth_pwrx(struct perf_sample *sample, FILE *fp)
> {
> struct perf_synth_intel_pwrx *data = perf_sample__synth_ptr(sample);
> int len;
> @@ -1273,13 +1281,13 @@ static void print_sample_synth_pwrx(struct perf_sample *sample)
> if (perf_sample__bad_synth_size(sample, *data))
> return;
>
> - len = printf(" deepest cstate: %u last cstate: %u wake reason: %#x ",
> + len = fprintf(fp, " deepest cstate: %u last cstate: %u wake reason: %#x ",
> data->deepest_cstate, data->last_cstate,
> data->wake_reason);
> - print_sample_pt_spacing(len);
> + fprint_sample_pt_spacing(len, fp);
> }
>
> -static void print_sample_synth_cbr(struct perf_sample *sample)
> +static void fprint_sample_synth_cbr(struct perf_sample *sample, FILE *fp)
> {
> struct perf_synth_intel_cbr *data = perf_sample__synth_ptr(sample);
> unsigned int percent, freq;
> @@ -1289,35 +1297,35 @@ static void print_sample_synth_cbr(struct perf_sample *sample)
> return;
>
> freq = (le32_to_cpu(data->freq) + 500) / 1000;
> - len = printf(" cbr: %2u freq: %4u MHz ", data->cbr, freq);
> + len = fprintf(fp, " cbr: %2u freq: %4u MHz ", data->cbr, freq);
> if (data->max_nonturbo) {
> percent = (5 + (1000 * data->cbr) / data->max_nonturbo) / 10;
> - len += printf("(%3u%%) ", percent);
> + len += fprintf(fp, "(%3u%%) ", percent);
> }
> - print_sample_pt_spacing(len);
> + fprint_sample_pt_spacing(len, fp);
> }
>
> -static void print_sample_synth(struct perf_sample *sample,
> - struct perf_evsel *evsel)
> +static void fprint_sample_synth(struct perf_sample *sample,
> + struct perf_evsel *evsel, FILE *fp)
> {
> switch (evsel->attr.config) {
> case PERF_SYNTH_INTEL_PTWRITE:
> - print_sample_synth_ptwrite(sample);
> + fprint_sample_synth_ptwrite(sample, fp);
> break;
> case PERF_SYNTH_INTEL_MWAIT:
> - print_sample_synth_mwait(sample);
> + fprint_sample_synth_mwait(sample, fp);
> break;
> case PERF_SYNTH_INTEL_PWRE:
> - print_sample_synth_pwre(sample);
> + fprint_sample_synth_pwre(sample, fp);
> break;
> case PERF_SYNTH_INTEL_EXSTOP:
> - print_sample_synth_exstop(sample);
> + fprint_sample_synth_exstop(sample, fp);
> break;
> case PERF_SYNTH_INTEL_PWRX:
> - print_sample_synth_pwrx(sample);
> + fprint_sample_synth_pwrx(sample, fp);
> break;
> case PERF_SYNTH_INTEL_CBR:
> - print_sample_synth_cbr(sample);
> + fprint_sample_synth_cbr(sample, fp);
> break;
> default:
> break;
> @@ -1353,7 +1361,7 @@ static int perf_evlist__max_name_len(struct perf_evlist *evlist)
> return max;
> }
>
> -static size_t data_src__printf(u64 data_src)
> +static size_t data_src__fprintf(u64 data_src, FILE *fp)
> {
> struct mem_info mi = { .data_src.val = data_src };
> char decode[100];
> @@ -1367,59 +1375,69 @@ static size_t data_src__printf(u64 data_src)
> if (maxlen < len)
> maxlen = len;
>
> - return printf("%-*s", maxlen, out);
> + return fprintf(fp, "%-*s", maxlen, out);
> }
>
> +#define FILE_LEN 100
> static void process_event(struct perf_script *script,
> struct perf_sample *sample, struct perf_evsel *evsel,
> struct addr_location *al,
> - struct machine *machine)
> + struct machine *machine, FILE *fp)
> {
> struct thread *thread = al->thread;
> struct perf_event_attr *attr = &evsel->attr;
> unsigned int type = output_type(attr->type);
> -
> + const char *evname;
> + char *file_name;
> if (output[type].fields == 0)
> return;
>
> - print_sample_start(sample, thread, evsel);
> + evname = perf_evsel__name(evsel);
> + if (script->tool.orientation_output == true) {
> + file_name = (char *)malloc(sizeof(char) * FILE_LEN);
> + strcpy(file_name, evname);
> + strcat(file_name, ".stacks");
> + fp = fopen(file_name, "a+");
> + if (!fp)
> + return;
> + free(file_name);
> + }
> + fprint_sample_start(sample, thread, evsel, fp);
>
> if (PRINT_FIELD(PERIOD))
> - printf("%10" PRIu64 " ", sample->period);
> + fprintf(fp, "%10" PRIu64 " ", sample->period);
>
> if (PRINT_FIELD(EVNAME)) {
> - const char *evname = perf_evsel__name(evsel);
> -
> if (!script->name_width)
> script->name_width = perf_evlist__max_name_len(script->session->evlist);
>
> - printf("%*s: ", script->name_width,
> + fprintf(fp, "%*s: ", script->name_width,
> evname ? evname : "[unknown]");
> }
>
> if (print_flags)
> - print_sample_flags(sample->flags);
> + fprint_sample_flags(sample->flags, fp);
>
> if (is_bts_event(attr)) {
> - print_sample_bts(sample, evsel, thread, al, machine);
> + fprint_sample_bts(sample, evsel, thread, al, machine, fp);
> return;
> }
>
> if (PRINT_FIELD(TRACE))
> - event_format__print(evsel->tp_format, sample->cpu,
> - sample->raw_data, sample->raw_size);
> + event_format__fprintf(evsel->tp_format, sample->cpu,
> + sample->raw_data, sample->raw_size, fp);
>
> if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH))
> - print_sample_synth(sample, evsel);
> + fprint_sample_synth(sample, evsel, fp);
>
> if (PRINT_FIELD(ADDR))
> - print_sample_addr(sample, thread, attr);
> + fprint_sample_addr(sample, thread, attr, fp);
>
> if (PRINT_FIELD(DATA_SRC))
> - data_src__printf(sample->data_src);
> + data_src__fprintf(sample->data_src, fp);
>
> if (PRINT_FIELD(WEIGHT))
> - printf("%16" PRIu64, sample->weight);
> + fprintf(fp, "%16" PRIu64, sample->weight);
>
> if (PRINT_FIELD(IP)) {
> struct callchain_cursor *cursor = NULL;
> @@ -1429,24 +1447,26 @@ static void process_event(struct perf_script *script,
> sample, NULL, NULL, scripting_max_stack) == 0)
> cursor = &callchain_cursor;
>
> - putchar(cursor ? '\n' : ' ');
> - sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, stdout);
> + fputc(cursor ? '\n' : ' ', fp);
> + sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, fp);
> }
>
> if (PRINT_FIELD(IREGS))
> - print_sample_iregs(sample, attr);
> + fprint_sample_iregs(sample, attr, fp);
>
> if (PRINT_FIELD(BRSTACK))
> - print_sample_brstack(sample, thread, attr);
> + fprint_sample_brstack(sample, thread, attr, fp);
> else if (PRINT_FIELD(BRSTACKSYM))
> - print_sample_brstacksym(sample, thread, attr);
> + fprint_sample_brstacksym(sample, thread, attr, fp);
> else if (PRINT_FIELD(BRSTACKOFF))
> - print_sample_brstackoff(sample, thread, attr);
> + fprint_sample_brstackoff(sample, thread, attr, fp);
>
> if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT))
> - print_sample_bpf_output(sample);
> - print_insn(sample, attr, thread, machine);
> - printf("\n");
> + fprint_sample_bpf_output(sample, fp);
> + fprint_insn(sample, attr, thread, machine, fp);
> + fprintf(fp, "\n");
> + if (script->tool.orientation_output == true)
> + fclose(fp);
> }
>
> static struct scripting_ops *scripting_ops;
> @@ -1554,9 +1574,12 @@ static int process_sample_event(struct perf_tool *tool,
>
> if (scripting_ops)
> scripting_ops->process_event(event, sample, evsel, &al);
> - else
> - process_event(scr, sample, evsel, &al, machine);
> -
> + else {
> + if (tool->orientation_output == false)
> + process_event(scr, sample, evsel, &al, machine, stdout);
> + else
> + process_event(scr, sample, evsel, &al, machine, orientation_file);
> + }
> out_put:
> addr_location__put(&al);
> return 0;
> @@ -1620,8 +1643,13 @@ static int process_comm_event(struct perf_tool *tool,
> sample->tid = event->comm.tid;
> sample->pid = event->comm.pid;
> }
> - print_sample_start(sample, thread, evsel);
> - perf_event__fprintf(event, stdout);
> + if (tool->orientation_output == false) {
> + fprint_sample_start(sample, thread, evsel, stdout);
> + perf_event__fprintf(event, stdout);
> + } else {
> + fprint_sample_start(sample, thread, evsel, orientation_file);
> + perf_event__fprintf(event, orientation_file);
> + }
> ret = 0;
> out:
> thread__put(thread);
> @@ -1655,8 +1683,13 @@ static int process_namespaces_event(struct perf_tool *tool,
> sample->tid = event->namespaces.tid;
> sample->pid = event->namespaces.pid;
> }
> - print_sample_start(sample, thread, evsel);
> - perf_event__fprintf(event, stdout);
> + if (tool->orientation_output == false) {
> + fprint_sample_start(sample, thread, evsel, stdout);
> + perf_event__fprintf(event, stdout);
> + } else {
> + fprint_sample_start(sample, thread, evsel, orientation_file);
> + perf_event__fprintf(event, orientation_file);
> + }
> ret = 0;
> out:
> thread__put(thread);
> @@ -1688,8 +1721,13 @@ static int process_fork_event(struct perf_tool *tool,
> sample->tid = event->fork.tid;
> sample->pid = event->fork.pid;
> }
> - print_sample_start(sample, thread, evsel);
> - perf_event__fprintf(event, stdout);
> + if (tool->orientation_output == false) {
> + fprint_sample_start(sample, thread, evsel, stdout);
> + perf_event__fprintf(event, stdout);
> + } else {
> + fprint_sample_start(sample, thread, evsel, orientation_file);
> + perf_event__fprintf(event, orientation_file);
> + }
> thread__put(thread);
>
> return 0;
> @@ -1717,8 +1755,13 @@ static int process_exit_event(struct perf_tool *tool,
> sample->tid = event->fork.tid;
> sample->pid = event->fork.pid;
> }
> - print_sample_start(sample, thread, evsel);
> - perf_event__fprintf(event, stdout);
> + if (tool->orientation_output == false) {
> + fprint_sample_start(sample, thread, evsel, stdout);
> + perf_event__fprintf(event, stdout);
> + } else {
> + fprint_sample_start(sample, thread, evsel, orientation_file);
> + perf_event__fprintf(event, orientation_file);
> + }
>
> if (perf_event__process_exit(tool, event, sample, machine) < 0)
> err = -1;
> @@ -1752,8 +1795,13 @@ static int process_mmap_event(struct perf_tool *tool,
> sample->tid = event->mmap.tid;
> sample->pid = event->mmap.pid;
> }
> - print_sample_start(sample, thread, evsel);
> - perf_event__fprintf(event, stdout);
> + if (tool->orientation_output == false) {
> + fprint_sample_start(sample, thread, evsel, stdout);
> + perf_event__fprintf(event, stdout);
> + } else {
> + fprint_sample_start(sample, thread, evsel, orientation_file);
> + perf_event__fprintf(event, orientation_file);
> + }
> thread__put(thread);
> return 0;
> }
> @@ -1783,8 +1831,13 @@ static int process_mmap2_event(struct perf_tool *tool,
> sample->tid = event->mmap2.tid;
> sample->pid = event->mmap2.pid;
> }
> - print_sample_start(sample, thread, evsel);
> - perf_event__fprintf(event, stdout);
> + if (tool->orientation_output == false) {
> + fprint_sample_start(sample, thread, evsel, stdout);
> + perf_event__fprintf(event, stdout);
> + } else {
> + fprint_sample_start(sample, thread, evsel, orientation_file);
> + perf_event__fprintf(event, orientation_file);
> + }
> thread__put(thread);
> return 0;
> }
> @@ -1809,8 +1862,13 @@ static int process_switch_event(struct perf_tool *tool,
> return -1;
> }
>
> - print_sample_start(sample, thread, evsel);
> - perf_event__fprintf(event, stdout);
> + if (tool->orientation_output == false) {
> + fprint_sample_start(sample, thread, evsel, stdout);
> + perf_event__fprintf(event, stdout);
> + } else {
> + fprint_sample_start(sample, thread, evsel, orientation_file);
> + perf_event__fprintf(event, orientation_file);
> + }
> thread__put(thread);
> return 0;
> }
> @@ -2690,6 +2748,7 @@ int cmd_script(int argc, const char **argv)
> .cpu_map = process_cpu_map_event,
> .ordered_events = true,
> .ordering_requires_timestamps = true,
> + .orientation_output = false,
> },
> };
> struct perf_data_file file = {
> @@ -2761,6 +2820,8 @@ int cmd_script(int argc, const char **argv)
> OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events,
> "Show namespace events (if recorded)"),
> OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
> + OPT_BOOLEAN('O', "orientation", &script.tool.orientation_output,
> + "print trace output to files named by the monitored events"),
> OPT_INTEGER(0, "max-blocks", &max_blocks,
> "Maximum number of code blocks to dump with brstackinsn"),
> OPT_BOOLEAN(0, "ns", &nanosecs,
> @@ -2797,6 +2858,12 @@ int cmd_script(int argc, const char **argv)
>
> file.path = input_name;
> file.force = symbol_conf.force;
> + for (i = 1; argv[i] != NULL; i++) {
> + if (strcmp(argv[i], "-O") == 0) {
> + script.tool.orientation_output = true;
> + break;
> + }
> + }
>
> if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
> rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
> diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
> index d549e50..131b6e4 100644
> --- a/tools/perf/util/tool.h
> +++ b/tools/perf/util/tool.h
> @@ -75,6 +75,7 @@ struct perf_tool {
> bool ordered_events;
> bool ordering_requires_timestamps;
> bool namespace_events;
> + bool orientation_output;
> enum show_feature_header show_feat_hdr;
> };
>
> --
> 1.8.3.1