インテル® C++ コンパイラー 19.0 デベロッパー・ガイドおよびリファレンス
通常、プログラマーが指定した領域はトランザクション実行とコミットに成功することが想定されます。しかし、インテル® トランザクショナル・シンクロナイゼーション・エクステンション (インテル® TSX) では、この保証はありません。トランザクション実行は、さまざまな理由によりアボートされることがあります。トランザクション機能を最大限に活用するには、プログラマーはプログラミングの注意事項を考慮して、トランザクション実行のコミットが成功する可能性を高める必要があります。
このセクションでは、トランザクション・アボートの原因となるさまざまなイベントについて説明します。アーキテクチャーは、トランザクション実行がアボートした場合、トランザクション領域の内部で行われた更新が表面化しないことを保証します。コミットされたトランザクション実行のみ、アーキテクチャー上の状態を更新します。トランザクション・アボートが機能的な問題を引き起こすことはありません。パフォーマンスにのみ影響します。
プログラマーは、トランザクション (HLE: Hardware Lock Elision または RTM: Restricted Transactional Memory) の内部ですべての命令を安全に使用でき、すべての特権レベルでトランザクションを使用できます。一部の命令は常にトランザクション実行をアボートさせ、実行は非トランザクション・パスにシームレスかつ安全に移行されます。
インテル® TSX では、ほとんどの一般的な命令をトランザクションの内部で使用できます。通常、次の操作によりトランザクションの内部でトランザクション実行がアボートされることはありません。
トランザクション領域の内部でインテル® ストリーミング SIMD 拡張命令 (インテル® SSE) とインテル® アドバンスト・ベクトル・エクステンション (インテル® AVX) 命令を混在して使用する場合は注意が必要です。XMM レジスターにアクセスするインテル® SSE 命令と YMM レジスターにアクセスするインテル® AVX 命令の混在使用は、トランザクション・アボートの原因となります。
プログラマーは、トランザクション領域の内部で REP/REPNE プリフィクス付きの文字列操作を使用できます。しかし、長い文字列はトランザクション・アボートの原因となります。さらに、DF フラグを変更する CLD および STD 命令はトランザクション・アボートを引き起こします。DF が '1' の場合、STD 命令を使用してもアボートは起こりません。同様に、DF が '0' の場合、CLD 命令を使用してもアボートは起こりません。
トランザクションの内部で使用されたときにアボートを引き起こすことが明記されていない命令によりトランザクションがアボートされることは通常ありません (例えば、MFENCE、LFENCE、SFENCE、RDTSC、RDTSCP、など)。
次の命令はすべての実装でトランザクション実行をアボートします。
一部の実装では、次の命令もトランザクション・アボートを常に引き起こします。これらの命令は通常、トランザクション領域の内部で使用されることは想定されていません。これらの命令がトランザクション・アボートを引き起こすかどうかは実装に依存するため、プログラマーはこれらの命令によりトランザクション・アボートが生じることを想定してはなりません。
命令ベースによるアボートに加えて、ランタイムイベントによりトランザクション実行がアボートされるケースもあります。それは、データ・アクセス・パターンやマイクロアーキテクチャーの実装が原因です。次の説明は、すべてのアボートの原因を包括的に説明したものではありません。
ソフトウェアに対してトランザクションのフォルトやトラップは抑止されます。トランザクション実行がアボートすると、フォルトやトラップが発生しなかったように処理され、実行は非トランザクション実行に移行します。例外がマスクされない場合、トランザクション・アボートが引き起こされ、例外が発生しなかったように処理されます。
トランザクション実行中に同期例外イベント (#DE、#OF、#NP、#SS、#GP、#BR、#UD、#AC、#XF、#PF、#NM、#TS、#MF、#DB、#BP/INT3) が発生すると、トランザクション実行はコミットされず、非トランザクション実行が必要になります。これらのイベントは、発生しなかったように処理されます。HLE では、非トランザクション・コード・パスはトランザクション・コード・パスと同一であるため、例外を引き起こした命令が再度非トランザクション実行されると、これらのイベントは再度現れ、非トランザクション実行で関連する同期イベントが適切に処理されます。
トランザクション実行中に非同期イベント (NMI、SMI、INTR、IPI、PMI、その他) が発生すると、トランザクション実行はアボートされ、非トランザクション実行に移行します。非同期イベントはキューに入れられ、トランザクション・アボートが処理された後に処理されます。
トランザクションは、ライトバック・キャッシュが可能なメモリータイプの操作のみサポートします。ほかのメモリータイプの操作が含まれている場合、トランザクションは常にアボートされます。キャッシュ不可 UC メモリータイプにフェッチする命令も同様です。
トランザクション領域内のメモリーアクセスを行うには、プロセッサーが参照するページ・テーブル・エントリーの Accessed フラグと Dirty フラグをセットする必要があります。プロセッサーがこの制御をどのように行うかは実装固有です。一部の実装では、トランザクション領域が続いてアボートされた場合でも、これらのフラグに対する更新を外部的に見えるようにします。また、一部のインテル® TSX の実装では、これらのフラグを更新する必要がある場合、トランザクション実行のアボートを選択することがあります。さらに、プロセッサーのページ・テーブル・ウォークにより、トランザクションに書き込まれますが、コミットされていない状態へのアクセスが行われることがあります。インテル® TSX の実装によっては、このような状況でトランザクション領域の実行のアボートを選択することがあります。アーキテクチャーは、トランザクション領域がアボートした場合、トランザクションに書き込まれた状態が TLB のような機能により可視状態にならないことを保証します。
自己修正コードのトランザクション実行がトランザクション・アボートを引き起こすこともあります。プログラマーは、HLE と RTM を使用する場合でも、自己修正コードやクロス修正コードの記述に際してインテルが推奨するガイドラインに従う必要があります。
RTM と HLE の実装では通常、共通のトランザクション領域を実行するための十分なリソースが提供されますが、トランザクション領域の実装を制約したりサイズを必要以上に大きくすると、トランザクション実行がアボートされ、非トランザクション実行に移行する場合があります。アーキテクチャーは、トランザクション実行で利用可能なリソース量を保証しません。また、トランザクション実行が常に成功することを保証しません。
トランザクション領域内にアクセスするキャッシュラインに対して競合する要求を行うと、トランザクション実行の妨げとなることがあります。例えば、論理プロセッサー P0 がトランザクション領域の行 A を読み取り、別の論理プロセッサー P1 が A (トランザクション領域の内部または外部のいずれか) を書き込み、論理プロセッサー P1 の書き込みが論理プロセッサー P0 のトランザクション実行に影響した場合、論理プロセッサー P0 の実行はアボートされます。
同様に、P0 がトランザクション領域の行 A に書き込み、P1 が A の読み取りまたは書き込みを行い、P1 の A へのアクセスが P0 のトランザクション実行に影響した場合も、P0 の実行はアボートされます。ほかのコヒーレンス・トラフィックが競合する要求として扱われ、アボートを引き起こすことがあります。これらの競合が発生する可能性はゼロではありませんが、ほとんど発生することはありません。競合解消ポリシーにより、P0 または P1 が上記のシナリオでアボートするかどうかが決まります。