MF4 补 ##SD/##SI/VLSD + 信号枚举文本 enumText + .mat 改随机读(流式进度)
1) 修复上轮记录的两个已知问题
- MatLoader: LoadPlainObject 不再为拿 dims 调 ReadDataset(整块解码第二次),
改用 ReadDatasetInfo;普通 v7.3 大矩阵的时间/内存不再翻倍。
- MdfFile::TextBlock 注释与实现对齐:真的支持 ##MD(UTF-8 XML,无长度前缀)。
2) 信号枚举信息(以 TestData/NEW-MF4.mf4 为目标)
- 新增 SignalEnumText(DataTable.hpp):values[] + texts[] + Empty()/Find(),
命名用 enumText —— 它描述"取值代表哪个状态",不是单位。
- DataTable::columnEnumText 与 columns 同下标;SignalData::enumText 由
BuildSignalGroup 移动赋值;其它格式(CSV/.mat)保持为空。
- MF4 cc_type = 7:cc_val[i](F64,数据段 +24)↔ cc_ref[4 + i](##TX/##MD 文本),
最后一个引用是默认文本,不使用。
- 界面只在**光标取值标注**追加 " = <枚举文本>"(等号两侧各一个空格、无尖括号),
查表用采样原值(ApplyDrawTransform 之前);常规状态显示一个像素都不变。
- 实测:NEW-MF4.mf4 8 信号 / 4 条带枚举(32+5+32+5),MF4-Record.MF4 另有 2 种(12/32)。
3) MF4 支持范围
- ##SI 采样索引:只有索引 ≥2 条且全部 < 周期数才生效(逐记录有效性位图)。
实测部分工具给每个通道挂只含常量 513/4 的 ##SI,必须忽略,否则整列变 NaN。
- ##SD + VLSD(cn_type == 1):##SD 数据段是「UINT32 长度 + 字节」样本序列,
记录里放 64 位偏移;AppendSignalData 递归展开 SD/DZ/DL/HL(单通道上限 512MB),
DecodeVlsdValue 先按直接偏移、失败再按 >>1 回退,取样本第一个元素。
- CN 的 cn_data / md_unit / md_comment 下标按链接总数反推:8 链接(MDF 4.0 风格)
= 换算[4]/数据[5]/单位[6]/注释[7],9 链接(4.1)= [5]/[6]/[7]/[8]。
实测 Simulink 导出的“4.10”仍写 8 链接,不能写死 Link(cn,4/5)。
- 主通道:cn_sync_type 1/2/3(时间/角度/距离)→ 名字 t/time/timestamp/zeit/时间
(含 t[...])→ 第一个数值通道兜底;cg_flags 第 2 位(远程主通道)跳过 sync 判定。
- 记录长度优先 cg_data_bytes(CG 数据段 +24);旧实现把 U8(cgData) 当
cg_record_id_len,其实是 cg_flags 低字节(总线事件位)。
- 进度:先走 DG 链得到真实组数(不再写死 64),hasBytes = true,bytesRead 取
MdfFile::ReadAt 累计(夹到文件大小);4MB 分块读取检查取消。
- ##DZ:数据段前有 28 字节头(original_type/zip_type/param/original_size/zip_size),
旧实现整段当 zlib 流是错的;只支持纯 deflate(zip_type = 0)。
- 一个信号都没有时,错误信息附带「布局无法解析 / 缺少时间通道 / 空数据组」计数。
4) .mat:内存映射 → 随机读 + 元数据块缓存(消除 SEH 风险)
- MatHdf5::Open 改为 CreateFileW(FILE_FLAG_SEQUENTIAL_SCAN) + ReadFile;
删除 MappedBytes,改为 ReadAt / Cached(16 × 64KB LRU + 上次命中槽)/ Tag /
ReadData / ReadCString。I/O 失败只会变成 false,不再触发页访问异常。
- 数据读取:连续布局按 4MB 切片;分块布局按需 + 64KB 对齐。
固定 4MB 预读在交错存放的分块数据集上会把读盘量放大到 2.2 倍(2874MB/1293MB),
改后 1301MB。
- 关键提速:dims=[N]、chunk=[32768,1] 归一化后 rank=2、每行 1 字节,逐行算坐标
是 12.9 亿次迭代;新增「rank == 2 且 chunkDims[1] == dims[1]」快路径(整块一次
sink)。BIG_MAT.mat(1.29GB / 5 × 16,142,471):21.5s → 7.9s,私有内存 +741MB。
- 进度:Open 立刻上报「0 / 总大小」,之后每读一块回调 ReadProgress(bytesRead,total)
→ MatLoader 映射到 0.02–0.98 并单调夹紧(字节进度与逐流解码取较大值),收尾 1.0。
遮罩层百分比不再一上来就 100%;取消会中止(StreamDataset 返回 false),不留 NaN 空洞。
- 连续布局数据不足(文件被截断)现在明确失败,不再静默截短。
验证(全部离屏:无可见窗口、不注入鼠标键盘屏幕)
- 新增 .preflight/perf/loadercheck(数据层)32/32:
NEW-MF4 8 信号 / 4 条枚举 / 枚举文本逐条核对 / 9396 与 94 行;
MF4-Record 124 信号 / 3 轴 / 4 条枚举;data-sample.mat 4 组 8 信号 / 行数;
BIG_MAT.mat 5 信号 × 16,142,471 + 进度(total 已知、ratio 单调、bytes 递增、
起点 ≤0.05、终值 1.0、更新 ≥10 次)。
- 新增 .preflight/perf/enumui(真实 Application + SW_HIDE)12/12:
只显示 gVR_WinOpenReq[0],光标落在枚举采样点上 —— 标签宽度 265px;
临时清空 enumText 后 25px;差值 240px 与 " = WinOpenReqAtDrvr_Idle" 的
UiMeasureTextWidth 完全一致;恢复后宽度回到 265px。
- 回归:datacheck 69/69、matcheck 21/21、matui 15/15(loading bytes 达到总大小)、
verify 49/49。
- make release / make debug 零警告。Build/Release/TargetCheck.exe = 820,224 字节
(上轮 785,920,+34KB)。(Target.exe 正在被用户运行的程序占用,链接步骤未覆盖它。)
This commit is contained in:
1 parent
75f0fafd41
commit
181f95cc3a
10 files changed
+1328
-291
No files matched your search
+85
-1
@@ -3001,6 +3001,8 @@ else if (panelOnly) { /* 只回送“本帧重绘过的区域并集” */ }
|
||||
|
||||
| 2026-10-19 | DeepSeek-V4.1-Flash(**本机**) | **`.mat` 流式解码(内存映射 + 逐 chunk 填充)+ MDF4 `##DL/##DZ/##HL` 数据块 + 光标数据点被时间面板遮住改三角(详见 §12 末尾「2026-10-19 第四轮」与 §11.2 第 154–159 条)**。① **`.mat`**:`MatHdf5::Open` 由“整文件 `fread` 进 `vector`”改为 **`MapViewOfFile`**(`MappedBytes` 只读视图,解析代码零改动);新增 `ReadDatasetInfo` + `StreamDataset(ByteSink)`(连续布局 4MB 切片、分块布局逐 chunk inflate)与 `ReadDoubleStream`(SDI `#data#` 字节流 → double,7 字节尾巴处理非 8 对齐 chunk);`ReadNumbers` 改为流式转换;`MatLoader` 先收集信号清单再按(分组, 时间流)合并成 `TableBlock`,时间列按内容去重、数据列 `std::move`,进度改成 `0–0.02 映射 / 0.02–0.98 逐流解码`。实测 `BIG_MAT.mat`(1.29GB / 5×16.14M):**117s → 12.5s**、私有内存 **+1234MB → +740MB**(数据本身 739MB)。② **MDF4**:`CollectDataSegments` 递归展开 `##DL`/`##HL`,识别 `##DT`/`##DV`/`##DZ`;`ReadRecordSegments` 支持跨段拼接与压缩段 inflate;压缩段记录长度改用通道位宽推算。`Problem-MF4.mf4` 由 **4 → 8 个信号**(与 Simulink SDI 一致)。③ **光标标记**:`MarkerCoveredByCursorLabel` + `CoverHiddenMarker`,圆点被底部时间读数/Δt 面板盖住时改为向下三角(原始信号与派生曲线两处)。验证:新增离屏 `.preflight/round4check` **34/34**;**A/B**(禁用 `##DL` ⇒ 2 项失败、禁用 `CoverHiddenMarker` ⇒ 3 项失败);回归 `round3check` 31/31、`editcheck` 20/20、`check` 137/137;`make release`/`make debug` 零警告。 |
|
||||
|
||||
| 2026-10-20 | DeepSeek-V4.1-Flash(**本机**) | **MF4 `##SD`/`##SI`/VLSD + 信号枚举文本 `enumText`(光标尾缀)+ `.mat` 由内存映射改为随机读(详见 §12 末尾「2026-10-20」)**。① **§2.6 两处**:`LoadPlainObject` 不再 `ReadDataset` 二次解码(改用 `ReadDatasetInfo` 取维度);`MdfFile::TextBlock` 真正支持 `##MD`(UTF-8 XML)。② **枚举**:新增 `SignalEnumText`(`values[]`/`texts[]`/`Find`)挂在 `DataTable::columnEnumText` 与 `SignalData::enumText`;MF4 `cc_type = 7` 按 `cc_val[i] ↔ cc_ref[4+i]` 解析。界面只在**光标取值标注**追加 ` = <枚举文本>`,常规状态零变化。`NEW-MF4.mf4` 实测 8 信号 / 4 条带枚举(32+5+32+5 项)。③ **MF4**:`##SI` 采样索引(≥2 条且全部 < 周期数才生效;实测工具会给每个通道挂只含常量 513 的 `##SI`,必须忽略)、`##SD` + VLSD(`UINT32` 长度前缀 + 64 位偏移,直接偏移优先、`>>1` 回退)、CN 链接下标按链接总数反推(4.0 的 8 链接 / 4.1 的 9 链接)、主通道接受 `sync_type` 1/2/3 + `cg_flags` 远程主通道、记录长度优先 `cg_data_bytes`、进度分母改真实 DG 数并上报字节、`##DZ` 28 字节头修正。④ **`.mat`**:删除 `MappedBytes`,改 `ReadFile` 随机读 + 16×64KB 元数据 LRU + 按需数据读取(固定 4MB 预读会把读盘量放大 2.2 倍 ⇒ 改后 1.0 倍);新增 rank=2 连续 chunk 快路径(12.9 亿次逐行迭代 ⇒ 每块一次回调),`BIG_MAT.mat` **21.5s → 7.9s**、私有 +741MB;进度按真实 `bytesRead / totalBytes` 推进(不再一上来 100%),取消会中止而不是留下 NaN 空洞。验证:新增离屏 `loadercheck` **32/32**、`enumui` **12/12**;回归 `datacheck` 69/69、`matcheck` 21/21、`matui` 15/15、`verify` 49/49;`make release`/`make debug` 零警告;`Target.exe` 785,920 → **820,224 字节**。 |
|
||||
|
||||
## 11. 跨设备协作须知(起源设备视角)
|
||||
|
||||
> **本文件是唯一权威记忆**。所有设备 / Agent 共用它,**不要再新建 `agent_mem_origin.md` 等旁支记忆文件**。
|
||||
@@ -6646,4 +6648,86 @@ DG3 data=0 cycle=0 (空组,一个字符串通道)
|
||||
(表中文本的前缀 `WinOpenReqAtDrvr_` 已省略;`gVR_WinOpenReq[1]` 的 CC 内容完全相同。)
|
||||
⚠️ 目前 `ParseChannel` 只认 `cc_type ∈ {0,1}`,所以这两个通道在界面上显示为原始整数;
|
||||
要显示标签需要按 `cc_type == 7` 读 `links[4..4+valCount-1]` 并与 `cc_val[]` 一一对应,
|
||||
再随信号传递到界面(本轮按要求**未做代码改动**)。
|
||||
再随信号传递到界面(本轮按要求**未做代码改动**)。
|
||||
|
||||
---
|
||||
|
||||
## 本轮(2026-10-20,本机):MF4 `##SD`/`##SI`/VLSD + 枚举文本 + `.mat` 改为随机读
|
||||
|
||||
> 用户需求:① 修复 §2.6 的两个已知问题;② 为信号增加**枚举信息**(准确命名 `enumText`,不是
|
||||
> 单位),以 `TestData/NEW-MF4.mf4` 为目标;常规状态显示不变,**只有启用光标时**在数值后追加
|
||||
> ` = <枚举文本>`(等号两侧各一个空格、无尖括号);③ MF4 支持 `##SD`/`##SI`、VLSD、
|
||||
> `cg_flags` 主通道判定、进度分母;④ `.mat` 由内存映射改为「随机读 + 元数据块缓存」,
|
||||
> 流式读取并动态更新「已读/总大小」,在可能范围内加速;⑤ 离屏验证后提交,不占用鼠标键盘屏幕。
|
||||
>
|
||||
> 验证(全部离屏,无可见窗口、无注入输入):
|
||||
> * 新增 `.preflight/perf/loadercheck.exe`(数据层)**32/32**;
|
||||
> * 新增 `.preflight/perf/enumui.exe`(真实 `Application` + `SW_HIDE` + 光标标签宽度)**12/12**;
|
||||
> * 回归 `datacheck` 69/69、`matcheck` 21/21、`matui` 15/15、`verify` 49/49;
|
||||
> * `make release` / `make debug` 零警告;`Target.exe` 785,920 → **820,224 字节**(+34KB)。
|
||||
|
||||
### A. §2.6 两个已知问题
|
||||
|
||||
1. **`LoadPlainObject` 解码两遍**:改为先 `ReadDatasetInfo`(只取 `dims`)再 `ReadNumbers`,
|
||||
不再为了维度去调用 `ReadDataset`(那会把整块数据解码第二次)。
|
||||
2. **`MdfFile::TextBlock` 注释与实现不符**:现在真的支持 `##MD`(数据段是 UTF-8 XML,
|
||||
没有长度前缀 ⇒ 直接转宽字符串)。`##TX` 的两种写法(长度前缀 / CANape 裸文本)保持不变。
|
||||
|
||||
### B. 枚举信息(`enumText`)
|
||||
|
||||
- 数据层新增 `struct SignalEnumText { values[]; texts[]; Empty(); Find(value); }`
|
||||
(定义在 `DataTable.hpp`)。**命名刻意用 `enumText`**:它描述「取值代表哪个状态」,
|
||||
不是单位、不是注释。`DataTable::columnEnumText` 与 `columns` 同下标;
|
||||
`SignalData::enumText` 由 `BuildSignalGroup` 移动赋值。
|
||||
- MF4 侧:`cc_type = 7` 时按 `cc_val_count` 读 `cc_val[]`(F64,从数据段 +24 开始)与
|
||||
`cc_ref[4 + i]`(`##TX`/`##MD` 文本);最后一个引用是「默认文本」,不使用。
|
||||
文本为空的取值不进入枚举表(保持 `values/texts` 对齐)。
|
||||
- 界面:**只有光标取值标注**追加 ` = <枚举文本>`(`PlotViewPaint.cpp` 里 `text += L" = "`)。
|
||||
常规状态(未启用光标)一个像素都不变;枚举查表用**采样原值**(在 `ApplyDrawTransform` 之前),
|
||||
避免系数/镜像把状态查丢。
|
||||
- `TestData/NEW-MF4.mf4` 实测:8 信号,4 条带枚举
|
||||
(`gVR_WinOpenReq[0/1]` 32 项、`gVP_WindowLearnSt[0/1]` 5 项);`MF4-Record.MF4` 也有 4 条
|
||||
(`gVP_ActrStopReazon[0]` 12 项、`gV_WinPosnSts[0]` 32 项)。
|
||||
|
||||
### C. MF4:`##SD` / `##SI` / VLSD / 主通道 / 进度
|
||||
|
||||
- **`##SI`(采样索引)**:只有当索引表 **≥2 条且全部 < 周期数**时才生效(逐记录有效性位图,
|
||||
其余行保持 NaN)。⚠️ 实测 `MF4-Record.MF4` / `NEW-MF4.mf4` 里每个通道都挂了一个只含
|
||||
**1 个值(513 / 4)** 的 `##SI`——那显然不是采样下标,必须忽略,否则整列会被清成 NaN。
|
||||
- **`##SD` + VLSD(`cn_type == 1`)**:`##SD` 数据段是「`UINT32` 长度 + 字节」的样本序列;
|
||||
记录在该通道 `cn_byte_offset` 处放 **64 位偏移**。实现 `AppendSignalData`(递归展开
|
||||
`##SD`/`##DZ`/`##DL`/`##HL`,单通道上限 512MB)与 `DecodeVlsdValue`
|
||||
(直接偏移优先,失败再按 `>>1` 回退;取样本的第一个元素作为采样值)。
|
||||
- **`cn_data` / `cn_md_unit` / `cn_md_comment` 的链接下标按链接总数反推**:
|
||||
8 链接(MDF 4.0 风格)= 换算[4]/数据[5]/单位[6]/注释[7];9 链接(4.1)= [5]/[6]/[7]/[8]。
|
||||
⚠️ 实测 Simulink 导出的「4.10」文件仍写 8 链接 ⇒ 不能写死 `Link(cn, 4/5)`。
|
||||
- **主通道判定**:`cn_sync_type` = 1/2/3 → 名字(`t`/`time`/`timestamp`/`zeit`/`时间`,
|
||||
含 `t[...]`)→ 第一个数值通道兜底。`cg_flags` 第 2 位(远程主通道)时跳过 sync 判定。
|
||||
- **记录长度**:优先 `cg_data_bytes`(CG 数据段 +24),其次「载荷 ÷ 周期数」,最后按位宽推算。
|
||||
⚠️ 旧实现把 `U8(cgData)` 当 `cg_record_id_len`,那其实是 `cg_flags` 的低字节(总线事件位)。
|
||||
- **进度**:先走一遍 DG 链得到**真实组数**(不再写死 64),`hasBytes = true`,
|
||||
`bytesRead` 来自 `MdfFile::ReadAt` 的累计(上报时夹到文件大小);4MB 分块读取时检查取消。
|
||||
- **`##DZ` 修正**:数据段前面有 28 字节头(`original_type`/`zip_type`/`param`/
|
||||
`original_size`/`zip_size`),旧实现把整段当 zlib 流是错的。只支持纯 deflate(`zip_type = 0`)。
|
||||
- 失败诊断:没有任何可绘制通道时,错误信息附带「布局无法解析 / 缺少时间通道 / 空数据组」计数。
|
||||
|
||||
### D. `.mat`:内存映射 → 随机读 + 元数据缓存
|
||||
|
||||
- `MatHdf5::Open` 改为 `CreateFileW(FILE_FLAG_SEQUENTIAL_SCAN)` + `ReadFile` 随机读;
|
||||
`MappedBytes` 删除,改为 `ReadAt` / `Cached` / `Tag` / `ReadData`。
|
||||
**彻底消除 SEH 风险**(I/O 失败只会变成 `false`)。
|
||||
- 元数据:16 × 64KB 块缓存(LRU + 上次命中槽快路径),覆盖对象头 / B-tree / 本地堆;
|
||||
成员名用 `ReadCString`(跨块边界安全)。
|
||||
- 数据:连续布局按 4MB 切片;分块布局**按需读取 + 64KB 对齐**,
|
||||
⚠️ 固定 4MB 预读在交错存放的分块数据集上会把读盘量放大到文件大小的 2.2 倍
|
||||
(实测 2874MB / 1293MB)⇒ 改后 1301MB。
|
||||
- **关键提速**:`dims=[N]`、chunk `[32768,1]` 归一化后 rank=2、每行 1 字节,
|
||||
逐行算坐标是 **12.9 亿次迭代**(约占总时间一半以上)。新增
|
||||
「rank == 2 且 `chunkDims[1] == dims[1]`」快路径:整块一次 `sink`。
|
||||
实测 `BIG_MAT.mat`(1.29GB / 5 信号 × 16,142,471):**21.5s → 7.9s**,私有内存 **+741MB**
|
||||
(最终列数据 739MB,与映射版一致)。
|
||||
- **进度**:`Open` 立刻上报「0 / 总大小」;之后 `ReadData`/切片每读一块回调
|
||||
`ReadProgress(bytesRead, total)` → `MatLoader` 映射到 0.02–0.98,并进行**单调夹紧**
|
||||
(字节进度与逐流解码进度取较大值),收尾 1.0。遮罩层百分比不再「一上来就 100%」。
|
||||
取消会置 `m_readCancelled` 并让 `StreamDataset` 立即失败(不会留下 NaN 空洞)。
|
||||
- 连续布局数据不足(文件被截断)现在**明确失败**,不再静默截短。
|
||||
Reference in new issue
Block a user