From 54fcfde920248a2c78d6b1159cb9b9da1aab25a2 Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Mon, 4 Dec 2023 19:20:25 +1030 Subject: [PATCH 1/7] Implement f64 method polyfills with intrinsics support --- Cargo.toml | 1 + src/lfu/tinylfu/bloom.rs | 22 ++++++++++++++++++++-- src/lru/two_queue.rs | 16 ++++++++++++---- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ab3fb19..8ada8a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ nightly = ["rand/nightly"] [dependencies] bitvec = { version = "1", default-features = false } hashbrown = { version = "0.14", optional = true } +libm = {version = "0.2.8", optional = true} rand = {version = "0.8", optional = true} [dev-dependencies] diff --git a/src/lfu/tinylfu/bloom.rs b/src/lfu/tinylfu/bloom.rs index 19c62e2..50f042a 100644 --- a/src/lfu/tinylfu/bloom.rs +++ b/src/lfu/tinylfu/bloom.rs @@ -7,7 +7,25 @@ // use bitvec::vec::BitVec; use alloc::{vec, vec::Vec}; +#[cfg(feature = "std")] +use compat::*; +#[cfg(feature = "std")] +mod compat { + pub(super) fn ceil(val: f64) -> f64 { + val.ceil() + } + pub(super) fn ln(val: f64) -> f64 { + val.ln() + } +} + + +#[cfg(not(feature = "std"))] +use libm::{ceil, log as ln}; + + const LN_2: f64 = core::f64::consts::LN_2; +const LN_2_2:f64 = LN_2 * LN_2; fn get_size(ui64: u64) -> (u64, u64) { let ui64 = if ui64 < 512 { 512 } else { ui64 }; @@ -21,8 +39,8 @@ fn get_size(ui64: u64) -> (u64, u64) { } fn calc_size_by_wrong_positives(num_entries: f64, wrongs: f64) -> (u64, u64) { - let size = (-num_entries * wrongs.ln() / LN_2.powi(2)).ceil() as u64; - let locs = (LN_2 * size as f64 / num_entries).ceil() as u64; + let size = ceil(-num_entries * ln(wrongs) / LN_2_2) as u64; + let locs = ceil(LN_2 * size as f64 / num_entries) as u64; (size, locs) } diff --git a/src/lru/two_queue.rs b/src/lru/two_queue.rs index 18a3ea4..2f39ebd 100644 --- a/src/lru/two_queue.rs +++ b/src/lru/two_queue.rs @@ -9,6 +9,14 @@ use alloc::fmt; use core::borrow::Borrow; use core::hash::{BuildHasher, Hash}; +#[cfg(feature = "std")] +pub(super) fn floor(val: f64) -> f64 { + val.floor() +} + +#[cfg(not(feature = "std"))] +use libm::floor; + /// `DEFAULT_2Q_RECENT_RATIO` is the ratio of the [`TwoQueueCache`] dedicated /// to recently added entries that have only been accessed once. /// @@ -191,8 +199,8 @@ impl TwoQueueCacheBuilder TwoQueueCache { } // Determine the sub-sizes - let rs = ((size as f64) * rr).floor() as usize; - let es = ((size as f64) * gr).floor() as usize; + let rs = floor((size as f64) * rr) as usize; + let es = floor((size as f64) * gr) as usize; // allocate the lrus let recent = RawLRU::new(size).unwrap(); From 51cbf05434cae46f50a147e3331363ecebe39a09 Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Mon, 4 Dec 2023 19:20:25 +1030 Subject: [PATCH 2/7] Implement f64 method polyfills with intrinsics support --- Cargo.toml | 3 ++- src/lfu/tinylfu/bloom.rs | 17 +------------- src/lib.rs | 10 ++++++++ src/lru/two_queue.rs | 6 +++++ src/polyfill.rs | 50 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 src/polyfill.rs diff --git a/Cargo.toml b/Cargo.toml index 8ada8a7..ce9f66c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "caches" -version = "0.2.8" +version = "0.2.9" authors = ["Al Liu "] description = "This is a Rust implementation for popular caches (support no_std)." homepage = "https://github.com/al8n/caches-rs" @@ -42,6 +42,7 @@ nightly = ["rand/nightly"] [dependencies] bitvec = { version = "1", default-features = false } +cfg-if = "1.0.0" hashbrown = { version = "0.14", optional = true } libm = {version = "0.2.8", optional = true} rand = {version = "0.8", optional = true} diff --git a/src/lfu/tinylfu/bloom.rs b/src/lfu/tinylfu/bloom.rs index 50f042a..94b9ada 100644 --- a/src/lfu/tinylfu/bloom.rs +++ b/src/lfu/tinylfu/bloom.rs @@ -7,22 +7,7 @@ // use bitvec::vec::BitVec; use alloc::{vec, vec::Vec}; -#[cfg(feature = "std")] -use compat::*; -#[cfg(feature = "std")] -mod compat { - pub(super) fn ceil(val: f64) -> f64 { - val.ceil() - } - pub(super) fn ln(val: f64) -> f64 { - val.ln() - } -} - - -#[cfg(not(feature = "std"))] -use libm::{ceil, log as ln}; - +use crate::polyfill::{ceil, ln}; const LN_2: f64 = core::f64::consts::LN_2; const LN_2_2:f64 = LN_2 * LN_2; diff --git a/src/lib.rs b/src/lib.rs index af6ca60..f0e2ee4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,10 +89,20 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, allow(unused_attributes))] #![deny(missing_docs)] +#![allow(unused_doc_comments)] #![allow(clippy::blocks_in_if_conditions, clippy::enum_variant_names)] + +#![feature(core_intrinsics)] + extern crate alloc; +#[macro_use] +extern crate cfg_if; + +#[doc(hidden)] +pub(crate) mod polyfill; + #[cfg(not(feature = "std"))] extern crate hashbrown; diff --git a/src/lru/two_queue.rs b/src/lru/two_queue.rs index 2f39ebd..c6c7307 100644 --- a/src/lru/two_queue.rs +++ b/src/lru/two_queue.rs @@ -9,6 +9,7 @@ use alloc::fmt; use core::borrow::Borrow; use core::hash::{BuildHasher, Hash}; +<<<<<<< HEAD #[cfg(feature = "std")] pub(super) fn floor(val: f64) -> f64 { val.floor() @@ -16,6 +17,11 @@ pub(super) fn floor(val: f64) -> f64 { #[cfg(not(feature = "std"))] use libm::floor; +======= +// f64 function polyfill to support no_std contexts +use crate::polyfill::floor; + +>>>>>>> 143023d (Implement f64 method polyfills with intrinsics support) /// `DEFAULT_2Q_RECENT_RATIO` is the ratio of the [`TwoQueueCache`] dedicated /// to recently added entries that have only been accessed once. diff --git a/src/polyfill.rs b/src/polyfill.rs new file mode 100644 index 0000000..2cdc0e9 --- /dev/null +++ b/src/polyfill.rs @@ -0,0 +1,50 @@ +/// Three level poliyfill dor the f64 `ceil`, `ln`, and `floor` functions. +/// Using these functions in a no_std context falls back to libm's manual +/// implementation from musl's libc. +/// Using the nightly feature allows the upgrade to using LLVM hints, and +/// allowing LLVM to provide a software fallback for target platforms +/// witout hardware f64 instructions. + +cfg_if! { + if #[cfg(feature = "std")] { + #[inline(always)] + pub(crate) fn ceil(val: f64) -> f64 { + val.ceil() + } + #[inline(always)] + pub(crate) fn ln(val: f64) -> f64 { + val.ln() + } + #[inline(always)] + pub(crate) fn floor(val: f64) -> f64 { + val.floor() + } + } else if #[cfg(feature = "nightly")] { + #[inline(always)] + pub(crate) fn ceil(val: f64) -> f64 { + unsafe {core::intrinsics::ceilf64(val)} + } + #[inline(always)] + pub(crate) fn ln(val: f64) -> f64 { + unsafe {core::intrinsics::logf64(val)} + } + #[inline(always)] + pub(crate) fn floor(val: f64) -> f64 { + unsafe {core::intrinsics::floorf64(val)} + } + } else { + use libm; + #[inline(always)] + pub(crate) fn ceil(val: f64) -> f64 { + libm::ceil(val) + } + #[inline(always)] + pub(crate) fn ln(val: f64) -> f64 { + libm::log(val) + } + #[inline(always)] + pub(crate) fn floor(val: f64) -> f64 { + libm::floor(val) + } + } +} \ No newline at end of file From 61fb13087d096a5b31634563a74ba4d087bdb9ad Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Mon, 4 Dec 2023 19:30:44 +1030 Subject: [PATCH 3/7] Fix use of polyfill crate module --- src/lru/two_queue.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/lru/two_queue.rs b/src/lru/two_queue.rs index c6c7307..3a52cfb 100644 --- a/src/lru/two_queue.rs +++ b/src/lru/two_queue.rs @@ -9,19 +9,9 @@ use alloc::fmt; use core::borrow::Borrow; use core::hash::{BuildHasher, Hash}; -<<<<<<< HEAD -#[cfg(feature = "std")] -pub(super) fn floor(val: f64) -> f64 { - val.floor() -} - -#[cfg(not(feature = "std"))] -use libm::floor; -======= // f64 function polyfill to support no_std contexts use crate::polyfill::floor; ->>>>>>> 143023d (Implement f64 method polyfills with intrinsics support) /// `DEFAULT_2Q_RECENT_RATIO` is the ratio of the [`TwoQueueCache`] dedicated /// to recently added entries that have only been accessed once. From a8679c70afc29bc79328f77b161482fe8308c279 Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Tue, 5 Dec 2023 08:57:37 +1030 Subject: [PATCH 4/7] Fix formatting and conditionally include #![feature(rustc_intrinsics)] --- src/lfu/tinylfu/bloom.rs | 2 +- src/lib.rs | 3 +- src/lru/two_queue.rs | 1 - src/polyfill.rs | 100 +++++++++++++++++++-------------------- 4 files changed, 52 insertions(+), 54 deletions(-) diff --git a/src/lfu/tinylfu/bloom.rs b/src/lfu/tinylfu/bloom.rs index 94b9ada..455eef8 100644 --- a/src/lfu/tinylfu/bloom.rs +++ b/src/lfu/tinylfu/bloom.rs @@ -10,7 +10,7 @@ use alloc::{vec, vec::Vec}; use crate::polyfill::{ceil, ln}; const LN_2: f64 = core::f64::consts::LN_2; -const LN_2_2:f64 = LN_2 * LN_2; +const LN_2_2: f64 = LN_2 * LN_2; fn get_size(ui64: u64) -> (u64, u64) { let ui64 = if ui64 < 512 { 512 } else { ui64 }; diff --git a/src/lib.rs b/src/lib.rs index f0e2ee4..5dec85e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,8 +92,7 @@ #![allow(unused_doc_comments)] #![allow(clippy::blocks_in_if_conditions, clippy::enum_variant_names)] - -#![feature(core_intrinsics)] +#![ cfg_attr( nightly, feature(core_intrinsics))] extern crate alloc; diff --git a/src/lru/two_queue.rs b/src/lru/two_queue.rs index 3a52cfb..9d1aefa 100644 --- a/src/lru/two_queue.rs +++ b/src/lru/two_queue.rs @@ -12,7 +12,6 @@ use core::hash::{BuildHasher, Hash}; // f64 function polyfill to support no_std contexts use crate::polyfill::floor; - /// `DEFAULT_2Q_RECENT_RATIO` is the ratio of the [`TwoQueueCache`] dedicated /// to recently added entries that have only been accessed once. /// diff --git a/src/polyfill.rs b/src/polyfill.rs index 2cdc0e9..f0f7723 100644 --- a/src/polyfill.rs +++ b/src/polyfill.rs @@ -1,50 +1,50 @@ -/// Three level poliyfill dor the f64 `ceil`, `ln`, and `floor` functions. -/// Using these functions in a no_std context falls back to libm's manual -/// implementation from musl's libc. -/// Using the nightly feature allows the upgrade to using LLVM hints, and -/// allowing LLVM to provide a software fallback for target platforms -/// witout hardware f64 instructions. - -cfg_if! { - if #[cfg(feature = "std")] { - #[inline(always)] - pub(crate) fn ceil(val: f64) -> f64 { - val.ceil() - } - #[inline(always)] - pub(crate) fn ln(val: f64) -> f64 { - val.ln() - } - #[inline(always)] - pub(crate) fn floor(val: f64) -> f64 { - val.floor() - } - } else if #[cfg(feature = "nightly")] { - #[inline(always)] - pub(crate) fn ceil(val: f64) -> f64 { - unsafe {core::intrinsics::ceilf64(val)} - } - #[inline(always)] - pub(crate) fn ln(val: f64) -> f64 { - unsafe {core::intrinsics::logf64(val)} - } - #[inline(always)] - pub(crate) fn floor(val: f64) -> f64 { - unsafe {core::intrinsics::floorf64(val)} - } - } else { - use libm; - #[inline(always)] - pub(crate) fn ceil(val: f64) -> f64 { - libm::ceil(val) - } - #[inline(always)] - pub(crate) fn ln(val: f64) -> f64 { - libm::log(val) - } - #[inline(always)] - pub(crate) fn floor(val: f64) -> f64 { - libm::floor(val) - } - } -} \ No newline at end of file +/// Three level poliyfill dor the f64 `ceil`, `ln`, and `floor` functions. +/// Using these functions in a no_std context falls back to libm's manual +/// implementation from musl's libc. +/// Using the nightly feature allows the upgrade to using LLVM hints, and +/// allowing LLVM to provide a software fallback for target platforms +/// witout hardware f64 instructions. + +cfg_if! { + if #[cfg(feature = "std")] { + #[inline(always)] + pub(crate) fn ceil(val: f64) -> f64 { + val.ceil() + } + #[inline(always)] + pub(crate) fn ln(val: f64) -> f64 { + val.ln() + } + #[inline(always)] + pub(crate) fn floor(val: f64) -> f64 { + val.floor() + } + } else if #[cfg(feature = "nightly")] { + #[inline(always)] + pub(crate) fn ceil(val: f64) -> f64 { + unsafe {core::intrinsics::ceilf64(val)} + } + #[inline(always)] + pub(crate) fn ln(val: f64) -> f64 { + unsafe {core::intrinsics::logf64(val)} + } + #[inline(always)] + pub(crate) fn floor(val: f64) -> f64 { + unsafe {core::intrinsics::floorf64(val)} + } + } else { + use libm; + #[inline(always)] + pub(crate) fn ceil(val: f64) -> f64 { + libm::ceil(val) + } + #[inline(always)] + pub(crate) fn ln(val: f64) -> f64 { + libm::log(val) + } + #[inline(always)] + pub(crate) fn floor(val: f64) -> f64 { + libm::floor(val) + } + } +} From 13faf06320eea6f7c98fd8b9ce802d9f6392c84f Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Tue, 5 Dec 2023 09:13:26 +1030 Subject: [PATCH 5/7] Change 'nightly' cfg option to feature in attribute declaration. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 5dec85e..582efb4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,7 +92,7 @@ #![allow(unused_doc_comments)] #![allow(clippy::blocks_in_if_conditions, clippy::enum_variant_names)] -#![ cfg_attr( nightly, feature(core_intrinsics))] +#![ cfg_attr( feature = "nightly", feature(core_intrinsics))] extern crate alloc; From cdd782f64babf8b83458b524e72715c57d6777b5 Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Tue, 5 Dec 2023 11:38:12 +1030 Subject: [PATCH 6/7] Removed intrinsics implementation as msvc targets do not support them. The intrinsics can be added back with more restrictive cfg attrs when they can be validated for availability. --- src/polyfill.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/polyfill.rs b/src/polyfill.rs index f0f7723..94797c8 100644 --- a/src/polyfill.rs +++ b/src/polyfill.rs @@ -19,19 +19,6 @@ cfg_if! { pub(crate) fn floor(val: f64) -> f64 { val.floor() } - } else if #[cfg(feature = "nightly")] { - #[inline(always)] - pub(crate) fn ceil(val: f64) -> f64 { - unsafe {core::intrinsics::ceilf64(val)} - } - #[inline(always)] - pub(crate) fn ln(val: f64) -> f64 { - unsafe {core::intrinsics::logf64(val)} - } - #[inline(always)] - pub(crate) fn floor(val: f64) -> f64 { - unsafe {core::intrinsics::floorf64(val)} - } } else { use libm; #[inline(always)] From 906849a369eac21c505217b62cef2e44d2d5628a Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Mon, 22 Jan 2024 22:48:17 +1030 Subject: [PATCH 7/7] Remove intrinsics feature, Fix benches, Fix clippy warning. This removes the feature flag for intrinsics, as I removed their use in `polyfill.rs`. Fixed type ambiguity errors in `wtinylfu_caches.rs` benchmark file. Fixed clippy warning for renamed check. --- benches/wtinylfu_cache.rs | 10 ++++++---- src/lib.rs | 4 +--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/benches/wtinylfu_cache.rs b/benches/wtinylfu_cache.rs index 31bc17b..652a38e 100644 --- a/benches/wtinylfu_cache.rs +++ b/benches/wtinylfu_cache.rs @@ -1,4 +1,4 @@ -use caches::{Cache, WTinyLFUCache, WTinyLFUCacheBuilder}; +use caches::{lfu::DefaultKeyHasher, Cache, WTinyLFUCache, WTinyLFUCacheBuilder}; use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion}; use fnv::FnvBuildHasher; use rand::{thread_rng, Rng}; @@ -59,10 +59,11 @@ fn bench_wtinylfu_cache_fx_hasher(c: &mut Criterion) { .collect(), ); - let builder = WTinyLFUCacheBuilder::new(82, 6488, 1622, 8192) + let builder = WTinyLFUCacheBuilder::, BuildHasherDefault, BuildHasherDefault, BuildHasherDefault>::new(82, 6488, 1622, 8192) .set_window_hasher(BuildHasherDefault::::default()) .set_protected_hasher(BuildHasherDefault::::default()) - .set_probationary_hasher(BuildHasherDefault::::default()); + .set_probationary_hasher(BuildHasherDefault::::default()) + .set_key_hasher(DefaultKeyHasher::default()); let l = WTinyLFUCache::from_builder(builder).unwrap(); (l, nums) }, @@ -99,7 +100,8 @@ fn bench_wtinylfu_cache_fnv_hasher(c: &mut Criterion) { }) .collect(), ); - let builder = WTinyLFUCacheBuilder::new(82, 6488, 1622, 8192) + let builder = WTinyLFUCacheBuilder::, BuildHasherDefault, BuildHasherDefault, BuildHasherDefault>::new(82, 6488, 1622, 8192) + .set_key_hasher(DefaultKeyHasher::default()) .set_window_hasher(FnvBuildHasher::default()) .set_protected_hasher(FnvBuildHasher::default()) .set_probationary_hasher(FnvBuildHasher::default()); diff --git a/src/lib.rs b/src/lib.rs index 582efb4..5f84d5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,9 +90,7 @@ #![cfg_attr(docsrs, allow(unused_attributes))] #![deny(missing_docs)] #![allow(unused_doc_comments)] -#![allow(clippy::blocks_in_if_conditions, clippy::enum_variant_names)] - -#![ cfg_attr( feature = "nightly", feature(core_intrinsics))] +#![allow(clippy::blocks_in_conditions, clippy::enum_variant_names)] extern crate alloc;