Linux Perf Users
 help / color / mirror / Atom feed
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


  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