OpenCL在CPU上的实现
《OpenCL异构计算》 chapter 6 读书笔记
这一节是第6章的第一部分。讲述了 OpenCL 在 AMD Phenom II X6 处理器上的实现。
设计目标是使得 OpenCL 代码以统一的方式在 AMD CPU 和 GPU 执行。
主要讲了 4 个方面的内容:
- 如何 mapping OpenCL kernel 到 CPU core 上面? host 代码在哪里执行?
- 如何实现 barrier 同步功能?
- 如何实现向量类型及其操作?
- 如何 mapping 各种 OpenCL device memory 到 CPU memory hierarchy?
在主机端,OpenCL 运行时像操作系统和其他应用程序一样在 X86 CPU 上允许。
在设备端,通过 OpenCL 运行时队列机制,使 OpenCL C 代码可以在 X86 设备上编译和运行。
该CPU 体系结构如下图所示:
OpenCL 到 该处理器的映射如下图所示:
Note that the host runs on the same cores that represent the OpenCL device’s compute units.
将整个 CPU 看作一个单独的设备。不同的核作为不同的 Compute Unit 。不过可以通过设备拆分技术将 CPU 拆分成多个设备(在第7章讨论)。
The OpenCL CPU runtime creates a thread to execute on each core of the CPU as a work pool to process OpenCL kernels as they are generated. These threads are passed work by a core management thread for each queue that has the role of removing the first entry from the queue and setting up work for the worker threads. Any given OpenCL kernel may comprise thousands of workgroups for which arguments must be appropriately prepared, memory allocated, and, if necessary, initialized and
work queues generated.
以上是讲了 OpenCL kernel 如何映射到 CPU 的各个 core 上面去。接下来讲,如何实现同步功能。
OpenCL 利用 barrier 和 fence 来实现细粒度的同步。但OS负责管理线程通信,线程与操作系统交互带来的开销阻碍高效并行扩展的实现。除此之外,在多个核上运行一个单独的 work-group 会导致 cache-sharing 问题。
针对以上问题的解决方案是:
OpenCL CPU 运行时在一个系统线程上运行一个 work-group 。 OpenCL 线程轮流运行同一个 work-group 内的每一个 work-item ,当这个 work-group 内的所有 work-item 全部运行完成后,再运行同一个工作队列中的下一个 work-group 。 因此,同一个 work-group 内的线程是没有并行性的。如果可能的话,多个系统线程将允许多个 work-group 并行执行。
由于 barrier 同步操作的存在,使得同一个 work-group 中的不同 work-item 可以 并发 执行。出于性能方面的考虑,通过操作系统的线程抢占方式实现 barrier 操作是不行的。在 AMD OpenCL 运行时中,barrier 操作是通过 setjmp 和 longjmp 函数 (AMD 自己的版本)实现。
OpenCL 利用 barrier 和 fence 来实现细粒度的同步。但OS负责管理线程通信,线程与操作系统交互带来的开销阻碍高效并行扩展的实现。除此之外,在多个核上运行一个单独的 work-group 会导致 cache-sharing 问题。
针对以上问题的解决方案是:
OpenCL CPU 运行时在一个系统线程上运行一个 work-group 。 OpenCL 线程轮流运行同一个 work-group 内的每一个 work-item ,当这个 work-group 内的所有 work-item 全部运行完成后,再运行同一个工作队列中的下一个 work-group 。 因此,同一个 work-group 内的线程是没有并行性的。如果可能的话,多个系统线程将允许多个 work-group 并行执行。
由于 barrier 同步操作的存在,使得同一个 work-group 中的不同 work-item 可以 并发 执行。出于性能方面的考虑,通过操作系统的线程抢占方式实现 barrier 操作是不行的。在 AMD OpenCL 运行时中,barrier 操作是通过 setjmp 和 longjmp 函数 (AMD 自己的版本)实现。
讲完如何实现 barrier 同步后,接着讲如何实现 OpenCL C 的各种向量类型及其操作。主要是通过 SSE 指令扩展来实现。向量类型存储在向量寄存器中,对向量的操作编译成 SSE 指令。
最后谈到了如何把 OpenCL Device Memory 映射到 CPU cache 上。下图进行了说明:
为改进 cache 本地化,本地内存区域以每个 CPU 线程一个数组的方式进行分配,并且可被这个线程执行的所有的 work-group 重用。存储在寄存器中的 work-item 的局部数据会在调用 setjmp 函数时被备份到主存的 work-item 栈中。This memory is carefully laid out to behave well in the cache, reducing cache contention and hence conflict misses and improving the utilization of the cache hierarchy. In particular, the work item stack data is staggered in memory to reduce the chance of conflicts, and data is maintained in large pages to ensure contiguous mapping to physical memory and to reduce pressure on the CPU’s translation lookaside buffer。
No comments:
Post a Comment