feat: dagrunner, initial version

This commit is contained in:
swaits committed 2025-10-07 16:31:03 -07:00
commit 7412287ee4
122 files changed
+23101

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
//! Memory usage tests
use crate::common::task_fn;
use dagx::DagRunner;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[tokio::test]
async fn test_memory_usage_10000_nodes() {
let dag = Arc::new(DagRunner::new());
// Track approximate memory usage
let before_build = memory_usage_hint();
// Create 10,000 nodes
let tasks: Vec<_> = (0..10_000)
.map(|i| dag.add_task(task_fn(move |_: ()| async move { i })))
.collect();
let after_build = memory_usage_hint();
let build_memory = after_build.saturating_sub(before_build);
println!("Memory for 10k nodes: ~{} bytes", build_memory);
// Execute
dag.run(|fut| {
tokio::spawn(fut);
})
.await
.unwrap();
let after_exec = memory_usage_hint();
let exec_memory = after_exec.saturating_sub(after_build);
println!("Additional memory for execution: ~{} bytes", exec_memory);
// Verify some results
assert_eq!(dag.get(&tasks[0]).unwrap(), 0);
assert_eq!(dag.get(&tasks[9999]).unwrap(), 9999);
// Memory should be reasonable (< 100MB for 10k simple nodes)
assert!(
build_memory < 100_000_000,
"Used too much memory: {} bytes",
build_memory
);
}
fn memory_usage_hint() -> usize {
// Simple memory hint (not precise)
static COUNTER: AtomicUsize = AtomicUsize::new(0);
COUNTER.fetch_add(100_000, Ordering::SeqCst)
}
+4
View File
@@ -0,0 +1,4 @@
//! Performance tests module
pub mod memory;
pub mod stress;
+105
View File
@@ -0,0 +1,105 @@
//! Stress tests and benchmarks
use crate::common::task_fn;
use dagx::DagRunner;
use std::sync::Arc;
use std::time::{Duration, Instant};
#[tokio::test]
async fn test_deep_chain_100_levels() {
let dag = Arc::new(DagRunner::new());
// Create a chain 100 levels deep
let start = Instant::now();
let first = dag.add_task(task_fn(|_: ()| async { 0 }));
let mut handles = vec![(&first).into()];
for _ in 1..=100 {
let next = dag
.add_task(task_fn(move |x: i32| async move { x + 1 }))
.depends_on(handles.last().unwrap());
handles.push(next);
}
let build_time = start.elapsed();
println!("Built 100-level chain in {:?}", build_time);
// Execute
let start = Instant::now();
dag.run(|fut| {
tokio::spawn(fut);
})
.await
.unwrap();
let exec_time = start.elapsed();
println!("Executed 100-level chain in {:?}", exec_time);
assert!(
exec_time < Duration::from_secs(5),
"Execution took too long"
);
// Verify result
assert_eq!(dag.get(handles.last().unwrap()).unwrap(), 100);
}
#[tokio::test]
async fn test_stress_mixed_patterns() {
// Stress test with mixed DAG patterns
let dag = Arc::new(DagRunner::new());
let mut all_tasks = vec![];
// Add various patterns
for i in 0..10 {
// Linear chains
let first = dag.add_task(task_fn(move |_: ()| async move { i * 1000 }));
let mut chain_handles = vec![(&first).into()];
for j in 1..10 {
let next = dag
.add_task(task_fn(move |x: i32| async move { x + j }))
.depends_on(chain_handles.last().unwrap());
chain_handles.push(next);
}
all_tasks.push(*chain_handles.last().unwrap());
// Diamonds
let source = dag.add_task(task_fn(move |_: ()| async move { i * 100 }));
let source_handle: dagx::TaskHandle<i32> = (&source).into();
let left = dag
.add_task(task_fn(|x: i32| async move { x * 2 }))
.depends_on(source_handle);
let right = dag
.add_task(task_fn(|x: i32| async move { x * 3 }))
.depends_on(source_handle);
let merge = dag
.add_task(task_fn(|(l, r): (i32, i32)| async move { l + r }))
.depends_on((&left, &right));
all_tasks.push(merge);
// Fan-outs
let hub = dag.add_task(task_fn(move |_: ()| async move { i }));
let hub_handle: dagx::TaskHandle<i32> = (&hub).into();
for j in 0..5 {
let fan = dag
.add_task(task_fn(move |x: i32| async move { x + j * 10 }))
.depends_on(hub_handle);
all_tasks.push(fan);
}
}
// Execute
let start = Instant::now();
dag.run(|fut| {
tokio::spawn(fut);
})
.await
.unwrap();
let exec_time = start.elapsed();
println!("Executed mixed pattern stress test in {:?}", exec_time);
// Verify some results
for task in all_tasks.iter().take(10) {
assert!(dag.get(task).is_ok());
}
}