tts*_*ras 18 rendering renderer openmp hyperthreading slowdown
执行摘要:如何在代码中指定OpenMP应该只为REAL内核使用线程,即不计算超线程的线程?
详细分析:多年来,我在空闲时间编写了一个仅限SW的开源渲染器(光栅化器/光线跟踪器).可以从这里获得GPL代码和Windows二进制文件:https: //www.thanassis.space/renderer.html 它在Windows,Linux,OS/X和BSD下编译并运行良好.
我上个月推出了一种光线追踪模式 - 生成的图片质量飙升.不幸的是,光线跟踪比光栅化要慢几个数量级.为了提高速度,就像我对光栅化器一样,我为光线跟踪器添加了OpenMP(和TBB)支持 - 以便轻松利用额外的CPU内核.光栅化和光线跟踪都很容易进行线程化(每个三角形工作 - 每像素工作).
在家里,凭借我的Core2Duo,第二核心帮助了所有模式 - 光栅化和光线跟踪模式的加速都在1.85x和1.9x之间.
问题:当然,我很想看到CPU的最高性能(我也玩"GPU",初步的CUDA端口),所以我想要一个坚实的基础进行比较.我把代码交给了我的一个好朋友,他可以使用16英寸,1500美元英特尔超级处理器的"野兽"机器.
他以"最重"模式运行它,光线跟踪模式......
......他的速度是我的Core2Duo的五分之一(!)
喘气 - 恐怖.刚刚发生了什么?
我们开始尝试不同的修改,补丁,......最终我们弄明白了.
通过使用OMP_NUM_THREADS环境变量,可以控制生成的OpenMP线程数.随着线程数从1增加到8,速度增加(接近线性增加).在我们越过8的那一刻,速度开始减弱,直到我的Core2Duo速度的五分之一,当使用所有16个核心时!
为什么8?
因为8是真实核心的数量.其他8个是...超线程的!
理论:现在,这对我来说是新闻 - 我看到超线程在其他算法中帮助很多(高达25%),所以这是出乎意料的.显然,即使每个超线程核心都有自己的寄存器(和SSE单元?),光线跟踪器也无法利用额外的处理能力.这引导我思考......
它可能不是缺乏处理能力 - 它是内存带宽.
光线跟踪器使用边界体积层次结构数据结构来加速光线三角形交叉.如果使用的芯超线程,则每个在一对"逻辑核"的,试图从在该数据结构不同的地方(即,在存储器中),以读 - 和CPU高速缓存(每对本地)完全捶打.至少,这是我的理论 - 任何建议都是最受欢迎的.
所以,问题是: OpenMP检测"核心"的数量并产生与之匹配的线程 - 也就是说,它包括计算中的超线程"核心".就我而言,这显然会导致灾难性的结果,速度方面.有谁知道如何使用OpenMP API(如果可能的话,可移植)只为REAL内核生成线程,而不是超线程的线程?
PS代码是开放的(GPL),可在上面的链接中找到,随时可以在您自己的机器上重现 - 我猜这将在所有超线程CPU中发生.
PPS原谅帖子的长度,我认为这是一种教育经历,想分享.