From 4ff015722bbebc845eb2e5a735e6e8b2eabd2457 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 17 Jul 2024 20:27:51 +0200 Subject: [PATCH] Speed up parse_header of the binary IndexData MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The change makes a measurable performance gain for debuginfod-rs: ``` Before: Time (mean ± σ): 2.322 s ± 0.042 s [User: 25.047 s, System: 4.994 s] After: Time (mean ± σ): 2.269 s ± 0.023 s [User: 24.264 s, System: 5.174 s] 1.02 ± 0.02 times faster than debuginfod-rs-before ``` --- src/rpm/headers/header.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/rpm/headers/header.rs b/src/rpm/headers/header.rs index d1fbfd6..fd7c509 100644 --- a/src/rpm/headers/header.rs +++ b/src/rpm/headers/header.rs @@ -54,13 +54,14 @@ where // add data to entries for entry in &mut entries { let mut remaining = &bytes[entry.offset as usize..]; + match &mut entry.data { IndexData::Null => {} IndexData::Char(ref mut chars) => { - parse_entry_data_number(remaining, entry.num_items, chars, be_u8)?; + parse_binary_entry(remaining, entry.num_items, chars, "Char")?; } IndexData::Int8(ref mut ints) => { - parse_entry_data_number(remaining, entry.num_items, ints, be_u8)?; + parse_binary_entry(remaining, entry.num_items, ints, "Int8")?; } IndexData::Int16(ref mut ints) => { parse_entry_data_number(remaining, entry.num_items, ints, be_u16)?; @@ -76,7 +77,7 @@ where string.push_str(String::from_utf8_lossy(raw_string).as_ref()); } IndexData::Bin(ref mut bin) => { - parse_entry_data_number(remaining, entry.num_items, bin, be_u8)?; + parse_binary_entry(remaining, entry.num_items, bin, "Bin")?; } IndexData::StringArray(ref mut strings) => { for _ in 0..entry.num_items { @@ -480,6 +481,7 @@ where E: nom::error::ParseError<&'a [u8]>, F: Fn(&'a [u8]) -> nom::IResult<&'a [u8], T, E>, { + items.reserve_exact(num_items as usize); for _ in 0..num_items { let (rest, data) = parser(input)?; items.push(data); @@ -489,6 +491,22 @@ where Ok((input, ())) } +fn parse_binary_entry( + input: &[u8], + num_items: u32, + items: &mut Vec, + bin_type: &str, +) -> Result<(), Error> { + let bin_bytes = input.get(..num_items as usize).ok_or_else(|| { + Error::Nom(format!( + "Insufficient bytes for IndexData::{} entry", + bin_type + )) + })?; + items.extend_from_slice(bin_bytes); + Ok(()) +} + /// A header keeping track of all other header records. #[derive(Debug, PartialEq)] pub(crate) struct IndexHeader {