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-appVsyncWorkDuration-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.cppWorkDuration::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.60msLate 模式(正常合成)453 次79.5%
27.60msEarlyGpu 模式(GPU合成提前唤醒)117 次20.5%

5.2 变化规律

变化规律与 EarlyGpuFrames counter 完美对应:

VsyncWorkDuration-sf 变化EarlyGpuFrames说明
15.60 → 27.60ms2发生 GPU 合成,切换到 EarlyGpu 模式
27.60 → 15.60ms0GPU 合成倒计时归零,回到 Late 模式

5.3 三个 WorkDuration 典型联动值(120Hz)

VsyncWorkDuration-sfVsyncWorkDuration-appVsyncWorkDuration-appSf
15.60ms(Late)20.00ms8.33ms
27.60ms(EarlyGpu)20.00ms8.33ms / 16.67ms

六、性能分析意义

场景含义关注点
长时间处于 27.60ms频繁 GPU 合成SF 需要更多时间,可能影响帧延迟
频繁在 15.60/27.60 间切换GPU/Client 合成策略频繁变化可能是图层变化、模糊效果导致
值偏大SF 唤醒更早留给 App 的时间更少(App 需提前交付 buffer)
值偏小SF 唤醒较晚延迟更低,但 SF 合成超时风险更高

对丢帧分析的帮助

  1. SF 合成超时:如果 SF 实际工作时间 > VsyncWorkDuration-sf,会导致错过目标 Vsync,引发丢帧
  2. App 交付延迟:VsyncWorkDuration-sf 值变大时,App 的 deadline 前移,可能导致 App buffer 来不及交付
  3. GPU 合成开销评估:EarlyGpu 模式频率反映 GPU 合成的频繁程度

七、源码关键文件索引

文件关键内容
services/surfaceflinger/Scheduler/MessageQueue.h:188VsyncWorkDuration-sf 定义
services/surfaceflinger/Scheduler/MessageQueue.cpp:311setDuration() 写入
services/surfaceflinger/Scheduler/MessageQueue.cpp:396scheduleFrame() 使用 workDuration
services/surfaceflinger/Scheduler/EventThread.cpp:329VsyncWorkDuration-app/appSf 定义
services/surfaceflinger/Scheduler/EventThread.cpp:371EventThread::setDuration()
services/surfaceflinger/Scheduler/VsyncModulator.cpp:178Early/Late/EarlyGpu 切换逻辑
services/surfaceflinger/Scheduler/VsyncModulator.cpp:207updateVsyncConfigLocked()
services/surfaceflinger/Scheduler/VsyncConfiguration.cpp:305WorkDuration 配置构造
services/surfaceflinger/Scheduler/Scheduler.cpp:641Scheduler::setDuration()
services/surfaceflinger/Scheduler/Scheduler.cpp:708setVsyncConfig() 调用链
services/surfaceflinger/SurfaceFlinger.cpp:7046初始化 EventThread workDuration
services/surfaceflinger/SurfaceFlinger.cpp:7057initVsync() 初始化 SF workDuration

源码仓库: frameworks/native (本地路径: /home/zbc/code_pangu/o2-w-pre/frameworks/native/)