如何提高IO效率

      游戏开发 2008-11-9 18:30


(本文参考了Game Programming Gems 6)

IO效率是游戏开发中经常被忽视的问题。
实际上,IO不仅与游戏的Loading时间息息相关(想象一下切换场景需要用户等上十秒),而且也悄悄地影响着游戏运行时的效率。虽然开发人员总是尽量避免,但游戏中总会遇到实时读取资源的情况,比如在脚本中播放一个突发的音效(想象此时游戏突然从很流畅变成只有几帧)。
随着游戏复杂程度的不断增加,资源量也在激增,IO效率有时会成为非常致命的瓶颈。

==================

首先,一个简单而常用的做法是把游戏资源进行打包,并且用一个管理器来控制资源的加载。

但是,资源文件的打包顺序通常就是硬盘上的目录结构和文件名排序的顺序,而游戏中很少会按照这个顺序去读取资源。
显然,如果能顺序地访问资源,IO效率就能得到显著的提高,这就要求我们对资源文件进行排序。

如果直接从磁盘读取不连续的数据,会导致磁头在扇区之间反复寻址,直接降低效率。
即使是把大量数据缓冲到内存,不连续的数据也会降低cache的效率。

假设在游戏中实时创建一个角色,需要读取一些资源。
如果所有相关的模型、材质、动画等资源全部是连续的,那必将极大地提高效率。

===================

现在大部分便携式嵌入系统(手机、PDA、MP4、掌机)都采用存储卡,为了更好地提高IO效率,我们有必要研究一下存储卡的工作特点:

一、存储卡工作时一般采用逻辑寻址方式,它没有磁头和磁道的转换操作。因此在访问连续扇区时,操作速度比磁盘的物理寻址方式速度快。

二、绝大部分存储卡的读取速度都比写入速度快。(release版的游戏较少需要实时写入存储器,除非截图或存档,所以这并不算关键问题)

三、存储卡对操作的响应并不快,频繁的操作下存储卡的性能表现会很差。(想象读一个10K的文件和读十个1K的文件)

四、容量大的存储卡由于寻址空间大,寻址速度上反而会慢一点。

可以看出,虽然存储卡不存在磁头和磁道的转换,但由于很低的响应速度,所以一次读取连续的数据也会大幅度提高效率。

==================

在以上分析的基础上,可以制定如下的优化策略:

一、运行游戏,通过日志文件记录各个资源文件的访问顺序。同时记录IO操作的时间,作为优化后的比较依据。

二、通过一个分析程序,将日志文件转换成简单的资源文件排序列表。

三、修改打包工具,使其可以根据上述排序列表对资源进行排序打包。

实际测试表明:
使用打包技术而不是读取零散的小文件,可以将IO效率提高近6倍;而对资源排序后再打包,又能进一步将效率提高2倍!
并且游戏的资源越多,优化的效果越显著。

另外,我们完全可以在整个项目的开发后期,或者版本发布时,才进行这样的优化。因为此时我们得到的顺序更接近最终版本,并且开发过程中也不必考虑这些繁琐的操作。

==================

需要注意的事项:

一、如果游戏并非通过光盘、只读存储卡等方式发布,那么操作系统或用户就可能打乱数据文件的存储顺序(比如进行了磁盘整理),导致文件碎片化。这个问题确实会直接对IO效率造成影响,可能导致排序的优化手段毫无作用。好在对于手机或掌机来说,大部分时候都不用太在意这一点。

二、这种排序手段是非常上下文相关的,一旦游戏逻辑发生变化,就会失效。因此可能对游戏的MOD开发者带来困扰。

===================

其它常见的优化:

一、即使我们只需要文件中的某几段数据,也最好从文件的开头顺序地读取每一个字节。这是为了更有效地利用硬件cache。

二、尽可能在内存中cache频繁使用的数据。可能需要把资源按照使用频度进行分类,由资源管理器进行调度,并且资源管理器与文件管理器协同工作。可能需要一定的经验去调整资源的分类,做到IO效率和内存开销的均衡。

三、数据压缩。对于一些大型并且压缩比很高的文件,可以采用zlib或其它常用压缩算法。这样虽然带来少量的解压缩的开销,但总体来说更划算。

标签集:TAGS:
回复Comments() 点击Count()

回复Comments

{commentauthor}
{commentauthor}
{commenttime}
{commentnum}
{commentcontent}
作者:
{commentrecontent}