use alec::*;
use std::time::Instant;
#[test]
#[ignore] fn stress_test_encoding() {
let mut encoder = Encoder::new();
let classifier = Classifier::default();
let mut context = Context::new();
let iterations = 1_000_000;
let start = Instant::now();
for i in 0..iterations {
let data = RawData::new(20.0 + (i as f64 * 0.001).sin(), i as u64);
let classification = classifier.classify(&data, &context);
let _message = encoder.encode(&data, &classification, &context);
context.observe(&data);
}
let elapsed = start.elapsed();
let rate = iterations as f64 / elapsed.as_secs_f64();
println!("Encoded {} messages in {:?}", iterations, elapsed);
println!("Rate: {:.0} messages/second", rate);
assert!(
rate > 100_000.0,
"Should encode at least 100k msg/s, got {:.0}",
rate
);
}
#[test]
#[ignore]
fn stress_test_roundtrip() {
let mut encoder = Encoder::new();
let mut decoder = Decoder::new();
let classifier = Classifier::default();
let mut ctx_enc = Context::new();
let mut ctx_dec = Context::new();
let iterations = 100_000;
let start = Instant::now();
for i in 0..iterations {
let data = RawData::new(20.0 + (i as f64 * 0.01).sin() * 5.0, i as u64);
let classification = classifier.classify(&data, &ctx_enc);
let message = encoder.encode(&data, &classification, &ctx_enc);
let decoded = decoder.decode(&message, &ctx_dec).unwrap();
assert!(
(decoded.value - data.value).abs() < 0.1,
"Roundtrip failed at iteration {}: {} vs {}",
i,
data.value,
decoded.value
);
ctx_enc.observe(&data);
ctx_dec.observe(&data);
}
let elapsed = start.elapsed();
let rate = iterations as f64 / elapsed.as_secs_f64();
println!("Roundtrip {} messages in {:?}", iterations, elapsed);
println!("Rate: {:.0} messages/second", rate);
assert!(
rate > 50_000.0,
"Should roundtrip at least 50k msg/s, got {:.0}",
rate
);
}
#[test]
#[ignore]
fn stress_test_fleet() {
let mut fleet = FleetManager::new();
let classifier = Classifier::default();
let num_emitters = 100;
let messages_per_emitter = 1000;
let mut encoders: Vec<_> = (0..num_emitters)
.map(|_| (Encoder::new(), Context::new()))
.collect();
let start = Instant::now();
for t in 0..messages_per_emitter {
for (emitter_id, (encoder, context)) in encoders.iter_mut().enumerate() {
let temp = 20.0 + (emitter_id as f64 * 0.1) + (t as f64 * 0.01).sin();
let data = RawData::new(temp, t as u64);
let classification = classifier.classify(&data, context);
let message = encoder.encode(&data, &classification, context);
fleet
.process_message(emitter_id as u32, &message, t as u64)
.unwrap();
context.observe(&data);
}
}
let elapsed = start.elapsed();
let total_messages = num_emitters * messages_per_emitter;
let rate = total_messages as f64 / elapsed.as_secs_f64();
println!(
"Fleet processed {} messages in {:?}",
total_messages, elapsed
);
println!("Rate: {:.0} messages/second", rate);
assert!(
rate > 10_000.0,
"Should process at least 10k msg/s, got {:.0}",
rate
);
}
#[test]
#[ignore]
fn stress_test_context_evolution() {
use alec::context::EvolutionConfig;
let mut context = Context::with_evolution(EvolutionConfig {
min_frequency: 2,
max_age: 10000,
evolution_interval: 100,
promotion_threshold: 5,
enabled: true,
});
let iterations = 100_000;
let start = Instant::now();
for i in 0..iterations {
let value = match i % 10 {
0 => 0.0, 1 => i as f64 * 0.1, 2 => (i as f64 * 0.1).sin() * 100.0, 3 => {
if i % 2 == 0 {
10.0
} else {
20.0
}
} _ => 50.0 + (i % 100) as f64, };
let data = RawData::new(value, i as u64);
context.observe(&data);
if i % 1000 == 0 {
context.evolve();
}
}
let elapsed = start.elapsed();
let rate = iterations as f64 / elapsed.as_secs_f64();
println!(
"Context evolution processed {} observations in {:?}",
iterations, elapsed
);
println!("Rate: {:.0} observations/second", rate);
println!("Final pattern count: {}", context.pattern_count());
assert!(
rate > 100_000.0,
"Should process at least 100k observations/s, got {:.0}",
rate
);
}
#[test]
#[ignore]
fn stress_test_classifier() {
let classifier = Classifier::default();
let context = Context::new();
let iterations = 1_000_000;
let start = Instant::now();
for i in 0..iterations {
let value = match i % 5 {
0 => -100.0, 1 => 150.0, 2 => (i as f64 * 0.001).sin() * 10.0, 3 => 50.0, _ => i as f64 % 100.0, };
let data = RawData::new(value, i as u64);
let _classification = classifier.classify(&data, &context);
}
let elapsed = start.elapsed();
let rate = iterations as f64 / elapsed.as_secs_f64();
println!("Classified {} messages in {:?}", iterations, elapsed);
println!("Rate: {:.0} classifications/second", rate);
assert!(
rate > 1_000_000.0,
"Should classify at least 1M msg/s, got {:.0}",
rate
);
}
#[test]
#[ignore]
fn stress_test_multi_value_encoding() {
use alec::protocol::Priority;
let mut encoder = Encoder::new();
let mut decoder = Decoder::new();
let mut ctx = Context::new();
let iterations = 50_000;
let values_per_message = 5;
let start = Instant::now();
for i in 0..iterations {
let base_timestamp = (i * values_per_message) as u64;
let mut values: Vec<(u8, f64)> = Vec::with_capacity(values_per_message);
for j in 0..values_per_message {
let value = 20.0 + (((i * values_per_message + j) as f64) * 0.01).sin() * 5.0;
values.push((j as u8, value));
}
let message =
encoder.encode_multi(&values, i as u32, base_timestamp, Priority::P3Normal, &ctx);
let decoded = decoder.decode_multi(&message, &ctx).unwrap();
assert_eq!(decoded.len(), values.len());
for (name_id, value) in &values {
ctx.observe(&RawData::new(*value, base_timestamp + *name_id as u64));
}
}
let elapsed = start.elapsed();
let total_values = iterations * values_per_message;
let rate = total_values as f64 / elapsed.as_secs_f64();
println!(
"Multi-value encoded {} values in {:?}",
total_values, elapsed
);
println!("Rate: {:.0} values/second", rate);
assert!(
rate > 100_000.0,
"Should encode at least 100k values/s, got {:.0}",
rate
);
}
#[test]
#[ignore]
fn stress_test_sync_messages() {
use alec::context::Pattern;
use alec::sync::{SyncAnnounce, SyncDiff, SyncMessage, SyncRequest};
let iterations = 100_000;
let start = Instant::now();
for i in 0..iterations {
let msg = match i % 4 {
0 => SyncMessage::Announce(SyncAnnounce {
version: i as u32,
hash: (i as u64) * 12345,
pattern_count: (i % 100) as u16,
}),
1 => SyncMessage::Request(SyncRequest {
from_version: i as u32,
to_version: Some((i + 10) as u32),
}),
2 => SyncMessage::Diff(SyncDiff {
base_version: i as u32,
new_version: (i + 1) as u32,
added: vec![(i as u32, Pattern::new(vec![1, 2, 3]))],
removed: vec![],
hash: (i as u64) * 54321,
}),
_ => SyncMessage::ReqDetail(i as u32),
};
let bytes = msg.to_bytes();
let _decoded = SyncMessage::from_bytes(&bytes).unwrap();
}
let elapsed = start.elapsed();
let rate = iterations as f64 / elapsed.as_secs_f64();
println!(
"Sync message roundtrip {} messages in {:?}",
iterations, elapsed
);
println!("Rate: {:.0} messages/second", rate);
assert!(
rate > 50_000.0,
"Should process at least 50k sync messages/s, got {:.0}",
rate
);
}
#[test]
#[ignore]
fn stress_test_memory_usage() {
let mut context = Context::new();
let mut encoder = Encoder::new();
let classifier = Classifier::default();
let initial_patterns = context.pattern_count();
for i in 0..10_000 {
let data = RawData::new(20.0 + (i as f64 * 0.1).sin() * 10.0, i as u64);
let classification = classifier.classify(&data, &context);
let _msg = encoder.encode(&data, &classification, &context);
context.observe(&data);
}
let final_patterns = context.pattern_count();
let estimated_memory = context.estimated_memory();
println!("Initial patterns: {}", initial_patterns);
println!("Final patterns: {}", final_patterns);
println!("Estimated memory: {} bytes", estimated_memory);
assert!(
estimated_memory < 1_000_000,
"Memory usage should be under 1MB, got {} bytes",
estimated_memory
);
}
#[test]
#[ignore]
fn stress_test_concurrent_fleet() {
use std::sync::{Arc, Mutex};
use std::thread;
let fleet = Arc::new(Mutex::new(FleetManager::new()));
let num_threads = 4;
let messages_per_thread = 10_000;
let start = Instant::now();
let handles: Vec<_> = (0..num_threads)
.map(|thread_id| {
let fleet = Arc::clone(&fleet);
thread::spawn(move || {
let mut encoder = Encoder::new();
let classifier = Classifier::default();
let mut context = Context::new();
for i in 0..messages_per_thread {
let data = RawData::new(
20.0 + (thread_id as f64) + (i as f64 * 0.01).sin(),
i as u64,
);
let classification = classifier.classify(&data, &context);
let message = encoder.encode(&data, &classification, &context);
let emitter_id = (thread_id * 100 + (i % 10)) as u32;
fleet
.lock()
.unwrap()
.process_message(emitter_id, &message, i as u64)
.unwrap();
context.observe(&data);
}
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
let elapsed = start.elapsed();
let total_messages = num_threads * messages_per_thread;
let rate = total_messages as f64 / elapsed.as_secs_f64();
println!(
"Concurrent fleet processed {} messages in {:?}",
total_messages, elapsed
);
println!("Rate: {:.0} messages/second", rate);
assert!(
rate > 5_000.0,
"Should process at least 5k msg/s concurrently, got {:.0}",
rate
);
}