欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

存储设备IO优化向导

程序员文章站 2022-09-01 08:59:35
1、概述虽然存储设备的恨不能在近年来一直在稳步提升,从raw nand到emmc,再到UFS都在进步,但和CPU相比它们依然是一个低俗的外设,并且IO是不可抢占的,所以应用程序在交互中等待IO会带来非常糟糕的用户体验,大部分程序员都意识到了这一点,所以绝大多数的程序尽量都会想办法改善这个问题,例如预读(readahead)和异步IO等。但是有些场景是很难规避IO的影响的。比如启动应用和本地音视频播放。如果在这两个场景中,还有其它的程序来竞争IO,那对用户体验来说可能无法接受。2、现有的优化设想有...

1、概述

虽然存储设备的恨不能在近年来一直在稳步提升,从raw nand到emmc,再到UFS都在进步,但和CPU相比它们依然是一个低俗的外设,并且IO是不可抢占的,所以应用程序在交互中等待IO会带来非常糟糕的用户体验,大部分程序员都意识到了这一点,所以绝大多数的程序尽量都会想办法改善这个问题,例如预读(readahead)和异步IO等。但是有些场景是很难规避IO的影响的。比如启动应用和本地音视频播放。如果在这两个场景中,还有其它的程序来竞争IO,那对用户体验来说可能无法接受。

2、现有的优化

设想有这样一个场景:某天用户心血来潮要整理设备上的照片或其它文件,通过文件浏览器把大量的文件拷到一张新的TF卡上,这个过程是很漫长的,这个时候他打开一个本地视频观看,但是不幸的事情来了,视频卡顿非常严重。

遇到这种情况,工程师们肯定能理解,文件拷贝和视频播放在竞争IO,导致解码器没有及时得到新的视频数据,进而导致丢帧或音视频不同步。但是用户不一定能接受这个解释。他觉得为什么不能把文件拷贝的速度放慢一些,优先保证视频播放的用户体验。

这时候又轮到工程师来想办法了,在这个场景中,IO实际上可以分两类,视频播放和文件拷贝。把其中视频播放的IO认为是关键IO,问题就变成 了如何避免关键IO拥塞。

让我们先看看万能的谷歌是怎么处理这个问题的,在最新的android版本上会设置所有视频相关进程的IO优先级到RT级,这种优先的效果肯定是有的,但是还有几个问题:

  • 效果有限 BT只能改善,而不能避免关键IO的拥塞,因为文件拷贝的进程会更频繁的发起IO请求,所以经常会碰到这种情况,视频播放的IO请求到来时,设备驱动正在执行文件拷贝操作的IO,由于IO不可抢占,此时只能等这个请求完成,视频播放的请求才能得到服务。
  • 对第三方应用支持有限 如果第三运用是通过MediaCodec或者OMX来实现音视频播放的,此时流媒体数据的请求是应用 自己发起的,并不会被自动配置成RT级
  • 没有考虑启动应用的场景 实测在文件拷贝的同时去启动应用,速度慢了近两倍

注:在线音视频缓存流媒体数据一般都是直接存在内在中的,一是可以保证性能,二是Flash设备的寿命有限,所以不需要考虑IO优化

3、如何改进

3.1、结合cgroup控制

kernel除了IO优先级以外,还有一个blk cgroup控制,目前支持两种控制策略:权重和节流。二者都是通过标准的cgroup方式提供配置接口的,这里就不详细描述了。把进程分组以后,可以给不同的分组配置不同的权重,例如给视频播放进程配置1000的权重,给文件拷贝分配10的权重,则内核会尽量按99:1的比例来分配存储设备的带宽,当然实际上的带宽比例不会是这样的,因为两个进程发起IO的频度是不一样的,内核只能保证短时间内的带宽按配置的权重来分配。而节流的话,则是可以给每个分组每个设备设置一个性能阈值,内核来保证性能不超过这个阈值,例如给文件拷贝分配2MB/s的读带宽,则内核会严格按这个指标分配带宽,即使此时设备带宽还没有用完。

3.2、提升第三方应用兼容性

大部分媒体应用都是直接调用MediaPlayer来实现播放,这样会通过MediaServer来读取流媒体数据,而这个进程android已经配置了RT优先级。但是还有一部分应用是直接调用MediaCodec来实现播放的,比如特殊的加密格式视频,又或者为了实现帧合成等特殊处理,在这种情况下是由视频应用本身来读取流媒体数据,为了改善这个问题,可以在dequeueInputBuffer函数中把当前线程IO优先级和权重都配置到最高。

3.3、识别启动应用的场景

所有的应用启动都要经过ActivityManagerService,所以AMS的startActivity中识别启动应用开始,在Activity.onStart中认为启动应用结束。

3.4、限制文件拷贝性能

为了进一步提升前台应用和媒体应用的用户体验,还需要降低文件拷贝的IO性能,即在识到到启动应用和音视频播放的场景后,会同时根据一个白名单(主要是各种文件浏览器),降低特定活动进程的IO优先级和权重,同时发出一个BROADCAST_IO_JANK的消息,各种系统服务如mtp服务、下载服务等可以在收到这个消息的时候降低IO优先级和权重。

3.5、提供框架层接口

框架层提供IO优先级和权重的配置接口,但是普通应用只支持降低优先级和权重,只有system权限的应用可以提高优先级和权重。

4、整体流程

  • step 1:开机启动过程中,init会为每个系统服务设定IO优先级和权重,其中media相关的进程全部都是RT和最高权重,debugerd、logcatd等都是IDLE和最低权重
  • step 2:AMS会在Activity的不同生命周期,设置不同的IO优先级和权重,其中TOP_APP > FORGROUND > BACKGROUD
  • step 3:媒体播放过程中会设置一个属性media.codec.running=true,来表示当前正在进行音视频编解码,并且会发出BROADCAST_IO_JANK消息,通知系统服务调低mtp、下载器和其它白名单中应用程序的IO优先级和权重到最低,并在播放结束后延迟发出BROADCAST_IO_RESUME(如果在延迟时间内触发新的BROADCAST_IO_JANK,会先移除这个延迟消息)通知系统服务恢复到正常优先级和权重。
  • step 4:在应用启动过程中,如果media.codec.running=false,则会发出BROADCAST_IO_JANK消息,通知系统服务调低mtp、下载器和其它白名单中应用程序的IO优先级和权重到最低,并在启动结束后延迟发出BROADCAST_IO_RESUME(如果在延迟时间内触发新的BROADCAST_IO_JANK,会先移除这个延迟消息),通知系统服务恢复到正常优先级和权重

 

本文地址:https://blog.csdn.net/xl19862005/article/details/108149101

相关标签: android kernel