mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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
> 

  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®