Files
SystemSimulationApp/docs/other/结果存储额度增量优化验证-2026-09-15.md
T

72 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 结果存储额度增量优化验证 — 2026-09-15
## 问题与范围
原生端每次准备写入状态块时,先通过 `storage-reserve` 申请状态块与后续输出块的合计额度,并同步等待 Python 回复。旧版 `ResultArchive.reserve()` 每次都遍历历史目录、统计大小、读取完整 manifest、检查使用锁和工作进程,再序列化、fsync 并原子替换当前 manifest。因此,块数、历史工程数量和历史清单体积一起放大了求解器的等待时间。
这里的重复扫描是历史目录和清单的配额检查,并非每块都重新读取历史二进制轨迹做 CRC。结束时的一次完整性扫描仍保留。
## 修改
- 使用预先持久化的额度窗口:最大 16 MiB,同时不超过总配额的 1/16;单块需求超过窗口时按实际需求申请。
- 窗口内逐块扣减本实例的剩余额度,不访问历史目录、不拿跨进程配额锁、不写 manifest。
- 剩余额度不足时,在原有全局锁下只为缺少的部分确保空间,再利用已有空闲空间适量预留。不会为了扩大窗口而额外淘汰历史记录。
- 额度先原子持久化、后允许工作进程写入。未消费的额度仍被其他进程计入占用,避免重复分配;发布失败不发放新额度。
- 实例内加锁,防止同一归档的并发扣减丢失。结束时归还未使用的窗口额度,关闭后拒绝继续申请。
- 原有使用锁、孤儿工作进程保护、未知文件不删除、配额耗尽返回部分结果以及 CRC 校验保持。
额度窗口只是记账,不会增加同等大小的内存缓冲或预写空文件。历史目录在创建归档及额度补充时仍会扫描,并非完全消除了历史数量的影响;磁盘空间紧张时,窗口缩小,收益也会降低。多个同时运行的工程可能暂时各占用一部分未消费额度,因此窗口设置了上限。本机制是应用内逻辑字节配额,不是操作系统硬配额,也不能防止用户从外部工具额外写入或删除文件。
不修改二进制格式、采样点、求解算法、求解容差或结果传输格式;不新增数据库、不迁移或清理用户的已有结果。
## 性能对比方法
脚本:`tests/manual/benchmark_result_reservations.py`。旧路径仅作为脚本内对照函数保留,生产代码使用新路径。所有历史目录、清单及结果文件都在独立临时目录中生成。使用真实文件系统、锁和 fsync,不模拟 I/O。
环境:Windows、本机 Python 3.12。每组两轮,下面为算术平均值;运行时间会受系统缓存、磁盘及其他进程影响。额度微基准的清单包含 1,000 个变量,历史文件是只用于目录/大小统计的合成夹具,不是完整真实工程。计时不包含夹具创建、归档初始化和结束扫描,也不包含求解与实际数据块写入。
| 历史记录数 | 申请负载 | 旧路径耗时 | 新路径耗时 | 检查/清单发布次数(旧 → 新) |
| --- | --- | --- | --- | --- |
| 0 | 256 × 64 KiB | 2.294 秒 | 0.00844 秒 | 256 → 1 |
| 100 | 256 × 64 KiB | 52.247 秒 | 0.22886 秒 | 256 → 1 |
| 300 | 256 × 64 KiB | 161.104 秒 | 0.57988 秒 | 256 → 1 |
| 0 | 64 × 1 MiB | 0.639 秒 | 0.04084 秒 | 64 → 4 |
以上是额度管理耗时,不可直接解释为整段仿真的提速比例。64 MiB 场景覆盖多次窗口补充。
### 实际原生仿真对比
机械质量块连接两个自由端口,RK45,仿真区间 0–1 秒,采样步长 0.00001 秒,共 100,001 点;结果目录内有 300 条合成历史记录。共用同一次编译产物,计时包含归档初始化、工作进程、写块、结果读取和结束校验,不包含编译和历史夹具创建。每种路径两轮。
| 路径 | 第 1 轮总耗时 | 第 2 轮总耗时 | 平均总耗时 | 平均额度申请耗时 |
| --- | --- | --- | --- | --- |
| 逐块全量检查 | 32.077 秒 | 28.035 秒 | 30.056 秒 | 29.085 秒 |
| 批量额度 | 1.458 秒 | 1.421 秒 | 1.440 秒 | 0.565 秒 |
- 每次仿真都有 98 次块额度请求;新路径只补充两次窗口。
- 包括初始化在内,目录配额检查由 99 次降至 3 次;包括初始化、工作进程登记和结束在内,清单发布由 101 次降至 5 次。
- 四次运行的 `states.bin`、`outputs.bin` SHA-256 完全一致,返回的每个采样值也完全一致,CRC 检查通过。
- 这是一组求解计算较轻、便于暴露存储等待的模型,不代表所有复杂工程都能获得约 95% 的总耗时降幅。本次没有改动求解器的数学计算路径。
复现:
```powershell
py -3.12 -m tests.manual.benchmark_result_reservations --native
py -3.12 -m tests.manual.benchmark_result_reservations --histories 0 --requests 64 --block-kib 1024 --repeats 2
```
## 正确性回归
新增窗口快速路径无文件系统操作、跨窗口只申请差额、临近配额不额外淘汰、发布失败回滚、八线程并发扣减、关闭后拒绝申请、结束归还额度、跨进程未消费额度保护、申请失败后仍可写入更小尾块等回归。
原生测试同时覆盖 RK45/BDF、多块及尾块、所有输出的 binary64 位一致性、负零、取消、强制终止、配额耗尽和存储 I/O 失败。
使用项目已有 `.venv-win` 完整依赖环境运行:
```powershell
$env:SIMULATION_NATIVE_REQUIRE_TOOLCHAIN='1'
./.venv-win/Scripts/python.exe -m unittest tests.test_result_storage tests.test_native_sample_storage tests.test_native_cache_storage tests.test_native_result_transport tests.test_result_csv_export -v
```
共 56 项,53 项通过,3 项因 Windows 缺少创建符号链接的权限而跳过;没有失败。传输流、取消后的部分结果和 CSV 导出契约也通过。单独使用系统 Python 跑后两组时缺少 FastAPI,随后已切换上述项目环境完成全部五组验证,未安装或更改依赖。Python 语法检查通过。