From 9d1978e66160915abe3a9f7f00cfd776ccc3fdc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20M=C3=BCller?= Date: Fri, 27 Dec 2024 10:36:49 -0800 Subject: [PATCH] Add benchmark for ELF "str2symtab" creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a benchmark for the creation of our ELF "str2symtab". This creation should trigger a good chunk of our data structure traversing and "parsing" paths. The performance is roughly as follows: $ cargo bench --features=nightly -- bench_str2sym_creation > test elf::parser::tests::bench_str2sym_creation ... bench: 26,023,493.50 ns/iter (+/- 644,362.62) The main reason for the addition of the benchmark is to get an idea how much performance we lost due to recent ELF parser changes: both the introduction of 32 bit support as well as the logic for working with different backends is assumed to have some runtime impact. Backporting the benchmark on top of commit 4688aa06bd5a ("cli: Rework tracing output") results in the following performance numbers before said ELF changes: $ cargo bench --features=nightly -- bench_str2sym_creation > test elf::parser::tests::bench_str2sym_creation ... bench: 25,233,120.60 ns/iter (+/- 496,742.81) The difference is reproducible, but arguably small and acceptable. We may be able to speed things up a bit more via the usage of smaller indexes. Signed-off-by: Daniel Müller --- src/elf/parser.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/elf/parser.rs b/src/elf/parser.rs index 6e479d2a..900daa30 100644 --- a/src/elf/parser.rs +++ b/src/elf/parser.rs @@ -1249,6 +1249,8 @@ mod tests { use std::env; use std::env::current_exe; + #[cfg(feature = "nightly")] + use std::hint::black_box; use std::io::Write as _; use std::mem::size_of; use std::slice; @@ -1257,6 +1259,9 @@ mod tests { use test_log::test; + #[cfg(feature = "nightly")] + use test::Bencher; + /// Exercise the `Debug` representation of various types. #[test] @@ -1820,4 +1825,30 @@ mod tests { let symtab = cache.ensure_symtab().unwrap(); assert!(symtab.is_empty()); } + + /// Benchmark creation of our "str2symtab" table. + /// + /// Creating this table exercises a lot of the parser code paths and + /// is expected to be a somewhat reasonable approximation of overall + /// end-to-end performance. + #[cfg(feature = "nightly")] + #[bench] + fn bench_str2sym_creation(b: &mut Bencher) { + let path = Path::new(&env!("CARGO_MANIFEST_DIR")) + .join("data") + .join("vmlinux-5.17.12-100.fc34.x86_64.elf"); + let parser = ElfParser::open(&path).unwrap(); + let mmap = &parser._backend; + + // Our memory mapping is created only once and criterion does a + // few warm up runs that should make sure that everything is + // paged in. So we expect to benchmark parsing & data structure + // traversing performance here. + + let () = b.iter(|| { + let cache = Cache::new(mmap.deref()); + let syms = cache.ensure_str2symtab().unwrap(); + let _syms = black_box(syms); + }); + } }