非効率な同期
この記事は、インテル® デベロッパー・ゾーンに公開されている、インテル® VTune™ Amplifier のオンラインヘルプの一部「Inefficient Synchronization」の日本語参考訳です。Windows* 用のヘルプではありますが、その他の OS 環境でも十分ご利用いただけます。また、構成は英語版のヘルプと同じ階層構造にしてあります。
コード中の非効率な同期の場所を特定するには、スタック収集 (英語) を有効にしてハードウェア・イベントベース・サンプリング解析を実行して提供されるデータを解析します。
タイムラインで同期の場所を表示
[Hardware Events viewpoint (ハードウェア・イベント・ビューポイント)] に解析中に収集されたデータが表示されます。
![]() |
[Call Stack (コールスタック)] ペインにユーザー関数とシステム関数の両方を表示するには、コールスタック・モード (英語) を [User/system functions (ユーザー/システム関数)] に設定します。 |
![]() |
[Timeline (タイム)] ペインで選択された同期コンテキスト・スイッチのコールスタックを見るには、[Call Stack] ペインのドロップダウン・メニューから [Synchronization Context Switch Count (同期コンテキスト・スイッチ・カウント)] タイプを選択します。 |
![]() |
タイムラインで頻繁に同期が行われている場所を見つけたら、コンテキスト・スイッチにマウスをホバーして詳細を表示します。例えば、上記の Advanced Hotspots (高度なホットスポット) の結果では、NtDelayExecution スレッドで同期による多数のコンテキスト・スイッチが発生しています。タイムライン上のコンテキスト・スイッチを選択すると、先行するスレッドの実行クアンタムの呼び出しシーケンスを表示するため、[Call Stack] ペインが更新されます。 |
[Average Wait (平均待機)] メトリックを解析
[Hotspots viewpoint (ホットスポット・ビューポイント)] を開くには、(change) リンクをクリックします。
![]() |
同期コンテキスト・スイッチごとの平均待機時間 (ミリ秒) を示す、[Wait Rate (待機率)] メトリックデータを解析します。このメトリックは、電力消費の問題と非効率である高い頻度の同期を特定するのに役立ちます。 |
![]() |
インテル® VTune™ Amplifier は、低い [Wait Rate] メトリック値 (1 ミリ秒以下) をパフォーマンスの問題として認識し、その項目をピンク色でハイライト表示します。このような値は、スレッド間の競合の増加とシステム API の非効率な利用を示します。 |
![]() | 短い待機時間と高い CPU 時間 (すべてのシステムコール時間の半分) を伴う同期を特定し、ホットスポット関数のソースコードを調査するためその項目をダブルクリックします。 |
同期コンテキスト・スイッチを解析
[Hardware Events viewpoint (ハードウェア・イベント・ビューポイント)] を開くには、(change) リンクをクリックします。デフォルトでは、[Event Count (イベントカウント)] グリッドは [Clockticks (クロックティック)] イベントでソートされます。実行に最も CPU 時間 (クロックティック) を消費し、最も頻繁に同期を行っているホットな関数を特定します。
この OpenMP* アプリケーションの例では、インテル® VTune™ Amplifier は、InterpolateN 関数が OpenMP* 領域から呼び出される計算のホットスポットであることを示しています。パフォーマンス損失 (待機関数のクロックティック/ホットスポット関数クロックティック) の約 30% につながる、主な競合が OpenMP* ランタイム内の WaitForSingleObject に見られます。
InterpolateN 関数をダブルクリックしてソースコードを開いて、非効率な同期の原因を調査します。
サンプル・アプリケーションのコード解析を調査すると、行のブロック単位で処理を行い、各ブロックを個別に並列化するため過度な OpenMP* のバリアーが追加されていることが分かります。この問題を回避するには、nowait 節を使用するか、parallel for 構文をループ全体に適用して動的にワークのスケジュールを行うようにします。
最適化の結果、Sleep() における相対的な競合のコストは低下しました (26,997)。
単一の parallel for とWaitForSingleObject 関数で動的なワークのスケジュールを行うことで、競合を減らしてパフォーマンスへの影響を約 1% に低下することができます。
次の最適化では、もう 1 つの高い競合を持つ関数 Sleep() (同期コンテキスト・スイッチのメトリックは 26,997) を調査します。実行時間を調べると、上位ホットスポットの 2% 内 (リストには表示されない) であるため、それほど重要ではないと思われます。しかし、この関数はプロセッサー数が多い環境でアプリケーションを実行すると問題となる可能性があります。
注:
(最適化前の) サンプルデータ収集セッションは、限られた時間間隔で実行されました。最適化されたバージョンでは、アプリケーションを最初から最後まで実行することができます。
上位トピック: チューニング手法
関連項目
パフォーマンス解析の設定
解析ターゲットの設定
スタックデータの解釈 (英語)
ペイン: Call Stack (コールスタック) (英語)
コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。