2014-07-21 47 views
1

的Linux的perf和GPerfTools優化C代碼pprof給了我很多停滯前端和後端的週期在這段代碼:有很多非關聯

for(j = oL; j < oR; j++) { 
    T[j].v = (T[j].x/div)*K+T[j].y /div; 
    T[j].x = T[j].x % div; 
    T[j].y = T[j].y % div;   
    counterK[T[j].k]++; 
    } 

給我:

9.973.660.617 stalled-cycles-frontend # 42,16% frontend cycles idle 
4.874.722.502 stalled-cycles-backend # 20,60% backend cycles idle 

我明白停滯週期意味着指令流水線不能真正前進,等待(也許)內存中的某些數據。我可以看到,在這段代碼中有很多解除引用的構件,這可能是一個問題,但是我擔心我缺乏足夠的知識來查看那裏的任何優化。誰能幫忙?

+0

我不認爲這是導致問題的結構。我很確定它在全國各地都使用T [j]。如果您使用了'struct * temp =&T [j]'並且使用了'temp->',您可能會看到更好的結果。 –

+1

由於.x和.y被修改並作爲表達式的輸入被使用,並且不清楚'counterK'是否可以替代'T',因此不可能重新排序加載和存儲(或將值緩存在寄存器中)再加上劃分和模數是相當昂貴的操作(~20個週期)。當然,正式創建了很多臨時文件,因此該結構中的類型最好是POD,或者多次複製它們。 – Damon

+0

可能是索姆非常小的東西:使用++ var;而不是var ++;預增量更快,因爲它不會創建一個臨時變量,我同意拉馬先生。如果變量「div」是2的冪,那麼你也可以做一個好的。不幸的是,分工很慢。 – Strigidis

回答

1

解除引用struct指針本身不應該成爲現代架構中的問題。他們可以進行相對處理,並且可以很好地處理這些訪問。另外一個評論中提到的鋸齒也不應該是一個問題。 *T*counterK有不同的類型,所以C永遠不會假設它們是別名。

通常,對於您向我們顯示的處理器/內存帶寬而言,這樣的循環通常是處理器而不是處理器的速度。所以可能是,你只是處於記憶能夠服務的極限。

您按順序訪問T,這已經是您可以爲之做的最好的選擇。對於T,唯一可能的優化方式是您有很多字段不被您向我們顯示的循環使用。那麼你可能會浪費處理器/內存帶寬。然後壓縮只包含所需信息的數組中的東西可能會有所幫助。

對於counterK事情比較複雜,因爲您給出的信息沒有提示訪問模式或數組大小。如果counterK很大(比L1緩存大得多),並且訪問非常不規則,則攤位可能來自此處。

+0

我嘗試瞭解引用,它現在下降了半秒,前端降低了1%(從42%降低到41%),後端降低了3%(從20%降到17%)...但是這些在這一點上是微觀優化... –