Skip to content

Commit

Permalink
chore: cascade simd usage, bench multiples of 8
Browse files Browse the repository at this point in the history
  • Loading branch information
rymnc committed Dec 29, 2024
1 parent 6960c51 commit 30248be
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 61 deletions.
3 changes: 3 additions & 0 deletions fuel-vm/benches/meq_performance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
94 changes: 33 additions & 61 deletions fuel-vm/src/interpreter/memory.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 30248be

Please sign in to comment.