perf test: Add --metric-only to perf stat output tests
authorNamhyung Kim <namhyung@kernel.org>
Tue, 4 Mar 2025 02:28:32 +0000 (18:28 -0800)
committerNamhyung Kim <namhyung@kernel.org>
Wed, 5 Mar 2025 17:17:01 +0000 (09:17 -0800)
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>
tools/perf/tests/shell/lib/perf_json_output_lint.py
tools/perf/tests/shell/lib/stat_output.sh
tools/perf/tests/shell/stat+csv_output.sh
tools/perf/tests/shell/stat+json_output.sh
tools/perf/tests/shell/stat+std_output.sh

index b066d721f89735df762b4872e7d244d51423ed99..9e772a89ce38163600e58ecf6b7ba2b7519c1384 100644 (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-node', 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)
 args = ap.parse_args()
 
@@ -64,6 +65,8 @@ def check_json_output(expected_items):
       'socket': lambda x: True,
       'thread': 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]'
   for item in json.loads(input):
@@ -78,6 +81,8 @@ def check_json_output(expected_items):
         pass
       elif count - 1 in expected_items and 'metric-threshold' in item:
           pass
+      elif count in expected_items and 'insn per cycle' in item:
+          pass
       elif count not in expected_items:
         raise RuntimeError(f'wrong number of fields. counted {count} expected {expected_items}'
                            f' in \'{item}\'')
@@ -95,6 +100,8 @@ try:
     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]
+  elif args.metric_only:
+    expected_items = [1, 2]
   else:
     # If no option is specified, don't check the number of items.
     expected_items = -1
index 9a176ceae4a3c3a252d517f0415e9d87bc084507..4d4aac547f0109d14d3b935747a71d1d27d1e5db 100644 (file)
@@ -148,6 +148,14 @@ check_per_socket()
        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
 # and -A ( no_aggr mode ) uses the info fetched from this
 # directory: "/sys/devices/system/cpu/cpu*/topology". For
index fc2d8cc6e5e0b1e5b47378b4de3e079cacc32674..7a6f6e1774028322a4be0323cf724bd08ecfc3fe 100755 (executable)
@@ -44,6 +44,7 @@ function commachecker()
        ;; "--per-die")         exp=8
        ;; "--per-cluster")     exp=8
        ;; "--per-cache")       exp=8
+       ;; "--metric-only")     exp=2
        esac
 
        while read line
@@ -75,6 +76,7 @@ check_interval "CSV" "$perf_cmd"
 check_event "CSV" "$perf_cmd"
 check_per_thread "CSV" "$perf_cmd"
 check_per_node "CSV" "$perf_cmd"
+check_metric_only "CSV" "$perf_cmd"
 if [ $skip_test -ne 1 ]
 then
        check_system_wide_no_aggr "CSV" "$perf_cmd"
index 6b630d33c3287899852c3ffa2ac06df0b96614d8..a4f257ea839e1368f9fe045fcc349d162aed908d 100755 (executable)
@@ -173,6 +173,14 @@ check_per_socket()
        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
 # and -A ( no_aggr mode ) uses the info fetched from this
 # directory: "/sys/devices/system/cpu/cpu*/topology". For
@@ -207,6 +215,7 @@ check_interval
 check_event
 check_per_thread
 check_per_node
+check_metric_only
 if [ $skip_test -ne 1 ]
 then
        check_system_wide_no_aggr
index 0f7967be60afdc7d059e190ed0cb5ec566e7ac05..6fee67693ba7a9beee713c6954ab6b0bea563387 100755 (executable)
@@ -30,6 +30,7 @@ trap trap_cleanup EXIT TERM INT
 function commachecker()
 {
        local prefix=1
+       local -i metric_only=0
 
        case "$1"
        in "--interval")        prefix=2
@@ -41,6 +42,7 @@ function commachecker()
        ;; "--per-die")         prefix=3
        ;; "--per-cache")       prefix=3
        ;; "--per-cluster")     prefix=3
+       ;; "--metric-only")     metric_only=1
        esac
 
        while read line
@@ -60,6 +62,9 @@ function commachecker()
                x=${main_body%#*}
                [ "$x" = "" ] && continue
 
+               # Check metric only - if it has a non-empty result
+               [ $metric_only -eq 1 ] && return 0
+
                # Skip metrics without event name
                y=${main_body#*#}
                for i in "${!skip_metric[@]}"; do
@@ -84,6 +89,8 @@ function commachecker()
                        exit 1;
                }
        done < "${stat_output}"
+
+       [ $metric_only -eq 1 ] && exit 1
        return 0
 }
 
@@ -95,6 +102,7 @@ check_system_wide "STD" "$perf_cmd"
 check_interval "STD" "$perf_cmd"
 check_per_thread "STD" "$perf_cmd"
 check_per_node "STD" "$perf_cmd"
+check_metric_only "STD" "$perf_cmd"
 if [ $skip_test -ne 1 ]
 then
        check_system_wide_no_aggr "STD" "$perf_cmd"