Re: [PATCH bpf-next v3 1/3] libbpf: hashmap interface update to long -> long

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 2022-11-07 at 16:46 -0800, Andrii Nakryiko wrote:
> On Sun, Nov 6, 2022 at 12:43 PM Alexei Starovoitov
> <alexei.starovoitov@xxxxxxxxx> wrote:
> > 
> > On Sun, Nov 6, 2022 at 12:29 PM Eduard Zingerman <eddyz87@xxxxxxxxx> wrote:
> > > 
> > > An update for libbpf's hashmap interface from void* -> void* to
> > > long -> long. Removes / simplifies some type casts when hashmap
> > > keys or values are 32-bit integers.
> > > 
> > > In libbpf hashmap is more often used with integral keys / values
> > > rather than with pointer keys / values.
> > > 
> > > Perf copies hashmap implementation from libbpf and has to be
> > > updated as well.
> > > 
> > > Changes to libbpf, selftests/bpf and perf are packed as a single
> > > commit to avoid compilation issues with any future bisect.
> > > 
> > > The net number of casts is decreased after this refactoring. Although
> > > perf mostly uses ptr to ptr maps, thus a lot of casts have to be
> > > added there:
> > > 
> > >              Casts    Casts
> > >              removed  added
> > > libbpf       ~50      ~20
> > > libbpf tests ~55      ~0
> > > perf         ~0       ~33
> > > perf tests   ~0       ~13
> > > 
> > > This is a follow up for [1].
> > > 
> > > [1] https://lore.kernel.org/bpf/af1facf9-7bc8-8a3d-0db4-7b3f333589a2@xxxxxxxx/T/#m65b28f1d6d969fcd318b556db6a3ad499a42607d
> > > 
> > > Signed-off-by: Eduard Zingerman <eddyz87@xxxxxxxxx>
> > > ---
> > >  tools/bpf/bpftool/btf.c                       |  25 ++---
> > >  tools/bpf/bpftool/common.c                    |  10 +-
> > >  tools/bpf/bpftool/gen.c                       |  19 ++--
> > >  tools/bpf/bpftool/link.c                      |   8 +-
> > >  tools/bpf/bpftool/main.h                      |  14 +--
> > >  tools/bpf/bpftool/map.c                       |   8 +-
> > >  tools/bpf/bpftool/pids.c                      |  16 +--
> > >  tools/bpf/bpftool/prog.c                      |   8 +-
> > >  tools/lib/bpf/btf.c                           |  41 ++++---
> > >  tools/lib/bpf/btf_dump.c                      |  16 +--
> > >  tools/lib/bpf/hashmap.c                       |  16 +--
> > >  tools/lib/bpf/hashmap.h                       |  34 +++---
> > >  tools/lib/bpf/libbpf.c                        |  18 ++--
> > >  tools/lib/bpf/strset.c                        |  18 ++--
> > >  tools/lib/bpf/usdt.c                          |  31 +++---
> > >  tools/perf/tests/expr.c                       |  40 +++----
> > >  tools/perf/tests/pmu-events.c                 |   6 +-
> > >  tools/perf/util/bpf-loader.c                  |  23 ++--
> > >  tools/perf/util/expr.c                        |  32 +++---
> > >  tools/perf/util/hashmap.c                     |  16 +--
> > >  tools/perf/util/hashmap.h                     |  34 +++---
> > >  tools/perf/util/metricgroup.c                 |  12 +--
> > >  tools/perf/util/stat.c                        |   9 +-
> > >  .../selftests/bpf/prog_tests/hashmap.c        | 102 +++++++++---------
> > >  .../bpf/prog_tests/kprobe_multi_test.c        |   6 +-
> > >  25 files changed, 257 insertions(+), 305 deletions(-)
> > 
> > Looks like the churn is not worth it.
> > I'd keep it as-is.
> 
> No-no, this is already a big win for libbpf/bpftool as is, but we can
> do even better for perf and some uses in selftest and libbpf itself.
> Given a hashmap can be used with a pointer or an integer as the
> key/value, we can use a bit of smartness (while keeping the safety)
> through simple macro wrapper for operations like hashmap__find and
> hashmap__insert (and co). That will avoid most of if not all casts for
> hashmap lookups/updates. And then for hashmap__for_each_entry and
> such, we can define hashmap_entry to have a union of long-based and
> void*-based key:
> 
> struct hashmap_entry {
>   union {
>     long key;
>     const void *pkey;
>   };
>   union {
>     long value;
>     void *pvalue;
>   };
>   ...
> }
> 
> I have it a try in few perf places, and it allows to avoid all the
> casts while thanks to that _Statis_assert we should be even safer than
> it was before. Eduard, please check the diff below and see if you can
> incorporate similar changes for other operations, if necessary.
> 

That's a nice hack, thank you. Everything works after interface
function / macro update. I need a bit more time to wrap up the
patch-set, will post it tomorrow.

> $ git diff
> diff --git a/tools/lib/bpf/hashmap.c b/tools/lib/bpf/hashmap.c
> index dfe99e766f30..0c1c1289a694 100644
> --- a/tools/lib/bpf/hashmap.c
> +++ b/tools/lib/bpf/hashmap.c
> @@ -203,7 +203,7 @@ int hashmap__insert(struct hashmap *map, long key,
> long value,
>         return 0;
>  }
> 
> -bool hashmap__find(const struct hashmap *map, long key, long *value)
> +bool hashmap_find(const struct hashmap *map, long key, long *value)
>  {
>         struct hashmap_entry *entry;
>         size_t h;
> diff --git a/tools/lib/bpf/hashmap.h b/tools/lib/bpf/hashmap.h
> index 7393ef616920..daec29012808 100644
> --- a/tools/lib/bpf/hashmap.h
> +++ b/tools/lib/bpf/hashmap.h
> @@ -47,8 +47,14 @@ typedef size_t (*hashmap_hash_fn)(long key, void *ctx);
>  typedef bool (*hashmap_equal_fn)(long key1, long key2, void *ctx);
> 
>  struct hashmap_entry {
> -       long key;
> -       long value;
> +       union {
> +               long key;
> +               const void *pkey;
> +       };
> +       union {
> +               long value;
> +               void *pvalue;
> +       };
>         struct hashmap_entry *next;
>  };
> 
> @@ -144,7 +150,13 @@ static inline int hashmap__append(struct hashmap
> *map, long key, long value)
> 
>  bool hashmap__delete(struct hashmap *map, long key, long *old_key,
> long *old_value);
> 
> -bool hashmap__find(const struct hashmap *map, long key, long *value);
> +bool hashmap_find(const struct hashmap *map, long key, long *value);
> +
> +#define hashmap__find(map, key, value) ({
>                          \
> +               _Static_assert(value == NULL || sizeof(*value) ==
> sizeof(long),                 \
> +                              "Value pointee should be a long-sized
> integer or a pointer");    \
> +               hashmap_find(map, (long)key, (long *)value);
>                          \
> +})
> 
>  /*
>   * hashmap__for_each_entry - iterate over all entries in hashmap
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 96092c9cb34b..1a1a76357f72 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -5669,7 +5669,7 @@ static int bpf_core_resolve_relo(struct bpf_program *prog,
>                 return -EINVAL;
> 
>         if (relo->kind != BPF_CORE_TYPE_ID_LOCAL &&
> -           !hashmap__find(cand_cache, local_id, (long *)&cands)) {
> +           !hashmap__find(cand_cache, local_id, &cands)) {
>                 cands = bpf_core_find_cands(prog->obj, local_btf, local_id);
>                 if (IS_ERR(cands)) {
>                         pr_warn("prog '%s': relo #%d: target candidate
> search failed for [%d] %s %s: %ld\n",
> diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c
> index 8107ed0428c2..cb206003c1f0 100644
> --- a/tools/perf/tests/expr.c
> +++ b/tools/perf/tests/expr.c
> @@ -130,12 +130,9 @@ static int test__expr(struct test_suite *t
> __maybe_unused, int subtest __maybe_u
>                         expr__find_ids("FOO + BAR + BAZ + BOZO", "FOO",
>                                         ctx) == 0);
>         TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 3);
> -       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, (long)"BAR",
> -                                                 (long *)&val_ptr));
> -       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, (long)"BAZ",
> -                                                 (long *)&val_ptr));
> -       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, (long)"BOZO",
> -                                                 (long *)&val_ptr));
> +       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
> (long)"BAR", &val_ptr));
> +       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
> (long)"BAZ", &val_ptr));
> +       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
> (long)"BOZO", &val_ptr));
> 
>         expr__ctx_clear(ctx);
>         ctx->sctx.runtime = 3;
> @@ -143,20 +140,16 @@ static int test__expr(struct test_suite *t
> __maybe_unused, int subtest __maybe_u
>                         expr__find_ids("EVENT1\\,param\\=?@ +
> EVENT2\\,param\\=?@",
>                                         NULL, ctx) == 0);
>         TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 2);
> -       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
> (long)"EVENT1,param=3@",
> -                                                 (long *)&val_ptr));
> -       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
> (long)"EVENT2,param=3@",
> -                                                 (long *)&val_ptr));
> +       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
> (long)"EVENT1,param=3@", &val_ptr));
> +       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
> (long)"EVENT2,param=3@", &val_ptr));
> 
>         expr__ctx_clear(ctx);
>         TEST_ASSERT_VAL("find ids",
>                         expr__find_ids("dash\\-event1 - dash\\-event2",
>                                        NULL, ctx) == 0);
>         TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 2);
> -       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, (long)"dash-event1",
> -                                                 (long *)&val_ptr));
> -       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, (long)"dash-event2",
> -                                                 (long *)&val_ptr));
> +       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
> (long)"dash-event1", &val_ptr));
> +       TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
> (long)"dash-event2", &val_ptr));
> 
>         /* Only EVENT1 or EVENT2 need be measured depending on the
> value of smt_on. */
>         {
> @@ -174,7 +167,7 @@ static int test__expr(struct test_suite *t
> __maybe_unused, int subtest __maybe_u
>                 TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 1);
>                 TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
>                                                           (long)(smton
> ? "EVENT1" : "EVENT2"),
> -                                                         (long *)&val_ptr));
> +                                                         &val_ptr));
> 
>                 expr__ctx_clear(ctx);
>                 TEST_ASSERT_VAL("find ids",
> @@ -183,7 +176,7 @@ static int test__expr(struct test_suite *t
> __maybe_unused, int subtest __maybe_u
>                 TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 1);
>                 TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
> 
> (long)(corewide ? "EVENT1" : "EVENT2"),
> -                                                         (long *)&val_ptr));
> +                                                         &val_ptr));
> 
>         }
>         /* The expression is a constant 1.0 without needing to
> evaluate EVENT1. */
> @@ -220,8 +213,7 @@ static int test__expr(struct test_suite *t
> __maybe_unused, int subtest __maybe_u
>                         expr__find_ids("source_count(EVENT1)",
>                         NULL, ctx) == 0);
>         TEST_ASSERT_VAL("source count", hashmap__size(ctx->ids) == 1);
> -       TEST_ASSERT_VAL("source count", hashmap__find(ctx->ids, (long)"EVENT1",
> -                                                     (long *)&val_ptr));
> +       TEST_ASSERT_VAL("source count", hashmap__find(ctx->ids,
> (long)"EVENT1", &val_ptr));
> 
>         expr__ctx_free(ctx);
> 
> diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
> index 55f114450316..2430b8965268 100644
> --- a/tools/perf/util/bpf-loader.c
> +++ b/tools/perf/util/bpf-loader.c
> @@ -131,7 +131,7 @@ static void *program_priv(const struct bpf_program *prog)
> 
>         if (IS_ERR_OR_NULL(bpf_program_hash))
>                 return NULL;
> -       if (!hashmap__find(bpf_program_hash, (long)prog, (long *)&priv))
> +       if (!hashmap__find(bpf_program_hash, prog, &priv))
>                 return NULL;
>         return priv;
>  }
> @@ -1170,7 +1170,7 @@ static void *map_priv(const struct bpf_map *map)
> 
>         if (IS_ERR_OR_NULL(bpf_map_hash))
>                 return NULL;
> -       if (!hashmap__find(bpf_map_hash, (long)map, (long *)&priv))
> +       if (!hashmap__find(bpf_map_hash, map, &priv))
>                 return NULL;
>         return priv;
>  }
> @@ -1184,7 +1184,7 @@ static void bpf_map_hash_free(void)
>                 return;
> 
>         hashmap__for_each_entry(bpf_map_hash, cur, bkt)
> -               bpf_map_priv__clear((struct bpf_map *)cur->key, (void
> *)cur->value);
> +               bpf_map_priv__clear(cur->pkey, cur->pvalue);
> 
>         hashmap__free(bpf_map_hash);
>         bpf_map_hash = NULL;
> diff --git a/tools/perf/util/hashmap.c b/tools/perf/util/hashmap.c
> index dfe99e766f30..0c1c1289a694 100644
> --- a/tools/perf/util/hashmap.c
> +++ b/tools/perf/util/hashmap.c
> @@ -203,7 +203,7 @@ int hashmap__insert(struct hashmap *map, long key,
> long value,
>         return 0;
>  }
> 
> -bool hashmap__find(const struct hashmap *map, long key, long *value)
> +bool hashmap_find(const struct hashmap *map, long key, long *value)
>  {
>         struct hashmap_entry *entry;
>         size_t h;
> diff --git a/tools/perf/util/hashmap.h b/tools/perf/util/hashmap.h
> index 7393ef616920..edbadb712725 100644
> --- a/tools/perf/util/hashmap.h
> +++ b/tools/perf/util/hashmap.h
> @@ -47,8 +47,14 @@ typedef size_t (*hashmap_hash_fn)(long key, void *ctx);
>  typedef bool (*hashmap_equal_fn)(long key1, long key2, void *ctx);
> 
>  struct hashmap_entry {
> -       long key;
> -       long value;
> +       union {
> +               long key;
> +               const void *pkey;
> +       };
> +       union {
> +               long value;
> +               void *pvalue;
> +       };
>         struct hashmap_entry *next;
>  };
> 
> @@ -144,7 +150,13 @@ static inline int hashmap__append(struct hashmap
> *map, long key, long value)
> 
>  bool hashmap__delete(struct hashmap *map, long key, long *old_key,
> long *old_value);
> 
> -bool hashmap__find(const struct hashmap *map, long key, long *value);
> +bool hashmap_find(const struct hashmap *map, long key, long *value);
> +
> +#define hashmap__find(map, key, value) ({
>                          \
> +               _Static_assert(sizeof(*value) == sizeof(long),
>                          \
> +                              "Value pointee should be a long-sized
> integer or a pointer");    \
> +               hashmap_find(map, (long)key, (long *)value);
>                          \
> +})
> 
>  /*
>   * hashmap__for_each_entry - iterate over all entries in hashmap
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index e9bd881c6912..2059ed3164ae 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -288,7 +288,7 @@ static int setup_metric_events(struct hashmap *ids,
>                  * combined or shared groups, this metric may not care
>                  * about this event.
>                  */
> -               if (hashmap__find(ids, (long)metric_id, (long *)&val_ptr)) {
> +               if (hashmap__find(ids, metric_id, &val_ptr)) {
>                         metric_events[matched_events++] = ev;
> 
>                         if (matched_events >= ids_size)
> 11/07 16:45:42.699 andriin@devbig019:~/linux/tools/lib/bpf (master)
> $





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux