はじめに
近頃筆者は、IT業界に新しい波が押し寄せていることを感じています。マルチコアCPUは既に一般化し、その動きに合わせた技術のニュースを見聞きする機会が多くなりました。例えば、Google社が近頃発表した新言語Goは、並行(concurrent)コンピューティングの仕組みを強力にサポートしています。そういった潮流を鑑みるに、並行処理/並列処理は今は当たり前のものとなった感があります。
そして、つい最近Windows 7が発売されました。その売れ行きは好調でOSにおいても新しい時代の到来を感じさせました。早速筆者が購入したところ、Windows 7は64ビットバージョンも同梱されており、マルチコアと同じく64ビット化の波も来ていることを感じました。
この2つの波を鑑みるに、これからの時代に開発者が求められている能力は、大量のリソース(マルチコアCPU、64ビットが可能にする大量のメモリ)を操る力だと筆者は考えるに至りました。
そこで、Windows 7に対応しており、各種並列化技術をサポートしている開発ソフトを求めていたところ、インテル C++ コンパイラー 11.1が筆者を惹きつけました。
インテル C++ コンパイラー 11.1の概要
インテル C++ コンパイラー 11.1はWindows 7に対応しています。それに加えて、次世代の256ビット命令セットに対応したインテルAVX(Advanced Vector Extensions)、AES(Advanced Encryption Standard)命令セット、最新のOpenMP 3.0……など多くの新技術にいち早く対応しています。
これらの機能を考慮するとインテル C++ コンパイラー 11.1は、プラットフォームとCPUの能力を最大限に活かす製品だと言えると思います。C++が必要となるのは高いパフォーマンスを要求される時ですので、この特徴は非常に好ましいものだと言えます。
また、付属のマニュアルとプロパティページなどのメッセージが日本語で書かれている点を筆者は非常に気に入りました。開発するにあたって日本語対応しているか否かは、生産性に関わるので非常に重要です。最先端の製品は英語である事が多く、英語が苦手な筆者は苦労していました。日本語対応は日本人にとって大変嬉しいポイントです。
これから、筆者がインテル C++ コンパイラー 11.1をサンプルコードを用いて試用した様子をお伝えします。このサンプルコードは、これはあくまでもコンパイラーを試す目的のものであり、実務的なものではないのでその点に注意して下さい。また、本記事で紹介しているURLは今後変更される恐れがありますので注意して下さい。
準備
インテル C++ コンパイラー 11.1を使用するには別途Visual Studioが必要となります。本記事では、Visual Studio 2008を使用します。お持ちでない方は、マイクロソフト社のホームページから入手して、インストールを済ませて下さい。Visual Studio 2008のインストールの完了後、インテル C++ コンパイラー 11.1のインストール作業を行います。
まずはエクセルソフト社のダウンロードサイトにアクセスして下さい。さまざまなソフトウェアがダウンロードできる画面「評価版&ドキュメントーダウンロード」が表示されるので、「評価版/マニュアル」タブよりインテル C++ コンパイラー Windows 版日本語版を手順に従ってダウンロードします。ダウンロードが終了したら、ダウンロードする前に入力したE-mailのアドレスにメールが届いていると思いますので、そのメールに添付されているライセンスファイルを保存して下さい。
後は先ほどダウンロードしたインテル C++ コンパイラー 11.1のセットアップファイルを実行するだけです。途中でライセンスを求める画面が表示されますので、そこでメールにて送られてきたライセンスファイルを選択して下さい。その他は日本語で説明が表示されていますので難しいところはありません。
これで準備完了です。これからWindows 7のAPIとOpenMP 3.0を使って、インテル C++ コンパイラー 11.1の機能を体験します。
Windows 7のサンプル
Windows 7で開発するためにはSDKが必要です。まずはマイクロソフト社のホームページからSDKを入手してインストールを済まして下さい。
このサンプルの内容は、Windows 7から用意されているCPU関連のAPIを使用して、自分のPCに搭載されているCPUの情報を取得するというものです。_WIN32_WINNを適切な値に設定してコンパイルして下さい。
//Windows 7の場合 #define _WIN32_WINN 0x0601 //WindowsXPの場合 //#define _WIN32_WINN 0x0502 #include <iostream> #include <windows.h> #include <Winbase.h> using namespace std; int main() { #if( _WIN32_WINN >= 0x0601 ) //アクティブプロセッサ数 DWORD count = GetActiveProcessorCount( ALL_PROCESSOR_GROUPS ); cout << "このPCのアクティブなプロセッサの数は「" << count << "」です" << endl; //アクティブプロセッサグループ数 DWORD group = GetActiveProcessorGroupCount(); cout << "このPCのアクティブなプロセッサグループの数は「" << group << "」です" << endl; //浮動小数点 cout << "このCPUに浮動小数点機能は? "; if ( GetEnabledExtendedFeatures( XSTATE_MASK_LEGACY_FLOATING_POINT ) != 0 ) cout << "あり" << endl; else cout << "なし" << endl; //SSE cout << "このCPUにSSE機能は? "; if ( GetEnabledExtendedFeatures( XSTATE_MASK_LEGACY_SSE ) != 0 ) cout << "あり" << endl; else cout << "なし" << endl; //Intel AVX cout << "このCPUにIntel AVX機能は? "; if ( GetEnabledExtendedFeatures( XSTATE_MASK_GSSE ) != 0 ) cout << "あり" << endl; else cout << "なし" << endl; #else cout << "このサンプルはWindows 7用です。" << endl; cout << "Windows 7以降のOS上でないと動作しません。" << endl; #endif //終了 cout << endl << endl; return 0; } </pre> </div>
デバッグ実行して下さい。自分のPCに搭載しているCPUに関する情報が取得できます。
OpenMP 3.0のサンプル
インテル C++ コンパイラー 11.1は最新のOpenMP 3.0に対応しています。OpenMP3.0に興味があった筆者は早速試してみました。OpenMP 3.0では「タスク」の概念が追加され、従来並列化できなかった複雑なコードも並列化することができます。
このサンプルの内容は、終了条件が事前に明確でないループを並列化できることを示しています。これは、#pragma omp for
ではできない並列化です。なお、このサンプルはあくまでもタスクを試すことを目的としたものであり深い意味はありません。数値を合計しているのは、正しく並列化できていることを確認するためのものです。
#include <cstdio> #include <climits> #include <ctime> #include <iostream> #include <windows.h> #include <winnt.h> #include <tchar.h> #include <process.h> #include <omp.h> using namespace std; int main() { //ロケールを設定してコンソールで日本語表示が出来るようにする _tsetlocale( LC_ALL, _T("") ); //最大値が出るまでランダムに数を生成 srand( static_cast<unsigned int> ( time( NULL ) ) ); //ランダムに生成 const int maxCount = 100; //最大数 const int maxNumber = 100; const int magicNumber = maxNumber << 1; //終了を示す値 const int processingTime = 10; //処理時間(ミリ秒単位) int* numbers = new int[ maxCount ]; for ( int i = 0; i < maxCount; i++ ) { int number = static_cast<int>( ( rand() % maxNumber ) + 1 ); if ( number == maxNumber ) { //ここで終了 numbers[ i ] = magicNumber; break; } else { numbers[ i ] = number; } } numbers[ maxCount - 1 ] = magicNumber; //最後まで到達した場合に備える int* numbers1 = new int[ maxCount ]; for ( int i = 0; i < maxCount; i++ ) { int number = static_cast<int>( ( rand() % maxNumber ) + 1); if ( number == maxNumber ) { //ここで終了 numbers1[ i ] = magicNumber; break; } else { numbers1[ i ] = number; } } numbers1[ maxCount - 1 ] = magicNumber; //最後まで到達した場合に備える //逐次的に総計を算出 long int sum = 0; double start = omp_get_wtime(); int index = 0; while ( true ) { if ( numbers[ index ] == magicNumber ) break; sum += numbers[ index ]; ++index; Sleep( processingTime ); } int saveIndex = index; index = 0; while ( true ) { if ( numbers1[ index ] == magicNumber ) break; sum += numbers1[ index ]; ++index; Sleep( processingTime ); } int saveIndex1 = index; double end = omp_get_wtime(); double second = end - start; cout << "逐次的に計算した場合" << second << "秒かかりました。" << endl; //並列的に総計を算出 long int ompSum = 0; long int ompSum1 = 0; start = omp_get_wtime(); #pragma omp parallel { #pragma omp single nowait //これがないと同じ処理をスレッド数と同じだけ行ってしまう { index = 0; #pragma omp task firstprivate(index) { while ( true ) { if ( numbers[ index ] == magicNumber ) break; ompSum += numbers[ index ]; ++index; Sleep( processingTime ); } } index = 0; #pragma omp task firstprivate(index) { while ( true ) { if ( numbers1[ index ]== magicNumber ) break; ompSum1 += numbers1[ index ]; ++index; Sleep( processingTime ); } } } } ompSum += ompSum1; end = omp_get_wtime(); double ompSecond = end - start; cout << "並列的に計算した場合" << ompSecond << "秒かかりました。" << endl; //処理結果をチェック if ( sum != ompSum ) { cout << "並列処理に誤りがあります" << endl; cout << "直列:" << sum << " 並列:" << ompSum << ":" << ompSum1 << endl; } cout << "処理量が" << saveIndex << "と" << saveIndex1 << "の場合"; cout << "処理効率は" << ( second / ompSecond ) << "倍です。" << endl; //後始末 delete[] numbers; delete[] numbers1; }
まずプロジェクトで右クリックして[インテル C++コンパイラー・プロフェッショナル]-[インテル C++を使用]をクリックしてコンパイラーを切り替えてください。そして[プロパティ]-[C++]-[言語]を選択してから「OpenMPのサポート」を並列コードの生成(/openmp, /Qopenmp と同等)にして下さい。そして、最後にデバッグ実行して下さい。OpenMP 3.0の効果が目視できます。
何度か実行して試して下さい。データ処理量により効率が変動します。この結果から処理を並列化する際には、適用する部分をよく考える必要があることが分かります。
まとめ
今回の記事では、大量のリソースを効果的に利用するための手段が必要であることと、インテル C++ コンパイラー 11.1がその目的を達成するだけの機能を備えていることを紹介しました。
インテル C++ コンパイラー 11.1の機能は多く、今回紹介しきれませんでしたが、OpenMPによる並列化ソースコードを分析し、メモリーリーク、デッドロックなどの問題を診断する「Parallel Lint」、リビルドしなくてもデバッグセッション中にシリアルモードで並列領域をステップ実行できる「インテル Parallel Debugger Extension」などの魅力的な機能がまだまだあります。
エクセルソフト社のホームページで評価版を入手できますので、皆様はぜひご自身の手でその豊富な機能をお試しください。日本語に対応していますので容易に、次世代の技術を思う存分味わうことができるでしょう。