Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/giant-clubs-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eppo_core": minor
---

[ahash] Add "ahash" feature flag to use faster hash function for all hashmaps. It is changing the public interface so is disabled by default so as to not cause breakage across SDKs and allow them to update one by one.
6 changes: 6 additions & 0 deletions .changeset/twenty-owls-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"python-sdk": patch
"ruby-sdk": patch
---

perf: use faster hash function for internal hashmaps (ahash).
4 changes: 4 additions & 0 deletions eppo_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ categories = ["config"]
rust-version = "1.80.0"

[features]
# Use ahash for HashMaps. This is currently disabled by default to
# allow SDKs adapt their usage one by one.
Comment on lines +13 to +14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice thinking

ahash = ["dep:ahash"]
# Unstable feature flag for an upcoming feature.
event_ingestion = ["dep:uuid", "dep:exponential-backoff"]
# Add implementation of `FromPyObject`/`ToPyObject` for some types.
Expand All @@ -24,6 +27,7 @@ rustler = ["dep:rustler"]
vendored = []

[dependencies]
ahash = { version = "0.8.12", optional = true }
base64 = "0.22.1"
chrono = { version = "0.4.38", features = ["serde"] }
derive_more = { version = "2.0.0", default-features = false, features = ["from", "into"] }
Expand Down
6 changes: 5 additions & 1 deletion eppo_core/benches/bandit_evaluation.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use std::collections::HashMap;
use std::fs::File;

use chrono::Utc;
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};

#[cfg(feature = "ahash")]
use eppo_core::ahash::{HashMap, HashMapExt};
#[cfg(not(feature = "ahash"))]
use std::collections::HashMap;

use eppo_core::ufc::UniversalFlagConfig;
use eppo_core::{eval::get_bandit_action, Configuration, ContextAttributes, SdkMetadata, Str};

Expand Down
27 changes: 22 additions & 5 deletions eppo_core/benches/evaluation_details.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

use chrono::Utc;
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};

#[cfg(feature = "ahash")]
use eppo_core::ahash::{HashMap, HashMapExt};
#[cfg(not(feature = "ahash"))]
use std::collections::HashMap;

use eppo_core::ufc::UniversalFlagConfig;
use eppo_core::{
eval::{get_assignment, get_assignment_details},
Expand Down Expand Up @@ -55,7 +60,11 @@ fn criterion_benchmark(c: &mut Criterion) {
{
let mut group = c.benchmark_group("rollout");
group.throughput(Throughput::Elements(1));
let attributes = Arc::new([("country".into(), "US".into())].into());
let attributes = {
let mut map = HashMap::new();
map.insert("country".into(), "US".into());
Arc::new(map)
};
group.bench_function("get_assignment", |b| {
b.iter(|| {
get_assignment(
Expand Down Expand Up @@ -86,7 +95,7 @@ fn criterion_benchmark(c: &mut Criterion) {
{
let mut group = c.benchmark_group("json-config-flag");
group.throughput(Throughput::Elements(1));
let attributes = Arc::new([].into());
let attributes = Arc::new(HashMap::new());
group.bench_function("get_assignment", |b| {
b.iter(|| {
get_assignment(
Expand Down Expand Up @@ -117,7 +126,11 @@ fn criterion_benchmark(c: &mut Criterion) {
{
let mut group = c.benchmark_group("numeric-one-of");
group.throughput(Throughput::Elements(1));
let attributes = Arc::new([("number".into(), 2.0.into())].into());
let attributes = {
let mut map = HashMap::new();
map.insert("number".into(), 2.0.into());
Arc::new(map)
};
group.bench_function("get_assignment", |b| {
b.iter(|| {
get_assignment(
Expand Down Expand Up @@ -148,7 +161,11 @@ fn criterion_benchmark(c: &mut Criterion) {
{
let mut group = c.benchmark_group("regex-flag");
group.throughput(Throughput::Elements(1));
let attributes = Arc::new([("email".into(), "test@gmail.com".into())].into());
let attributes = {
let mut map = HashMap::new();
map.insert("email".into(), "test@gmail.com".into());
Arc::new(map)
};
group.bench_function("get_assignment", |b| {
b.iter(|| {
get_assignment(
Expand Down
4 changes: 2 additions & 2 deletions eppo_core/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{borrow::Cow, collections::HashMap, sync::Arc};
use std::{borrow::Cow, sync::Arc};

use serde::{Deserialize, Serialize};

use crate::Str;
use crate::{hashmap::HashMap, Str};

mod context_attributes;

Expand Down
8 changes: 4 additions & 4 deletions eppo_core/src/attributes/context_attributes.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

use serde::{Deserialize, Serialize};

use crate::Str;
use crate::{hashmap::*, Str};

use super::{
AttributeValue, AttributeValueImpl, Attributes, CategoricalAttribute, NumericAttribute,
Expand Down Expand Up @@ -81,11 +81,11 @@ impl ContextAttributes {

#[cfg(feature = "pyo3")]
mod pyo3_impl {
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

use pyo3::{prelude::*, types::PyDict};

use crate::{Attributes, CategoricalAttribute, NumericAttribute, Str};
use crate::{hashmap::*, Attributes, CategoricalAttribute, NumericAttribute, Str};

use super::ContextAttributes;

Expand Down
2 changes: 1 addition & 1 deletion eppo_core/src/bandits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(missing_docs)]

use std::collections::HashMap;
use crate::hashmap::HashMap;

use serde::{Deserialize, Serialize};

Expand Down
3 changes: 2 additions & 1 deletion eppo_core/src/configuration_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ impl ConfigurationStore {

#[cfg(test)]
mod tests {
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

use crate::hashmap::*;
use chrono::Utc;

use super::ConfigurationStore;
Expand Down
3 changes: 2 additions & 1 deletion eppo_core/src/eval/eval_bandits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::HashMap;
use std::sync::Arc;

use crate::hashmap::HashMap;

use chrono::{DateTime, Utc};
use serde::Serialize;

Expand Down
4 changes: 3 additions & 1 deletion eppo_core/src/eval/eval_details_builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

use crate::hashmap::*;

use chrono::{DateTime, Utc};

Expand Down
8 changes: 5 additions & 3 deletions eppo_core/src/eval/eval_precomputed.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::HashMap;
use std::sync::Arc;

use crate::hashmap::*;

use chrono::{DateTime, Utc};

use crate::eval::get_assignment;
Expand Down Expand Up @@ -58,7 +59,7 @@ pub fn get_precomputed_configuration(
);
None
})
.map(|assignment| ((flag_key.clone(), PrecomputedAssignment::from(assignment))))
.map(|assignment| (flag_key.clone(), PrecomputedAssignment::from(assignment)))
})
.collect::<HashMap<_, _>>();

Expand Down Expand Up @@ -137,14 +138,15 @@ pub fn get_precomputed_configuration(
mod tests {
use crate::Str;
use chrono::Utc;
use std::collections::HashMap;

use crate::{
eval::get_precomputed_configuration, ufc::UniversalFlagConfig, Configuration,
ContextAttributes, SdkMetadata,
};
use std::{fs, sync::Arc};

use crate::hashmap::*;

#[test]
fn test_precomputed_assignment_basic() {
let _ = env_logger::builder().is_test(true).try_init();
Expand Down
34 changes: 28 additions & 6 deletions eppo_core/src/eval/eval_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ impl ConditionCheck {

#[cfg(test)]
mod tests {
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

use crate::hashmap::*;

use crate::{
eval::{eval_visitor::NoopEvalVisitor, subject::Subject},
Expand Down Expand Up @@ -361,7 +363,11 @@ mod tests {
&mut NoopEvalVisitor,
&Subject::new(
"key".into(),
Arc::new(HashMap::from([("age".into(), 11.0.into())]))
Arc::new({
let mut map = HashMap::new();
map.insert("age".into(), 11.0.into());
map
})
)
));
}
Expand Down Expand Up @@ -392,21 +398,33 @@ mod tests {
&mut NoopEvalVisitor,
&Subject::new(
"key".into(),
Arc::new(HashMap::from([("age".into(), 20.0.into())]))
Arc::new({
let mut map = HashMap::new();
map.insert("age".into(), 20.0.into());
map
})
)
));
assert!(!rule.eval(
&mut NoopEvalVisitor,
&Subject::new(
"key".into(),
Arc::new(HashMap::from([("age".into(), 17.0.into())]))
Arc::new({
let mut map = HashMap::new();
map.insert("age".into(), 17.0.into());
map
})
)
));
assert!(!rule.eval(
&mut NoopEvalVisitor,
&Subject::new(
"key".into(),
Arc::new(HashMap::from([("age".into(), 110.0.into())]))
Arc::new({
let mut map = HashMap::new();
map.insert("age".into(), 110.0.into());
map
})
)
));
}
Expand All @@ -427,7 +445,11 @@ mod tests {
&mut NoopEvalVisitor,
&Subject::new(
"key".into(),
Arc::new(HashMap::from([("name".into(), "alice".into())]))
Arc::new({
let mut map = HashMap::new();
map.insert("name".into(), "alice".into());
map
})
)
));
}
Expand Down
4 changes: 3 additions & 1 deletion eppo_core/src/eval/evaluator.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

use crate::hashmap::HashMap;

use chrono::Utc;

Expand Down
4 changes: 3 additions & 1 deletion eppo_core/src/events.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

use crate::hashmap::HashMap;

use serde::Serialize;

Expand Down
5 changes: 5 additions & 0 deletions eppo_core/src/hashmap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#[cfg(feature = "ahash")]
pub use ahash::{HashMap, HashMapExt};

#[cfg(not(feature = "ahash"))]
pub use std::collections::HashMap;
5 changes: 5 additions & 0 deletions eppo_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@

#![warn(rustdoc::missing_crate_level_docs)]

// Re-export public dependencies.
#[cfg(feature = "ahash")]
pub use ahash;

pub mod attributes;
pub mod background;
pub mod bandits;
Expand All @@ -67,6 +71,7 @@ pub mod ufc;

mod configuration;
mod error;
mod hashmap;
mod obfuscation;
mod precomputed;
mod sdk_key;
Expand Down
4 changes: 3 additions & 1 deletion eppo_core/src/precomputed.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashMap;
use std::sync::Arc;

use crate::hashmap::HashMap;
use base64::Engine;
use rand::Rng;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -198,6 +198,8 @@ impl From<PrecomputedBandit> for ObfuscatedPrecomputedBandit {

#[cfg(test)]
mod tests {
use crate::hashmap::*;

use super::*;

#[test]
Expand Down
4 changes: 3 additions & 1 deletion eppo_core/src/ufc/compiled_flag_config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

use crate::hashmap::*;

use serde::Serialize;

Expand Down
3 changes: 1 addition & 2 deletions eppo_core/src/ufc/models.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::collections::HashMap;

use crate::hashmap::HashMap;
use derive_more::From;
use regex::Regex;
use semver::Version;
Expand Down
2 changes: 1 addition & 1 deletion python-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ publish = false
crate-type = ["cdylib"]

[dependencies]
eppo_core = { version = "=9.3.0", path = "../eppo_core", features = ["pyo3"] }
eppo_core = { version = "=9.3.0", path = "../eppo_core", features = ["pyo3", "ahash"] }
log = "0.4.22"
pyo3 = "0.27.2"
pyo3-log = "0.13.2"
Expand Down
2 changes: 1 addition & 1 deletion python-sdk/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::{
collections::HashMap,
ops::Deref,
sync::{
atomic::{AtomicBool, Ordering},
Expand All @@ -17,6 +16,7 @@ use pyo3::{
};

use eppo_core::{
ahash::HashMap,
background::BackgroundThread,
configuration_fetcher::ConfigurationFetcher,
configuration_poller::{
Expand Down
Loading
Loading