|
22 | 22 | #include "util/cpumap.h"
|
23 | 23 | #include "util/thread_map.h"
|
24 | 24 | #include "util/stat.h"
|
| 25 | +#include "util/color.h" |
25 | 26 | #include "util/string2.h"
|
26 | 27 | #include "util/thread-stack.h"
|
27 | 28 | #include "util/time-utils.h"
|
@@ -90,6 +91,7 @@ enum perf_output_field {
|
90 | 91 | PERF_OUTPUT_SYNTH = 1U << 25,
|
91 | 92 | PERF_OUTPUT_PHYS_ADDR = 1U << 26,
|
92 | 93 | PERF_OUTPUT_UREGS = 1U << 27,
|
| 94 | + PERF_OUTPUT_METRIC = 1U << 28, |
93 | 95 | };
|
94 | 96 |
|
95 | 97 | struct output_option {
|
@@ -124,6 +126,7 @@ struct output_option {
|
124 | 126 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF},
|
125 | 127 | {.str = "synth", .field = PERF_OUTPUT_SYNTH},
|
126 | 128 | {.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR},
|
| 129 | + {.str = "metric", .field = PERF_OUTPUT_METRIC}, |
127 | 130 | };
|
128 | 131 |
|
129 | 132 | enum {
|
@@ -215,20 +218,27 @@ struct perf_evsel_script {
|
215 | 218 | char *filename;
|
216 | 219 | FILE *fp;
|
217 | 220 | u64 samples;
|
| 221 | + /* For metric output */ |
| 222 | + u64 val; |
| 223 | + int gnum; |
218 | 224 | };
|
219 | 225 |
|
| 226 | +static inline struct perf_evsel_script *evsel_script(struct perf_evsel *evsel) |
| 227 | +{ |
| 228 | + return (struct perf_evsel_script *)evsel->priv; |
| 229 | +} |
| 230 | + |
220 | 231 | static struct perf_evsel_script *perf_evsel_script__new(struct perf_evsel *evsel,
|
221 | 232 | struct perf_data *data)
|
222 | 233 | {
|
223 |
| - struct perf_evsel_script *es = malloc(sizeof(*es)); |
| 234 | + struct perf_evsel_script *es = zalloc(sizeof(*es)); |
224 | 235 |
|
225 | 236 | if (es != NULL) {
|
226 | 237 | if (asprintf(&es->filename, "%s.%s.dump", data->file.path, perf_evsel__name(evsel)) < 0)
|
227 | 238 | goto out_free;
|
228 | 239 | es->fp = fopen(es->filename, "w");
|
229 | 240 | if (es->fp == NULL)
|
230 | 241 | goto out_free_filename;
|
231 |
| - es->samples = 0; |
232 | 242 | }
|
233 | 243 |
|
234 | 244 | return es;
|
@@ -1472,6 +1482,86 @@ static int data_src__fprintf(u64 data_src, FILE *fp)
|
1472 | 1482 | return fprintf(fp, "%-*s", maxlen, out);
|
1473 | 1483 | }
|
1474 | 1484 |
|
| 1485 | +struct metric_ctx { |
| 1486 | + struct perf_sample *sample; |
| 1487 | + struct thread *thread; |
| 1488 | + struct perf_evsel *evsel; |
| 1489 | + FILE *fp; |
| 1490 | +}; |
| 1491 | + |
| 1492 | +static void script_print_metric(void *ctx, const char *color, |
| 1493 | + const char *fmt, |
| 1494 | + const char *unit, double val) |
| 1495 | +{ |
| 1496 | + struct metric_ctx *mctx = ctx; |
| 1497 | + |
| 1498 | + if (!fmt) |
| 1499 | + return; |
| 1500 | + perf_sample__fprintf_start(mctx->sample, mctx->thread, mctx->evsel, |
| 1501 | + mctx->fp); |
| 1502 | + fputs("\tmetric: ", mctx->fp); |
| 1503 | + if (color) |
| 1504 | + color_fprintf(mctx->fp, color, fmt, val); |
| 1505 | + else |
| 1506 | + printf(fmt, val); |
| 1507 | + fprintf(mctx->fp, " %s\n", unit); |
| 1508 | +} |
| 1509 | + |
| 1510 | +static void script_new_line(void *ctx) |
| 1511 | +{ |
| 1512 | + struct metric_ctx *mctx = ctx; |
| 1513 | + |
| 1514 | + perf_sample__fprintf_start(mctx->sample, mctx->thread, mctx->evsel, |
| 1515 | + mctx->fp); |
| 1516 | + fputs("\tmetric: ", mctx->fp); |
| 1517 | +} |
| 1518 | + |
| 1519 | +static void perf_sample__fprint_metric(struct perf_script *script, |
| 1520 | + struct thread *thread, |
| 1521 | + struct perf_evsel *evsel, |
| 1522 | + struct perf_sample *sample, |
| 1523 | + FILE *fp) |
| 1524 | +{ |
| 1525 | + struct perf_stat_output_ctx ctx = { |
| 1526 | + .print_metric = script_print_metric, |
| 1527 | + .new_line = script_new_line, |
| 1528 | + .ctx = &(struct metric_ctx) { |
| 1529 | + .sample = sample, |
| 1530 | + .thread = thread, |
| 1531 | + .evsel = evsel, |
| 1532 | + .fp = fp, |
| 1533 | + }, |
| 1534 | + .force_header = false, |
| 1535 | + }; |
| 1536 | + struct perf_evsel *ev2; |
| 1537 | + static bool init; |
| 1538 | + u64 val; |
| 1539 | + |
| 1540 | + if (!init) { |
| 1541 | + perf_stat__init_shadow_stats(); |
| 1542 | + init = true; |
| 1543 | + } |
| 1544 | + if (!evsel->stats) |
| 1545 | + perf_evlist__alloc_stats(script->session->evlist, false); |
| 1546 | + if (evsel_script(evsel->leader)->gnum++ == 0) |
| 1547 | + perf_stat__reset_shadow_stats(); |
| 1548 | + val = sample->period * evsel->scale; |
| 1549 | + perf_stat__update_shadow_stats(evsel, |
| 1550 | + val, |
| 1551 | + sample->cpu); |
| 1552 | + evsel_script(evsel)->val = val; |
| 1553 | + if (evsel_script(evsel->leader)->gnum == evsel->leader->nr_members) { |
| 1554 | + for_each_group_member (ev2, evsel->leader) { |
| 1555 | + perf_stat__print_shadow_stats(ev2, |
| 1556 | + evsel_script(ev2)->val, |
| 1557 | + sample->cpu, |
| 1558 | + &ctx, |
| 1559 | + NULL); |
| 1560 | + } |
| 1561 | + evsel_script(evsel->leader)->gnum = 0; |
| 1562 | + } |
| 1563 | +} |
| 1564 | + |
1475 | 1565 | static void process_event(struct perf_script *script,
|
1476 | 1566 | struct perf_sample *sample, struct perf_evsel *evsel,
|
1477 | 1567 | struct addr_location *al,
|
@@ -1559,6 +1649,9 @@ static void process_event(struct perf_script *script,
|
1559 | 1649 | if (PRINT_FIELD(PHYS_ADDR))
|
1560 | 1650 | fprintf(fp, "%16" PRIx64, sample->phys_addr);
|
1561 | 1651 | fprintf(fp, "\n");
|
| 1652 | + |
| 1653 | + if (PRINT_FIELD(METRIC)) |
| 1654 | + perf_sample__fprint_metric(script, thread, evsel, sample, fp); |
1562 | 1655 | }
|
1563 | 1656 |
|
1564 | 1657 | static struct scripting_ops *scripting_ops;
|
|
0 commit comments