簡體   English   中英

OpenMP 數組初始化影響

[英]OpenMP array initialization impact

我在陣列(工作部分)上與 OpenMP 並行工作。 如果我之前並行初始化數組,那么我的工作部分需要 18 毫秒。 如果我在沒有 OpenMP 的情況下串行初始化數組,那么我的工作部分需要 58 毫秒。 是什么導致性能變差?

系統:

  • Intel(R) Xeon(R) CPU E5-2697 v3(28 核/56 線程,2 個插槽)

示例代碼:

unsigned long sum = 0;
long* array = (long*)malloc(sizeof(long) * 160000000);

// Initialisation
#pragma omp parallel for num_threads(56) schedule(static)
for(unsigned int i = 0; i < array_length; i++){
    array[i]= i%10;
}


// Time start

// Work
#pragma omp parallel for num_threads(56) shared(array, 160000000) reduction(+: sum)
for (unsigned long i = 0; i < array_length; i++)
{
    if (array[i] < 4)
    {
        sum += array[i];
    }
}

// Time End

這里有兩個方面在起作用:

NUMA分配

在 NUMA 系統中,memory 頁可以是 CPU 的本地頁面或遠程頁面。 默認情況下,Linux 在首次接觸策略中分配 memory,這意味着對 memory 頁面的首次寫入訪問決定了該頁面物理分配在哪個節點上。

如果您的 malloc 足夠大,操作系統會請求新的 memory(而不是重新使用現有的堆內存),那么第一次接觸將在初始化時發生。 因為您為 OpenMP 使用 static 調度,所以同一個線程將使用初始化它的 memory。 因此,除非線程遷移到不同的 CPU(這不太可能),否則 memory 將是本地的。

如果不並行初始化,memory 將在主線程本地結束,這對於位於不同 sockets 上的線程來說更糟。

請注意,Windows 不使用首次接觸政策 (AFAIK)。 所以這種行為是不可移植的。

緩存

同上也適用於緩存。 初始化會將數組元素放入 CPU 的緩存中。 如果同一個 CPU 在第二階段訪問 memory,則它會處於緩存熱狀態並准備好使用。

首先,@Homer512 的解釋是完全正確的。

現在我注意到您將此問題標記為“C++”,但您正在為數組使用malloc 這在 C++ 中是糟糕的風格:你應該為你的簡單容器使用std::vector ,為足夠小的容器使用std::array

然后你會遇到一個大問題,因為std::vector使用“值初始化”:整個數組自動填充零,你無法讓它與 OpenMP 並行完成。

這是一個大技巧:

template<typename T> 
struct uninitialized {
  uninitialized() {};
  T val;
  constexpr operator T() const {return val;};
  double operator=( const T&& v ) { val = v; return val; };
};

vector<uninitialized<double>> x(N),y(N);

#pragma omp parallel for 
for (int i=0; i<N; i++)
  y[i] = x[i] = 0.; 
x[0] = 0; x[N-1] = 1.;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM