fix(plotview): 边沿计数表格归位、统计面板悬停时持续更新、加载不再被统计阻塞、统计提速
1) 表格改造归位(上一轮误做在中心轴上) - 「边沿计数」改为表格:表头(信号名/上升沿计数/下降沿计数)、每信号一行、 行底色取信号配色、三列对齐、内容可滚动(Lane::edgeCountScroll)。 - 「中心轴边沿计数」恢复为可滚动分组列表(条目栏 + 复选框 + 展开后统计行 + 两行滑块), Lane::EnsureEdgeCenterItem 恢复默认展开。 - EdgePanelWidth / EdgePanelLayoutFor / PaintEdgeCursor 统一 listStyle / countTable 判定; EdgeCenterTableHeader 更名为 EdgeCountTableHeader。 2) 鼠标持续移动时统计面板不更新 - 根因:交互态(拖拽或 140ms 内移动)把统计数字整段从面板缓存键中跳过, 只要鼠标不停移动就永远命中旧缓存。 - 修法:扫描推进/完成时自增 m_edgeScanRevision,Paint 开头转为 m_panelStatsVersion (非交互帧立即同步,交互帧按 kEdgeScanStatsRefreshFrames=4 节流), PanelSlotKey 对 COUNT/CENTER 仅混入该版本号(O(1),不再逐信号查询)。 3) 统计进行中无法加载文件 - 新增 PlotView::SetLoadingBusy:加载期间统计时间预算归零、跳过浮动面板绘制、 不再自请求扫描帧;Application::LoadFileAsync 进出各设置一次。实测加载 22~31ms。 4) 统计提速 - 扫描预算由固定采样对改为 QPC 时间片(非交互 6ms / 交互 1.5ms,每块检查超时), 采样对配额改为按未完成状态数公平分摊并把上限提到 8M(交互 2M)。 - 真实 MF4-Record.MF4(283 信号)全部统计状态在 1 帧内完成;悬停+移动帧中位 2~3ms。 验证:离屏探针 p20/p20c/p20d/p21/p22/p23/p25 全绿(新增 p25 12 项); make release / make debug 零 warning;Release 808,960 B。共享规则已同步到 Documents/agent_mem.md。
This commit is contained in:
1 parent
8de8a8fb85
commit
ea704b03ea
9 files changed
+424
-553
No files matched your search
@@ -2648,6 +2648,10 @@ namespace jdi
|
||||
// 本函数在 `EdgeScanFor` 里按“未完成的状态”逐个调用,288 条信号时单帧会 Post 288 次!
|
||||
// 大量 `WM_MSG`+重绘会把优先级更低的 `WM_TIMER` 饿死(分组折起动画因此永远结束不了),
|
||||
// 同时把 CPU 占满、拖慢所有交互。用一个“本帧已请求”标志收敛成一次。
|
||||
if (m_loadingBusy)
|
||||
{
|
||||
return; // 加载中:不推进、不自请求(否则加载进度被统计重绘拖慢)
|
||||
}
|
||||
if (m_edgeScanRequestFrame == m_edgeScanFrame)
|
||||
{
|
||||
return;
|
||||
@@ -2705,6 +2709,14 @@ namespace jdi
|
||||
falling = 0;
|
||||
complete = false;
|
||||
|
||||
// ⚠️ **宿主正在加载文件时不推进**:加载线程的主循环不断 `UpdateWindow` 触发整帧绘制,
|
||||
// 若这里继续扫,加载会被统计抢走 CPU(用户报告“统计没算完就无法开始加载”)。
|
||||
// 加载完成后数据层结构变化会整体作废累积状态,本来就要重算。
|
||||
if (m_loadingBusy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const std::size_t count = signal.values.size();
|
||||
if (count < 2)
|
||||
{
|
||||
@@ -2800,6 +2812,7 @@ namespace jdi
|
||||
created.justReset = true;
|
||||
m_edgeScans.push_back(std::move(created));
|
||||
state = &m_edgeScans.back();
|
||||
++m_edgeScanRevision; // 新状态:让面板重算(可能刚从“统计中…”切换)
|
||||
}
|
||||
else if (!centre && state->threshold != threshold)
|
||||
{
|
||||
@@ -2814,6 +2827,7 @@ namespace jdi
|
||||
state->justReset = true;
|
||||
std::fill(state->blockRising.begin(), state->blockRising.end(), 0);
|
||||
std::fill(state->blockFalling.begin(), state->blockFalling.end(), 0);
|
||||
++m_edgeScanRevision;
|
||||
}
|
||||
|
||||
// ---- 中心轴:**就地**计算所需的那一小段均值滤波曲线 ---------------------
|
||||
@@ -2989,6 +3003,17 @@ namespace jdi
|
||||
std::size_t scanned = 0;
|
||||
std::size_t pair = state->scannedPair;
|
||||
std::size_t block = (pair > 0) ? ((pair - 1) / kEdgeBlockSamples) : 0;
|
||||
/** @brief 本帧的**时间预算**是否已用完(每块检查一次,QPC 开销可忽略)。 */
|
||||
const auto timeUp = [this]() -> bool
|
||||
{
|
||||
if (m_edgeScanDeadline <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
LARGE_INTEGER now = {};
|
||||
QueryPerformanceCounter(&now);
|
||||
return now.QuadPart >= m_edgeScanDeadline;
|
||||
};
|
||||
while (pair < count && scanned < quota && m_edgeScanBudget > 0)
|
||||
{
|
||||
const std::size_t blockFirst = block * kEdgeBlockSamples + 1;
|
||||
@@ -3057,6 +3082,10 @@ namespace jdi
|
||||
{
|
||||
++block;
|
||||
}
|
||||
if (timeUp())
|
||||
{
|
||||
break; // 本帧的时间预算用完:剩下的帧接着扫
|
||||
}
|
||||
}
|
||||
state->scannedPair = pair;
|
||||
state->complete = (pair >= count);
|
||||
@@ -3072,6 +3101,11 @@ namespace jdi
|
||||
}
|
||||
state->pumpedPairs += scanned;
|
||||
m_edgeScanBudget -= std::min(m_edgeScanBudget, scanned);
|
||||
if (scanned > 0)
|
||||
{
|
||||
// 数字(或“是否扫完”)变了 ⇒ 面板缓存键要跟着变,否则会一直贴旧像素。
|
||||
++m_edgeScanRevision;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user