display: Scheduling for the Android display pipeline-2020

Android用户几乎在所有互动中都大量使用显示设备;因此,良好的显示性能对于用户体验至关重要。实现这种性能并不是那么容易。有很多需要协同工作的部分,内核并不总是像人们所希望的那样支持这种协作。Android小组目前正在考虑权衡现有内核功能的多种组合以及可能的改进,以提供最佳的显示体验。

显示由Android显示管道管理,Android显示管道是一个复杂的系统,其中不同的任务和硬件加速器在应用程序的执行以及通过屏幕呈现给用户的图形内容的更新方面进行协作。显示管道负责生成显示输出,因此其性能表现直接影响用户与设备之间最重要的交互渠道之一。

除了不断增长的移动游戏行业所要求的低延迟要求外,在显示管线中优先考虑的是提供稳定的帧速率(不跳过任何帧)。此外,Android在移动设备中处于领先地位,其中有限的电量消耗和散热代表了系统必须满足的其他严格要求;这些可以概括为使功耗最小化。所有这些需求是相互对立的,需要在参与此过程的实体之间进行精确的调整和工作负载分配,以及对Linux内核调度程序和CPU频率调节器提供的功能的明智使用。此处所做的选择直接影响系统的整体性能

A short journey through the Android display pipeline

Android显示管道是软件和硬件组件的混合,不仅在显示输出的产生中,而且在应用程序执行的推进中都相互配合。参与显示管道的软件组件被拆分为应用程序本身Android框架;这些部件通过零复制机制交换数据。本节将展开Android显示管道循环,并遵循组件之间的依赖关系链,并简要介绍每个组件。

一切都始于显示控制器,除了负责显示缓冲区和显示配置外,它还负责管理显示器与系统其余部分之间的所有同步信号。当显示器准备好接受新数据进行显示(“一帧”)时,显示控制器将生成一个VSYNC信号,该信号代表整个显示管道的启动触发器。该信号以显示屏的刷新率发生,因此是周期性的:刷新率为60Hz的显示屏每16.6667ms产生一个VSYNC。由于其信号特性,选择了VSYNC这个名称是为了纪念阴极射线管(CRT)监视器的垂直同步。

通过使用SurfaceFlinger的DispSync线程直接负责将周期性VSYNC信号传播到显示管道的其他组件。根据系统的实现,这些信号可能会定期与显示控制器生成的硬件VSYNC重新对齐。DispSync还负责以预定义的不同偏移量向应用程序和主SurfaceFlinger线程广播VSYNC。延迟和位移对VSYNC信号广播的引入将在后面说明。

当用户应用程序的用户界面线程从DispSync接收到 VSYNC信号时,它将从epoll()睡眠中唤醒,并执行以下操作:

  • 处理输入事件
  • 执行由应用程序开发人员定义的Animation回调。
  • 遍历“视图View”树以布置UI并创建一个称为RenderNode树的绘制命令树。
  • 将更新的RenderNode树传递到另一个称为RenderThread的应用程序线程。
  • 执行其他一些操作,例如清理和监视,然后在epoll()中返回睡眠状态,等待下一个VSYNC。

当RenderThread在接收到RenderNode树后醒来时,它:

  • 从与SurfaceFlinger共享的BufferQueue中获取下一个输出缓冲区,并等待关联栅(fence)释放,以防缓冲区尚不可用。
  • 优化绘制命令列表(例如,通过删除对象的操作)。
  • 将列表转换为GPU命令。
  • 要求GPU执行渲染。
  • 将输出缓冲区排队到与SurfaceFlinger共享的BufferQueue中。使输出缓冲区入队,而无需等待GPU完成。它包括硬件围栏(fence),GPU通过该围栏(fence)通知SurfaceFlinger光栅化帧的渲染已完成。
  • 执行其他关闭操作,然后返回睡眠状态,等待来自UI线程的下一个请求。

如前所述,内存分配和与显示相关的数据传递是通过称为BufferQueue的临时数据结构执行的零复制操作。用户空间和内核空间之间的同步(例如,通知用户空间GPU已完成光栅化帧的生成)是通过内核中实现的篱笆(fence)实现的。https://lwn.net/Articles/702339/ fence

DispSync还使用延迟的VSYNC信号唤醒SurfaceFlinger的主线程。SurfaceFlinger负责将来自不同来源(应用程序)的栅格化帧(已经完成渲染的view)粘合(或组成)在一起,在大多数情况下,这些来源是:

  • 屏幕上当前显示的应用程序,
  • 导航栏,以及没有物理按钮的设备上,显示位于屏幕底部的按钮,
  • 状态栏(顶部的栏),其中显示时间,剩余电量,通知图标等。

因为硬件2D合成器的存在,减少了合成时间,减轻了GPU的负担,使应用程序可以自由访问它(GPU)进行渲染。在执行此操作(2d合成)方面,它比GPU更高效,更快。完成所有合成以后,准备好将最后帧发送到显示器。

------从这个叙述,回想wayland/weston。以作对比。

有关所有这些部分如何组合在一起的简化(!)概述,请参见下图:

What is the benefit of this complexity?

流水线中组织的多个实体之间划分框架生产工作流的好处是可以提高并行度并减少瓶颈。在高工作负荷的情况下,当显示器显示第N帧时 ,SurfaceFlinger已在组成(合成)第N + 1帧 ;同时,在应用程序中,RenderThread正在准备(frame) N + 2帧,而UI线程已经在frame N + 3上工作

在这种情况下,应用程序最多需要三个显示周期才能将一帧显示在显示屏上,这是一种不幸的情况,但是可以接受。通常会发生的情况是,应用程序的UI线程和RenderThread在单个周期内完成,因此管道的总延迟仅为两个周期(个人理解第一帧完成各自的渲染,下一帧完成最终帧的合成)。还有一种最好的情况,UI线程和RenderThread都很短,应用程序和SurfaceFlinger都能适应一个周期,从而将延迟减少到少于一个帧。仅当SurfaceFlinger在应用程序生成光栅化帧之后立即启动并在即将到来的VSYNC之前返回合成帧时才发生这种情况 。下面举例说明了其中两种情况:

当将信号转发到应用程序和SurfaceFlinger时,DispSync引入 的VSYNC相位移使最佳情况成为可能。如果这些组件中的每个组件的总持续时间不超过VSYNC周期,则系统将生成一个顺应显示帧速率的平滑显示输出。如果其中一个实体的行为不当且执行时间更长,则结果可能是跳过一帧或多帧。

Scheduling display pipeline entities

对于上述所有SurfaceFlinger和Hardware Composer任务, Android使用SCHED_FIFO实时调度策略。理由是这些活动对延迟敏感,并且作为系统服务,它们的执行路径是已知的,并且可以保证其执行时间不会使其他进程饿死。

应用程序也是显示管道链的组成部分,因此其性能也是用户体验的基础。不幸的是,应用程序是由第三方开发的,并且没有关于其性能特征的事先知识。将应用程序分配给诸如SCHED_RT之类的调度类,可能会导致其他以SCHED_OTHER运行的系统服务匮乏 ,从而导致不良行为。相反,使用完全公平调度程序(CFS)作为默认应用程序调度程序提供了重要的功能,例如任务之间的公平性以及与CPU频率调节器的整合集成。

---这里讲的是调度策略,android推荐先进先出的调度策略,并且不推荐其他方式如实时调度,先进先出是一种稳定的且公平的方式,不会导致因为调度策略的问题产生进程饥饿。也就是说,我们需要按部就班,而不是”凡事优先“(这里是开玩笑的)。

Schedutil, Linux, and Android

Android使用的默认CPU频率调节器是schedutil,它依赖于可运行任务的CPU利用率来选择执行它们的CPU的频率:利用率越高,它们可运行时的CPU频率就越高。该调节器非常适合移动Android设备的需求,在Android中,它还负责SCHED_RT任务,这些任务通常在主线Linux内核中以最大频率运行。

Schedutil根据对系统利用率的衡量,选择足以使系统不过载的最低频率。当任务独立且能够并行运行时,此解决方案效果很好。但是,只要存在依赖关系(在其他任务完成时被阻塞的任务),单任务利用率计费机制就不足以定义整个任务集的需求。

例如,在下面显示的场景中,schedutil看到RenderThread仅需要CPU容量的50%,因此它将CPU频率设置为最大频率的50%。但是RenderThread不能运行,直到UI线程完成其工作-这两个任务不能并行运行-因此它错过了截止日期。

Android当前实现了一种称为“ TouchBoost”的变通办法来应对这种不当行为。当用户与设备进行交互时,TouchBoost将调速器可以在给定的时间内选择的最低频率设置为较高的值。当用户与设备进行交互时,此暴力解决方案成功提供了显示管道所需的资源。这种方法的缺点是,当显示管道的工作量较低时,TouchBoost强制使用的最低频率可能远远高于管道的需求。频率的这种可能的过度供应导致一些能量浪费,这没有改善用户体验,因此应该加以限制或消除。

---虽然性能没问题,但是浪费了资源。

Some possible solutions

可以遵循许多不同的路径来处理此行为,这需要在用户空间或内核空间中或多或少地付出努力。可能的解决方案包括使用不同的调度类,在Android框架中实现反馈循环以从内核分担相互依赖任务的CPU利用率聚合,或扩展调度机制

CFS and Utilclamp

 

克服TouchBoost过度配置的一个直接解决方案是实施类似但更智能的机制,该机制可以预测相互依赖的任务按时完成所需的最低利用率。要实现此机制,需要监视应用程序线程的执行时间(随设备,内核,应用程序,应用程序的当前状态以及系统运行的其他操作而异),并且需要一个API来通知内核有关性能要求的信息。任务。

Utilclamp是Patrick Bellasi开发的一种机制;它允许用户空间以最小和/或最大上限来限制由内核衡量的一项或多项任务的利用率。这种机制允许用户空间在处理特定任务时更改内核的行为,从而确保在这些任务可运行时将CPU频率设置在给定范围内。操纵利用率限制不仅会影响CPU频率的选择,还会影响异构体系结构中的任务放置。

例如,具有较大交错时间的短任务的利用率较低,但是如果用户空间知道该任务必须尽快完成,则可以设置限制以提高该任务的最低感知利用率,从而使其在较高的速度下运行高性能的CPU。另一个示例是批处理任务,其利用率可能接近100%,但是用户空间知道它可以在后台运行,并且可以限制其最大利用率,以便该任务可以在低频下以低性能运行,高能效的CPU。

在Android显示管道的特定情况下,Android框架可以计算覆盖UI线程和RenderThread的执行的组的正确利用率。然后,它可以使用Utilclamp强制内核使用该值,而不是内部测量的单任务利用率。此解决方案将解决定义相互依赖的任务的利用的问题,但结果是,UI线程和RenderThread将与其他次要的CFS任务竞争CPU,并且没有期限或其他实时性的概念此类依赖于延迟的任务集的要求。

此外,几乎不可能通过使用规范的CLOCK_MONOTONIC或 CLOCK_THREAD_CPUTIME_ID时钟来获得对任务持续时间的良好估计,因为这些测量值受任务运行的频率和CPU容量的影响)放置任务的位置。另外,Linux内核仍然缺少将进程或线程的容量和频率不变的执行时间导出到用户空间的方法。

SCHED_RT

如果我们的应用程序任务如此重要,为什么不能选择 SCHED_FIFO或SCHED_RR 实时类?该解决方案将解决应用程序和CFS服务之间的竞争,并且由于 SCHED_RT任务也以schedutil确定的频率运行,因此与CFS相同的能源效率考虑因素以及使用利用率限制机制的考虑。

这里的问题是,尽管我们的应用程序任务的性能确实很重要,但并非所有任务部分都是时间紧迫的,并且存在我们的应用程序可能导致CFS下运行的系统服务匮乏的风险。实时限制是一种可以限制此问题的机制,但它可能导致某些应用程序带宽的损失,从而导致无法解决的解决方案。RT_RUNTIME_GREED 由丹尼尔Bristot奥利维拉是,可通过将节流实时任务放回执行,如果没有其他非实时任务运行减轻这种带宽损耗问题的解决方案。

此解决方案中仍然缺少的另一件事是任务期限的概念。

SCHED_DEADLINE

SCHED_DEADLINE是一个调度类,它具有许多可能对Android显示管道有利的功能。使用 SCHED_DEADLINE时,该应用程序的任务不会被用户空间可访问的任何其他调度类抢占。此外,该课程最后介绍了任务的期限,该期限用作调度的动态优先级。SCHED_DEADLINE还需要为任务定义运行时间;它成为带宽约束,既可以用于任务限制,也可以用于确定将用于频率选择和任务放置的利用率值。

不幸的是,SCHED_DEADLINE也有一些缺点,使其无法使用。该调度类尚无可用的优先级继承机制来管理相互依赖的任务,但目前正在讨论应解决此问题的代理执行机制 。

此外,截止日期调度程序的带宽限制机制过于激进,在为任务选择的运行时间太短的情况下,会错过截止日期。这要求以安全的余量设置悲观的运行时间,从而导致带宽损失,而其他SCHED_DEADLINE任务可能会使用这些带宽 ,如果使用schedutil,则会选择更高的频率,从而浪费能源。与SCHED_RT一样,应用程序线程也不完全是时间紧迫的,它们的非时间紧迫的部分可以使用CFS进行调度,而不必参与SCHED_DEADLINE任务的运行时间。

将SCHED_DEADLINE应用于应用程序任务的另一个问题是这些任务会自动挂起。例如,RenderThread可能会阻止等待输出缓冲区从BufferQueue出队的等待。当SCHED_DEADLINE 任务在挂起后唤醒时,内核可能会推迟其截止日期,从而降低了任务本身的优先级,并可能导致其错过了截止日期,因为它可能会被另一个SCHED_DEADLINE任务抢占 。

SCHED_DEADLINE也不考虑任务放置中的CPU容量,并且在异构体系结构中,它可能在慢速的CPU上调度高带宽任务,从而导致截止期限。当前正在讨论应该解决此问题的能力意识。最后,由SCHED_DEADLINE实施的调度策略不能管理重叠的cpuset控制组,因此,禁止使用自定义CPU关联性,并且只能使用独占cpuset cgroup(根域)来实现对有限CPU的定义。

SCHED_DEADLINE with token passing

在应用程序的UI线程和RenderThread之间的交互中要注意的一点是,关键路径遵循数据流,它是顺序的。

不用考虑任务的截止日期,而是看待问题的另一种方法是将截止日期与数据相关联。一旦应用程序唤醒,UI线程就很关键,直到它将绘制命令列表发送到RenderThread,而RenderThread才是关键,直到将栅格化的帧提交给BufferQueue。提交此数据的截止日期是SurfaceFlinger醒来消耗组合物的BufferQueue数据的时间。这类似于具有单个 SCHED_DEADLINE任务,该任务的期限等于SurfaceFlinger的唤醒时间,该任务执行UI线程和RenderThread的关键部分。

该解决方案可以通过使用交换两个任务的调度属性的令牌传递机制扩展调度程序API来实现。甲SCHED_DEADLINE它通过绘制指令列表后UI线程可以捐赠其内部调度参数,以RenderThread,和RenderThread可以给回SCHED_DEADLINE令牌到UI线程。

这种方法从应用程序的非时间紧迫的部分中节省了最后期限带宽,并且不需要任何优先级继承或最后期限同步机制。

但是,当系统过载时,Android显示管道可能会同时运行UI线程和RenderThread,这是一种执行模式,可能需要退回到CFS解决方案,或者需要引入两个SCHED_DEADLINE令牌,这些令牌必须在UI线程和RenderThread,两者之间具有更复杂的同步机制。

Hierarchical scheduling: SCHED_DEADLINE on top of SCHED_RT

在系统具有协作实时任务组的更一般情况下,可能需要考虑使用其他解决方案。通过使用 SCHED_DEADLINE实体替换SCHED_RT的实时节流机制,可以将共享同一截止日期的多个协作任务安排为特殊的SCHED_DEADLINE 实体,并且可以在该调度实体中使用SCHED_RT(或其他)策略进行安排 。

除了简化任务集的实时分析之外,此解决方案还将减少SCHED_DEADLINE带宽的悲观情绪。在为任务组选择运行时间时,同时进入多个任务的不幸的最坏情况执行时间代码分支的可能性非常低,因此分配给任务组的总运行时间可以小于它的任务的所有最坏情况执行时间的总和。

另一方面,由于两个调度层和大量任务迁移,此解决方案引入了更多的调度开销。而且,这种方法会将诸如CPU亲和力之类的SCHED_DEADLINE问题暴露 给其他调度类。这使其不可行。

我在本节中提到的分层调度算法的理论最初是由Leontyev和Anderson提出的(一种具有时序保证的分层多处理器带宽预留方案[PDF])。Andrea Parri,Mauro Marinoni,Juri Lelli和Giuseppe Lipari在针对任务组的多处理器带宽预留机制的实现中描述了Linux内核中的第一个实现。要提供实时分析支持的实时保证,需要两级调度层次结构的额外开销,以及在当前CPU上的任务执行保证时间到期时迁移任务组的所有工作。

Conclusions

此处介绍的解决方案均缺少使它们可直接用于Android显示管道的功能。每个解决方案都迫使这个复杂的子系统依赖并依赖未在Linux内核上游完全合并的解决方案。与主流Linux代码库的差异会导致这些修改很难(即使不是不可能)在将来的内核版本中维护。

当前,在这些解决方案中尚无明确的赢家,而采用其中一种解决方案是一项昂贵,冒险的操作,需要仔细计划。但是,所有这些解决方案都有很大的成功潜力,并且逐步解决上述空白可能对现在的许多应用程序立即是有利的,并且将来可能会成为Android显示管道基础的一部分。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


  •  

  •  

 

 

https://lwn.net/Articles/809545/

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
注意你的基带版本需要是MDC或者MDL一,准备材料:1,电脑安装Microsoft .NET Framework 4.5,点我2,下载三星驱动,点我3,下载解锁软件,点我下载4,下载安装DFS,点我下载5,全部安装好上面的软件在电脑6,MDC版本基带下载:点我下载二,降级基带为MDC版本1,下载odin:odin_V3.0.7.zip2,解压并且打开odin软件3,手机L720彻底关机(拔掉UIM卡,SIM卡)5,按住音量下+主页键+电源键进入警告的英文页面6,看到警告之后,按一下音量上键,进入了Downloading....下载模式,也就是挖煤模式或者说odin刷机模式。连上电脑数据线(台式电脑连后面的USB接口,网吧电脑一般被阉割了,是太监,不行)7,odin软件上点击PHONE,选择SPH-L720_MDC_Modem.tar.md5基带文件8,等待1分钟左右MD5验9,点击start,开始刷机三,破解电信插卡3G1,手机在拨号界面输入*#0808# (或者拨号##3424#),上面选择AP 下面选择MODEM+ADB+DM2,下载SPCUtility.apk 这个软件安装在手机3,手机连接WiFi或者网络,打开SPCUtility.apk这个软件,read 读取即可出SPC4,手机连接电脑数据线5,打开桌面的DFS软件6,连接三星端口7,输入PWD密码为2012112120131219 8,SPC密码是上面第2.3步骤获取到的6位数字 9,默认是写号,改为RuimOnly 读UIM卡模式 10,写电信的3G接口照图写ctwap@mycdma.cnvnet.mobi 11,写SimpleIP 12,写完上面的参数,关闭DFS。不要断开手机,也不用拔掉数据线。接着做下面的步骤四四,破解三网识别:1,打开桌面的S4 Flasher软件,点击scan and unlock,然后等待手机重启,就完成解锁三网了。到此完美三网插卡。2手机享受三网插卡吧!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值