From: Ian Rogers <irogers@google.com>
To: irogers@google.com, acme@kernel.org, ctshao@google.com,
namhyung@kernel.org
Cc: adrian.hunter@intel.com, james.clark@linaro.org,
jolsa@kernel.org, linux-kernel@vger.kernel.org,
linux-perf-users@vger.kernel.org, mingo@redhat.com,
peterz@infradead.org
Subject: [PATCH v4 07/14] perf stat: Implement CSV formatting callbacks
Date: Thu, 16 Jul 2026 00:02:56 -0700 [thread overview]
Message-ID: <20260716070303.507066-8-irogers@google.com> (raw)
In-Reply-To: <20260716070303.507066-1-irogers@google.com>
This patch implements CSV output formatting callbacks inside
util/stat-print-csv.c, replacing the empty stubs introduced in Commit 1.
Defines the format-private `struct queued_event` and `struct
queued_metric` DOM nodes to buffer traversal streams, and fully
encapsulates CSV queued lists lifecycle and deallocations inside
csv_print_start() and csv_print_end().
Utilizes the newly centralized unified aggregation helpers to format CPU
and thread column prefixes cleanly, fixes metrics separators padding,
and incorporates full interval-mode timestamp printing support.
Signed-off-by: Ian Rogers <irogers@google.com>
Assisted-by: Antigravity:gemini-3.5-flash
Acked-by: Chun-Tse Shao <ctshao@google.com>
---
tools/perf/util/stat-print-csv.c | 678 ++++++++++++++++++++++++++++++-
1 file changed, 671 insertions(+), 7 deletions(-)
diff --git a/tools/perf/util/stat-print-csv.c b/tools/perf/util/stat-print-csv.c
index ee86d07636ea..f93ca1885d46 100644
--- a/tools/perf/util/stat-print-csv.c
+++ b/tools/perf/util/stat-print-csv.c
@@ -1,13 +1,677 @@
// SPDX-License-Identifier: GPL-2.0
-#include "stat-print.h"
+#include <errno.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <time.h>
+#include <stdbool.h>
#include <linux/compiler.h>
+#include <linux/list.h>
+
+#include "cpumap.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "stat-print.h"
+#include "stat.h"
+#include "thread_map.h"
+#include "debug.h"
+
+#define COMM_LEN 16
+#define PID_LEN 7
+
+struct queued_metric {
+ struct list_head list;
+ struct evsel *evsel;
+ char *name;
+ char *unit;
+ double val;
+ int aggr_idx;
+};
+
+/**
+ * struct queued_event - In-memory record of a buffered CSV counter event.
+ * @list: Linked list node for queueing.
+ * @evsel: The associated performance event selector.
+ * @name: The uniquely formatted/resolved event name.
+ * @unit: The event's unit (e.g. "msec", "cycles").
+ * @cgrp: Cgroup name (optional).
+ * @val: Raw aggregated counter value.
+ * @ena: Enabled time for multiplexing percentage.
+ * @run: Running time for multiplexing percentage.
+ * @scale: Event scale factor.
+ * @stdev_pct: Standard deviation percentage.
+ * @supported: Event hardware support indicator.
+ * @aggr_idx: Aggregation index.
+ * @metrics_list: Linked list head containing nested queued_metric structures.
+ */
+struct queued_event {
+ struct list_head list;
+ struct evsel *evsel;
+ char *name;
+ char *unit;
+ char *cgrp;
+ u64 val, ena, run;
+ double scale;
+ double stdev_pct;
+ bool supported;
+ int aggr_idx;
+ struct list_head metrics_list;
+};
+
+/**
+ * struct csv_print_state - Print state context for CSV output.
+ * @fp: File descriptor to output to.
+ * @sep: CSV column separator character/string.
+ * @timestamp: Formatted interval timestamp (optional).
+ * @events_list: Linked list head containing queued_event nodes.
+ * @current_event: Pointer to the currently active event being printed.
+ * Serves as a temporary bridge to associate streaming metrics back to
+ * their parent event node during list buffering. This relies on a
+ * strict temporal coupling in the traversal driver: the driver always
+ * invokes print_metric() callbacks for a counter synchronously and
+ * immediately after its print_event() callback, prior to advancing
+ * to the next event or aggregation node. This pointer is completely
+ * private to CSV printing, keeping the traversal driver decoupled
+ * and preserving strict encapsulation.
+ */
+struct csv_print_state {
+ FILE *fp;
+ const char *sep;
+ char timestamp[64];
+ struct list_head events_list;
+ struct queued_event *current_event;
+};
+
+/**
+ * struct csv_metric_only_print_state - Metric-only print state context for CSV output.
+ * @fp: File descriptor to output to.
+ * @sep: CSV column separator.
+ * @timestamp: Formatted interval timestamp (optional).
+ * @evlist: Evlist to query entries from.
+ * @queued_metrics: Linked list head containing queued_metric nodes.
+ */
+struct csv_metric_only_print_state {
+ FILE *fp;
+ const char *sep;
+ char timestamp[64];
+ struct evlist *evlist;
+ struct list_head queued_metrics;
+};
+
+/**
+ * print_aggr_id_csv - Print the aggregation prefix for CSV format.
+ *
+ * Copied and adapted from stat-display.c.
+ */
+static void print_aggr_id_csv(const struct perf_stat_config *config, FILE *output,
+ struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr)
+{
+ const char *sep = config->csv_sep;
+
+ switch (config->aggr_mode) {
+ case AGGR_CORE:
+ fprintf(output, "S%d-D%d-C%d%s%d%s", id.socket, id.die, id.core, sep, aggr_nr, sep);
+ break;
+ case AGGR_CACHE:
+ fprintf(output, "S%d-D%d-L%d-ID%d%s%d%s", id.socket, id.die, id.cache_lvl, id.cache,
+ sep, aggr_nr, sep);
+ break;
+ case AGGR_CLUSTER:
+ fprintf(output, "S%d-D%d-CLS%d%s%d%s", id.socket, id.die, id.cluster, sep, aggr_nr,
+ sep);
+ break;
+ case AGGR_DIE:
+ fprintf(output, "S%d-D%d%s%d%s", id.socket, id.die, sep, aggr_nr, sep);
+ break;
+ case AGGR_SOCKET:
+ fprintf(output, "S%d%s%d%s", id.socket, sep, aggr_nr, sep);
+ break;
+ case AGGR_NODE:
+ fprintf(output, "N%d%s%d%s", id.node, sep, aggr_nr, sep);
+ break;
+ case AGGR_NONE:
+ if (evsel->percore && !config->percore_show_thread)
+ fprintf(output, "S%d-D%d-C%d%s", id.socket, id.die, id.core, sep);
+ else if (id.cpu.cpu > -1)
+ fprintf(output, "CPU%d%s", id.cpu.cpu, sep);
+ break;
+ case AGGR_THREAD: {
+ const char *comm = "unknown";
+ int pid = -1;
+
+ if (evsel && evsel->core.threads && id.thread_idx >= 0 &&
+ id.thread_idx < perf_thread_map__nr(evsel->core.threads)) {
+ comm = perf_thread_map__comm(evsel->core.threads,
+ id.thread_idx);
+ pid = perf_thread_map__pid(evsel->core.threads,
+ id.thread_idx);
+ }
+ fprintf(output, "%s-%d%s", comm, pid, sep);
+ break;
+ }
+ case AGGR_GLOBAL:
+ case AGGR_UNSET:
+ case AGGR_MAX:
+ default:
+ break;
+ }
+}
+
+/*
+ * CSV Output Callbacks - Normal Mode
+ */
+
+static int csv_print_start(void *ctx, struct perf_stat_config *config __maybe_unused)
+{
+ struct csv_print_state *ps = ctx;
+
+ INIT_LIST_HEAD(&ps->events_list);
+ ps->current_event = NULL;
+ return 0;
+}
+
+static int csv_print_event(void *ctx, struct perf_stat_config *config,
+ struct evsel *evsel, int aggr_idx, u64 val, u64 ena,
+ u64 run, double stdev_pct, const char *cgrp)
+{
+ struct csv_print_state *ps = ctx;
+ struct queued_event *ev;
+ struct aggr_cpu_id id = aggr_cpu_id__empty();
+
+ if (config && config->aggr_map && aggr_idx >= 0 &&
+ aggr_idx < config->aggr_map->nr)
+ id = config->aggr_map->map[aggr_idx];
+
+ /* Skip zero counters in CSV callbacks if they qualify */
+ if (val == 0 && should_skip_zero_counter(config, evsel, &id)) {
+ ps->current_event = NULL;
+ return 0;
+ }
+
+ ev = malloc(sizeof(*ev));
+ if (!ev)
+ return -ENOMEM;
+
+ ev->name = strdup(evsel__name(evsel));
+ if (!ev->name) {
+ free(ev);
+ return -ENOMEM;
+ }
+
+ if (evsel->unit) {
+ ev->unit = strdup(evsel->unit);
+ if (!ev->unit) {
+ free(ev->name);
+ free(ev);
+ return -ENOMEM;
+ }
+ } else {
+ ev->unit = NULL;
+ }
+
+ if (cgrp && cgrp[0]) {
+ ev->cgrp = strdup(cgrp);
+ if (!ev->cgrp) {
+ free(ev->unit);
+ free(ev->name);
+ free(ev);
+ return -ENOMEM;
+ }
+ } else {
+ ev->cgrp = NULL;
+ }
+
+ ev->evsel = evsel;
+ ev->val = val;
+ ev->ena = ena;
+ ev->run = run;
+ ev->scale = evsel->scale;
+ ev->stdev_pct = stdev_pct;
+ ev->supported = evsel->supported;
+ ev->aggr_idx = aggr_idx;
+ INIT_LIST_HEAD(&ev->metrics_list);
+
+ list_add_tail(&ev->list, &ps->events_list);
+ ps->current_event = ev;
+
+ return 0;
+}
+
+static int csv_print_metric(void *ctx, struct perf_stat_config *config __maybe_unused,
+ struct evsel *evsel, int aggr_idx,
+ const char *name, const char *unit, double val,
+ enum metric_threshold_classify thresh __maybe_unused)
+{
+ struct csv_print_state *ps = ctx;
+ struct queued_metric *b;
+
+ if (!ps->current_event)
+ return 0;
+
+ if (evsel != ps->current_event->evsel) {
+ pr_err("decoupled print engine: temporal coupling violation: evsel mismatch!\n");
+ return -EINVAL;
+ }
+
+ b = malloc(sizeof(*b));
+ if (!b)
+ return -ENOMEM;
+
+ b->evsel = evsel;
+ b->name = strdup(name);
+ if (!b->name) {
+ free(b);
+ return -ENOMEM;
+ }
+
+ if (unit && unit[0]) {
+ b->unit = strdup(unit);
+ if (!b->unit) {
+ free(b->name);
+ free(b);
+ return -ENOMEM;
+ }
+ } else {
+ b->unit = NULL;
+ }
+
+ b->val = val;
+ b->aggr_idx = aggr_idx;
+ list_add_tail(&b->list, &ps->current_event->metrics_list);
+
+ return 0;
+}
+
+static int csv_print_end(void *ctx, struct perf_stat_config *config)
+{
+ struct csv_print_state *ps = ctx;
+ struct queued_event *ev, *tmp_ev;
+ struct queued_metric *met, *tmp_met;
+ FILE *output = ps->fp;
+ const char *sep = ps->sep;
+ bool has_metrics;
+
+ list_for_each_entry_safe(ev, tmp_ev, &ps->events_list, list) {
+ struct evsel *evsel = ev->evsel;
+ bool ok = (ev->run != 0 && ev->ena != 0);
+ const char *bad_count = ev->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED;
+ double enabled_percent = 100;
+
+ /* Print interval timestamp first if configured */
+ if (config->interval && ps->timestamp[0])
+ fprintf(output, "%s", ps->timestamp);
+
+ /* Print aggregation prefix first in CSV normal mode */
+ if (config->aggr_map && ev->aggr_idx >= 0) {
+ struct aggr_cpu_id id = config->aggr_map->map[ev->aggr_idx];
+ int aggr_nr = 0;
+
+ if (evsel->stats && evsel->stats->aggr)
+ aggr_nr = evsel->stats->aggr[ev->aggr_idx].nr;
+
+ print_aggr_id_csv(config, output, evsel, id, aggr_nr);
+ }
+
+ /* 1. Print Value, Unit, Name (Columns 1, 2, 3) */
+ if (ok) {
+ double sc = ev->scale;
+ double avg = ev->val * sc;
+ const char *fmt = floor(sc) != sc ? "%.2f%s" : "%.0f%s";
+
+ fprintf(output, fmt, avg, sep);
+ } else {
+ fprintf(output, "%s%s", bad_count, sep);
+ }
-int perf_stat__print_csv(struct evlist *evlist __maybe_unused,
- const struct perf_stat_config *config __maybe_unused,
- const struct target *target __maybe_unused,
- const struct timespec *ts __maybe_unused,
- int argc __maybe_unused,
- const char **argv __maybe_unused)
+ if (ev->unit)
+ fprintf(output, "%s%s", ev->unit, sep);
+ else
+ fprintf(output, "%s", sep);
+
+ fprintf(output, "%s", ev->name);
+
+ /* 2. Print Runtime and Enabled Percentage (Columns 4, 5) */
+ if (ev->run != ev->ena)
+ enabled_percent = 100.0 * ev->run / ev->ena;
+ fprintf(output, "%s%" PRIu64 "%s%.2f", sep, ev->run, sep,
+ enabled_percent);
+
+ /* 3. Print Metrics (Columns 6, 7) */
+ has_metrics = false;
+ list_for_each_entry_safe(met, tmp_met, &ev->metrics_list, list) {
+ if (!has_metrics) {
+ has_metrics = true;
+ } else {
+ fprintf(output, "\n");
+ if (config->interval && ps->timestamp[0])
+ fprintf(output, "%s", ps->timestamp);
+ if (config->aggr_map && ev->aggr_idx >= 0) {
+ struct aggr_cpu_id id = config->aggr_map->map[ev->aggr_idx];
+ int aggr_nr = 0;
+
+ if (evsel->stats && evsel->stats->aggr)
+ aggr_nr = evsel->stats->aggr[ev->aggr_idx].nr;
+
+ print_aggr_id_csv(config, output, evsel, id, aggr_nr);
+ }
+ /*
+ * Pad exactly 4 commas (Value, Unit, Name, Run, Enabled)
+ * to line up with the Metric Value column.
+ */
+ fprintf(output, "%s%s%s%s", sep, sep, sep, sep);
+ }
+ fprintf(output, "%s%.2f%s", sep, met->val, sep);
+ if (met->name && met->name[0])
+ fprintf(output, "%s", met->name);
+
+ list_del(&met->list);
+ free(met->name);
+ free(met->unit);
+ free(met);
+ }
+ if (!has_metrics)
+ fprintf(output, "%s%s", sep, sep);
+ fprintf(output, "\n");
+
+ list_del(&ev->list);
+ free(ev->name);
+ free(ev->unit);
+ free(ev->cgrp);
+ free(ev);
+ }
+ return 0;
+}
+
+static const struct perf_stat_print_callbacks csv_print_callbacks = {
+ .print_start = csv_print_start,
+ .print_end = csv_print_end,
+ .print_event = csv_print_event,
+ .print_metric = csv_print_metric,
+};
+
+/*
+ * CSV Output Callbacks - Metric-Only Mode
+ */
+
+static int csv_metric_only_print_start(void *ctx,
+ struct perf_stat_config *config __maybe_unused)
{
+ struct csv_metric_only_print_state *ps = ctx;
+
+ INIT_LIST_HEAD(&ps->queued_metrics);
return 0;
}
+
+static int csv_metric_only_print_metric(void *ctx,
+ struct perf_stat_config *config __maybe_unused,
+ struct evsel *evsel, int aggr_idx,
+ const char *name, const char *unit, double val,
+ enum metric_threshold_classify thresh __maybe_unused)
+{
+ struct csv_metric_only_print_state *ps = ctx;
+ struct queued_metric *b = malloc(sizeof(*b));
+
+ if (!b)
+ return -ENOMEM;
+
+ b->evsel = evsel;
+ b->name = strdup(name);
+ if (!b->name) {
+ free(b);
+ return -ENOMEM;
+ }
+
+ if (unit && unit[0]) {
+ b->unit = strdup(unit);
+ if (!b->unit) {
+ free(b->name);
+ free(b);
+ return -ENOMEM;
+ }
+ } else {
+ b->unit = NULL;
+ }
+
+ b->val = val;
+ b->aggr_idx = aggr_idx;
+ list_add_tail(&b->list, &ps->queued_metrics);
+
+ return 0;
+}
+
+static int csv_metric_only_print_end(void *ctx, struct perf_stat_config *config)
+{
+ struct csv_metric_only_print_state *ps = ctx;
+ FILE *output = ps->fp;
+ const char *sep = ps->sep;
+ struct queued_metric *b, *tmp;
+ char **unique_names = NULL;
+ size_t num_unique = 0;
+ size_t unique_alloc = 0;
+ int *unique_aggrs = NULL;
+ size_t num_aggrs = 0;
+ size_t aggr_alloc = 0;
+ size_t i, j;
+ int ret = 0;
+ int err;
+
+ if (list_empty(&ps->queued_metrics))
+ return 0;
+
+ /* 1. Build unique metric names and unique aggr_idx lists */
+ list_for_each_entry(b, &ps->queued_metrics, list) {
+ bool found_metric = false;
+ bool found_aggr = false;
+
+ for (i = 0; i < num_unique; i++) {
+ if (!strcmp(unique_names[i], b->name)) {
+ found_metric = true;
+ break;
+ }
+ }
+ if (!found_metric) {
+ if (num_unique >= unique_alloc) {
+ unique_alloc = unique_alloc ? unique_alloc * 2 : 16;
+ unique_names = realloc(unique_names,
+ unique_alloc * sizeof(char *));
+ if (!unique_names) {
+ ret = -ENOMEM;
+ goto cleanup_grid;
+ }
+ }
+ unique_names[num_unique++] = strdup(b->name);
+ if (!unique_names[num_unique - 1]) {
+ num_unique--;
+ ret = -ENOMEM;
+ goto cleanup_grid;
+ }
+ }
+
+ for (i = 0; i < num_aggrs; i++) {
+ if (unique_aggrs[i] == b->aggr_idx) {
+ found_aggr = true;
+ break;
+ }
+ }
+ if (!found_aggr) {
+ if (num_aggrs >= aggr_alloc) {
+ aggr_alloc = aggr_alloc ? aggr_alloc * 2 : 16;
+ unique_aggrs = realloc(unique_aggrs,
+ aggr_alloc * sizeof(int));
+ if (!unique_aggrs) {
+ ret = -ENOMEM;
+ goto cleanup_grid;
+ }
+ }
+ unique_aggrs[num_aggrs++] = b->aggr_idx;
+ }
+ }
+
+ /* 2. Print Headers (if not already printed) */
+ if (!config->metric_only_headers_printed) {
+ if (config->interval) {
+ fprintf(output, "#%s%s", "time", sep);
+ } else {
+ if (config->aggr_map && num_aggrs > 0 &&
+ config->aggr_mode != AGGR_GLOBAL) {
+ const char *header = aggr_header_csv[config->aggr_mode];
+ const char *p = header;
+
+ while (*p) {
+ if (*p == ',')
+ fputs(sep, output);
+ else
+ fputc(*p, output);
+ p++;
+ }
+ }
+ }
+
+ /* Print uniquely collected headers in exact columnar order */
+ for (i = 0; i < num_unique; i++) {
+ char *header_name = NULL;
+ /* Find first matching metric to grab its unit for the header */
+ char *unit = NULL;
+
+ list_for_each_entry(b, &ps->queued_metrics, list) {
+ if (!strcmp(b->name, unique_names[i])) {
+ unit = b->unit;
+ break;
+ }
+ }
+
+ if (unit && unit[0])
+ err = asprintf(&header_name, "%s %s", unit,
+ unique_names[i]);
+ else
+ err = asprintf(&header_name, "%s",
+ unique_names[i]);
+
+ if (err < 0 || !header_name) {
+ ret = -ENOMEM;
+ goto cleanup_grid;
+ }
+ fprintf(output, "%s%s", header_name, sep);
+ free(header_name);
+ }
+ fprintf(output, "\n");
+ config->metric_only_headers_printed = true;
+ }
+
+ /* 3. Print Values for Each Aggregation Node */
+ for (i = 0; i < num_aggrs; i++) {
+ int current_aggr = unique_aggrs[i];
+ struct evsel *last_evsel = NULL;
+
+ /* Print aggregation prefix */
+ if (config->interval && ps->timestamp[0])
+ fprintf(output, "%s", ps->timestamp);
+
+ if (config->aggr_map && current_aggr >= 0 &&
+ current_aggr < config->aggr_map->nr) {
+ struct aggr_cpu_id id = config->aggr_map->map[current_aggr];
+ int aggr_nr = 0;
+
+ /* Find evsel for this aggr_idx */
+ list_for_each_entry(b, &ps->queued_metrics, list) {
+ if (b->aggr_idx == current_aggr) {
+ last_evsel = b->evsel;
+ break;
+ }
+ }
+
+ if (last_evsel && last_evsel->stats &&
+ last_evsel->stats->aggr &&
+ current_aggr < last_evsel->stats->nr_aggr)
+ aggr_nr = last_evsel->stats->aggr[current_aggr].nr;
+
+ print_aggr_id_csv(config, output, last_evsel, id, aggr_nr);
+ }
+
+ /* Print each metric, or pad with empty comma if missing for this node */
+ for (j = 0; j < num_unique; j++) {
+ struct queued_metric *found_metric = NULL;
+
+ list_for_each_entry(b, &ps->queued_metrics, list) {
+ if (b->aggr_idx == current_aggr &&
+ !strcmp(b->name, unique_names[j])) {
+ found_metric = b;
+ break;
+ }
+ }
+
+ if (found_metric) {
+ if (isnan(found_metric->val))
+ fprintf(output, "%s", sep);
+ else
+ fprintf(output, "%.1f%s",
+ found_metric->val, sep);
+ } else {
+ /* Padding for missing metric to preserve column alignment */
+ fprintf(output, "%s", sep);
+ }
+ }
+ fprintf(output, "\n");
+ }
+
+cleanup_grid:
+ for (i = 0; i < num_unique; i++)
+ free(unique_names[i]);
+ free(unique_names);
+ free(unique_aggrs);
+
+ list_for_each_entry_safe(b, tmp, &ps->queued_metrics, list) {
+ list_del(&b->list);
+ free(b->name);
+ free(b->unit);
+ free(b);
+ }
+ return ret;
+}
+
+static const struct perf_stat_print_callbacks csv_metric_only_print_callbacks = {
+ .print_start = csv_metric_only_print_start,
+ .print_end = csv_metric_only_print_end,
+ .print_event = NULL,
+ .print_metric = csv_metric_only_print_metric,
+};
+
+int perf_stat__print_csv(struct evlist *evlist, struct perf_stat_config *config,
+ const struct target *target, const struct timespec *ts,
+ int argc, const char **argv)
+{
+ if (config->metric_only) {
+ struct csv_metric_only_print_state ps = {
+ .fp = config->output,
+ .sep = config->csv_sep,
+ .evlist = evlist,
+ };
+ if (config->interval && ts) {
+ scnprintf(ps.timestamp, sizeof(ps.timestamp), "%lu.%09lu%s",
+ (unsigned long)ts->tv_sec, ts->tv_nsec, config->csv_sep);
+ } else {
+ ps.timestamp[0] = '\0';
+ }
+ return perf_stat__print_cb(evlist, config, target, ts, argc, argv,
+ &csv_metric_only_print_callbacks, &ps);
+ } else {
+ struct csv_print_state ps = {
+ .fp = config->output,
+ .sep = config->csv_sep,
+ };
+
+
+
+ if (config->interval && ts) {
+ scnprintf(ps.timestamp, sizeof(ps.timestamp), "%lu.%09lu%s",
+ (unsigned long)ts->tv_sec, ts->tv_nsec, config->csv_sep);
+ } else {
+ ps.timestamp[0] = '\0';
+ }
+ return perf_stat__print_cb(evlist, config, target, ts, argc, argv,
+ &csv_print_callbacks, &ps);
+ }
+}
--
2.55.0.141.g00534a21ce-goog
next prev parent reply other threads:[~2026-07-16 7:03 UTC|newest]
Thread overview: 91+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-22 22:33 [RFC PATCH v1 00/14] perf stat: Decouple and modularize metrics/events output printing API Ian Rogers
2026-05-22 22:33 ` [RFC PATCH v1 01/14] perf stat: Introduce core generic print traversal engine and header stubs Ian Rogers
2026-05-22 23:47 ` sashiko-bot
2026-05-22 22:33 ` [RFC PATCH v1 02/14] perf stat: Implement standard console (STD) formatting callbacks Ian Rogers
2026-05-22 22:54 ` sashiko-bot
2026-05-22 22:33 ` [RFC PATCH v1 03/14] perf stat: Extend STD output linter to test basic New API checks Ian Rogers
2026-05-22 22:33 ` [RFC PATCH v1 04/14] perf stat: Extend STD output linter to test core aggregation checks Ian Rogers
2026-05-22 22:33 ` [RFC PATCH v1 05/14] perf stat: Extend STD output linter to test advanced PMU checks Ian Rogers
2026-05-22 22:33 ` [RFC PATCH v1 06/14] perf stat: Extend STD output linter to test metric-only checks Ian Rogers
2026-05-22 22:33 ` [RFC PATCH v1 07/14] perf stat: Implement CSV formatting callbacks Ian Rogers
2026-05-22 23:01 ` sashiko-bot
2026-05-22 22:33 ` [RFC PATCH v1 08/14] perf stat: Extend CSV output linter to test core aggregation checks Ian Rogers
2026-05-22 22:59 ` sashiko-bot
2026-05-22 22:33 ` [RFC PATCH v1 09/14] perf stat: Extend CSV output linter to test advanced PMU and metric-only checks Ian Rogers
2026-05-22 22:48 ` sashiko-bot
2026-05-22 22:33 ` [RFC PATCH v1 10/14] perf stat: Implement streaming JSON formatting callbacks Ian Rogers
2026-05-22 23:02 ` sashiko-bot
2026-05-22 22:33 ` [RFC PATCH v1 11/14] perf stat: Extend JSON output linter to test core aggregation checks Ian Rogers
2026-05-22 22:53 ` sashiko-bot
2026-05-22 22:33 ` [RFC PATCH v1 12/14] perf stat: Extend JSON output linter to test advanced PMU and metric-only checks Ian Rogers
2026-05-22 22:33 ` [RFC PATCH v1 13/14] perf stat: Add --new support to PMU metrics Python validator Ian Rogers
2026-05-22 22:33 ` [RFC PATCH v1 14/14] perf stat: Extend PMU metrics value linter to validate --new outputs Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 00/14] perf stat: Decouple and modularize metrics/events output printing API Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 01/14] perf stat: Introduce core generic print traversal engine and header stubs Ian Rogers
2026-05-25 23:38 ` Arnaldo Carvalho de Melo
2026-05-25 23:48 ` Ian Rogers
2026-05-26 0:20 ` Arnaldo Carvalho de Melo
2026-05-25 23:18 ` [RFC PATCH v2 02/14] perf stat: Implement standard console (STD) formatting callbacks Ian Rogers
2026-05-25 23:49 ` Arnaldo Carvalho de Melo
2026-05-26 0:09 ` Ian Rogers
2026-05-25 23:53 ` sashiko-bot
2026-05-25 23:18 ` [RFC PATCH v2 03/14] perf stat: Extend STD output linter to test basic New API checks Ian Rogers
2026-05-25 23:39 ` Arnaldo Carvalho de Melo
2026-05-25 23:18 ` [RFC PATCH v2 04/14] perf stat: Extend STD output linter to test core aggregation checks Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 05/14] perf stat: Extend STD output linter to test advanced PMU checks Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 06/14] perf stat: Extend STD output linter to test metric-only checks Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 07/14] perf stat: Implement CSV formatting callbacks Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 08/14] perf stat: Extend CSV output linter to test core aggregation checks Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 09/14] perf stat: Extend CSV output linter to test advanced PMU and metric-only checks Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 10/14] perf stat: Implement streaming JSON formatting callbacks Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 11/14] perf stat: Extend JSON output linter to test core aggregation checks Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 12/14] perf stat: Extend JSON output linter to test advanced PMU and metric-only checks Ian Rogers
2026-05-25 23:18 ` [RFC PATCH v2 13/14] perf stat: Add --new support to PMU metrics Python validator Ian Rogers
2026-05-25 23:19 ` [RFC PATCH v2 14/14] perf stat: Extend PMU metrics value linter to validate --new outputs Ian Rogers
2026-05-25 23:53 ` sashiko-bot
2026-06-05 18:02 ` [RFC PATCH v2 00/14] perf stat: Decouple and modularize metrics/events output printing API Chun-Tse Shao
2026-07-16 4:32 ` [PATCH v3 00/14] perf stat: Decouple printing API and introduce streaming zero-allocation printers Ian Rogers
2026-07-16 4:32 ` [PATCH v3 01/14] perf stat: Introduce core generic print traversal engine and header stubs Ian Rogers
2026-07-16 4:47 ` sashiko-bot
2026-07-16 4:32 ` [PATCH v3 02/14] perf stat: Implement standard console (STD) formatting callbacks Ian Rogers
2026-07-16 4:44 ` sashiko-bot
2026-07-16 4:32 ` [PATCH v3 03/14] perf stat: Extend STD output linter to test basic New API checks Ian Rogers
2026-07-16 4:42 ` sashiko-bot
2026-07-16 4:32 ` [PATCH v3 04/14] perf stat: Extend STD output linter to test core aggregation checks Ian Rogers
2026-07-16 4:38 ` sashiko-bot
2026-07-16 4:32 ` [PATCH v3 05/14] perf stat: Extend STD output linter to test advanced PMU checks Ian Rogers
2026-07-16 4:43 ` sashiko-bot
2026-07-16 4:32 ` [PATCH v3 06/14] perf stat: Extend STD output linter to test metric-only checks Ian Rogers
2026-07-16 4:32 ` [PATCH v3 07/14] perf stat: Implement CSV formatting callbacks Ian Rogers
2026-07-16 4:43 ` sashiko-bot
2026-07-16 4:32 ` [PATCH v3 08/14] perf stat: Extend CSV output linter to test core aggregation checks Ian Rogers
2026-07-16 4:32 ` [PATCH v3 09/14] perf stat: Extend CSV output linter to test advanced PMU and metric-only checks Ian Rogers
2026-07-16 4:32 ` [PATCH v3 10/14] perf stat: Implement streaming JSON formatting callbacks Ian Rogers
2026-07-16 4:46 ` sashiko-bot
2026-07-16 4:32 ` [PATCH v3 11/14] perf stat: Extend JSON output linter to test core aggregation checks Ian Rogers
2026-07-16 4:42 ` sashiko-bot
2026-07-16 4:32 ` [PATCH v3 12/14] perf stat: Extend JSON output linter to test advanced PMU and metric-only checks Ian Rogers
2026-07-16 4:32 ` [PATCH v3 13/14] perf stat: Add --new support to PMU metrics Python validator Ian Rogers
2026-07-16 4:52 ` sashiko-bot
2026-07-16 4:32 ` [PATCH v3 14/14] perf stat: Extend PMU metrics value linter to validate --new outputs Ian Rogers
2026-07-16 4:49 ` sashiko-bot
2026-07-16 7:02 ` [PATCH v4 00/14] perf stat: Decouple and modularize display formatting Ian Rogers
2026-07-16 7:02 ` [PATCH v4 01/14] perf stat: Introduce core generic print traversal engine and header stubs Ian Rogers
2026-07-16 7:16 ` sashiko-bot
2026-07-16 7:02 ` [PATCH v4 02/14] perf stat: Implement standard console (STD) formatting callbacks Ian Rogers
2026-07-16 7:24 ` sashiko-bot
2026-07-16 7:02 ` [PATCH v4 03/14] perf stat: Extend STD output linter to test basic New API checks Ian Rogers
2026-07-16 7:02 ` [PATCH v4 04/14] perf stat: Extend STD output linter to test core aggregation checks Ian Rogers
2026-07-16 7:02 ` [PATCH v4 05/14] perf stat: Extend STD output linter to test advanced PMU checks Ian Rogers
2026-07-16 7:02 ` [PATCH v4 06/14] perf stat: Extend STD output linter to test metric-only checks Ian Rogers
2026-07-16 7:02 ` Ian Rogers [this message]
2026-07-16 7:11 ` [PATCH v4 07/14] perf stat: Implement CSV formatting callbacks sashiko-bot
2026-07-16 7:02 ` [PATCH v4 08/14] perf stat: Extend CSV output linter to test core aggregation checks Ian Rogers
2026-07-16 7:02 ` [PATCH v4 09/14] perf stat: Extend CSV output linter to test advanced PMU and metric-only checks Ian Rogers
2026-07-16 7:02 ` [PATCH v4 10/14] perf stat: Implement streaming JSON formatting callbacks Ian Rogers
2026-07-16 7:19 ` sashiko-bot
2026-07-16 7:03 ` [PATCH v4 11/14] perf stat: Extend JSON output linter to test core aggregation checks Ian Rogers
2026-07-16 7:03 ` [PATCH v4 12/14] perf stat: Extend JSON output linter to test advanced PMU and metric-only checks Ian Rogers
2026-07-16 7:03 ` [PATCH v4 13/14] perf stat: Add --new support to PMU metrics Python validator Ian Rogers
2026-07-16 7:03 ` [PATCH v4 14/14] perf stat: Extend PMU metrics value linter to validate --new outputs Ian Rogers
2026-07-16 7:16 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260716070303.507066-8-irogers@google.com \
--to=irogers@google.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=ctshao@google.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox