Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move simd under a feature flag, use fast CharLookup if not enabled #6

Merged
merged 1 commit into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ version = "0.6.2"
nom = "7.1.3"

[features]
# default = ["custom-vecdeque"]
default = ["simd"]
rc-alloc = []
custom-vecdeque = []
simd = []

[profile.release]
lto = true
Expand Down
18 changes: 9 additions & 9 deletions src/protocol/h1/parser/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ fn http_status(i: &[u8]) -> IResult<&[u8], (&[u8], u16)> {
#[inline]
#[allow(clippy::type_complexity)]
pub fn parse_request_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8], Version)> {
let (i, method) = tchar::take_while_simd(i)?;
let (i, method) = tchar::take_while_fast(i)?;
let (i, _) = space(i)?;
let (i, uri) = vchar::take_while_simd(i)?;
let (i, uri) = vchar::take_while_fast(i)?;
let (i, _) = space(i)?;
let (i, version) = http_version(i)?;
let (i, _) = crlf(i)?;
Expand All @@ -224,7 +224,7 @@ pub fn parse_response_line(i: &[u8]) -> IResult<&[u8], (Version, &[u8], u16, &[u
let (i, _) = space(i)?;
let (i, (status, code)) = http_status(i)?;
let (i, _) = space(i)?;
let (i, reason) = achar::take_while_simd(i)?;
let (i, reason) = achar::take_while_fast(i)?;
let (i, _) = crlf(i)?;
Ok((i, (version, status, code, reason)))
}
Expand All @@ -236,13 +236,13 @@ pub fn parse_response_line(i: &[u8]) -> IResult<&[u8], (Version, &[u8], u16, &[u
#[inline]
#[allow(clippy::type_complexity)]
pub fn parse_header_or_cookie(i: &[u8]) -> IResult<&[u8], Option<(&[u8], &[u8])>> {
let (i, key) = tchar::take_while_simd(i)?;
let (i, key) = tchar::take_while_fast(i)?;
let (i, _) = tag(b":")(i)?;
let (i, _) = take_while(is_space)(i)?;
if compare_no_case(key, b"cookie") {
return Ok((i, None));
}
let (i, val) = achar::take_while_simd(i)?;
let (i, val) = achar::take_while_fast(i)?;
let (i, _) = crlf(i)?;
Ok((i, Some((key, val))))
}
Expand All @@ -253,10 +253,10 @@ pub fn parse_header_or_cookie(i: &[u8]) -> IResult<&[u8], Option<(&[u8], &[u8])>
/// example: `Content-Length: 42\r\n`
#[inline]
pub fn parse_header(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
let (i, key) = tchar::take_while_simd(i)?;
let (i, key) = tchar::take_while_fast(i)?;
let (i, _) = tag(b":")(i)?;
let (i, _) = take_while(is_space)(i)?;
let (i, val) = achar::take_while_simd(i)?;
let (i, val) = achar::take_while_fast(i)?;
let (i, _) = crlf(i)?;
Ok((i, (key, val)))
}
Expand All @@ -277,8 +277,8 @@ pub fn parse_single_crumb(i: &[u8], first: bool) -> IResult<&[u8], (&[u8], &[u8]
} else {
i
};
let (i, key) = ck_char::take_while_simd(i)?;
let (i, val) = opt(tuple((tag(b"="), cv_char::take_while_simd)))(i)?;
let (i, key) = ck_char::take_while_fast(i)?;
let (i, val) = opt(tuple((tag(b"="), cv_char::take_while_fast)))(i)?;

match val {
Some((_, val)) => Ok((i, (key, val))),
Expand Down
80 changes: 75 additions & 5 deletions src/protocol/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,10 @@ macro_rules! compile_lookup {
mod $name {
use $crate::h1::parser::primitives::{CharLookup, CharRanges, CharTable};
pub const LOOKUP: CharLookup = $crate::make_char_lookup!($($t)*);
pub const RANGES: CharRanges = LOOKUP.ranges;
pub const TABLE: CharTable = LOOKUP.table;
#[allow(dead_code)]
pub const RANGES: CharRanges = LOOKUP.ranges;
#[allow(dead_code)]
pub const LENGTH: i32 = LOOKUP.len;

#[inline]
Expand All @@ -115,11 +117,11 @@ macro_rules! compile_lookup {
}

#[inline]
#[allow(dead_code)]
#[cfg(feature="simd")]
/// Returns the longest string that fits the rule (simd optimized)
///
/// *Streaming version* will return a Err::Incomplete(Needed::Unknown) if the pattern reaches the end of the input.
pub fn take_while_simd(input: &[u8]) -> nom::IResult<&[u8], &[u8]> {
fn take_while_simd(input: &[u8]) -> nom::IResult<&[u8], &[u8]> {
use std::arch::x86_64::{
_mm_cmpestri, _mm_lddqu_si128, _mm_loadu_si128, _SIDD_CMP_RANGES,
_SIDD_LEAST_SIGNIFICANT, _SIDD_UBYTE_OPS,
Expand Down Expand Up @@ -173,9 +175,9 @@ macro_rules! compile_lookup {
}

#[inline]
#[allow(dead_code)]
#[cfg(feature="simd")]
/// Returns the longest string that fits the rule (simd optimized)
pub fn take_while_complete_simd(input: &[u8]) -> nom::IResult<&[u8], &[u8]> {
fn take_while_complete_simd(input: &[u8]) -> nom::IResult<&[u8], &[u8]> {
use std::arch::x86_64::{
_mm_cmpestri, _mm_lddqu_si128, _mm_loadu_si128, _SIDD_CMP_RANGES,
_SIDD_LEAST_SIGNIFICANT, _SIDD_UBYTE_OPS,
Expand Down Expand Up @@ -223,6 +225,74 @@ macro_rules! compile_lookup {
))
}
}

#[inline]
#[allow(dead_code)]
/// Returns the longest string that fits the rule (not simd optimized)
///
/// *Streaming version* will return a Err::Incomplete(Needed::Unknown) if the pattern reaches the end of the input.
pub fn take_while(input: &[u8]) -> nom::IResult<&[u8], &[u8]> {
let mut i = 0;
while i < input.len() {
if unsafe { !TABLE.get_unchecked(*input.get_unchecked(i) as usize) } {
break;
}
i += 1;
}
if i == input.len() {
return Err(nom::Err::Incomplete(nom::Needed::Unknown));
} else {
unsafe {
Ok((
input.get_unchecked(i..),
input.get_unchecked(..i),
))
}
}
}

#[inline]
#[allow(dead_code)]
/// Returns the longest string that fits the rule (not simd optimized)
pub fn take_while_complete(input: &[u8]) -> nom::IResult<&[u8], &[u8]> {
let mut i = 0;
while i < input.len() {
if unsafe { !TABLE.get_unchecked(*input.get_unchecked(i) as usize) } {
break;
}
i += 1;
}
unsafe {
Ok((
input.get_unchecked(i..),
input.get_unchecked(..i),
))
}
}

#[inline]
#[allow(dead_code)]
/// Returns the longest string that fits the rule (using simd if enabled)
///
/// *Streaming version* will return a Err::Incomplete(Needed::Unknown) if the pattern reaches the end of the input.
pub fn take_while_fast(input: &[u8]) -> nom::IResult<&[u8], &[u8]> {
#[cfg(feature="simd")]
let result = take_while_simd(input);
#[cfg(not(feature="simd"))]
let result = take_while(input);
result
}

#[inline]
#[allow(dead_code)]
/// Returns the longest string that fits the rule (using simd if enabled)
pub fn take_while_complete_fast(input: &[u8]) -> nom::IResult<&[u8], &[u8]> {
#[cfg(feature="simd")]
let result = take_while_complete_simd(input);
#[cfg(not(feature="simd"))]
let result = take_while_complete(input);
result
}
}
}
}