From: Namhyung Kim <namhyung@kernel.org>
To: Ian Rogers <irogers@google.com>
Cc: acme@kernel.org, adrian.hunter@intel.com, haghdoost@uber.com,
james.clark@linaro.org, jolsa@kernel.org,
linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org,
mingo@redhat.com, peterz@infradead.org
Subject: Re: [PATCH v2 01/18] perf bench internals: Add symbols and maps benchmarks
Date: Sat, 31 Oct 2026 19:48:49 -0700 [thread overview]
Message-ID: <auaokSIk3deCgp-D@z2> (raw)
In-Reply-To: <20261027231513.816148-2-irogers@google.com>
On Tue, Oct 27, 2026 at 04:14:55PM -0700, Ian Rogers wrote:
> Add two new 'perf bench internals' subcommands to measure symbol and map
> operations directly:
>
> - 'perf bench internals symbols':
> 1. Loads symbols from an ELF binary (defaulting to the running perf
> executable, or specified via -b/--binary) and sorts them by name,
> reporting both average runtime and heap memory consumption.
> 2. Inserts synthetic symbols in two ascending runs (simulating .symtab
> and .dynsym), fixes up symbol ends and duplicates, and queries each
> symbol by address.
> 3. Incrementally appends symbols at interior addresses and immediately
> queries each appended symbol by address.
>
> - 'perf bench internals maps':
> 1. Inserts non-overlapping maps in ascending address order (simulating
> /proc/<pid>/maps synthesis) and queries each map by address.
> 2. Incrementally appends maps at interior addresses (simulating runtime
> PERF_RECORD_MMAP2 / JIT events) and immediately queries each map by
> address and by name.
Can you please add an example output?
>
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
[SNIP]
> diff --git a/tools/perf/bench/symbols.c b/tools/perf/bench/symbols.c
> new file mode 100644
> index 000000000000..5ab71d440e67
> --- /dev/null
> +++ b/tools/perf/bench/symbols.c
> @@ -0,0 +1,236 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Benchmark symbol loading, sorting, and address/name lookup.
> + */
> +#include <elf.h>
> +#include <errno.h>
> +#include <inttypes.h>
> +#include <limits.h>
> +#include <malloc.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/time.h>
> +#include <linux/compiler.h>
> +#include <linux/kernel.h>
> +#include <linux/time64.h>
> +#include <subcmd/parse-options.h>
> +#include "bench.h"
> +#include "../util/debug.h"
> +#include "../util/dso.h"
> +#include "../util/map.h"
> +#include "../util/stat.h"
> +#include "../util/symbol.h"
> +#include "../util/util.h"
> +
> +static unsigned int iterations = 20;
> +static unsigned int nr_symbols = 10000;
> +static unsigned int nr_appends = 200;
> +static const char *binary_path;
> +static bool no_demangle;
> +
> +static const struct option options[] = {
> + OPT_UINTEGER('i', "iterations", &iterations,
> + "Number of iterations used to compute average (default: 20)"),
> + OPT_STRING('b', "binary", &binary_path, "path",
> + "Binary path for ELF symbol load benchmark (default: perf binary)"),
> + OPT_UINTEGER('n', "nr-symbols", &nr_symbols,
> + "Number of synthetic symbols for bulk benchmark (default: 10000)"),
> + OPT_UINTEGER('a', "nr-appends", &nr_appends,
> + "Number of incremental symbol appends per iteration (default: 200)"),
> + OPT_BOOLEAN(0, "no-demangle", &no_demangle,
> + "Disable symbol demangling during ELF load"),
> + OPT_END()
> +};
> +
> +static const char *const bench_usage[] = {
> + "perf bench internals symbols <options>",
> + NULL
> +};
> +
> +static int do_dso_load_bench(const char *path)
> +{
> + struct stats time_stats;
> +#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 33)
> + struct stats mem_stats;
> +#endif
> + double time_average, time_stddev;
> + unsigned int i;
> +
> + init_stats(&time_stats);
> +#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 33)
> + init_stats(&mem_stats);
> +#endif
> +
> + for (i = 0; i < iterations; i++) {
> + struct timeval start, end, diff;
> + struct map *map;
> + struct dso *dso;
> + u64 runtime_us;
> +#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 33)
> + size_t mem_before = mallinfo2().uordblks;
> + size_t mem_after;
> +#endif
Can we just use maxrss from getrusage()? It doesn't need to be average,
probably we just want to know the maximum memory usage.
> +
> + gettimeofday(&start, NULL);
> + map = dso__new_map(path);
> + if (!map) {
> + pr_err("Failed to create map for %s\n", path);
> + return -ENOMEM;
> + }
> + if (map__load(map) < 0) {
> + pr_err("Failed to load symbols from %s\n", path);
> + map__put(map);
> + return -EINVAL;
> + }
> + dso = map__dso(map);
> + dso__sort_by_name(dso);
Probably better to have a separate test not to use symbol names. As we
expect to have lazy symbol loading soon.
Thanks,
Namhyung
> + gettimeofday(&end, NULL);
> +
> +#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 33)
> + mem_after = mallinfo2().uordblks;
> + if (mem_after > mem_before)
> + update_stats(&mem_stats, (mem_after - mem_before) / 1024);
> +#endif
> + map__put(map);
> +
> + timersub(&end, &start, &diff);
> + runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec;
> + update_stats(&time_stats, runtime_us);
> + }
> +
> + time_average = avg_stats(&time_stats) / USEC_PER_MSEC;
> + time_stddev = stddev_stats(&time_stats) / USEC_PER_MSEC;
> + printf(" Average DSO load + sort: %.3f msec (+- %.3f msec)\n",
> + time_average, time_stddev);
> +
> +#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 33)
> + printf(" Average DSO memory usage: %.0f KB (+- %.0f KB)\n",
> + avg_stats(&mem_stats), stddev_stats(&mem_stats));
> +#endif
> + return 0;
> +}
> +
> +static int do_synthetic_symbols_bench(void)
> +{
> + struct stats bulk_stats, append_stats;
> + unsigned int i, j, half = nr_symbols / 2;
> +
> + if (half == 0)
> + return 0;
> +
> + init_stats(&bulk_stats);
> + init_stats(&append_stats);
> +
> + for (i = 0; i < iterations; i++) {
> + struct timeval start, end, diff;
> + struct dso *dso = dso__new("[bench_symbols]");
> + u64 runtime_us;
> + char name[32];
> +
> + if (!dso)
> + return -ENOMEM;
> +
> + /*
> + * Phase 1: Insert symbols in two ascending runs (simulating
> + * .symtab + .dynsym), fixup ends and duplicates, and look up
> + * all symbols by address.
> + */
> + gettimeofday(&start, NULL);
> + for (j = 0; j < nr_symbols; j++) {
> + u64 addr = (j < half) ?
> + (0x100000ULL + (u64)j * 0x40ULL) :
> + (0x100020ULL + (u64)(j - half) * 0x40ULL);
> + struct symbol *sym;
> +
> + scnprintf(name, sizeof(name), "bench_sym_%06u", j);
> + sym = symbol__new(addr, 0x18, STB_GLOBAL, STT_FUNC, name);
> + if (!sym) {
> + dso__put(dso);
> + return -ENOMEM;
> + }
> + symbols__insert(dso__symbols(dso), sym);
> + }
> + symbols__fixup_end(dso__symbols(dso), false);
> + symbols__fixup_duplicate(dso__symbols(dso));
> +
> + for (j = 0; j < nr_symbols; j++) {
> + u64 addr = (j < half) ?
> + (0x100000ULL + (u64)j * 0x40ULL + 4) :
> + (0x100020ULL + (u64)(j - half) * 0x40ULL + 4);
> +
> + (void)dso__find_symbol_nocache(dso, addr);
> + }
> + gettimeofday(&end, NULL);
> + timersub(&end, &start, &diff);
> + runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec;
> + update_stats(&bulk_stats, runtime_us);
> +
> + /*
> + * Phase 2: Incrementally append one symbol at a time at an
> + * interior address and immediately query by address.
> + */
> + gettimeofday(&start, NULL);
> + for (j = 0; j < nr_appends; j++) {
> + u64 addr = 0x100010ULL + ((u64)(j * 197 % half)) * 0x40ULL;
> + struct symbol *sym;
> +
> + scnprintf(name, sizeof(name), "jit_sym_%06u", j);
> + sym = symbol__new(addr, 0x08, STB_GLOBAL, STT_FUNC, name);
> + if (!sym) {
> + dso__put(dso);
> + return -ENOMEM;
> + }
> + dso__insert_symbol(dso, sym);
> + (void)dso__find_symbol_nocache(dso, addr + 2);
> + }
> + gettimeofday(&end, NULL);
> + timersub(&end, &start, &diff);
> + runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec;
> + update_stats(&append_stats, runtime_us);
> +
> + dso__put(dso);
> + }
> +
> + printf(" Average bulk insert + lookup: %.3f usec (+- %.3f usec)\n",
> + avg_stats(&bulk_stats), stddev_stats(&bulk_stats));
> + printf(" Average append + lookup: %.3f usec (+- %.3f usec)\n",
> + avg_stats(&append_stats), stddev_stats(&append_stats));
> + return 0;
> +}
> +
> +int bench_symbols(int argc, const char **argv)
> +{
> + char exe_buf[PATH_MAX];
> + const char *path;
> + bool orig_demangle;
> + int err;
> +
> + argc = parse_options(argc, argv, options, bench_usage, 0);
> + if (argc) {
> + usage_with_options(bench_usage, options);
> + exit(EXIT_FAILURE);
> + }
> +
> + if (symbol__init(NULL) < 0)
> + return -1;
> +
> + orig_demangle = symbol_conf.demangle;
> + if (no_demangle)
> + symbol_conf.demangle = false;
> +
> + if (binary_path) {
> + path = binary_path;
> + } else {
> + perf_exe(exe_buf, sizeof(exe_buf));
> + path = exe_buf;
> + }
> +
> + err = do_dso_load_bench(path);
> + if (!err)
> + err = do_synthetic_symbols_bench();
> +
> + symbol_conf.demangle = orig_demangle;
> + return err;
> +}
> diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
> index 62bebdedd3b8..57a4199a058c 100644
> --- a/tools/perf/builtin-bench.c
> +++ b/tools/perf/builtin-bench.c
> @@ -97,6 +97,8 @@ static const struct bench internals_benchmarks[] = {
> { "inject-build-id", "Benchmark build-id injection", bench_inject_build_id },
> { "evlist-open-close", "Benchmark evlist open and close", bench_evlist_open_close },
> { "pmu-scan", "Benchmark sysfs PMU info scanning", bench_pmu_scan },
> + { "symbols", "Benchmark symbol loading, sorting and lookup", bench_symbols },
> + { "maps", "Benchmark maps insertion, sorting and lookup", bench_maps },
> { NULL, NULL, NULL }
> };
>
> --
> 2.56.0.313.g2479322e68-goog
>
next prev parent reply other threads:[~2026-11-01 2:48 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-28 7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
2026-09-28 7:52 ` [PATCH v1 1/7] perf symbol: Add accessor functions for struct symbol fields Ian Rogers
2026-09-28 7:52 ` [PATCH v1 2/7] perf symbol: Remove symbol_conf.priv_size and negative-offset allocations Ian Rogers
2026-09-28 7:52 ` [PATCH v1 3/7] perf symbol: Switch backing storage from rbtree to struct symbols array Ian Rogers
2026-09-28 7:52 ` [PATCH v1 4/7] perf symbol: Add reference counting and DECLARE_RC_STRUCT(symbol) Ian Rogers
2026-09-28 7:52 ` [PATCH v1 5/7] perf symbol: Add LRU memory shrinking for symbols, DSOs, and machines Ian Rogers
2026-09-28 7:52 ` [PATCH v1 6/7] perf session: Periodically shrink symbols and DSOs during event processing Ian Rogers
2026-09-28 7:52 ` [PATCH v1 7/7] perf test symbols: Add tests for symbol and DSO LRU shrinking Ian Rogers
2026-09-28 15:37 ` [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and " Ian Rogers
2026-09-28 19:45 ` Alireza Haghdoost
2026-09-28 20:55 ` Ian Rogers
2026-09-28 21:51 ` Namhyung Kim
2026-09-28 22:04 ` Ian Rogers
2026-09-29 0:12 ` Alireza Haghdoost
2026-09-29 18:09 ` Namhyung Kim
2026-09-29 21:24 ` Alireza Haghdoost
2026-09-29 18:06 ` Namhyung Kim
2026-10-27 23:14 ` [PATCH v2 00/18] perf symbol: Reference counting, sorted arrays, and memory shrinking Ian Rogers
2026-10-27 23:14 ` [PATCH v2 01/18] perf bench internals: Add symbols and maps benchmarks Ian Rogers
2026-10-29 19:46 ` Alireza Haghdoost
2026-11-01 2:48 ` Namhyung Kim [this message]
2026-10-27 23:14 ` [PATCH v2 02/18] perf demangle: Add fast-path prefix checks for Rust and Java demanglers Ian Rogers
2026-10-27 23:14 ` [PATCH v2 03/18] perf symbol: Add accessor functions for struct symbol fields Ian Rogers
2026-10-30 4:08 ` Alireza Haghdoost
2026-10-27 23:14 ` [PATCH v2 04/18] perf map_browser: Compute symbol browser index on demand Ian Rogers
2026-10-27 23:14 ` [PATCH v2 05/18] perf db-export: Store symbol database IDs in a hashmap Ian Rogers
2026-10-27 23:15 ` [PATCH v2 06/18] perf annotate: Move struct annotation to a hashmap and remove symbol_conf.priv_size Ian Rogers
2026-10-30 12:51 ` Alireza Haghdoost
2026-10-27 23:15 ` [PATCH v2 07/18] perf symbol: Switch backing storage from rbtree to struct symbols array Ian Rogers
2026-10-30 13:12 ` Alireza Haghdoost
2026-10-27 23:15 ` [PATCH v2 08/18] perf symbol: Add reference counting and DECLARE_RC_STRUCT(symbol) Ian Rogers
2026-10-30 13:22 ` Alireza Haghdoost
2026-10-27 23:15 ` [PATCH v2 09/18] perf symbol: Optimize symbol sorting with natural-run merge sort and binary insertion Ian Rogers
2026-10-30 13:27 ` Alireza Haghdoost
2026-10-27 23:15 ` [PATCH v2 10/18] perf maps: Optimize tail insertion and small-append sorting Ian Rogers
2026-10-27 23:15 ` [PATCH v2 11/18] perf symbol-elf: Cache ELF program/section headers and defer symbol name lookup Ian Rogers
2026-10-30 13:32 ` Alireza Haghdoost
2026-10-27 23:15 ` [PATCH v2 12/18] perf rwsem: Add down_read_trylock() and down_write_trylock() Ian Rogers
2026-10-30 13:39 ` Alireza Haghdoost
2026-10-27 23:15 ` [PATCH v2 13/18] perf vdso: Constify dso parameter in dso__is_vdso() Ian Rogers
2026-10-27 23:15 ` [PATCH v2 14/18] perf machine: Protect machines->guests rbtree with a rw_semaphore Ian Rogers
2026-10-27 23:15 ` [PATCH v2 15/18] perf symbol: Add memory shrinking for symbols, DSOs, and machines Ian Rogers
2026-10-30 13:53 ` Alireza Haghdoost
2026-10-27 23:15 ` [PATCH v2 16/18] perf session: Add dso__session() and session-scoped allocation wrappers Ian Rogers
2026-10-27 23:15 ` [PATCH v2 17/18] perf symbol: Use session allocation wrappers in symbol, DSO, thread, and hist paths Ian Rogers
2026-10-27 23:15 ` [PATCH v2 18/18] perf test symbols: Add tests for symbol shrinking and session alloc wrappers Ian Rogers
2026-10-30 13:55 ` Alireza Haghdoost
2026-10-28 20:29 ` [PATCH v2 00/18] perf symbol: Reference counting, sorted arrays, and memory shrinking Ian Rogers
2026-10-30 14:02 ` Alireza Haghdoost
2026-10-30 16:10 ` Ian Rogers
2026-10-30 17:57 ` Ian Rogers
2026-10-31 17:22 ` David Laight
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=auaokSIk3deCgp-D@z2 \
--to=namhyung@kernel.org \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=haghdoost@uber.com \
--cc=irogers@google.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=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
all inboxes | Powered by JetHome®