悬停光晕 210ms/帧 → 4ms(包络带填充 + 光标窗口裁剪)+ 平移丢波形判据修正 + 随机组合压力测试
一、悬停巨型信号时整帧卡死(用户报:VERY_BIG_DATA 的「编码器A相」,浮动提示不再跟随鼠标)
探针复现:hoverMean = 210.31ms / baseline = 0.90ms。
根因:PaintSignalHalo 用「加粗 GDI+ 折线」描边整条曲线,而包络带信号的顶点是
「每像素列上/下包络交替」的满幅竖锯齿 —— GDI+ 描边代价 ≈ 线段数 × 覆盖行数
(2503 顶点 × 1081 行)。同一几何改用 FillPath 只要 ~1ms。
修法(PlotViewPaint.cpp / PlotViewInternal.hpp):
1) 包络带信号(cached.bandMode)的光晕改为**填充与曲线本身同一几何**的包络带
(bandBreaks 段 → 上包络正向 + 下包络反向,alpha 0x55);
2) 只画鼠标附近一段(kHaloWindowHalfWidth=72 逻辑像素、kHaloWindowMinPoints=360):
· 包络带:窗口换算成列区间再填充(下包络反向存储 ⇒ 列 c 在 start+half+(half-1-c),
列区间恰对应一段正向可读的连续区间);
· 折线描边:O(n) 扫一遍取窗口内的连续顶点段,段首尾各多含一个顶点(跨窗口的线段完整画出);
· 散点高亮同样按窗口过滤(步长仍与 PaintLane 同源)。
3) 窗口中心 = 鼠标 x;鼠标不在绘图区时取绘图区中心(列表/样式区悬停代价同样恒定)。
实测 210ms → 4.0ms(提示恢复跟手)。几何正确性用「透明位图上两次绘制」探针确认:
窗口内与整条光晕逐像素相同(mismatched=0)、窗口外 0 像素(far=0)、全部落在包络带内(outsideBand=0)。
二、组折叠/展开动画卡顿甚至中断(用户用 MF4→BIG→MF4 + 只勾「编码器A相」稳定复现)
这是上面那条的连带症状:列表悬停时 Application::Render 把 panel.HoveredSignal() 推给
SetExternalHoverSignal ⇒ 鼠标每动一次就重画一次光晕;悬停在 2576 万采样的编码器行上
= 210ms/帧 ⇒ 动画定时器被饿死,看起来「卡顿甚至中断」。
同一修复后列表悬停帧 0.72ms(≈ 基线 0.81ms)。探针 [3b] 固化该判据。
三、快速中键拖拽「所有网格信号一起消失」——主修复已正确,之前的失败是度量错了
上一轮把「位移超出 kLayerRollMaxShiftPixels 就作废图层」改成
「driftLimit + 每帧最多滚 kLayerRollMaxStepPixels=240px」,剩余位移由 BlitWideBuffer 的
srcX 承担 ⇒ |shift| 可长期停在 ±(margin-24) 附近而**不会空白**。
之前探针拿「适应视图时的墨迹」当基准,而平移本身会移出数据范围(时间轴外没有采样),
墨迹自然下降 ⇒ 误报。正确判据(已固化进 panflash / stress):
同一次拖拽中把当前帧与**同一视界的整幅强制重绘**(m_sceneValid=false + 清空 m_layerFront)比墨迹,
比值 < 0.9 才算丢波形。三条拖拽模式(120px/帧、90×7 斜向、260px/帧)全部 badFrames=0,
worstRatio 0.966~0.999;MF4 8 个单点信号网格 framesWithMissingPoints=0。
四、新增随机组合压力测试(用户第 4 项要求:给出评估方法与压力验证)
.preflight/perf/stress_main.cpp:1 个 VERY_BIG_DATA(5×2576 万采样)+ 6 个 MF4 分组
(~1500 信号、41 个可见网格),固定种子的随机序列覆盖:中键拖拽(抽样做空白判据)、
滚轮缩放/分布缩放、悬停扫掠、组折叠展开(**每帧都把鼠标扫过正在出现/消失的行**,并校验
m_contentHeight 单调)、适应视图、面板滚动条拖拽、勾选/取消信号、标签页新建/切换/关闭。
判据全部为**同一次运行内的相对量**(基线帧 vs 交互帧),避免绝对 ms 阈值的漂移。
实测:ops=26 frames=209 mean=8.53ms worst=44.87ms(toggleSignal) overBudget=0;
pan blank check 90 个车道样本 0 个低于整幅重绘的 80%;group animation heightRegressions=0。
最慢帧是勾选信号(41 个网格全部重画曲线像素),属于用户明确排除的「需要重绘信号曲线」场景。
五、验证(全部离屏,不占用鼠标/键盘/屏幕)
- 新增 .preflight/perf/panflash_main.cpp(panflash.exe)19/19:三条拖拽模式的丢波形判据、
MF4 单点网格、悬停耗时(4.0ms)、列表悬停联动(0.72ms)、光晕窗口化几何精确性;
- 新增 stress 6/6;既有回归 verify 49/49、panelanim 158/158、hoverdrag 20/20、
gridanim 93/93、lanescroll 23/23、datacheck 69/69;
- make release TARGET_FILE_NAME=TargetCheck 通过(Target.exe 被运行中的实例占用)。
文档:Documents/agent_mem.md 新增本轮小节(含 4 条新规则:GDI+ 加粗描边不得用于包络带几何、
随鼠标变化的绘制必须 O(光标附近)、判据必须是同一次运行内的相对量、平移正确性只能与整幅重绘对比)。
This commit is contained in:
1 parent
fd606a6f80
commit
0efaa8c0ca
4 files changed
+288
-50
No files matched your search
@@ -6040,3 +6040,75 @@ else if (panelOnly) { /* 只回送“本帧重绘过的区域并集” */ }
|
||||
- `uitest` **463/463**;`panperf` PASS(竖直中位 4.4ms、水平 7-10ms);
|
||||
`layercheck` `clobbers=0/24` + `pan frames wrong=0/4`;`cursorcheck` 30/30;
|
||||
- `make clean && make all` 零警告,`Build/Release/Target.exe` 已更新。
|
||||
|
||||
---
|
||||
|
||||
## 本轮(2026-10-18):悬停光晕 210ms/帧 → 4ms(探针 `panflash` / 新增 `stress`)
|
||||
|
||||
用户报告三件事(VERY_BIG_DATA 与 MF4 都要测):① 快速中键拖拽时**所有网格的信号一起消失**;
|
||||
② 组折叠/展开动画在鼠标移到"即将出现的信号行"上方时**卡顿甚至中断**;③ 悬停巨型信号(编码器A相)时
|
||||
**整帧卡死、浮动提示不再跟随鼠标**。
|
||||
|
||||
### A. ③ 的真凶:`PaintSignalHalo` 用**加粗 GDI+ 折线**描边整条曲线
|
||||
|
||||
`panflash` 探针复现(`hoverMean = 210.31ms` vs `baseline = 0.90ms`)。根因是"像素列包络带"信号的
|
||||
`points` 是**每列上/下包络交替的满幅竖锯齿**,GDI+ 描边代价 ≈ 线段数 × 覆盖行数(2503 顶点 × 1081 行)。
|
||||
|
||||
修法(`PlotViewPaint.cpp`):
|
||||
|
||||
1. **包络带信号(`cached.bandMode`)**:光晕改为 `FillPath` 填充**与曲线本身同一几何**的包络带
|
||||
(`bandBreaks` 段 → 上包络正向 + 下包络反向),alpha 0x55;
|
||||
2. **只画鼠标附近一段**(`kHaloWindowHalfWidth = 72` 逻辑像素、`kHaloWindowMinPoints = 360`):
|
||||
- 包络带:把窗口换算成**列区间**再填充(下包络反向存储 ⇒ 列 c 在 `start+half+(half-1-c)`,
|
||||
列区间对应一段**正向可读**的连续区间);
|
||||
- 折线描边:O(n) 扫一遍取窗口内的**连续顶点段**,段首尾各多含一个顶点(跨窗口的线段完整画出)。
|
||||
3. 窗口中心 = 鼠标 x(鼠标不在绘图区时取绘图区中心,保证列表悬停代价同样恒定)。
|
||||
|
||||
结果:**210ms → 4.0ms**(`baseline 0.9ms`),提示恢复跟手。几何正确性由"透明位图上两次绘制"探针确认:
|
||||
窗口内的像素与整条光晕**逐像素相同**、窗口外 0 像素、且全部落在包络带内(`outsideBand=0`)。
|
||||
|
||||
### B. ② 是 ③ 的连带症状
|
||||
|
||||
列表悬停 → `Application::Render` 把 `panel.HoveredSignal()` 推给 `SetExternalHoverSignal`
|
||||
→ 每帧(鼠标动一次就一次)重画光晕。以前悬停在 2500 万采样的编码器行上 = **210ms/帧**,
|
||||
于是动画看着"卡顿甚至中断"(定时器被饿死,动画帧被拉长后跳变)。
|
||||
同一修复后 `[3b] listHover mean=0.72ms`(≈基线)。
|
||||
|
||||
### C. ① 的结论:主修复(`driftLimit` + 分帧滚动)**已经正确**,之前的 FAIL 是度量错了
|
||||
|
||||
`RollWideBuffer` 用 `kLayerRollMaxStepPixels=240` 每帧只把超限的位移往回滚最多 240px,
|
||||
其余位移仍由 `BlitWideBuffer` 的 `srcX` 承担;因此 `|shift|` 可以长期停在 ±(margin-24) 附近,**不会空白**。
|
||||
之前的探针拿"适应视图时的墨迹"当基准比 → 平移本身会移出数据范围(时间轴外没有采样),
|
||||
墨迹自然下降 → 误报。
|
||||
|
||||
**新的正确判据(已固化进 `panflash` 与 `stress`)**:
|
||||
同一次拖拽中,把当前帧与**同一视界的整幅强制重绘**(`m_sceneValid=false` + 清空 `m_layerFront`)比墨迹,
|
||||
比值 < 0.9 才算"丢波形"。三条拖拽模式(120px/帧、90×7 斜向、260px/帧)全部 `badFrames=0`,
|
||||
`worstRatio 0.966~0.999`。
|
||||
|
||||
### D. 新增 `stress` 探针(随机组合压力测试,用户第 4 项要求)
|
||||
|
||||
1 个 `VERY_BIG_DATA`(5×2576 万采样)+ 6 个 MF4 分组(共 ~1500 信号)、41 个可见网格;
|
||||
种子固定的随机序列覆盖:中键拖拽(含空白判据抽样)、滚轮缩放 / 分布缩放、悬停扫掠、组折叠展开
|
||||
(**每帧都把鼠标扫过正在出现/消失的行**,并校验 `m_contentHeight` 单调)、适应视图、面板滚动条拖拽、
|
||||
勾选/取消信号、标签页新建/切换/关闭。判据全部**相对**(同一次运行内测基线),
|
||||
避免机器状态导致的绝对阈值漂移。
|
||||
|
||||
实测:`ops=26 frames=209 mean=8.53ms worst=44.87ms (toggleSignal) overBudget=0`;
|
||||
`pan blank check: 90 lane samples, 0 below 80%`;`group animation: heightRegressions=0`。
|
||||
最慢帧是 `toggleSignal`(勾选信号 ⇒ 41 个网格全部重画信号曲线像素),属于用户明确排除的"需要重绘曲线"场景。
|
||||
|
||||
### F. 验证(全部离屏,不占用鼠标/键盘/屏幕)
|
||||
|
||||
- `panflash` **19/19**(平移无丢波形 + 悬停 4ms + 列表悬停 0.7ms + 光晕几何窗口化精确);
|
||||
- `stress` **6/6**;回归:`verify` 49/49、`panelanim` 158/158、`hoverdrag` 20/20、`gridanim` 93/93、
|
||||
`lanescroll` 23/23、`datacheck` 69/69;
|
||||
- `make release TARGET_FILE_NAME=TargetCheck` 通过(`Target.exe` 被运行中的实例占用,不能直接覆盖)。
|
||||
|
||||
### G. 教训(新增规则)
|
||||
|
||||
1. **GDI+ 的"加粗折线描边"绝不能用于逐像素列的包络带几何**:代价随"线段数 × 覆盖行数"爆炸;
|
||||
稠密信号的光晕/高亮一律用 `FillPath`(同一几何)+ 鼠标附近窗口裁剪。
|
||||
2. **任何"每帧随鼠标变化"的绘制都必须 O(光标附近)**,不能 O(整条曲线);否则一次悬停就能把 60fps 打成 5fps。
|
||||
3. **性能与正确性判据必须是"同一次运行内的相对量"**:绝对 ms / 绝对墨迹都会随机器状态和视界内容变化而误报。
|
||||
4. 平移正确性的唯一可信判据是"与同一视界的整幅重绘对比",而不是"与某个固定基准帧对比"。
|
||||
Reference in new issue
Block a user