[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20250902114837.274786-1-pablo@sifflez.org>
Date: Tue, 2 Sep 2025 13:48:37 +0200
From: Pablo de Oliveira Castro <pablo@...flez.org>
To: Peter Zijlstra <peterz@...radead.org>,
Ingo Molnar <mingo@...hat.com>
Cc: Arnaldo Carvalho de Melo <acme@...nel.org>,
Namhyung Kim <namhyung@...nel.org>,
Mark Rutland <mark.rutland@....com>,
Alexander Shishkin <alexander.shishkin@...ux.intel.com>,
Jiri Olsa <jolsa@...nel.org>,
Ian Rogers <irogers@...gle.com>,
Adrian Hunter <adrian.hunter@...el.com>,
Kan Liang <kan.liang@...ux.intel.com>,
James Clark <james.clark@...aro.org>,
Pablo de Oliveira Castro <pablo@...flez.org>,
linux-perf-users@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH] perf stat: fix JSON output with non-C locales
When running `perf stat -j` under a locale that uses ',' as radix point
separator (e.g. LC_NUMERIC=fr_FR.UTF-8), the JSON output becomes
invalid. This is reproducible with perf test "perf stat JSON output
linter", which fails which such locales.
Example failure:
$ LC_NUMERIC=fr_FR.UTF-8 perf test "JSON output" -v
Checking json output: no args Test failed for input:
{"counter-value" : "1,202545", "unit" : "msec", "event" :
"task-clock", "event-runtime" : 1202545, "pcnt-running" : 100,00,
"metric-value" : "0,473483", "metric-unit" : "CPUs utilized"}
json.decoder.JSONDecodeError: Expecting property name enclosed in
double quotes: line 2 column 121 (char 122)
Fix this by always using the POSIX numeric locale in json_out(),
ensuring that '.' is consistently used as the radix point in all JSON
numbers.
Signed-off-by: Pablo de Oliveira Castro <pablo@...flez.org>
---
tools/perf/util/stat-display.c | 35 +++++++++++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c
index a67b991f4e81..ff8225e7435c 100644
--- a/tools/perf/util/stat-display.c
+++ b/tools/perf/util/stat-display.c
@@ -1,6 +1,8 @@
#include <stdlib.h>
#include <stdio.h>
+#include <stdarg.h>
#include <inttypes.h>
+#include <locale.h>
#include <linux/string.h>
#include <linux/time64.h>
#include <math.h>
@@ -149,7 +151,38 @@ static const char *json_sep(struct outstate *os)
return sep;
}
-#define json_out(os, format, ...) fprintf((os)->fh, "%s" format, json_sep(os), ##__VA_ARGS__)
+/* Print formatted output using the POSIX numeric locale */
+static int clocale_fprintf(FILE *os, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ /* Create and temporarily switch to a POSIX numeric locale */
+ locale_t posix_numeric = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
+
+ if (posix_numeric) {
+ locale_t prev = uselocale(posix_numeric);
+
+ va_start(ap, fmt);
+ ret = vfprintf(os, fmt, ap);
+ va_end(ap);
+
+ /* restore previous locale */
+ uselocale(prev);
+ freelocale(posix_numeric);
+ return ret;
+ }
+
+ /* If newlocale() failed, just print with the current locale */
+ va_start(ap, fmt);
+ ret = vfprintf(os, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+/* use clocale_fprintf so the radix point is always . as required by JSON */
+#define json_out(os, format, ...) \
+ clocale_fprintf((os)->fh, "%s" format, json_sep(os), ##__VA_ARGS__)
static void print_running_json(struct outstate *os, u64 run, u64 ena)
{
--
2.43.0
Powered by blists - more mailing lists