mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-23 02:04:02 +00:00
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: e1cc918b6c ("perf stat: Drop metric-unit if unit is NULL")
Signed-off-by: James Clark <james.clark@linaro.org>
Tested-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Tim Chen <tim.c.chen@linux.intel.com>
Cc: Yicong Yang <yangyicong@hisilicon.com>
Link: https://lore.kernel.org/r/20241112160048.951213-2-james.clark@linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
105 lines
3.6 KiB
Python
105 lines
3.6 KiB
Python
#!/usr/bin/python
|
|
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
|
# Basic sanity check of perf JSON output as specified in the man page.
|
|
|
|
import argparse
|
|
import sys
|
|
import json
|
|
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument('--no-args', action='store_true')
|
|
ap.add_argument('--interval', action='store_true')
|
|
ap.add_argument('--system-wide-no-aggr', action='store_true')
|
|
ap.add_argument('--system-wide', action='store_true')
|
|
ap.add_argument('--event', action='store_true')
|
|
ap.add_argument('--per-core', action='store_true')
|
|
ap.add_argument('--per-thread', action='store_true')
|
|
ap.add_argument('--per-cache', action='store_true')
|
|
ap.add_argument('--per-cluster', action='store_true')
|
|
ap.add_argument('--per-die', action='store_true')
|
|
ap.add_argument('--per-node', action='store_true')
|
|
ap.add_argument('--per-socket', action='store_true')
|
|
ap.add_argument('--file', type=argparse.FileType('r'), default=sys.stdin)
|
|
args = ap.parse_args()
|
|
|
|
Lines = args.file.readlines()
|
|
|
|
def isfloat(num):
|
|
try:
|
|
float(num)
|
|
return True
|
|
except ValueError:
|
|
return False
|
|
|
|
|
|
def isint(num):
|
|
try:
|
|
int(num)
|
|
return True
|
|
except ValueError:
|
|
return False
|
|
|
|
def is_counter_value(num):
|
|
return isfloat(num) or num == '<not counted>' or num == '<not supported>'
|
|
|
|
def check_json_output(expected_items):
|
|
checks = {
|
|
'aggregate-number': lambda x: isfloat(x),
|
|
'core': lambda x: True,
|
|
'counter-value': lambda x: is_counter_value(x),
|
|
'cgroup': lambda x: True,
|
|
'cpu': lambda x: isint(x),
|
|
'cache': lambda x: True,
|
|
'cluster': lambda x: True,
|
|
'die': lambda x: True,
|
|
'event': lambda x: True,
|
|
'event-runtime': lambda x: isfloat(x),
|
|
'interval': lambda x: isfloat(x),
|
|
'metric-unit': lambda x: True,
|
|
'metric-value': lambda x: isfloat(x),
|
|
'metric-threshold': lambda x: x in ['unknown', 'good', 'less good', 'nearly bad', 'bad'],
|
|
'metricgroup': lambda x: True,
|
|
'node': lambda x: True,
|
|
'pcnt-running': lambda x: isfloat(x),
|
|
'socket': lambda x: True,
|
|
'thread': lambda x: True,
|
|
'unit': lambda x: True,
|
|
}
|
|
input = '[\n' + ','.join(Lines) + '\n]'
|
|
for item in json.loads(input):
|
|
if expected_items != -1:
|
|
count = len(item)
|
|
if count not in expected_items and count >= 1 and count <= 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 multiplexing.
|
|
pass
|
|
elif count not in expected_items and count >= 1 and count <= 5 and 'metricgroup' in item:
|
|
pass
|
|
elif count - 1 in expected_items and 'metric-threshold' in item:
|
|
pass
|
|
elif count not in expected_items:
|
|
raise RuntimeError(f'wrong number of fields. counted {count} expected {expected_items}'
|
|
f' in \'{item}\'')
|
|
for key, value in item.items():
|
|
if key not in checks:
|
|
raise RuntimeError(f'Unexpected key: key={key} value={value}')
|
|
if not checks[key](value):
|
|
raise RuntimeError(f'Check failed for: key={key} value={value}')
|
|
|
|
|
|
try:
|
|
if args.no_args or args.system_wide or args.event:
|
|
expected_items = [5, 7]
|
|
elif args.interval or args.per_thread or args.system_wide_no_aggr:
|
|
expected_items = [6, 8]
|
|
elif args.per_core or args.per_socket or args.per_node or args.per_die or args.per_cluster or args.per_cache:
|
|
expected_items = [7, 9]
|
|
else:
|
|
# If no option is specified, don't check the number of items.
|
|
expected_items = -1
|
|
check_json_output(expected_items)
|
|
except:
|
|
print('Test failed for input:\n' + '\n'.join(Lines))
|
|
raise
|