4. 何の変哲も無いプログラム
#include <vector>
using namespace std;
forループの処理が重い…
forループの処理が重い…
const int N = 1000000;
vector<MyData> data = /* N要素 */;
for (int i = 0; i < N; ++i) {
process(data[i]);
}
4
5. 何の変哲も無いプログラム
#include <vector>
using namespace std;
forループの処理が重い…
forループの処理が重い…
const int N = 1000000;
そうだ、並列処理しよう
そうだ、並列処理しよう
vector<MyData> data = /* N要素 */;
for (int i = 0; i < N; ++i) {
process(data[i]);
}
5
9. 並列化 powered by C++11
int m = max(thread::hardware_concurrency(), 1u);
vector<thread> worker;
for (int i = 0; i < m; ++i) {
worker.emplace_back([&](int id) {
int r0 = N/m * id + min(N%m, id);
int r1 = N/m * (id+1) + min(N%m, id+1);
for (int j = r0; j < r1; ++j) {
process(data[j]);
}
}, i);
}
for (auto& t : worker) t.join();
9
10. 並列化 powered by C++11
int m = max(thread::hardware_concurrency(), 1u);
プロセッサ数取得
vector<thread> worker;
for (int i = 0; i < m; ++i) {
スレッド生成
worker.emplace_back([&](int id) {
int r0 = N/m * id + min(N%m, id);
int r1 = N/m * (id+1) + min(N%m, id+1);
区間均等分割
for (int j = r0; j < r1; ++j) {
process(data[j]);
}
}, i);
forループ処理
}
スレッド終了待機
for (auto& t : worker) t.join();
10
11. 並列化 powered by C++11
int m = max(thread::hardware_concurrency(), 1u);
vector<thread> worker;
for (int i = 0; i < m; ++i) {
worker.emplace_back([&](int id) {
int r0 = N/m * id + min(N%m, id);
int r1 = N/m * (id+1) + min(N%m, id+1);
for (int j = r0; j < r1; ++j) {
process(data[j]);
}
}, i);
}
for (auto& t : worker) t.join();
並列化のためのコードでなく
並列化のためのコードでなく
ロジック記述に注力したい
ロジック記述に注力したい
11
14. 並列化 powered by OpenMP
// 逐次処理
for (int i = 0; i < N; ++i) {
process(data[i]);
}
// OpenMP並列化
#pragma omp parallel for
for (int i = 0; i < N; ++i) {
process(data[i]);
}
14
15. 並列化 powered by OpenMP
// C++11標準ライブラリによる並列化
int m = max(thread::hardware_concurrency(), 1u);
vector<thread> worker;
for (int i = 0; i < m; ++i) {
worker.emplace_back([&](int id) {
int r0 = N/m * id + min(N%m, id);
int r1 = N/m * (id+1) + min(N%m, id+1);
for (int j = r0; j < r1; ++j) {
process(data[j]);
}
}, i);
}
for (auto& t : worker) t.join();
// OpenMP並列化
#pragma omp parallel for
for (int i = 0; i < N; ++i) {
process(data[i]);
}
どのように並列処理するか?
→ なにを並列処理するか?
手続的(HOW)な記述
→ 宣言的(WHAT)な記述
15
24. Fully automatic parallelization is still a
“pipe dream”
【可算名詞】
〔アヘン吸引者が見るような〕
夢想、幻想
Parallel and Concurrent Programming in Haskell,
O'REILLY, 2013
24
25. Real World Parallel Programming...
ライブラリ/言語拡張を利用した
ライブラリ/言語拡張を利用した
並列処理プログラミングが必要
並列処理プログラミングが必要
マシンレベル並列(分散処理)
プロセスレベル並列
スレッドレベル並列
ベクトルレベル並列(SIMD)
命令レベル並列
25
47. C++並列拡張
N3850 “Working Draft, Technical Specification for
C++ Extensions for Parallelism”
http://isocpp.org/blog/2013/10/trip-report-fall-iso-c-meeting
47
48. C++並列拡張
N3850 “Working Draft, Technical Specification for
C++ Extensions for Parallelism”
並列アルゴリズムのインターフェースを規定
C++標準アルゴリズムを並列実行可能に拡張
(<algorithm>, <numeric>, <memory>ヘッダ)
API設計は Thrust をベースとする
48
49. C++並列拡張
N3850 “Working Draft, Technical Specification for
C++ Extensions for Parallelism”
C++並列ライブラリの広範な実装経験確立が目的
検討用実装:https://github.com/n3554/n3554/
今は std::experimental::parallel 名前空間
→ std 名前空間 への昇格を目指す
49
52. C++1y ParallelTS (n3850)
// C++標準アルゴリズム
template <class In, class F>
In for_each( In first, In last, F f );
実行ポリシーを指定する
実行ポリシーを指定する
オーバーロード追加
オーバーロード追加
// C++1y ParallelTS
template <class ExecPolicy, class In, class F>
In for_each( ExecPolicy&& exec, In first, In last, F f );
52
67. 参考URL(1)
n3850 “Working Draft, Technical Specification for C++ Extensions for
Parallelism”(Thrustベース 並列アルゴリズム提案)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3850.pdf
https://github.com/n3554/n3554/
n3571 “A Proposal to add Single Instruction Multiple Data Computation to the
Standard Library”(Boost.SIMDベース データ型+操作関数提案)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3571.pdf
n3831 “Language Extensions for Vector level parallelism”
(CilkPlusベース ベクトル並列ループ構文提案)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3831.pdf
n3851 “Multidimensional bounds, index and array_view”
(C++AMPベース データ型提案)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3851.pdf
67
68. 参考URL(2)
OpenMP
http://openmp.org/
Thrust
http://thrust.github.io/
Intel TBB(Threading Building Blocks)
https://www.threadingbuildingblocks.org/
Microsoft ConcRT(Concurrency Runtime) / PPL(Parallel Pattern Library)
http://msdn.microsoft.com/ja-jp/library/dd492418.aspx
libstdc++ Parallel Mode
http://gcc.gnu.org/onlinedocs/libstdc++/manual/parallel_mode.html
Intel CilkPlus https://www.cilkplus.org/
GCC実装
https://www.cilkplus.org/build-gcc-cilkplus
Clang実装 http://cilkplus.github.io/
Microsoft C++ AMP(Accelerated Massive Parallelism)
http://msdn.microsoft.com/ja-jp/library/hh265137.aspx
Clang http://isocpp.org/blog/2012/12/shevlin-park
Boost.SIMD https://github.com/MetaScale/nt2/
SIMD intrinsic function
x86
http://software.intel.com/sites/landingpage/IntrinsicsGuide/
ARM
http://infocenter.arm.com/help/topic/com.arm.doc.dui0491c/CIHJBEFE.html
68
69. [予備] OpenMPでC++例外伝播
#include <omp.h>
try {
std::exception_ptr ep;
omp_lock_t ep_guard;
omp_init_lock(&ep_guard);
#pragma omp parallel for
for (int i = 0; i < N; ++i) {
try {
process(data[i]); // C++例外をthrow
} catch (...) {
omp_set_lock(&ep_guard);
if (!ep) ep = std::current_exception(); // 最初の例外のみ保存
omp_unset_lock(&ep_guard);
}
}
omp_destroy_lock(&ep_guard);
if (ep) std::rethrow_exception(ep); // 例外をparallel region外で再throw
} catch (...) {
// 例外処理
}
69