use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScaleConfig {
pub device_count: usize,
pub points_per_device: usize,
pub batch_size: usize,
pub memory_per_device: usize,
pub concurrent_connections: usize,
pub target_ops_per_sec: u64,
}
impl Default for ScaleConfig {
fn default() -> Self {
Self::medium()
}
}
impl ScaleConfig {
pub fn devices(count: usize) -> Self {
Self {
device_count: count,
points_per_device: 100,
batch_size: (count / 100).max(100),
memory_per_device: 4096,
concurrent_connections: (count / 100).max(10),
target_ops_per_sec: (count * 10) as u64,
}
}
pub fn tiny() -> Self {
Self {
device_count: 10,
points_per_device: 10,
batch_size: 10,
memory_per_device: 1024,
concurrent_connections: 5,
target_ops_per_sec: 100,
}
}
pub fn small() -> Self {
Self {
device_count: 100,
points_per_device: 50,
batch_size: 50,
memory_per_device: 2048,
concurrent_connections: 20,
target_ops_per_sec: 1000,
}
}
pub fn medium() -> Self {
Self {
device_count: 1_000,
points_per_device: 100,
batch_size: 100,
memory_per_device: 4096,
concurrent_connections: 100,
target_ops_per_sec: 10_000,
}
}
pub fn large() -> Self {
Self {
device_count: 10_000,
points_per_device: 100,
batch_size: 500,
memory_per_device: 4096,
concurrent_connections: 500,
target_ops_per_sec: 100_000,
}
}
pub fn xlarge() -> Self {
Self {
device_count: 50_000,
points_per_device: 100,
batch_size: 1000,
memory_per_device: 4096,
concurrent_connections: 1000,
target_ops_per_sec: 500_000,
}
}
pub fn max() -> Self {
Self {
device_count: 100_000,
points_per_device: 100,
batch_size: 2000,
memory_per_device: 4096,
concurrent_connections: 2000,
target_ops_per_sec: 1_000_000,
}
}
pub fn with_device_count(mut self, count: usize) -> Self {
self.device_count = count;
self
}
pub fn with_points_per_device(mut self, count: usize) -> Self {
self.points_per_device = count;
self
}
pub fn with_batch_size(mut self, size: usize) -> Self {
self.batch_size = size;
self
}
pub fn with_memory_per_device(mut self, bytes: usize) -> Self {
self.memory_per_device = bytes;
self
}
pub fn total_points(&self) -> usize {
self.device_count * self.points_per_device
}
pub fn estimated_memory(&self) -> usize {
self.device_count * self.memory_per_device
}
pub fn estimated_memory_mb(&self) -> f64 {
self.estimated_memory() as f64 / 1024.0 / 1024.0
}
pub fn description(&self) -> String {
format!(
"{} devices, {} points/device ({} total), ~{:.1} MB",
self.device_count,
self.points_per_device,
self.total_points(),
self.estimated_memory_mb()
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ScalePreset {
Tiny,
Small,
Medium,
Large,
XLarge,
Max,
}
impl ScalePreset {
pub fn to_config(self) -> ScaleConfig {
match self {
Self::Tiny => ScaleConfig::tiny(),
Self::Small => ScaleConfig::small(),
Self::Medium => ScaleConfig::medium(),
Self::Large => ScaleConfig::large(),
Self::XLarge => ScaleConfig::xlarge(),
Self::Max => ScaleConfig::max(),
}
}
pub fn all() -> &'static [ScalePreset] {
&[
Self::Tiny,
Self::Small,
Self::Medium,
Self::Large,
Self::XLarge,
Self::Max,
]
}
}
impl From<ScalePreset> for ScaleConfig {
fn from(preset: ScalePreset) -> Self {
preset.to_config()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scale_presets() {
assert_eq!(ScaleConfig::tiny().device_count, 10);
assert_eq!(ScaleConfig::small().device_count, 100);
assert_eq!(ScaleConfig::medium().device_count, 1_000);
assert_eq!(ScaleConfig::large().device_count, 10_000);
assert_eq!(ScaleConfig::xlarge().device_count, 50_000);
assert_eq!(ScaleConfig::max().device_count, 100_000);
}
#[test]
fn test_scale_devices() {
let config = ScaleConfig::devices(5000);
assert_eq!(config.device_count, 5000);
}
#[test]
fn test_total_points() {
let config = ScaleConfig::devices(100).with_points_per_device(50);
assert_eq!(config.total_points(), 5000);
}
#[test]
fn test_estimated_memory() {
let config = ScaleConfig::devices(1024).with_memory_per_device(1024);
assert_eq!(config.estimated_memory(), 1024 * 1024);
assert!((config.estimated_memory_mb() - 1.0).abs() < 0.01);
}
#[test]
fn test_scale_preset_conversion() {
let config: ScaleConfig = ScalePreset::Large.into();
assert_eq!(config.device_count, 10_000);
}
#[test]
fn test_description() {
let config = ScaleConfig::tiny();
let desc = config.description();
assert!(desc.contains("10 devices"));
}
}