VsyncWorkDuration-sf 深度研究报告
一、定义与来源
VsyncWorkDuration-sf 是 SurfaceFlinger 中 MessageQueue 的一个 traced counter,定义在:
MessageQueue.h:188-189
struct Vsync {
TracedOrdinal<std::chrono::nanoseconds> workDuration
GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)};
};它通过 TracedOrdinal 模板自动写入 atrace/perfetto counter,每次赋值都会产生一条 trace 记录。
同类还有 VsyncWorkDuration-app 和 VsyncWorkDuration-appSf,分别在 EventThread.cpp:329 中通过 base::StringPrintf("VsyncWorkDuration-%s", name) 动态命名(name 为 “app” 或 “appSf”)。
二、核心含义
VsyncWorkDuration-sf 表示 SurfaceFlinger 合成工作的”预算时间”——即 SF 在收到 Vsync 唤醒后,需要在多长时间内完成 commit + composite + present 的全部工作。
它直接决定了 SF 被 Vsync 唤醒的时机:
SF 唤醒时间 = 目标 Vsync 时间 - VsyncWorkDuration-sf
值越大 → SF 越早被唤醒 → 有更多时间完成合成工作。
三、值的来源与切换机制
3.1 三档配置(VsyncModulator)
VsyncModulator 维护三档配置,每档都有不同的 sfWorkDuration:
| 模式 | 触发条件 | sfWorkDuration |
|---|---|---|
| Late(正常) | 默认/空闲状态 | 较小值(如 15.60ms) |
| Early(提前) | 有 Transaction 提交、刷新率切换中 | 较大值 |
| EarlyGpu(GPU提前) | 使用了 GPU 合成 | 较大值(如 27.60ms) |
VsyncModulator.cpp:178-200 中的选择逻辑:
auto VsyncModulator::getNextVsyncConfigType() const -> VsyncConfigType {
if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd ||
mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
return VsyncConfigType::Early;
} else if (mEarlyGpuFrames > 0) {
return VsyncConfigType::EarlyGpu;
} else {
return VsyncConfigType::Late;
}
}判断优先级:Early > EarlyGpu > Late
Early触发条件:有未完成的 EarlyWakeup 请求、EarlyEnd 调度、EarlyTransaction 倒计时未归零、或刷新率切换进行中EarlyGpu触发条件:最近使用了 GPU 合成(mEarlyGpuFrames > 0,初始值为MIN_EARLY_GPU_FRAMES = 2,每帧递减)Late触发条件:以上条件都不满足
3.2 写入路径
当 VsyncModulator 决定切换配置后,调用链如下:
VsyncModulator::updateVsyncConfigLocked()
→ Scheduler::setVsyncConfig(config, vsyncPeriod)
→ Scheduler::setDuration(Cycle::LastComposite, vsyncPeriod, config.sfWorkDuration)
→ MessageQueue::setDuration(sfWorkDuration) // ← 这里写入 trace counter
Scheduler.cpp:708-742 中的关键代码:
void Scheduler::setVsyncConfig(const VsyncConfig& config, Period vsyncPeriod) {
setDuration(Cycle::Render,
/* workDuration */ config.appWorkDuration,
/* readyDuration */ config.sfWorkDuration);
setDuration(Cycle::LastComposite,
/* workDuration */ vsyncPeriod,
/* readyDuration */ config.sfWorkDuration);
setDuration(config.sfWorkDuration);
}MessageQueue.cpp:311-326
void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) {
SFTRACE_CALL();
std::lock_guard lock(mVsync.mutex);
mVsync.workDuration = workDuration; // ← 触发 TracedOrdinal 写 trace counter
mVsync.scheduledFrameTimeOpt =
mVsync.registration->update({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.lastVsync = mVsync.lastCallbackTime.ns()});
}赋值后立即调用 VSyncCallbackRegistration::update() 重新调度下一次 Vsync 回调。
3.3 WorkDuration 配置值的计算
在 VsyncConfiguration.cpp 的 WorkDuration::constructOffsets() 中,根据当前刷新率(vsyncDuration)构造 late/early/earlyGpu 三组配置:
VsyncConfigSet WorkDuration::constructOffsets(nsecs_t vsyncDuration) const {
const auto sfDuration = sfDurationFixup(mSfDuration); // late sf duration
const auto sfEarlyDuration = sfDurationFixup(mSfEarlyDuration); // early sf duration
const auto sfEarlyGpuDuration = sfDurationFixup(mSfEarlyGpuDuration); // earlyGpu sf duration
return {
.early = { .sfWorkDuration = sfEarlyDuration, ... },
.earlyGpu = { .sfWorkDuration = sfEarlyGpuDuration, ... },
.late = { .sfWorkDuration = sfDuration, ... },
};
}这些 mSfDuration / mSfEarlyDuration 来自系统属性和 sysprop 配置。
四、与 VsyncWorkDuration-app/appSf 的关系
App端渲染流水线:
┌───────────────────┐ ┌──────────────┐ ┌────────────────┐
│ VsyncWorkDuration │ │VsyncWorkDur- │ │ VsyncWorkDur- │
│ -app │───>│ ation-appSf │───>│ ation-sf │───> HW Vsync
│ (App 渲染预算) │ │ (App→SF传递) │ │ (SF 合成预算) │
└───────────────────┘ └──────────────┘ └────────────────┘
App 被唤醒时间点 App 必须完成的 SF 被唤醒开始合成
deadline
三者共同决定了 Vsync 唤醒链:
VsyncWorkDuration-app:App 渲染的时间预算(EventThread “app” 的 workDuration)VsyncWorkDuration-appSf:App→SF 之间的 ready duration(EventThread “appSf” 的 workDuration)VsyncWorkDuration-sf:SF 合成的时间预算(MessageQueue 的 workDuration)
时间关系:
App 唤醒时间 = 目标 Vsync - VsyncWorkDuration-app - VsyncWorkDuration-appSf(readyDuration)
SF 唤醒时间 = 目标 Vsync - VsyncWorkDuration-sf
五、Trace 数据验证(Row312 锁屏解锁场景)
5.1 值分布
| 值 | 含义 | 出现次数 | 占比 |
|---|---|---|---|
| 15.60ms | Late 模式(正常合成) | 453 次 | 79.5% |
| 27.60ms | EarlyGpu 模式(GPU合成提前唤醒) | 117 次 | 20.5% |
5.2 变化规律
变化规律与 EarlyGpuFrames counter 完美对应:
| VsyncWorkDuration-sf 变化 | EarlyGpuFrames | 说明 |
|---|---|---|
| 15.60 → 27.60ms | 2 | 发生 GPU 合成,切换到 EarlyGpu 模式 |
| 27.60 → 15.60ms | 0 | GPU 合成倒计时归零,回到 Late 模式 |
5.3 三个 WorkDuration 典型联动值(120Hz)
| VsyncWorkDuration-sf | VsyncWorkDuration-app | VsyncWorkDuration-appSf |
|---|---|---|
| 15.60ms(Late) | 20.00ms | 8.33ms |
| 27.60ms(EarlyGpu) | 20.00ms | 8.33ms / 16.67ms |
六、性能分析意义
| 场景 | 含义 | 关注点 |
|---|---|---|
| 长时间处于 27.60ms | 频繁 GPU 合成 | SF 需要更多时间,可能影响帧延迟 |
| 频繁在 15.60/27.60 间切换 | GPU/Client 合成策略频繁变化 | 可能是图层变化、模糊效果导致 |
| 值偏大 | SF 唤醒更早 | 留给 App 的时间更少(App 需提前交付 buffer) |
| 值偏小 | SF 唤醒较晚 | 延迟更低,但 SF 合成超时风险更高 |
对丢帧分析的帮助
- SF 合成超时:如果 SF 实际工作时间 > VsyncWorkDuration-sf,会导致错过目标 Vsync,引发丢帧
- App 交付延迟:VsyncWorkDuration-sf 值变大时,App 的 deadline 前移,可能导致 App buffer 来不及交付
- GPU 合成开销评估:EarlyGpu 模式频率反映 GPU 合成的频繁程度
七、源码关键文件索引
| 文件 | 关键内容 |
|---|---|
services/surfaceflinger/Scheduler/MessageQueue.h:188 | VsyncWorkDuration-sf 定义 |
services/surfaceflinger/Scheduler/MessageQueue.cpp:311 | setDuration() 写入 |
services/surfaceflinger/Scheduler/MessageQueue.cpp:396 | scheduleFrame() 使用 workDuration |
services/surfaceflinger/Scheduler/EventThread.cpp:329 | VsyncWorkDuration-app/appSf 定义 |
services/surfaceflinger/Scheduler/EventThread.cpp:371 | EventThread::setDuration() |
services/surfaceflinger/Scheduler/VsyncModulator.cpp:178 | Early/Late/EarlyGpu 切换逻辑 |
services/surfaceflinger/Scheduler/VsyncModulator.cpp:207 | updateVsyncConfigLocked() |
services/surfaceflinger/Scheduler/VsyncConfiguration.cpp:305 | WorkDuration 配置构造 |
services/surfaceflinger/Scheduler/Scheduler.cpp:641 | Scheduler::setDuration() |
services/surfaceflinger/Scheduler/Scheduler.cpp:708 | setVsyncConfig() 调用链 |
services/surfaceflinger/SurfaceFlinger.cpp:7046 | 初始化 EventThread workDuration |
services/surfaceflinger/SurfaceFlinger.cpp:7057 | initVsync() 初始化 SF workDuration |
源码仓库:
frameworks/native(本地路径:/home/zbc/code_pangu/o2-w-pre/frameworks/native/)