Skip to content

Commit

Permalink
Implement f64 method polyfills with intrinsics support (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
pantsman0 authored Feb 22, 2024
1 parent b21f0d1 commit bd2816c
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 12 deletions.
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 <[email protected]>"]
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)
}
}
}

0 comments on commit bd2816c

Please sign in to comment.