From nobody Mon Feb 9 01:16:46 2026 Received: from mail-yb1-f202.google.com (mail-yb1-f202.google.com [209.85.219.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 239E974436 for ; Wed, 28 Feb 2024 17:57:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1709143027; cv=none; b=DfqOvez9KneqAVbIdAndQ1IS+CWx1PVWhzLpaCW1v1eBfPe74FeSHvGKixyPx4aiPUwDAFuJ5oqfLQKcDPTqs8h0yvxNcOluqAUrCG903JA7zmf7mj550K0coAcz6DxYb7vfzkpS0T+Dl1Pj4YWRJVPYU/KoP+ASzsDNPzom6Vs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1709143027; c=relaxed/simple; bh=RFf0SovuHqWJtY0/DKROVO/7jIucJjMLUFN5wMVSl0U=; h=Date:In-Reply-To:Message-Id:Mime-Version:References:Subject:From: To:Content-Type; b=M14gxrkb5WVyM07xQAPKRYXeoas3l2a/iKJLLvNlC1QOwTmDchvJYKuGHREtEhfYiAZyPBEAbSsNsj+Frn3/1Ak5gS4VTq4hnXyax1JcS+XWSFP8LkbBBDg6njiyABN1gzVN8+6n9CTNY0YN7wQB2YhCsSoDvlNLQIQdz80LCmw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=vso+9MMN; arc=none smtp.client-ip=209.85.219.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="vso+9MMN" Received: by mail-yb1-f202.google.com with SMTP id 3f1490d57ef6-dcd94cc48a1so84344276.3 for ; Wed, 28 Feb 2024 09:57:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1709143025; x=1709747825; darn=vger.kernel.org; h=to:from:subject:references:mime-version:message-id:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=M6NqTe4lQsI2lCeybdcDVIAKYLSVy1HDfTgRobHAwi4=; b=vso+9MMNgXr6fayIR2i1LyL62utD/cc1sKvPb0PfhNZwymo1M/gyZW+v3uaSHSdQU7 T2ov0MIlHn51uINxFF0lREaMCLvvGxnahnFJ3sweFaGaA9XM00ok8T1kWykxjbksnyH+ DBZuUOmpZnSkiDz0+1vXnj+Xzq2KUP/yQhv0VuZv2G1EsFOCJ6a+3atI5V72W+a+l178 jzwXs/pTCEx9TKnUYhw/IjmxoUsuZ8Fh+jXZwQoEM7RrkBAGeRmmCrqNOsdV859TX+Ee zDTyJcnFzHG8Kgh64AobR9P1sBnBPNaJCL5KWytIbWh1XsJh0wmHkCRscWpA79GDD4Ud 8P/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1709143025; x=1709747825; h=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=M6NqTe4lQsI2lCeybdcDVIAKYLSVy1HDfTgRobHAwi4=; b=JsDASKh1ybCS0+eavV6d/gFyOzuFBrgJdQsVLe4UaaqmKJtW0af7W7igm+ZPwakpaU glkXaifH6mSoe+fiZD1XcguzgAcWIcyuZRem/JP6O57grU1ClbdFZrwZfzUlsCsbbG+s D1o5YePtSMpm2f+ihzn2VmaAsi8mmymAuj+DBJQbzkBNK5TAFsuPHDPoi1BTDOtdyq6A 0NhboOhStHEHgaIoHDQMCIo8Dl4FKhU99GZFFoN0yQ5Urb5wCeag+EiSp2iGOkWxDbMY bpemD53NTmJzf2ldEamCpVfJthNJBaKlLHN4SapTW5X3ucD8RkuWPeVyByBUnuq8xVH6 4J4g== X-Forwarded-Encrypted: i=1; AJvYcCWUCOFp9bB4EVyng55KITjzfKUV3Tom6mo5J+nz3qYzC148bBiUIq54A2dMFbc1O0r0ZbV2bIzNQj723rWKh3RwGB7q2n6L5FqUeZ0k X-Gm-Message-State: AOJu0YyyXuV8Px4Mw/NHlBy/GKWb33SWWlmgh64czsrduyfRRKVtvOBZ XJlTLGUt4bbbOFHjERSuMfp63ANt59oJFNIX9LuBINXuYqqnz2q/jxinXNTbkjZJ/DIXnN4Vw0d p4Wwssw== X-Google-Smtp-Source: AGHT+IEXq2MY86zbh8qNj0dj6Z5P07UKBCnxR9qEnKybPAvKfXIeSsHZc2tWN3H1cMUiTPnEctFXUrTRqY9Z X-Received: from irogers.svl.corp.google.com ([2620:15c:2a3:200:77dc:144c:334e:e2dd]) (user=irogers job=sendgmr) by 2002:a05:6902:1244:b0:dcf:b5b8:f825 with SMTP id t4-20020a056902124400b00dcfb5b8f825mr11204ybu.0.1709143025258; Wed, 28 Feb 2024 09:57:05 -0800 (PST) Date: Wed, 28 Feb 2024 09:56:17 -0800 In-Reply-To: <20240228175617.4049201-1-irogers@google.com> Message-Id: <20240228175617.4049201-13-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240228175617.4049201-1-irogers@google.com> X-Mailer: git-send-email 2.44.0.278.ge034bb2e1d-goog Subject: [PATCH v1 12/12] perf jevents: Add load event json to verify and allow fallbacks From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , John Garry , Kan Liang , Jing Zhang , Thomas Richter , James Clark , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Andi Kleen , Kajol Jain , Sandipan Das , Ravi Bangoria , Perry Taylor , Samantha Alt , Caleb Biggers , Weilin Wang , Edward Baker , Stephane Eranian Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a LoadEvents function that loads all event json files in a directory. In the Event constructor ensure all events are defined in the event json except for legacy events like "cycles". If the initial event isn't found then legacy_event1 is used, and if that isn't found legacy_event2 is used. This allows a single Event to have multiple event names as models will often rename the same event over time. If the event doesn't exist an exception is raised. So that references to metrics can be added, add the MetricRef class. This doesn't validate as an event name and so provides an escape hatch for metrics to refer to each other. Signed-off-by: Ian Rogers --- tools/perf/pmu-events/amd_metrics.py | 7 ++- tools/perf/pmu-events/arm64_metrics.py | 7 ++- tools/perf/pmu-events/intel_metrics.py | 7 ++- tools/perf/pmu-events/metric.py | 77 +++++++++++++++++++++++++- 4 files changed, 92 insertions(+), 6 deletions(-) diff --git a/tools/perf/pmu-events/amd_metrics.py b/tools/perf/pmu-events/a= md_metrics.py index cb850ab1ed13..227f9b98c016 100755 --- a/tools/perf/pmu-events/amd_metrics.py +++ b/tools/perf/pmu-events/amd_metrics.py @@ -1,14 +1,19 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) -from metric import (JsonEncodeMetric, JsonEncodeMetricGroupDescriptions, M= etricGroup) +from metric import (JsonEncodeMetric, JsonEncodeMetricGroupDescriptions, L= oadEvents, + MetricGroup) import argparse import json +import os =20 parser =3D argparse.ArgumentParser(description=3D"AMD perf json generator") parser.add_argument("-metricgroups", help=3D"Generate metricgroups data", = action=3D'store_true') parser.add_argument("model", help=3D"e.g. amdzen[123]") args =3D parser.parse_args() =20 +directory =3D f"{os.path.dirname(os.path.realpath(__file__))}/arch/x86/{ar= gs.model}/" +LoadEvents(directory) + all_metrics =3D MetricGroup("",[]) =20 if args.metricgroups: diff --git a/tools/perf/pmu-events/arm64_metrics.py b/tools/perf/pmu-events= /arm64_metrics.py index a54fa8aae2fa..7cd0ebc0bd80 100755 --- a/tools/perf/pmu-events/arm64_metrics.py +++ b/tools/perf/pmu-events/arm64_metrics.py @@ -1,8 +1,10 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) -from metric import (JsonEncodeMetric, JsonEncodeMetricGroupDescriptions, M= etricGroup) +from metric import (JsonEncodeMetric, JsonEncodeMetricGroupDescriptions, L= oadEvents, + MetricGroup) import argparse import json +import os =20 parser =3D argparse.ArgumentParser(description=3D"ARM perf json generator") parser.add_argument("-metricgroups", help=3D"Generate metricgroups data", = action=3D'store_true') @@ -10,6 +12,9 @@ parser.add_argument("vendor", help=3D"e.g. arm") parser.add_argument("model", help=3D"e.g. neoverse-n1") args =3D parser.parse_args() =20 +directory =3D f"{os.path.dirname(os.path.realpath(__file__))}/arch/arm64/{= args.vendor}/{args.model}/" +LoadEvents(directory) + all_metrics =3D MetricGroup("",[]) =20 if args.metricgroups: diff --git a/tools/perf/pmu-events/intel_metrics.py b/tools/perf/pmu-events= /intel_metrics.py index 8b67b9613ab5..4fbb31c9eccd 100755 --- a/tools/perf/pmu-events/intel_metrics.py +++ b/tools/perf/pmu-events/intel_metrics.py @@ -1,14 +1,19 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) -from metric import (JsonEncodeMetric, JsonEncodeMetricGroupDescriptions, M= etricGroup) +from metric import (JsonEncodeMetric, JsonEncodeMetricGroupDescriptions, L= oadEvents, + MetricGroup) import argparse import json +import os =20 parser =3D argparse.ArgumentParser(description=3D"Intel perf json generato= r") parser.add_argument("-metricgroups", help=3D"Generate metricgroups data", = action=3D'store_true') parser.add_argument("model", help=3D"e.g. skylakex") args =3D parser.parse_args() =20 +directory =3D f"{os.path.dirname(os.path.realpath(__file__))}/arch/x86/{ar= gs.model}/" +LoadEvents(directory) + all_metrics =3D MetricGroup("",[]) =20 if args.metricgroups: diff --git a/tools/perf/pmu-events/metric.py b/tools/perf/pmu-events/metric= .py index 0326050f1e0f..7d445e47ae09 100644 --- a/tools/perf/pmu-events/metric.py +++ b/tools/perf/pmu-events/metric.py @@ -3,10 +3,50 @@ import ast import decimal import json +import os import re from enum import Enum from typing import Dict, List, Optional, Set, Tuple, Union =20 +all_events =3D set() + +def LoadEvents(directory: str) -> None: + """Populate a global set of all known events for the purpose of validati= ng Event names""" + global all_events + all_events =3D { + "context\-switches", + "cycles", + "duration_time", + "instructions", + "l2_itlb_misses", + } + for file in os.listdir(os.fsencode(directory)): + filename =3D os.fsdecode(file) + if filename.endswith(".json"): + for x in json.load(open(f"{directory}/{filename}")): + if "EventName" in x: + all_events.add(x["EventName"]) + elif "ArchStdEvent" in x: + all_events.add(x["ArchStdEvent"]) + + +def CheckEvent(name: str) -> bool: + """Check the event name exists in the set of all loaded events""" + global all_events + if len(all_events) =3D=3D 0: + # No events loaded so assume any event is good. + return True + + if ':' in name: + # Remove trailing modifier. + name =3D name[:name.find(':')] + elif '/' in name: + # Name could begin with a PMU or an event, for now assume it is good. + return True + + return name in all_events + + class MetricConstraint(Enum): GROUPED_EVENTS =3D 0 NO_GROUP_EVENTS =3D 1 @@ -317,9 +357,18 @@ def _FixEscapes(s: str) -> str: class Event(Expression): """An event in an expression.""" =20 - def __init__(self, name: str, legacy_name: str =3D ''): - self.name =3D _FixEscapes(name) - self.legacy_name =3D _FixEscapes(legacy_name) + def __init__(self, *args: str): + error =3D "" + for name in args: + if CheckEvent(name): + self.name =3D _FixEscapes(name) + return + if error: + error +=3D " or " + name + else: + error =3D name + global all_events + raise Exception(f"No event {error} in:\n{all_events}") =20 def ToPerfJson(self): result =3D re.sub('/', '@', self.name) @@ -338,6 +387,28 @@ class Event(Expression): return self =20 =20 +class MetricRef(Expression): + """A metric reference in an expression.""" + + def __init__(self, name: str): + self.name =3D _FixEscapes(name) + + def ToPerfJson(self): + return self.name + + def ToPython(self): + return f'MetricRef(r"{self.name}")' + + def Simplify(self) -> Expression: + return self + + def Equals(self, other: Expression) -> bool: + return isinstance(other, MetricRef) and self.name =3D=3D other.name + + def Substitute(self, name: str, expression: Expression) -> Expression: + return self + + class Constant(Expression): """A constant within the expression tree.""" =20 --=20 2.44.0.278.ge034bb2e1d-goog