From 5f549d9b49868648f0fb152aa12084dcb859ee45 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Jan 2022 10:11:49 +1100 Subject: [PATCH 1/2] Modify the buffer position directly when reading leb128 values. It's a small but clear performance win. --- compiler/rustc_serialize/src/leb128.rs | 18 ++++++++---------- compiler/rustc_serialize/src/opaque.rs | 6 +----- compiler/rustc_serialize/tests/leb128.rs | 6 ++---- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs index ea2df80e64168..de3337747632e 100644 --- a/compiler/rustc_serialize/src/leb128.rs +++ b/compiler/rustc_serialize/src/leb128.rs @@ -53,16 +53,15 @@ impl_write_unsigned_leb128!(write_usize_leb128, usize); macro_rules! impl_read_unsigned_leb128 { ($fn_name:ident, $int_ty:ty) => { #[inline] - pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) { + pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty { let mut result = 0; let mut shift = 0; - let mut position = 0; loop { - let byte = slice[position]; - position += 1; + let byte = slice[*position]; + *position += 1; if (byte & 0x80) == 0 { result |= (byte as $int_ty) << shift; - return (result, position); + return result; } else { result |= ((byte & 0x7F) as $int_ty) << shift; } @@ -122,15 +121,14 @@ impl_write_signed_leb128!(write_isize_leb128, isize); macro_rules! impl_read_signed_leb128 { ($fn_name:ident, $int_ty:ty) => { #[inline] - pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) { + pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty { let mut result = 0; let mut shift = 0; - let mut position = 0; let mut byte; loop { - byte = slice[position]; - position += 1; + byte = slice[*position]; + *position += 1; result |= <$int_ty>::from(byte & 0x7F) << shift; shift += 7; @@ -144,7 +142,7 @@ macro_rules! impl_read_signed_leb128 { result |= (!0 << shift); } - (result, position) + result } }; } diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index cc1216418ae79..3d28e3293e189 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -559,11 +559,7 @@ impl<'a> Decoder<'a> { } macro_rules! read_leb128 { - ($dec:expr, $fun:ident) => {{ - let (value, bytes_read) = leb128::$fun(&$dec.data[$dec.position..]); - $dec.position += bytes_read; - Ok(value) - }}; + ($dec:expr, $fun:ident) => {{ Ok(leb128::$fun($dec.data, &mut $dec.position)) }}; } impl<'a> serialize::Decoder for Decoder<'a> { diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs index 3e2aab5125ab7..314c07db981da 100644 --- a/compiler/rustc_serialize/tests/leb128.rs +++ b/compiler/rustc_serialize/tests/leb128.rs @@ -30,9 +30,8 @@ macro_rules! impl_test_unsigned_leb128 { let mut position = 0; for &expected in &values { - let (actual, bytes_read) = $read_fn_name(&stream[position..]); + let actual = $read_fn_name(&stream, &mut position); assert_eq!(expected, actual); - position += bytes_read; } assert_eq!(stream.len(), position); } @@ -77,9 +76,8 @@ macro_rules! impl_test_signed_leb128 { let mut position = 0; for &expected in &values { - let (actual, bytes_read) = $read_fn_name(&stream[position..]); + let actual = $read_fn_name(&stream, &mut position); assert_eq!(expected, actual); - position += bytes_read; } assert_eq!(stream.len(), position); } From facba24926e218f996a953b0d91494a04374b217 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Jan 2022 11:50:52 +1100 Subject: [PATCH 2/2] Unpeel the first iteration of the loop in impl_read_unsigned_leb128. --- compiler/rustc_serialize/src/leb128.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs index de3337747632e..08b3c054200b7 100644 --- a/compiler/rustc_serialize/src/leb128.rs +++ b/compiler/rustc_serialize/src/leb128.rs @@ -54,8 +54,17 @@ macro_rules! impl_read_unsigned_leb128 { ($fn_name:ident, $int_ty:ty) => { #[inline] pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty { - let mut result = 0; - let mut shift = 0; + // The first iteration of this loop is unpeeled. This is a + // performance win because this code is hot and integer values less + // than 128 are very common, typically occurring 50-80% or more of + // the time, even for u64 and u128. + let byte = slice[*position]; + *position += 1; + if (byte & 0x80) == 0 { + return byte as $int_ty; + } + let mut result = (byte & 0x7F) as $int_ty; + let mut shift = 7; loop { let byte = slice[*position]; *position += 1;