Hybridizer 是一個(gè)來自 Altimesh 的編譯器,它允許您從 C 代碼或.NET 程序集編程 GPUs 和其他加速器。使用修飾符號來表示并行性, Hybridizer 生成針對多核 CPUs 和 GPUs 優(yōu)化的源代碼或二進(jìn)制文件。在這篇博文中,我們展示了 CUDA 的目標(biāo)。
圖 1 顯示了混合器編譯管道。使用 Parallel.For 等并行化模式,或者像在 CUDA 中那樣顯式地分配并行工作,您可以從加速器的計(jì)算馬力中獲益,而無需了解其內(nèi)部架構(gòu)的所有細(xì)節(jié)。
圖 1 雜交劑管道。
[EntryPoint] public static void Run(double[] a, double[] b, int N) { Parallel.For(0, N, i => { a[i] += b[i]; }); }
您可以使用 NVIDIA Nsight Visual Studio Edition 在 GPU 上調(diào)試和分析這段代碼。Hybridizer 實(shí)現(xiàn)高級 C#功能,包括虛擬功能和泛型。
哪里可以獲取 Hybridizer
Hybridizer 有 兩個(gè)版本 :
Hybridizer 軟件套件:啟用 CUDA 、 AVX 、 AVX2 、 AVX512 目標(biāo)并輸出源代碼??梢圆榭创嗽创a,這在投資銀行等一些業(yè)務(wù)中是強(qiáng)制性的。 Hybridizer 軟件套件是根據(jù)客戶 應(yīng)要求 獲得許可的。
雜交者基本要素 :僅啟用 CUDA 目標(biāo)并僅輸出二進(jìn)制文件。 Hybridizer Essentials 是免費(fèi)的 Visual Studio 擴(kuò)展 ,沒有硬件限制。 您可以在 GitHub 上找到一組基本的代碼示例和教育材料 。這些樣本也可以用來重現(xiàn)我們的性能結(jié)果。
在提供自動(dòng)默認(rèn)行為的同時(shí), Hybridizer 在每個(gè)階段都提供了完全的開發(fā)人員控制,允許您重用現(xiàn)有的特定于設(shè)備的代碼、現(xiàn)有的外部庫或定制的手工代碼片段。
調(diào)試和分析
使用調(diào)試信息編譯時(shí),可以在目標(biāo)硬件上運(yùn)行優(yōu)化的代碼時(shí),在 Microsoft Visual Studio 中調(diào)試 Hybridizer C #/。 NET 代碼。例如,用 C 編寫的程序可以在 Visual Studio 中命中 C 文件中的斷點(diǎn),并且可以探索駐留在 GPU 上的本地變量和對象數(shù)據(jù)。
圖 2 :使用 Hybridizer 和 NVIDIA Nsight VisualStudio Edition 調(diào)試運(yùn)行在 GPU 上的 C 代碼。
您可以在復(fù)雜的項(xiàng)目中集成 Hybridizer ,即使在代碼不可用或混淆的庫中也是如此,因?yàn)?Hybridizer 操作的是 MSIL 字節(jié)碼。我們在 我們的博客帖子 中展示了這種能力,即在不修改庫的情況下,用雜交子加速大型圖像處理庫。在 MSIL 字節(jié)碼上操作還支持在。 Net 虛擬機(jī)上構(gòu)建的各種語言,例如 VB 。 Net 和 F 。
所有這些靈活性并不是以性能損失為代價(jià)的。正如我們的 benchmark 所說明的,雜交器生成的代碼可以執(zhí)行與手寫代碼一樣好的性能。您可以使用性能分析器,如 NVIDIA Nsight 和 NVIDIA 可視化探查器來測量生成的二進(jìn)制文件的性能,性能指標(biāo)引用原始源代碼(例如 C )。
一個(gè)簡單的例子:曼德爾布洛特
作為第一個(gè)示例,我們演示了在 NVIDIA GeForce GTX 1080 Ti GPU ( Pascal 體系結(jié)構(gòu);計(jì)算能力 6 。 1 )上運(yùn)行的 Mandelbrot 分形的渲染。
Mandelbrot C 代碼
下面的代碼片段顯示了純 C #。它在 CPU 上平穩(wěn)運(yùn)行,沒有任何性能損失,因?yàn)榇蠖鄶?shù)代碼修改都是在運(yù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
屬性告訴雜交器生成一個(gè) CUDA 內(nèi)核。多維數(shù)組映射到內(nèi)部類型,而Parallel2D.For
映射到 2D 執(zhí)行網(wǎng)格。給出幾行樣板代碼,我們在 GPU 上透明地運(yùn)行這段代碼。
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 所示。
圖 3 。在 CUDA 源代碼視圖中分析 Mandelbrot C #代碼。
剖析器允許使用與 CUDA C ++代碼相同的調(diào)查級別。
至于性能,這個(gè)例子達(dá)到了峰值計(jì)算 FLOP / s 的 72 。 5% ,這是用 CUDA C++ 手寫的相同代碼的 83% 。
圖 4 : Profiler 輸出顯示了 GPU 上 Mandelbrot 代碼的利用率和執(zhí)行效率。它達(dá)到了與手寫 CUDA C ++代碼差不多的良好效率。
使用雜交器提供的擴(kuò)展控制,可以從 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 ++代碼執(zhí)行一致,達(dá)到峰值觸發(fā)器的 87% ,如圖 5 所示。
圖 5 :分析手動(dòng)優(yōu)化的 Mandelbrot C 代碼。
泛型與虛函數(shù)
Hybridizer 在設(shè)備功能上支持 泛型和虛函數(shù)調(diào)用 ?,F(xiàn)代編程語言的這些基本概念促進(jìn)了代碼模塊化并提高了表達(dá)能力。然而, C 型的類型解析是在運(yùn)行時(shí)完成的,這引入了一些性能上的懲罰。席。 NET- 泛型可以在保持靈活性的同時(shí)實(shí)現(xiàn)更高的性能: FixZER 將泛型映射到 C ++模板,這些模板在編譯時(shí)被解決,允許函數(shù)內(nèi)聯(lián)和過程間優(yōu)化。另一方面,虛擬函數(shù)中的方法被映射到另一個(gè)虛擬函數(shù)中。
模板實(shí)例化提示由兩個(gè)屬性 HybridTemplateConcept 和 HybridRegisterTemplate 提供給混合器(在設(shè)備代碼中觸發(fā)實(shí)際的模板實(shí)例化),另一個(gè)使用模板映射?;鶞?zhǔn)依賴于一個(gè)公開下標(biāo)運(yùn)算符的公共接口 IMyArray :
[HybridTemplateConcept] public interface IMyArray { double this[int index] { get; set; } }
這些操作員必須與設(shè)備功能“混合”。為此,我們將Kernel
屬性放在實(shí)現(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; } } }
虛函數(shù)調(diào)用
在第一個(gè)版本中,我們使用接口編寫一個(gè)流算法,而不向編譯器提供進(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]; } } }
因?yàn)槲覀冊?code style="font-size:inherit;color:inherit;margin:0px;padding:0px;border:0px;font-style:inherit;font-variant:inherit;font-weight:inherit;line-height:inherit;vertical-align:baseline;background-color:rgb(244,244,244);">a和b
上調(diào)用下標(biāo)運(yùn)算符,所以在 MSIL 中有一個(gè)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ù)表中生成了一個(gè)查找,如圖 6 所示。
圖 6 PTX 中的虛函數(shù)調(diào)用。
這個(gè)版本的算法消耗 32 個(gè)寄存器,達(dá)到 271 GB / s 的帶寬,如圖 7 所示。在相同的硬件上, CUDA 工具箱中的 bandwidthTest 示例達(dá)到 352Gb / s 。
圖 7 由于虛擬函數(shù)調(diào)用,實(shí)現(xiàn)的帶寬較低。
虛函數(shù)表導(dǎo)致更大的寄存器壓力,并阻止內(nèi)聯(lián)。
一般呼叫
我們用泛型編寫了第二個(gè)版本,要求雜交子生成模板代碼。
[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 生成適當(dāng)?shù)哪0鍖?shí)例。然后優(yōu)化器內(nèi)聯(lián)函數(shù)調(diào)用,如圖 8 所示。
圖 8 使用泛型參數(shù)生成內(nèi)聯(lián)函數(shù)調(diào)用,而不是虛擬函數(shù)表查找。
泛型參數(shù)的性能要好得多,達(dá)到 339gb / s ,性能提高了 25% (圖 9 ),比 bandwidthTest 提高了 96% 。
圖 9 由于函數(shù)內(nèi)聯(lián),泛型實(shí)現(xiàn)了更高的帶寬。
開始使用雜交劑
Hybridizer 支持多種 C 特性,允許代碼分解和表達(dá)能力。 Visual Studio 與 Nsight (調(diào)試器和探查器)的集成為您提供了一個(gè)安全高效的開發(fā)環(huán)境。 Hybridizer 即使在非常復(fù)雜、高度定制的代碼上也能獲得出色的 GPU 性能。
關(guān)于作者
Florent Duguet 是 Altimesh 的創(chuàng)始人, Altimesh 是一家法國軟件工程公司,專門從事自動(dòng)代碼轉(zhuǎn)換和多核和多核代碼優(yōu)化。他學(xué)習(xí)數(shù)學(xué)、物理和計(jì)算機(jī)科學(xué),并于 2005 年獲得計(jì)算機(jī)圖形學(xué)博士學(xué)位。作為 GPU 計(jì)算領(lǐng)域的早期采用者, Florent 自 2007 年初開始在各種環(huán)境中實(shí)施 CUDA 解決方案,如定量金融、石油和天然氣以及圖像處理,同時(shí)致力于 Hybridizer 以實(shí)現(xiàn)代碼轉(zhuǎn)換的自動(dòng)化。
R é gis 是 Altimesh 的研究工程師。他于 2010 年畢業(yè)于 Ecole Polytechnique ,學(xué)習(xí)純數(shù)學(xué)和應(yīng)用數(shù)學(xué),如拓?fù)鋵W(xué)和計(jì)算流體力學(xué)。瑞吉斯在加入 Altimesh 之前曾在微軟做過三年的工程師。 Regis 專注于使 LLVM-IR 成為雜交劑和雜交劑要素開發(fā)的輸入。
審核編輯:郭婷
-
cpu
+關(guān)注
關(guān)注
68文章
11080瀏覽量
217091 -
gpu
+關(guān)注
關(guān)注
28文章
4948瀏覽量
131244 -
虛擬機(jī)
+關(guān)注
關(guān)注
1文章
966瀏覽量
29368
發(fā)布評論請先 登錄
邊緣設(shè)備AI部署:編譯器如何實(shí)現(xiàn)輕量化與高性能?
EE-88:使用21xx編譯器在C中初始化變量

Triton編譯器與GPU編程的結(jié)合應(yīng)用
Triton編譯器如何提升編程效率
Triton編譯器在高性能計(jì)算中的應(yīng)用
Triton編譯器的優(yōu)化技巧
Triton編譯器的優(yōu)勢與劣勢分析
Triton編譯器在機(jī)器學(xué)習(xí)中的應(yīng)用
Triton編譯器支持的編程語言
Triton編譯器與其他編譯器的比較
Triton編譯器功能介紹 Triton編譯器使用教程
HighTec C/C++編譯器支持Andes晶心科技RISC-V IP
MSP430優(yōu)化C/C++編譯器v21.6.0.LTS

TMS320C6000優(yōu)化C/C++編譯器v8.3.x

C7000優(yōu)化C/C++編譯器

評論