refactor: consolidate some tests/examples/benchmarks
This commit is contained in:
1 parent
49be497964
commit
b8204c4ed9
83 files changed
+569
-10068
No files matched your search
+151
-3
@@ -1,8 +1,11 @@
|
||||
//! Tests for timing and speedup verification
|
||||
|
||||
use dagx::{task, DagResult, DagRunner};
|
||||
use dagx::{task, task_fn, DagResult, DagRunner};
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tokio::time::sleep;
|
||||
|
||||
struct SleepTask(usize, Duration);
|
||||
@@ -49,7 +52,7 @@ async fn test_parallel_execution_speedup() -> DagResult<()> {
|
||||
|
||||
// Parallel execution should be significantly faster
|
||||
assert!(
|
||||
elapsed < sequential_time / 2,
|
||||
elapsed < sequential_time / 4,
|
||||
"Parallel execution too slow: {:?} vs sequential {:?}",
|
||||
elapsed,
|
||||
sequential_time
|
||||
@@ -57,3 +60,148 @@ async fn test_parallel_execution_speedup() -> DagResult<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_layers_execute_in_parallel() -> DagResult<()> {
|
||||
// Test that tasks in the same topological layer execute in parallel
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let layer_timing = Arc::new(Mutex::new(Vec::new()));
|
||||
|
||||
struct Layer0Task {
|
||||
timing: Arc<Mutex<Vec<(String, Instant)>>>,
|
||||
idx: i32,
|
||||
}
|
||||
|
||||
#[task]
|
||||
impl Layer0Task {
|
||||
async fn run(&self) -> i32 {
|
||||
let start = Instant::now();
|
||||
self.timing
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((format!("L0_{}", self.idx), start));
|
||||
sleep(Duration::from_millis(20)).await;
|
||||
self.idx * 10
|
||||
}
|
||||
}
|
||||
|
||||
// Layer 0: 3 independent sources
|
||||
let sources: Vec<_> = (0..3)
|
||||
.map(|i| {
|
||||
dag.add_task(Layer0Task {
|
||||
timing: layer_timing.clone(),
|
||||
idx: i,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
struct Layer1Task {
|
||||
timing: Arc<Mutex<Vec<(String, Instant)>>>,
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
#[task]
|
||||
impl Layer1Task {
|
||||
async fn run(&self, x: &i32) -> i32 {
|
||||
let start = Instant::now();
|
||||
self.timing
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((format!("L1_{}", self.idx), start));
|
||||
sleep(Duration::from_millis(20)).await;
|
||||
x + 1
|
||||
}
|
||||
}
|
||||
|
||||
// Layer 1: Tasks depending on layer 0
|
||||
let layer1: Vec<_> = sources
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, source)| {
|
||||
dag.add_task(Layer1Task {
|
||||
idx: i,
|
||||
timing: layer_timing.clone(),
|
||||
})
|
||||
.depends_on(source)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Layer 2: Final aggregation
|
||||
let final_task = {
|
||||
let timing = layer_timing.clone();
|
||||
dag.add_task(task_fn::<(i32, i32, i32), _, _>(
|
||||
move |(a, b, c): (&i32, &i32, &i32)| {
|
||||
let timing = timing.clone();
|
||||
let start = Instant::now();
|
||||
timing.lock().unwrap().push(("L2_final".to_string(), start));
|
||||
a + b + c
|
||||
},
|
||||
))
|
||||
.depends_on((&layer1[0], &layer1[1], &layer1[2]))
|
||||
};
|
||||
|
||||
dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
|
||||
.await?;
|
||||
|
||||
assert_eq!(dag.get(final_task)?, 33); // (0+1) + (10+1) + (20+1)
|
||||
|
||||
// Analyze timing
|
||||
let timing = layer_timing.lock().unwrap();
|
||||
|
||||
// Get layer 0 start times
|
||||
let l0_times: Vec<Instant> = (0..3)
|
||||
.map(|i| {
|
||||
timing
|
||||
.iter()
|
||||
.find(|(name, _)| name == &format!("L0_{}", i))
|
||||
.map(|(_, t)| *t)
|
||||
.unwrap()
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Get layer 1 start times
|
||||
let l1_times: Vec<Instant> = (0..3)
|
||||
.map(|i| {
|
||||
timing
|
||||
.iter()
|
||||
.find(|(name, _)| name == &format!("L1_{}", i))
|
||||
.map(|(_, t)| *t)
|
||||
.unwrap()
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Layer 0 tasks should all start nearly simultaneously
|
||||
let l0_spread = l0_times
|
||||
.iter()
|
||||
.max()
|
||||
.unwrap()
|
||||
.duration_since(*l0_times.iter().min().unwrap());
|
||||
assert!(
|
||||
l0_spread < Duration::from_millis(5),
|
||||
"Layer 0 tasks should start together, spread was {:?}",
|
||||
l0_spread
|
||||
);
|
||||
|
||||
// Layer 1 tasks should also start nearly simultaneously (after layer 0 completes)
|
||||
let l1_spread = l1_times
|
||||
.iter()
|
||||
.max()
|
||||
.unwrap()
|
||||
.duration_since(*l1_times.iter().min().unwrap());
|
||||
assert!(
|
||||
l1_spread < Duration::from_millis(5),
|
||||
"Layer 1 tasks should start together, spread was {:?}",
|
||||
l1_spread
|
||||
);
|
||||
|
||||
// Layer 1 should start after layer 0
|
||||
let earliest_l1 = *l1_times.iter().min().unwrap();
|
||||
let earliest_l0 = *l0_times.iter().min().unwrap();
|
||||
assert!(
|
||||
earliest_l1 >= earliest_l0 + Duration::from_millis(15),
|
||||
"Layer 1 should start after layer 0 completes"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user