diff --git a/fuel-vm/benches/meq_performance.rs b/fuel-vm/benches/meq_performance.rs index c744f9765e..9ed2d54621 100644 --- a/fuel-vm/benches/meq_performance.rs +++ b/fuel-vm/benches/meq_performance.rs @@ -47,6 +47,9 @@ fn meq_performance(c: &mut Criterion) { let benchmark_matrix = [ 1, 10, 100, 1000, 10_000, 50_000, 100_000, 500_000, 1_000_000, 2_000_000, 2_500_000, 5_000_000, 10_000_000, 15_000_000, 20_000_000, + // some exact multiples of 8 to verify alignment perf + 8, 16, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, + 262144, 524288, 1048576, 2097152, 4194304, 8388608, ]; for size in benchmark_matrix.iter() { diff --git a/fuel-vm/src/interpreter/memory.rs b/fuel-vm/src/interpreter/memory.rs index d997313d85..fe83450a53 100644 --- a/fuel-vm/src/interpreter/memory.rs +++ b/fuel-vm/src/interpreter/memory.rs @@ -1,7 +1,11 @@ #![cfg(feature = "alloc")] #[cfg(feature = "experimental")] -use core::simd::{u8x16, u8x32, u8x64}; +use core::simd::{ + u8x16, + u8x32, + u8x64, +}; use super::{ internal::inc_pc, @@ -1040,76 +1044,44 @@ fn slice_eq(a: &[u8], b: &[u8]) -> bool { return false; } - enum SimdVariant { - U8x16, - U8x32, - U8x64, - } + // cascade of SIMD comparisons + let len = a.len(); + let mut i = 0; - impl SimdVariant { - fn chunk_size(&self) -> usize{ - match &self { - SimdVariant::U8x16 => 16, - SimdVariant::U8x32 => 32, - SimdVariant::U8x64 => 64, - } + while i + 64 <= len { + let simd_a = u8x64::from_slice(&a[i..]); + let simd_b = u8x64::from_slice(&b[i..]); + if simd_a != simd_b { + return false; } } - // we check if the number of bytes is divisible by 16, 32, 64. - // we choose the largest number that has the smallest remainder - - let remainder_16 = a.len() % 16; - let remainder_32 = a.len() % 32; - let remainder_64 = a.len() % 64; - - // based on the smallest remainder, we then use the appropriate simd instruction - // to compare the slices - let variant = if remainder_16 < remainder_32 { - if remainder_16 < remainder_64 { - SimdVariant::U8x16 - } else { - SimdVariant::U8x64 + while i + 32 <= len { + let simd_a = u8x32::from_slice(&a[i..]); + let simd_b = u8x32::from_slice(&b[i..]); + if simd_a != simd_b { + return false; } - } else { - if remainder_32 < remainder_64 { - SimdVariant::U8x32 - } else { - SimdVariant::U8x64 + } + + while i + 16 <= len { + let simd_a = u8x16::from_slice(&a[i..]); + let simd_b = u8x16::from_slice(&b[i..]); + if simd_a != simd_b { + return false; } - }; - - let chunks = a.chunks_exact(variant.chunk_size()); - let remainder = chunks.remainder(); - - for (chunk_a, chunk_b) in chunks.zip(b.chunks_exact(variant.chunk_size())) { - match variant { - SimdVariant::U8x16 => { - let simd_a = u8x16::from_slice(chunk_a); - let simd_b = u8x16::from_slice(chunk_b); - if simd_a != simd_b { - return false; - } - } - SimdVariant::U8x32 => { - let simd_a = u8x32::from_slice(chunk_a); - let simd_b = u8x32::from_slice(chunk_b); - if simd_a != simd_b { - return false; - } - } - SimdVariant::U8x64 => { - let simd_a = u8x64::from_slice(chunk_a); - let simd_b = u8x64::from_slice(chunk_b); - if simd_a != simd_b { - return false; - } - } + } + + while i < len { + if a[i] != b[i] { + return false; } + i += 1; } - remainder == &b[a.len() - remainder.len()..] + true } + #[cfg(not(feature = "experimental"))] { a == b