我試圖優化和並行化一些代碼,在圖形結構中用鏈接和節點進行模擬。主熱點是這樣一個循環:我該如何並行化這個解算器代碼
void ExecuteAll()
{
for(long i = TotalCount(); i >= 1; i--)
{
long k = linkOrder[i];
long link = firstLink[k];
if (link == 0)
continue;
double d = 0.;
for(; link != 0; link = nextLink[link])
{
long kk = getNode(link);
d += fak[link]*res[kk];
}
d += res[k];
double d2 = d/fak2[k];
res[k] = d2;
res2[k] += d2;
}
}
我返工這個通過實施這樣的一類具有多線程工作:
class myDemoClass
{
bool volatile *isDone;
public:
void ExecuteSlice()
{
for(long i = TotalCount() - mThreadIndex; i >= 1; i -= threadCount)
{
long k = linkOrder[i];
Execute(k);
}
}
void Execute(long k)
{
long link = firstLink[k];
if (link == 0)
{
isDone[k] = true;
return;
}
double d = 0.;
for(; link != 0; link = nextLink[link])
{
long kk = getNode(link);
for(int x = 0; ! isDone[kk]; x++)
{} // Wait until data is ready. Time too short for sleep or event
d += fak[link]*res[kk];
}
d += res[k];
double d2 = d/fak2[k];
res[k] = d2;
res2[k] += d2;
isDone[k] = true;
}
}
我創建這個類的一個實例爲每個線程哪裏每個線程運行在i
的所有值的切片上。我引入了一個新的數組bool volatile *isDone
,因爲我不能使用非處理節點的結果。我試圖插入一個睡眠或事件,而不是for(;...;){}
循環,但事實證明,等待狀態對此太短。
這似乎工作正常。所有對Execute()的調用中只有10%必須進入等待循環,因爲圖形從起點開始越來越多,並且結果是正確的。
但是,當使用具有8個線程的新代碼時,令人驚訝的是,在8核心XEON機器上沒有可衡量的性能增益(或損失)。我知道這個代碼在緩存失效方面並不是最優的,主要是因爲isDone
和res
是從多個核心寫入和讀取的。但在大多數情況下,解除引用的索引距離彼此很遠。該圖有大約1.000.000個節點和鏈接。
如何提高此代碼的並行度?
線程代碼在哪裏? – Mark
你應該使用互斥或原子compare_and_swap而不是靜音循環(編譯器可能會刪除)。 –
@Mark。線程代碼太大而不能顯示在這裏。但主要是它爲每個CPU啓動一個線程並啓動ExecuteSlice()函數。 @Joel靜音循環未被優化,因爲iSDone被標記爲易失性。 –