[PATCH] perf script: Add script orientation output support for monitored events

From: Wind Yu
Date: Mon Aug 28 2017 - 04:44:01 EST


Introduce a new option to print trace output to files named by the
monitored events and update perf-script documentation accordingly.

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