docs: record the simulation layer design
This commit is contained in:
parent
a09dd802e0
commit
528c4a8c6d
|
|
@ -4,3 +4,7 @@
|
||||||
分层边界。单个 crate 的内部设计写在对应 crate 的模块文档中。
|
分层边界。单个 crate 的内部设计写在对应 crate 的模块文档中。
|
||||||
|
|
||||||
文档内容需自包含,仅引用本仓库内的代码或可公开访问的标准。
|
文档内容需自包含,仅引用本仓库内的代码或可公开访问的标准。
|
||||||
|
|
||||||
|
## 各层设计
|
||||||
|
|
||||||
|
- [仿真层](sim.md)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
# 仿真层设计
|
||||||
|
|
||||||
|
本文件记录仿真层(`sim`)的跨 crate 决策。各 crate 的内部设计见其模块文档。
|
||||||
|
|
||||||
|
## 组成与依赖
|
||||||
|
|
||||||
|
```text
|
||||||
|
apsis-event 事件类型与事件队列
|
||||||
|
apsis-sim-engine 离散事件引擎
|
||||||
|
apsis-scenario 场景定义与文本加载
|
||||||
|
apsis-output 仿真输出记录
|
||||||
|
apsis-sim 仿真门面(整合上述四个)
|
||||||
|
```
|
||||||
|
|
||||||
|
依赖方向:
|
||||||
|
|
||||||
|
```text
|
||||||
|
apsis-event -> apsis-sim-engine -> apsis-sim -> apsis-rs
|
||||||
|
apsis-scenario -----------------> apsis-sim
|
||||||
|
apsis-output -------------------> apsis-sim
|
||||||
|
```
|
||||||
|
|
||||||
|
`apsis-sim` 同时依赖 ops 层(`apsis-scheduler`、`apsis-schedule`、
|
||||||
|
`apsis-task`、`apsis-resource`),因为它要规划场景并读取计划。其余 crate
|
||||||
|
只依赖 foundation。
|
||||||
|
|
||||||
|
## 事件顺序
|
||||||
|
|
||||||
|
同一时刻的多个事件必须按可复现的顺序投递,否则同一输入会产生不同输出,
|
||||||
|
无法与参考实现对拍。约定:
|
||||||
|
|
||||||
|
- 每个事件在入队时获得一个递增的序号。
|
||||||
|
- 事件先按时间排序,时间相同则按序号排序,即入队顺序。
|
||||||
|
- 处理函数在处理某事件时新调度的事件,排在该时刻已有事件之后。
|
||||||
|
|
||||||
|
该顺序由 `apsis-event` 保证,`apsis-sim-engine` 与 `apsis-sim` 直接沿用。
|
||||||
|
序列号由队列分配,调用方无法制造两个同号事件。
|
||||||
|
|
||||||
|
## 时间原点
|
||||||
|
|
||||||
|
事件时间是从仿真原点起算的秒数,与日历无关;需要日历的场景由上层换算。
|
||||||
|
|
||||||
|
场景的 `epoch` 是时钟起点。时间线中的事件时间相对场景原点,`apsis-sim`
|
||||||
|
在投递前加上 `epoch`。若不偏移,引擎会在投递首个事件时把时钟回拨。
|
||||||
|
|
||||||
|
时间限制按同一绝对时间轴比较:时间晚于上限的事件留在队列中而不执行,因此
|
||||||
|
调用方可以查看运行结束时还剩什么。时钟停在最后一个已执行事件上,而不是停在
|
||||||
|
上限上。
|
||||||
|
|
||||||
|
## 事件限制是累计的
|
||||||
|
|
||||||
|
`apsis-sim-engine` 的事件上限是引擎整个生命周期的总数,而非单次 `run`
|
||||||
|
的数量。达到上限后再次 `run` 不执行任何事件。这样"上限"始终表示一个不会
|
||||||
|
被绕过的界,调用方要运行剩余事件需显式提高上限。
|
||||||
|
|
||||||
|
## 时间线语义
|
||||||
|
|
||||||
|
`apsis-sim` 把计划展开为时间线上的起止事件:每个已放置任务贡献一个开始
|
||||||
|
事件和一个结束事件,二者是独立事件,因此引擎能按时间顺序把它们与其他事件
|
||||||
|
正确排序,重叠任务的先后也由时钟决定。
|
||||||
|
|
||||||
|
时间线是计划本身,不是物理模型。开始/结束事件触发时调用什么物理计算由处理
|
||||||
|
函数决定,门面只负责排序与记录。
|
||||||
|
|
||||||
|
## 场景文本格式
|
||||||
|
|
||||||
|
`apsis-scenario` 自带一套零依赖的行式文本格式,用于存储与重新加载。
|
||||||
|
解析分三遍(资源、任务、优先级约束),因此 `require` 可以引用文件中稍后
|
||||||
|
定义的资源,`precedence` 可以引用任意顺序定义的任务。每处失败都带行号。
|
||||||
|
|
||||||
|
`Scenario::to_text` 的输出必须能被 `Scenario::parse` 读回为相等场景,
|
||||||
|
即文本形式是往返稳定的;这一点由测试保证。
|
||||||
|
|
||||||
|
任务的"无窗口"(两端为无穷)无法写入文本,故写为一个包含该任务的有限区间,
|
||||||
|
读回后任务仍可用。
|
||||||
|
|
||||||
|
## 确定性
|
||||||
|
|
||||||
|
仿真结果必须可复现,这是对拍的前提。确定性来自三点:
|
||||||
|
|
||||||
|
- 事件队列表述的同刻顺序规则;
|
||||||
|
- 规划器对同权任务的稳定排序(见 ops 层);
|
||||||
|
- 记录器保留插入顺序,`Trace::in_time_order` 为稳定排序。
|
||||||
|
|
||||||
|
`integrate_sim` 示例断言同一次准备出的仿真重复运行得到相同轨迹。
|
||||||
Loading…
Reference in New Issue