From nobody Sat Oct 4 09:34:56 2025 Received: from mail-ua1-f73.google.com (mail-ua1-f73.google.com [209.85.222.73]) (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 8F75E13C3F6 for ; Mon, 18 Aug 2025 19:05:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755543919; cv=none; b=jGgRwb8B4Hz+GsLkz5CiZ3k7rz1TLm8oqBwvyizBtFkjPctfqfOZZ7B8vQfH0IEnPyLkZammCPmBpaFLcFKleKGAVSTLRxIC7tFNXE+W9TJ2xtOm6l70kBZDHGNG9bd06ZY3bZ3luxJ5S+WDa2QrupklUuQ3vEnuz5gFRtd4h8w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755543919; c=relaxed/simple; bh=qa4R15qOtzR/BH3eD0r26mPAJuG5D1h7By2gS57JXe4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=emCv2Maz5gVzN7Z+Dd53Yd6ej5eNEeeoULGLdUOPf+0bNR3uqPJybXM1zKNZkWdLeG9Yu2Tc3qZ2s3iUvUqsWQldTWGlAC2d+wwgkT3yqjnwu5kfVKT7Ut/iHKH2paxHa9z1a8caMFrSnu90wnpHaUc63dv6gjtJcGfEfuLPEA0= 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=fBkhZOTm; arc=none smtp.client-ip=209.85.222.73 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="fBkhZOTm" Received: by mail-ua1-f73.google.com with SMTP id a1e0cc1a2514c-89018f681bbso10672700241.1 for ; Mon, 18 Aug 2025 12:05:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1755543916; x=1756148716; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=AeQy6U6Mcs+KaMWERQdrKYPgECEKs1fDnJTxQRr5IIg=; b=fBkhZOTmDW1Qq9cScgjCtBJKDryRuCkpfYdmwjXk1uR6i0tI8ica+GK+WKnGJZvA9O DNfnNBWvcJOEyJT+M2PG2PJE+7wHPr2/H/tbyMv/bon36exYVuel8Mw41jPYlRl2jBts IFLFIzsWWfcUiWcvRA5yIYZVqbt/aKJNEnJ/KtotS79GjNXBO6EyM2H09yf91QgerZaJ x87YYf7ZkZlLwmnE4lfsvbTMR9s47BsjNHxPGobcd1RO2AGrDshiKVw9UrZrxDH6z2WA IMenRNMf7JvQbTKgAjf3rQntuDK4Q6EF6+93QbBhcsN/UM87J933lnoeDfWLDecDHEua GuTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755543916; x=1756148716; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=AeQy6U6Mcs+KaMWERQdrKYPgECEKs1fDnJTxQRr5IIg=; b=fTgqGN8/HcbFAaEDS++rFR2T6sXWYbrakxVyBb85iGGwNrtEb9GFBtjF1NKKFaNOMe 5YZjTq1HLqXKrkJzPbZoob7UbS5lwwFzhXKGoYWMcr9LD4rQD46tkuvP5jxzvrZ8yQI6 XGjARRm9mmz6FX44UZfXtB8kGxNpDn/OuQ79DgmgEpxyEF67hSuTQb7XMWm/vYyM/EMu 9U2feQWJscCDyoWDk2yT4T3m0eGNV21Yx1WNxl3/YRqQYbWhBafiN0bEf4cF9OCFfsFH TpO3S05kl3aWq8Eupa3XABAx3ARSjZ9BNOFtnDe+gPHbsGYG14YiSNXzoNmPpk3ZnuD8 h9yA== X-Forwarded-Encrypted: i=1; AJvYcCXPvF0dk7gvvyk4HKzUnqcyM8TS9IdQRZlK/eNpQ7A1ORKviPPF/ldSi2ZlE/L2/YP85ISbuuCAE7ek8hw=@vger.kernel.org X-Gm-Message-State: AOJu0Yyxpyf/b4oi/BAwPFXBPPPUBDrdFQgbVB7QvoPGkJzKLYiTO4pX ZgboN2ZBVvJXajTIXHvzJQss3hq3ZEPNjAaHUOvI5rBmaPVbbqX05IyI7Agpr0cyE0f/Vm5h9xm 2pm60fnchwA== X-Google-Smtp-Source: AGHT+IEfHh5zGZXDJ9T3IT6pTGa5q70K/Gu2z6P2zjPHw2vIVBLhzL3OtHQqqFDhXcyKpJAh+Pcx/6lmk97i X-Received: from qkntz8.prod.google.com ([2002:a05:620a:6908:b0:7e2:e9ed:1448]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6102:dcb:b0:4fa:d2c:4ff with SMTP id ada2fe7eead31-514cb1a5babmr4171144137.27.1755543916305; Mon, 18 Aug 2025 12:05:16 -0700 (PDT) Date: Mon, 18 Aug 2025 12:03:57 -0700 In-Reply-To: <20250818190416.145274-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250818190416.145274-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.rc1.167.g924127e9c0-goog Message-ID: <20250818190416.145274-2-irogers@google.com> Subject: [PATCH v2 01/20] perf parse-events: Handle fake PMUs in CPU terms From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Kan Liang , "=?UTF-8?q?Andreas=20F=C3=A4rber?=" , Manivannan Sadhasivam , Caleb Biggers , Thomas Falcon , Weilin Wang , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, linux-actions@lists.infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The "Parsing of PMU event table metrics with fake PMUs" will test metrics on machines/models that may be missing a PMU, in such a case the fake_pmu should be used to avoid errors. Metrics that get the cpumask from a different PMU, such as "tsc/cpu=3Dcpu_atom/", also need to be resilient in this test. The parse_events_state fake_pmu is set when missing PMUs should be ignored. So that it can be queried, pass it to the config term functions, as well as to get_config_cpu, then ignore failures when fake_pmu is set. Some minor code refactoring to cut down on the indent and remove some redundant checks. Fixes: bd741d80dc65 ("perf parse-events: Allow the cpu term to be a PMU or = CPU range") Signed-off-by: Ian Rogers --- tools/perf/util/parse-events.c | 116 +++++++++++++++++---------------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 8282ddf68b98..0026cff4d69e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -126,7 +126,8 @@ static char *get_config_name(const struct parse_events_= terms *head_terms) return get_config_str(head_terms, PARSE_EVENTS__TERM_TYPE_NAME); } =20 -static struct perf_cpu_map *get_config_cpu(const struct parse_events_terms= *head_terms) +static struct perf_cpu_map *get_config_cpu(const struct parse_events_terms= *head_terms, + bool fake_pmu) { struct parse_events_term *term; struct perf_cpu_map *cpus =3D NULL; @@ -135,24 +136,33 @@ static struct perf_cpu_map *get_config_cpu(const stru= ct parse_events_terms *head return NULL; =20 list_for_each_entry(term, &head_terms->terms, list) { - if (term->type_term =3D=3D PARSE_EVENTS__TERM_TYPE_CPU) { - struct perf_cpu_map *term_cpus; + struct perf_cpu_map *term_cpus; =20 - if (term->type_val =3D=3D PARSE_EVENTS__TERM_TYPE_NUM) { - term_cpus =3D perf_cpu_map__new_int(term->val.num); + if (term->type_term !=3D PARSE_EVENTS__TERM_TYPE_CPU) + continue; + + if (term->type_val =3D=3D PARSE_EVENTS__TERM_TYPE_NUM) { + term_cpus =3D perf_cpu_map__new_int(term->val.num); + } else { + struct perf_pmu *pmu =3D perf_pmus__find(term->val.str); + + if (pmu) { + term_cpus =3D pmu->is_core && perf_cpu_map__is_empty(pmu->cpus) + ? cpu_map__online() + : perf_cpu_map__get(pmu->cpus); } else { - struct perf_pmu *pmu =3D perf_pmus__find(term->val.str); - - if (pmu && perf_cpu_map__is_empty(pmu->cpus)) - term_cpus =3D pmu->is_core ? cpu_map__online() : NULL; - else if (pmu) - term_cpus =3D perf_cpu_map__get(pmu->cpus); - else - term_cpus =3D perf_cpu_map__new(term->val.str); + term_cpus =3D perf_cpu_map__new(term->val.str); + if (!term_cpus && fake_pmu) { + /* + * Assume the PMU string makes sense on a different + * machine and fake a value with all online CPUs. + */ + term_cpus =3D cpu_map__online(); + } } - perf_cpu_map__merge(&cpus, term_cpus); - perf_cpu_map__put(term_cpus); } + perf_cpu_map__merge(&cpus, term_cpus); + perf_cpu_map__put(term_cpus); } =20 return cpus; @@ -369,13 +379,13 @@ static int parse_aliases(const char *str, const char = *const names[][EVSEL__MAX_A =20 typedef int config_term_func_t(struct perf_event_attr *attr, struct parse_events_term *term, - struct parse_events_error *err); + struct parse_events_state *parse_state); static int config_term_common(struct perf_event_attr *attr, struct parse_events_term *term, - struct parse_events_error *err); + struct parse_events_state *parse_state); static int config_attr(struct perf_event_attr *attr, const struct parse_events_terms *head, - struct parse_events_error *err, + struct parse_events_state *parse_state, config_term_func_t config_term); =20 /** @@ -471,7 +481,7 @@ int parse_events_add_cache(struct list_head *list, int = *idx, const char *name, bool found_supported =3D false; const char *config_name =3D get_config_name(parsed_terms); const char *metric_id =3D get_config_metric_id(parsed_terms); - struct perf_cpu_map *cpus =3D get_config_cpu(parsed_terms); + struct perf_cpu_map *cpus =3D get_config_cpu(parsed_terms, parse_state->f= ake_pmu); int ret =3D 0; struct evsel *first_wildcard_match =3D NULL; =20 @@ -514,8 +524,7 @@ int parse_events_add_cache(struct list_head *list, int = *idx, const char *name, found_supported =3D true; =20 if (parsed_terms) { - if (config_attr(&attr, parsed_terms, parse_state->error, - config_term_common)) { + if (config_attr(&attr, parsed_terms, parse_state, config_term_common)) { ret =3D -EINVAL; goto out_err; } @@ -767,8 +776,7 @@ int parse_events_add_breakpoint(struct parse_events_sta= te *parse_state, attr.sample_period =3D 1; =20 if (head_config) { - if (config_attr(&attr, head_config, parse_state->error, - config_term_common)) + if (config_attr(&attr, head_config, parse_state, config_term_common)) return -EINVAL; =20 if (get_config_terms(head_config, &config_terms)) @@ -903,12 +911,12 @@ void parse_events__shrink_config_terms(void) =20 static int config_term_common(struct perf_event_attr *attr, struct parse_events_term *term, - struct parse_events_error *err) + struct parse_events_state *parse_state) { -#define CHECK_TYPE_VAL(type) \ -do { \ - if (check_type_val(term, err, PARSE_EVENTS__TERM_TYPE_ ## type)) \ - return -EINVAL; \ +#define CHECK_TYPE_VAL(type) \ +do { \ + if (check_type_val(term, parse_state->error, PARSE_EVENTS__TERM_TYPE_ ## = type)) \ + return -EINVAL; \ } while (0) =20 switch (term->type_term) { @@ -939,7 +947,7 @@ do { \ if (strcmp(term->val.str, "no") && parse_branch_str(term->val.str, &attr->branch_sample_type)) { - parse_events_error__handle(err, term->err_val, + parse_events_error__handle(parse_state->error, term->err_val, strdup("invalid branch sample type"), NULL); return -EINVAL; @@ -948,7 +956,7 @@ do { \ case PARSE_EVENTS__TERM_TYPE_TIME: CHECK_TYPE_VAL(NUM); if (term->val.num > 1) { - parse_events_error__handle(err, term->err_val, + parse_events_error__handle(parse_state->error, term->err_val, strdup("expected 0 or 1"), NULL); return -EINVAL; @@ -990,7 +998,7 @@ do { \ case PARSE_EVENTS__TERM_TYPE_PERCORE: CHECK_TYPE_VAL(NUM); if ((unsigned int)term->val.num > 1) { - parse_events_error__handle(err, term->err_val, + parse_events_error__handle(parse_state->error, term->err_val, strdup("expected 0 or 1"), NULL); return -EINVAL; @@ -1005,7 +1013,7 @@ do { \ case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: CHECK_TYPE_VAL(NUM); if (term->val.num > UINT_MAX) { - parse_events_error__handle(err, term->err_val, + parse_events_error__handle(parse_state->error, term->err_val, strdup("too big"), NULL); return -EINVAL; @@ -1016,7 +1024,7 @@ do { \ =20 if (term->type_val =3D=3D PARSE_EVENTS__TERM_TYPE_NUM) { if (term->val.num >=3D (u64)cpu__max_present_cpu().cpu) { - parse_events_error__handle(err, term->err_val, + parse_events_error__handle(parse_state->error, term->err_val, strdup("too big"), /*help=3D*/NULL); return -EINVAL; @@ -1028,8 +1036,8 @@ do { \ break; =20 map =3D perf_cpu_map__new(term->val.str); - if (!map) { - parse_events_error__handle(err, term->err_val, + if (!map && !parse_state->fake_pmu) { + parse_events_error__handle(parse_state->error, term->err_val, strdup("not a valid PMU or CPU number"), /*help=3D*/NULL); return -EINVAL; @@ -1042,7 +1050,7 @@ do { \ case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: default: - parse_events_error__handle(err, term->err_term, + parse_events_error__handle(parse_state->error, term->err_term, strdup(parse_events__term_type_str(term->type_term)), parse_events_formats_error_string(NULL)); return -EINVAL; @@ -1057,7 +1065,7 @@ do { \ * if an invalid config term is provided for legacy events * (for example, instructions/badterm/...), which is confusing. */ - if (!config_term_avail(term->type_term, err)) + if (!config_term_avail(term->type_term, parse_state->error)) return -EINVAL; return 0; #undef CHECK_TYPE_VAL @@ -1065,7 +1073,7 @@ do { \ =20 static int config_term_pmu(struct perf_event_attr *attr, struct parse_events_term *term, - struct parse_events_error *err) + struct parse_events_state *parse_state) { if (term->type_term =3D=3D PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE) { struct perf_pmu *pmu =3D perf_pmus__find_by_type(attr->type); @@ -1074,7 +1082,7 @@ static int config_term_pmu(struct perf_event_attr *at= tr, char *err_str; =20 if (asprintf(&err_str, "Failed to find PMU for type %d", attr->type) >= =3D 0) - parse_events_error__handle(err, term->err_term, + parse_events_error__handle(parse_state->error, term->err_term, err_str, /*help=3D*/NULL); return -EINVAL; } @@ -1100,7 +1108,7 @@ static int config_term_pmu(struct perf_event_attr *at= tr, char *err_str; =20 if (asprintf(&err_str, "Failed to find PMU for type %d", attr->type) >= =3D 0) - parse_events_error__handle(err, term->err_term, + parse_events_error__handle(parse_state->error, term->err_term, err_str, /*help=3D*/NULL); return -EINVAL; } @@ -1128,12 +1136,12 @@ static int config_term_pmu(struct perf_event_attr *= attr, */ return 0; } - return config_term_common(attr, term, err); + return config_term_common(attr, term, parse_state); } =20 static int config_term_tracepoint(struct perf_event_attr *attr, struct parse_events_term *term, - struct parse_events_error *err) + struct parse_events_state *parse_state) { switch (term->type_term) { case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: @@ -1147,7 +1155,7 @@ static int config_term_tracepoint(struct perf_event_a= ttr *attr, case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: case PARSE_EVENTS__TERM_TYPE_AUX_ACTION: case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: - return config_term_common(attr, term, err); + return config_term_common(attr, term, parse_state); case PARSE_EVENTS__TERM_TYPE_USER: case PARSE_EVENTS__TERM_TYPE_CONFIG: case PARSE_EVENTS__TERM_TYPE_CONFIG1: @@ -1166,12 +1174,10 @@ static int config_term_tracepoint(struct perf_event= _attr *attr, case PARSE_EVENTS__TERM_TYPE_HARDWARE: case PARSE_EVENTS__TERM_TYPE_CPU: default: - if (err) { - parse_events_error__handle(err, term->err_term, + parse_events_error__handle(parse_state->error, term->err_term, strdup(parse_events__term_type_str(term->type_term)), strdup("valid terms: call-graph,stack-size\n") ); - } return -EINVAL; } =20 @@ -1180,13 +1186,13 @@ static int config_term_tracepoint(struct perf_event= _attr *attr, =20 static int config_attr(struct perf_event_attr *attr, const struct parse_events_terms *head, - struct parse_events_error *err, + struct parse_events_state *parse_state, config_term_func_t config_term) { struct parse_events_term *term; =20 list_for_each_entry(term, &head->terms, list) - if (config_term(attr, term, err)) + if (config_term(attr, term, parse_state)) return -EINVAL; =20 return 0; @@ -1378,8 +1384,7 @@ int parse_events_add_tracepoint(struct parse_events_s= tate *parse_state, if (head_config) { struct perf_event_attr attr; =20 - if (config_attr(&attr, head_config, err, - config_term_tracepoint)) + if (config_attr(&attr, head_config, parse_state, config_term_tracepoint)) return -EINVAL; } =20 @@ -1408,8 +1413,7 @@ static int __parse_events_add_numeric(struct parse_ev= ents_state *parse_state, } =20 if (head_config) { - if (config_attr(&attr, head_config, parse_state->error, - config_term_common)) + if (config_attr(&attr, head_config, parse_state, config_term_common)) return -EINVAL; =20 if (get_config_terms(head_config, &config_terms)) @@ -1418,7 +1422,7 @@ static int __parse_events_add_numeric(struct parse_ev= ents_state *parse_state, =20 name =3D get_config_name(head_config); metric_id =3D get_config_metric_id(head_config); - cpus =3D get_config_cpu(head_config); + cpus =3D get_config_cpu(head_config, parse_state->fake_pmu); ret =3D __add_event(list, &parse_state->idx, &attr, /*init_attr*/true, na= me, metric_id, pmu, &config_terms, first_wildcard_match, cpus, /*alternate_hw_config=3D*/PERF_COUNT_HW_MAX) ? 0 : -ENOMEM; @@ -1531,7 +1535,7 @@ static int parse_events_add_pmu(struct parse_events_s= tate *parse_state, fix_raw(&parsed_terms, pmu); =20 /* Configure attr/terms with a known PMU, this will set hardcoded terms. = */ - if (config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu= )) { + if (config_attr(&attr, &parsed_terms, parse_state, config_term_pmu)) { parse_events_terms__exit(&parsed_terms); return -EINVAL; } @@ -1555,7 +1559,7 @@ static int parse_events_add_pmu(struct parse_events_s= tate *parse_state, =20 /* Configure attr/terms again if an alias was expanded. */ if (alias_rewrote_terms && - config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu= )) { + config_attr(&attr, &parsed_terms, parse_state, config_term_pmu)) { parse_events_terms__exit(&parsed_terms); return -EINVAL; } @@ -1583,7 +1587,7 @@ static int parse_events_add_pmu(struct parse_events_s= tate *parse_state, return -EINVAL; } =20 - term_cpu =3D get_config_cpu(&parsed_terms); + term_cpu =3D get_config_cpu(&parsed_terms, parse_state->fake_pmu); evsel =3D __add_event(list, &parse_state->idx, &attr, /*init_attr=3D*/tru= e, get_config_name(&parsed_terms), get_config_metric_id(&parsed_terms), pmu, --=20 2.51.0.rc1.167.g924127e9c0-goog