このセクションでは、er_print コマンド行とスレッドアナライザの両方を使用して、検出したデータの競合それぞれに関する次の情報を表示する方法について説明します。
データの競合の一意の ID。
データの競合に関連付けられた仮想アドレス、Vaddr。複数の仮想アドレスがある場合は、Multiple Addresses のラベルが括弧に囲まれて表示されます。
2 つの異なるスレッドによる仮想アドレス Vaddr へのメモリーアクセス。アクセスの種類 (読み取りまたは書き込み) のほか、関数、オフセット、およびアクセスが行われたソースコード内の行番号が表示されます。
データの競合に関連付けられた呼び出しスタックトレースの総数。各トレースは、2 つのデータの競合アクセスが行われた時点で、スレッド呼び出しスタックの組を参照します。
スレッドアナライザを使用している場合、「競合」ビューで個々の呼び出しスタックトレースを選択すると、2 つの呼び出しスタックが「競合の詳細」ウィンドウに表示されます。er_print ユーティリティーを使用している場合、rdetail コマンドによって 2 つの呼び出しスタックが表示されます。
prime_omp.c でのデータの競合を調べるには、データの競合の検出実験を作成するで作成したいずれかの実験を使用できます。
er_print で prime_omp_instr.er 実験のデータの競合情報を表示するには、次のコマンドを入力します。
% er_print prime_omp_inst.er
(er_print) プロンプトで races と入力すると、次のような出力が表示されます。
(er_print) races Total Races: 4 Experiment: prime_omp_inst.er Race #1, Vaddr: 0x21850 Access 1: Write, line 25 in "prime_omp.c", is_prime Access 2: Read, line 22 in "prime_omp.c", is_prime Total Callstack Traces: 1 Race #2, Vaddr: (Multiple Addresses) Access 1: Write, line 49 in "prime_omp.c", main Access 2: Write, line 49 in "prime_omp.c", main Total Callstack Traces: 1 Race #3, Vaddr: 0xffbff534 Access 1: Write, line 50 in "prime_omp.c", main Access 2: Read, line 49 in "prime_omp.c", main Total Callstack Traces: 1 Race #4, Vaddr: 0xffbff534 Access 1: Write, line 50 in "prime_omp.c", main Access 2: Write, line 50 in "prime_omp.c", main Total Callstack Traces: 1 (er_print)
この特定のプログラム実行中に、4 つのデータの競合が生じました。
スレッドアナライザで prime_omp_inst.er 実験結果を開くには、次のコマンドを入力します。
% tha prime_omp_inst.er
次のスクリーンショットには、スレッドアナライザに表示された、prime_omp.c で検出された競合が示されています。
図 1 prime_omp.c で検出されたデータの競合
prime_omp.c には、次の 4 つのデータの競合が示されています。
Race #1 は、行 25 での関数 is_prime() の書き込みと、行 22 での同じ関数の読み取りとの競合を示しています。ソースコードを見ると、これらの行で pflag[ ] 配列がアクセスされていることがわかります。スレッドアナライザで「デュアルソース」ビューをクリックすると、両方の行番号でのソースコードとともに、コードの影響を受けた行での競合アクセス数を示すメトリックを簡単に確認できます。
Race #2 は、main 関数の行 49 での 2 つの書き込み間の競合を示しています。「デュアルソース」ビューをクリックすると、primes [ ] 配列の要素へのアクセスが行 49 で複数回試みられたことがわかります。 Race #2 は、配列 primes[ ] の異なる要素で発生したデータ競合のグループを表しています。これは、Multiple Addresses と指定された Vaddr で示されます。
Race #3 は、行 50 での main 関数の書き込みと、行 49 での同じ関数の読み取りとの競合です。ソースコードを見ると、これらの行で変数 total がアクセスされていることがわかります。
Race #4 は、main 関数内の行 50 での 2 つの書き込み間の競合を示しています。ソースコードを見ると、これらの行で変数 total が更新されていることがわかります。
スレッドアナライザの「デュアルソース」ビューでは、データの競合に関連付けられた 2 つのソース位置を同時に確認できます。たとえば、「競合」ビューで prime_omp.c の Race #1 を選択してから、「デュアルソース」ビューをクリックします。次のように表示されます。
スレッドアナライザの「デュアルソース」ビューでは、データの競合に関連付けられた 2 つのソース位置を同時に確認できます。たとえば、「競合」ビューで prime_pthr.c の Race #3 を選択してから、「デュアルソース」ビューをクリックします。次のように表示されます。
図 2 prime_omp.c で検出されたデータの競合のソースコード
prime_pthr.c でのデータの競合を調べるには、データの競合の検出実験を作成するで作成したいずれかの実験を使用できます。
er_print で prime_pthr_instr.er 実験のデータの競合情報を表示するには、次のコマンドを入力します。
% er_print prime_pthr_inst.er
(er_print) プロンプトで races と入力すると、次のような出力が表示されます。
(er_print) races Total Races: 5 Experiment: prime_pthr_inst.er Race #1, Vaddr: (Multiple Addresses) Access 1: Write, line 26 in "prime_pthr.c", is_prime + 0x00000234 Access 2: Write, line 26 in "prime_pthr.c", is_prime + 0x00000234 Total Callstack Traces: 2 Race #2, Vaddr: 0xffbff6dc Access 1: Write, line 59 in "prime_pthr.c", main + 0x00000208 Access 2: Read, line 39 in "prime_pthr.c", work + 0x00000070 Total Callstack Traces: 1 Race #3, Vaddr: 0x21620 Access 1: Write, line 44 in "prime_pthr.c", work + 0x000001C0 Access 2: Read, line 43 in "prime_pthr.c", work + 0x0000011C Total Callstack Traces: 2 Race #4, Vaddr: 0x21620 Access 1: Write, line 44 in "prime_pthr.c", work + 0x000001C0 Access 2: Write, line 44 in "prime_pthr.c", work + 0x000001C0 Total Callstack Traces: 2 Race #5, Vaddr: (Multiple Addresses) Access 1: Write, line 43 in "prime_pthr.c", work + 0x00000174 Access 2: Write, line 43 in "prime_pthr.c", work + 0x00000174 Total Callstack Traces: 2 (er_print)
この特定のプログラム実行中に、5 つのデータの競合が生じました。
スレッドアナライザで prime_pthr_inst.er 実験結果を開くには、次のコマンドを入力します。
% tha prime_pthr_inst.er
次のスクリーンショットには、スレッドアナライザに表示された、prime_pthr.c で検出された競合が示されています。er_print で示された競合と同じであることに注意してください。
図 3 prime_pthr.c で検出されたデータの競合
prime_pthr.c には、次の 5 つのデータの競合が示されています。
Race #1 は、行 26 で発生した、関数 is_prime() での pflag[ ] 配列の要素への 2 つの書き込みの間のデータ競合です。
Race #2 は、行 59 での main() における i というメモリー位置への書き込みと、行 39 での work() における *arg という同じメモリー位置の読み取りとのデータの競合です。
Race #3 は、行 44 での total への書き込みと、行 43 での total の読み取りとの間のデータ競合です。
Race #4 は、行 44 での total への書き込みと、同じ行での total への別の書き込みとのデータの競合です。
Race #5 は、main() 関数内の行 43 での 2 つの書き込み間のデータ競合です。Race #5 は、配列 primes[ ] の異なる要素で生じたデータの競合のグループを表します。これは、Multiple Addresses と指定された Vaddr で示されます。
Race #3 を選択したあとに「デュアルソース」ビューをクリックした場合、次のスクリーンショットのように、2 つのソース位置が表示されます。
図 4 データの競合のソースコード詳細
Race #2 の最初のアクセスは行 59 で行われ、上部のパネルに表示されます。2 番目のアクセスは行 39 で行われ、下部のパネルに表示されます。ソースコードの左側に「競合アクセス」メトリックが強調表示されます。このメトリックは、その行でデータの競合アクセスが報告された回数を示します。
スレッドアナライザの「競合」ビューで一覧表示されたデータの競合ごとに、1 つまたは複数の呼び出しスタックトレースが関連付けられています。呼び出しスタックは、データの競合を招く、コード内の実行パスを表示します。呼び出しスタックトレースをクリックすると、右パネルの「競合の詳細」ウィンドウに、データの競合を引き起こした関数呼び出しが表示されます。
図 5 prime_omp.c の呼び出しスタックトレースを示した「競合」ビュー