【问题标题】:At what code complexity does an OpenACC kernel lose efficiency on common GPU?OpenACC 内核在什么代码复杂度下会在普通 GPU 上失去效率?
【发布时间】:2017-08-02 04:42:04
【问题描述】:

OpenACC 内核在常见的 GPU 和寄存器上失去效率的代码复杂度是多少?共享内存操作或其他一些方面开始成为性能瓶颈?

还有一些时候,太少的任务和传输到 GPU 和内核的开销会成为瓶颈?

缓存大小和代码是否适合表明每个内核的最佳任务或其他什么?

与潜在性能相比,每个内核的 OpenACC 开销有多大?它是否因各种指令而有很大差异?

【问题讨论】:

    标签: c++ openacc


    【解决方案1】:

    我会避免使用代码的复杂性作为性能指标。您可以让高度复杂的代码在 GPU 上非常高效地运行,而简单的代码运行不佳。相反,我会考虑以下因素:

    1. 设备和主机之间的数据移动。限制数据移动的频率并尝试以连续的块传输数据。使用 OpenACC 非结构化数据区域来匹配设备上的主机分配(即,在通过“new”或“malloc”分配数据的同时使用“enter data”)。将尽可能多的计算转移到 GPU,并且仅在绝对必要时使用 OpenACC 更新指令来同步主机和设备数据。如果数据移动不可避免,请使用“async”子句将数据移动与计算交错进行调查。
    2. 设备上的数据访问和限制内存分歧。确保有您的数据布局,以便跨向量连续访问数组的 stride-1(连续)维度。
    3. 具有高计算强度,即计算与数据移动的比率。计算越多,数据移动越少越好。但是,如果存在其他高强度循环,则计算强度较低的循环很好,将数据移动到主机的成本将抵消在设备上运行内核的成本。
    4. 避免在设备上分配数据,因为它会强制线程序列化。这包括使用 Fortran“自动”数组,以及在其构造函数中使用包含分配声明 C++ 对象。
    5. 避免原子操作。与宿主原子相比,原子操作实际上非常有效,但仍应尽可能避免。
    6. 避免子程序调用。尽可能尝试内联例程。
    7. 占用。占用率是可能在 GPU 上运行的线程数与可能运行的最大线程数之比。请注意,100% 的入住率并不能保证高性能,但如果可能,您应该尝试将其提高到 50% 以上。占用的限制因素是每个线程(向量)使用的寄存器数量和每个块(群)使用的共享内存。假设您使用的是 PGI 编译器,您可以通过运行 PGI“pgaccelinfo”实用程序来查看设备的限制。使用的寄存器数量将取决于使用的本地标量的数量(由程序员明确声明和由编译器创建用于保存中间计算的临时变量),使用的共享内存量将由 OpenACC“缓存”和“私有”确定" 在 "gang" 循环中使用 "private" 时的指令。您可以通过添加标志“-ta=tesla:ptxinfo”来查看每个内核使用了多少。您可以通过“-ta=tesla:maxregcount:”限制每个线程使用的寄存器数量。减少寄存器的数量会增加占用率,但也会增加寄存器溢出的数量。溢出很好,只要它们只溢出到 L1/L2 缓存。溢出到全局内存会损害性能。与溢出到全局内存相比,降低占用率通常更好。

    请注意,我强烈建议使用分析器(PGPROF、NVprof、Score-P、TAU、Vampir 等)来帮助发现程序的性能瓶颈。

    【讨论】:

      猜你喜欢
      • 2020-04-07
      • 2021-09-24
      • 2011-07-04
      • 2013-06-06
      • 1970-01-01
      • 1970-01-01
      • 2016-07-04
      • 2015-12-03
      • 1970-01-01
      相关资源
      最近更新 更多