From nobody Mon Nov 25 05:21:56 2024 Received: from mail-wm1-f50.google.com (mail-wm1-f50.google.com [209.85.128.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BA24E1E5734 for ; Wed, 30 Oct 2024 11:40:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730288409; cv=none; b=GzpgqgBYIbmSxzm8rHBeVXvu+1Zv7h/T0BwbMuCzd+v8ldHigx1vK228zZR3xtO1Ve84YDchfTMjFdOJQGxt2s7gciH8rhMj53lw5AnFXazX9DTsA3KEkAqmZdh+826AszyrrCQnR/P/cxzkUPepLUEkBgwuPNj6zBsMwAWiXDo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730288409; c=relaxed/simple; bh=hndESY0fTHq3ihnMSf4uOT1Ww2EQSwidUL8QqXZoiKk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=QFifjvJYIkzX7k+rz7n5Vpj3iffubUgeWH3qjFUvxC3Em1iT+s7/KDozozXjCcTmxyRrdrVPgs2NOTekphnFfRB417KyqdKQzbNQwt2V+LOYlx1yl2PYxoa1wzYfYrhWMG7JmQNyEfXXuOuUDukyWjyDKI/pKWvaOfIsyjhZTYY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=hYAeLGgL; arc=none smtp.client-ip=209.85.128.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="hYAeLGgL" Received: by mail-wm1-f50.google.com with SMTP id 5b1f17b1804b1-43169902057so60728525e9.0 for ; Wed, 30 Oct 2024 04:40:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1730288404; x=1730893204; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BLjvkm8Yhd4wQCCeRrOFLXQ8waVtWTu3jnkxfp+th8s=; b=hYAeLGgLGud4wmclwxGtvBdstMS2ljVBKuQuKw1eH1xaxgL0QFzoh/pNPclnmbqXr+ AU3+oorcu6LcLkIQUdw8K99evv6LH76JDVvDwKnM3gW3AMw1+9L0lticl9/dqw0jlPFr tbx1Yjafkyxl7F4Q6VMZin0f87NkTw7JRTAZEU60zYg8nipSvxu7HScx8ECgpeDS+hyz uxqmvswxTMEwf2ydaxR5SoCzS5Nk/UMDcdIz6xuUEsSQb9gDJIuk1UQyzPUHreVX389X +/Ye893rfq0eKMS8ELp3KqQ0s4rXKnNs1VpGAgRH3hImdyYgxpc9Wqm74tXq/Jwmy+7q Zyaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730288404; x=1730893204; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BLjvkm8Yhd4wQCCeRrOFLXQ8waVtWTu3jnkxfp+th8s=; b=Eh2CYao3gSLPNYNxnluZVIXYEnTaeh1Gk0iTROArkJe98WTnhAEznOlwNQNSJ26W7H GsP5/DRYdnBNofZs1Ds+B7oMXtpVEEwLxf820lkBAV0mwDvDG+1qW0PLJUjSq729CPPp 798Rv7B9YIq8vir1XvZOdAl7P/MMxWp2F7Anz+pST+VifT1bph7FlD1MSKGovC76JP0B Z9gnR6CPJCXWPu1yoxnd0Q5vJNzePfCz7kQBKLPPRoLswnoGCRIvxCMoyynpmHl2Mv4/ vlCvQ2M8zmZtKf/YwD75V79TNVNZz/XXZGfyfWOll5THGzAaIrZryMdB4VmM0rGHGedc KwcQ== X-Forwarded-Encrypted: i=1; AJvYcCX9IFBiOZVRZkmpYO2qpSRo2tQfx/zX49/Mi9/L5wW0FFZGj7urKrTelby9K17/xrG+RxvaCD9DYi9Eb+E=@vger.kernel.org X-Gm-Message-State: AOJu0YzsvNAr+UrvoCuD3ekjv6gOdSTHnFCdN/Qa2p+qbkEZYcjJWRiG OD2hyy4ic7WYYYvQJN19PV7Q5a7aFc33L2LQU+SVpSUMiKOfqvAS6Fnpt7vO5no= X-Google-Smtp-Source: AGHT+IF81T6OtIouz1Bvzt+cCbiI5hb913tC0ZONupU2KsFOBKS3JrEbdEjQh6S3Ko/XjJvzEFe7Ng== X-Received: by 2002:a05:600c:4215:b0:431:55af:a230 with SMTP id 5b1f17b1804b1-431bb9e6031mr23713295e9.33.1730288403899; Wed, 30 Oct 2024 04:40:03 -0700 (PDT) Received: from pop-os.. ([145.224.65.67]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-431bd9ca6f8sm18885045e9.39.2024.10.30.04.40.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Oct 2024 04:40:03 -0700 (PDT) From: James Clark To: linux-perf-users@vger.kernel.org, acme@kernel.org, namhyung@kernel.org, irogers@google.com, tim.c.chen@linux.intel.com Cc: James Clark , Peter Zijlstra , Ingo Molnar , Mark Rutland , Alexander Shishkin , Jiri Olsa , Adrian Hunter , "Liang, Kan" , Yicong Yang , linux-kernel@vger.kernel.org Subject: [PATCH v2 1/2] perf stat: Fix trailing comma when there is no metric unit Date: Wed, 30 Oct 2024 11:39:44 +0000 Message-Id: <20241030113946.229361-2-james.clark@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241030113946.229361-1-james.clark@linaro.org> References: <20241030113946.229361-1-james.clark@linaro.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Now that printing metric-value and metric-unit is optional, print_running_json() shouldn't add the comma in case it becomes trailing. Replace all manual json comma stuff with a json_out() function that uses the existing os->first tracking and auto inserts a comma if it's needed. Update the test to handle that two of the fields can be missing. This fixes the following test failure on Cortex A57 where the branch misses metric is missing a required event: $ perf test -vvv "json output" 106: perf stat JSON output linter: --- start --- test child forked, pid 665682 Checking json output: no args Test failed for input: ... {"counter-value" : "3112.000000", "unit" : "", "event" : "armv8_pmuv3_1/branch-misses/", "event-runtime" : 20699340, "pcnt-running" : 100.00, } ... json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 12 column 144 (char 2109) ---- end(-1) ---- 106: perf stat JSON output linter : FAILED! Fixes: e1cc918b6cfd ("perf stat: Drop metric-unit if unit is NULL") Signed-off-by: James Clark --- .../tests/shell/lib/perf_json_output_lint.py | 14 +- tools/perf/util/stat-display.c | 177 ++++++++++-------- 2 files changed, 104 insertions(+), 87 deletions(-) diff --git a/tools/perf/tests/shell/lib/perf_json_output_lint.py b/tools/pe= rf/tests/shell/lib/perf_json_output_lint.py index 8ddb85586131..b066d721f897 100644 --- a/tools/perf/tests/shell/lib/perf_json_output_lint.py +++ b/tools/perf/tests/shell/lib/perf_json_output_lint.py @@ -69,16 +69,16 @@ def check_json_output(expected_items): for item in json.loads(input): if expected_items !=3D -1: count =3D len(item) - if count !=3D expected_items and count >=3D 1 and count <=3D 7 and '= metric-value' in item: + if count not in expected_items and count >=3D 1 and count <=3D 7 and= 'metric-value' in item: # Events that generate >1 metric may have isolated metric # values and possibly other prefixes like interval, core, # aggregate-number, or event-runtime/pcnt-running from multiplexin= g. pass - elif count !=3D expected_items and count >=3D 1 and count <=3D 5 and= 'metricgroup' in item: + elif count not in expected_items and count >=3D 1 and count <=3D 5 a= nd 'metricgroup' in item: pass - elif count =3D=3D expected_items + 1 and 'metric-threshold' in item: + elif count - 1 in expected_items and 'metric-threshold' in item: pass - elif count !=3D expected_items: + elif count not in expected_items: raise RuntimeError(f'wrong number of fields. counted {count} expec= ted {expected_items}' f' in \'{item}\'') for key, value in item.items(): @@ -90,11 +90,11 @@ def check_json_output(expected_items): =20 try: if args.no_args or args.system_wide or args.event: - expected_items =3D 7 + expected_items =3D [5, 7] elif args.interval or args.per_thread or args.system_wide_no_aggr: - expected_items =3D 8 + expected_items =3D [6, 8] elif args.per_core or args.per_socket or args.per_node or args.per_die o= r args.per_cluster or args.per_cache: - expected_items =3D 9 + expected_items =3D [7, 9] else: # If no option is specified, don't check the number of items. expected_items =3D -1 diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index 53dcdf07f5a2..a5d72f4a515c 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -114,23 +114,44 @@ static void print_running_csv(struct perf_stat_config= *config, u64 run, u64 ena) fprintf(config->output, "%s%" PRIu64 "%s%.2f", config->csv_sep, run, config->csv_sep, enabled_percent); } +struct outstate { + FILE *fh; + bool newline; + bool first; + const char *prefix; + int nfields; + int aggr_nr; + struct aggr_cpu_id id; + struct evsel *evsel; + struct cgroup *cgrp; +}; =20 -static void print_running_json(struct perf_stat_config *config, u64 run, u= 64 ena) +static const char *json_sep(struct outstate *os) +{ + const char *sep =3D os->first ? "" : ", "; + + os->first =3D false; + return sep; +} + +#define json_out(os, format, ...) fprintf((os)->fh, "%s" format, json_sep(= os), ##__VA_ARGS__) + +static void print_running_json(struct outstate *os, u64 run, u64 ena) { double enabled_percent =3D 100; =20 if (run !=3D ena) enabled_percent =3D 100 * run / ena; - fprintf(config->output, "\"event-runtime\" : %" PRIu64 ", \"pcnt-running\= " : %.2f, ", - run, enabled_percent); + json_out(os, "\"event-runtime\" : %" PRIu64 ", \"pcnt-running\" : %.2f", + run, enabled_percent); } =20 -static void print_running(struct perf_stat_config *config, +static void print_running(struct perf_stat_config *config, struct outstate= *os, u64 run, u64 ena, bool before_metric) { if (config->json_output) { if (before_metric) - print_running_json(config, run, ena); + print_running_json(os, run, ena); } else if (config->csv_output) { if (before_metric) print_running_csv(config, run, ena); @@ -153,20 +174,20 @@ static void print_noise_pct_csv(struct perf_stat_conf= ig *config, fprintf(config->output, "%s%.2f%%", config->csv_sep, pct); } =20 -static void print_noise_pct_json(struct perf_stat_config *config, +static void print_noise_pct_json(struct outstate *os, double pct) { - fprintf(config->output, "\"variance\" : %.2f, ", pct); + json_out(os, "\"variance\" : %.2f", pct); } =20 -static void print_noise_pct(struct perf_stat_config *config, +static void print_noise_pct(struct perf_stat_config *config, struct outsta= te *os, double total, double avg, bool before_metric) { double pct =3D rel_stddev_stats(total, avg); =20 if (config->json_output) { if (before_metric) - print_noise_pct_json(config, pct); + print_noise_pct_json(os, pct); } else if (config->csv_output) { if (before_metric) print_noise_pct_csv(config, pct); @@ -176,7 +197,7 @@ static void print_noise_pct(struct perf_stat_config *co= nfig, } } =20 -static void print_noise(struct perf_stat_config *config, +static void print_noise(struct perf_stat_config *config, struct outstate *= os, struct evsel *evsel, double avg, bool before_metric) { struct perf_stat_evsel *ps; @@ -185,7 +206,7 @@ static void print_noise(struct perf_stat_config *config, return; =20 ps =3D evsel->stats; - print_noise_pct(config, stddev_stats(&ps->res_stats), avg, before_metric); + print_noise_pct(config, os, stddev_stats(&ps->res_stats), avg, before_met= ric); } =20 static void print_cgroup_std(struct perf_stat_config *config, const char *= cgrp_name) @@ -198,18 +219,19 @@ static void print_cgroup_csv(struct perf_stat_config = *config, const char *cgrp_n fprintf(config->output, "%s%s", config->csv_sep, cgrp_name); } =20 -static void print_cgroup_json(struct perf_stat_config *config, const char = *cgrp_name) +static void print_cgroup_json(struct outstate *os, const char *cgrp_name) { - fprintf(config->output, "\"cgroup\" : \"%s\", ", cgrp_name); + json_out(os, "\"cgroup\" : \"%s\"", cgrp_name); } =20 -static void print_cgroup(struct perf_stat_config *config, struct cgroup *c= grp) +static void print_cgroup(struct perf_stat_config *config, struct outstate = *os, + struct cgroup *cgrp) { if (nr_cgroups || config->cgroup_list) { const char *cgrp_name =3D cgrp ? cgrp->name : ""; =20 if (config->json_output) - print_cgroup_json(config, cgrp_name); + print_cgroup_json(os, cgrp_name); else if (config->csv_output) print_cgroup_csv(config, cgrp_name); else @@ -324,47 +346,45 @@ static void print_aggr_id_csv(struct perf_stat_config= *config, } } =20 -static void print_aggr_id_json(struct perf_stat_config *config, +static void print_aggr_id_json(struct perf_stat_config *config, struct out= state *os, struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr) { - FILE *output =3D config->output; - switch (config->aggr_mode) { case AGGR_CORE: - fprintf(output, "\"core\" : \"S%d-D%d-C%d\", \"aggregate-number\" : %d, = ", + json_out(os, "\"core\" : \"S%d-D%d-C%d\", \"aggregate-number\" : %d", id.socket, id.die, id.core, aggr_nr); break; case AGGR_CACHE: - fprintf(output, "\"cache\" : \"S%d-D%d-L%d-ID%d\", \"aggregate-number\" = : %d, ", + json_out(os, "\"cache\" : \"S%d-D%d-L%d-ID%d\", \"aggregate-number\" : %= d", id.socket, id.die, id.cache_lvl, id.cache, aggr_nr); break; case AGGR_CLUSTER: - fprintf(output, "\"cluster\" : \"S%d-D%d-CLS%d\", \"aggregate-number\" := %d, ", + json_out(os, "\"cluster\" : \"S%d-D%d-CLS%d\", \"aggregate-number\" : %d= ", id.socket, id.die, id.cluster, aggr_nr); break; case AGGR_DIE: - fprintf(output, "\"die\" : \"S%d-D%d\", \"aggregate-number\" : %d, ", + json_out(os, "\"die\" : \"S%d-D%d\", \"aggregate-number\" : %d", id.socket, id.die, aggr_nr); break; case AGGR_SOCKET: - fprintf(output, "\"socket\" : \"S%d\", \"aggregate-number\" : %d, ", + json_out(os, "\"socket\" : \"S%d\", \"aggregate-number\" : %d", id.socket, aggr_nr); break; case AGGR_NODE: - fprintf(output, "\"node\" : \"N%d\", \"aggregate-number\" : %d, ", + json_out(os, "\"node\" : \"N%d\", \"aggregate-number\" : %d", id.node, aggr_nr); break; case AGGR_NONE: if (evsel->percore && !config->percore_show_thread) { - fprintf(output, "\"core\" : \"S%d-D%d-C%d\"", + json_out(os, "\"core\" : \"S%d-D%d-C%d\"", id.socket, id.die, id.core); } else if (id.cpu.cpu > -1) { - fprintf(output, "\"cpu\" : \"%d\", ", + json_out(os, "\"cpu\" : \"%d\"", id.cpu.cpu); } break; case AGGR_THREAD: - fprintf(output, "\"thread\" : \"%s-%d\", ", + json_out(os, "\"thread\" : \"%s-%d\"", perf_thread_map__comm(evsel->core.threads, id.thread_idx), perf_thread_map__pid(evsel->core.threads, id.thread_idx)); break; @@ -376,29 +396,17 @@ static void print_aggr_id_json(struct perf_stat_confi= g *config, } } =20 -static void aggr_printout(struct perf_stat_config *config, +static void aggr_printout(struct perf_stat_config *config, struct outstate= *os, struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr) { if (config->json_output) - print_aggr_id_json(config, evsel, id, aggr_nr); + print_aggr_id_json(config, os, evsel, id, aggr_nr); else if (config->csv_output) print_aggr_id_csv(config, evsel, id, aggr_nr); else print_aggr_id_std(config, evsel, id, aggr_nr); } =20 -struct outstate { - FILE *fh; - bool newline; - bool first; - const char *prefix; - int nfields; - int aggr_nr; - struct aggr_cpu_id id; - struct evsel *evsel; - struct cgroup *cgrp; -}; - static void new_line_std(struct perf_stat_config *config __maybe_unused, void *ctx) { @@ -413,7 +421,7 @@ static inline void __new_line_std_csv(struct perf_stat_= config *config, fputc('\n', os->fh); if (os->prefix) fputs(os->prefix, os->fh); - aggr_printout(config, os->evsel, os->id, os->aggr_nr); + aggr_printout(config, os, os->evsel, os->id, os->aggr_nr); } =20 static inline void __new_line_std(struct outstate *os) @@ -499,9 +507,9 @@ static void print_metric_json(struct perf_stat_config *= config __maybe_unused, FILE *out =3D os->fh; =20 if (unit) { - fprintf(out, "\"metric-value\" : \"%f\", \"metric-unit\" : \"%s\"", val,= unit); + json_out(os, "\"metric-value\" : \"%f\", \"metric-unit\" : \"%s\"", val,= unit); if (thresh !=3D METRIC_THRESHOLD_UNKNOWN) { - fprintf(out, ", \"metric-threshold\" : \"%s\"", + json_out(os, "\"metric-threshold\" : \"%s\"", metric_threshold_classify__str(thresh)); } } @@ -514,9 +522,11 @@ static void new_line_json(struct perf_stat_config *con= fig, void *ctx) struct outstate *os =3D ctx; =20 fputs("\n{", os->fh); + os->first =3D true; if (os->prefix) - fprintf(os->fh, "%s", os->prefix); - aggr_printout(config, os->evsel, os->id, os->aggr_nr); + json_out(os, "%s", os->prefix); + + aggr_printout(config, os, os->evsel, os->id, os->aggr_nr); } =20 static void print_metricgroup_header_json(struct perf_stat_config *config, @@ -526,7 +536,7 @@ static void print_metricgroup_header_json(struct perf_s= tat_config *config, if (!metricgroup_name) return; =20 - fprintf(config->output, "\"metricgroup\" : \"%s\"}", metricgroup_name); + json_out((struct outstate *) ctx, "\"metricgroup\" : \"%s\"}", metricgrou= p_name); new_line_json(config, ctx); } =20 @@ -644,7 +654,6 @@ static void print_metric_only_json(struct perf_stat_con= fig *config __maybe_unuse const char *unit, double val) { struct outstate *os =3D ctx; - FILE *out =3D os->fh; char buf[64], *ends; char tbuf[1024]; const char *vals; @@ -661,8 +670,7 @@ static void print_metric_only_json(struct perf_stat_con= fig *config __maybe_unuse *ends =3D 0; if (!vals[0]) vals =3D "none"; - fprintf(out, "%s\"%s\" : \"%s\"", os->first ? "" : ", ", unit, vals); - os->first =3D false; + json_out(os, "\"%s\" : \"%s\"", unit, vals); } =20 static void new_line_metric(struct perf_stat_config *config __maybe_unused, @@ -743,28 +751,27 @@ static void print_counter_value_csv(struct perf_stat_= config *config, fprintf(output, "%s", evsel__name(evsel)); } =20 -static void print_counter_value_json(struct perf_stat_config *config, +static void print_counter_value_json(struct outstate *os, struct evsel *evsel, double avg, bool ok) { - FILE *output =3D config->output; const char *bad_count =3D evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_= SUPPORTED; =20 if (ok) - fprintf(output, "\"counter-value\" : \"%f\", ", avg); + json_out(os, "\"counter-value\" : \"%f\"", avg); else - fprintf(output, "\"counter-value\" : \"%s\", ", bad_count); + json_out(os, "\"counter-value\" : \"%s\"", bad_count); =20 if (evsel->unit) - fprintf(output, "\"unit\" : \"%s\", ", evsel->unit); + json_out(os, "\"unit\" : \"%s\"", evsel->unit); =20 - fprintf(output, "\"event\" : \"%s\", ", evsel__name(evsel)); + json_out(os, "\"event\" : \"%s\"", evsel__name(evsel)); } =20 -static void print_counter_value(struct perf_stat_config *config, +static void print_counter_value(struct perf_stat_config *config, struct ou= tstate *os, struct evsel *evsel, double avg, bool ok) { if (config->json_output) - print_counter_value_json(config, evsel, avg, ok); + print_counter_value_json(os, evsel, avg, ok); else if (config->csv_output) print_counter_value_csv(config, evsel, avg, ok); else @@ -772,12 +779,13 @@ static void print_counter_value(struct perf_stat_conf= ig *config, } =20 static void abs_printout(struct perf_stat_config *config, + struct outstate *os, struct aggr_cpu_id id, int aggr_nr, struct evsel *evsel, double avg, bool ok) { - aggr_printout(config, evsel, id, aggr_nr); - print_counter_value(config, evsel, avg, ok); - print_cgroup(config, evsel->cgrp); + aggr_printout(config, os, evsel, id, aggr_nr); + print_counter_value(config, os, evsel, avg, ok); + print_cgroup(config, os, evsel->cgrp); } =20 static bool is_mixed_hw_group(struct evsel *counter) @@ -868,17 +876,17 @@ static void printout(struct perf_stat_config *config,= struct outstate *os, out.force_header =3D false; =20 if (!config->metric_only && !counter->default_metricgroup) { - abs_printout(config, os->id, os->aggr_nr, counter, uval, ok); + abs_printout(config, os, os->id, os->aggr_nr, counter, uval, ok); =20 - print_noise(config, counter, noise, /*before_metric=3D*/true); - print_running(config, run, ena, /*before_metric=3D*/true); + print_noise(config, os, counter, noise, /*before_metric=3D*/true); + print_running(config, os, run, ena, /*before_metric=3D*/true); } =20 if (ok) { if (!config->metric_only && counter->default_metricgroup) { void *from =3D NULL; =20 - aggr_printout(config, os->evsel, os->id, os->aggr_nr); + aggr_printout(config, os, os->evsel, os->id, os->aggr_nr); /* Print out all the metricgroup with the same metric event. */ do { int num =3D 0; @@ -891,8 +899,8 @@ static void printout(struct perf_stat_config *config, s= truct outstate *os, __new_line_std_csv(config, os); } =20 - print_noise(config, counter, noise, /*before_metric=3D*/true); - print_running(config, run, ena, /*before_metric=3D*/true); + print_noise(config, os, counter, noise, /*before_metric=3D*/true); + print_running(config, os, run, ena, /*before_metric=3D*/true); from =3D perf_stat__print_shadow_stats_metricgroup(config, counter, ag= gr_idx, &num, from, &out, &config->metric_events); @@ -905,8 +913,8 @@ static void printout(struct perf_stat_config *config, s= truct outstate *os, } =20 if (!config->metric_only) { - print_noise(config, counter, noise, /*before_metric=3D*/false); - print_running(config, run, ena, /*before_metric=3D*/false); + print_noise(config, os, counter, noise, /*before_metric=3D*/false); + print_running(config, os, run, ena, /*before_metric=3D*/false); } } =20 @@ -1083,12 +1091,17 @@ static void print_counter_aggrdata(struct perf_stat= _config *config, return; =20 if (!metric_only) { - if (config->json_output) + if (config->json_output) { + os->first =3D true; fputc('{', output); - if (os->prefix) - fprintf(output, "%s", os->prefix); - else if (config->summary && config->csv_output && - !config->no_csv_summary && !config->interval) + } + if (os->prefix) { + if (config->json_output) + json_out(os, "%s", os->prefix); + else + fprintf(output, "%s", os->prefix); + } else if (config->summary && config->csv_output && + !config->no_csv_summary && !config->interval) fprintf(output, "%s%s", "summary", config->csv_sep); } =20 @@ -1114,15 +1127,19 @@ static void print_metric_begin(struct perf_stat_con= fig *config, =20 if (config->json_output) fputc('{', config->output); - if (os->prefix) - fprintf(config->output, "%s", os->prefix); =20 + if (os->prefix) { + if (config->json_output) + json_out(os, "%s", os->prefix); + else + fprintf(config->output, "%s", os->prefix); + } evsel =3D evlist__first(evlist); id =3D config->aggr_map->map[aggr_idx]; aggr =3D &evsel->stats->aggr[aggr_idx]; - aggr_printout(config, evsel, id, aggr->nr); + aggr_printout(config, os, evsel, id, aggr->nr); =20 - print_cgroup(config, os->cgrp ? : evsel->cgrp); + print_cgroup(config, os, os->cgrp ? : evsel->cgrp); } =20 static void print_metric_end(struct perf_stat_config *config, struct outst= ate *os) @@ -1343,7 +1360,7 @@ static void prepare_interval(struct perf_stat_config = *config, return; =20 if (config->json_output) - scnprintf(prefix, len, "\"interval\" : %lu.%09lu, ", + scnprintf(prefix, len, "\"interval\" : %lu.%09lu", (unsigned long) ts->tv_sec, ts->tv_nsec); else if (config->csv_output) scnprintf(prefix, len, "%lu.%09lu%s", @@ -1557,7 +1574,7 @@ static void print_footer(struct perf_stat_config *con= fig) fprintf(output, " %17.*f +- %.*f seconds time elapsed", precision, avg, precision, sd); =20 - print_noise_pct(config, sd, avg, /*before_metric=3D*/false); + print_noise_pct(config, NULL, sd, avg, /*before_metric=3D*/false); } fprintf(output, "\n\n"); =20 --=20 2.34.1