インテル® ソフトウェア開発製品

Similar documents
IntelR Compilers Professional Editions

インテル® スレッディング・ビルディング・ブロック・リファレンス・マニュアル

Jackson Marusarz 開発製品部門

並列アプリケーション向けインテル® TBB スケーラブル・メモリー・アロケーターの活用

インテル(R) Visual Fortran コンパイラ 10.0

Slide 1

Product Brief 高速なコードを素早く開発 インテル Parallel Studio XE 2017 インテル ソフトウェア開発ツール 概要 高速なコード : 現在および次世代のプロセッサーでスケーリングする優れたアプリケーション パフォーマンスを実現します 迅速に開発 : 高速かつ安定し

DPD Software Development Products Overview

インテル® Parallel Studio XE 2013 Windows* 版インストール・ガイドおよびリリースノート

Microsoft PowerPoint - 03_What is OpenMP 4.0 other_Jan18

インテル® Parallel Studio XE 2013 Linux* 版インストール・ガイドおよびリリースノート

Microsoft Word - matlab-coder-code-generation-quick-start-guide-japanese-r2016a

DPD Software Development Products Overview

memo

Java の ConcurrentHashMap における同期化 バッドケースとその対処法 2013 年 9 月湊隆行 1. はじめに表 1.1 に示すように Java の Collections Framework には 3 つの世代があります バージョン 1.0 から存在するレガシー API バ

Microsoft PowerPoint - kougi7.ppt

HashMapからConcurrentHashMapへの移行

4-3- 基 C++ に関する知識 オープンソースシステムのソースを解読する上で C++ の知識は必須であるといえる 本カリキュラムでは まずオブジェクト指向に関する Ⅰ. 概要理解を深め クラスの扱い方について学習し STL を使用してアルゴリズムとデータ構造を実装する方法を学習する Ⅱ. 対象専

PowerPoint プレゼンテーション

program7app.ppt

POSIXプログラミング Pthreads編

Using VectorCAST/C++ with Test Driven Development

Oracle SQL Developer Data Modeler

memo

概要 プログラミング論 変数のスコープ, 記憶クラス. メモリ動的確保. 変数のスコープ 重要. おそらく簡単. 記憶クラス 自動変数 (auto) と静的変数 (static). スコープほどではないが重要.

POSIXスレッド

第2回

第 2 章インタフェース定義言語 (IDL) IDL とは 言語や OS に依存しないインタフェース定義を行うためのインタフェース定義言語です CORBA アプリケーションを作成する場合は インタフェースを定義した IDL ファイルを作成する必要があります ここでは IDL の文法や IDL ファイ

自己紹介 湯浅陽一 1999 年より Linux kernel 開発に参加 MIPS アーキテクチャのいくつかの CPU へ Linux kernel を移植

Insert your Title here

Microsoft PowerPoint - FormsUpgrade_Tune.ppt

slide5.pptx

インテル® Fortran Studio XE 2011 SP1 Windows* 版インストール・ガイドおよびリリースノート

for (int x = 0; x < X_MAX; x++) { /* これらの 3 つの行は外部ループの自己データと * 合計データの両方にカウントされます */ bar[x * 2] = x * ; bar[(x * 2) - 1] = (x - 1.0) *

Microsoft PowerPoint - 1_コンパイラ入門セミナー.ppt

TFTP serverの実装

連載講座 : 高生産並列言語を使いこなす (5) 分子動力学シミュレーション 田浦健次朗 東京大学大学院情報理工学系研究科, 情報基盤センター 目次 1 問題の定義 17 2 逐次プログラム 分子 ( 粒子 ) セル 系の状態 ステップ 18

Java講座

Microsoft* Windows* 10 における新しい命令セットの利用

Microsoft PowerPoint - VSUGDAY_2008_Intel_V2.ppt

デジタル表現論・第6回

Delphi Generics.Collections

kantan_C_1_iro3.indd

SuperH RISC engine C/C++ コンパイラ Ver.7 不具合内容 - 過去のお知らせ SuperH RISC engine C/C++ コンパイラ Ver.7 台における不具合内容を以下に示します のチェックツールをルネサスエレクトロニクス株式会社のホームページ

Microsoft Word _VBAProg1.docx

Prog1_6th

インテル® Parallel Studio XE 2015 Composer Edition for Linux* インストール・ガイドおよびリリースノート

RX ファミリ用 C/C++ コンパイラ V.1.00 Release 02 ご使用上のお願い RX ファミリ用 C/C++ コンパイラの使用上の注意事項 4 件を連絡します #pragma option 使用時の 1 または 2 バイトの整数型の関数戻り値に関する注意事項 (RXC#012) 共用

memo

Microsoft PowerPoint - 11.pptx

Microsoft PowerPoint - 09.pptx

プログラミング基礎I(再)

ピクセル同期を利用した順不同半透明描画 (更新)

Oracle Un お問合せ : Oracle Data Integrator 11g: データ統合設定と管理 期間 ( 標準日数 ):5 コースの概要 Oracle Data Integratorは すべてのデータ統合要件 ( 大量の高パフォーマンス バッチ ローブンの統合プロセスおよ

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

JavaプログラミングⅠ

Microsoft PowerPoint Java基本技術PrintOut.ppt [互換モード]

生成された C コードの理解 コメント元になった MATLAB コードを C コード内にコメントとして追加しておくと その C コードの由来をより簡単に理解できることがよくありま [ 詳細設定 ] [ コード外観 ] を選択 C コードのカスタマイズ より効率的な C コードを生成するベストプラクテ

Microsoft PowerPoint - kougi2.ppt

21 章のお話

2 概要 市場で不具合が発生にした時 修正箇所は正常に動作するようにしたけど将来のことを考えるとメンテナンス性を向上させたいと考えた リファクタリングを実施して改善しようと考えた レガシーコードなのでどこから手をつけて良いものかわからない メトリクスを使ってリファクタリング対象を自動抽出する仕組みを

JavaプログラミングⅠ

Click to edit title

Microsoft PowerPoint - OpenMP入門.pptx

プログラミング実習I

.NETプログラマー早期育成ドリル ~VB編 付録 文法早見表~

Program Design (プログラム設計)

PowerPoint プレゼンテーション

AquesTalk for WinCE プログラミングガイド

ただし 無作為にスレッドを複数実行すると 結果不正やデッドロックが起きる可能性がある 複数のスレッド ( マルチスレッド ) を安全に実行する ( スレッドセーフにする ) ためには 同期処理を用いるこ とが必要になる 同期処理は 予約語 synchronized で行うことができる ここでは sy

Microsoft PowerPoint - 計算機言語 第7回.ppt

PowerPoint プレゼンテーション

Microsoft PowerPoint - CproNt02.ppt [互換モード]

Microsoft Word - 商業-3

intra-mart Accel Platform — IM-共通マスタ スマートフォン拡張プログラミングガイド   初版  

Microsoft PowerPoint - ●SWIM_ _INET掲載用.pptx

プログラム言語及び演習Ⅲ

Microsoft Word - Cプログラミング演習(12)

24th Embarcadero Developer Camp

Microsoft認定資格問題集(70-483_demo)

02: 変数と標準入出力

プレポスト【問題】

Android Layout SDK プログラミング マニュアル

ホンダにおける RT ミドルウェア開発と標準化活動 株式会社本田技術研究所基礎技術研究センター関谷眞

メソッドのまとめ

Python によるジオプロセシング スクリプト入門

(1) プログラムの開始場所はいつでも main( ) メソッドから始まる 順番に実行され add( a,b) が実行される これは メソッドを呼び出す ともいう (2)add( ) メソッドに実行が移る この際 add( ) メソッド呼び出し時の a と b の値がそれぞれ add( ) メソッド

本文ALL.indd

講習No.9

パフォーマンス徹底比較 Seasar2 vs Spring 2006/04/12 株式会社電通国際情報サービスひがやすを株式会社アークシステム本間宏崇 Copyright the Seasar Foundation and the others all rights reserved.

PowerPoint プレゼンテーション

The Parallel Universe 1 インテル MPI ライブラリーのマルチ EP によりハイブリッド アプリケーションのパフォーマンスを向上 最小限のコード変更でエクサスケール時代に備える Rama Kishan Malladi インテルコーポレーショングラフィックス パフォーマンス モ

Microsoft PowerPoint ppt

Programming D 1/15

/*Source.cpp*/ #include<stdio.h> //printf はここでインクルードして初めて使えるようになる // ここで関数 average を定義 3 つの整数の平均値を返す double 型の関数です double average(int a,int b,int c){

Microsoft PowerPoint - 12.ppt [互換モード]

memo

Microsoft PowerPoint - kougi6.ppt

ストリームを用いたコンカレントカーネルプログラミングと最適化 エヌビディアジャパン CUDAエンジニア森野慎也 GTC Japan 2014

PowerPoint Presentation

Transcription:

インテル ソフトウェア開発製品 James Reinders セールス & マーケティング ディレクター

インテル ソフトウェア開発製品 XML インテル C++ コンパイラーは Windows* Linux* Mac OS* X で開発を行う Microsoft* と gcc (GNU) ユーザーの最も一般的なアップグレード パス インテル Fortran コンパイラーは 現在最も使われている Fortran コンパイラー ライブラリー 解析ツール クラスターツールに加えて スレッド化の助けとなる新しい製品が追加されている インテル スレッディング ビルディング ブロック ( インテル TBB) は 並列処理用の C++ 拡張ライブラリー 2 マルチコア プロセッサー時代をリードするインテルのソフトウェア開発ツール

インテル TBB の紹介 Robert Reed テクニカル コンサルティング エンジニア ソフトウェア & ソリューション グループ

オープンソースと商用 ライセンスを除いて同一 4

TBB に関する非常に活発なフォーラム ブログ FAQ 扱われている内容 : ライセンス 移植に関する問題 ベンチマーク オーバーヘッドの評価 ライブラリーの機能 ( 既存 / 拡張 ) 互換性 共存 さまざまなケースでの利用 5

インテル TBB の内容 基本的なアルゴリズム : 高度なアルゴリズム : コンテナー : parallel_for, parallel_reduce, parallel_scan parallel_while, pipeline, parallel_sort concurrent_queue, concurrent_vector, concurrent_hash_map スケーラブルなメモリー割り当て : scalable_malloc, scalable_free, scalable_realloc, scalable_calloc, scalable_allocator, cache_aligned_allocator 排他制御 : mutex: アトミック操作 : 時間計測 : タスク スケジューラー : mutexspin_mutex, queuing_mutex, spin_rw_mutex, queuing_rw_mutex fetch_and_add, fetch_and_increment, fetch_and_decrement, compare_and_swap, fetch_and_store 移植性のあるファイングレイン ( 細粒度 ) のグローバル タイム スタンプタスクの作成とアクティベーションを制御する直接アクセス 6

インテル TBB 2.0 threadingbuildingblocks.org 多くのプラットフォームをサポートすべてのコンパイラー すべての OS すべてのプロセッサーをサポートすることを目標とし 現在は主要なものをサポートしている オープンソース プロジェクト http://threadingbuildingblocks.org ( 標準ライセンス : GPL v2 ランタイム例外 gnu C++ が長年使用してきたものと同じ ) オープンソースと商用版の違い継続して提供される商用版ではインテルからサポートを受けられる オライリーの Nutshell 本 オライリーから出版された TBB の Nutshell 本 初心者から熟練者まで すべての C / C++ プログラマーに役立つ 日本語訳版は近日出版予定 7

TBB が C++ 標準ライブラリーの並列性における基礎となったのは喜ばしいことです Alexander Stepanov 氏アドビシステムズ TBB は C++ における新しい並列プログラミング方法を提供します Marc Snir 氏イリノイ大学 インテルの TBB と並列プログラミングの関係は 単純な C++ と STL のようなものです Lawrence Rauchwerger 氏テキサス A&M 大学 8

時間計測関数インテル TBB はさまざまな機能をサポート タスク イニシエーター parallel_for parallel_while parallel_reduce parallel_scan pipeline parallel_sort タスク スケジューラー scalable_allocator メモリー割り当て cache_aligned_allocator 同期プリミティブネイティブ mutex を含むスコープロック スピンまたはキュー 単純な型または読み取り / 書き込み型 アトミック型 スレッドセーフ コンテナー concurrent_vector concurrent_queue concurrent_hash_map 9

インテル TBB の設計目標 プロセッサー数の増加に伴う並列プログラミングの負担を軽減 簡単な説明でパフォーマンスを向上する先進の機能を開発 アクセス可能な手法を構築して採用を促進 インテル TBB の概念 ワーカー ( スレッド ) ではなく作業 ( タスク ) に注目 再帰的な並列処理を利用する機会を最大限にする キャッシュに収まるように範囲を分割し ワークスチールを促進 汎用プログラミングを使用して新しいデータ型とアプリケーションで動作する効率的なコードを抽象化 10

メモリーはフリーではない レイテンシー CPU / メモリーの速度差は徐々に拡大している 最近のアーキテクチャーには 3~4 のメモリーレイヤーが存在 キャッシュの最適化がパフォーマンス向上の鍵 インテル TBB は 分割可能な範囲の概念を使用 R::R (const R&) R::~R() bool R::empty() const bool R::is_divisible() const R::R (R& r, split) コピー コンストラクターデストラクター範囲が空の場合は true 範囲を分割できる場合は true r を 2 つのサブ範囲に分割 範囲分割とスレッドの割り当てはライブラリーによって制御 現在サポートしているクラス : blocked_range blocked_range2d ( まもなく 3d) サブ範囲の深さを粒度で制御 11

分割範囲をローカルに保つ 範囲を... [Data, Data+N) [Data, Data+N/2) [Data+N/2, Data+N) 大きく 一部がキャッシュにない タスクスチールの最良の候補...GrainSize 以下に... [Data, Data+N/k)... 再帰的に分割 スチール可能なタスク [Data, Data+GrainSize/2) 細分化によりデータアクセスをローカルに保つ 12

コードへの適用方法 単純なコード例から始める long d[10000]; fill_data(&d); long sum = 0, sumsq = 0; for (int i = 0; i < 10000; ++i) { sum += d[i]; sumsq += d[i] * d[i]; } 13

コードへの適用方法 class Body { Body() {} operator() (const blocked_range<int> &r) const { for (int i = r.begin(); i!= r.end(); ++i) { sum += d[i]; sumsq += d[i] * d[i]; } } }; long d[10000]; fill_data(&d); long sum = 0, sumsq = 0; parallel_for (blocked_range<int>(0, 10000), Body body, auto_partitioner()); 平均と標準偏差の計算 配列 d は blocked_range と parallel_for を使用してタスクのセットに細分化できる for の範囲を blocked_range に変更する ループ本体は個別の関数とクラスに含める必要がある 最後に parallel_for ( と他のコード ) を追加する または スタティック パーティショナーを使用して粒度を調整する parallel_for (blocked_range<int>(0, 10000, 200), Body body); 14

コードの確認 tbb::atomic<float> sum, sumsq; class Body { Body() {} operator() (const blocked_range<int> &r) { for (int i = r.begin(); i!= r.end(); ++i) { sum += d[i]; sumsq += d[i] * d[i]; } } }; long d[10000]; fill_data(&d); long sum = 0, sumsq = 0; parallel_for (blocked_range<int>(0, 10000), Body body, auto_partitioner); インテル スレッドチェッカーを実行すると ここに競合状態があることがわかる アクセスをアトミックにする : 最も簡単だが非効率 > 注 : atomic は整数型でのみ動作 (float や double 型では動作しない ) 15

コードの確認 class Body { Body() {} operator() (const blocked_range<int> &r) { for (int i = r.begin(); i!= r.end(); ++i) { SummingMutexType::scoped_lock lock(summingmutex); sum += d[i]; sumsq += d[i] * d[i]; } } }; long d[10000]; fill_data(&d); long sum = 0, sumsq = 0; parallel_for (blocked_range<int>(0, 10000), Body body, auto_partitioner()); インテル スレッドチェッカーを実行すると ここに競合状態があることがわかる アクセスをアトミックにする : 最も簡単だが非効率 > 注 : atomic は整数型でのみ動作 (float や double 型では動作しない ) スコープロックを使用する : 簡単だが効率はあまり良くない 16

コードの確認 class Body { long m_sum, m_sumsq; Body() : m_sum(0), m_sumsq(0) {} operator() (const blocked_range<int> &r) { for (int i = r.begin(); i!= r.end(); ++i) { m_sum += d[i]; m_sumsq += d[i] * d[i]; } } void join(body &rhs) { m_sum += rhs.m_sum; m_sumsq += rhs.m_sumsq; } } }; long d[10000]; fill_data(&d); Body body; parallel_reduce (blocked_range<int>(0, 10000), body, auto_partitioner()); インテル スレッドチェッカーを実行すると ここに競合状態があることがわかる アクセスをアトミックにする : 最も簡単だが非効率 > 注 : atomic は整数型でのみ動作 (float や double 型では動作しない ) スコープロックを使用する : 簡単だが効率はあまり良くない parallel_reduce に変更する : この例では最良のソリューション 17

はじめに 初期化が必要 18 最初の並列コードの前に 初期化を行う main (int argc, char **argv) { task_scheduler_init init; プログラムの残りの部分 } このオブジェクトは スレッドプールの作成を含む状態を定義する スレッドカウントはオブジェクトの存在期間によって決まる デフォルトは利用可能な処理要素あたり 1 つのスレッド 少なくとも 1 つの初期化が必要 - 追加の宣言は参照カウント スレッドカウントは明示的に保留または設定できる task_scheduler_init init(thread-count task_scheduler_init::automatic deferred); スレッド化環境を併用する場合 オーバーサブスクリプションを回避する必要がある init オブジェクトはダイナミックにスレッドカウントを変更できる >(init オブジェクトの存在期間を制御 )

インクルード ファイル 19 すべての機能には独自のインクルード ファイルがある task_scheduler_init?#include <tbb/task_scheduler_init.h> blocked_range?#include <tbb/blocked_range.h> parallel_for?#include <tbb/parallel_for.h> spin read-write mutex?#include <tbb/spin_rw_mutex.h> 多くの TBB の動作はインライン展開をサポートするため ヘッダーでエンコードされる ヘッダーをよく見ると多くのことがわかる template<typename RandomAccessIterator, typename Compare> struct quick_sort_range { static const size_t grainsize = 500; 2 3 のデバッグ宣言もある #define TBB_DO_ASSERT 1 // ヘッダーファイルにエラーチェックを追加 Windows システムでは自動的にアサートされ デバッグ ライブラリーとともに使用される tbb::assertion_failure にデバッガーのブレークポイントを設定するとエラーになる #define TBB_DO_THREADING_TOOLS 1 // フックを追加して解析を改善 コスト パフォーマンスを調整して解析を改善する 現在の実装で影響を受ける機能 : spin_mutex/spin_rw_mutex

parallel_for 多少フォーマル 2 つの形式がある template <typename Range, typename Body> void parallel_for(const Range &range, const Body &body) template <typename Range, typename Body, typename Partitioner> void parallel_for(const Range &range, const Body &body, const Partitioner &partitioner) 前者は 単純な分割機能の使用を意味する 範囲のサイズが粒度より大きい間は細分化が続行される 粒度は Range コンストラクターで指定する parallel_for(blocked_range<type>(start, end, grain size), body); 3D になると チューニングが難しくなる blocked_range3d<type>(start1, end1, grain1, start2, end2, grain2, start3, end3, grain3); 自動パーティショナーは スレッド数に基づいて粒度を設定する パフォーマンスが最適でない場合もゴールは信用できる 20

blocked_range<type> ブロック範囲は ワークカーネルの内部で連続する区間を抽象化する for (type i = begin; i!= end; ++i) は for (type i = r.begin(); i!= r.end(); ++i) に変換される 2d blocked_range はループのペアを入れ子にする for (type i = begini; i!= endi; ++i) { for (type j = beginj; j!= endj; ++j) { は次のように変換される for (type i = r.rows().begin(); i!= r.rows().end(); ++i) { for (type j = r.cols().begin(); j!= r.cols().end(); ++j) { 21

コードをまとめる parallel_<something> の一般的な形式は次のようになる class BodyClass { int m_thing1, m_thing2; // ループに利用可能なオブジェクトとメンバーのローカルコピー public: BodyClass(int thing1, int thing2 ) : m_thing1(thing1), m_thing2(thing2) {} // ローカルデータを初期化 operator() (const blocked_range<int> &r) { for (int i = r.begin(); i!= r.end(); ++i) {. } } }; 並列コードを呼び出すには次のように記述する BodyClass body(thing1, thing2 ); parallel_for( blocked_range<int>(0, limit), body, auto_partitioner()); 22

parallel_reduce parallel_for に累積プロセス ( ベクトルからスカラー ) を追加する class BodyClass { int m_thing1, m_thing2; // ループに利用可能なオブジェクトとメンバーのローカルコピー int m_sum; // ローカル累積変数 public: BodyClass(int thing1, int thing2 ) : m_thing1(thing1), m_thing2(thing2), m_sum(0) {} operator() (const blocked_range<int> &r) { for (int i = r.begin(); i!= r.end(); ++i) { m_sum += <something> ;. BodyClass (BodyClass &b, split) : m_thing1(b.m_thing1), m_thing2(b.m_thing2), m_sum(0) {} join( const BodyClass &b) { m_sum += b.m_sum; } }; リダクション演算は任意の結合演算またはプロセスになる (a b) c == a (b c ) 減算では動作しない! 浮動小数点演算 ( 内積?) でも同様に動作しない 23

時間計測 パフォーマンスを計測するタイミングは tick_count を使用すると簡単 tick_count t0 = tick_count::now(); // コード tick_count t1 = tick_count::now(); double duration = (t1-t0).seconds(); tick_count::interval_t は 加算と減算 秒への変換をサポート スレッド間の時間の比較は安全であることが保証される > 異なるスレッドで記録された tick の差分を求めることができる 分解能はスレッド間で提供されるサービスの最も高い分解能に対応 > しかし プラットフォーム間の一貫性は保証されない 24

同期プリミティブ 並列タスクは共有データを更新する データの更新が重なる場合 競合状態を回避するために排他制御を使用する TBB のすべての排他制御領域はスコープロックによって保護されている ロックの範囲はロックの期間によって決定される ロックの範囲から出るにはデストラクターを呼び出し 例外時も安定させる ロックを短くして競合状態を防ぐ operator() ( ) { // 他のカーネル作業 { // ロックの範囲を制限する内側の範囲 SummingMutexType::scoped_lock lock(summingmutex); // 競合状態が発生しやすい操作 } // 他のカーネル作業 } 25

同期プリミティブ 並列タスクは共有データを更新する データの更新が重なる場合 競合状態を回避するために排他制御を使用する TBB のすべての排他制御領域はスコープロックによって保護されている ロックの範囲はロックの期間によって決定される ロックの範囲から出るにはデストラクターを呼び出し 例外時も安定させる ロックを短くして競合状態を防ぐ さまざまな mutex の動作が利用可能 スピン vs. キュー ( 非スケーラブル アンフェア vs. スケーラブル フェア ) > spin_mutex, queuing_mutex ライター vs. リーダー / ライター ( 複数のリーダーと単一のライターをサポート ) > spin_rw_mutex, queuing_rw_mutex ネイティブな排他制御関数のスコープラッパー > mutex (Windows: CRITICAL_SECTION, Linux: pthreads mutex) 26

同期プリミティブ mutex の特徴 スケーラブル : mutex アクセスの直列化よりも優れている フェア : スレッド要求の順序を保存して何もしない状態を防ぐ リエントラント : ロックはスタック可能で 提供されている動作ではサポートされていない ウェイトメソッド : スレッドがロックを待つ方法 スケーラブル フェア ウェイト mutex OS 依存 OS 依存 スリープ spin_mutex スピン queuing_mutex スピン spin_rw_mutex スピン queuing_rw_mutex スピン 存在期間がある mutex では デッドロックまたはコンボイが発生する ロックの期間を減らすか atomic 操作を使用してこれらの問題を回避する > atomic<t> は 整数型の読み取り- 修正 - 書き込みサイクルのハードウェア ロックをサポート > セマフォー 参照カウントのような単一のネイティブ型の更新に役立つ 27

スコープロックの構文 mutex の種類を選択して mutex を作成する mutex の存在期間は mutex を使用するロックの期間以上にする ファイルの範囲で mutex を定義するのに最も安全 同期が必要な場所で mutex を使用してロックする { } typedef spin_mutex MyMutexType; MyMutexType MyMutex; { MyMutexType::scoped_lock lock(mymutex); // MyMutex 保護操作 } スコープロックは 必要であれば他の操作を提示する MyMutexType::scoped_lock lock(); lock.acquire(mymutex); lock.try_acquire(mymutex); lock.release(); 28

parallel_sort このテンプレートも 2 つの形式がある template <typename RandomAccessIterator> inline void parallel_sort(randomaccessiterator begin, RandomAccessIterator end); template <typename RandomAccessIterator, typename Compare> void parallel_sort(randomaccessiterator begin, RandomAccessIterator end, const Compare ); 前者は std::less<randomaccessiterator 値の型 > を使用する parallel_sort 分割コンストラクターはクイックソート分割を行う 分割の粒度のしきい値は 500 エントリー 500 未満のエントリーのチャンクは std:sort にそのまま送られる 分割コンストラクターは範囲中のすべてのデータも処理する > キャッシュライン処理の優れた例ではない 29

parallel_scan 呼び出された並列プリフィックスは 次の回帰パターンに基づいてシーケンスを別のシーケンスに変換する y 0 = I x 0 x 0, x 0 x 1, x 0 x 1 x 2, y i = y i 1 X i 演算子 は結合で parallel_reduce のように浮動小数点を処理する場合は特に注意が必要 TBB は 2 つのパスで実装されている 1 つめのパスは リダクションのように 部分的な結果を累積する 結果は 2 つめのパスで分配される スレッドの分割は 操作の数が増加しても実行時間を減らす 30

コンカレント コンテナー インテル TBB には コンカレント コンテナーが用意されている STL コンテナーは並列操作では安全ではない > 複数の修正を同時に行うと問題が発生する 標準的手法 : STL コンテナーのアクセスをロックでラップする > アクセサーが一度に 1 つのみ操作するように制限する TBB は 競合が少ない場合に効率的なファイングレイン ( 細粒度 ) ロックを提供 シングルスレッドのパフォーマンスは低下するが スケーラビリティーは向上する TBB OpenMP* またはネイティブスレッドとともに使用可能 スピンロック ベースで 長い期間待つことは想定していない 31

コンカレント インターフェイスの要件 いくつかの STL インターフェイスは並列性をサポートするように設計されていない 例えば 2 つのスレッドがそれぞれ別のものを実行すると仮定する extern std::queue q; if(!q.empty()) { item=q.front(); q.pop(); } この時点で 別のスレッドが最後の要素をポップする可能性がある ソリューション : インテル TBB の concurrent_queue で pop_if_present() メソッドを使用する 32

concurrent_vector<t> T のダイナミックに拡張可能な配列 grow_by(n) grow_to_at_least(n) クリアされるまで要素を移動しない 同時にアクセスして拡張可能 clear() メソッドは アクセス / サイズ変更に関してスレッドセーフではない Range コンストラクターは parallel_for などに並列ベクトルを接続する 例 // スレッドセーフな方法でシーケンス [begin,end) を x に追加 template<typename T> void Append(concurrent_vector<T> &x, const T *begin, const T *end ) { std::copy(begin, end, x.begin() + x.grow_by(end-begin) ) } 33

concurrent_queue<t> ローカルの要素の順序を保存 あるスレッドがプッシュし 別のスレッドが 2 つの値をポップすると プッシュした順序でポップされる 2 種類のポップ ブロック pop() 非ブロック pop_if_present() size() メソッドは符号付き整数を返す : (push pop) size() が n を返した場合 n ポップが対応するプッシュを待つことを意味する 注意 : キューはキャッシュを冷却する 34

concurrent_hash<key,t,hashcompare> ハッシュテーブルは読み取りと更新の同時アクセスを許可 > bool insert( accessor &result, const Key &key) 追加または編集 > bool find( accessor &result, const Key &key) 編集 > bool find( const_accessor &result, const Key &key) 調査 > bool erase( const Key &key) 削除 リーダーロックは共存可能 ライターロックは排他的 35

例 : 文字列から整数へのマップ struct MyHashCompare { static long hash( const char* x ) { long h = 0; for( const char* s = x; *s; s++ ) h = (h*157)^*s; return h; } 複数のスレッドが同時にエントリーを挿入または更新できる }; static bool equal( const char* x, const char* y ) { return strcmp(x,y)==0; } typedef concurrent_hash_map<const char*,int,myhashcompare> StringTable; StringTable MyTable; void MyUpdateCount( const char* x ) { StringTable::accessor a; MyTable.insert( a, x ); a->second += 1; } アクセサー オブジェクトは スマートポインターとライターロックとして動作する 36

parallel_while 項目のストリームを制御するために提供されている parallel_while<applyprocess> w; ItemStream stream; ApplyProcess body; w.run(stream, body); ストリームアクセスはスケーラビリティーを制限する フェッチは直列に行われる class ApplyProcess { public: void operator() (Item *item) const { // process item->data w.add(item->data->left); w.add(item->data->right); } typedef Item *argument_type; } ストリームのボトルネックは add メソッドを使用してタスク実行の前の拡張に再帰を追加することで回避できる 37

並列パイプライン ステージ化された線形パイプライン 処理できる項目の最大値を指定 線形パイプラインにマップして任意の DAG を制御 各ステージは直列または並列 直列ステージは一度に 1 つの項目を順に処理 並列ステージは一度に複数の項目を順序に関係なく処理 キャッシュを効率的に使用 各スレッドはできるだけ多くのステージを通って項目を処理 新しい項目に移る前に古い項目を終了するようにバイアスがかけられる コードがコアからコアへ移動する際にデータが変わらないようにする DAG = 有向非循環グラフ (Directed Acyclic Graph) 38

並列パイプライン 直列ステージは一度に 1 つの項目を順に処理 2 4 並列ステージは項目を並列または順序に関係なく処理できるのでスケーラブルである 別の直列ステージ シーケンス番号を含む項目 5 12 11 10 6 3 1 直列ステージに入るのを待っている項目 7 8 シーケンス番号を使用して直列ステージの順序を回復 処理能力は最も遅い直列ステージの処理能力によって制限される 9 パイプラインを流れる項目の総数を制限して過度な並列処理を制御 39

パイプラインは効率的 サンプルのインテル TBB パイプラインはオーバーラップした I/O 処理を行う 40

インテル TBB 基本的なアルゴリズム : 高度なアルゴリズム : コンテナー : スケーラブルなメモリー割り当て : 排他制御 : mutex: アトミック操作 : 時間計測 : タスク スケジューラー : parallel_for, parallel_reduce, parallel_scan parallel_while, pipeline, parallel_sort concurrent_queue, concurrent_vector, concurrent_hash_map scalable_malloc, scalable_free, scalable_realloc, scalable_calloc, scalable_allocator, cache_aligned_allocator mutexspin_mutex, queuing_mutex, spin_rw_mutex, queuing_rw_mutex fetch_and_add, fetch_and_increment, fetch_and_decrement, compare_and_swap, fetch_and_store 移植性のあるファイングレイン ( 細粒度 ) のグローバル タイム スタンプタスクの作成とアクティベーションを制御する直接アクセス 42

本資料に掲載されている情報は インテル製品の概要説明を目的としたものです 製品に付属の売買契約書 Intel s Terms and conditions of Sales に規定されている場合を除き インテルはいかなる責を負うものではなく またインテル製品の販売や使用に関する明示または黙示の保証 ( 特定目的への適合性 商品性に関する保証 第三者の特許権 著作権 その他 知的所有権を侵害していないことへの保証を含む ) に関しても一切責任を負わないものとします インテル製品は 予告なく仕様が変更されることがあります 2007 Intel Corporation. 43