深度修复实验性功能预览曲线导致的交互卡顿(平移/拖滑块/缩放/改样式不跟手)

根因:派生预览曲线按可见采样窗口计算,代价正比于窗口采样数(弱波增强整段 2576 万采样单条约 368ms);旧策略对超过 4M 采样的窗口不缓存,导致大跨度下每帧(含悬停重绘)重算整段曲线;拖滑块每帧改参数即每帧重算。实测弱波增强整段拖滑块单帧约 2303ms,2.5s 跨度约 89ms。

修复:1) 大窗口也进缓存并按总字节预算淘汰(静止重绘 2247ms-0.25ms);2) 交互期间对超出预算的大窗口延迟重算、复用旧曲线(拖滑块 2303ms-18ms),小窗口仍实时重算;3) 计算缓冲改 thread_local 复用容量。仅改何时计算与是否缓存,几何与取值算法不变,逐像素比对 0 差异。

缩放等级差异:整段放大时窗口为整条信号(千万级)每帧重算故最卡;极小跨度窗口仅几千采样故不卡;中间跨度几十毫秒亦卡。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-11 11:32:58 +08:00
1 parent 2f7a6bc2d2
commit aca84df0ac
4 files changed
+138 -19

No files matched your search

+18 -7
View File
@@ -1032,7 +1032,10 @@ namespace jdi
}
// 后续各阶以上一阶的结果为输入(double 中转,避免 float→double 的精度损失累积)。
std::vector<double> buffer(values.size(), std::numeric_limits<double>::quiet_NaN());
// 中转缓冲复用容量(线程本地),避免每阶重新分配上千万元素的向量。
thread_local std::vector<double> bufferBuffer;
std::vector<double>& buffer = bufferBuffer;
buffer.assign(values.size(), std::numeric_limits<double>::quiet_NaN());
std::vector<float> stage;
for (int iteration = 1; iteration < stages; ++iteration)
{
@@ -1070,7 +1073,7 @@ namespace jdi
* @return 确实有采样点被改动返回 true;完全无弱波时返回 false。
*/
bool ApplyWeakBoostStage(const std::vector<float>& input, double strength,
std::vector<float>& output)
std::vector<float>& output, std::vector<BoostExtremum>& extremes)
{
const std::size_t count = input.size();
output.assign(count, std::numeric_limits<float>::quiet_NaN());
@@ -1092,7 +1095,7 @@ namespace jdi
// 1) 识别波峰 / 波谷:扫描单调段,方向翻转处的上一个采样点即为极值点。
// 波峰(先升后降)与波谷(先降后升)必然交替出现,
// 因此同类极值就是极值序列里下标 ±2 的两个。
std::vector<BoostExtremum> extremes;
extremes.clear();
{
int direction = 0; // 当前单调段方向(+1 上升、-1 下降)。
bool hasPrevious = false;
@@ -1145,7 +1148,9 @@ namespace jdi
// 2) 逐个极值点判定“是否偏弱”,并算出它自己的目标偏移量。
const std::size_t extremeCount = extremes.size();
std::vector<double> shift(extremeCount, 0.0);
thread_local std::vector<double> shiftBuffer;
std::vector<double>& shift = shiftBuffer;
shift.assign(extremeCount, 0.0);
for (std::size_t k = 2; k + 2 < extremeCount; ++k)
{
const BoostExtremum& current = extremes[k];
@@ -1241,7 +1246,13 @@ namespace jdi
}
// 第 1 阶:从原始采样值出发(非有限值保持 NaN)。
std::vector<float> current(count, std::numeric_limits<float>::quiet_NaN());
// 工作缓冲用线程本地变量复用容量:单条曲线动辄上千万采样,若每次调用都重新分配
// 并零初始化,单条「弱波增强」的耗时会被明显放大(内存分配 + page fault)。
thread_local std::vector<float> currentBuffer;
thread_local std::vector<float> nextBuffer;
thread_local std::vector<BoostExtremum> extremesBuffer;
std::vector<float>& current = currentBuffer;
current.assign(count, std::numeric_limits<float>::quiet_NaN());
for (std::size_t index = 0; index < count; ++index)
{
const double value = values[index];
@@ -1256,10 +1267,10 @@ namespace jdi
// 多次迭代时相邻的弱波会互相抬高彼此的基准,从而把较宽的弱波区逐步恢复。
const int stages = std::max(1, std::min(iterations, 1000));
const double strength = std::max(0.0, std::min(1.0, level));
std::vector<float> next;
std::vector<float>& next = nextBuffer;
for (int stage = 0; stage < stages; ++stage)
{
if (!ApplyWeakBoostStage(current, strength, next))
if (!ApplyWeakBoostStage(current, strength, next, extremesBuffer))
{
// 这一阶没有任何采样点需要调整:后续迭代次数也不会再有变化,提前结束。
break;