Skip to content

perf: add experimental cityhash option for bandit shuffling - #394

Merged
dd-oleksii merged 1 commit into
mainfrom
oleksii/jj-kxmvnnwxmlwp
Jan 7, 2026
Merged

dd-oleksii merged 1 commit into
mainfrom
oleksii/jj-kxmvnnwxmlwp

Conversation

@dd-oleksii

Copy link
Copy Markdown
Collaborator

Motivation and Context

Hashing (for shuffling actions) is the main contributor to bandit evaluation performance, and while we gained ~2x boost from various performance optimizations, there's only so much we can do without breaking compatibility with other SDKs.

This PR is what we can do if compatibility is not a concern. It adds a new experimental env variable to use CityHash instead of md5, boosting performance by another 2x+. Though this obviously produces incompatible results.

image

How has this been documented?

Changelog entry.

How has this been tested?

Benchmarks.

@changeset-bot

changeset-bot Bot commented Jan 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 99f5019

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
python-sdk Patch
eppo_core Patch
ruby-sdk Patch
elixir-sdk Patch
rust-sdk Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Comment on lines +39 to +49
// Check environment variable for experimental CityHash support
let bandit_hashing_algorithm = std::env::var("EPPO_EXPERIMENTAL_BANDITS_CITYHASH")
.ok()
.and_then(|val| {
if val == "1" || val == "true" || val == "TRUE" {
Some(BanditHashingAlgorithm::CityHash)
} else {
None
}
})
.unwrap_or(BanditHashingAlgorithm::Md5);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Don't want to read env variable on the hot evaluation path, so reading it here (which usually happens in background thread)

subject_key,
subject_attributes,
actions.iter(),
configuration.bandit_hashing_algorithm,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

^ new parameter (caused a bit of reformatting in this section)

// Compute selection hash once
let selection_hash = {
let hash = base_ctx.clone().finish();
hash as u32 as f64 / u32::MAX as f64

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

"sharding" by 10k was arbitrary and somewhat useless, so using truncation to 32-bits in the new algorithm (which should be a tad faster and less biased)

@dd-oleksii
dd-oleksii force-pushed the oleksii/jj-kxmvnnwxmlwp branch from 831dd10 to 99f5019 Compare January 5, 2026 06:07
Comment on lines +249 to +258
trait BanditHasher: Clone {
/// Create a new hasher pre-initialized with flag_key + "-" + subject_key
fn new(flag_key: &str, subject_key: &str) -> Self;

/// Get the selection hash (0.0..1.0) for choosing action based on weights
fn selection_hash(&self) -> f64;

/// Compute hash for shuffling a specific action
fn action_shuffle_hash(&self, action_key: &str) -> u64;
}

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 job distilling the universal hashing operations needed for bandits here

None
}
})
.unwrap_or(BanditHashingAlgorithm::Md5);

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 use of strategy pattern!

@dd-oleksii
dd-oleksii merged commit aa6130d into main Jan 7, 2026
45 checks passed
@dd-oleksii
dd-oleksii deleted the oleksii/jj-kxmvnnwxmlwp branch January 7, 2026 09:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants