如何可靠地查询金属计算着色器的 SIMD 组大小? threadExecutionWidth 并不总是匹配

问题描述 投票:0回答:1

我正在尝试在 Mac 应用程序中的一系列相当复杂的计算内核中使用 SIMD 组缩减/前缀函数。我需要分配一些线程组内存来协调同一线程组中的 SIMD 组。因此,该数组的容量应取决于

[[simdgroups_per_threadgroup]]
,但这不是编译时值,因此它不能用作数组维度。

现在,根据各种 WWDC 会话视频,管道对象上的

threadExecutionWidth
应返回 SIMD 组大小,然后我可以使用计算编码器上的
setThreadgroupMemoryLength:atIndex:
分配适当数量的内存。

这在某些硬件上一致工作(例如 Apple M1,

threadExecutionWidth
似乎总是报告 32),但我遇到的配置中
threadExecutionWidth
与明显的 SIMD 组大小不匹配,导致由于越界访问而导致运行时错误。 (例如,在 Intel UHD Graphics 630 上,对于某些复杂内核,
threadExecutionWidth
= 16,尽管 SIMD 组大小似乎为 32)

所以:

  1. 有没有可靠的方法可以在计算内核运行之前查询 SIMD 组大小?
  2. 或者,设备上所有内核的 SIMD 组大小是否始终相同?

如果后者至少是正确的,我大概可以相信

threadExecutionWidth
对于最微不足道的内核?或者我应该向 GPU 提交一个简单的内核并返回
[[threads_per_simdgroup]]

我怀疑这个问题可能发生在 Metal 提供“奇数”(非 pow2)最大线程组大小的内核中,尽管在我遇到的情况下,最大线程组大小报告为 896,它是32,所以它并不是使用最大线程组大小和 SIMD 组大小之间的最大公分母来实现

threadExecutionWidth

macos gpgpu metal compute-shader
1个回答
0
投票

我从来没有找到一个特别令人满意的解决方案,但我至少找到了一个有效的解决方案:

  1. 预期SIMD 组大小作为内核参数传递,该参数用作分配缓冲区大小的基础。从
    threadExecutionWidth
    开始。
  2. 作为计算内核的第一部分,将其与
    simdgroups_per_threadgroup
    的实际值进行比较。如果匹配,那就太好了,运行内核的其余部分。
  3. 如果匹配,则返回device参数内存缓冲区中的反馈/错误报告变量/字段中的
    实际
    SIMD大小。然后提前退出计算内核。
  4. 在主机端,通过
    device
    内存中的状态检查计算内核是否提前退出。如果是这样,请检查报告的 SIMD 组大小,调整缓冲区分配,然后使用新值重新运行内核。

对于真正偏执的人来说,明智的做法是在步骤 2 中进行检查,将其设置为下限或上限,或者可能是一个范围,而不是相等性检查:例如,分配的内存对于 SIMD 组大小最多是安全的来自 N 个线程。这样,如果线程组缓冲区分配应该 change

simdgroups_per_threadgroup
(😱),你最终不会在值之间来回跳跃,没有任何进展。

还要注意您在 SIMD 组中所做的操作:并非所有 GPU 型号都支持 SIMD 组缩减功能,即使它们支持 SIMD 排列,因此如有必要,请为此类旧 GPU 提供替代版本的内核。

最后,我发现大多数 GPU 报告的 SIMD 组大小为 32 个线程,但 2015 年 MacBook Pro 的 Intel Iris Graphics 6100 报告

simdgroups_per_threadgroup
(和
threadExecutionWidth
)值为 8。(事实并非如此)不支持 SIMD 缩减函数,但支持 SIMD 排列函数,包括
simd_ballot()
,它几乎与某些算法的缩减一样有效。)

© www.soinside.com 2019 - 2024. All rights reserved.