From nobody Sat Oct 4 09:40:56 2025 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4FA4132C32D; Mon, 18 Aug 2025 17:14:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755537252; cv=none; b=ojKthGTqaYgml4iAfmRJEAoXC8g9i0nEqBRRCXKGyS4yUt3Yb8UbRhzrSWhawqo9+Z4XYE1KXGwhXe+kBY3cdgMCBH49wCx0PVwIGOUGbPHIcszqTU7NqFRNu8VFJCrfsXHNBi9TaR4pmEAx8I3+nxcqyCrZMkJ9sB6GxYozH1w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755537252; c=relaxed/simple; bh=WskN2oOK6aFY4zvPiSz8zULkpYxhixIw1aAr8ljYeWI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Sg+HddO3RvBvSmfm7DFhpJCeZjsrJikApWDGNcoBrEh/khhdLdG6gnZKAJLYcrx8Xj8GOr8fvRpnccPjhpfEZkMAKfJXs7M8gu4H46b9J2RsN1hPrwoxlrX0B2Zxk5wJxfefhGWe/yWiDDeyhr2781cGs3+fceNHP+XVywxSGRI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=NqVv4V/t; arc=none smtp.client-ip=198.175.65.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="NqVv4V/t" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1755537250; x=1787073250; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=WskN2oOK6aFY4zvPiSz8zULkpYxhixIw1aAr8ljYeWI=; b=NqVv4V/tzX11m8kJaB1+KpJPsnXsRSuOZXb1XJLClJKSoaSvz7h97WWq 6l+nOxBF+edcQ2Wx3Q/wgi7AAhSd6qviYkjJTkPEPnzyVszN1ej3QEkb0 j4+n8nqHV4bpOjHUOLONAk/aQd/xRS++jJiaAi5EXTnKgaHHDtZ1DYA7M OY1e7LvJ4GctWkm5Vb9drqB5BMRWy6d8dJ0JNOSAzTyU5jnhC3QTihMFk FkyC5ursgfKy0VemxwOb/IbVXxHU4R5tich/WO6VhGND53MRNgmbK0sC6 WzZSWW/aDi/6MQnK53r0Nf5rvY69a94w2wf4vvc9RpTtqC+7wLEwChtex A==; X-CSE-ConnectionGUID: f0MCREB/RdyNvjGBnIb57g== X-CSE-MsgGUID: e47f+E0YTpqX/7lQv1SS5g== X-IronPort-AV: E=McAfee;i="6800,10657,11526"; a="80350261" X-IronPort-AV: E=Sophos;i="6.17,300,1747724400"; d="scan'208";a="80350261" Received: from fmviesa007.fm.intel.com ([10.60.135.147]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Aug 2025 10:14:10 -0700 X-CSE-ConnectionGUID: EMzbB/yjS+mlDhQaC03Iaw== X-CSE-MsgGUID: 6NCrrzjHQQeGocarTcNLew== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.17,300,1747724400"; d="scan'208";a="167137045" Received: from tfalcon-desk.amr.corp.intel.com (HELO tfalcon-desk.attlocal.net) ([10.125.108.14]) by fmviesa007.fm.intel.com with ESMTP; 18 Aug 2025 10:14:08 -0700 From: Thomas Falcon To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Kan Liang Cc: linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ak@linux.intel.com, Thomas Falcon Subject: [PATCH v2 1/2] perf record: Add ratio-to-prev term Date: Mon, 18 Aug 2025 12:13:54 -0500 Message-ID: <20250818171358.332331-2-thomas.falcon@intel.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250818171358.332331-1-thomas.falcon@intel.com> References: <20250818171358.332331-1-thomas.falcon@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Provide ratio-to-prev term which allows the user to set the event sample period of two events corresponding to a desired ratio. If using on an Intel x86 platform with Auto Counter Reload support, also set corresponding event's config2 attribute with a bitmask which counters to reset and which counters to sample if the desired ratio is met or exceeded. On other platforms, only the sample period is affected by the ratio-to-prev term. Signed-off-by: Thomas Falcon --- tools/perf/Documentation/intel-acr.txt | 53 ++++++++++++++++++ tools/perf/Documentation/perf-list.txt | 2 + tools/perf/arch/x86/util/evsel.c | 53 ++++++++++++++++++ tools/perf/util/evsel.c | 76 ++++++++++++++++++++++++++ tools/perf/util/evsel.h | 1 + tools/perf/util/evsel_config.h | 1 + tools/perf/util/parse-events.c | 22 ++++++++ tools/perf/util/parse-events.h | 3 +- tools/perf/util/parse-events.l | 1 + tools/perf/util/pmu.c | 3 +- 10 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 tools/perf/Documentation/intel-acr.txt diff --git a/tools/perf/Documentation/intel-acr.txt b/tools/perf/Documentat= ion/intel-acr.txt new file mode 100644 index 000000000000..72654fdd9a52 --- /dev/null +++ b/tools/perf/Documentation/intel-acr.txt @@ -0,0 +1,53 @@ +Intel Auto Counter Reload Support +--------------------------------- +Support for Intel Auto Counter Reload in perf tools + +Auto counter reload provides a means for software to specify to hardware +that certain counters, if supported, should be automatically reloaded +upon overflow of chosen counters. By taking a sample only if the rate of +one event exceeds some threshold relative to the rate of another event, +this feature enables software to sample based on the relative rate of +two or more events. To enable this, the user must provide a sample period +term and a bitmask ("acr_mask") for each relevant event specifying the +counters in an event group to reload if the event's specified sample +period is exceeded. + +For example, if the user desires to measure a scenario when IPC > 2, +the event group might look like the one below: + + perf record -e {cpu_atom/instructions,period=3D200000,acr_mask=3D0x2/, \ + cpu_atom/cycles,period=3D100000,acr_mask=3D0x3/} -- true + +In this case, if the "instructions" counter exceeds the sample period of +200000, the second counter, "cycles", will be reset and a sample will be +taken. If "cycles" is exceeded first, both counters in the group will be +reset. In this way, samples will only be taken for cases where IPC > 2. + +The acr_mask term is a hexadecimal value representing a bitmask of the +events in the group to be reset when the period is exceeded. In the +example above, "instructions" is assigned an acr_mask of 0x2, meaning +only the second event in the group is reloaded and a sample is taken +for the first event. "cycles" is assigned an acr_mask of 0x3, meaning +that both event counters will be reset if the sample period is exceeded +first. + +ratio-to-prev Event Term +------------------------ +To simplify this, an event term "ratio-to-prev" is provided which is used +alongside the sample period term n or the -c/--count option. This would +allow users to specify the desired relative rate between events as a +ratio. Note: Both events compared must belong to the same PMU. + +The command above would then become + + perf record -e {cpu_atom/instructions/, \ + cpu_atom/cycles,period=3D100000,ratio-to-prev=3D0.5/} -- true + +ratio-to-prev is the ratio of the event using the term relative +to the previous event in the group, which will always be 1, +for a 1:0.5 or 2:1 ratio. + +To sample for IPC < 2 for example, the events need to be reordered: + + perf record -e {cpu_atom/cycles/, \ + cpu_atom/instructions,period=3D200000,ratio-to-prev=3D2.0/} -- true diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentat= ion/perf-list.txt index 28215306a78a..10bc66d39202 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -392,6 +392,8 @@ Support raw format: . '--raw-dump [hw|sw|cache|tracepoint|pmu|event_glob]', shows the raw-dump= of a certain kind of events. =20 +include::intel-acr.txt[] + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-top[1], diff --git a/tools/perf/arch/x86/util/evsel.c b/tools/perf/arch/x86/util/ev= sel.c index 9bc80fff3aa0..84858e4c397d 100644 --- a/tools/perf/arch/x86/util/evsel.c +++ b/tools/perf/arch/x86/util/evsel.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include "util/evlist.h" #include "util/evsel.h" +#include "util/evsel_config.h" #include "util/env.h" #include "util/pmu.h" #include "util/pmus.h" @@ -67,6 +69,57 @@ int arch_evsel__hw_name(struct evsel *evsel, char *bf, s= ize_t size) event_name); } =20 +void arch_evsel__apply_ratio_to_prev(struct evsel *evsel, + struct perf_event_attr *attr) +{ + struct perf_event_attr *prev_attr =3D NULL; + struct evsel *evsel_prev =3D NULL; + const char *name =3D "acr_mask"; + int evsel_idx =3D 0; + __u64 ev_mask, pr_ev_mask; + + if (!perf_pmu__has_format(evsel->pmu, name)) { + pr_err("'%s' does not have acr_mask format support\n", evsel->pmu->name); + return; + } + if (perf_pmu__format_type(evsel->pmu, name) !=3D + PERF_PMU_FORMAT_VALUE_CONFIG2) { + pr_err("'%s' does not have config2 format support\n", evsel->pmu->name); + return; + } + + evsel_prev =3D evsel__prev(evsel); + if (!evsel_prev) { + pr_err("Previous event does not exist.\n"); + return; + } + + prev_attr =3D &evsel_prev->core.attr; + + if (prev_attr->config2) { + pr_err("'%s' has set config2 (acr_mask?) already, configuration not supp= orted\n", evsel_prev->name); + return; + } + + /* + * acr_mask (config2) is calculated using the event's index in + * the event group. The first event will use the index of the + * second event as its mask (e.g., 0x2), indicating that the + * second event counter will be reset and a sample taken for + * the first event if its counter overflows. The second event + * will use the mask consisting of the first and second bits + * (e.g., 0x3), meaning both counters will be reset if the + * second event counter overflows. + */ + + evsel_idx =3D evsel__group_idx(evsel); + ev_mask =3D 1ull << evsel_idx; + pr_ev_mask =3D 1ull << (evsel_idx - 1); + + prev_attr->config2 =3D ev_mask; + attr->config2 =3D ev_mask | pr_ev_mask; +} + static void ibs_l3miss_warn(void) { pr_warning( diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d264c143b592..f6f93920c0aa 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1091,6 +1091,71 @@ static void evsel__reset_callgraph(struct evsel *evs= el, struct callchain_param * } } =20 +static void evsel__apply_ratio_to_prev(struct evsel *evsel, + struct perf_event_attr *attr, + struct record_opts *opts, + const char *buf) +{ + struct perf_event_attr *prev_attr =3D NULL; + struct evsel *evsel_prev =3D NULL; + u64 type =3D evsel->core.attr.sample_type; + u64 prev_type =3D 0; + double rtp; + + rtp =3D strtod(buf, NULL); + if (rtp <=3D 0) { + pr_err("Invalid ratio-to-prev value %lf\n", rtp); + return; + } + if (evsel =3D=3D evsel__leader(evsel)) { + pr_err("Invalid use of ratio-to-prev term without preceding element in g= roup\n"); + return; + } + if (!evsel->pmu->is_core) { + pr_err("Event using ratio-to-prev term must have a core PMU\n"); + return; + } + + evsel_prev =3D evsel__prev(evsel); + if (!evsel_prev) { + pr_err("Previous event does not exist.\n"); + return; + } + + if (evsel_prev->pmu->type !=3D evsel->pmu->type) { + pr_err("Compared events (\"%s\", \"%s\") must have same PMU\n", + evsel->name, evsel_prev->name); + return; + } + + prev_attr =3D &evsel_prev->core.attr; + prev_type =3D evsel_prev->core.attr.sample_type; + + if (!(prev_type & PERF_SAMPLE_PERIOD)) { + attr->sample_period =3D prev_attr->sample_period * rtp; + attr->freq =3D 0; + evsel__reset_sample_bit(evsel, PERIOD); + } else if (!(type & PERF_SAMPLE_PERIOD)) { + prev_attr->sample_period =3D attr->sample_period / rtp; + prev_attr->freq =3D 0; + evsel__reset_sample_bit(evsel_prev, PERIOD); + } else { + if (opts->user_interval !=3D ULLONG_MAX) { + prev_attr->sample_period =3D opts->user_interval; + attr->sample_period =3D prev_attr->sample_period * rtp; + prev_attr->freq =3D 0; + attr->freq =3D 0; + evsel__reset_sample_bit(evsel_prev, PERIOD); + evsel__reset_sample_bit(evsel, PERIOD); + } else { + pr_err("Event period term or count (-c) must be set when using ratio-to= -prev term.\n"); + return; + } + } + + arch_evsel__apply_ratio_to_prev(evsel, attr); +} + static void evsel__apply_config_terms(struct evsel *evsel, struct record_opts *opts, bool track) { @@ -1104,6 +1169,7 @@ static void evsel__apply_config_terms(struct evsel *e= vsel, u32 dump_size =3D 0; int max_stack =3D 0; const char *callgraph_buf =3D NULL; + const char *rtp_buf =3D NULL; =20 list_for_each_entry(term, config_terms, list) { switch (term->type) { @@ -1174,6 +1240,9 @@ static void evsel__apply_config_terms(struct evsel *e= vsel, break; case EVSEL__CONFIG_TERM_CFG_CHG: break; + case EVSEL__CONFIG_TERM_RATIO_TO_PREV: + rtp_buf =3D term->val.str; + break; default: break; } @@ -1225,6 +1294,8 @@ static void evsel__apply_config_terms(struct evsel *e= vsel, evsel__config_callchain(evsel, opts, ¶m); } } + if (rtp_buf) + evsel__apply_ratio_to_prev(evsel, attr, opts, rtp_buf); } =20 struct evsel_config_term *__evsel__get_config_term(struct evsel *evsel, en= um evsel_term_type type) @@ -1249,6 +1320,11 @@ void __weak arch__post_evsel_config(struct evsel *ev= sel __maybe_unused, { } =20 +void __weak arch_evsel__apply_ratio_to_prev(struct evsel *evsel __maybe_un= used, + struct perf_event_attr *attr __maybe_unused) +{ +} + static void evsel__set_default_freq_period(struct record_opts *opts, struct perf_event_attr *attr) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 5797a02e5d6a..5002c795e818 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -342,6 +342,7 @@ void evsel__set_sample_id(struct evsel *evsel, bool use= _sample_identifier); void arch_evsel__set_sample_weight(struct evsel *evsel); void arch__post_evsel_config(struct evsel *evsel, struct perf_event_attr *= attr); int arch_evsel__open_strerror(struct evsel *evsel, char *msg, size_t size); +void arch_evsel__apply_ratio_to_prev(struct evsel *evsel, struct perf_even= t_attr *attr); =20 int evsel__set_filter(struct evsel *evsel, const char *filter); int evsel__append_tp_filter(struct evsel *evsel, const char *filter); diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h index 94a1e9cf73d6..bcd3a978f0c4 100644 --- a/tools/perf/util/evsel_config.h +++ b/tools/perf/util/evsel_config.h @@ -28,6 +28,7 @@ enum evsel_term_type { EVSEL__CONFIG_TERM_AUX_ACTION, EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE, EVSEL__CONFIG_TERM_CFG_CHG, + EVSEL__CONFIG_TERM_RATIO_TO_PREV, }; =20 struct evsel_config_term { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 8282ddf68b98..850de3a51f47 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -834,6 +834,7 @@ const char *parse_events__term_type_str(enum parse_even= ts__term_type term_type) [PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE] =3D "legacy-cache", [PARSE_EVENTS__TERM_TYPE_HARDWARE] =3D "hardware", [PARSE_EVENTS__TERM_TYPE_CPU] =3D "cpu", + [PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV] =3D "ratio-to-prev", }; if ((unsigned int)term_type >=3D __PARSE_EVENTS__TERM_TYPE_NR) return "unknown term"; @@ -884,6 +885,7 @@ config_term_avail(enum parse_events__term_type term_typ= e, struct parse_events_er case PARSE_EVENTS__TERM_TYPE_RAW: case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: + case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV: default: if (!err) return false; @@ -1037,6 +1039,21 @@ do { \ perf_cpu_map__put(map); break; } + case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV: + CHECK_TYPE_VAL(STR); + if (strtod(term->val.str, NULL) <=3D 0) { + parse_events_error__handle(err, term->err_val, + strdup("zero or negative"), + NULL); + return -EINVAL; + } + if (errno =3D=3D ERANGE) { + parse_events_error__handle(err, term->err_val, + strdup("too big"), + NULL); + return -EINVAL; + } + break; case PARSE_EVENTS__TERM_TYPE_DRV_CFG: case PARSE_EVENTS__TERM_TYPE_USER: case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: @@ -1165,6 +1182,7 @@ static int config_term_tracepoint(struct perf_event_a= ttr *attr, case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: case PARSE_EVENTS__TERM_TYPE_CPU: + case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV: default: if (err) { parse_events_error__handle(err, term->err_term, @@ -1289,6 +1307,9 @@ do { \ ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size, term->val.num, term->weak); break; + case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV: + ADD_CONFIG_TERM_STR(RATIO_TO_PREV, term->val.str, term->weak); + break; case PARSE_EVENTS__TERM_TYPE_USER: case PARSE_EVENTS__TERM_TYPE_CONFIG: case PARSE_EVENTS__TERM_TYPE_CONFIG1: @@ -1355,6 +1376,7 @@ static int get_config_chgs(struct perf_pmu *pmu, stru= ct parse_events_terms *head case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: case PARSE_EVENTS__TERM_TYPE_CPU: + case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV: default: break; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 62dc7202e3ba..b2dcc52e3814 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -83,7 +83,8 @@ enum parse_events__term_type { PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE, PARSE_EVENTS__TERM_TYPE_HARDWARE, PARSE_EVENTS__TERM_TYPE_CPU, -#define __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_CPU + 1) + PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV, +#define __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_RATIO_TO_PRE= V + 1) }; =20 struct parse_events_term { diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 2034590eb789..25206de68007 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -336,6 +336,7 @@ aux-action { return term(yyscanner, PARSE_EVENTS__TERM= _TYPE_AUX_ACTION); } aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMP= LE_SIZE); } metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); } cpu { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CPU); } +ratio-to-prev { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_RATIO_TO_P= REV); } cpu-cycles|cycles { return hw_term(yyscanner, PERF_COUNT_HW_CPU_CYCLES)= ; } stalled-cycles-frontend|idle-cycles-frontend { return hw_term(yyscanner, P= ERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } stalled-cycles-backend|idle-cycles-backend { return hw_term(yyscanner, PER= F_COUNT_HW_STALLED_CYCLES_BACKEND); } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 5a291f1380ed..3d1f975e8db9 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1541,7 +1541,7 @@ static int pmu_config_term(const struct perf_pmu *pmu, break; case PARSE_EVENTS__TERM_TYPE_USER: /* Not hardcoded. */ return -EINVAL; - case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_CPU: + case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_RATIO_TO_P= REV: /* Skip non-config terms. */ break; default: @@ -1930,6 +1930,7 @@ int perf_pmu__for_each_format(struct perf_pmu *pmu, v= oid *state, pmu_format_call "aux-action=3D(pause|resume|start-paused)", "aux-sample-size=3Dnumber", "cpu=3Dnumber", + "ratio-to-prev=3Dstring", }; struct perf_pmu_format *format; int ret; --=20 2.50.1 From nobody Sat Oct 4 09:40:56 2025 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F1BB253F03; Mon, 18 Aug 2025 17:14:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755537253; cv=none; b=Sy8yIhrHrpRfNZRLvYBif4fQd9EgPHLh2xy5WrWR55sMoMYG6fH0PUtzoAwUSLoPvtS9jg2xh4jAGz6SUs75cyBhWqoXFzTqu3DoztpyTZCsmSrkuFACB/9/YDzWdQ1wLLrfJdsS0E6GGUZq2WDQVeitJ2P22S4b5b0RYsvaeAk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755537253; c=relaxed/simple; bh=Ao1u5mWLcffmdlkohbo84IUaqTvWkpqLbl0RYa+WiHc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ikc92tOtRyDAsJcNYL/oVdTczW2z1q8gzQN3KE5dOoVRliPLXV8DuTXqp3YVVE6BkpG5q1psIgXUemLV6BuPbIfJUlnglImst/jECGd2lNd6uKrO7kYbwoOYsTYTLRvELpuZnk5urFGTQ/M22s596wMaYJ6f7PRKeL/oa2dCDB0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=OfKgnjrT; arc=none smtp.client-ip=198.175.65.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="OfKgnjrT" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1755537252; x=1787073252; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Ao1u5mWLcffmdlkohbo84IUaqTvWkpqLbl0RYa+WiHc=; b=OfKgnjrTFIV9cgV/2vI0hUltF1bkN3EFnoHXuWYtAzcNN0nrQyNrEilD uVPIDqFrOygdZ2VWU1xsgXc2uXBmmPjlZWx94fiy0TyoDB7A2Pba+kdYZ CAuYPkbMaS0ndyPRrxKq2wzkamZ+LEIaRhDyqlRTymWjrfUP5Geh5SIBk vqZMoheGPenm7R3APB9avGZ2Al3W9YjBGzNqXKIiul9FGQL2m3IJRCffh fiE0wTUsrYgmq0/91hSacec0UrbkOA1egUjjPhbzGFUBkIRn2hyFfWyUe XP6qdCuvRvvlgg/+KaHD4wCen0pjCWMt6scKTsWQqpxtgefQ/fGNP4m8/ w==; X-CSE-ConnectionGUID: M+GnqwjDQqCNkgFLXCcwKg== X-CSE-MsgGUID: yT/GCQ70STWosxEc2UvsRA== X-IronPort-AV: E=McAfee;i="6800,10657,11526"; a="80350278" X-IronPort-AV: E=Sophos;i="6.17,300,1747724400"; d="scan'208";a="80350278" Received: from fmviesa007.fm.intel.com ([10.60.135.147]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Aug 2025 10:14:12 -0700 X-CSE-ConnectionGUID: SEv656NRRASwgJI3Lj1gAQ== X-CSE-MsgGUID: qsC6eq+/RnukgGXF7wLICg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.17,300,1747724400"; d="scan'208";a="167137052" Received: from tfalcon-desk.amr.corp.intel.com (HELO tfalcon-desk.attlocal.net) ([10.125.108.14]) by fmviesa007.fm.intel.com with ESMTP; 18 Aug 2025 10:14:10 -0700 From: Thomas Falcon To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Kan Liang Cc: linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ak@linux.intel.com, Thomas Falcon Subject: [PATCH v2 2/2] perf record: Add auto counter reload parse and regression tests Date: Mon, 18 Aug 2025 12:13:55 -0500 Message-ID: <20250818171358.332331-3-thomas.falcon@intel.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250818171358.332331-1-thomas.falcon@intel.com> References: <20250818171358.332331-1-thomas.falcon@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Include event parsing and regression tests for auto counter reload and ratio-to-prev event term. Signed-off-by: Thomas Falcon --- tools/perf/tests/parse-events.c | 54 ++++++++++++++++++++++++++++++++ tools/perf/tests/shell/record.sh | 40 +++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-event= s.c index bb8004397650..67550cc60555 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1736,6 +1736,53 @@ static int test__intel_pt(struct evlist *evlist) return TEST_OK; } =20 +static bool test__acr_valid(void) +{ + struct perf_pmu *pmu =3D NULL; + + while ((pmu =3D perf_pmus__scan_core(pmu)) !=3D NULL) { + if (perf_pmu__has_format(pmu, "acr_mask")) + return true; + } + + return false; +} + +static int test__ratio_to_prev(struct evlist *evlist) +{ + struct evsel *evsel; + int ret; + + TEST_ASSERT_VAL("wrong number of entries", 2 * perf_pmus__num_core_pmus()= =3D=3D evlist->core.nr_entries); + + evlist__for_each_entry(evlist, evsel) { + if (!perf_pmu__has_format(evsel->pmu, "acr_mask")) + return TEST_OK; + + if (evsel =3D=3D evlist__first(evlist)) { + TEST_ASSERT_VAL("wrong config2", 0 =3D=3D evsel->core.attr.config2); + TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members =3D=3D = 2); + TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) =3D=3D 0); + ret =3D assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + } else { + TEST_ASSERT_VAL("wrong config2", 0 =3D=3D evsel->core.attr.config2); + TEST_ASSERT_VAL("wrong leader", !evsel__is_group_leader(evsel)); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members =3D=3D = 0); + TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) =3D=3D 1); + ret =3D assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructio= ns"); + } + if (ret) + return ret; + /* + * The period value gets configured within evlist__config, + * while this test executes only parse events method. + */ + TEST_ASSERT_VAL("wrong period", 0 =3D=3D evsel->core.attr.sample_period); + } + return TEST_OK; +} + static int test__checkevent_complex_name(struct evlist *evlist) { struct evsel *evsel =3D evlist__first(evlist); @@ -2249,6 +2296,13 @@ static const struct evlist_test test__events[] =3D { .check =3D test__checkevent_tracepoint, /* 4 */ }, + { + .name =3D "{cycles,instructions/period=3D200000,ratio-to-prev=3D2.0/}", + .valid =3D test__acr_valid, + .check =3D test__ratio_to_prev, + /* 5 */ + }, + }; =20 static const struct evlist_test test__events_pmu[] =3D { diff --git a/tools/perf/tests/shell/record.sh b/tools/perf/tests/shell/reco= rd.sh index b1ad24fb3b33..0f5841c479e7 100755 --- a/tools/perf/tests/shell/record.sh +++ b/tools/perf/tests/shell/record.sh @@ -388,6 +388,45 @@ test_callgraph() { echo "Callgraph test [Success]" } =20 +test_ratio_to_prev() { + echo "ratio-to-prev test" + if ! perf record -o /dev/null -e "{instructions, cycles/period=3D100000,= ratio-to-prev=3D0.5/}" \ + true 2> /dev/null + then + echo "ratio-to-prev [Skipped not supported]" + return + fi + if ! perf record -o /dev/null -e "instructions, cycles/period=3D100000,r= atio-to-prev=3D0.5/" \ + true |& grep -q 'Invalid use of ratio-to-prev term without preceding = element in group' + then + echo "ratio-to-prev test [Failed elements must be in same group]" + err=3D1 + return + fi + if ! perf record -o /dev/null -e "{instructions,dummy,cycles/period=3D10= 0000,ratio-to-prev=3D0.5/}" \ + true |& grep -q 'must have same PMU' + then + echo "ratio-to-prev test [Failed elements must have same PMU]" + err=3D1 + return + fi + if ! perf record -o /dev/null -e "{instructions,cycles/ratio-to-prev=3D0= .5/}" \ + true |& grep -q 'Event period term or count (-c) must be set when usi= ng ratio-to-prev term.' + then + echo "ratio-to-prev test [Failed period must be set]" + err=3D1 + return + fi + if ! perf record -o /dev/null -e "{cycles/ratio-to-prev=3D0.5/}" \ + true |& grep -q 'Invalid use of ratio-to-prev term without preceding = element in group' + then + echo "ratio-to-prev test [Failed need 2+ events]" + err=3D1 + return + fi + echo "Basic ratio-to-prev record test [Success]" +} + # raise the limit of file descriptors to minimum if [[ $default_fd_limit -lt $min_fd_limit ]]; then ulimit -Sn $min_fd_limit @@ -404,6 +443,7 @@ test_leader_sampling test_topdown_leader_sampling test_precise_max test_callgraph +test_ratio_to_prev =20 # restore the default value ulimit -Sn $default_fd_limit --=20 2.50.1