关于ios:Metal新特性大幅度提升iOS端性能

93次阅读

共计 6516 个字符,预计需要花费 17 分钟才能阅读完成。

前言

Metal 是一个和 OpenGL ES 相似的面向底层的图形编程接口,通过应用相干的 api 能够间接操作 GPU,最早在 2014 年的 WWDC 的时候公布。Metal 是 iOS 平台独有的,意味着它不能像 OpenGL ES 那样反对跨平台,然而它能最大的开掘苹果挪动设施的 GPU 能力,进行简单的运算,像 Unity 等游戏引擎都通过 Metal 对 3D 能力进行了优化,App Store 还有相应的使用 Metal 技术的游戏专题。

阿里巴巴淘系技术部的闲鱼团队是比拟早在客户端侧抉择 Flutter 计划的技术团队, 以后的闲鱼工程里也是一个较为简单的 Native-Flutter 混合工程。作为一个 2C 的利用,性能和用户体验始终是闲鱼技术团队在开发中比拟关注的点。而 Metal 这样的间接操作 GPU 的底层接口无疑会给闲鱼技术团队突破性能瓶颈提供一些新的思路。

上面会具体论述一下这次大会 Metal 相干的新个性,以及对于闲鱼技术和整个淘系技术来说,这些新个性带来了哪些技术启发与思考。

(WWDC 2020 精彩内容思否专栏:https://segmentfault.com/blog…  

本篇内容来自于阿里巴巴淘系技术部,无线开发工程师岑彧。
更多精彩内容可关注【淘系技术】公众号。)

Metal 相干新个性

1.Harness Apple GPUs with Metal

这一章其实次要介绍的是 Apple GPU 的在图形渲染上的原理和工作流,是一些比拟底层的硬件原理。当咱们应用 Metal 进行 App 或者是游戏的构建的时候,Metal 会利用 GPU 的 tile-based deferred rendering (TBDR) 架构给利用和游戏带来十分可观的性能晋升。这一章次要就是介绍 GPU 的的架构和能力,以及 TBDR 架构进行图像渲染的原理和流程。总之就是号召开发者们应用 Metal 来构建利用和游戏。因为这个 session 没有波及到下层的软件开发,就不对视频的具体内容进行赘述了。详情可见:Harness Apple GPUs with Metal

2.Optimize Metal apps and games with GPU counters

这一章次要介绍了 Xcode 中的 GPU 性能剖析工具 Instrument,这个工具当初曾经反对了 GPU 的性能剖析。而后从多个方面剖析了 GPU 的性能瓶颈,以及性能瓶颈呈现时的优化点。总体来说就是通过性能剖析工具来优化咱们的 App 或者游戏,让整个画面更加晦涩。整个章节次要分为五个局部:

1. 总体介绍

这个环节次要是疾速回顾了一下 Apple 的 GPU 的架构和渲染流程。而后因为很多渲染工作都须要在不同的硬件单元上进行,例如 ALU 和 TPU。他们对不同的吞吐量有着不同的度量。有很多 GPU 的性能指标须要被思考,所以推出了 GPU 性能计数器。这个计数器可能测量到 GPU 的利用率,过高和过低都会造成咱们的渲染性能瓶颈。对于计数器的具体应用,参考官网的 video 成果会更好:Optimize Metal apps and games with GPU counters(6:37~9:57),次要应用了 Instrument 工具,对于工具的全面具体的应用能够参考 WWDC19 的 session videoGetting Started with Instruments

2. 性能瓶颈剖析

这一章次要介绍了造成 GPU 性能瓶颈的各个方面以及它们的优化点。次要分为六个方面,如下图所示:

1.Arithmetic(运算能力)

GPU 中通常通过 ALU(Arithmetic Logic Unit)来解决各种运算,例如位操作,关系操作等。他是着色器外围的一部分。在这里一些简单的操作或者是高精度的浮点运算都会造成一些性能瓶颈,所以给出以下倡议来进行优化:

如上图所示,咱们能够应用近似或者是查找表的形式来替换简单的运算。此外,咱们能够将全精度的浮点数替换为半精度的浮点数。尽量避免隐式转换,防止 32 位浮点数的输出。以及确保所有的着色器都应用 Metal 的“-ffast-math”来进行编译。

2.Texture Read and Write

GPU 通过 Texture Processing Unit 来解决纹理的读写操作。当然在读写的过程中也会遇到一些性能瓶颈问题。这里从读和写两个局部别离来给出优化点:

1.Read

如上图所示,咱们能够尝试应用 mipmaps。此外,能够思考更改过滤选项。例如,应用双线性代替三线性,升高像素大小。确保应用了纹理压缩,对 Asset 应用块压缩(如 ASTC),对运行时生成的纹理应用无损纹理压缩。

2.Write

如上图所示,咱们应该留神到像素的大小,以及每个像素中惟一 MSAA 样本的数量。此外,能够尝试一些优化一些逻辑写法。

3.Tile Memory Load and Store

图块内存是一组存储 Thread Group 和 ImageBlock 数据的高性能内存。当从 ImageBlock 或是 Threadgroup 读取或写入像素数据时,比方在应用 Tile 着色器时或者是计算分派时, 能够拜访到 Tile 内存。那当应用 GPU 性能计数器发现这个方面的性能瓶颈时,咱们能够如下图所示进行优化。

思考缩小 threadgroup 的并行,或者是 SIMD/Quadgroup 操作。此外,确保将线程组的内存调配和拜访对齐到 16 字节。最初,能够思考从新排序内存拜访模式。

4.Buffer Read and Write

在 Metal 中,缓冲区只被着色器外围拜访。在这个中央发现了性能瓶颈。咱们能够如下图所示进行优化:

能够更大力度的压缩打包数据,例如应用例如 packed_half3 这样小的类型。此外,能够尝试向量化加载和存储。例如应用 SIMD 类型。防止寄存器溢出,以及能够应用纹理来均衡工作负载。

5.GPU Last Level Cache

如果在这个方面,咱们的 GPU 性能计数器显示一个过高的值。咱们能够如下图这样优化:

如果纹理或者是缓存区也同样显示一个过高的值,咱们能够把这个优化放到第一优先级。咱们能够思考减小工作集的大小。如果 Shader 正在应用 Device Atomics,咱们能够尝试重构咱们的代码来应用 Threadgroup Atomics。

6.Fragment Input Interpolation

分段输出插值。分段输出在渲染阶段由着色器外围进行插值。着色器外围有一个专用的分段输出插值器。这个是比拟固定和高精度的性能。咱们能优化的点不多,如下图所示:

尽可能的移除传递给分段着色器的顶点属性。

3. 内存带宽

内存带宽也是影响咱们 GPU 性能的一个重要因素。如果在 GPU 性能计数器的内存带宽模块看到一个很高的值。咱们就应该如下图所示来进行优化:

如果纹理和缓存区也同样显示比拟高的值,那优化优先级应该排到第一位。优化计划也是较少 Working Set 的大小。此外,咱们应该只加载以后渲染过程须要的数据,只存储将来渲染过程须要的数据。而后就是确保应用纹理压缩。

4.Occupancy

如果咱们看到整体利用率比拟低,这意味着 Shader 可能曾经耗尽了一些外部资源,比方 tile 或者 threadgroup 内存。也可能是线程实现执行的速度比 GPU 创立新线程的速度快。

5. 防止反复绘制

咱们通过 GPU 计数器能够统计到反复绘制的区域,咱们应该高校应用 HSR 来防止这样的重绘。咱们能够如图所示的程序来进行绘制。

3.Build GPU binaries with Metal

这一章次要给开发者们介绍了一种应用 Metal 的编程工作流,能够通过优化 Metal 的渲染编译模型来加强渲染管线,这个优化能够在应用程序启动,特地是首次启动时大大减少 PSO(管线状态对象) 的加载工夫。能够让咱们的图形渲染更加的高效。整个章节次要分为四个局部:

1.Metal 的 Shader 编译模型概述

家喻户晓,Metal Shading Language 是 Apple 为开发者提供的 Shader 编程语言,Metal 会将编程语言编译成为一个叫做 AIR 的两头产物,而后 AIR 会在设施上进一步编译,生成每个 GPU 所需的特定的机器码。整个过程如下图所示:

上述过程在每个管线的生命周期中都会产生,以后 Apple 为了减速管线的从新编译和从新创立流程,会缓存一些 Metal 的办法变体,然而这个过程还是会造成屏幕的加载耗时过长。而且在以后的这个编译模型中,应用程序不能在不同的 PSO(管线状态对象)中重用之前生成的机器码子程序。
所以咱们须要一种办法来缩小这个整个管线编译(即源代码 ->AIR->GPU 二进制代码)的工夫老本,还须要一种机制来反对不同 PSO 之间共享子程序和办法,这样就不须要将雷同的代码屡次编译或者是屡次加载到内存中。这样开发者们就能够应用这套工具来优化 App 首次的启动体验。

2.Metal 二进制文件介绍

Metal 二进制文件就是解决上述需要的办法之一,当初开发者们能够间接应用 Metal 为二进制文件来管制 PSO 的缓存。开发者能够收集已编译的 PSO,而后将它们存储到设施中,甚至能够散发到其余兼容的设施中(同样的 GPU 和同样的操作系统),这种二进制文件能够看做一种 Asset。上面是一些例程和示意图:

总的来说就是这个 Metal 二进制文件能够提供开发者手动治理管线缓存的办法,这样就能够从一个设施中获取这些文件并部署到其余兼容的设施上,在 iOS 环境下,极大地缩小了第一次装置游戏或利用以及设施重启后的管道创立工夫。能够优化利用的首次启动体验和冷启动体验。

3.Metal 对动静库的反对

动静库将容许开发者编写可重用的库代码,却能够缩小从新编译程序的工夫和内存老本,这个个性将会容许开发者将计算着色器和程序库动静链接。而且和二进制文件一样,动静库也是可序列化和可转移的。这也是解决上述需要的计划之一。
在 PSO 生成的时候,每个应用程序都须要为程序 library 生成机器码,而且应用雷同的程序库编译多个管线会导致生成反复的机器码。因为大量的编译和内存的减少,这个可能会导致更长的管线加载工夫。而动静库就能够解决这个问题。
Metal Dynamic Library 容许开发者以机器码的模式动静链接, 加载和共享工具办法。代码能够在多个计算管线中重用,打消了反复编译和多个雷同子程序的存储。而且这个 MTLDynamicLibrary 是可序列化的,能够作为应用程序的 Asset 应用。MTLDynamicLibrary 其实就是多个计算管线调用的导出办法的汇合。
大抵的工作流程如下:咱们首先创立一个 MTLLibrary 作为咱们指定的动静库,这个能够将咱们的 metal 代码编译为 AIR。而后咱们调用办法 makeDynamicLibrary,这个办法须要指定一个惟一的 installname,在管线创立时,linker 将会应用这个名字来加载动静库。这个办法能够将咱们的动静库编译成为机器码。这就实现了动静库的创立。
对于动静库的应用来说:通过设置 MTLCompileOptions 里的 libraries 参数,就能够实现动静库的加载和应用了。代码如下:

4. 开发工具介绍

这个局部次要介绍了构建 Metal 二进制文件和构建动静库的具体工具和办法。以视频的模式可能会更好的体现,详情可见:Build GPU binaries with Metal(从 22:51 开始)

4.Debug GPU-side errors in Metal

这一章次要介绍的是 GPU 侧的 bug,以后如果咱们的应用程序呈现了 GPU 侧的 bug,他的谬误日志经常都不能让开发者很直观的定位到谬误的代码范畴和调用栈。所以在最新的 Xcode 中,加强了对于 GPU 侧的 debug 机制。能够像在代码侧发成的谬误一样岂但能定位到谬误起因,还有谬误的调用堆栈和各种信息都能够具体的查看到。让开发者能更好的修复代码造成的 GPU 侧的渲染谬误。

1.Enhanced Command Buffer Errors

这是以后的谬误日志上报,咱们能够看到 GPU 侧的谬误日志不像 Api 的谬误日志一样能够让开发者很快的定位到谬误起因和谬误的代码地位。

而最新的 Metal debugging 工具就加强了这方面的能力,让 Shader 的 code 也能够像 Api 代码一样提供谬误定位和分类能力。

咱们通过以下代码便能够启用增强版的 commandbuffer 谬误机制

谬误一共有五种状态:

咱们也能够通过以下代码来打印 error:

开发者能够在开发时和测试时启用优化版的谬误机制

2.Shader Validation

如上图所示,这个性能能够在 GPU 侧产生渲染谬误时主动定位和 catch 到谬误并定位到代码,以及获取回溯栈帧。

咱们能够在 Xcode 中依照以下流程来开启这个性能:

1. 开启 Metal 中的两个 Validation 选项

2. 开启 issue 主动断点开关并配置类型和分类等选项

Video 中用了一个 demo 来展现整个工作流,具体参见 Debug GPU-side errors in Metal(11:25~14:45)大抵流程如下图所示:

这是一个 Demo 应用程序,很显著它在渲染上呈现了一些异样,然而因为是 GPU 侧的问题,所以开发者很难定位。然而通过上述的工作流开启 Shader Validation 之后。

Xcode 会主动断点到产生异样的中央,并展现出异样信息,这样就能够极大的晋升开发者的谬误修复效率。

5.Gain insights into your Metal app with Xcode 12

这一章次要讲的是 Xcode12 给 Metal App 提供了更多调试和剖析的新工具。大抵如下图所示:

次要分为两个局部:

1.Metal Debugger

这个工具能够让开发者在 App 运行时,获取到想剖析和调试的任何一帧,而后再进入 Xcode 提供的各种剖析界面,总体状况,依赖状况,内存,带宽,GPU,Shader 等各种具体的界面来对这一帧进行更加具体的剖析和调试。整个过程应用视频的形式可能会更加高效,所以这里不会进行具体的赘述和剖析。详情能够参见 Gain insights into your Metal app with Xcode 12

2.Metal System Trace

整个工具跟之前提到过的 Debugger 相比,他的性能次要是让开发者能够随着工夫的推移来捕捉应用程序的各种信息和特色,能够让开发者很好的调试一些例如终端,帧失落,内存透露等问题。而 Debugger 次要是对某一帧进行调试和剖析。
他提供了一个叫做编码工夫线的工具,能够让开发者查看到 GPU 在利用运行中的运行各种命令缓冲的状况。而后提供了一个叫做着色器工夫线的工具,能够让开发者查看到各种着色器在代码运行期间运行的过程。而后还有 GPU 计数器的工具,这个工具咱们在前文进行了具体的剖析,次要是用于解决 GPU 的绘制性能问题的工具。而后最初一个工具就是内存调配跟踪工具,能够让开发者查看到利用程序运行过程中各种内存的调配和开释,能够帮忙开发者解决内存透露问题或者是升高利用内存占用。

技术启发与思考

WWDC 20 对于 Metal 的 Session 中,比拟重要的就是官网提供了很多可供开发者进行 GPU 级别的调试工具以及性能剖析工具。给比拟成熟宏大而简单的工程突破性能瓶颈,提供更加优良的用户体验提供了一些思路。

闲鱼作为一个电商类 App,随着性能和增多和以及工程的复杂化,在劫难逃的会遇到性能瓶颈,而闲鱼团队以后面对挑战的形式是从工程级别来进行优化。从 Flutter 的角度来看,WWDC 20 对于 Metal 的调试工具和性能剖析工具的欠缺,无疑提供了更多的优化思路。这为将来运行在 iOS 上的利用的调优和突破性能瓶颈带来了新的思路和可能性。

对于跨平台框架,Apple 有自家的 SwiftUI,这也是此次大会的重点项目。不过无论是 Flutter,还是 SwiftUI,大家最初对利用的性能瓶颈冲破和优化肯定是必由之路的,也就是深刻到 GPU 级别来进行开发和调试以及性能剖析。对于将来的客户端开发人员,了解 GPU 和进行 GPU 级别的编程必定是不可或缺的技能点之一。

(WWDC 2020 精彩内容思否专栏:https://segmentfault.com/blog…  

本篇内容来自于阿里巴巴淘系技术部,无线开发工程师岑彧。
更多精彩内容可关注【淘系技术】公众号。)

正文完
 0