让我们查看I/O使用情况
记住侧边栏中的“存储情况”图并没有展现出太多活动吧?事实证明,你可以扩充它到更多的图表。
目前,我们已经取得了一些进展!当我们导入TGA文件时,“文件I/O”综述图将显示出大量的活动。我们只想弄明白发生了什么事。双击侧边栏中的图标,显示出I/O的详细情况:
你或许能通过图标看出它的情况。我们有许多需要读取的文件,实际上大约有四十万个。这数字听起来是那么惊人!就像是CPU的一部分,我们把UI归类到黄色分频器左边的一个列中。让我们拖动“Process”列到左边,这将表明所有这些读取确实来自于unity。
当我们展开实时事件后,揭秘出原因:
我们正在读取文件。每一次要消耗3个字节。
但为什么会是这样呢?
为什么我们要在3字节块中读取12兆字节的TGA文件呢?没有人在很长一段时间更新我们的图像读取库,那为何要退回到这一步骤呢?
在代码中找到我们正调用FreeImage的地方。这看起来像正在设置我们自己的I/O API函数,并告知FreeImage去使用它们:
版本控制的历史检查:事实上,几周前该代码就有了一些变更,“从文件路径中加载图像”到“使用I/O回调函数加载图像”。
如果我有自定义的文件系统函数,通常它对我们来说就会很有意义。这样我们能够从non-plain-files中支持阅读(例如,档案或压缩文件)等等。在这种特殊情况下,变更已完成,可在光照贴图缓冲中支持LZ4压缩(FreeImage将导入纹理文件,而无需知道LZ4压缩已经完成)。
一切进行顺利。除非那种截然不同的运行特性的变更。
当你不通过文件I/O API函数传递到FreeImage时,然后它就会使用C stdio 的“默认设置”。
目前,C stdio完成默认的I/O缓冲……我们的I/O API函数并不是。FreeImage的TGA载入器有大量单像素的读取。
公平的讲,“在某一时刻读取单个TGA像素”似乎固定在upstream FreeImage中;我们正使用着一个很老的版本,当我们看到这么多的bug之后,确实感觉到FreeImage的版本太老了,并要升级版本,虽然并不一定非得在今天就要完成升级。
修复
因此,我们要完成一个合适的修复:为FreeImage安装已缓冲好的I/O API函数。原本是我们并没有它们其中的任何一个。但做起来并不是特别难,我就让其他工作人员完成它。
同时,要去检查它问题所在,并没有出现“TGA导入过于缓慢”。我只是做了读取全部图像到内存中的热门修复的操作,并再次加载它们。
读取所有的图像到内存缓冲区好吗?还是看情况而定。95%的情况下没问题,尤其是64位的Unity编辑器。大多数图像的未压缩数据最终将比文件大小还要大。或许还有一种例外。那就是PSD文件,它有许多图层,但我们只关心在文件区域内读取“合成图像”。所以,这就是我说的“hotfix(热修复补丁)”,一个合适的解决方案就是缓冲好的I/O API函数和升级FreeImage。
实际上正因为这些原因,TGA和PNG的导入速度和以前相比快了很多:TGA是75ms,PNG是87ms(在Unity 4.6中,TGA是310ms,PNG是116ms;)当前的beta版本中,TGA是9800ms,PNG是108ms)。
结论
当替代你实现功能中的某些内置功能时一定要小心(譬如,标准I/O,内存分配,登录,或某些库的实例)。这些功能有不同的性能特征。
Windows上的xperf非常实用。更多了解xperf的内容,请参阅Bruce Dawson的博文,链接https://randomascii.wordpress.com/category/xperf/ 。
在Mac上,苹果的Instruments是一款相似的工具。我想我将使用它作为未来博文中的一个条目。
或许,在我看到这个问题的数分钟后,我就应该考虑到“太多细小的文件读取需要召回”是其主要原因。但我真不知当时我为啥没有想到这一点儿,下一次再发生这种情况时我就记住了。
欢迎光临 纳金网 (http://go.narkii.com/club/) | Powered by Discuz! X2.5 |