忍者ブログ
  • 2019.07
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 2019.09
C++17でモンテカルロを並列化してみた。(GNU Version)
C++17でモンテカルロを並列化してみた。に触発されて、GNU版で作ってみました
■コンパイル
$ g++ test.cc -Wall -march=native -std=c++17 -O3  -fopenmp
■ソース
#include <parallel/algorithm>
//#include <execution>
#include <atomic>
#include <mutex>
#include <iostream>
#include <random>
#include <array>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    static int const NUM = 1000000000;
    static int threads = 8;
    static_assert(std::atomic<int>::is_always_lock_free);
    if (argc >= 2)
    {
        threads = atoi(argv[1]);
    }
    auto nums = std::vector<int>(threads);
    for (auto &num : nums)
    {
        num = NUM / threads;
    }
    __gnu_parallel::_Settings s;
    s.algorithm_strategy = __gnu_parallel::force_parallel;
    __gnu_parallel::_Settings::set(s);

    std::atomic counter = {0};

    __gnu_parallel::for_each(nums.begin(), nums.end(), [&counter](int num) {
        std::random_device rnd;
        thread_local std::mt19937 mt(rand());
         std::uniform_real_distribution<double> score(0.0, 1.0);
        for (auto &&no = 0; no < num; ++no)
        {
            auto &&x = score(mt);
            auto &&y = score(mt);
            if ((x * x + y * y) < 1.0)
            {
                counter++;
            }
        }
    });

    std::cout << "PI = " << 4.0 * counter / NUM << std::endl;
}
■結果
$ time ./a.out 1
PI = 3.14155

real	0m27.461s
user	0m27.469s
sys	0m0.001s
$ time ./a.out 2
PI = 3.14159

real	0m29.238s
user	0m58.008s
sys	0m0.016s
$ time ./a.out 3
PI = 3.14151

real	0m28.447s
user	1m24.458s
sys	0m0.000s
$ time ./a.out 4
PI = 3.14155

real	0m32.101s
user	2m5.238s
sys	0m0.020s

なぜか延べ時間(user)が増えるだけでreal時間が減りません。。。
そこでソースを修正してみました。
■ソース修正後
#include <parallel/algorithm>
//#include <execution>
#include <atomic>
#include <mutex>
#include <iostream>
#include <random>
#include <array>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    static int const NUM = 1000000000;
    static int threads = 8;
    static_assert(std::atomic<int>::is_always_lock_free);
    if (argc >= 2)
    {
        threads = atoi(argv[1]);
    }
    auto nums = std::vector<int>(threads);
    for (auto &num : nums)
    {
        num = NUM / threads;
    }
    __gnu_parallel::_Settings s;
    s.algorithm_strategy = __gnu_parallel::force_parallel;
    __gnu_parallel::_Settings::set(s);

    std::atomic counter = {0};

    __gnu_parallel::for_each(nums.begin(), nums.end(), [&counter](int num) {
        std::random_device rnd;
        thread_local std::mt19937 mt(rand());
        int _counter = 0;
        std::uniform_real_distribution<double> score(0.0, 1.0);
        for (auto &&no = 0; no < num; ++no)
        {
            auto &&x = score(mt);
            auto &&y = score(mt);
            if ((x * x + y * y) < 1.0)
            {
                _counter++;
            }
        }
        counter += _counter;
    });

    std::cout << "PI = " << 4.0 * counter / NUM << std::endl;
}

■結果
$ time ./a.out 1
PI = 3.14155

real	0m20.263s
user	0m20.255s
sys	0m0.000s
$ time ./a.out 2
PI = 3.14159

real	0m10.117s
user	0m20.223s
sys	0m0.000s
$ time ./a.out 3
PI = 3.14151

real	0m7.409s
user	0m22.209s
sys	0m0.000s
$ time ./a.out 4
PI = 3.14155

real	0m6.129s
user	0m24.492s
sys	0m0.001s
core4個分で20秒から6秒にその後、8個に増やしても増えませんでした。。。
なかなかのパフォーマンスなり。
PR
【2019/05/01 17:11 】 | 未選択 | 有り難いご意見(1)
                                    
<<超万能なsorted | ホーム | SECCON令和に参加してみました>>
有り難いご意見
無題
nwpfhさん

早速、参考にさせて頂きました(⌒⌒;

atomicの処理分だけ減ってる感じです。
【2019/05/01 19:55】| URL | ゼンガイチ #9b127fad8d [ 編集 ]


貴重なご意見の投稿














<<前ページ | ホーム | 次ページ>>