perf metric: Change divide by zero and !support events behavior
authorIan Rogers <irogers@google.com>
Tue, 2 May 2023 22:38:08 +0000 (15:38 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 10 May 2023 15:35:02 +0000 (12:35 -0300)
Division by zero causes expression parsing to fail and no metric to be
generated. This can mean for short running benchmarks metrics are not
shown. Change the behavior to make the value nan, which gets shown like:

'''
$ perf stat -M TopdownL2 true

 Performance counter stats for 'true':

         1,031,492      INST_RETIRED.ANY                 #      nan %  tma_fetch_bandwidth
                                                  #      nan %  tma_heavy_operations
                                                  #      nan %  tma_light_operations
            29,304      CPU_CLK_UNHALTED.REF_XCLK        #      nan %  tma_fetch_latency
                                                  #      nan %  tma_branch_mispredicts
                                                  #      nan %  tma_machine_clears
                                                  #      nan %  tma_core_bound
                                                  #      nan %  tma_memory_bound
         2,658,319      IDQ_UOPS_NOT_DELIVERED.CORE
            11,167      EXE_ACTIVITY.BOUND_ON_STORES
           262,058      EXE_ACTIVITY.1_PORTS_UTIL
     <not counted>      BR_MISP_RETIRED.ALL_BRANCHES                                            (0.00%)
     <not counted>      INT_MISC.RECOVERY_CYCLES_ANY                                            (0.00%)
     <not counted>      CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE                                        (0.00%)
     <not counted>      CPU_CLK_UNHALTED.THREAD                                                 (0.00%)
     <not counted>      UOPS_RETIRED.RETIRE_SLOTS                                               (0.00%)
     <not counted>      CYCLE_ACTIVITY.STALLS_MEM_ANY                                           (0.00%)
     <not counted>      UOPS_RETIRED.MACRO_FUSED                                                (0.00%)
     <not counted>      IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE                                        (0.00%)
     <not counted>      EXE_ACTIVITY.2_PORTS_UTIL                                               (0.00%)
     <not counted>      CYCLE_ACTIVITY.STALLS_TOTAL                                             (0.00%)
     <not counted>      MACHINE_CLEARS.COUNT                                                    (0.00%)
     <not counted>      UOPS_ISSUED.ANY                                                         (0.00%)

       0.002864879 seconds time elapsed

       0.003012000 seconds user
       0.000000000 seconds sys
'''

When events aren't supported a count of 0 can be confusing and make
metrics look meaningful. Change these to be nan also which, with the
next change, gets shown like:

'''
$ perf stat true
 Performance counter stats for 'true':

              1.25 msec task-clock:u                     #    0.387 CPUs utilized
                 0      context-switches:u               #    0.000 /sec
                 0      cpu-migrations:u                 #    0.000 /sec
                46      page-faults:u                    #   36.702 K/sec
           255,942      cycles:u                         #    0.204 GHz                         (88.66%)
           123,046      instructions:u                   #    0.48  insn per cycle
            28,301      branches:u                       #   22.580 M/sec
             2,489      branch-misses:u                  #    8.79% of all branches
             4,719      CPU_CLK_UNHALTED.REF_XCLK:u      #    3.765 M/sec
                                                  #      nan %  tma_frontend_bound
                                                  #      nan %  tma_retiring
                                                  #      nan %  tma_backend_bound
                                                  #      nan %  tma_bad_speculation
           344,855      IDQ_UOPS_NOT_DELIVERED.CORE:u    #  275.147 M/sec
   <not supported>      INT_MISC.RECOVERY_CYCLES_ANY:u
     <not counted>      CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE:u                                        (0.00%)
     <not counted>      CPU_CLK_UNHALTED.THREAD:u                                               (0.00%)
     <not counted>      UOPS_RETIRED.RETIRE_SLOTS:u                                             (0.00%)
     <not counted>      UOPS_ISSUED.ANY:u                                                       (0.00%)

       0.003238142 seconds time elapsed

       0.000000000 seconds user
       0.003434000 seconds sys
'''

Ensure that nan metric values are quoted as nan isn't a valid number
in JSON.

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Kan Liang <kan.liang@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ahmad Yasin <ahmad.yasin@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Edward Baker <edward.baker@intel.com>
Cc: Florian Fischer <florian.fischer@muhq.space>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kang Minchul <tegongkang@gmail.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Samantha Alt <samantha.alt@intel.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Sumanth Korikkar <sumanthk@linux.ibm.com>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Tiezhu Yang <yangtiezhu@loongson.cn>
Cc: Weilin Wang <weilin.wang@intel.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Link: https://lore.kernel.org/r/20230502223851.2234828-2-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/tests/expr.c
tools/perf/tests/parse-metric.c
tools/perf/util/expr.y
tools/perf/util/stat-display.c
tools/perf/util/stat-shadow.c

index cbf0e0c..733ead1 100644 (file)
@@ -120,7 +120,8 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u
 
        p = "FOO/0";
        ret = expr__parse(&val, ctx, p);
-       TEST_ASSERT_VAL("division by zero", ret == -1);
+       TEST_ASSERT_VAL("division by zero", ret == 0);
+       TEST_ASSERT_VAL("division by zero", isnan(val));
 
        p = "BAR/";
        ret = expr__parse(&val, ctx, p);
index 1185b79..c05148e 100644 (file)
@@ -38,6 +38,7 @@ static void load_runtime_stat(struct evlist *evlist, struct value *vals)
        evlist__alloc_aggr_stats(evlist, 1);
        evlist__for_each_entry(evlist, evsel) {
                count = find_value(evsel->name, vals);
+               evsel->supported = true;
                evsel->stats->aggr->counts.val = count;
                if (evsel__name_is(evsel, "duration_time"))
                        update_stats(&walltime_nsecs_stats, count);
index 250e444..4ce931c 100644 (file)
@@ -225,7 +225,11 @@ expr: NUMBER
 {
        if (fpclassify($3.val) == FP_ZERO) {
                pr_debug("division by zero\n");
-               YYABORT;
+               assert($3.ids == NULL);
+               if (compute_ids)
+                       ids__free($1.ids);
+               $$.val = NAN;
+               $$.ids = NULL;
        } else if (!compute_ids || (is_const($1.val) && is_const($3.val))) {
                assert($1.ids == NULL);
                assert($3.ids == NULL);
index 73b2ff2..bf5a6c1 100644 (file)
@@ -431,7 +431,7 @@ static void print_metric_json(struct perf_stat_config *config __maybe_unused,
        struct outstate *os = ctx;
        FILE *out = os->fh;
 
-       fprintf(out, "\"metric-value\" : %f, ", val);
+       fprintf(out, "\"metric-value\" : \"%f\", ", val);
        fprintf(out, "\"metric-unit\" : \"%s\"", unit);
        if (!config->metric_only)
                fprintf(out, "}");
index eeccab6..1566a20 100644 (file)
@@ -403,12 +403,25 @@ static int prepare_metric(struct evsel **metric_events,
                        if (!aggr)
                                break;
 
-                       /*
-                        * If an event was scaled during stat gathering, reverse
-                        * the scale before computing the metric.
-                        */
-                       val = aggr->counts.val * (1.0 / metric_events[i]->scale);
-                       source_count = evsel__source_count(metric_events[i]);
+                        if (!metric_events[i]->supported) {
+                               /*
+                                * Not supported events will have a count of 0,
+                                * which can be confusing in a
+                                * metric. Explicitly set the value to NAN. Not
+                                * counted events (enable time of 0) are read as
+                                * 0.
+                                */
+                               val = NAN;
+                               source_count = 0;
+                       } else {
+                               /*
+                                * If an event was scaled during stat gathering,
+                                * reverse the scale before computing the
+                                * metric.
+                                */
+                               val = aggr->counts.val * (1.0 / metric_events[i]->scale);
+                               source_count = evsel__source_count(metric_events[i]);
+                       }
                }
                n = strdup(evsel__metric_id(metric_events[i]));
                if (!n)