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

Implement f64 method polyfills with intrinsics support #21

Merged
merged 7 commits into from
Feb 22, 2024
Merged
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "caches"
version = "0.2.8"
version = "0.2.9"
authors = ["Al Liu <scygliu1@gmail.com>"]
description = "This is a Rust implementation for popular caches (support no_std)."
homepage = "https://github.com/al8n/caches-rs"
Expand Down Expand Up @@ -42,7 +42,9 @@ 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}

[dev-dependencies]
Expand Down
10 changes: 6 additions & 4 deletions benches/wtinylfu_cache.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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::<u64, DefaultKeyHasher<u64>, BuildHasherDefault<FxHasher>, BuildHasherDefault<FxHasher>, BuildHasherDefault<FxHasher>>::new(82, 6488, 1622, 8192)
.set_window_hasher(BuildHasherDefault::<FxHasher>::default())
.set_protected_hasher(BuildHasherDefault::<FxHasher>::default())
.set_probationary_hasher(BuildHasherDefault::<FxHasher>::default());
.set_probationary_hasher(BuildHasherDefault::<FxHasher>::default())
.set_key_hasher(DefaultKeyHasher::default());
let l = WTinyLFUCache::from_builder(builder).unwrap();
(l, nums)
},
Expand Down Expand Up @@ -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::<u64, DefaultKeyHasher<u64>, BuildHasherDefault<fnv::FnvHasher>, BuildHasherDefault<fnv::FnvHasher>, BuildHasherDefault<fnv::FnvHasher>>::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());
Expand Down
7 changes: 5 additions & 2 deletions src/lfu/tinylfu/bloom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
// use bitvec::vec::BitVec;
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;

fn get_size(ui64: u64) -> (u64, u64) {
let ui64 = if ui64 < 512 { 512 } else { ui64 };
Expand All @@ -21,8 +24,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)
}

Expand Down
9 changes: 8 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,17 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, allow(unused_attributes))]
#![deny(missing_docs)]
#![allow(clippy::blocks_in_if_conditions, clippy::enum_variant_names)]
#![allow(unused_doc_comments)]
#![allow(clippy::blocks_in_conditions, clippy::enum_variant_names)]

extern crate alloc;

#[macro_use]
extern crate cfg_if;

#[doc(hidden)]
pub(crate) mod polyfill;

#[cfg(not(feature = "std"))]
extern crate hashbrown;

Expand Down
11 changes: 7 additions & 4 deletions src/lru/two_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ use alloc::fmt;
use core::borrow::Borrow;
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.
///
Expand Down Expand Up @@ -191,8 +194,8 @@ impl<RH: BuildHasher, FH: BuildHasher, GH: BuildHasher> TwoQueueCacheBuilder<RH,
}

// 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

Expand Down Expand Up @@ -361,8 +364,8 @@ impl<K: Hash + Eq, V> TwoQueueCache<K, V> {
}

// 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();
Expand Down
37 changes: 37 additions & 0 deletions src/polyfill.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// 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 {
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)
}
}
}