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

perf: experiment with alt dispatch pattern #184

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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
125 changes: 121 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,122 @@
ignore_invalid_headers: bool,
}

// Runtime build of parse_headers_iter_uninit
#[cfg(all(
httparse_simd,
not(any(
httparse_simd_target_feature_sse42,
httparse_simd_target_feature_avx2,
)),
any(
target_arch = "x86",
target_arch = "x86_64",
),
))]
fn parse_headers_iter_uninit<'a>(headers: &mut &mut [MaybeUninit<Header<'a>>], bytes: &mut Bytes<'a>, config: &HeaderParserConfig) -> Result<usize> {

Check failure on line 1058 in src/lib.rs

View workflow job for this annotation

GitHub Actions / msrv (x64)

mismatched types
static mut PARSE_FUNC: fn(&mut &mut [MaybeUninit<Header<'a>>], &mut Bytes<'a>, &HeaderParserConfig) -> Result<usize> = parse_headers_setup;

Check failure on line 1059 in src/lib.rs

View workflow job for this annotation

GitHub Actions / check x86

can't use generic parameters from outer item

Check failure on line 1059 in src/lib.rs

View workflow job for this annotation

GitHub Actions / check x86

can't use generic parameters from outer item

Check failure on line 1059 in src/lib.rs

View workflow job for this annotation

GitHub Actions / SIMD +avx2 on beta

can't use generic parameters from outer item

Check failure on line 1059 in src/lib.rs

View workflow job for this annotation

GitHub Actions / SIMD +avx2 on beta

can't use generic parameters from outer item

Check failure on line 1059 in src/lib.rs

View workflow job for this annotation

GitHub Actions / SIMD +sse4.2,+avx2 on beta

can't use generic parameters from outer item

Check failure on line 1059 in src/lib.rs

View workflow job for this annotation

GitHub Actions / SIMD +sse4.2,+avx2 on beta

can't use generic parameters from outer item

Check failure on line 1059 in src/lib.rs

View workflow job for this annotation

GitHub Actions / msrv (x64)

use of undeclared lifetime name `'a`

Check failure on line 1059 in src/lib.rs

View workflow job for this annotation

GitHub Actions / msrv (x64)

use of undeclared lifetime name `'a`

fn parse_headers_avx2<'a>(headers: &mut &mut [MaybeUninit<Header<'a>>], bytes: &mut Bytes<'a>, config: &HeaderParserConfig) -> Result<usize> {
struct Avx2HeaderMatcher;
impl HeaderMatcher for Avx2HeaderMatcher {
#[inline(always)]
fn match_name(bytes: &mut Bytes) {
simd::avx2_match_header_name_vectored(bytes)
}
#[inline(always)]
fn match_value(bytes: &mut Bytes) {
simd::avx2_match_header_value_vectored(bytes)
}
}

_parse_headers_iter_uninit::<'a, Avx2HeaderMatcher>(headers, bytes, config)

Check failure on line 1074 in src/lib.rs

View workflow job for this annotation

GitHub Actions / msrv (x64)

cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
}

fn parse_headers_sse42<'a>(headers: &mut &mut [MaybeUninit<Header<'a>>], bytes: &mut Bytes<'a>, config: &HeaderParserConfig) -> Result<usize> {
struct Sse42HeaderMatcher;
impl HeaderMatcher for Sse42HeaderMatcher {
#[inline(always)]
fn match_name(bytes: &mut Bytes) {
simd::sse42_match_header_name_vectored(bytes)
}
#[inline(always)]
fn match_value(bytes: &mut Bytes) {
simd::sse42_match_header_value_vectored(bytes)
}
}

_parse_headers_iter_uninit::<'a, Sse42HeaderMatcher>(headers, bytes, config)
}

fn parse_headers_swar<'a>(headers: &mut &mut [MaybeUninit<Header<'a>>], bytes: &mut Bytes<'a>, config: &HeaderParserConfig) -> Result<usize> {
struct SwarHeaderMatcher;
impl HeaderMatcher for SwarHeaderMatcher {
#[inline(always)]
fn match_name(bytes: &mut Bytes) {
simd::swar_match_header_name_vectored(bytes)
}
#[inline(always)]
fn match_value(bytes: &mut Bytes) {
simd::swar_match_header_value_vectored(bytes)
}
}

_parse_headers_iter_uninit::<'a, SwarHeaderMatcher>(headers, bytes, config)
}

fn parse_headers_setup(headers: &mut &mut [MaybeUninit<Header<'a>>], bytes: &mut Bytes<'a>, config: &HeaderParserConfig) -> Result<usize> {

Check failure on line 1109 in src/lib.rs

View workflow job for this annotation

GitHub Actions / check x86

can't use generic parameters from outer item

Check failure on line 1109 in src/lib.rs

View workflow job for this annotation

GitHub Actions / check x86

can't use generic parameters from outer item

Check failure on line 1109 in src/lib.rs

View workflow job for this annotation

GitHub Actions / SIMD +avx2 on beta

can't use generic parameters from outer item

Check failure on line 1109 in src/lib.rs

View workflow job for this annotation

GitHub Actions / SIMD +avx2 on beta

can't use generic parameters from outer item

Check failure on line 1109 in src/lib.rs

View workflow job for this annotation

GitHub Actions / SIMD +sse4.2,+avx2 on beta

can't use generic parameters from outer item

Check failure on line 1109 in src/lib.rs

View workflow job for this annotation

GitHub Actions / SIMD +sse4.2,+avx2 on beta

can't use generic parameters from outer item

Check failure on line 1109 in src/lib.rs

View workflow job for this annotation

GitHub Actions / msrv (x64)

use of undeclared lifetime name `'a`

Check failure on line 1109 in src/lib.rs

View workflow job for this annotation

GitHub Actions / msrv (x64)

use of undeclared lifetime name `'a`
if is_x86_feature_detected!("avx2") {
unsafe {
PARSE_FUNC = parse_headers_avx2;
}
} else if is_x86_feature_detected!("sse4.2") {
unsafe {
PARSE_FUNC = parse_headers_sse42;
}
} else {
unsafe {
PARSE_FUNC = parse_headers_swar;
}
}

unsafe {
PARSE_FUNC(headers, bytes, config)
}
}
}

// Specialized build of parse_headers_iter_uninit
#[cfg(not(all(
httparse_simd,
not(any(
httparse_simd_target_feature_sse42,
httparse_simd_target_feature_avx2,
)),
any(
target_arch = "x86",
target_arch = "x86_64",
),
)))]
fn parse_headers_iter_uninit<'a>(headers: &mut &mut [MaybeUninit<Header<'a>>], bytes: &mut Bytes<'a>, config: &HeaderParserConfig) -> Result<usize> {
struct SimdHeaderMatcher;
impl HeaderMatcher for SimdHeaderMatcher {
#[inline(always)]
fn match_name(bytes: &mut Bytes) {
simd::match_header_name_vectored(bytes)
}
#[inline(always)]
fn match_value(bytes: &mut Bytes) {
simd::match_header_value_vectored(bytes)
}
}
_parse_headers_iter_uninit::<SimdHeaderMatcher>(headers, bytes, config)
}

trait HeaderMatcher {
fn match_name(bytes: &mut Bytes);
fn match_value(bytes: &mut Bytes);
}

/* Function which parsers headers into uninitialized buffer.
*
* Guarantees that it doesn't write garbage, so casting
Expand All @@ -1052,11 +1168,12 @@
* Also it promises `headers` get shrunk to number of initialized headers,
* so casting the other way around after calling this function is safe
*/
fn parse_headers_iter_uninit<'a>(
fn _parse_headers_iter_uninit<'a, Matcher: HeaderMatcher>(
headers: &mut &mut [MaybeUninit<Header<'a>>],
bytes: &mut Bytes<'a>,
config: &HeaderParserConfig
) -> Result<usize> {
) -> Result<usize>
{

/* Flow of this function is pretty complex, especially with macros,
* so this struct makes sure we shrink `headers` to only parsed ones.
Expand Down Expand Up @@ -1181,7 +1298,7 @@
#[allow(clippy::never_loop)]
// parse header name until colon
let header_name: &str = 'name: loop {
simd::match_header_name_vectored(bytes);
Matcher::match_name(bytes);
let mut b = next!(bytes);

// SAFETY: previously bumped by 1 with next! -> always safe.
Expand Down Expand Up @@ -1241,7 +1358,7 @@
'value_lines: loop {
// parse value till EOL

simd::match_header_value_vectored(bytes);
Matcher::match_value(bytes);
let b = next!(bytes);

//found_ctl
Expand Down
52 changes: 38 additions & 14 deletions src/simd/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
use std::sync::atomic::{AtomicU8, Ordering};
use crate::iter::Bytes;
use super::avx2;
use super::sse42;
use crate::iter::Bytes;
use std::sync::atomic::{AtomicU8, Ordering};

pub use self::avx2::match_header_name_vectored as avx2_match_header_name_vectored;

Check failure on line 6 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / check x86

unresolved import `self::avx2::match_header_name_vectored`

Check failure on line 6 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +avx2 on beta

unresolved import `self::avx2::match_header_name_vectored`

Check failure on line 6 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +sse4.2,+avx2 on beta

unresolved import `self::avx2::match_header_name_vectored`

Check failure on line 6 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / msrv (x64)

unresolved import `self::avx2::match_header_name_vectored`
pub use self::avx2::match_header_value_vectored as avx2_match_header_value_vectored;
pub use self::sse42::match_header_name_vectored as sse42_match_header_name_vectored;

Check failure on line 8 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / check x86

unresolved import `self::sse42::match_header_name_vectored`

Check failure on line 8 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +avx2 on beta

unresolved import `self::sse42::match_header_name_vectored`

Check failure on line 8 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +sse4.2,+avx2 on beta

unresolved import `self::sse42::match_header_name_vectored`

Check failure on line 8 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / msrv (x64)

unresolved import `self::sse42::match_header_name_vectored`
pub use self::sse42::match_header_value_vectored as sse42_match_header_value_vectored;
pub use self::swar::match_header_name_vectored as swar_match_header_name_vectored;

Check failure on line 10 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / check x86

unresolved import `self::swar`

Check failure on line 10 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +avx2 on beta

unresolved import `self::swar`

Check failure on line 10 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +sse4.2,+avx2 on beta

unresolved import `self::swar`

Check failure on line 10 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / msrv (x64)

unresolved import `self::swar`
pub use self::swar::match_header_value_vectored as swar_match_header_value_vectored;

Check failure on line 11 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / check x86

unresolved import `self::swar`

Check failure on line 11 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +avx2 on beta

unresolved import `self::swar`

Check failure on line 11 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +sse4.2,+avx2 on beta

unresolved import `self::swar`

Check failure on line 11 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / msrv (x64)

unresolved import `self::swar`

const AVX2: u8 = 1;
const SSE42: u8 = 2;
Expand Down Expand Up @@ -34,24 +41,41 @@
super::swar::match_header_name_vectored(bytes);
}

static mut MATCH_URI_VECTORED: fn(&mut Bytes) = setup_and_call_match_uri_vectored;
static mut MATCH_HEADER_VALUE_VECTORED: fn(&mut Bytes) = setup_and_call_match_header_value_vectored;

fn setup_and_call_match_uri_vectored(bytes: &mut Bytes) {
unsafe {
let feature = get_runtime_feature();
MATCH_URI_VECTORED = match feature {
AVX2 => avx2::match_uri_vectored,

Check failure on line 51 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / check x86

mismatched types

Check failure on line 51 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +avx2 on beta

mismatched types

Check failure on line 51 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +sse4.2,+avx2 on beta

mismatched types
SSE42 => sse42::match_uri_vectored,
_ /* NOP */ => super::swar::match_uri_vectored,
};
MATCH_URI_VECTORED(bytes);
}
}

fn setup_and_call_match_header_value_vectored(bytes: &mut Bytes) {
unsafe {
let feature = get_runtime_feature();
MATCH_HEADER_VALUE_VECTORED = match feature {
AVX2 => avx2::match_header_value_vectored,

Check failure on line 63 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / check x86

mismatched types

Check failure on line 63 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +avx2 on beta

mismatched types

Check failure on line 63 in src/simd/runtime.rs

View workflow job for this annotation

GitHub Actions / SIMD +sse4.2,+avx2 on beta

mismatched types
SSE42 => sse42::match_header_value_vectored,
_ /* NOP */ => super::swar::match_header_value_vectored,
};
MATCH_HEADER_VALUE_VECTORED(bytes);
}
}

pub fn match_uri_vectored(bytes: &mut Bytes) {
// SAFETY: calls are guarded by a feature check
unsafe {
match get_runtime_feature() {
AVX2 => avx2::match_uri_vectored(bytes),
SSE42 => sse42::match_uri_vectored(bytes),
_ /* NOP */ => super::swar::match_uri_vectored(bytes),
}
MATCH_URI_VECTORED(bytes);
}
}

pub fn match_header_value_vectored(bytes: &mut Bytes) {
// SAFETY: calls are guarded by a feature check
unsafe {
match get_runtime_feature() {
AVX2 => avx2::match_header_value_vectored(bytes),
SSE42 => sse42::match_header_value_vectored(bytes),
_ /* NOP */ => super::swar::match_header_value_vectored(bytes),
}
MATCH_HEADER_VALUE_VECTORED(bytes);
}
}
Loading