Initial Dever 0.0.1

This commit is contained in:
Codex committed 2026-11-03 03:32:07 +00:00
commit 81233d098c
1479 files changed
+163782

No files matched your search

+404
View File
@@ -0,0 +1,404 @@
// 保留原单次入口参照,另外区分入口成本和同一入口内连续执行的任务成本。
// 每个 steady 样本仍逐次创建、等待并清理真实任务,只复用父入口。
const CONTINUOUS_CALLS: usize = 16;
// 与 Dever async_total 保持同样的可失败计时分支和携带文本的错误合同,不加填充字段。
enum NativeAsyncFailure {
Fault(Fault),
Sleep(String, Fault),
}
impl From<Fault> for NativeAsyncFailure {
fn from(value: Fault) -> Self {
Self::Fault(value)
}
}
impl From<NativeAsyncFailure> for Fault {
fn from(value: NativeAsyncFailure) -> Self {
match value {
NativeAsyncFailure::Fault(fault) => fault,
NativeAsyncFailure::Sleep(message, fault) => {
drop(message);
fault
}
}
}
}
async fn native_fallible_sleep(millis: i64) -> Result<(), NativeAsyncFailure> {
let fail = |message: &str| NativeAsyncFailure::Sleep(message.to_owned(), task_fault("timer"));
let millis = u64::try_from(millis).map_err(|_| fail("sleep duration must be nonnegative"))?;
let deadline = tokio::time::Instant::now()
.checked_add(Duration::from_millis(millis))
.ok_or_else(|| fail("sleep deadline is out of range"))?;
tokio::time::sleep_until(deadline).await;
Ok(())
}
async fn native_async_total(values: Vec<i64>, delayed: bool) -> Result<i64, NativeAsyncFailure> {
if delayed {
native_fallible_sleep(0).await?;
}
native_total(&values).map_err(Into::into)
}
// 仅作成本诊断:保留原始 Rust 参照,另测附带完成跟踪的相同双任务负载。
// 元组先放返回值再放令牌,未领取结果的析构顺序与生产运行库相同。
fn native_tracked<Failure, Work>(
native: &NativeTasks,
work: Work,
cancel: CancellationToken,
tracking: tokio_util::task::task_tracker::TaskTrackerToken,
) -> JoinHandle<(
Result<i64, Failure>,
tokio_util::task::task_tracker::TaskTrackerToken,
)>
where
Failure: From<Fault> + Send + 'static,
Work: std::future::Future<Output = Result<i64, Failure>> + Send + 'static,
{
let admission = native.tasks.clone().try_acquire_owned().unwrap();
let workers = native.workers.clone();
tokio::spawn(async move {
let tracking = tracking;
let result = tokio::select! {
biased;
result = work => result,
() = cancel.cancelled() => Err(task_fault("cancelled").into()),
};
drop(workers);
drop(admission);
(result, tracking)
})
}
fn reference_async_tracked(values: &[TaskCase]) -> Result<i64, Fault> {
reference_tracked(values, |values| async move { native_total(&values) })
}
fn reference_async_typed(values: &[TaskCase]) -> Result<i64, Fault> {
reference_tracked(values, |values| native_async_total(values, false))
}
fn reference_tracked<Failure, Work>(
values: &[TaskCase],
call: impl Fn(Vec<i64>) -> Work,
) -> Result<i64, Fault>
where
Failure: From<Fault> + Into<Fault> + Send + 'static,
Work: std::future::Future<Output = Result<i64, Failure>> + Send + 'static,
{
let Some(value) = values.first() else {
return Ok(0);
};
value.native.runtime.block_on(async {
let cancel = CancellationToken::new();
let tasks = tokio_util::task::TaskTracker::new();
let outcome = async {
let mut total = 0i64;
for _ in 0..CONTINUOUS_CALLS {
let first = native_tracked(
&value.native,
call(value.values.clone()),
cancel.child_token(),
tasks.token(),
);
let second = native_tracked(
&value.native,
call(value.values.clone()),
cancel.child_token(),
tasks.token(),
);
let first = first
.await
.map_err(task_fault)
.and_then(|(result, _tracking)| result.map_err(Into::into));
if first.is_err() {
cancel.cancel();
}
let second = second
.await
.map_err(task_fault)
.and_then(|(result, _tracking)| result.map_err(Into::into));
let result = first?
.checked_add(second?)
.ok_or_else(|| task_fault("integer overflow"))?;
total = total
.checked_add(result)
.ok_or_else(|| task_fault("integer overflow"))?;
}
Ok(total)
}
.await;
cancel.cancel();
tasks.close();
tasks.wait().await;
outcome
})
}
fn generated_entry(values: &[TaskCase]) -> Result<i64, Fault> {
let Some(value) = values.first() else {
return Ok(0);
};
value.generated.run(async |_| 1i64).map_err(task_fault)
}
fn reference_entry(values: &[TaskCase]) -> Result<i64, Fault> {
let Some(value) = values.first() else {
return Ok(0);
};
Ok(value.native.runtime.block_on(async { 1i64 }))
}
fn generated_leaf_entry(values: &[TaskCase]) -> Result<i64, Fault> {
let Some(value) = values.first() else { return Ok(0); };
value.generated.run_leaf(async { 1i64 }).map_err(task_fault)
}
fn generated_async_steady(values: &[TaskCase]) -> Result<i64, Fault> {
let Some(value) = values.first() else {
return Ok(0);
};
value
.generated
.run(async |scope| {
let mut total = 0i64;
for _ in 0..CONTINUOUS_CALLS {
let result = GENERATED_ASYNC(&value.values, scope)
.await
.map_err(task_fault)?;
total = total
.checked_add(result)
.ok_or_else(|| task_fault("integer overflow"))?;
}
Ok(total)
})
.map_err(task_fault)?
}
fn reference_async_steady(values: &[TaskCase]) -> Result<i64, Fault> {
let Some(value) = values.first() else {
return Ok(0);
};
value.native.runtime.block_on(async {
let cancel = CancellationToken::new();
let mut total = 0i64;
for _ in 0..CONTINUOUS_CALLS {
let first = value
.native
.start(value.values.clone(), true, cancel.child_token());
let second = value
.native
.start(value.values.clone(), true, cancel.child_token());
let first = first.await.map_err(task_fault).and_then(|result| result);
if first.is_err() {
cancel.cancel();
}
let second = second.await.map_err(task_fault).and_then(|result| result);
let result = first?
.checked_add(second?)
.ok_or_else(|| task_fault("integer overflow"))?;
total = total
.checked_add(result)
.ok_or_else(|| task_fault("integer overflow"))?;
}
cancel.cancel();
Ok(total)
})
}
fn generated_cancel_steady(values: &[TaskCase]) -> Result<i64, Fault> {
let Some(value) = values.first() else {
return Ok(0);
};
value
.generated
.run(async |scope| {
let mut total = 0i64;
for _ in 0..CONTINUOUS_CALLS {
let result = GENERATED_CANCEL(scope).await.map_err(task_fault)?;
total = total
.checked_add(result)
.ok_or_else(|| task_fault("integer overflow"))?;
}
Ok(total)
})
.map_err(task_fault)?
}
fn reference_cancel_steady(values: &[TaskCase]) -> Result<i64, Fault> {
let Some(value) = values.first() else {
return Ok(0);
};
value.native.runtime.block_on(async {
let root = CancellationToken::new();
let mut total = 0i64;
for _ in 0..CONTINUOUS_CALLS {
let admission = value.native.tasks.clone().try_acquire_owned().unwrap();
let cancel = root.child_token();
let child = cancel.clone();
let task = tokio::spawn(async move {
let deadline = tokio::time::Instant::now()
.checked_add(Duration::from_millis(60000))
.unwrap();
tokio::select! {
biased;
() = tokio::time::sleep_until(deadline) => panic!("cancelled timer completed"),
() = child.cancelled() => (),
}
drop(admission);
});
cancel.cancel();
task.await.map_err(task_fault)?;
total = total
.checked_add(1)
.ok_or_else(|| task_fault("integer overflow"))?;
}
root.cancel();
Ok(total)
})
}
// 取消机制采用标准 JoinHandle::abort 的独立 Rust 对照;原 token 对照继续保留。
fn reference_cancel_abort(values: &[TaskCase]) -> Result<i64, Fault> {
let Some(value) = values.first() else { return Ok(0); };
value.native.runtime.block_on(async {
let admission = value.native.tasks.clone().try_acquire_owned().unwrap();
let task = tokio::spawn(async move {
let _admission = admission;
let deadline = tokio::time::Instant::now()
.checked_add(Duration::from_millis(60000))
.ok_or_else(|| task_fault("sleep deadline"))?;
tokio::time::sleep_until(deadline).await;
Ok::<(), Fault>(())
});
task.abort();
match task.await {
Err(error) if error.is_cancelled() => Ok(1),
Err(error) => Err(task_fault(error)),
Ok(result) => { result?; Err(task_fault("cancelled timer completed")) }
}
})
}
fn lifecycle(cases: &[TaskCase]) {
let expected = native_total(&cases[0].values).unwrap() * 2 * CONTINUOUS_CALLS as i64;
assert_eq!(generated_async_steady(cases).unwrap(), expected);
assert_eq!(reference_async_steady(cases).unwrap(), expected);
assert_eq!(reference_async_tracked(cases).unwrap(), expected);
assert_eq!(reference_async_typed(cases).unwrap(), expected);
let native = &cases[0].native;
assert_eq!(
native
.runtime
.block_on(native_async_total(cases[0].values.clone(), true))
.map_err(Fault::from)
.unwrap(),
expected / CONTINUOUS_CALLS as i64 / 2
);
assert!(native.runtime.block_on(native_fallible_sleep(-1)).is_err());
eprintln!(
"result-layout: rust_typed_async={}",
std::mem::size_of::<Result<i64, NativeAsyncFailure>>()
);
assert_eq!(
generated_cancel_steady(cases).unwrap(),
CONTINUOUS_CALLS as i64
);
assert_eq!(
reference_cancel_steady(cases).unwrap(),
CONTINUOUS_CALLS as i64
);
cases[0]
.generated
.run(async |scope| {
eprintln!(
"task-layout: task={} optional_task={}",
std::mem::size_of::<dever_runtime::task::Task<()>>(),
std::mem::size_of::<Option<dever_runtime::task::Task<()>>>(),
);
eprintln!(
"future-layout: fault={} dever_pair={} rust_pair={} dever_cancel={} rust_cancel={}",
std::mem::size_of::<Fault>(),
std::mem::size_of_val(&GENERATED_ASYNC(&cases[0].values, scope)),
std::mem::size_of_val(&handwritten_pair(scope, &cases[0].values)),
std::mem::size_of_val(&GENERATED_CANCEL(scope)),
std::mem::size_of_val(&handwritten_cancel(scope)),
);
let result = GENERATED_ASYNC(&cases[0].values, scope).await;
eprintln!(
"result-layout: dever_async={} rust_async={}",
std::mem::size_of_val(&result),
std::mem::size_of::<Result<i64, Fault>>()
);
let result = GENERATED_CANCEL(scope).await;
eprintln!(
"result-layout: dever_cancel={} rust_cancel={}",
std::mem::size_of_val(&result),
std::mem::size_of::<Result<i64, Fault>>()
);
})
.unwrap();
compare(
"task_entry_ready",
cases,
100000,
generated_entry,
reference_entry,
|value| *value as u64,
);
compare(
"task_leaf_entry_ready",
cases,
100000,
generated_leaf_entry,
reference_entry,
|value| *value as u64,
);
compare(
"task_async_steady",
cases,
64,
generated_async_steady,
reference_async_steady,
|value| *value as u64,
);
compare(
"task_cancel_steady",
cases,
64,
generated_cancel_steady,
reference_cancel_steady,
|value| *value as u64,
);
compare_named(
"task_async_tracked_diagnostic",
cases,
64,
generated_async_steady,
reference_async_tracked,
|value| *value as u64,
"rust_tracked",
);
compare_named(
"task_async_typed_diagnostic",
cases,
64,
generated_async_steady,
reference_async_typed,
|value| *value as u64,
"rust_typed",
);
compare_named(
"task_cancel_abort_diagnostic",
cases,
1000,
generated_cancel,
reference_cancel_abort,
|value| *value as u64,
"rust_abort",
);
}