From patchwork Wed Dec 21 22:34:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Rogers X-Patchwork-Id: 35548 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:8188:b0:89:790f:f786 with SMTP id m8csp4950153dye; Wed, 21 Dec 2022 14:36:17 -0800 (PST) X-Google-Smtp-Source: AMrXdXvQpmKpUtNL7bU7aMKuTAj3FuImxYITpAYGX7L4MOPFIJG1xu0FYW0r+nTuLb9Q4C0xO0MO X-Received: by 2002:a17:90b:1203:b0:219:823e:6726 with SMTP id gl3-20020a17090b120300b00219823e6726mr3995191pjb.19.1671662177021; Wed, 21 Dec 2022 14:36:17 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1671662177; cv=none; d=google.com; s=arc-20160816; b=xt8E4UPjC0L1YWuxlExuRZdcIsVgBi7OkoRW9GTvnlD1Q5VIiqDhUKb9GdRO3PeNsk 6fcLqGUf3ePXSISyC6hgQHOURh06bNLJ3Ew8F9jzm8KB5bcYn12KkcpzPw0ZFRge2d0J /HBTg6Ab46J81/e+3S3OiqKQyfYSLLW3v4R7079ipbkx6IywDwcraat11Yde3WymXiKs b39UvBtu3E2GWxEeKHZx/VYYtMvtRGy+CVUt+UfLEbwb+kBPfVTLI6iatEsUGhBTjC1j 3xQY1sHEZJWP/98cqoT8U5rQQkgVGpyDMFvJH8/oUow3Wu6bKZvjfIIvnrB9n51po+gu 9Jdg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:dkim-signature; bh=XSRdXmmYpH3FUi2ntSEaBZfMzdFPCToyU2P+KywsVtE=; b=z2d/mBg5IsiX94jrJR/N/3m/OrUeWbcE8scLuCnRVRi+ok6E9UbUY4axtRXn/rlGKp JnZM/lz03T+kdJkZciVcgMo2aNKgh7MUhH4g9gh2a+TqUl2N/hPY4j+Wl1Rd+hmqc3B2 zhZfW5RLYA8HtWND1XaFX9JC5xXhHC72Y7ol+Ke9q9wRURApFjSyD3d/EqXOmnymX0eE mLQLTOzbEc5rcsjzovg4tk4EfNSww6+sica3rPKO7aMiRKWE3nktbbn2mHeJFhZv704n lp/xgStPMgJLT/jZP1BWREBx5cAaYlhdRczs+DvoRGcoqKMdN6Vod9EbqzSbfj5Xnwn9 STxg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=NvffAvua; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id mu3-20020a17090b388300b00218cacee1besi2956035pjb.153.2022.12.21.14.36.03; Wed, 21 Dec 2022 14:36:16 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=NvffAvua; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235096AbiLUWev (ORCPT + 99 others); Wed, 21 Dec 2022 17:34:51 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45662 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235042AbiLUWeq (ORCPT ); Wed, 21 Dec 2022 17:34:46 -0500 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 122A564EB for ; Wed, 21 Dec 2022 14:34:45 -0800 (PST) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-3dfb9d11141so3921547b3.3 for ; Wed, 21 Dec 2022 14:34:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=XSRdXmmYpH3FUi2ntSEaBZfMzdFPCToyU2P+KywsVtE=; b=NvffAvuaPXn6ccEpX8X07e5RRoMC12LkowBZEDZmy/VL6P7LQ5DbzNaf40i08etEDX ZrCCHFTZaM6dTI5lWq5CZwfAtt5n11ZgnoYtIjS0eps9AxnGF4SzE+3NhHhYCf97teX9 +h+YsC4zqbDV5Tiu6c+sFYAd0Ev+oGyiUjqGEOAvjj1NEaOigELNK7b/GcGevDv5w33X xkHa3VCMZNC3Z1g0KJ4z8rZNEoJhAawuX8F/MtsRICQjsUggG/bkv4zNHCj9TOQOZgIZ lx+HZ4IkQJ71oIH0yk+VPa7/ExO0mpUQFZd9/JgUWcBeKEHpAPsGnquGoF2Znl8+kPL3 kGyw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=XSRdXmmYpH3FUi2ntSEaBZfMzdFPCToyU2P+KywsVtE=; b=hYNfTuG5RRGk70NnWQLNpEZ271NapnMPezR7gDsW3GPJM2FVZTO+4T10tgMLZwOK8r vi6AAU3tvCFNjixMVWJiidUxACJfzAJ2Lgq0ChmRe35k9PgO/4LW02HBV+Q9LxO/sX34 u633hz4eDTUcpe7l0xUDSilswf0qC4E7cDWKS0lTnNeG8WCi6bzrqKyp4vJqXcdMgBc6 MLEKKSFr7WDMx5xE/IzASSo3daXLBwr6ePFYIY59K48uLa5/yW3OnuyNPO5l0A272ikF 9TmFAlzqfuDYol7wRUfrRoWbAqbULSESOpXb6Nihn3BhylEVvOR72ZmSaerNuttzW8gA +U8A== X-Gm-Message-State: AFqh2kqOFYvpx14rY4JCqQzPFeE82DUNrpKiup65ZmMCGrhM1q2Pcr5N XFmxPnaZEx+OjrMFmIaM8cutZ1WMaYFj X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:62bd:f120:1fd8:1d21]) (user=irogers job=sendgmr) by 2002:a0d:ca54:0:b0:370:4a99:df7d with SMTP id m81-20020a0dca54000000b003704a99df7dmr254226ywd.308.1671662084298; Wed, 21 Dec 2022 14:34:44 -0800 (PST) Date: Wed, 21 Dec 2022 14:34:13 -0800 In-Reply-To: <20221221223420.2157113-1-irogers@google.com> Message-Id: <20221221223420.2157113-3-irogers@google.com> Mime-Version: 1.0 References: <20221221223420.2157113-1-irogers@google.com> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog Subject: [PATCH v2 2/9] perf jevents metric: Add ability to rewrite metrics in terms of others From: Ian Rogers To: John Garry , Will Deacon , James Clark , Mike Leach , Leo Yan , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Adrian Hunter , Kan Liang , Kim Phillips , Florian Fischer , Ravi Bangoria , Xing Zhengjun , Rob Herring , Kang Minchul , linux-arm-kernel@lists.infradead.org, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Sandipan Das , Jing Zhang , linuxppc-dev@lists.ozlabs.org, Kajol Jain Cc: Stephane Eranian , Perry Taylor , Caleb Biggers , Ian Rogers X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1752864838761851813?= X-GMAIL-MSGID: =?utf-8?q?1752864838761851813?= Add RewriteMetricsInTermsOfOthers that iterates over pairs of names and expressions trying to replace an expression, within the current expression, with its name. Signed-off-by: Ian Rogers --- tools/perf/pmu-events/metric.py | 73 +++++++++++++++++++++++++++- tools/perf/pmu-events/metric_test.py | 10 ++++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/tools/perf/pmu-events/metric.py b/tools/perf/pmu-events/metric.py index 2f2fd220e843..ed13efac7389 100644 --- a/tools/perf/pmu-events/metric.py +++ b/tools/perf/pmu-events/metric.py @@ -4,7 +4,7 @@ import ast import decimal import json import re -from typing import Dict, List, Optional, Set, Union +from typing import Dict, List, Optional, Set, Tuple, Union class Expression: @@ -26,6 +26,9 @@ class Expression: """Returns true when two expressions are the same.""" raise NotImplementedError() + def Substitute(self, name: str, expression: 'Expression') -> 'Expression': + raise NotImplementedError() + def __str__(self) -> str: return self.ToPerfJson() @@ -186,6 +189,15 @@ class Operator(Expression): other.lhs) and self.rhs.Equals(other.rhs) return False + def Substitute(self, name: str, expression: Expression) -> Expression: + if self.Equals(expression): + return Event(name) + lhs = self.lhs.Substitute(name, expression) + rhs = None + if self.rhs: + rhs = self.rhs.Substitute(name, expression) + return Operator(self.operator, lhs, rhs) + class Select(Expression): """Represents a select ternary in the parse tree.""" @@ -225,6 +237,14 @@ class Select(Expression): other.false_val) and self.true_val.Equals(other.true_val) return False + def Substitute(self, name: str, expression: Expression) -> Expression: + if self.Equals(expression): + return Event(name) + true_val = self.true_val.Substitute(name, expression) + cond = self.cond.Substitute(name, expression) + false_val = self.false_val.Substitute(name, expression) + return Select(true_val, cond, false_val) + class Function(Expression): """A function in an expression like min, max, d_ratio.""" @@ -267,6 +287,15 @@ class Function(Expression): return result return False + def Substitute(self, name: str, expression: Expression) -> Expression: + if self.Equals(expression): + return Event(name) + lhs = self.lhs.Substitute(name, expression) + rhs = None + if self.rhs: + rhs = self.rhs.Substitute(name, expression) + return Function(self.fn, lhs, rhs) + def _FixEscapes(s: str) -> str: s = re.sub(r'([^\\]),', r'\1\\,', s) @@ -293,6 +322,9 @@ class Event(Expression): def Equals(self, other: Expression) -> bool: return isinstance(other, Event) and self.name == other.name + def Substitute(self, name: str, expression: Expression) -> Expression: + return self + class Constant(Expression): """A constant within the expression tree.""" @@ -317,6 +349,9 @@ class Constant(Expression): def Equals(self, other: Expression) -> bool: return isinstance(other, Constant) and self.value == other.value + def Substitute(self, name: str, expression: Expression) -> Expression: + return self + class Literal(Expression): """A runtime literal within the expression tree.""" @@ -336,6 +371,9 @@ class Literal(Expression): def Equals(self, other: Expression) -> bool: return isinstance(other, Literal) and self.value == other.value + def Substitute(self, name: str, expression: Expression) -> Expression: + return self + def min(lhs: Union[int, float, Expression], rhs: Union[int, float, Expression]) -> Function: @@ -461,6 +499,7 @@ class MetricGroup: class _RewriteIfExpToSelect(ast.NodeTransformer): + """Transformer to convert if-else nodes to Select expressions.""" def visit_IfExp(self, node): # pylint: disable=invalid-name @@ -498,7 +537,37 @@ def ParsePerfJson(orig: str) -> Expression: for kw in keywords: py = re.sub(rf'Event\(r"{kw}"\)', kw, py) - parsed = ast.parse(py, mode='eval') + try: + parsed = ast.parse(py, mode='eval') + except SyntaxError as e: + raise SyntaxError(f'Parsing expression:\n{orig}') from e _RewriteIfExpToSelect().visit(parsed) parsed = ast.fix_missing_locations(parsed) return _Constify(eval(compile(parsed, orig, 'eval'))) + + +def RewriteMetricsInTermsOfOthers(metrics: list[Tuple[str, Expression]] + )-> Dict[str, Expression]: + """Shorten metrics by rewriting in terms of others. + + Args: + metrics (list): pairs of metric names and their expressions. + Returns: + Dict: mapping from a metric name to a shortened expression. + """ + updates: Dict[str, Expression] = dict() + for outer_name, outer_expression in metrics: + updated = outer_expression + while True: + for inner_name, inner_expression in metrics: + if inner_name.lower() == outer_name.lower(): + continue + if inner_name in updates: + inner_expression = updates[inner_name] + updated = updated.Substitute(inner_name, inner_expression) + if updated.Equals(outer_expression): + break + if outer_name in updates and updated.Equals(updates[outer_name]): + break + updates[outer_name] = updated + return updates diff --git a/tools/perf/pmu-events/metric_test.py b/tools/perf/pmu-events/metric_test.py index 15315d0f716c..ced5998bd827 100644 --- a/tools/perf/pmu-events/metric_test.py +++ b/tools/perf/pmu-events/metric_test.py @@ -2,7 +2,9 @@ import unittest from metric import Constant from metric import Event +from metric import Expression from metric import ParsePerfJson +from metric import RewriteMetricsInTermsOfOthers class TestMetricExpressions(unittest.TestCase): @@ -153,5 +155,13 @@ class TestMetricExpressions(unittest.TestCase): after = '0 * SLOTS' self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) + def test_RewriteMetricsInTermsOfOthers(self): + Expression.__eq__ = lambda e1, e2: e1.Equals(e2) + before = [('m1', ParsePerfJson('a + b + c + d')), + ('m2', ParsePerfJson('a + b + c'))] + after = {'m1': ParsePerfJson('m2 + d')} + self.assertEqual(RewriteMetricsInTermsOfOthers(before), after) + Expression.__eq__ = None + if __name__ == '__main__': unittest.main()