From: Ian Rogers Date: Thu, 23 Sep 2021 07:46:15 +0000 (-0700) Subject: perf metric: Don't compute unused events X-Git-Tag: v5.16-rc1~93^2~90 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a8e4e880834b5dc53ff6b4cfc9f4268e61399976;p=thirdparty%2Flinux.git perf metric: Don't compute unused events For a metric like: EVENT1 if #smt_on else EVENT2 currently EVENT1 and EVENT2 will be measured and then when the metric is reported EVENT1 or EVENT2 will be printed depending on the value from smt_on() during the expr parsing. Computing both events is unnecessary and can lead to multiplexing as discussed in this thread: https://lore.kernel.org/lkml/20201110100346.2527031-1-irogers@google.com/ If the input is constant to certain operators like: IDS1 if CONST else IDS2 then the result will be either IDS1 or IDS2 depending on CONST (which may be evaluated from an entire expression), and so IDS1 or IDS2 may be discarded avoiding events from being programmed. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-13-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index 1c881bea7fcad..287989321d2a1 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "util/debug.h" #include "util/expr.h" +#include "util/smt.h" #include "tests.h" #include #include @@ -132,6 +133,16 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused) TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, "EVENT2,param=3/", (void **)&val_ptr)); + /* Only EVENT1 or EVENT2 need be measured depending on the value of smt_on. */ + expr__ctx_clear(ctx); + TEST_ASSERT_VAL("find ids", + expr__find_ids("EVENT1 if #smt_on else EVENT2", + NULL, ctx, 0) == 0); + TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 1); + TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, + smt_on() ? "EVENT1" : "EVENT2", + (void **)&val_ptr)); + expr__ctx_free(ctx); return 0; diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index 5a295e385914a..5b878f044f22a 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -123,14 +123,30 @@ start: if_expr if_expr: expr IF expr ELSE expr { - if (!compute_ids) { - $$.ids = NULL; - if (fpclassify($3.val) == FP_ZERO) { - $$.val = $5.val; - } else { - $$.val = $1.val; - } + if (fpclassify($3.val) == FP_ZERO) { + /* + * The IF expression evaluated to 0 so treat as false, take the + * ELSE and discard everything else. + */ + $$.val = $5.val; + $$.ids = $5.ids; + ids__free($1.ids); + ids__free($3.ids); + } else if (!compute_ids || is_const($3.val)) { + /* + * If ids aren't computed then treat the expression as true. If + * ids are being computed and the IF expr is a non-zero + * constant, then also evaluate the true case. + */ + $$.val = $1.val; + $$.ids = $1.ids; + ids__free($3.ids); + ids__free($5.ids); } else { + /* + * Value is either the LHS or RHS and we need the IF expression + * to compute it. + */ $$ = union_expr($1, union_expr($3, $5)); } }