multithreading - 本地和全局大小对程序执行的影响 - OpenCl

标签 multithreading parallel-processing opencl

在阅读了大量有关全局工作规模和本地工作规模的定义后,我仍然不太明白它们是什么以及它们如何工作。 我认为全局工作大小决定了内核函数将被调用多少次,但是本地工作大小?

我认为本地工作大小决定了同时并行使用多少个线程,但我真的正确吗?

本地大小是否是每个全局大小值执行一个内核程序的线程数?我的意思是,当我们的全局大小 = 1 且局部大小 = 1 时,内核函数将被调用一次,并且只有一个线程将对其进行处理。 但是当我们的全局大小 = 4096 且本地大小(如果允许这么高)为 1024 时,我们有 4096 次内核函数调用,并且每次调用有 1024 个线程同时处理?我说得对吗?

这是我找到的一些示例代码: enter image description here

我的另一个问题是:局部大小的变化如何影响该代码? 正如我所见,它显然适用于 global_id,没有本地 ID,因此本地大小更改为比 1 更大的值是否会影响执行该算法所花费的时间?

当我们在该算法中使用 for 循环时,它是否会改变有关局部大小影响的任何内容?更改本地大小时我们是否需要使用 local_id 才能看到任何差异?

我在我的几个程序上进行了测试,即使我只使用 global_id 不断变化的本地工作大小,也能显着缩短执行时间。 那么它是怎样工作的?我不明白。

提前谢谢您!

最佳答案

I thought that local work size determine how many threads are gonna be used in the same time in parallel, but am I really correct?

正确,但它是针对每个计算单元的,而不是整个设备。如果计算单元多于本地线程组,则设备未得到充分使用。当线程组的数量多于计算单元但不是精确的倍数时,某些计算单元会在最后等待其他计算单元。当两个值相等(或精确倍数)时,“多少次”对于完全占用所有 ALUS 很重要。

例如,8 核 cpu 可以定义 8 个计算单元(如果使用硬件多线程,可能会增加 8 个计算单元)。但价格相近的 GPU 可以有 20 到 64 个计算单元。然后,即使在单个计算单元内,许多线程组也可以“运行中”,这不会被显式调整,而是会根据每个线程、每个计算单元甚至每个 GPU 的资源使用情况进行更改。

how local size change influence that code? As i see it is clearly working on global_id's, no local one's so is local size change to bigger one than lets say 1 will influence time spent executing that algorithm?

可矢量化/可并行化的内核代码可以具有将线程分配给 ALU、核心的 SIMD 或更广泛的 GPU 计算单元的 SIMD 的优势。对于CPU来说,可以同时发出8条标量指令。对于 GPU 来说,它可能有数千个。因此,当您将本地大小减少到 1 时,您将并行线程问题的宽度限制为 1 ALU,这会削弱许多体系结构的性能。当本地大小太大时,每个线程的资源会下降并且性能会受到影响。如果您不知道,如果您为其参数指定 null,opencl api 可以为您调整本地大小。

And when we would have for loop in that algorithm, is it changing anything then regarding local size influence? Do we need to use local_id's to see any difference when changing local size?

对于旧的静态调度架构,建议循环展开,其展开步长等于基本 SIMD 宽度的宽度。不,本地 id 只是对其计算单元中的线程 id 的查询,因此如果不需要,则无需查询。

I tested that on few of my programs, and even when I used only global_id's changing local work size gave me significantly shorter executing times. So how does it work?

如果内核需要大量资源,您可以考虑每个本地组 1 个线程。如果内核除了立即值之外不需要任何资源,则应该将其设置为最大本地值。每个线程的资源分配(由于内核代码)很重要。新的架构具有负载平衡功能,因此将来如果让 api 选择最佳值可能并不重要。

为了保持所有 ALU 忙碌,调度程序为每个核心发出许多线程,当一个线程等待内存操作时,另一个线程可以同时执行 ALU 操作。当资源使用量较小时,这很好。当您使用计算单元所有资源的 %50 时,它只能有 2 个正在运行的线程。线程共享L1缓存、本地内存、寄存器文件等可共享资源。

诸如 c[i]=a[i]+b[i] 之类的标量 float 代码是可向量化的。如果编译器尚未在后台执行此操作,则使用 float8、float16 和类似结构可以获得更好的性能。这样,它需要更少的线程来完成所有工作,并且对内存的访问速度更快。您还可以在内核中添加一个循环来进一步减少线程数量,这对 CPU 有利,因为 2 个数据 block 之间需要更少的线程调度。对于 GPU 来说,这可能并不重要。


CPU 的简单示例:

4 个核心,本地大小 = 10,全局大小 = 100

核心 1 和核心 2 各有 3 个线程组。核心 3 和 4 只有 2 个线程组。

  • 1:30 个线程 --> 完全性能
  • 2:30 个线程
  • 3:20 个线程 --> 性能较低,但可以更好地抢占其他作业
  • 4:20 个线程

虽然核心 1 和 2 的指令流水线没有太多气泡,但核心 3 和 4 的气泡在一段时间后开始,因此它们可以用于其他作业,例如并行运行的第二个内核或操作系统或某些阵列复制。当您平等地使用所有核心(例如 120 个线程)时,它们每秒完成更多工作,但如果内核已经使用内存,CPU 无法执行数组复制。(除非操作系统抢占其他线程)

关于multithreading - 本地和全局大小对程序执行的影响 - OpenCl,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41826953/

相关文章:

java - 使用 Stream 从 BufferedReader 读取行

java - 将包含 size_t 的结构从 Java 传递到 OpenCL

android - 在纯服务应用程序中使用 SpeechRecognizer。在主线程上运行代码

java - 第二个 AsyncTask 没有执行

c++ - C++ 中的 Winsock 服务器在三个客户端后拒绝连接

c# - 使用 Parallel.ForEach (多线程)从列表中获取总和为值的元素数组

java - “Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1;”-使用@Scheduled方法调用删除时

c++ - 独立于平台的 C++ 并发编程库

multithreading - 如何在多核上编译 OpenCL 程序?

Linux QT OpenCL 基本设置