技術(shù)帖:GPU上的高性能C#——Hybridizer

責(zé)任編輯:editor006

作者:smart編譯

2017-12-25 16:41:23

摘自:it168網(wǎng)站

Hybridizer是來自Altimesh的編譯器,可以讓人們采用C 代碼或 NET程序集編程GPU和其他加速器。圖7由于虛函數(shù)調(diào)用而實現(xiàn)的低帶寬  虛函數(shù)表會導(dǎo)致更多的注冊壓力,并防止內(nèi)聯(lián)。

Hybridizer是來自Altimesh的編譯器,可以讓人們采用C#代碼或.NET程序集編程GPU和其他加速器。Hybridizer使用修飾符號來表達(dá)并行性,可以生成針對多核CPU和GPU優(yōu)化的源代碼或二進(jìn)制文件。在這篇博文中演示了CUDA的目標(biāo)。

Hybridizer:GPU上的高性能C

圖1 Hybridizer編譯管線

圖1顯示了Hybridizer編譯管線。使用Parallel.For之類的并行化模式,或者像在CUDA中一樣明確地分配并行工作,可以從加速器的計算能力中受益,而無需了解其內(nèi)部架構(gòu)的所有細(xì)節(jié)。下面是一個使用Parallel.For和lambda的簡單示例。

Hybridizer:GPU上的高性能C

人們可以使用NVIDIA Nsight Visual Studio Edition在GPU上調(diào)試和分析這些代碼。 Hybridizer實現(xiàn)了先進(jìn)的C#功能,其中包括虛函數(shù)和泛型。

在哪里可以獲得Hybridizer

Hybridizer有兩個版本:

Hybridizer Software Suite:支持CUDA,AVX,AVX2,AVX512目標(biāo)和輸出源代碼。這個源代碼需要被審查,這在某些企業(yè)(如投資銀行)是強制性的。Hybridizer軟件套件根據(jù)客戶要求獲得許可。

Hybridizer Essentials:僅啟用CUDA目標(biāo)并僅輸出二進(jìn)制文件。 Hybridizer Essentials是一個免費的Visual Studio擴展程序,沒有硬件限制。人們可以在GitHub上找到一組基本代碼示例和教育資料。這些樣本也可以用來重現(xiàn)其性能結(jié)果。

調(diào)試和分析

使用調(diào)試信息進(jìn)行編譯時,可以在Microsoft Visual Studio中調(diào)試Hybridizer C#/ .NET代碼,同時在目標(biāo)硬件上運行優(yōu)化代碼。例如,用C#編寫的程序可以在Visual Studio中的C#文件中創(chuàng)建一個斷點,可以瀏覽駐留在GPU上的本地變量和對象數(shù)據(jù)。

Hybridizer:GPU上的高性能C

圖2 使用Hybridizer和NVIDIA Nsight Visual Studio Edition調(diào)試GPU上運行的C#代碼

人們可以在復(fù)雜項目中集成Hybridizer,即使在代碼不可用或模糊的庫中,這是因為Hybridizer在MSIL字節(jié)碼上運行。在博客文章中展示了使用Hybridizer加速AForge圖像處理庫而沒有修改庫的能力。在MSIL字節(jié)碼上運行也支持在.Net虛擬機之上構(gòu)建的各種語言,比如VB.Net和F#。

所有這些靈活性不會以犧牲性能損失為代價。正如基準(zhǔn)測試所示,Hybridizer產(chǎn)生的代碼可以像手寫代碼一樣執(zhí)行。人們可以使用性能分析器(例如NVIDIA Nsight和NVIDIA Visual Profiler)來測量生成的二進(jìn)制文件的性能,其性能指標(biāo)指的是原始源代碼(例如C#)。

舉一個簡單的例子:Mandelbrot

作為第一個例子,演示了在NVIDIA GeForce GTX 1080 Ti GPU(Pascal架構(gòu),計算能力6.1)上運行的Mandelbrot分形的渲染。

Mandelbrot C#代碼

以下代碼片斷顯示了plain C#。它在CPU上平穩(wěn)運行,沒有任何性能損失,因為大多數(shù)代碼都是屬性的修改,在運行時沒有任何影響(例如Run方法中的EntryPoint屬性)。

[EntryPoint]

public static void Run(float[,] result)

{

int size = result.GetLength(0);

Parallel2D.For(0, size, 0, size, (i, j) => {

float x = fromX + i * h;

float y = fromY + j * h;

result[i, j] = IterCount(x, y);

});

}

public static float IterCount(float cx, float cy)

{

float result = 0.0F;

float x = 0.0f, y = 0.0f, xx = 0.0f, yy = 0.0f;

while (xx + yy <= 4.0f && result < maxiter) {

xx = x * x;

yy = y * y;

float xtmp = xx - yy + cx;

y = 2.0f * x * y + cy;

x = xtmp;

result++;

}

return result;

}

EntryPoint屬性告訴Hybridizer生成一個CUDA內(nèi)核。多維數(shù)組映射到內(nèi)部類型,而Parallel2D.For映射到2D執(zhí)行網(wǎng)格。給定幾行Boilerplate(樣板)代碼,可以透明地在GPU上運行這些代碼。

float[,] result = new float[N,N];

HybRunner runner = HybRunner.Cuda("Mandelbrot_CUDA.dll").SetDistrib(32, 32, 16, 16, 1, 0);

dynamic wrapper = runner.Wrap(new Program());

wrapper.Run(result);

剖析

我們使用Nvidia Nsight Visual Studio Edition分析器來分析此代碼。將C#代碼鏈接到CUDA源代碼視圖中的PTX,如圖3所示。

Hybridizer:GPU上的高性能C

圖3在CUDA源代碼視圖中分析Mandelbrot C#代碼

分析器允許與CUDA C ++代碼相同的調(diào)查級別。

就性能而言,這個例子達(dá)到峰值計算FLOP / s的72.5%。這是CUDA C ++人工編寫的相同代碼的83%。

Hybridizer:GPU上的高性能C

圖4 Profiler輸出顯示了GPU上Mandelbrot代碼的GPU利用率和執(zhí)行效率。它實現(xiàn)的效率幾乎與人工編寫CUDA C ++代碼一樣高效。 使用Hybridizer提供的擴展控件,可以從C#代碼中獲得更好的性能。如下面的代碼所示,其語法與CUDA C ++非常相似。[EntryPoint]

public static void Run(float[] result)

{

for (int i = threadIdx.y + blockIdx.y * blockDim.y; i < N; i += blockDim.y * gridDim.y)

{

for (int j = threadIdx.x + blockIdx.x * blockDim.x; j < N; j += blockDim.x * gridDim.x)

{

float x = fromX + i * h;

float y = fromY + j * h;

result[i * N + j] = IterCount(x, y);

}

}

}

在這個案例中,生成的代碼和人工編寫的CUDA C ++代碼的性能完全相同,達(dá)到峰值FLOP/s的87%,如圖5所示。

Hybridizer:GPU上的高性能C

圖5分析人工優(yōu)化的Mandelbrot C#代碼

泛型和虛函數(shù)

Hybridizer支持設(shè)備功能中的泛型和虛函數(shù)調(diào)用。現(xiàn)代編程語言的這些基本概念有助于代碼模塊化并提高表達(dá)能力。但是,C#中的類型解析是在運行時完成的,這會導(dǎo)致一些性能損失。.NET的泛型可以在保持靈活性的同時實現(xiàn)更高的性能:Hybridizer將泛型映射到C++模板,C ++模板在編譯時解析,允許函數(shù)內(nèi)聯(lián)和過程間優(yōu)化。另一方面,虛函數(shù)調(diào)用被映射到其中實例方法被注冊的虛函數(shù)表。

通過兩個屬性HybridTemplateConcept和HybridRegisterTemplate(在設(shè)備代碼中觸發(fā)實際的模板實例化)給模板實例化提示。作為一個例子,我們來看看兩個版本中的一個簡單的stream benchmark,一個使用虛函數(shù)調(diào)用,另一個使用模板映射。該基準(zhǔn)依賴于一個通用的接口IMyArray暴露出下標(biāo)運算符:

[HybridTemplateConcept]

public interface IMyArray {

double this[int index] { get; set; }

}

這些操作符必須與設(shè)備功能"Hybridized(雜交)"。為此,我們把Kernel屬性放在實現(xiàn)類中。

public class MyArray : IMyArray {

double[] _data;

public MyArray(double[] data) {

_data = data;

}

[Kernel]

public double this[int index] {

get { return _data[index]; }

set { _data[index] = value; }

}

}

虛擬功能調(diào)用

在第一個版本中,使用接口編寫了一個流算法,沒有進(jìn)一步提示編譯器。public class MyAlgorithmDispatch {

IMyArray a, b;

public MyAlgorithmDispatch(IMyArray a, IMyArray b) {

this.a = a;

this.b = b;

}

[Kernel]

public void Add(int n) {

IMyArray a = this.a;

IMyArray b = this.b;

for (int k = threadIdx.x + blockDim.x * blockIdx.x;

k < n;

k += blockDim.x * gridDim.x) {

a[k] += b[k];

}

}

}

因為把a和b上的下標(biāo)運算符稱為接口,所以在MSIL中有一個callvirt。IL_002a: ldloc.3

IL_002b: ldloc.s 4

IL_002d: callvirt instance float64 Mandelbrot.IMyArray::get_Item(int32)

IL_0032: ldloc.1

IL_0033: ldloc.2

IL_0034: callvirt instance float64 Mandelbrot.IMyArray::get_Item(int32)

IL_0039: add

IL_003a: callvirt instance void Mandelbrot.IMyArray::set_Item(int32, float64檢查生成的二進(jìn)制表明Hybridizer在虛函數(shù)表中生成了一個查找,如圖6所示。

圖6. PTX中的虛函數(shù)調(diào)用 這個版本的算法消耗32個寄存器,并獲得271GB/s的帶寬,如圖7所示。在同一硬件上,CUDA Toolkit中的帶寬測試示例達(dá)到352GB/s。

Hybridizer:GPU上的高性能C

圖7由于虛函數(shù)調(diào)用而實現(xiàn)的低帶寬

虛函數(shù)表會導(dǎo)致更多的注冊壓力,并防止內(nèi)聯(lián)。

通用要求

采用泛型寫了第二個版本,要求Hybridizer生成模板代碼。

[HybridRegisterTemplate(Specialize = typeof(MyAlgorithm))]

public class MyAlgorithm where T : IMyArray

{

T a, b;

[Kernel]

public void Add(int n)

{

T a = this.a;

T b = this.b;

for (int k = threadIdx.x + blockDim.x * blockIdx.x;

k < n;

k += blockDim.x * gridDim.x)

a[k] += b[k];

}

}

public MyAlgorithm(T a, T b)

{

this.a = a;

this.b = b;

}

}

使用RegisterTemplate屬性,Hybridizer將生成相應(yīng)的模板實例。然后生成內(nèi)聯(lián)函數(shù)的調(diào)用,如圖8所示。

圖8使用泛型參數(shù)生成內(nèi)聯(lián)函數(shù)調(diào)用,而不是虛函數(shù)表查找

其通用參數(shù)性能要好得多,達(dá)到339GB/s,性能提高25%(如圖9所示),帶寬測試為96%。

Hybridizer:GPU上的高性能C

圖9 由于函數(shù)內(nèi)聯(lián),泛型實現(xiàn)了更高的帶寬開始使用Hybridizer

Hybridizer支持各種C#特性,允許代碼分解和表達(dá)。Visual Studio和Nsight(調(diào)試器和分析器)中的集成為人們提供了一個安全高效的開發(fā)環(huán)境。即使在非常復(fù)雜的高度定制的代碼上,Hybridizer也可以實現(xiàn)出色的GPU性能。

人們可以從Visual Studio Marketplace下載Hybridizer Essentials。查看在github上的SDK。

鏈接已復(fù)制,快去分享吧

企業(yè)網(wǎng)版權(quán)所有?2010-2024 京ICP備09108050號-6京公網(wǎng)安備 11010502049343號