perf test: Add --metric-only to perf stat output tests

Add a test case for --metric-only for std, csv, json output mode using
shadow IPC metric from instructions and cycles events.  It should
produce 'insn per cycle' metric.

But currently JSON output has (none) 'GHz' as well.  It looks like a bug
but I don't have enough time to debug it for now so I made it pass. :(

  $ perf stat --metric-only -e instructions,cycles true

   Performance counter stats for 'true':

                    0.56

         0.002127319 seconds time elapsed

         0.002077000 seconds user
         0.000000000 seconds sys

  $ perf stat -x, --metric-only -e instructions,cycles true

  0.55,,

  $ perf stat -j --metric-only -e instructions,cycles true
  {"insn per cycle" : "0.53", "GHz" : "none"}

  $ perf test output -v
    5: Test data source output                                         : Ok
   31: Sort output of hist entries                                     : Ok
   88: perf stat CSV output linter                                     : Ok
   90: perf stat JSON output linter                                    : Ok
   92: perf stat STD output linter                                     : Ok

Tested-by: Thomas Falcon <thomas.falcon@intel.com>
Link: https://lore.kernel.org/r/20250304022837.1877845-2-namhyung@kernel.org
Suggested-by: Ian Rogers <irogers@google.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Namhyung Kim 2025-03-03 18:28:32 -08:00
parent 2cc2f258a9
commit 45a86d017a
5 changed files with 34 additions and 0 deletions

View File

@ -19,6 +19,7 @@ ap.add_argument('--per-cluster', action='store_true')
ap.add_argument('--per-die', action='store_true') ap.add_argument('--per-die', action='store_true')
ap.add_argument('--per-node', action='store_true') ap.add_argument('--per-node', action='store_true')
ap.add_argument('--per-socket', action='store_true') ap.add_argument('--per-socket', action='store_true')
ap.add_argument('--metric-only', action='store_true')
ap.add_argument('--file', type=argparse.FileType('r'), default=sys.stdin) ap.add_argument('--file', type=argparse.FileType('r'), default=sys.stdin)
args = ap.parse_args() args = ap.parse_args()
@ -64,6 +65,8 @@ def check_json_output(expected_items):
'socket': lambda x: True, 'socket': lambda x: True,
'thread': lambda x: True, 'thread': lambda x: True,
'unit': lambda x: True, 'unit': lambda x: True,
'insn per cycle': lambda x: isfloat(x),
'GHz': lambda x: True, # FIXME: it seems unintended for --metric-only
} }
input = '[\n' + ','.join(Lines) + '\n]' input = '[\n' + ','.join(Lines) + '\n]'
for item in json.loads(input): for item in json.loads(input):
@ -78,6 +81,8 @@ def check_json_output(expected_items):
pass pass
elif count - 1 in expected_items and 'metric-threshold' in item: elif count - 1 in expected_items and 'metric-threshold' in item:
pass pass
elif count in expected_items and 'insn per cycle' in item:
pass
elif count not in expected_items: elif count not in expected_items:
raise RuntimeError(f'wrong number of fields. counted {count} expected {expected_items}' raise RuntimeError(f'wrong number of fields. counted {count} expected {expected_items}'
f' in \'{item}\'') f' in \'{item}\'')
@ -95,6 +100,8 @@ try:
expected_items = [6, 8] 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: 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] expected_items = [7, 9]
elif args.metric_only:
expected_items = [1, 2]
else: else:
# If no option is specified, don't check the number of items. # If no option is specified, don't check the number of items.
expected_items = -1 expected_items = -1

View File

@ -148,6 +148,14 @@ check_per_socket()
echo "[Success]" echo "[Success]"
} }
check_metric_only()
{
echo -n "Checking $1 output: metric only "
perf stat --metric-only $2 -e instructions,cycles true
commachecker --metric-only
echo "[Success]"
}
# The perf stat options for per-socket, per-core, per-die # The perf stat options for per-socket, per-core, per-die
# and -A ( no_aggr mode ) uses the info fetched from this # and -A ( no_aggr mode ) uses the info fetched from this
# directory: "/sys/devices/system/cpu/cpu*/topology". For # directory: "/sys/devices/system/cpu/cpu*/topology". For

View File

@ -44,6 +44,7 @@ function commachecker()
;; "--per-die") exp=8 ;; "--per-die") exp=8
;; "--per-cluster") exp=8 ;; "--per-cluster") exp=8
;; "--per-cache") exp=8 ;; "--per-cache") exp=8
;; "--metric-only") exp=2
esac esac
while read line while read line
@ -75,6 +76,7 @@ check_interval "CSV" "$perf_cmd"
check_event "CSV" "$perf_cmd" check_event "CSV" "$perf_cmd"
check_per_thread "CSV" "$perf_cmd" check_per_thread "CSV" "$perf_cmd"
check_per_node "CSV" "$perf_cmd" check_per_node "CSV" "$perf_cmd"
check_metric_only "CSV" "$perf_cmd"
if [ $skip_test -ne 1 ] if [ $skip_test -ne 1 ]
then then
check_system_wide_no_aggr "CSV" "$perf_cmd" check_system_wide_no_aggr "CSV" "$perf_cmd"

View File

@ -173,6 +173,14 @@ check_per_socket()
echo "[Success]" echo "[Success]"
} }
check_metric_only()
{
echo -n "Checking json output: metric only "
perf stat -j --metric-only -e instructions,cycles -o "${stat_output}" true
$PYTHON $pythonchecker --metric-only --file "${stat_output}"
echo "[Success]"
}
# The perf stat options for per-socket, per-core, per-die # The perf stat options for per-socket, per-core, per-die
# and -A ( no_aggr mode ) uses the info fetched from this # and -A ( no_aggr mode ) uses the info fetched from this
# directory: "/sys/devices/system/cpu/cpu*/topology". For # directory: "/sys/devices/system/cpu/cpu*/topology". For
@ -207,6 +215,7 @@ check_interval
check_event check_event
check_per_thread check_per_thread
check_per_node check_per_node
check_metric_only
if [ $skip_test -ne 1 ] if [ $skip_test -ne 1 ]
then then
check_system_wide_no_aggr check_system_wide_no_aggr

View File

@ -30,6 +30,7 @@ trap trap_cleanup EXIT TERM INT
function commachecker() function commachecker()
{ {
local prefix=1 local prefix=1
local -i metric_only=0
case "$1" case "$1"
in "--interval") prefix=2 in "--interval") prefix=2
@ -41,6 +42,7 @@ function commachecker()
;; "--per-die") prefix=3 ;; "--per-die") prefix=3
;; "--per-cache") prefix=3 ;; "--per-cache") prefix=3
;; "--per-cluster") prefix=3 ;; "--per-cluster") prefix=3
;; "--metric-only") metric_only=1
esac esac
while read line while read line
@ -60,6 +62,9 @@ function commachecker()
x=${main_body%#*} x=${main_body%#*}
[ "$x" = "" ] && continue [ "$x" = "" ] && continue
# Check metric only - if it has a non-empty result
[ $metric_only -eq 1 ] && return 0
# Skip metrics without event name # Skip metrics without event name
y=${main_body#*#} y=${main_body#*#}
for i in "${!skip_metric[@]}"; do for i in "${!skip_metric[@]}"; do
@ -84,6 +89,8 @@ function commachecker()
exit 1; exit 1;
} }
done < "${stat_output}" done < "${stat_output}"
[ $metric_only -eq 1 ] && exit 1
return 0 return 0
} }
@ -95,6 +102,7 @@ check_system_wide "STD" "$perf_cmd"
check_interval "STD" "$perf_cmd" check_interval "STD" "$perf_cmd"
check_per_thread "STD" "$perf_cmd" check_per_thread "STD" "$perf_cmd"
check_per_node "STD" "$perf_cmd" check_per_node "STD" "$perf_cmd"
check_metric_only "STD" "$perf_cmd"
if [ $skip_test -ne 1 ] if [ $skip_test -ne 1 ]
then then
check_system_wide_no_aggr "STD" "$perf_cmd" check_system_wide_no_aggr "STD" "$perf_cmd"