vsync是显示屏的垂直同步信号它指示着前一帧的结束,和新一帧的开始。
在本人的G965手机源码中,可以看到硬件的vsync首先是外部command屏幕的GPIO中断出发的(简称vsync_irq),中断handler里会调用wake_up_interruptible_all函数唤醒内核态vsync线程(简称k_vsync_thread),在k_vsync_thread中会调用sysfs_notify函数唤醒一个kworker,这个kworker的callback函数里会调用wake_up_interruptible唤醒用户态的vsync线程(简称u_vsync_thread),那么这个process如下。
vsync_irq
+
|
|
v
k_vsync_thread
+
|
|
v
kworker
+
|
|
v
u_vsync_thread
sysfs_notify:可以理解为一种通信机制,用来唤醒在读写文件(sysfs节点)时因调用select()或poll()而阻塞的用户态进程。
vsync经过多个线程的长途跋涉才让用户态服务程序感知到,不免怀疑是否会不及时。中断的响应是很快的,而后面三个线程的唤醒才是探讨performance的关键。
task(线程/进程)被唤醒的代码流程如下
try_to_wake_up -> ttwu_queue -> ttwu_do_activate -> ttwu_activate -> activate_task -> enqueue_task
+
|
|
v
ttwu_do_wakeup -> check_preempt_curr
对应CFS调度类里的函数
const struct sched_class fair_sched_class = {
......
.enqueue_task = enqueue_task_fair,
......
.check_preempt_curr = check_preempt_wakeup,
......
};
休眠的进程(非实时)在唤醒时会立刻抢占CPU么?CFS调度算法为了保证交互式进程的响应速度,加入了WAKEUP_PREEMPTION这个feature,可以cat如下文件查看是否打开了这个feature。
cat /sys/kernel/debug/sched_features
被唤醒的进程抢占CPU是一个大概率事件,因为休眠的进程在唤醒时会在enqueue_task_fair -> enqueue_entity -> place_entity这个调用流程里获得vruntime的补偿(和cfs_rq->min_vruntime的值保持差别不大),补偿的大小由
/proc/sys/kernel/sched_latency_ns
的数值和GENTLE_FAIR_SLEEPERS这个feature决定。除此之外,还有
/proc/sys/kernel/sched_wakeup_granularity_ns
这个值表示current进程与被唤醒的进程两者vruntime差值大于该数值时才抢占CPU,如果这个数值越小,那么发生抢占的概率也就越高。
所以vsync大多数情况是可以及时上报的,当然也会有delay的时候,这对于智能手机60HZ的要求是完全可以的,而对于有实时要求的场景来说,还在用这个方式就有点勉强了,可以缩短上报流程提高优先级来解决。