簡體   English   中英

STL 並行執行與 OpenMP 性能

[英]STL parallel execution vs. OpenMP performance

我正在開始一個新項目,並希望並行化一些計算。 我過去使用過 OpenMP,但我知道現在可以直接並行化許多 STL 算法。 由於這兩種方法都遵循不同的范例(例如原始循環與迭代器和匿名函數),我想預先選擇一種。

一般哪個更快?

為了對此進行測試,我對以下 C++20 代碼進行了基准測試:

#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
#include <cmath>
#include <chrono>
#include <execution>

template <class ExecutionPolicy>
int test_stl(const std::vector<double>& X, ExecutionPolicy policy) {
    std::vector<double> Y(X.size());
    const auto start = std::chrono::high_resolution_clock::now();
    std::transform(policy, X.cbegin(), X.cend(), Y.begin(), [](double x){
        volatile double y = std::sin(x);
        return y;
    });
    const auto stop = std::chrono::high_resolution_clock::now();
    auto diff = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
    return diff.count();
}

int test_openmp(const std::vector<double>& X) {
    std::vector<double> Y(X.size());
    const auto start = std::chrono::high_resolution_clock::now();
#pragma omp parallel for
    for (size_t i = 0; i < X.size(); ++i) {
        volatile double y = std::sin(X[i]);
        Y[i] = y;
    }
    const auto stop = std::chrono::high_resolution_clock::now();
    auto diff = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
    return diff.count();
}

int main() {
    const size_t N = 10000000;
    std::vector<double> data(N);
    std::iota(data.begin(), data.end(), 1);
    std::cout << "OpenMP:        " << test_openmp(data) << std::endl;
    std::cout << "STL seq:       " << test_stl(data, std::execution::seq) << std::endl;
    std::cout << "STL par:       " << test_stl(data, std::execution::par) << std::endl;
    std::cout << "STL par_unseq: " << test_stl(data, std::execution::par_unseq) << std::endl;
    std::cout << "STL unseq:     " << test_stl(data, std::execution::unseq) << std::endl;
    return 0;
}

在我的機器上使用 GCC 10.3.0 (MSYS2) 編譯,OpenMP 代碼的運行速度始終快 10 倍:

OpenMP:        54719
STL seq:       628451
STL par:       638454
STL par_unseq: 494143
STL unseq:     506647

對於功能等效的代碼,OpenMP 通常(啟發式)更快嗎? 考慮到目前的 state 發展,這可能會在未來改變嗎?

編輯:

我正在使用以下CMakeLists.txt構建此基准:

cmake_minimum_required(VERSION 3.19)

add_executable(TEST main.cpp)
target_compile_features(TEST PRIVATE cxx_std_20)
set_target_properties(TEST PROPERTIES CXX_EXTENSIONS OFF)

find_package(OpenMP)
target_link_libraries(TEST PUBLIC OpenMP::OpenMP_CXX)

然后我用 Windows Powershell 命令編譯它:

cmake .. -G "MinGW Makefiles"
mingw32-make
./TEST.exe

我已經在我的 windows 11 機器上使用 MSVC 測試了你的代碼(只是在 openmp 實現中將 size_t 更改為 int),因為我認為讓 almos all stl 以相同的性能並行是非常奇怪的...... seq執行策略不完全執行並行性......並且在你的測試中它的表現非常接近其他執行策略......

所以,我已經編譯了這個:

cl.exe /Zi /EHsc /nologo /std:c++latest /O2 /openmp /Fe: .\openmp-vs-exec-policy.exe .\openmp-vs-exec-policy.cpp

我的結果是:

.\openmp-vs-exec-policy.exe
OpenMP:        14089
STL seq:       99299
STL par:       10659
STL par_unseq: 9811
STL unseq:     68051

在我的另一個測試中,stl 幾乎總是比 openmp 表現更好......

所以,我的猜測是你正在使用的 stl 沒有很好地實現或者 GCC 對於 windows 沒有很好地編譯 stl ...

[編輯]

我一直在尋找 g++ 實現 STL 並行性,發現它只有在安裝了 libtbb 時才有效。

就像 OpenMP 只有在使用-fopenmp編譯時才有效,如果它沒有傳遞給編譯器,一切都會回落到順序,STL 如果你沒有安裝 libtbb,執行策略的實現會回落到順序默認為 g++。

暫無
暫無

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

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