0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

OpenMPとMicrosoft PPLとParallel STLを比較してみる(その2)

Last updated at Posted at 2020-08-19

はじめに

前回の記事
OpenMPとMicrosoft PPLとParallel STLを比較してみる(その1)
にてMicrosoft PPLがSequentialよりも遅かったので、パフォーマンスを改善してベンチマークを行いました。ベンチマークにはgoogle benchmarkを使用しました。
コードはshohirose/openmp-examples/benchmarkにあげてあります。

コード解説

前回の記事のコードをベンチマークしやすいようにリファクタリングしたものを使っています。

parallel_benchmark.cpp
# include <benchmark/benchmark.h>

# include "function.hpp"

using namespace shirose;

std::vector<Point>& getPoints() {
  static std::vector<Point> points = generatePoints(10'000'000);
  return points;
}

template <typename Counter>
void BM_PiCalculation(benchmark::State& state) {
  const auto& points = getPoints();
  for (auto _ : state) {
    const auto numPoints = state.range(0);
    const auto pi = calcPi(points.data(), numPoints, Counter{});
    benchmark::DoNotOptimize(pi);
  }
}

BENCHMARK_TEMPLATE(BM_PiCalculation, SequentialSTLCounter)
    ->RangeMultiplier(4)
    ->Range(1 << 10, 1 << 22);

BENCHMARK_TEMPLATE(BM_PiCalculation, OpenMPCounter)
    ->RangeMultiplier(4)
    ->Range(1 << 10, 1 << 22);

BENCHMARK_TEMPLATE(BM_PiCalculation, MicrosoftPPLCounter)
    ->RangeMultiplier(4)
    ->Range(1 << 10, 1 << 22);

BENCHMARK_TEMPLATE(BM_PiCalculation, ChunkedMicrosoftPPLCounter)
    ->RangeMultiplier(4)
    ->Range(1 << 10, 1 << 22);

BENCHMARK_TEMPLATE(BM_PiCalculation, ParallelSTLCounter)
    ->RangeMultiplier(4)
    ->Range(1 << 10, 1 << 22);

BENCHMARK_TEMPLATE(BM_PiCalculation, ParallelOrVectorizedSTLCounter)
    ->RangeMultiplier(4)
    ->Range(1 << 10, 1 << 22);

BENCHMARK_MAIN();

ParallelSTLCounterstd::execution::parを使い、ParallelOrVectorizedSTLCounterstd::execution::par_unseqを使っています。ChunkedMicrosoftPPLCounterは自分で範囲を分割してconcurrency::parallel_for内でforループを回しています。

各クラスの詳細はファイルを直接みてもらうものとして、google benchmarkに係る部分について解説します。
まず点をランダムに生成するgeneratePointsは重い処理なので、ベンチマーク開始のときにgetPoints関数内で十分な数を一度だけ生成してしまいます。各ベンチマークではその点列を使って円周率を計算しています。ベンチマーク関数内に初期化処理を記載するとベンチマークを実行するたびに初期化処理が行われ、ベンチマーク全体が非常に遅くなるため、それを避けるためにベンチマーク外で初期化を行っています。

結果

データサイズとCPU時間

cputime.png

Core i7 9700K(8コア)を使っているので、コア当たりのデータサイズに対してCPU時間をプロットしました(Sequentialは1スレッドですが比較のため合わせています)。
データサイズが小さいと計算時間はOpenMP<Chunked Microsoft PPL<Sequential STL<Parallel STLs<Microsoft PPLの順ですが、ある程度データサイズが大きくなるとOpenMP=Chunked Microsoft PPL=Parallel STLs<Sequential STL<Microsoft PPLとなりました。Core i7 9700KのL2キャッシュが256KB(コア当たり)なので、図1の128~512KBの間の屈曲はL2キャッシュを超えてしまったことが原因と考えています。

データサイズと速度向上率

speedup-ratio.png

上図は同じデータサイズのSequentialに対する速度向上率を示しています。
データサイズが小さい(512KB未満)ではOpenMPが最も早く、次にマニュアル調整したChunked Microsoft PPLが続きました。データサイズが大きくなるとSTLもOpenMPとChunked Microsoft PPLとほぼ同程度の速度が出ています。小さなループではOpenMPが非常に強いですね…

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?