Skip to content

Commit

Permalink
ahash compile-time-rng
Browse files Browse the repository at this point in the history
  • Loading branch information
ijl committed Jan 18, 2024
1 parent ef675bf commit 5ae9b58
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 46 deletions.
53 changes: 53 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ no-panic = [
yyjson = []

[dependencies]
ahash = { version = "=0.8.6", default_features = false }
ahash = { version = "=0.8.6", default_features = false, features = ["compile-time-rng"] }
arrayvec = { version = "0.7", default_features = false, features = ["std", "serde"] }
associative-cache = { version = "2", default_features = false }
beef = { version = "0.5", default_features = false, features = ["impl_serde"] }
Expand Down
9 changes: 4 additions & 5 deletions src/deserialize/cache.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

use crate::typeref::HASH_BUILDER;
use associative_cache::replacement::RoundRobinReplacement;
use associative_cache::*;
use once_cell::unsync::OnceCell;
use std::hash::BuildHasher;
use std::hash::Hasher;
use std::os::raw::c_void;

Expand Down Expand Up @@ -42,12 +40,13 @@ pub type KeyMap =
pub static mut KEY_MAP: OnceCell<KeyMap> = OnceCell::new();

pub fn cache_hash(key: &[u8]) -> u64 {
// try to omit code for >64 path in ahash
debug_assert!(key.len() <= 64);
#[cfg(feature = "intrinsics")]
unsafe {
std::intrinsics::assume(!key.is_empty());
std::intrinsics::assume(key.len() <= 64);
}
let mut hasher = unsafe { HASH_BUILDER.get().unwrap().build_hasher() };
};
let mut hasher = ahash::AHasher::default();
hasher.write(key);
hasher.finish()
}
43 changes: 24 additions & 19 deletions src/deserialize/pyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,39 @@

use crate::deserialize::cache::*;
use crate::str::{hash_str, unicode_from_str};
use crate::typeref::{EMPTY_UNICODE, FALSE, NONE, TRUE};
use crate::typeref::{FALSE, NONE, TRUE};
use std::ptr::NonNull;

pub fn get_unicode_key(key_str: &str) -> *mut pyo3_ffi::PyObject {
let pykey: *mut pyo3_ffi::PyObject;
if unlikely!(key_str.len() > 64) {
pykey = unicode_from_str(key_str);
hash_str(pykey);
} else if unlikely!(key_str.is_empty()) {
pykey = use_immortal!(EMPTY_UNICODE);
let pykey = if unlikely!(key_str.len() > 64) {
create_str_impl(key_str)
} else {
let hash = cache_hash(key_str.as_bytes());
let map = unsafe { KEY_MAP.get_mut().unwrap_or_else(|| unreachable!()) };
let entry = map.entry(&hash).or_insert_with(
|| hash,
|| {
let pyob = unicode_from_str(key_str);
hash_str(pyob);
CachedKey::new(pyob)
},
);
pykey = entry.get();
}
get_unicode_key_impl(key_str)
};
debug_assert!(ffi!(Py_REFCNT(pykey)) >= 1);
debug_assert!(unsafe { (*pykey.cast::<pyo3_ffi::PyASCIIObject>()).hash != -1 });
pykey
}

fn get_unicode_key_impl(key_str: &str) -> *mut pyo3_ffi::PyObject {
let hash = cache_hash(key_str.as_bytes());
let map = unsafe { KEY_MAP.get_mut().unwrap_or_else(|| unreachable!()) };
let entry = map.entry(&hash).or_insert_with(
|| hash,
|| {
let pyob = create_str_impl(key_str);
CachedKey::new(pyob)
},
);
entry.get()
}

fn create_str_impl(key_str: &str) -> *mut pyo3_ffi::PyObject {
let pyob = unicode_from_str(key_str);
hash_str(pyob);
pyob
}

#[allow(dead_code)]
#[inline(always)]
pub fn parse_bool(val: bool) -> NonNull<pyo3_ffi::PyObject> {
Expand Down
21 changes: 0 additions & 21 deletions src/typeref.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

use crate::ffi::orjson_fragmenttype_new;
use ahash::RandomState;
use once_cell::race::{OnceBool, OnceBox};
use pyo3_ffi::*;
#[cfg(feature = "yyjson")]
Expand Down Expand Up @@ -76,23 +75,6 @@ pub static mut DESCR_STR: *mut PyObject = null_mut();
pub static mut VALUE_STR: *mut PyObject = null_mut();
pub static mut INT_ATTR_STR: *mut PyObject = null_mut();

pub static mut HASH_BUILDER: OnceBox<ahash::RandomState> = OnceBox::new();

pub fn ahash_init() -> Box<ahash::RandomState> {
unsafe {
debug_assert!(!VALUE_STR.is_null());
debug_assert!(!DICT_TYPE.is_null());
debug_assert!(!STR_TYPE.is_null());
debug_assert!(!BYTES_TYPE.is_null());
Box::new(RandomState::with_seeds(
VALUE_STR as u64,
DICT_TYPE as u64,
STR_TYPE as u64,
BYTES_TYPE as u64,
))
}
}

#[cfg(feature = "yyjson")]
pub const YYJSON_BUFFER_SIZE: usize = 1024 * 1024 * 8;

Expand Down Expand Up @@ -214,9 +196,6 @@ fn _init_typerefs_impl() -> bool {
JsonEncodeError = pyo3_ffi::PyExc_TypeError;
Py_INCREF(JsonEncodeError);
JsonDecodeError = look_up_json_exc();

// after all type lookups
HASH_BUILDER.get_or_init(ahash_init);
};
true
}
Expand Down

0 comments on commit 5ae9b58

Please sign in to comment.