6

私は haswell の tsx 拡張機能を試しています。既存の中規模 (数千行) のコードベースを、粗粒度のロックの代わりに GCC トランザクション メモリ拡張機能 (このマシンでは間接的に haswell tsx を使用しています) を使用するように適応させています。私は GCC の transactional_memory 拡張機能を使用しており、独自の _xbegin / _xend を直接記述していません。ITM_DEFAULT_METHOD=htm を使用しています

不可解な理由でハードウェア トランザクションが異常終了する率が高いため、十分な速度で動作させるのに問題があります。以下に示すように、これらの中止は競合や容量制限によるものではありません。

以下は、失敗率と根本的な原因を定量化するために使用した perf コマンドです。

perf stat \
 -e cpu/event=0x54,umask=0x2,name=tx_mem_abort_capacity_write/ \
 -e cpu/event=0x54,umask=0x1,name=tx_mem_abort_conflict/ \
 -e cpu/event=0x5d,umask=0x1,name=tx_exec_misc1/ \
 -e cpu/event=0x5d,umask=0x2,name=tx_exec_misc2/ \
 -e cpu/event=0x5d,umask=0x4,name=tx_exec_misc3/ \
 -e cpu/event=0x5d,umask=0x8,name=tx_exec_misc4/ \
 -e cpu/event=0x5d,umask=0x10,name=tx_exec_misc5/ \
 -e cpu/event=0xc9,umask=0x1,name=rtm_retired_start/ \
 -e cpu/event=0xc9,umask=0x2,name=rtm_retired_commit/ \
 -e cpu/event=0xc9,umask=0x4,name=rtm_retired_aborted/pp \
 -e cpu/event=0xc9,umask=0x8,name=rtm_retired_aborted_misc1/ \
 -e cpu/event=0xc9,umask=0x10,name=rtm_retired_aborted_misc2/ \
 -e cpu/event=0xc9,umask=0x20,name=rtm_retired_aborted_misc3/ \
 -e cpu/event=0xc9,umask=0x40,name=rtm_retired_aborted_misc4/ \
 -e cpu/event=0xc9,umask=0x80,name=rtm_retired_aborted_misc5/ \ 
./myprogram -th 1 -reps 3000000

したがって、プログラムはトランザクションを含むコードを 3000 万回実行します。各リクエストには、1 つのトランザクション gcc__transaction_atomicブロックが含まれます。この実行には 1 つのスレッドしかありません。

この特定のコマンドは、 Intel ソフトウェア開発者マニュアル vol 3perfに記載されている関連する tsx パフォーマンス イベントのほとんどをキャプチャします。

からの出力perf statは次のとおりです。

             0 tx_mem_abort_capacity_write                                  [26.66%]
             0 tx_mem_abort_conflict                                        [26.65%]
    29,937,894 tx_exec_misc1                                                [26.71%]
             0 tx_exec_misc2                                                [26.74%]
             0 tx_exec_misc3                                                [26.80%]
             0 tx_exec_misc4                                                [26.92%]
             0 tx_exec_misc5                                                [26.83%]
    29,906,632 rtm_retired_start                                            [26.79%]
             0 rtm_retired_commit                                           [26.70%]
    29,985,423 rtm_retired_aborted                                          [26.66%]
             0 rtm_retired_aborted_misc1                                    [26.75%]
             0 rtm_retired_aborted_misc2                                    [26.73%]
    29,927,923 rtm_retired_aborted_misc3                                    [26.71%]
             0 rtm_retired_aborted_misc4                                    [26.69%]
           176 rtm_retired_aborted_misc5                                    [26.67%]

  10.583607595 seconds time elapsed

出力からわかるように:

  • rtm_retired_startカウントは 3000 万 (プログラムへの入力と一致)
  • カウントはほぼ同じです(rtm_retired_abortコミットはまったくありません)
  • abort_conflictとのabort_capacityカウントは 0 であるため、これらは理由ではありません。また、実行中のスレッドは 1 つだけであることを思い出してください。競合はめったに発生しないはずです。
  • ここでの唯一の実際のリードは と の高い値でtx_exec_misc1ありrtm_retired_aborted_misc3、説明が多少似ています。

Intel のマニュアル (第 3 巻) では、rtm_retired_aborted_misc3カウンターを次のように定義しています。

コード:C9H 20H

ニーモニック: RTM_RETIRED.ABORTED_MISC3

説明: HLE に適していない命令が原因で RTM 実行が中止された回数。

の定義にtx_exec_misc1は、似たような言葉がいくつかあります。

コード: 5DH 01H

ニーモニック: TX_EXEC.MISC1

説明: トランザクションのアボートを引き起こす可能性のあるクラスの命令が実行された回数をカウントします。これは実行回数であるため、必ずしもトランザクションのアボートが発生するとは限りません。

の高精度 (PEBS) サポートを使用したパフォーマンス レコード/パフォーマンス レポートを使用して、アボートのアセンブリの場所を確認しましたrtm_retired_aborted。場所には、movレジスタからレジスタへの命令があります。変な命令名は近くにありません。

アップデート:

それ以来、私が試した2つのことは次のとおりです。

1) ここで見られる tx_exec_misc1 および rtm_retired_aborted_misc3 署名は、たとえば、次の形式のダミー ブロックによって取得できます。

for (int i = 0; i < 10000000; i++){
  __transaction_atomic{
    _xabort(1);
  }
}

またはいずれかの形式

for (int i = 0; i < 10000000; i++){
  __transaction_atomic{
    printf("hello");
    fflush(stdout);
  }
}

どちらの場合も、パフォーマンス カウンターは私が見たものと似ています。ただし、どちらの場合も、perf reportfor-e cpu/tx-abort/ は直観的に正しいアセンブリ ラインを指しています。xabort最初の例の命令とsyscall2 番目の例の命令です。実際のコードベースでは、perf レポートは、関数の開始時にスタック プッシュが行われたことを示しています。

           :    00000000004167e0 <myns::myfun()>:
    100.00 :      4167e0:       push   %rbp
      0.00 :      4167e1:       mov    %rsp,%rbp
      0.00 :      4167e4:       push   %r15

Intel ソフトウェア開発エミュレーターでも同じコマンドを実行しました。その場合、問題はなくなることがわかりました。アプリケーションに関する限り、アボートは発生しません。

4

1 に答える 1