0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Hybridizer编译器在GPU上实现高级C#功能

星星科技指导员 来源:NVIDIA 作者:NVIDIA 2022-04-28 16:19 次阅读

Hybridizer 是一个来自 Altimesh 的编译器,它允许您从 C 代码或.NET 程序集编程 GPUs 和其他加速器。使用修饰符号来表示并行性, Hybridizer 生成针对多核 CPUs 和 GPUs 优化的源代码或二进制文件。在这篇博文中,我们展示了 CUDA 的目标。

图 1 显示了混合器编译管道。使用 Parallel.For 等并行化模式,或者像在 CUDA 中那样显式地分配并行工作,您可以从加速器的计算马力中获益,而无需了解其内部架构的所有细节。

图 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 上调试和分析这段代码。Hybridizer 现高级 C#功能,包括虚拟功能和泛型。

哪里可以获取 Hybridizer

Hybridizer 有 两个版本 :

Hybridizer 软件套件:启用 CUDA 、 AVX 、 AVX2 、 AVX512 目标并输出源代码。可以查看此源代码,这在投资银行等一些业务中是强制性的。 Hybridizer 软件套件是根据客户 应要求 获得许可的。

杂交者基本要素 :仅启用 CUDA 目标并仅输出二进制文件。 Hybridizer Essentials 是免费的 Visual Studio 扩展 ,没有硬件限制。 您可以在 GitHub 上找到一组基本的代码示例和教育材料 。这些样本也可以用来重现我们的性能结果。

在提供自动默认行为的同时, Hybridizer 在每个阶段都提供了完全的开发人员控制,允许您重用现有的特定于设备的代码、现有的外部库或定制的手工代码片段。

调试和分析

使用调试信息编译时,可以在目标硬件上运行优化的代码时,在 Microsoft Visual Studio 中调试 Hybridizer C #/。 NET 代码。例如,用 C 编写的程序可以在 Visual Studio 中命中 C 文件中的断点,并且可以探索驻留在 GPU 上的本地变量和对象数据。

图 2 :使用 Hybridizer 和 NVIDIA Nsight VisualStudio Edition 调试运行在 GPU 上的 C 代码。

您可以在复杂的项目中集成 Hybridizer ,即使在代码不可用或混淆的库中也是如此,因为 Hybridizer 操作的是 MSIL 字节码。我们在 我们的博客帖子 中展示了这种能力,即在不修改库的情况下,用杂交子加速大型图像处理库。在 MSIL 字节码上操作还支持在。 Net 虚拟机上构建的各种语言,例如 VB 。 Net 和 F 。

所有这些灵活性并不是以性能损失为代价的。正如我们的 benchmark 所说明的,杂交器生成的代码可以执行与手写代码一样好的性能。您可以使用性能分析器,如 NVIDIA Nsight 和 NVIDIA 可视化探查器来测量生成的二进制文件的性能,性能指标引用原始源代码(例如 C )。

一个简单的例子:曼德尔布洛特

作为第一个示例,我们演示了在 NVIDIA GeForce GTX 1080 Ti GPU ( Pascal 体系结构;计算能力 6 。 1 )上运行的 Mandelbrot 分形的渲染。

Mandelbrot C 代码

下面的代码片段显示了纯 C #。它在 CPU 上平稳运行,没有任何性能损失,因为大多数代码修改都是在运行时没有影响的属性(例如 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属性告诉杂交器生成一个 CUDA 内核。多维数组映射到内部类型,而Parallel2D.For映射到 2D 执行网格。给出几行样板代码,我们在 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 所示。

图 3 。在 CUDA 源代码视图中分析 Mandelbrot C #代码。

剖析器允许使用与 CUDA C ++代码相同的调查级别。

至于性能,这个例子达到了峰值计算 FLOP / s 的 72 。 5% ,这是用 CUDA C++ 手写的相同代码的 83% 。

图 4 : Profiler 输出显示了 GPU 上 Mandelbrot 代码的利用率和执行效率。它达到了与手写 CUDA C ++代码差不多的良好效率。

使用杂交器提供的扩展控制,可以从 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 ++代码执行一致,达到峰值触发器的 87% ,如图 5 所示。

图 5 :分析手动优化的 Mandelbrot C 代码。

泛型与虚函数

Hybridizer 在设备功能上支持 泛型和虚函数调用 。现代编程语言的这些基本概念促进了代码模块化并提高了表达能力。然而, C 型的类型解析是在运行时完成的,这引入了一些性能上的惩罚。席。 NET- 泛型可以在保持灵活性的同时实现更高的性能: FixZER 将泛型映射到 C ++模板,这些模板在编译时被解决,允许函数内联和过程间优化。另一方面,虚拟函数中的方法被映射到另一个虚拟函数中。

模板实例化提示由两个属性 HybridTemplateConcept 和 HybridRegisterTemplate 提供给混合器(在设备代码中触发实际的模板实例化),另一个使用模板映射。基准依赖于一个公开下标运算符的公共接口 IMyArray :

[HybridTemplateConcept]
public interface IMyArray {

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

这些操作员必须与设备功能“混合”。为此,我们将Kernel属性放在实现类中。

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; }
    }
}

虚函数调用

在第一个版本中,我们使用接口编写一个流算法,而不向编译器提供进一步的提示。

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];
        }
    }
}

因为我们在ab上调用下标运算符,所以在 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)

检查生成的二进制文件显示, Hybridizer 在虚拟函数表中生成了一个查找,如图 6 所示。

图 6 PTX 中的虚函数调用。

这个版本的算法消耗 32 个寄存器,达到 271 GB / s 的带宽,如图 7 所示。在相同的硬件上, CUDA 工具箱中的 bandwidthTest 示例达到 352Gb / s 。

图 7 由于虚拟函数调用,实现的带宽较低。

虚函数表导致更大的寄存器压力,并阻止内联。

一般呼叫

我们用泛型编写了第二个版本,要求杂交子生成模板代码。

[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 生成适当的模板实例。然后优化器内联函数调用,如图 8 所示。

图 8 使用泛型参数生成内联函数调用,而不是虚拟函数表查找。

泛型参数的性能要好得多,达到 339gb / s ,性能提高了 25% (图 9 ),比 bandwidthTest 提高了 96% 。

图 9 由于函数内联,泛型实现了更高的带宽。

开始使用杂交剂

Hybridizer 支持多种 C 特性,允许代码分解和表达能力。 Visual Studio 与 Nsight (调试器和探查器)的集成为您提供了一个安全高效的开发环境。 Hybridizer 即使在非常复杂、高度定制的代码上也能获得出色的 GPU 性能。

关于作者

Florent Duguet 是 Altimesh 的创始人, Altimesh 是一家法国软件工程公司,专门从事自动代码转换和多核和多核代码优化。他学习数学、物理和计算机科学,并于 2005 年获得计算机图形学博士学位。作为 GPU 计算领域的早期采用者, Florent 自 2007 年初开始在各种环境中实施 CUDA 解决方案,如定量金融、石油和天然气以及图像处理,同时致力于 Hybridizer 以实现代码转换的自动化。

R é gis 是 Altimesh 的研究工程师。他于 2010 年毕业于 Ecole Polytechnique ,学习纯数学和应用数学,如拓扑学和计算流体力学。瑞吉斯在加入 Altimesh 之前曾在微软做过三年的工程师。 Regis 专注于使 LLVM-IR 成为杂交剂和杂交剂要素开发的输入。

审核编辑:郭婷

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10442

    浏览量

    206548
  • gpu
    gpu
    +关注

    关注

    27

    文章

    4417

    浏览量

    126689
  • 虚拟机
    +关注

    关注

    1

    文章

    855

    浏览量

    27374
收藏 人收藏

    评论

    相关推荐

    编译器的优化选项

    一个程序首先要保证正确性,在保证正确性的基础上,性能也是一个重要的考量。要编写高性能的程序,第一,必须选择合适的算法和数据结构;第二,应该编写编译器能够有效优化以转换成高效可执行代码的源代码,要做到
    的头像 发表于 11-24 15:37 406次阅读
    <b class='flag-5'>编译器</b>的优化选项

    嵌入式javascript编译器的设计与实现

    电子发烧友网站提供《嵌入式javascript编译器的设计与实现.pdf》资料免费下载
    发表于 10-30 11:29 0次下载
    嵌入式javascript<b class='flag-5'>编译器</b>的设计与<b class='flag-5'>实现</b>

    如何安装ARM编译器Linux版

    本教程介绍如何下载、安装、设置您的环境,以及如何开始使用ARM编译器for Linux。 ARM编译器Linux版软件包包括ARM C/C++编译器
    发表于 08-28 06:45

    RealView编译工具4.0版编译器参考指南

    编译器有几种模式,在这些模式中,要么强制遵守源语言,要么放松遵守: 严格模式严格模式下,编译器强制遵守与源语言相关的语言标准。 例如,使用//-样式的注释会在编译Strong
    发表于 08-18 06:13

    ARM编译器ARM CC++库及浮点支持用户指南

    它。 如果您在没有协处理的系统编译编译器将在软件中实现计算。 例如,编译器选项--fpu=
    发表于 08-16 07:36

    ARM编译器可扩展矢量扩展用户指南

    ARM编译器工具链支持为ARMv8-A AArch64实现可伸缩向量扩展(SVE)EAC(00rel1)的目标。 SVE是针对AArch64的下一代SIMD指令集,它为高性能计算(HPC)引入了以下
    发表于 08-16 06:51

    RealView用于BREW编译器和库的编译工具指南

    99的一些功能,如Long Long,也是可用的。 ARM C++编译器期望C++符合国际标准化组织/国际电工委员会14822:1998年的C
    发表于 08-12 07:38

    Arm C/C++编译器22.1版开发人员和参考指南

    提供帮助您使用ARM®编译器Linux版的ARM®C/C++编译器组件的信息。 ARM®C/C+
    发表于 08-11 07:46

    如何将Arm Neon C#内部函数与Unity Burst编译器一起使用

    本指南解释了如何将Arm Neon C#内部函数与Unity Burst编译器一起使用,以提高Unity Android应用程序的性能。 本指南结束时,您将了解到: •单指令多数据(SIMD)指令
    发表于 08-10 07:11

    Arm编译器可扩展矢量扩展用户指导

    Arm编译器工具链支持实现可伸缩矢量扩展(SVE)EAC的目标(00rel2)用于Armv8‑A AArch64。 SVE是AArch64的SIMD指令集,它为High引入了以下体系结构特征性能计算
    发表于 08-08 06:34

    如何使用Arm Compiler 6自动矢量化功能为Neon编译

    哪个Arm编译器命令行选项启用高级SIMD代码的一代。 •您将能够编写利用Arm各种优化功能C/ c++代码
    发表于 08-02 19:31

    如何实现VBA编译器崩溃

    本篇文章为VBA脚本隐藏技术的最后一篇,将介绍如何在保证VBA脚本正常执行的情况下,使分析人员无法打开编译器
    发表于 07-15 10:02 460次阅读
    如何<b class='flag-5'>实现</b>VBA<b class='flag-5'>编译器</b>崩溃

    如何在Windows 10安装C编译器

    我想学习c,据我所知,我需要ac编译器。但是那里似乎有一些。寻找教程时,我看到的最多的是 minGW 和 gcc,我不太确定该怎么做。有什么好的方法可以让 c 进入你的电脑吗?
    发表于 06-08 06:31

    IDE和编译器的效率比较哪个最好?

    当在微控制实现某些功能时,例如脉冲发生,我粗略地想象 - 所选 Fck 的最大脉冲频率(当在不同的 IDE 中使用汇编程序
    发表于 06-01 11:02

    R32C/100系列C编译器包V.1.01 C编译器用户手册

    R32C/100系列C编译器包V.1.01 C编译器用户手册
    发表于 04-28 19:54 1次下载
    R32C/100系列C<b class='flag-5'>编译器</b>包V.1.01 C<b class='flag-5'>编译器</b>用户手册