blob: 2dacffbbe860483984124dfa8f98c1716e39b3b1 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use criterion::{black_box, criterion_group, criterion_main, Criterion};
#[cfg(target_feature = "avx2")]
use std::arch::x86_64::*;
use fory_core::buffer::{Reader, Writer};
use fory_core::meta::buffer_rw_string::{
read_latin1_simd, read_latin1_standard, write_latin1_simd, write_latin1_standard,
write_latin1_string,
};
#[cfg(target_feature = "sse2")]
use std::arch::x86_64::*;
#[cfg(target_feature = "avx2")]
pub(crate) const MIN_DIM_SIZE_AVX: usize = 32;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(crate) const MIN_DIM_SIZE_SIMD: usize = 16;
#[cfg(target_feature = "sse2")]
unsafe fn is_latin_sse(s: &str) -> bool {
let bytes = s.as_bytes();
let len = s.len();
let ascii_mask = _mm_set1_epi8(0x80u8 as i8);
let remaining = len % MIN_DIM_SIZE_SIMD;
let range_end = len - remaining;
for i in (0..range_end).step_by(MIN_DIM_SIZE_SIMD) {
let chunk = _mm_loadu_si128(bytes.as_ptr().add(i) as *const __m128i);
let masked = _mm_and_si128(chunk, ascii_mask);
let cmp = _mm_cmpeq_epi8(masked, _mm_setzero_si128());
if _mm_movemask_epi8(cmp) != 0xFFFF {
return false;
}
}
for item in bytes.iter().take(range_end).skip(range_end) {
if !item.is_ascii() {
return false;
}
}
true
}
#[cfg(target_feature = "avx2")]
unsafe fn is_latin_avx(s: &str) -> bool {
let bytes = s.as_bytes();
let len = s.len();
let ascii_mask = _mm256_set1_epi8(0x80u8 as i8);
let remaining = len % MIN_DIM_SIZE_AVX;
let range_end = len - remaining;
for i in (0..(len - remaining)).step_by(MIN_DIM_SIZE_AVX) {
let chunk = _mm256_loadu_si256(bytes.as_ptr().add(i) as *const __m256i);
let masked = _mm256_and_si256(chunk, ascii_mask);
let cmp = _mm256_cmpeq_epi8(masked, _mm256_setzero_si256());
if _mm256_movemask_epi8(cmp) != 0xFFFF {
return false;
}
}
for item in bytes.iter().take(range_end).skip(range_end) {
if !item.is_ascii() {
return false;
}
}
true
}
fn is_latin_std(s: &str) -> bool {
s.bytes().all(|b| b.is_ascii())
}
fn benchmark_write_latin1(c: &mut Criterion) {
let sizes = [100, 1000, 10000, 100000];
let ascii_string = "abcdefghijklmnopqrstuvwxyz0123456789";
for &size in &sizes {
let s_ascii = ascii_string.repeat(size / ascii_string.len() + 1);
let name_simd = format!("Write Latin-1 SIMD size {}", size);
c.bench_function(&name_simd, |b| {
b.iter(|| {
let mut buffer = vec![];
let mut writer = Writer::from_buffer(&mut buffer);
write_latin1_simd(black_box(&mut writer), black_box(&s_ascii));
})
});
let name_scalar = format!("Write Latin-1 Standard size {}", size);
c.bench_function(&name_scalar, |b| {
b.iter(|| {
let mut buffer = vec![];
let mut writer = Writer::from_buffer(&mut buffer);
write_latin1_standard(black_box(&mut writer), black_box(&s_ascii));
})
});
}
}
fn benchmark_read_latin1(c: &mut Criterion) {
let sizes = [100, 1000, 10000, 100000];
let ascii_string = "abcdefghijklmnopqrstuvwxyz0123456789";
for &size in &sizes {
let s_ascii = ascii_string.repeat(size / ascii_string.len() + 1);
let mut buffer = vec![];
let mut writer = Writer::from_buffer(&mut buffer);
write_latin1_string(&mut writer, &s_ascii);
let data = writer.dump();
let name_simd = format!("Read Latin-1 SIMD size {}", size);
c.bench_function(&name_simd, |b| {
b.iter(|| {
let mut reader = Reader::new(black_box(&data));
read_latin1_simd(black_box(&mut reader), black_box(s_ascii.len())).unwrap();
})
});
let name_scalar = format!("Read Latin-1 Standard size {}", size);
c.bench_function(&name_scalar, |b| {
b.iter(|| {
let mut reader = Reader::new(black_box(&data));
read_latin1_standard(black_box(&mut reader), black_box(s_ascii.len())).unwrap();
})
});
}
}
fn criterion_benchmark(c: &mut Criterion) {
let test_str_short = "Hello, World!";
let test_str_long = "Hello, World! ".repeat(1000);
#[cfg(target_feature = "sse2")]
c.bench_function("SIMD sse short", |b| {
b.iter(|| unsafe { is_latin_sse(black_box(test_str_short)) })
});
#[cfg(target_feature = "sse2")]
c.bench_function("SIMD sse long", |b| {
b.iter(|| unsafe { is_latin_sse(black_box(&test_str_long)) })
});
#[cfg(target_feature = "avx2")]
c.bench_function("SIMD avx short", |b| {
b.iter(|| unsafe { is_latin_avx(black_box(test_str_short)) })
});
#[cfg(target_feature = "avx2")]
c.bench_function("SIMD avx long", |b| {
b.iter(|| unsafe { is_latin_avx(black_box(&test_str_long)) })
});
c.bench_function("Standard short", |b| {
b.iter(|| is_latin_std(black_box(test_str_short)))
});
c.bench_function("Standard long", |b| {
b.iter(|| is_latin_std(black_box(&test_str_long)))
});
benchmark_write_latin1(c);
benchmark_read_latin1(c);
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);