Portable SIMD Programs Using ISPC

from Game Engine Gme 3 16 Chapter

在20世纪90年代末,硬件领域加速之前,游戏已经在CPU上的软件中进行了vertex transformation和Lighting.随着3D游戏成为了主流,SIMD(单指令多数据)指令集,如SSE(Streaming SIMD Extensions)被添加到CPU中,以加速几何处理和其他代价昂贵得多计算任务。与执行标量操作的常规浮点指令不同,SSE指令执行四个浮点数组进行操作,如下所示,SSE在游戏编程中的广泛适用性使得这种SIMD指令称为任何高性能游戏引擎的组成部分。SIMD指令集已经经历了巨大的发展。

[1 2 3 4] + [5 6 7 8] = [(1+5) (2+6) (3+7) (4+8)] = [6 8 10 12]

并行计算的例子

由于SIMD 只是针对更现代化CPU,一些老的硬件或者一些低端手机硬件并不支持这种功能。除了可移植性,使用一些目前可使用的工具也很困难,一些常用方法有:

Assuming你的C/C++编译器会自动将标量代码转换为向量代码。

三维线性代数类算法使用SIMD

使用内部技术的特殊功能,有编译器识别并直接转换为SIMD指令。

不幸的是,所有的这些方法都有一个主要的问题:

编译器不能可靠的应用自动向量化,因为对代码非常小的改动都会破坏它,理想情况下,我们希望能够保证向量化正在发生。

类似与Float4这样的三维线性代数类由于它们的结构数组性质,暴露的数组结构收到限制导致不是数组结构。将浮点数x,y,z,w组件依次存储在内存中,可以在点积等常见的操作中无效地使用SIMD [Fredriksson, 2015] 。该方法也不能扩展到具有更宽向量的指令集。

内联函数不可移植。

理想情况,我们希望编写能够充分利用当前和未来的指令集的程序,这个代码是可维护的,已于编写,并且有利于性能,为此,我们引入了ISPC,这是一种类似c语言的编译器,它可以通过一个浅层的抽象使用SIMD轻松编写可移植和高效的代码。

array-of-struct与struct-of-array的设计比较,struct -of- array 设计更适合于SIMD操作。

// Array-of-structs design

struct float4

{

float x;

float y;

float z;

float w;

};

float4 mystructs[N];

//Struct-of-arrays design

struct Float4Array

{

float xs[N];

float ys[N];

float zs[N];

float ws[N];

};

Float4Array myarrays;

基本的ISPC

SPMD的编程模型类似于GPU着色器,编写程序就好像他们在一个值上执行操作一样,但程序实际上被并行执行了很多次。ISPC使用SIMD指令有效的实现了这一点。

在ISPC术语中,程序的每个执行都称为程序实例,所有同时执行程序的组称为一组。在ISPC中,组的大小在编译时是已知的,并且是基于目标SIMD指令集的。在编写ISPC代码时,将从单个程序的实例的视图来描述算法。

ISPC在语法上与C语言相似,并添加了一些语意。例如ISPC添加了在变量声明中使用统一的和变化的限定符。这些限定符描述了变量在不同程序之间的行为。一个统一的限定符在组的每个程序实例中具有相同的值,一个会变化的变量在每个程序实例中有一个独立的值。这种差异有一个有趣的影响,因为不同的变量会导致控制流在程序的实例之间发散。

为了使用的SIMD指令实现不同的控制流。ISPC使用了预测,采取所有可能的控制流路径,并且ISPC跟踪任意组程序实例在代码的任何点都会满足条件,副作用是只对这组程序实例执行,并且当控制流收敛时,结果会被合并。预测还用于处理循环的迭代计数不是实例计数的倍数的情况。

ISPC 程序例子

作为介绍,我们将详细介绍下图中的简单的.ispc程序。这个程序对于C程序员来说应该是最直观的,因为等效的C程序几乎是相同的。这个程序和C等价程序之间的唯一区别是:

export关键字,它告送ISPC为应用它的函数生成一个C入口点。

uniform关键字,由于输入是从C发出的,其他任何实例访问都是同一个值。

foreach loop,它并行执行多个实例。

这个预测循环值得更多的解释:它生成一个名为索引的变化变量。因为索引是不同的,所以它在每个程序实例中都有一个不同的值。例如,如果程序实例计数为4,在每次迭代中,索引将为[0 1 2 3]。因此,读取vin[index]实际上读取四个浮点到v(这是一个不同的浮点)。计算在这四个浮点数上并行进行,然后将它们写入vout中。由于if…else在循环中,一些程序实例将使v平方,而其他程序实例将计算它的平方根。这些结果使用预测进行合并。

在编译此程序时,将创建一个包含下面代码中的声明的头。该函数可以通过使用下面的示例C代码来调用该函数。

extern void simple(float vin[], float vout[], int32_t count);

实例c代码例子:

游戏引擎中集成

ISPC可以用于游戏、游戏引擎或游戏资产管道中的各种任务。最常见的用途是计算量大的算法,因为ISPC通过自动化条件执行和循环结束等繁琐的结构,使生成SIMD代码变得更容易。

ISPC代码实现裁剪一系列球体

将繁重的计算量卸载到GPU上是很诱人的,但是使用ISPC来代替类似着色器的工作负载有一些明显的优势。因为它运行在CPU上,所以ISPC可以直接与您的C/C++程序共享数据结构。此外,ISPC允许您使用CPU的低延迟,而不是使用GPU的延迟隐藏机制。您可以有效地从C++调用一个简短的ISPC函数,或者从ISPC回调到C++代码,这些都是让gpu感到羞愧的工作负载。

由于相同的ISPC代码可以针对不同的体系结构进行编译,因此它有效地利用了用于编译资产的异构服务场,在这里可以编译代码以利用任何给定处理器的SIMD功能。您甚至可以在游戏和资产之间共享相同的ISPC代码。

将ISPC添加到现有的C/C++项目中很容易。ISPC构建 .obj 文件可以简单地链接到二进制文件中,它还生成一个头文件,您可以简单地#include,以便调用导出的函数。

作为一个快速设置指南,ISPC可以集成到Visual Studio项目中,如下所示:

1. Download ispc.exe from http://ispc.github.io/.

2. Put ispc.exe into your project’s directory.

3. Add your .ispc source file to your project.

4. Right click on your .ispc file in Visual Studio, and choose Properties.

5. Under “Configuration Properties > General”, set “Item Type” to “Custom

Build Tool”.

6. Under “Configuration Properties > Custom Build Tool > General”, configure similarly to that shown in Figure .

以下是作者使用ISPC的经验,以下是一些充分利用ISPC的技巧。

Prefer uniform, and don’t use varying unless you need to

由于varying变量是变量的默认限定符,因此在所有程序实例都具有相同值的情况下,可能会意外地使用varying变量。在这种情况下,使用varying将产生比显式地将其标记为uniform的更差的性能。

Build for all instruction sets, and choose the best available at runtime

相同的ISPC程序可以同时为多个目标指令集编译,并且所有这些不同的编译程序都可以链接到同一个可执行文件中。这使得动态决定在运行时使用哪个指令集成为可能,这对于像用户拥有各种硬件功能的PC游戏来说是很有趣的。这是通过将多个以逗号分隔的目标传递到ISPC命令行来自动实现的。为导出的函数生成的入口点将检查CPU的功能,并调用最合适的实现。

Consider the effects of divergence(考虑分支的影响)

SPMD与使用分支的算法的交互作用很差。考虑一种算法迭代地改进其结果的情况。该算法的核心是一个循环,当值收敛或在最大迭代次数后结束。当运行循环时,一些大小为N的SPMD组的程序实例将比其他程序实例更早收敛。即使只有一个程序实例是活动的,循环也有可能保持迭代,这意味着其他N-1个程序实例正在等待重新收敛。因此,算法应该被设计成最小化分歧,以实现更高的吞吐量。有先进的解决方案可以通过填充早期收敛的车道来处理分歧。

Avoid gathers (避免聚集)

使用不同索引加载/存储可能会导致聚集/分散操作。当这种情况发生时,ISPC将生成性能警告,因为这些操作本身就很慢。这会影响表查找和计算之间的性能平衡。由于所需的聚集操作,在表中查找函数的结果通常比计算函数慢。

找到创造性的方法将表转换为等效函数可以产生性能上的好处,尽管看起来是多余的计算。

The advantages of the struct-of-arrays approach for dot products are further explained in [Fredriksson 2015].

[Fredriksson 2015] Andreas Fredriksson. “SIMD at Insomniac Games: How We Do the Shuffle”. Game Developers Conference 2015. Available at http://www.gdcvault.com/play/1022249/SIMD-at-Insomniac-Games-How.

[Pharr and Mark 2012] Matt Pharr and William R. Mark. “ispc: A SPMD Compiler for High-Performance CPU Programming. Innovative Parallel Computing”. Innovative Parallel Computing, 2012.

[Valve 2015] Valve Steam Hardware & Software Survey, July 2015. Available at http://store.steampowered.com/hwsurvey/.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值