Visual C++ 終於正式支援 OpenMP 3 的 task 了

| | 0 Comments| 13:42
Categories:

微軟的 Visual C++ 這幾年雖然對於 C++ 新的標準支援的算是相當積極,但是對於 OpenMP 的支援一直以來都很糟糕,儘管官方標準已經更新到 OpenMP 5.2 了,但是直到推出 Visual Studio 2019 的時候,卻還停留在 OpenMP 2.0 的超古老版本…

直到之前在 Visual Studio 2019 16.9 的時候,才終於試著開始幫 Visual C++ 的 OpenMP 加上新功能;當時主要的改進,是加入了 OpenMP 對於 SIMD 的支援,另外也開始試著要將 OpenMP 的實作切換到 LLVM 的版本。

而這次微軟又發布了《OpenMP Task Support for C++ in Visual Studio》,在最新的 Visual Studio 2022 17.2(還在預覽階段)中,在使用 LLVM OpenMP(加上 -openmp:llvm)的情況下,終於支援 OpenMP 3 的 task 這個 directive 了!

不過其實要說終於支援,其實之前 16.9 的時候就可以了,只是過當時還是實驗性質、還要加上 -openmp:experimental 就是了。(話說,-openmp:llvm 現在也還是不在專案設定的介面裡、而是要手動加啊…)

基本上,OpenMP 的 tasksection 其實有點像,都算是將不同的工作分給不同的 thread 去做。

下面就是一個簡單的例子(來源):

#include <iostream>
#include <omp.h>
 
 
int fib(int n)
{
  int i, j;
  if (n < 2)
    return n;
  else
  {
    #pragma omp task shared(i) firstprivate(n)
    i = fib(n - 1);
    
    #pragma omp task shared(j) firstprivate(n)
    j = fib(n - 2);
 
    #pragma omp taskwait
    return i + j;
  }
}
 
int main()
{
  int n = 20;
 
  #pragma omp parallel shared(n)
  {
    #pragma omp single
    std::cout << "fib(" << n << ") = " << fib(n) << std::endl;
  }
}

這是一個透過 OpenMP 的 task 來計算費波那契數(Fibonacci Numbers、F(n) = F(n-1) + F(n-2))的小程式,他會用遞迴的形式去呼叫 fib() 這個函式,

而在 fib(n) 中,則會把 fib(n-1)fib(n-2) 分成兩個 task、然後透過 taskwait 等兩個 task 都結束後,再將兩者的答案加起來。

這邊算是一個很簡單的例子,但是實際上…由於每個次呼叫都會分成兩個 task,然後又不是真的要計算什麼,所以其實透過上面這種平行化的方法來跑,反而會比直接跑更慢就是了。 XD

而如果想要用 LLVM OpenMP 的 task 的話也要注意,目前他僅支援 OpenMP 3.1 的標準,之後版本加上的功能並不支援。


老實說,在目前的 C++ 標準來說,個人覺得 OpenMP 比較實用的,好像還是 parallel for 這種 data-parallel 的狀況,task parallel 的情境其實有許多其他工具感覺還比較方便。

而以這個觀點來看,LLVM OpenMP 比較大的好處,是他讓 MSVC 終於可以用 unsigned 的型別來做為迴圈的索引值了!

#pragma omp parallel for
for (unsigned int i = 0; i < n; i++)
{
  c[i] = a[i] + b[i];
}

在以往 MSVC 的環境,上面的程式要編譯的時候,都是會出錯而無法完成編譯的。而錯誤的內容,就是:

C3016    'i': OpenMP 'for' 陳述式中的索引變數必須具有帶正負號的整數類資料類型

在現在陣列越來越大,甚至會需要用 size_t 作為陣列大小的現在,他還強制要用 int 作為索引,其實是件很吐血的事…

而在改用 LLVM OpenMP 後,至少算是把這個問題解決了,對於更大的資料,也能更好地作處理了!


理論上,Visual Studio 2022 17.2 算是終於支援完整的 OpenMP 2.5(2005 年發布的版本…)了;而除了標準的 OpenMP 2.5 外,也支援了 OpenMP 3.1 的 task、以及在 parallel for 使用無號索引值(unsigned indices)。

而微軟目前的目標,則是要透過 LLVM 的 OpenMP runtime 慢慢地完成 OpenMP 3.1 的標準(2011 發布的版本…)。

至於會不會有哪一天終於能支援 OpenMP 4.0 以後的 GPGPU 呢?恩,慢慢等。

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *