はじめに
2010年9月3日、並列プログラミングを支援するツールスイートである「インテルParallel Studio 2011」(以下、Parallel Studio 2011)がエクセルソフト社より発売されました。
Parallel Studio 2011はC/C++開発者のための複数のツールを含むスイート製品で、過去にもParallel Studioとしてリリースされていましたが、今回のリリースよりバージョン番号が付加され、いくつもの新機能が追加されています。各製品の特徴と新機能を表に示します。
製品名 | 特徴 | 主な新機能 | 共通の新機能 |
Parallel Advisor 2011 | ソースコード中の並列化処理すべき部分を解析する | Parallel Studio 2011からの新製品 | Visual Studio 2010に対応 Windows Server 2008 R2に対応 |
Parallel Composer 2011 | 並列アプリケーションを実装するためのコンパイラ、デバッガ、ライブラリを提供する | インテルCilk Plus対応 | |
Parallel Inspector 2011 | 並列化に伴うエラーやデータ競合を検出する | リソースリークの検出機能追加 | |
Parallel Amplifier 2011 | パフォーマンスのボトルネックを検出する |
Parallel Studio 2011での大きなトピックは、アプリケーションを分析して並列化処理すべき部分を見つけ出す、Parallel Advisor 2011という製品がスイートに追加されたことです。なお、Parallel Advisor 2011については、別途記事で解説されていますので、参考にしてください。
Parallel Studio 2011を使ったアプリケーションの並列化実装の流れは図1のようになります。
本記事では、Parallel Advisor 2011以外の製品の主な新機能について解説します。
また、過去のバージョンになりますが、Parallel Studioの解説記事がCodeZine内で公開されていますので、参考にしてください。
- 手軽に並列化を実現する「インテルParallel Studio」の魅力
- インテル Parallel Studioを使って並列化プログラミングを試してみた
- 並列プログラミングの効率的なデバッグを実現する「Parallel Inspector」
- 正しい分析でムダなくチューニング アプリの並列化を支援する「インテル Parallel Amplifier」
動作環境
Parallel Studio 2011は以下の環境で動作します。なお、以前のバージョンのParallel Studioを使用しているユーザはParallel Studio 2011を無償で入手できます。
OS | Windows XP,Windows Vista,Windows 7,Windows Server 2003,Windows Server 2008(各32ビット/x64エディションに対応) |
開発環境 | Visual Studio 2005 / 2008 / 2010 |
開発言語 | C/C++(ネイティブコードのみ。.NET用のマネージドコードは不可) |
エクセルソフト社よりParallel Studio 2011の評価版が公開されており、30日間無償で体験することができます。
なお、本記事では、Windows 7(32ビット版)、Visual Studio 2010を使って解説します。
Parallel Composer 2011の新機能
Parallel Composer 2011は、高性能なコードを出力するインテルC++コンパイラーとデバッガ、並列化のための各種ライブラリを含み、並列化アプリケーション実装の中心となる製品です。
今回のバージョンでは、以下のような新機能が追加されています。
- インテルC++コンパイラーがC++の次期標準であるC++0xのサポートを拡大
- 並列化のためのC/C++言語拡張であるインテルCilk Plus(シルクプラス)
- 並列化ライブラリであるArray Building Blocks(ベータ版)
本記事では、注目株のインテルCilk Plus(以下、Cilk Plus)を解説します。
Cilk Plus
Cilk Plusは並列化処理のためのC/C++言語拡張です(綴りはClickやClikではなくCilkなのでタイプミスに注意)。
シンプルな記法で、ループや特定の関数呼び出しなどを並列化処理することができます。Cilk Plusで定義されているキーワードは以下の3つです。
キーワード | 機能 | 別名 |
_Cilk_for | 並列でfor文を処理する | cilk_for |
_Cilk_spawn | 並列で関数を呼び出す | cilk_spawn |
_Cilk_sync | _Cilk_spawnの結果を待つ | cilk_sync |
なお、各キーワードは<cilk/cilk.h>で別名でも定義されています。
このようにCilk Plusのキーワードはわずか3つで、使い方も実にシンプルです。
例えば、これまで逐次処理していたfor文を並列処理する際は、以下のようにコードを書き換えます。
for(int i = 0 ; i < LOOP_MAX ; i++){ //処理内容 }
↓
cilk_for(int i = 0 ; i < LOOP_MAX ; i++){ //並列処理内容 }
同様に、逐次的に関数呼び出しを行っていた部分を並列処理する際は、以下のようにコードを置き換えます。
someMethod1(); //1番目のメソッド呼び出し someMethod2(); //1番目のメソッド終了後、2番目のメソッド呼び出し someMethod3(); //同上
↓
cilk_spawn someMethod1(); //メソッドを並列に呼び出し cilk_spawn someMethod2(); //someMethod1の終了を待たず、メソッドを並列に呼び出し cilk_spawn someMethod3(); //同上 cilk_sync; //すべてのメソッド終了まで待つ
Parallel Composer 2011には、よく知られたアルゴリズムであるクイックソートをcilk_spawnを使って並列化したサンプルが含まれています({Parallel Studio 2011をインストールしたフォルダ}\Composer\Samples\en_US\C++\Cilk\qsort)。
クイックソートはソート対象を小さな問題に分割しながら処理を行う分割統治法を用いていますが、このサンプルでは、分割した前半部分を並列に再帰呼び出ししています。
//クイックソートを行う再帰関数 void sample_qsort(int * begin, int * end) { if (begin != end) { --end; int * middle = std::partition(begin, end, std::bind2nd(std::less<int>(), *end)); using std::swap; swap(*end, *middle); //前半部分をcilk_spawnで並列処理 cilk_spawn sample_qsort(begin, middle); //後半部分は逐次処理(直後にcilk_syncがあるため、並列処理する意味がない) sample_qsort(++middle, ++end); //並列処理結果を待つ cilk_sync; } }
この並列処理クイックソートと、cilk_spawn,cilk_syncを除いた逐次処理クイックソートで、100,000,000個の数字を処理したところ、以下のように17%ほどの高速化が確認できました(筆者の環境はIntel Core 2 Duo T9300 2.5GHz デュアルコア)。
逐次処理 | 13375ms |
並列処理 | 11140ms |
また、Parallel Composer同梱のQuickDemoサンプル({Parallel Studio 2011をインストールしたフォルダ}\Composer\Samples\en_US\C++\Cilk\QuickDemo)では、並列処理と逐次処理の処理速度を並列度を変えながら視覚的に比較することができます。
Parallel Inspector 2011の新機能
Parallel Inspector 2011は、メモリーリークやスレッド間のデータ競合といった、並列化処理を実装する際に発生する問題も解析可能なツールです。
今回のバージョンでは、以下のような新機能が追加されています。
- Cilk Plusのサポート
- リソースリーク検出機能
本節ではリソースリーク検出機能について紹介します。
リソースリーク検出
Parallel Inspectorは以前のバージョンからメモリリークの検出機能を持っていましたが、今回のバージョンから、リソースリークの検出機能が追加されました。これは、WindowsのUI機能を提供するGDIと、カーネルのリソースを取得したまま、解放処理を行っていない箇所について検出する機能です。
例えば、GDI、カーネルそれぞれで、以下のようにリソースを使用する関数を呼び、使用後にきちんとリソースを開放していない場合、リソースリークが発生します。
呼び出す関数 | 使用後に行うべき処理 | |
GDI | CreateBitmap(ビットマップ作成) CreateDC(デバイスコンテキスト作成) CreateFont(フォント作成)など |
DeleteObject関数でハンドルの削除 |
カーネル | CreateThread(スレッド作成) CreateProcess(プロセス作成) HeapCreate(ヒープオブジェクト作成)など |
CloseHandle関数でリソースを削除 (HeapCreate関数に対してはHeapDestroy関数) |
サンプルでリソースリーク検出を確認してみましょう。以下はスレッドを作成したのに、CloseHandle関数を呼び出し忘れたケースです。
//何もしないスレッド関数 DWORD WINAPI thread(LPVOID vdParam) { return 0; } int _tmain(int argc, _TCHAR* argv[]) { //スレッドを生成 HANDLE hThread = CreateThread(0, 8192, thread, NULL, 0, NULL); //CloseHandle関数を呼び忘れた! //CloseHandle(hThread); return 0; }
Visual Studio 2010で以上のソースをビルドし、画面上部のツールバーから、[Inspect]ボタンをクリックします。
表示される[Configure Analysis]ダイアログでは、[Analysis Type](検出する内容)を[Memory Errors]と[Threading Errors]から選択します。
それぞれ以下のエラーを検出できます。
Analysis Type | 検出されるエラー |
Memory Errors | メモリリーク、リソースリークなど |
Threading Errors | データ競合など |
今回はリソースリークを検出するため[Memory Errors]を選択しましょう。
また同じダイアログでは、検出の詳細度も選択できます。詳細な検出を行うほど処理時間が掛かります。今回は一番軽い処理の[Does my target leak memory?]を選択しましょう。
[Run analysis]ボタンをクリックすると、アプリケーションが実行され、終了後エラーが検出されます。今回は図のようにカーネルのリソースリークが検出されています。
該当する行をダブルクリックすると、以下のように該当する行が表示されます。
小さなサンプルであればこうした問題の発見は手動でも用意ですが、大規模なアプリケーション開発では、以前からサポートされていたメモリリークの検出に加え、今回からサポートされたリソースリークの検出は大いに役立つことでしょう。
まとめ
今後のアプリケーション開発において、並列化というテーマは不可避になっていくことでしょう。つまり「並列化するか否か」ではなく「どのように並列化するか」を中心に考えていく必要があります。
Parallel Studio 2011で新たにサポートされたCilk Plusは、複雑なマルチスレッドコードを書くことなく、シンプルな記法で並列化処理を実現することができます。まだ日本語の情報源も少ない状態ですが、ぜひ活用しましょう。
アプリケーションの並列化において有益な情報源として、Intel社からリリースされている「マルチスレッドアプリ開発ガイド」の日本語版がParallel Studio 2011の日本発売元であるエクセルソフト社のサイトで公開されています。
この開発ガイドでは、マルチスレッドアプリケーションの開発に伴って検討すべき要素を、基本的な理論から具体的な実装方法まで解説しています。(以前のバージョンではありますが)Parallel Studioの実践的な使用方法についても解説していますので、ぜひ参照してください。