From nobody Fri Oct 3 10:15:35 2025 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (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 B9D7A186E2E; Thu, 2 Oct 2025 23:43:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759448613; cv=none; b=o6Bs7JnsAr9AwiAdZxNNmsQGGON1uQf6b69+TZflIy4eB5JaFd0A/Lexxdge6w1xDXfIkppz1+qRlH4lPTWLeAifuOZ88Ly+3jAWjeA/jfSlzRStISnYfdUiPBekmVkNVV+WhtlQjYBsX1KLKRCyirujxI/tIrJCnVZoHopAQjA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759448613; c=relaxed/simple; bh=jJvHcbWAf4BQyTOyi0wN3KBal96wMSPUvnsK+BA4L9M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WSq0x/jk3EdBlcv2DjN5X579pGtzPwV6oj6lUdxA/A/hw+nNR2LgKrVM5I6XYz4ePzBl1kFCxW/PcvAxDXCUYJ1ZEteSrmzDliVt13v+iyEO7OEbsv2x3Oc5Tn70d9eHWi1SaStD9YWBdNmPhyX0mcmBiq60oLXJLsFWYVjEa6A= 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=ldOiLDfY; arc=none smtp.client-ip=192.198.163.18 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="ldOiLDfY" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1759448612; x=1790984612; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=jJvHcbWAf4BQyTOyi0wN3KBal96wMSPUvnsK+BA4L9M=; b=ldOiLDfYzAMTCd8B94PRhoSJC6l8AgX+yXYVTnBfCXepDfmN4qcD4Rze x3JnoguPX+wYU7/5oZomiL2cjeUweRwlFc/OwFCxh2/oP9Cj+p0FaBrHK NYMj720Fo4d43H3NY+5Dy5UmuAP4WhpCklhwP175j8BJnk+sxjrhpmoJQ jSnApXv93T7NLeBHnPHwt7zM1bbEZyGMDiJYPpwCvQpnjMmuDBgc5d4tB +Zj8Mixp84u55sXziAHUnX4nngAH+vRx4LKyGRJLORjPTgyMYXMQKUV3I s9Qqw32qVYa9mNyCwpgw/aFzAqWy1DapPmQKv4FzImq0v5e6DqCpSOS9m g==; X-CSE-ConnectionGUID: PGt3WUKCSB2rO12vM8slXA== X-CSE-MsgGUID: 2tTVMY3gSfSYaRmEoNh+2w== X-IronPort-AV: E=McAfee;i="6800,10657,11570"; a="60948394" X-IronPort-AV: E=Sophos;i="6.18,310,1751266800"; d="scan'208";a="60948394" Received: from orviesa010.jf.intel.com ([10.64.159.150]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Oct 2025 16:43:31 -0700 X-CSE-ConnectionGUID: QQKTnCR0SeS+ap9J6b4s7Q== X-CSE-MsgGUID: w8c11MG0T+q8x8SjiF2qWA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.18,310,1751266800"; d="scan'208";a="178444540" Received: from mgoodin-mobl3.amr.corp.intel.com (HELO tfalcon-desk.attlocal.net) ([10.124.223.53]) by orviesa010.jf.intel.com with ESMTP; 02 Oct 2025 16:43:30 -0700 From: thomas.falcon@intel.com 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, Andi Kleen , Dapeng Mi , Thomas Falcon Subject: [Patch v3 1/2] perf record: Add ratio-to-prev term Date: Thu, 2 Oct 2025 18:43:05 -0500 Message-ID: <20251002234308.64218-2-thomas.falcon@intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251002234308.64218-1-thomas.falcon@intel.com> References: <20251002234308.64218-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" From: Thomas Falcon 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. Reviewed-by: Ian Rogers 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 | 52 ++++++++++++++++++ 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, 212 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 a5039d1614f9..a4378a0cd914 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -393,6 +393,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 e67701d26f24..23a8e662a912 100644 --- a/tools/perf/arch/x86/util/evsel.c +++ b/tools/perf/arch/x86/util/evsel.c @@ -4,6 +4,7 @@ #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" @@ -71,6 +72,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 1a29d4f47bbf..56cef1310574 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 03f9f22e3a0c..521d280c4abe 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -343,6 +343,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, int err, char *msg, siz= e_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 452f12191f6e..da73d686f6b9 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -842,6 +842,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"; @@ -892,6 +893,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; @@ -1045,6 +1047,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(parse_state->error, term->err_val, + strdup("zero or negative"), + NULL); + return -EINVAL; + } + if (errno =3D=3D ERANGE) { + parse_events_error__handle(parse_state->error, 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: @@ -1173,6 +1190,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: parse_events_error__handle(parse_state->error, term->err_term, strdup(parse_events__term_type_str(term->type_term)), @@ -1295,6 +1313,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: @@ -1361,6 +1382,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 a5c5fc39fd6f..8f8c8e7fbcf1 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 294e943bcdb4..c985aa8a7d56 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -337,6 +337,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 Fri Oct 3 10:15:35 2025 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (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 854342C08D5; Thu, 2 Oct 2025 23:43:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759448615; cv=none; b=Iz9ekUKbUTK1FY0Uj/FQik+ED1pk86GvA6EEy/jQF0t93Nqm4dNrlcN8apyOVRkCQXwTsmE416IVYTRjs773RdB583CbJatGCQAU8Ywc4Z+8vVrhgLdQxhL4Sye/JxFMdyE9vccBqTyzT0+5P7KDBLsO/tqFUBSlfpQleYrnDS8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759448615; c=relaxed/simple; bh=53y8mTKwYGU9EQpfzk/NGpruUlqMD9aiccI+mmERdBg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dDltKTB3Vphl5kkzSZbCY5dQ0eg025kAooXyuCrC7BBT5elDTJgeCY14RCy3SvHompV6qwrX8NQLxO9+OREJpaEJ/etnkLjyrJ2YfrnI/qlGG0+d1a/N3oQ7FoiUXS+SSzvO77HlGxPutzf4UpMwUUrR6f5uREkgHq2kv5JSfNI= 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=X6cxv/B0; arc=none smtp.client-ip=192.198.163.18 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="X6cxv/B0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1759448614; x=1790984614; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=53y8mTKwYGU9EQpfzk/NGpruUlqMD9aiccI+mmERdBg=; b=X6cxv/B0eed+7jj82xh4eNcAav310t96jVLvio6XARHMSWVetz/HI9am JWm4WLmI1pfv6evWswgrYUemavVWfpdPYm6grZLufud0TSimCNhSYppx+ Pges+PXWx/D+iivM1chhwIWDyJzgvDZPVoOmFo2XVzXPQbNC98mk2Bre/ Y2MdJwIkBpVcsnUrABp0z+s5lH8g7bjqwEtO0PvSI1LjmmX891jVQi3UV FD1Ugfbb1merMdPAC1IRz4soqI97HG0V3++BV/HGBjgqQJs7FQaGdUdSf HGUsi43cMqilTUz6sKQ9LDrPHwBL2J4VTD3boIChOvLRlsr74k4PqkBKW g==; X-CSE-ConnectionGUID: mltELkH8TwqieYu98yrnlA== X-CSE-MsgGUID: GFcz0VFLQTG/YwWSWTNRvA== X-IronPort-AV: E=McAfee;i="6800,10657,11570"; a="60948401" X-IronPort-AV: E=Sophos;i="6.18,310,1751266800"; d="scan'208";a="60948401" Received: from orviesa010.jf.intel.com ([10.64.159.150]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Oct 2025 16:43:33 -0700 X-CSE-ConnectionGUID: TWYbA5FgRiaf6JbFs5CK/A== X-CSE-MsgGUID: kyvZrzOsTO2S42W5shpXwg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.18,310,1751266800"; d="scan'208";a="178444545" Received: from mgoodin-mobl3.amr.corp.intel.com (HELO tfalcon-desk.attlocal.net) ([10.124.223.53]) by orviesa010.jf.intel.com with ESMTP; 02 Oct 2025 16:43:32 -0700 From: thomas.falcon@intel.com 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, Andi Kleen , Dapeng Mi , Thomas Falcon Subject: [Patch v3 2/2] perf record: Add auto counter reload parse and regression tests Date: Thu, 2 Oct 2025 18:43:06 -0500 Message-ID: <20251002234308.64218-3-thomas.falcon@intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251002234308.64218-1-thomas.falcon@intel.com> References: <20251002234308.64218-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" From: Thomas Falcon Include event parsing and regression tests for auto counter reload and ratio-to-prev event term. Reviewed-by: Ian Rogers 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