226 lines
6.2 KiB
Rust
226 lines
6.2 KiB
Rust
// 调度器保持存活,计时包含输入复制、提交、结果领取和作用域清理。
|
|
// 独立参照针对同样的一层双任务/worker/计时器,不能代表任意嵌套并发已验收。
|
|
use dever_runtime::task::{Limits, Runtime};
|
|
|
|
struct TaskCase {
|
|
generated: Runtime,
|
|
native: NativeTasks,
|
|
values: Vec<i64>,
|
|
}
|
|
|
|
fn new_runtime() -> Runtime {
|
|
Runtime::new(Limits {
|
|
threads: 2,
|
|
workers: 2,
|
|
tasks: 8,
|
|
})
|
|
.unwrap()
|
|
}
|
|
|
|
fn generated_sync(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
let Some(value) = values.first() else {
|
|
return Ok(0);
|
|
};
|
|
value
|
|
.generated
|
|
.run(async |scope| { GENERATED_SYNC(&value.values, scope).await })
|
|
.map_err(task_fault)?
|
|
.map_err(task_fault)
|
|
}
|
|
|
|
fn reference_sync(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
values
|
|
.first()
|
|
.map_or(Ok(0), |value| value.native.pair(&value.values, false))
|
|
}
|
|
|
|
fn generated_async(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
let Some(value) = values.first() else {
|
|
return Ok(0);
|
|
};
|
|
value
|
|
.generated
|
|
.run(async |scope| { GENERATED_ASYNC(&value.values, scope).await })
|
|
.map_err(task_fault)?
|
|
.map_err(task_fault)
|
|
}
|
|
|
|
fn reference_async(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
values
|
|
.first()
|
|
.map_or(Ok(0), |value| value.native.pair(&value.values, true))
|
|
}
|
|
|
|
fn generated_parallel(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
let Some(value) = values.first() else {
|
|
return Ok(0);
|
|
};
|
|
value
|
|
.generated
|
|
.run(async |scope| { GENERATED_PARALLEL(&value.values, scope).await })
|
|
.map_err(task_fault)?
|
|
.map_err(task_fault)
|
|
}
|
|
|
|
fn reference_parallel(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
values
|
|
.first()
|
|
.map_or(Ok(0), |value| value.native.blocking(&value.values, false))
|
|
}
|
|
|
|
fn generated_blocking(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
let Some(value) = values.first() else {
|
|
return Ok(0);
|
|
};
|
|
value
|
|
.generated
|
|
.run(async |scope| { GENERATED_BLOCKING(&value.values, scope).await })
|
|
.map_err(task_fault)?
|
|
.map_err(task_fault)
|
|
}
|
|
|
|
fn reference_blocking(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
values
|
|
.first()
|
|
.map_or(Ok(0), |value| value.native.blocking(&value.values, true))
|
|
}
|
|
|
|
fn generated_cancel(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
let Some(value) = values.first() else {
|
|
return Ok(0);
|
|
};
|
|
value
|
|
.generated
|
|
.run(async |scope| { GENERATED_CANCEL(scope).await })
|
|
.map_err(task_fault)?
|
|
.map_err(task_fault)
|
|
}
|
|
|
|
fn reference_cancel(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
values.first().map_or(Ok(0), |value| value.native.cancel())
|
|
}
|
|
|
|
fn generated_timer(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
let Some(value) = values.first() else {
|
|
return Ok(0);
|
|
};
|
|
value
|
|
.generated
|
|
.run_leaf(GENERATED_TIMER())
|
|
.map_err(task_fault)?
|
|
.map_err(task_fault)
|
|
}
|
|
|
|
fn reference_timer(values: &[TaskCase]) -> Result<i64, Fault> {
|
|
values.first().map_or(Ok(0), |value| value.native.timer())
|
|
}
|
|
|
|
fn generated_fault(values: &[TaskCase]) -> Result<bool, Fault> {
|
|
Ok(generated_sync(values).is_err())
|
|
}
|
|
fn reference_fault(values: &[TaskCase]) -> Result<bool, Fault> {
|
|
Ok(reference_sync(values).is_err())
|
|
}
|
|
|
|
fn main() {
|
|
if std::env::args().any(|argument| argument == "--check-cancel-cleanup") {
|
|
check_cancel_cleanup();
|
|
return;
|
|
}
|
|
if std::env::args().any(|argument| argument == "--check-worker-cleanup") {
|
|
check_worker_cleanup();
|
|
return;
|
|
}
|
|
let cases = [TaskCase {
|
|
generated: new_runtime(),
|
|
native: NativeTasks::new(),
|
|
values: (0..128).collect(),
|
|
}];
|
|
let expected = native_total(&cases[0].values).unwrap();
|
|
assert_eq!(generated_sync(&cases).unwrap(), expected * 2);
|
|
assert_eq!(generated_async(&cases).unwrap(), expected * 2);
|
|
assert_eq!(generated_parallel(&cases).unwrap(), expected);
|
|
assert_eq!(generated_blocking(&cases).unwrap(), expected);
|
|
assert_eq!(generated_cancel(&cases).unwrap(), 1);
|
|
println!("case,sample,implementation,elapsed_ns,checksum");
|
|
compare(
|
|
"task_sync_pair",
|
|
&cases,
|
|
500,
|
|
generated_sync,
|
|
reference_sync,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"task_async_pair",
|
|
&cases,
|
|
1000,
|
|
generated_async,
|
|
reference_async,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"task_parallel",
|
|
&cases,
|
|
500,
|
|
generated_parallel,
|
|
reference_parallel,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"task_blocking",
|
|
&cases,
|
|
500,
|
|
generated_blocking,
|
|
reference_blocking,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"task_cancel",
|
|
&cases,
|
|
1000,
|
|
generated_cancel,
|
|
reference_cancel,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"task_timer_zero",
|
|
&cases,
|
|
10,
|
|
generated_timer,
|
|
reference_timer,
|
|
|value| *value as u64,
|
|
);
|
|
let failures = [TaskCase {
|
|
generated: new_runtime(),
|
|
native: NativeTasks::new(),
|
|
values: vec![i64::MAX, 1],
|
|
}];
|
|
assert!(generated_fault(&failures).unwrap());
|
|
assert!(generated_async(&failures).is_err());
|
|
assert!(reference_async(&failures).is_err());
|
|
assert!(shared_async(&failures).is_err());
|
|
assert!(shared_worker::<false>(&failures).is_err());
|
|
assert!(shared_worker::<true>(&failures).is_err());
|
|
assert!(generated_nested(&failures).is_err());
|
|
assert!(reference_nested(&failures).is_err());
|
|
compare(
|
|
"task_sync_fault",
|
|
&failures,
|
|
500,
|
|
generated_fault,
|
|
reference_fault,
|
|
|value| u64::from(*value),
|
|
);
|
|
assert!(generated_async_steady(&failures).is_err());
|
|
assert!(reference_async_steady(&failures).is_err());
|
|
assert!(reference_async_tracked(&failures).is_err());
|
|
assert!(reference_async_typed(&failures).is_err());
|
|
drop(failures);
|
|
lifecycle(&cases);
|
|
shared_runtime(&cases);
|
|
worker_steady(&cases);
|
|
worker_scoped(&cases);
|
|
cancel_scoped(&cases);
|
|
}
|