From: Ian Rogers <irogers@google.com>
To: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Namhyung Kim <namhyung@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>, Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
James Clark <james.clark@linaro.org>,
linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v1 15/26] perf expr: Use generic hashmap for expr_ids
Date: Fri, 13 Nov 2026 13:48:39 -0800 [thread overview]
Message-ID: <20261113214850.3329699-16-irogers@google.com> (raw)
In-Reply-To: <20261113214850.3329699-1-irogers@google.com>
Convert expr_parse_ctx::ids and ids__* helpers across util/expr.{c,h,y},
util/metricgroup.c, tests/expr.c, and tests/pmu-events.c to
DECLARE_HASHMAP(expr_ids_map, const char *, struct expr_id_data *).
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/expr.c | 2 +-
tools/perf/tests/pmu-events.c | 16 +++---
tools/perf/util/expr.c | 99 +++++++++++++++++------------------
tools/perf/util/expr.h | 18 ++++---
tools/perf/util/expr.y | 2 +-
tools/perf/util/metricgroup.c | 28 +++++-----
6 files changed, 83 insertions(+), 82 deletions(-)
diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c
index 726cf8d4da28..a2c7dc4d71c9 100644
--- a/tools/perf/tests/expr.c
+++ b/tools/perf/tests/expr.c
@@ -15,7 +15,7 @@
static int test_ids_union(void)
{
- struct hashmap *ids1, *ids2;
+ struct expr_ids_map *ids1, *ids2;
/* Empty union. */
ids1 = ids__new();
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index e6e4f4cf1fa2..42862501f0bf 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -964,10 +964,10 @@ static struct test_metric metrics[] = {
static int metric_parse_fake(const char *metric_name, const char *str)
{
struct expr_parse_ctx *ctx;
- struct hashmap_entry *cur;
+ const char *key;
+ struct expr_id_data *val;
double result;
int ret = -1;
- size_t bkt;
int i;
pr_debug("parsing '%s': '%s'\n", metric_name, str);
@@ -989,11 +989,11 @@ static int metric_parse_fake(const char *metric_name, const char *str)
* make them unique.
*/
i = 1;
- hashmap__for_each_entry(ctx->ids, cur, bkt)
- expr__add_id_val(ctx, strdup(cur->pkey), i++);
+ hashmap__for_each(ctx->ids, key, val)
+ expr__add_id_val(ctx, strdup(key), i++);
- hashmap__for_each_entry(ctx->ids, cur, bkt) {
- if (check_parse_fake(cur->pkey)) {
+ hashmap__for_each(ctx->ids, key, val) {
+ if (check_parse_fake(key)) {
pr_err("check_parse_fake failed\n");
goto out;
}
@@ -1006,8 +1006,8 @@ static int metric_parse_fake(const char *metric_name, const char *str)
* resolve divide by zero issues.
*/
i = 1024;
- hashmap__for_each_entry(ctx->ids, cur, bkt)
- expr__add_id_val(ctx, strdup(cur->pkey), i--);
+ hashmap__for_each(ctx->ids, key, val)
+ expr__add_id_val(ctx, strdup(key), i--);
if (expr__parse(&result, ctx, str)) {
pr_err("expr__parse failed for %s\n", metric_name);
/* The following have hard to avoid divide by zero. */
diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index ac0243576def..d548ae5a4ec9 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -64,48 +64,46 @@ static bool key_equal(long key1, long key2, void *ctx __maybe_unused)
return !strcmp((const char *)key1, (const char *)key2);
}
-struct hashmap *ids__new(void)
+struct expr_ids_map *ids__new(void)
{
- return hashmap__new(key_hash, key_equal, NULL);
+ return expr_ids_map__new(key_hash, key_equal, NULL);
}
-void ids__free(struct hashmap *ids)
+void ids__free(struct expr_ids_map *ids)
{
- struct hashmap_entry *cur;
- size_t bkt;
+ const char *key;
+ struct expr_id_data *val;
if (ids == NULL)
return;
- hashmap__for_each_entry(ids, cur, bkt) {
- zfree(&cur->pkey);
- zfree(&cur->pvalue);
+ hashmap__for_each(ids, key, val) {
+ free((char *)key);
+ free(val);
}
- hashmap__free(ids);
+ expr_ids_map__free(ids);
}
-int ids__insert(struct hashmap *ids, const char *id)
+int ids__insert(struct expr_ids_map *ids, const char *id)
{
struct expr_id_data *data_ptr = NULL, *old_data = NULL;
- char *old_key = NULL;
+ const char *old_key = NULL;
int ret;
ret = hashmap__set(ids, id, data_ptr, &old_key, &old_data);
if (ret)
free(data_ptr);
- free(old_key);
+ free((char *)old_key);
free(old_data);
return ret;
}
-struct hashmap *ids__union(struct hashmap *ids1, struct hashmap *ids2)
+struct expr_ids_map *ids__union(struct expr_ids_map *ids1, struct expr_ids_map *ids2)
{
- size_t bkt;
- struct hashmap_entry *cur;
+ const char *key, *old_key = NULL;
+ struct expr_id_data *val, *old_data = NULL;
int ret;
- struct expr_id_data *old_data = NULL;
- char *old_key = NULL;
if (!ids1)
return ids2;
@@ -113,24 +111,24 @@ struct hashmap *ids__union(struct hashmap *ids1, struct hashmap *ids2)
if (!ids2)
return ids1;
- if (hashmap__size(ids1) < hashmap__size(ids2)) {
- struct hashmap *tmp = ids1;
+ if (hashmap__size(ids1) < hashmap__size(ids2)) {
+ struct expr_ids_map *tmp = ids1;
ids1 = ids2;
ids2 = tmp;
}
- hashmap__for_each_entry(ids2, cur, bkt) {
- ret = hashmap__set(ids1, cur->key, cur->value, &old_key, &old_data);
- free(old_key);
+ hashmap__for_each(ids2, key, val) {
+ ret = hashmap__set(ids1, key, val, &old_key, &old_data);
+ free((char *)old_key);
free(old_data);
if (ret) {
- hashmap__free(ids1);
- hashmap__free(ids2);
+ expr_ids_map__free(ids1);
+ expr_ids_map__free(ids2);
return NULL;
}
}
- hashmap__free(ids2);
+ expr_ids_map__free(ids2);
return ids1;
}
@@ -151,7 +149,7 @@ int expr__add_id_val_source_count_aggr_nr(struct expr_parse_ctx *ctx, const char
double val, int source_count, int aggr_nr)
{
struct expr_id_data *data_ptr = NULL, *old_data = NULL;
- char *old_key = NULL;
+ const char *old_key = NULL;
int ret;
data_ptr = malloc(sizeof(*data_ptr));
@@ -170,7 +168,7 @@ int expr__add_id_val_source_count_aggr_nr(struct expr_parse_ctx *ctx, const char
data_ptr->val.source_count += old_data->val.source_count;
data_ptr->val.aggr_nr += old_data->val.aggr_nr;
}
- free(old_key);
+ free((char *)old_key);
free(old_data);
return ret;
}
@@ -185,7 +183,7 @@ int expr__add_id_val_source_count(struct expr_parse_ctx *ctx, const char *id,
int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
{
struct expr_id_data *data_ptr = NULL, *old_data = NULL;
- char *old_key = NULL;
+ const char *old_key = NULL;
char *name;
int ret;
@@ -210,13 +208,15 @@ int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
data_ptr->kind = EXPR_ID_DATA__REF;
ret = hashmap__set(ctx->ids, name, data_ptr, &old_key, &old_data);
- if (ret)
+ if (ret) {
free(data_ptr);
+ free(name);
+ }
pr_debug2("adding ref metric %s: %s\n",
ref->metric_name, ref->metric_expr);
- free(old_key);
+ free((char *)old_key);
free(old_data);
return ret;
}
@@ -232,12 +232,11 @@ int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
bool expr__subset_of_ids(struct expr_parse_ctx *haystack,
struct expr_parse_ctx *needles)
{
- struct hashmap_entry *cur;
- size_t bkt;
- struct expr_id_data *data;
+ const char *key;
+ struct expr_id_data *val, *data;
- hashmap__for_each_entry(needles->ids, cur, bkt) {
- if (expr__get_id(haystack, cur->pkey, &data))
+ hashmap__for_each(needles->ids, key, val) {
+ if (expr__get_id(haystack, key, &data))
return false;
}
return true;
@@ -285,10 +284,10 @@ int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
{
struct expr_id_data *old_val = NULL;
- char *old_key = NULL;
+ const char *old_key = NULL;
hashmap__delete(ctx->ids, id, &old_key, &old_val);
- free(old_key);
+ free((char *)old_key);
free(old_val);
}
@@ -300,7 +299,7 @@ struct expr_parse_ctx *expr__ctx_new(void)
if (!ctx)
return NULL;
- ctx->ids = hashmap__new(key_hash, key_equal, NULL);
+ ctx->ids = expr_ids_map__new(key_hash, key_equal, NULL);
if (!ctx->ids) {
free(ctx);
return NULL;
@@ -311,30 +310,30 @@ struct expr_parse_ctx *expr__ctx_new(void)
void expr__ctx_clear(struct expr_parse_ctx *ctx)
{
- struct hashmap_entry *cur;
- size_t bkt;
+ const char *key;
+ struct expr_id_data *val;
- hashmap__for_each_entry(ctx->ids, cur, bkt) {
- zfree(&cur->pkey);
- zfree(&cur->pvalue);
+ hashmap__for_each(ctx->ids, key, val) {
+ free((char *)key);
+ free(val);
}
hashmap__clear(ctx->ids);
}
void expr__ctx_free(struct expr_parse_ctx *ctx)
{
- struct hashmap_entry *cur;
- size_t bkt;
+ const char *key;
+ struct expr_id_data *val;
if (!ctx)
return;
zfree(&ctx->sctx.user_requested_cpu_list);
- hashmap__for_each_entry(ctx->ids, cur, bkt) {
- zfree(&cur->pkey);
- zfree(&cur->pvalue);
+ hashmap__for_each(ctx->ids, key, val) {
+ free((char *)key);
+ free(val);
}
- hashmap__free(ctx->ids);
+ expr_ids_map__free(ctx->ids);
free(ctx);
}
@@ -438,7 +437,7 @@ double expr__has_event(const struct expr_parse_ctx *ctx, bool compute_ids, const
struct evlist *tmp;
double ret;
- if (hashmap__find(ctx->ids, id, /*value=*/NULL))
+ if (hashmap__find(ctx->ids, id, /*value_ptr=*/NULL))
return 1.0;
if (!compute_ids)
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index ed12e4007d2d..57edcb3f70ea 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -2,9 +2,13 @@
#ifndef PARSE_CTX_H
#define PARSE_CTX_H 1
-struct hashmap;
+#include "hashmap.h"
+
+struct expr_id_data;
struct metric_ref;
+DECLARE_HASHMAP(expr_ids_map, const char *, struct expr_id_data *);
+
struct expr_scanner_ctx {
char *user_requested_cpu_list;
int runtime;
@@ -13,20 +17,18 @@ struct expr_scanner_ctx {
};
struct expr_parse_ctx {
- struct hashmap *ids;
+ struct expr_ids_map *ids;
struct expr_scanner_ctx sctx;
};
-struct expr_id_data;
-
-struct hashmap *ids__new(void);
-void ids__free(struct hashmap *ids);
-int ids__insert(struct hashmap *ids, const char *id);
+struct expr_ids_map *ids__new(void);
+void ids__free(struct expr_ids_map *ids);
+int ids__insert(struct expr_ids_map *ids, const char *id);
/*
* Union two sets of ids (hashmaps) and construct a third, freeing ids1 and
* ids2.
*/
-struct hashmap *ids__union(struct hashmap *ids1, struct hashmap *ids2);
+struct expr_ids_map *ids__union(struct expr_ids_map *ids1, struct expr_ids_map *ids2);
struct expr_parse_ctx *expr__ctx_new(void);
void expr__ctx_clear(struct expr_parse_ctx *ctx);
diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
index e20f649354cf..d39ba27d75bc 100644
--- a/tools/perf/util/expr.y
+++ b/tools/perf/util/expr.y
@@ -29,7 +29,7 @@ int expr_lex(YYSTYPE * yylval_param , void *yyscanner);
* When creating ids, holds the working set of event ids. NULL
* implies the set is empty.
*/
- struct hashmap *ids;
+ struct expr_ids_map *ids;
/*
* The metric value. When not creating ids this is the value
* read from a counter, a constant or some computed value. When
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 779fe56fe8d0..41887fad4968 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -289,7 +289,7 @@ static bool contains_metric_id(struct evsel **metric_events, int num_events,
* @metric_evlist: the list of perf events.
* @out_metric_events: holds the created metric events array.
*/
-static int setup_metric_events(const char *pmu, struct hashmap *ids,
+static int setup_metric_events(const char *pmu, struct expr_ids_map *ids,
struct evlist *metric_evlist,
struct evsel ***out_metric_events)
{
@@ -563,16 +563,16 @@ static int metricgroup__build_event_string(struct strbuf *events,
const char *modifier,
bool group_events)
{
- struct hashmap_entry *cur;
- size_t bkt;
+ const char *id;
+ struct expr_id_data *val;
bool no_group = true, has_tool_events = false;
bool tool_events[TOOL_PMU__EVENT_MAX] = {false};
int ret = 0;
#define RETURN_IF_NON_ZERO(x) do { if (x) return x; } while (0)
- hashmap__for_each_entry(ctx->ids, cur, bkt) {
- const char *sep, *rsep, *id = cur->pkey;
+ hashmap__for_each(ctx->ids, id, val) {
+ const char *sep, *rsep;
enum tool_pmu_event ev;
pr_debug("found event %s\n", id);
@@ -748,8 +748,8 @@ static int resolve_metric(struct list_head *metric_list,
const struct visited_metric *visited,
const struct pmu_metrics_table *table)
{
- struct hashmap_entry *cur;
- size_t bkt;
+ const char *key;
+ struct expr_id_data *val;
struct to_resolve {
/* The metric to resolve. */
struct pmu_metric pm;
@@ -765,10 +765,10 @@ static int resolve_metric(struct list_head *metric_list,
* Iterate all the parsed IDs and if there's a matching metric and it to
* the pending array.
*/
- hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
+ hashmap__for_each(root_metric->pctx->ids, key, val) {
struct pmu_metric pm;
- if (pmu_metrics_table__find_metric(table, pmu, cur->pkey,
+ if (pmu_metrics_table__find_metric(table, pmu, key,
metricgroup__find_metric_callback,
&pm) != PMU_METRICS__NOT_FOUND) {
pending = realloc(pending,
@@ -777,7 +777,7 @@ static int resolve_metric(struct list_head *metric_list,
return -ENOMEM;
memcpy(&pending[pending_cnt].pm, &pm, sizeof(pm));
- pending[pending_cnt].key = cur->pkey;
+ pending[pending_cnt].key = key;
pending_cnt++;
}
}
@@ -1229,8 +1229,8 @@ static void find_tool_events(const struct list_head *metric_list,
static int build_combined_expr_ctx(const struct list_head *metric_list,
struct expr_parse_ctx **combined)
{
- struct hashmap_entry *cur;
- size_t bkt;
+ const char *key;
+ struct expr_id_data *val;
struct metric *m;
char *dup;
int ret;
@@ -1241,8 +1241,8 @@ static int build_combined_expr_ctx(const struct list_head *metric_list,
list_for_each_entry(m, metric_list, nd) {
if (!m->group_events && !m->modifier) {
- hashmap__for_each_entry(m->pctx->ids, cur, bkt) {
- dup = strdup(cur->pkey);
+ hashmap__for_each(m->pctx->ids, key, val) {
+ dup = strdup(key);
if (!dup) {
ret = -ENOMEM;
goto err_out;
--
2.56.1.703.gf848ed807c-goog
next prev parent reply other threads:[~2026-11-13 21:49 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 21:48 [PATCH v1 00/26] perf hashmap: Fix undefined behavior, remove ERR_PTR, and add type-safe generic hashmaps Ian Rogers
2026-11-13 21:48 ` [PATCH v1 01/26] perf threads: Fix uninitialized pointer put when thread removal misses Ian Rogers
2026-11-13 21:56 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 02/26] perf annotate: Fix sym_hist_entry memory leak when zeroing histograms Ian Rogers
2026-11-13 21:59 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 03/26] perf stat: Fix per_pkg_mask key leak on hashmap__add failure Ian Rogers
2026-11-13 21:55 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 04/26] perf build: Don't check difference of perf and libbpf hashmap Ian Rogers
2026-11-13 21:54 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 05/26] perf hashmap: Always build perf's hashmap and avoid libbpf symbol conflict Ian Rogers
2026-11-13 21:55 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 06/26] perf hashmap: Fix strict aliasing violations in hashmap Ian Rogers
2026-11-13 21:56 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 07/26] perf hashmap: Remove errptr usage from hashmap Ian Rogers
2026-11-13 22:01 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 08/26] perf hashmap: Introduce generic types and macros Ian Rogers
2026-11-13 22:01 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 09/26] perf fncache: Use generic hashmap for fncache Ian Rogers
2026-11-13 21:56 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 10/26] perf ftrace: Use generic hashmap for profile_hash Ian Rogers
2026-11-13 21:57 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 11/26] perf trace: Use generic hashmap for syscall_stats Ian Rogers
2026-11-13 22:04 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 12/26] perf trace: Use generic hashmap for bpf-trace-summary Ian Rogers
2026-11-13 21:58 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 13/26] perf lock: Use generic hashmap for slab_hash Ian Rogers
2026-11-13 21:57 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 14/26] perf stat: Use generic hashmap for per_pkg_mask Ian Rogers
2026-11-13 21:57 ` sashiko-bot
2026-11-13 21:48 ` Ian Rogers [this message]
2026-11-13 22:02 ` [PATCH v1 15/26] perf expr: Use generic hashmap for expr_ids sashiko-bot
2026-11-13 21:48 ` [PATCH v1 16/26] perf pmu: Use generic hashmap for pmu aliases Ian Rogers
2026-11-13 22:04 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 17/26] perf hwmon_pmu: Use generic hashmap for hwmon events Ian Rogers
2026-11-13 21:58 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 18/26] perf s390: Use generic hashmap for counter name cache Ian Rogers
2026-11-13 21:59 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 19/26] perf threads: Use generic hashmap for thread shards Ian Rogers
2026-11-13 22:01 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 20/26] perf annotate: Use generic hashmap for sym_samples Ian Rogers
2026-11-13 22:08 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 21/26] perf annotate: Use generic hashmap for browser type_hash Ian Rogers
2026-11-13 21:59 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 22/26] perf annotate-data: Use generic hashmap for type_hist samples Ian Rogers
2026-11-13 22:00 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 23/26] perf inject: Use generic hashmap for aslr remap_addresses Ian Rogers
2026-11-13 21:59 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 24/26] perf inject: Use generic hashmap for aslr top_addresses Ian Rogers
2026-11-13 21:59 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 25/26] perf inject: Use generic hashmap for aslr evsel_orig_attrs Ian Rogers
2026-11-13 22:00 ` sashiko-bot
2026-11-13 21:48 ` [PATCH v1 26/26] perf hashmap: Remove untyped struct hashmap API Ian Rogers
2026-11-13 22:01 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261113214850.3329699-16-irogers@google.com \
--to=irogers@google.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox