執行摘要: 如何在代碼中指定OpenMP應該只爲線程使用REAL內核,即不計算超線程內核?超線程......讓我的渲染器慢了10倍
詳細分析:多年來,我在空閒時間編寫了一個僅限SW的開源渲染器(rasterizer/raytracer)。 GPL代碼和Windows二進制文件可從這裏獲得: https://www.thanassis.space/renderer.html 它在Windows,Linux,OS/X和BSD下編譯並運行良好。
我上個月介紹了一種光線跟蹤模式 - 生成的圖片質量天空搖滾。不幸的是,光線跟蹤比光柵化要慢幾個數量級。爲了提高速度,就像我爲光柵掃描儀所做的那樣,我將OpenMP(和TBB)支持添加到了光線跟蹤器中 - 以便輕鬆使用更多的CPU內核。光柵化和光線追蹤都很容易進行線程化(按三角形工作 - 每像素工作)。
在家裏,用我的Core2Duo,第二個核心幫助了所有模式 - 光柵化和光線追蹤模式的速度都在1.85x和1.9x之間。
問題:當然,我很好奇,想看看上面的CPU性能(我也「玩」的GPU,preliminary CUDA port),所以我想爲比較堅實的基礎。我將代碼交給了我的一個好朋友,他可以使用一臺16核1500美元的英特爾超級處理器的「野獸」機器。
他經營着它的「最重」模式,光線跟蹤模式...
......他得到五分之一我的酷睿2
喘氣的速度(!) - 恐怖。剛剛發生了什麼?
我們開始嘗試不同的修改,修補程序......並最終找出結果。
通過使用OMP_NUM_THREADS環境變量,可以控制產生了多少OpenMP線程。當線程數量從1增加到8時,速度在增加(接近線性增加)。 當我們越過8時,速度開始減弱,直到它降低到Core2Duo速度的五分之一時,所有16個內核都被使用了!
爲什麼8?
因爲8是real內核的編號。其他8個是......超線程的!
理論:現在,這是我的新聞 - 我已經看到其他算法中的超線程幫助很多(高達25%),所以這是意想不到的。顯然,即使每個超線程核心都帶有自己的寄存器(和SSE單元?),光線跟蹤器也無法利用額外的處理能力。這導致我想...
它可能不是處理能力是餓死 - 它是內存帶寬。
raytracer使用邊界卷層次結構數據結構來加速光線三角形相交。如果使用超線程核心,則一對中的每個「邏輯核心」試圖從該數據結構中的不同位置讀取(即,在內存中) - 並且CPU緩存(本地每對)完全被破壞。至少,這是我的理論 - 任何建議最受歡迎。
因此,問題: OpenMP檢測「核心」的數量併產生線程以匹配它 - 也就是說,它包含計算中的超線程「核心」。就我而言,這顯然會導致災難性的結果,速度明智。有誰知道如何使用OpenMP API(如果可能的話,可攜帶)只爲REAL核心產生線程,而不是超線程的線程?
P.S.代碼是開放的(GPL),可以在上面的鏈接中找到,隨時在自己的機器上重現 - 我猜這會發生在所有超線程CPU上。
P.P.S.請原諒這篇文章的長度,我認爲這是一種教育體驗,並希望分享。
這篇文章有一些有用的答案。 「http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine」 – Dan 2011-01-27 15:09:07
不幸的是,這些並沒有多大幫助 - 它們都報告了一個數字,其中包括超線程「核」 ...... – ttsiodras 2011-01-27 18:33:50
我發現'超線程'可能是很多應用程序的垃圾。在許多情況下,我已經關閉了它(在BIOS中),因爲應用程序不再運行或性能變差。這不僅僅是英特爾(也看到了它的實力)。 – Marm0t 2011-01-27 18:40:56