1026 lines
19 KiB
Markdown
1026 lines
19 KiB
Markdown
# 图表渲染整体架构设计
|
||
|
||
## 1. 总体模型
|
||
|
||
每个 RenderAble 拆成四类数据:
|
||
|
||
```text
|
||
State 三缓冲
|
||
Input 三缓冲
|
||
Render 私有缓存
|
||
Color 三缓冲
|
||
```
|
||
|
||
职责边界:
|
||
|
||
```text
|
||
State:
|
||
小型、可复制、表示显示配置和稳定状态。
|
||
|
||
Input:
|
||
外部输入到渲染线程的增量数据。
|
||
|
||
RenderCache:
|
||
渲染侧长期缓存,不复制,不参与状态交换。
|
||
|
||
Color:
|
||
后台生成的像素图,交给 Qt 主线程贴图。
|
||
```
|
||
|
||
核心原则:
|
||
|
||
```text
|
||
配置走 State。
|
||
样本走 Input。
|
||
缓存留在 RenderData 私有成员。
|
||
像素走 Color。
|
||
```
|
||
|
||
不能把流式样本、环形缓冲、累计矩阵塞进 State。
|
||
|
||
State 的同步语义是复制。
|
||
|
||
Input 的同步语义是角色交换。
|
||
|
||
RenderCache 的语义是渲染侧所有权。
|
||
|
||
## 2. 整体流程
|
||
|
||
```text
|
||
用户操作 / 属性修改
|
||
↓
|
||
修改 edit_state
|
||
↓
|
||
state edit -> ready 复制
|
||
↓
|
||
state ready -> render 交换
|
||
```
|
||
|
||
```text
|
||
数据输入 / giveData
|
||
↓
|
||
追加到 edit_input
|
||
↓
|
||
input edit -> ready 交换
|
||
↓
|
||
input ready -> render 交换
|
||
↓
|
||
prepareData 消费 render_input
|
||
↓
|
||
更新 RenderCache
|
||
↓
|
||
clear render_input
|
||
```
|
||
|
||
```text
|
||
draw
|
||
↓
|
||
读取 render_state
|
||
↓
|
||
读取 RenderCache
|
||
↓
|
||
写 render_color
|
||
↓
|
||
color render -> ready 交换
|
||
↓
|
||
Qt paintEvent 消费 ready_color 到 front_color
|
||
```
|
||
|
||
完整数据链路:
|
||
|
||
```text
|
||
edit_state + edit_input
|
||
↓
|
||
prepareData
|
||
render_state + render_input
|
||
↓
|
||
RenderCache
|
||
↓
|
||
render_color
|
||
↓
|
||
ready_color
|
||
↓
|
||
front_color
|
||
```
|
||
|
||
## 3. 三缓冲控制器
|
||
|
||
State、Input、Color 的角色交换都使用同一个控制器:
|
||
|
||
```text
|
||
Triple_Role_Buffer_Control
|
||
```
|
||
|
||
控制器只负责:
|
||
|
||
```text
|
||
role -> physical index
|
||
busy 标记
|
||
lease
|
||
swap_role
|
||
```
|
||
|
||
它不理解实际数据类型。
|
||
|
||
实际数据可以是:
|
||
|
||
```text
|
||
RenderState
|
||
InputData
|
||
ColorBuffer
|
||
```
|
||
|
||
控制器语义:
|
||
|
||
```text
|
||
slot_state 管角色映射。
|
||
busy 管物理占用。
|
||
lease 管一次具体使用。
|
||
swap_role 只交换角色,不复制业务数据。
|
||
```
|
||
|
||
长时间使用某个角色时,必须释放 lease,不允许按 role 释放。
|
||
|
||
因为使用期间 role 可能已经被交换。
|
||
|
||
## 4. State 三缓冲
|
||
|
||
State 有三个角色:
|
||
|
||
```text
|
||
State_Edit
|
||
State_Ready
|
||
State_Render
|
||
```
|
||
|
||
State 里只放:
|
||
|
||
```text
|
||
坐标轴指针
|
||
范围
|
||
颜色
|
||
画笔
|
||
字体
|
||
hover 状态
|
||
marker 状态
|
||
模式开关
|
||
点数配置
|
||
```
|
||
|
||
State 里不放:
|
||
|
||
```text
|
||
输入样本列表
|
||
环形缓冲区
|
||
QImage
|
||
累计矩阵
|
||
曲线当前数据缓存
|
||
WaterFall 行缓存
|
||
Afterglow 能量累计缓存
|
||
```
|
||
|
||
State 同步流程:
|
||
|
||
```text
|
||
如果 edit_state.version 新于 ready_state.version:
|
||
mark ready_state
|
||
copy edit_state -> ready_state
|
||
unmark ready_state
|
||
|
||
如果 ready_state.version 新于 render_state.version:
|
||
swap ready_state, render_state
|
||
```
|
||
|
||
State 的核心意义:
|
||
|
||
```text
|
||
把可复制配置从编辑侧稳定发布给渲染侧。
|
||
跳过中间状态。
|
||
保证 CPU 绘制时读取稳定 render_state。
|
||
```
|
||
|
||
## 5. Input 三缓冲
|
||
|
||
Input 有三个角色:
|
||
|
||
```text
|
||
Input_Edit
|
||
Input_Ready
|
||
Input_Render
|
||
```
|
||
|
||
InputData 里放增量输入:
|
||
|
||
```text
|
||
WaterFall 新行
|
||
AudioFrequent 新功率点
|
||
TimeAxis 新时间点
|
||
SweepFrequent 新块数据
|
||
Planisphere 新星座点
|
||
Spectrum 新曲线样本
|
||
Afterglow 新功率行
|
||
```
|
||
|
||
输入线程只追加到 edit_input。
|
||
|
||
追加成功后:
|
||
|
||
```text
|
||
input_slot.version = ++mInputVersion
|
||
input_slot.pending = true
|
||
requestRender()
|
||
```
|
||
|
||
Input 同步流程:
|
||
|
||
```text
|
||
如果 edit_input.pending 且 edit_input.version 新于 ready_input.version:
|
||
swap edit_input, ready_input
|
||
|
||
如果 ready_input.pending 且 ready_input.version 新于 render_input.version:
|
||
swap ready_input, render_input
|
||
```
|
||
|
||
prepareData 消费流程:
|
||
|
||
```text
|
||
auto input = renderInputData()
|
||
for each delta in input:
|
||
更新 RenderCache
|
||
clearRenderInput()
|
||
```
|
||
|
||
clearRenderInput 必须同时完成:
|
||
|
||
```text
|
||
清空 render_input 数据
|
||
render_input.pending = false
|
||
```
|
||
|
||
Input 三缓冲的核心意义:
|
||
|
||
```text
|
||
输入数据不复制到 State。
|
||
输入数据不触发 RenderState 大对象复制。
|
||
渲染侧按批消费增量。
|
||
edit_input 可以在下一轮继续接收新数据。
|
||
```
|
||
|
||
## 6. Render 私有缓存
|
||
|
||
RenderCache 是 RenderData 的私有成员,不参与三缓冲复制。
|
||
|
||
典型对象:
|
||
|
||
```text
|
||
QImage image
|
||
WaterFallRingBuffer ringBuffer
|
||
TimeAxis::Psc::StreamRingBuffer_ST buffer
|
||
AudioFrequent::Psc::StreamRingBuffer_ST buffer
|
||
SweepFrequent::mFrequents
|
||
Planisphere::dataList
|
||
Afterglow cachedPowerData / oldCachePowerData / mergedPowerData
|
||
Spectrum curPowers / maxPowers / minPowers / frequents
|
||
```
|
||
|
||
RenderCache 的来源:
|
||
|
||
```text
|
||
render_state 配置
|
||
render_input 增量
|
||
```
|
||
|
||
RenderCache 的更新位置:
|
||
|
||
```text
|
||
prepareData()
|
||
```
|
||
|
||
RenderCache 的读取位置:
|
||
|
||
```text
|
||
draw()
|
||
```
|
||
|
||
RenderCache 不应该由属性 setter 直接修改。
|
||
|
||
属性 setter 只改 edit_state。
|
||
|
||
数据输入函数只追加 edit_input。
|
||
|
||
RenderAble 可以选择开启独立像素缓存:
|
||
|
||
```text
|
||
RenderAble::setIndependentPixelCache(true)
|
||
```
|
||
|
||
开启后:
|
||
|
||
```text
|
||
该 RenderAble 的 markRenderDirty 不再触发整张 Plot renderColor。
|
||
该 RenderAble 单独 prepare/draw 到自己的透明 QImage。
|
||
Plot::paintEvent 在绘制 Plot 级 ColorBuffer 后叠加独立像素缓存。
|
||
```
|
||
|
||
默认不开启。
|
||
|
||
它适合:
|
||
|
||
```text
|
||
PerformanceShower
|
||
轻量 overlay
|
||
高频变化但不应该触发整图重绘的辅助层
|
||
```
|
||
|
||
## 7. Color 三缓冲
|
||
|
||
Color 有三个角色:
|
||
|
||
```text
|
||
Color_Front
|
||
Color_Ready
|
||
Color_Render
|
||
```
|
||
|
||
Color_Render:
|
||
|
||
```text
|
||
CPU 后台线程写入。
|
||
```
|
||
|
||
Color_Ready:
|
||
|
||
```text
|
||
后台完成后等待 Qt 主线程消费。
|
||
```
|
||
|
||
Color_Front:
|
||
|
||
```text
|
||
Qt paintEvent 当前显示。
|
||
```
|
||
|
||
发布流程:
|
||
|
||
```text
|
||
render_color.version 新于 ready_color.version:
|
||
swap ready_color, render_color
|
||
|
||
ready_color.version 新于 front_color.version:
|
||
request update
|
||
```
|
||
|
||
paintEvent 流程:
|
||
|
||
```text
|
||
按 Plot_Buffer_Acquire_Mode 消费 ready_color
|
||
mark front_color
|
||
drawImage(front_color)
|
||
unmark front_color
|
||
```
|
||
|
||
Plot_Buffer_Acquire_Mode 有两种策略:
|
||
|
||
```text
|
||
Try:
|
||
paintEvent 尝试交换 ready_color -> front_color。
|
||
如果物理 buffer 正忙,立即放弃本次新帧消费。
|
||
这是默认模式,GUI 线程不进入 atomic_wait。
|
||
|
||
Wait:
|
||
paintEvent 等待参与交换或 front_color lease 可用。
|
||
只适合调用方明确接受 GUI 线程短暂等待的场景。
|
||
```
|
||
|
||
Color 发布侧仍然可以等待 Color_Render / Color_Ready,因为它运行在调度和后台渲染流程,不阻塞 Qt paintEvent。
|
||
|
||
## 8. 三缓冲获取策略
|
||
|
||
三缓冲获取策略不是单一全局开关,而是分层控制。
|
||
|
||
Plot 层:
|
||
|
||
```text
|
||
Plot_Buffer_Acquire_Mode
|
||
```
|
||
|
||
只控制 Qt paintEvent 消费 Color_Ready / Color_Front 的行为。
|
||
|
||
默认:
|
||
|
||
```text
|
||
Try
|
||
```
|
||
|
||
RenderAble 层:
|
||
|
||
```text
|
||
Plot_Buffer_Acquire_Mode
|
||
```
|
||
|
||
控制单个 RenderAble 在后台 draw 阶段获取 State_Render lease 的行为。
|
||
|
||
默认:
|
||
|
||
```text
|
||
Wait
|
||
```
|
||
|
||
RenderAble 设置为 Try 后:
|
||
|
||
```text
|
||
draw 阶段取不到 State_Render lease
|
||
↓
|
||
跳过该 RenderAble 本帧绘制
|
||
```
|
||
|
||
State/Input 的编辑发布路径默认仍使用 Wait。
|
||
|
||
原因:
|
||
|
||
```text
|
||
setter / giveData 当前多数是 void 语义。
|
||
Try 失败后没有统一返回值表达本次修改是否被接受。
|
||
在没有重新设计 API 返回语义前,不允许静默丢弃编辑和输入。
|
||
```
|
||
|
||
Plot 还保存一个 RenderAble 默认获取策略:
|
||
|
||
```text
|
||
Plot::renderAbleBufferAcquireMode()
|
||
Plot::setRenderAbleBufferAcquireMode()
|
||
```
|
||
|
||
RenderAble init 到 Plot 时会复制父 Plot 当前的默认策略。
|
||
|
||
之后单个 RenderAble 可以独立调用:
|
||
|
||
```text
|
||
RenderAble::bufferAcquireMode()
|
||
RenderAble::setBufferAcquireMode()
|
||
```
|
||
|
||
## 9. 调度版本
|
||
|
||
渲染调度使用 RenderPipeline 的帧版本。
|
||
|
||
State dirty 和 Input dirty 都会推进帧版本。
|
||
|
||
区别:
|
||
|
||
```text
|
||
State dirty:
|
||
edit_state.version++
|
||
frame_version++
|
||
|
||
Input dirty:
|
||
input_version++
|
||
frame_version++
|
||
```
|
||
|
||
Input dirty 不递增 edit_state.version。
|
||
|
||
这点非常重要。
|
||
|
||
它保证流式输入不会导致 RenderState 全量复制。
|
||
|
||
## 10. RenderScheduler
|
||
|
||
渲染调度使用一个全局 RenderScheduler。
|
||
|
||
RenderScheduler 由两部分组成:
|
||
|
||
```text
|
||
单线程 asio::io_context
|
||
asio::thread_pool
|
||
```
|
||
|
||
单线程 asio::io_context 负责:
|
||
|
||
```text
|
||
Plot 注册/移除
|
||
resize 状态写入
|
||
timer async_wait
|
||
submitRender
|
||
prepareData
|
||
finishRender
|
||
jobState 推进
|
||
Color 发布
|
||
```
|
||
|
||
asio::thread_pool 负责:
|
||
|
||
```text
|
||
renderColor
|
||
draw
|
||
CPU 像素绘制
|
||
```
|
||
|
||
不允许再引入:
|
||
|
||
```text
|
||
TimerThread
|
||
按 Plot 名称绑定渲染线程
|
||
业务层 bindRenderThread
|
||
多个 QThread scheduler
|
||
```
|
||
|
||
所有 Plot 共用一个 scheduler。
|
||
|
||
## 11. 渲染管线和调度策略
|
||
|
||
渲染拆成两层:
|
||
|
||
```text
|
||
RenderPipeline:
|
||
管 State/Input/Color 三缓冲、jobState、一次提交。
|
||
|
||
RenderSchedulePolicy:
|
||
管什么时候触发一次提交。
|
||
```
|
||
|
||
核心边界:
|
||
|
||
```text
|
||
submitRenderOnce()
|
||
```
|
||
|
||
只负责:
|
||
|
||
```text
|
||
当前是否可以提交一帧。
|
||
如果可以,准备数据并投递 CPU render。
|
||
成功返回 true。
|
||
失败返回 false。
|
||
```
|
||
|
||
它不负责:
|
||
|
||
```text
|
||
限速
|
||
是否追帧
|
||
是否响应 timer
|
||
finish 后是否继续
|
||
```
|
||
|
||
这些全部属于调度策略。
|
||
|
||
Plot 级调度模式:
|
||
|
||
```text
|
||
Plot_Render_Schedule_Mode::Timer_Check
|
||
Plot_Render_Schedule_Mode::Chase_Latest
|
||
Plot_Render_Schedule_Mode::Max_Fps
|
||
Plot_Render_Schedule_Mode::Manual
|
||
```
|
||
|
||
语义:
|
||
|
||
```text
|
||
Timer_Check:
|
||
只响应 asio timer。
|
||
dirty 只推进版本,不立即提交。
|
||
|
||
Chase_Latest:
|
||
dirty、timer、finish、manual 都会尝试提交。
|
||
finish 后如果仍有新状态,会继续追最新帧。
|
||
|
||
Max_Fps:
|
||
dirty 不丢弃。
|
||
如果没到下一帧允许提交时间,只记录 pending 并安排 mSubmitTimer。
|
||
到点后只提交最新状态。
|
||
|
||
Manual:
|
||
只响应 Render_Request_Source::Manual。
|
||
```
|
||
|
||
请求来源:
|
||
|
||
```text
|
||
Render_Request_Source::Timer
|
||
Render_Request_Source::Dirty
|
||
Render_Request_Source::Finish
|
||
Render_Request_Source::Manual
|
||
```
|
||
|
||
`startRender(int fps)` 的语义改成:
|
||
|
||
```text
|
||
启动渲染调度。
|
||
设置 timer 检查频率。
|
||
是否按这个 fps 限制实际 render,由 Plot_Render_Schedule_Mode 决定。
|
||
```
|
||
|
||
严格限帧使用:
|
||
|
||
```text
|
||
Plot_Render_Schedule_Mode::Max_Fps
|
||
Plot::setMaxRenderFps()
|
||
```
|
||
|
||
asio timer 分成两个:
|
||
|
||
```text
|
||
mRenderTimer:
|
||
周期性产生 Render_Request_Source::Timer。
|
||
|
||
mSubmitTimer:
|
||
Max_Fps 或 RenderAble 局部 Max_Fps 的延迟提交唤醒。
|
||
```
|
||
|
||
RenderAble 级策略:
|
||
|
||
```text
|
||
RenderAble_Render_Schedule_Mode::Inherit
|
||
RenderAble_Render_Schedule_Mode::Chase_Latest
|
||
RenderAble_Render_Schedule_Mode::Max_Fps
|
||
RenderAble_Render_Schedule_Mode::On_Dirty
|
||
RenderAble_Render_Schedule_Mode::Manual
|
||
```
|
||
|
||
RenderAble 默认:
|
||
|
||
```text
|
||
Inherit
|
||
```
|
||
|
||
RenderAble 局部策略控制:
|
||
|
||
```text
|
||
本轮是否把该 RenderAble 的 State/Input 推进到 render 侧。
|
||
```
|
||
|
||
如果一个 RenderAble 没通过自己的策略闸门:
|
||
|
||
```text
|
||
prepareData 不执行。
|
||
render_state / RenderCache 保持上一帧。
|
||
draw 仍读取上一帧已经发布的 render 侧数据。
|
||
```
|
||
|
||
这样一个高频对象不会强迫静态对象每帧同步 State/Input。
|
||
|
||
独立像素缓存对象也走同一套 RenderAble 策略。
|
||
|
||
PerformanceShower 可以观测:
|
||
|
||
```text
|
||
Pipeline.renderScheduleMode
|
||
Pipeline.renderCheckFps
|
||
Pipeline.maxRenderFps
|
||
Pipeline.renderSubmitPending
|
||
RenderAble.<name>.renderScheduleMode
|
||
RenderAble.<name>.renderScheduleMaxFps
|
||
```
|
||
|
||
右键菜单的 Plot 基础栏提供:
|
||
|
||
```text
|
||
渲染策略下拉框
|
||
渲染检查FPS
|
||
最大渲染FPS
|
||
```
|
||
|
||
## 12. prepareData 边界
|
||
|
||
prepareData 的标准流程:
|
||
|
||
```text
|
||
syncStatePipeline()
|
||
读取 render_state 配置
|
||
读取 render_input 增量
|
||
更新 RenderCache
|
||
clearRenderInput()
|
||
```
|
||
|
||
syncStatePipeline 内部同时处理:
|
||
|
||
```text
|
||
State edit -> ready -> render
|
||
Input edit -> ready -> render
|
||
```
|
||
|
||
prepareData 不再持有 RenderData 对象级锁。
|
||
|
||
edit_state 写入必须通过 State_Edit lease。
|
||
|
||
edit_input 写入必须通过 Input_Edit lease。
|
||
|
||
RenderCache 只允许 render 流程内部更新。
|
||
|
||
prepareData 不应该写 Color。
|
||
|
||
prepareData 不应该触发 QWidget 绘制。
|
||
|
||
prepareData 不应该把 RenderCache 复制回 State。
|
||
|
||
## 13. draw 边界
|
||
|
||
draw 的标准流程:
|
||
|
||
```text
|
||
读取 render_state
|
||
读取 RenderCache
|
||
写入当前 render_color 对应的 QPainter
|
||
```
|
||
|
||
draw 不消费 Input。
|
||
|
||
draw 不修改 edit_state。
|
||
|
||
draw 不修改 ready_state。
|
||
|
||
draw 不做输入队列交换。
|
||
|
||
## 14. 数据分类规则
|
||
|
||
判断一个字段应该放哪里:
|
||
|
||
```text
|
||
需要被属性 getter/setter 表达,体积小,可复制:
|
||
放 State。
|
||
|
||
外部不断输入,prepareData 批量消费:
|
||
放 InputData。
|
||
|
||
由 render_state + render_input 计算出来,长期保留给 draw 使用:
|
||
放 RenderData 私有缓存。
|
||
|
||
最终像素图:
|
||
放 ColorBuffer。
|
||
```
|
||
|
||
错误分类:
|
||
|
||
```text
|
||
把 QVector 大缓存放 State。
|
||
把 QImage 放 State。
|
||
把输入 list 放 State。
|
||
把 RenderCache 放 InputData。
|
||
把配置项放 InputData。
|
||
```
|
||
|
||
## 15. 锁使用边界
|
||
|
||
radio 渲染链路不允许使用 RenderData 对象级大锁。
|
||
|
||
允许存在的同步只有下面几类:
|
||
|
||
```text
|
||
Triple_Role_Buffer_Control:
|
||
使用 atomic busy / slot_state / wait / notify。
|
||
只保护物理 buffer lease 和 role 交换。
|
||
|
||
RenderPipeline:
|
||
使用 color buffer version / paintRequestPending / editStateVersion。
|
||
只保护帧发布和 Qt update 请求合并。
|
||
|
||
Plot / RenderScheduler:
|
||
mRenderEnabled / mDestroying / mActiveRenderTasks / pending render size / paint buffer acquire mode 使用 atomic。
|
||
mRenderTaskMutex + mRenderTaskDone 只用于 Plot 析构等待已投递任务结束。
|
||
RenderScheduler::postAndWait 的局部 mutex + condition_variable 只用于跨线程同步 shutdown/removePlot。
|
||
|
||
PerformanceShower:
|
||
本身是 RenderAble。
|
||
统计写入走 Input 三缓冲。
|
||
统计 map 和显示列表是 Render 私有缓存。
|
||
计数使用 CPP_Core/Core/Statistics::Speed_Statistics。
|
||
耗时使用 CPP_Core/Core/Statistics::Value_Statistics。
|
||
Value_Statistics 提供 instant / smooth / variation。
|
||
开启独立像素缓存,不进入 Plot 整图 renderColor。
|
||
统计写入按观察者节流刷新,不允许每条事件触发整图 dirty。
|
||
```
|
||
|
||
不允许重新引入:
|
||
|
||
```text
|
||
RenderData::mBufferLock
|
||
prepareData 全局锁
|
||
render size mutex
|
||
Graphic resize mutex
|
||
HoverInfo 独立 mutex
|
||
PrePareMutiDataMutex
|
||
SpinLock / SpinLockGuard
|
||
Singleton mutex + atomic 双重检查
|
||
```
|
||
|
||
prepareData 和 draw 的并发边界由调度流保证:
|
||
|
||
```text
|
||
submitRender 进入 asio scheduler。
|
||
scheduler 串行推进 jobState。
|
||
prepareData 在 scheduler 阶段消费 State/Input。
|
||
renderColor 在 asio thread_pool 阶段只读取 State_Render 和 RenderCache。
|
||
finishRender 回到 scheduler 发布 Color。
|
||
```
|
||
|
||
CPP_Core 和第三方库内部同步不属于 radio 渲染架构边界:
|
||
|
||
```text
|
||
RingBuffer_MT / StreamRingBuffer_MT:
|
||
通用多线程容器版本。
|
||
|
||
SM_RingBuffer / Cross_Process_Mutex:
|
||
跨进程共享内存同步。
|
||
|
||
Frequency_Limit:
|
||
通用频率限制器。
|
||
|
||
spdlog / asio / googlepinyin:
|
||
第三方或通用库内部同步。
|
||
```
|
||
|
||
这些同步不能向 RenderData、prepareData、draw 路径扩散。
|
||
|
||
## 16. 性能统计
|
||
|
||
性能测试框是 RenderAble,不再是 QWidget。
|
||
|
||
开启和停止性能测试只修改 PerformanceShower 的 enabled 状态。
|
||
|
||
停止性能测试不删除 PerformanceShower 对象。
|
||
|
||
原因:
|
||
|
||
```text
|
||
render/scheduler/cpu 线程可能持有 Cacl。
|
||
Cacl 需要在析构时写统计。
|
||
如果停止性能测试时删除 QWidget,会形成跨线程悬挂指针。
|
||
```
|
||
|
||
统计写入走 Input 三缓冲:
|
||
|
||
统计类型:
|
||
|
||
```text
|
||
Duration:
|
||
阶段耗时,使用 Psc::Value_Statistics。
|
||
|
||
Counter:
|
||
事件频率,使用 Psc::Speed_Statistics。
|
||
|
||
Gauge:
|
||
当前数值状态。
|
||
|
||
State:
|
||
当前文本状态。
|
||
```
|
||
|
||
统计链路:
|
||
|
||
```text
|
||
PerformanceShower::recordDuration / incrementCounter / setGauge / setState
|
||
↓
|
||
PerformanceShowerInputData events
|
||
↓
|
||
prepareData()
|
||
↓
|
||
PerformanceShowerPrivate::mScopes
|
||
↓
|
||
draw()
|
||
```
|
||
|
||
Value_Statistics 的含义:
|
||
|
||
```text
|
||
instant:
|
||
本次采样值。
|
||
|
||
average:
|
||
保留旧字段语义的 EWMA 平均值。
|
||
|
||
smooth:
|
||
类似 SRTT 的平滑值。
|
||
|
||
variation:
|
||
类似 RTTVAR 的波动估计。
|
||
它不是严格方差或标准差,而是 instant 与 smooth 偏差的 EWMA。
|
||
|
||
p95:
|
||
最近 64 次采样的 95 分位估计。
|
||
```
|
||
|
||
性能框当前分组:
|
||
|
||
```text
|
||
Pipeline:
|
||
schedulerQueueWait
|
||
requestToSubmit
|
||
cpuQueueWait
|
||
prepareData
|
||
renderColor
|
||
draw
|
||
publishRenderColor
|
||
updateToPaint
|
||
paintEvent
|
||
jobState
|
||
activeRenderTasks
|
||
renderEnabled
|
||
paintBufferAcquireMode
|
||
renderAbleDefaultAcquireMode
|
||
paintRequestPending
|
||
editStateVersion
|
||
renderStateVersion
|
||
|
||
RenderAble:
|
||
<RenderAble>.prepareData
|
||
<RenderAble>.draw
|
||
<RenderAble>.stateLeaseMiss
|
||
<RenderAble>.bufferAcquireMode
|
||
|
||
Buffer:
|
||
Color.mark/swap/busy/swapNoNeed/wait
|
||
<RenderAble>.State.mark/swap/busy/swapNoNeed/wait
|
||
<RenderAble>.Input.mark/swap/busy/swapNoNeed/wait
|
||
```
|
||
|
||
性能框显示策略:
|
||
|
||
```text
|
||
默认视图:
|
||
Plot
|
||
|
||
Plot 视图显示:
|
||
Pipeline
|
||
General
|
||
Color buffer
|
||
|
||
左侧栏显示:
|
||
一级:Plot / 每个有统计数据的 RenderAble
|
||
二级:当前对象拥有的数据面
|
||
|
||
Plot 的二级数据面:
|
||
Pipeline
|
||
General
|
||
Color
|
||
|
||
RenderAble 的二级数据面:
|
||
RenderAble
|
||
State
|
||
Input
|
||
|
||
内容区:
|
||
不显示 [Pipeline] / [Buffer] / [RenderAble] 这种分组标题。
|
||
当前层级已经表达数据归属。
|
||
指标名会去掉已由层级表达的对象和缓冲前缀。
|
||
内容过长时显示滚动条,鼠标滚轮滚动内容区。
|
||
|
||
布局宽度策略:
|
||
左侧两级栏宽只在栏项目变化时重算。
|
||
右侧指标内容宽只在切换视图时重算。
|
||
```
|
||
|
||
PerformanceShower 的刷新策略:
|
||
|
||
```text
|
||
统计事件:
|
||
写入 PerformanceShower Input。
|
||
不逐条 markRenderDirty。
|
||
|
||
观察者刷新:
|
||
普通统计事件最多 10Hz 触发一次独立像素缓存刷新。
|
||
Clear / 选择视图 / 滚动 立即刷新。
|
||
|
||
排除项:
|
||
PerformanceShower 自身不进入 RenderAble 性能统计列表。
|
||
```
|
||
|
||
Pull snapshot 的含义:
|
||
|
||
```text
|
||
Push gauge:
|
||
每帧主动把每个 RenderAble 的每个 Buffer 统计写成事件。
|
||
会制造大量 PerformanceShower Input。
|
||
|
||
Pull snapshot:
|
||
Buffer 控制器只维护 atomic 计数。
|
||
性能面板刷新时按需读取当前快照。
|
||
没有面板刷新就不产生统计事件。
|
||
```
|
||
|
||
完整性能面板最终应该使用 QWidget:
|
||
|
||
```text
|
||
Overlay:
|
||
只显示摘要。
|
||
|
||
右键菜单 QWidget 面板:
|
||
显示完整 Pipeline / RenderAble / Buffer 树。
|
||
使用低频 pull snapshot 刷新。
|
||
```
|
||
|
||
## 17. 最终规则
|
||
|
||
```text
|
||
State 负责配置快照。
|
||
Input 负责增量输入交接。
|
||
RenderCache 负责渲染侧长期缓存。
|
||
Color 负责像素交接。
|
||
```
|
||
|
||
一句话:
|
||
|
||
```text
|
||
每个 RenderAble 使用 State 三缓冲发布小状态,使用 Input 三缓冲发布增量输入,使用 RenderData 私有缓存保存重型渲染中间结果,使用 Color 三缓冲把后台像素图交给 Qt 主线程。
|
||
```
|