181f95cc3a8c84082fe0934ac8eb6ef0861e3660
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
181f95cc3a |
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 正在被用户运行的程序占用,链接步骤未覆盖它。)
|
||
|
|
75f0fafd41 |
.mat 改为流式解码(内存映射 + 逐 chunk 填充);MF4 支持 ##DL/##DZ/##HL;光标数据点被时间面板遮住时改三角
1) .mat(BIG_MAT.mat 1.29GB / 5 信号 x 16,142,471 采样)
旧链路同时驻留三份内存:整文件 fread 进 vector、整个数据集解压成字节数组、再 memcpy 成
double;外加 streams 缓存与每条信号各一份时间列拷贝。实测私有内存 +1233.9MB、117s。
现改为:
- MatHdf5::Open 用 CreateFileW + CreateFileMappingW + MapViewOfFile(MappedBytes 只读视图,
解析代码零改动;虚拟地址不等于物理内存,未访问页不驻留);
- 新增 ReadDatasetInfo(只读元信息)+ StreamDataset(ByteSink)(连续布局 4MB 切片、
分块布局逐 chunk inflate)+ ReadDoubleStream(SDI #data# 字节流按 8 字节一组直接写 double,
7 字节尾巴处理非 8 对齐 chunk);ReadNumbers 改为流式转换;
- MatLoader 先收集信号清单,再按(分组,时间流)合并为一个 TableBlock:时间列按内容去重、
数据列直接 move;进度改成 0-0.02 映射 / 0.02-0.98 逐流解码 / 1.0。
结果:117.3s -> 12.5s,私有内存 +1233.9MB -> +740.4MB(最终列数据 738.9MB)。
关键性能修正:SDI 的 #data# 是 dims=[N]、chunk=[N,1],归一化后每行只有 1 字节;旧的逐行回调
(且每行分配 coordinate 向量)只有 11MB/s。把目标连续的行合并成一次回调后约 110MB/s。
顺带把 inflate 的 Huffman 解码改成 9 位快查表,并抽到新的 Deflate.hpp/.cpp 供 MF4 复用。
2) MDF4 数据块
Problem-MF4.mf4 的第二个数据组把记录写在 ##DL(数据列表,两个 ##DT:131040+504 字节)
里,旧实现只认 ##DT,整组被跳过,于是 8 个信号只读出 4 个。
新增 CollectDataSegments(递归展开 ##DL / ##HL,叶子识别 ##DT / ##DV / ##DZ)与
ReadRecordSegments(跨段拼接、压缩段先 inflate、非压缩段仍按 4MB 分块读),
压缩段的记录长度改用 max(cg_record_id_len*8, 各通道 bitOffset+bitCount) 推算(载荷是压缩长度)。
实测 8 个信号:gVP_WindowLearnSt[0] 94 行、gVR_WinOpenReq[0] 9396 行,时间列单调。
##SD(已排序数据)仍未实现,这类数据组会被跳过。
另按要求只做检查、不改代码:该文件中 gVP_WindowLearnSt[0] 与 gVR_WinOpenReq[0] 都存在
值枚举文本(##CC,cc_type=7;links[4+i] 对应 cc_val[i]),清单已写入 Documents/agent_mem.md。
3) 光标数据点标记
光标的时间读数与差值胶囊绘制在绘图区底部、且在取值标注之后绘制,靠近底部的数据点圆点
会被完全盖住。新增 MarkerCoveredByCursorLabel(圆心落入面板或重叠面积达到半个圆)
与 CoverHiddenMarker(改成向下的三角、锚点放到面板上沿上方),在原始信号与派生曲线胶囊
两处调用,语义与“数据点在视界下方”一致。
验证(全部离屏:SW_HIDE 窗口 + 只注入合成消息 + BELOW_NORMAL,不占用鼠标键盘屏幕):
- 新增 .preflight/round4check 34/34;A/B:临时禁用 ##DL 支持 => 2 项如实失败;
临时禁用 CoverHiddenMarker => 3 项如实失败(含像素断言为 0);
- 回归:.preflight/round3check 31/31、editcheck 20/20、check 137/137;
- make release / make debug 零警告;Build/Release/Target.exe 785,920 字节(< 800KB)。
|
||
|
|
6eedbe3c5d |
数据层大重构:文件→分组 / 时间轴一等公民 / 加载器抽象 + CSV 多时间轴 + MF4 支持
一、数据模型解耦(详见 Documents/refactor_report_2026-10-15.md 与 agent_mem §9.27)
1. DataFile → SignalGroup:删除 filePath / fileName / time / timeColumnName / timeMonotonic /
minTime / maxTime —— 「分组」是应用内的逻辑容器,加载完成后与磁盘文件再无关系。
2. 新增 TimeAxis(name / time / minTime / maxTime / monotonic / finiteCount),一个分组可含 1..N 条;
SignalData 新增 axisIndex 指向所属时间轴,采样值与时间的对应关系自包含。
3. SignalData 删除冗余的 rawHeader(name 的副本)与 unit(由列名猜出、全仓无人使用);
名字只保留 name(源名称)+ displayName(用户重命名),Title() 统一展示。
4. SignalRef::fileIndex → groupIndex;DataSet:AddGroup/RemoveGroup/GroupAt/GroupCount/Groups()/
SetGroupDisplayName/RemapSelectionAfterGroupRemoval + 新增 Axis(ref);
TabConfig:SetGroupVisible/GroupHasVisible/GroupAllVisible/RemapAfterGroupRemoval +
RowKind::GROUP / CMD_GROUP_*。
5. 采样与统计 API 首参由 const DataFile& 改为 const TimeAxis&:
SampleSignalAt / SampleDisplayedSignalAt / FindNearestSample(Utilities)与
SampleSpacingPixels / VisibleIndexRange / EdgeIndexRange / MeanFilterValueAt / WeakPeakValueAt /
EdgeCountsFor / EdgeCenterCountsFor / EdgeScanFor(PlotView)。
6. 视图层:ResolvedSignal = { data, style, group, axis, visible };PolylineCacheEntry::file→group;
EdgeScanState::file→axis(统计身份 = 时间轴 + 信号);
ComputeVisibleTimeBounds 只统计可见信号真正用到的时间轴。
二、加载层抽象(格式与模型彻底解耦)
- 新增 Utilities/Inc/DataTable.hpp:DataTable(通用列优先表格)+ LoadProgress/Info +
TableBlock(一个时间轴块)+ LoadedSource(源文件全部块)。
- 新增 Utilities/Inc|Src/DataLoader.*:唯一入口 LoadSignalSource 按扩展名分发 +
IsSupportedSignalFile + SignalFileDialogFilter。
- 新增 Utilities/Inc|Src/CsvLoader.*:CSV 解析 + 多时间轴切分 + 各轴按自己的时间列裁剪。
- 新增 Utilities/Inc|Src/Mf4Loader.*:ASAM MDF v4 解析。
- 删除 Utilities/Inc/CsvTable.hpp 与 Utilities/Src/CsvTable.cpp。
- 唯一装配点 BuildSignalGroup(LoadedSource&&, paletteBase, group, error, progress):
时间轴去重合并 + 信号命名 + 调色板取色 + 统计与粗粒度包络;新增格式只需写一个加载器。
三、CSV 多时间轴(修正用户报告的缺陷)
- 只有名为 t/time/timestamp/simulation time/时间/时间轴 的列是时间轴(判据收紧,
不再用「包含 time」以免把 timeout 误判成时间轴)。
- 每个时间列开启一个新块,其后直到下一个时间列之前的列都属于该块;各块按自己的时间列裁剪
⇒ 支持各轴长度不同(Multi_Timeline.CSV 实测切出 3 条轴,长度 7/4/7);
**不再把其它 time 列当成信号显示**。
- 完全没有时间列时保留旧行为(第一列当时间轴,单轴)。
四、MF4 支持(新功能)
- 加载后新建一个分组、组名 = 文件名,文件内全部信号归入该分组。
- 每个通道组(CG)是一条时间轴,内容相同的时间轴自动合并(实测 27 个 CG → 3 条轴 / 124 条信号)。
- 实现 MDF v4 块解析(HD/DG/CG/CN/CC/DT)、1–64 位整数(任意位偏移、含符号扩展)与
32/64 位 IEEE 浮点解码、无效位(inval bit)处理、线性换算 phys = cc_val[0] + cc_val[1]*raw。
- TX 文本块同时兼容规范写法(U32 长度 + UTF-16/UTF-8)与 CANape 的「无长度前缀 NUL 结尾裸文本」。
- 未实现(跳过该组):压缩块 ##DZ/##HL/##SD、##DL 数据列表、字符串/MIME 通道。
五、顺带修复
- Application::Initialize:窗口类已注册(ERROR_CLASS_ALREADY_EXISTS)时复用而不是弹模态错误框
(旧实现让同一进程第二次构造 Application 永久阻塞);Shutdown 注销窗口类并销毁窗口。
- UI 文案统一到「分组」:选中该分组全部信号 / 取消该分组全部信号 / 关闭该分组(从工作区移除)/
请关闭部分分组或信号后重试。/ 尚未加载数据,请打开数据文件 / 打开数据文件以查看波形 /
(可同时加载多个文件,各自成为一个分组);对话框过滤器增加 *.mf4/*.mdf。
六、验证(全部离屏:BELOW_NORMAL 优先级 + SW_HIDE 窗口 + 只注入合成消息)
- 新增 .preflight/perf/datacheck_main.cpp:69/69 通过(单轴 CSV 回归、多时间轴 CSV、MF4 组名/信号数/
时间轴/主时间轴 ns→s/setSpeed 首样本与原始字节人工核对、DataSet 不变量、派生信号沿用源轴、
MF4 集成 124 信号并一格 60~68ms/帧)。
- 新增 .preflight/perf/edgecheck_main.cpp(ASCII-only,替代被编码破坏的 panelcheck):46/46 通过
(「调整」符号规则走真实菜单路径、边沿统计按帧推进/不饿死/逐位一致/无鼠标输入也完成、
面板两列等宽与信号名限宽、弱峰复位控件)。
- 既有 .preflight/perf/verify_main.cpp(已适配新 API):47/47,另有 2 条本机未同步的旧规则断言
(derived offsetTime kept / mouse in lane1 lower half),与本轮无关。
- make clean && make all 零警告。
|