TSX

Haswellにおける、特にエンタープライズ向けの大きな目玉がトランザクションメモリである。トランザクションメモリとは如何な物で、どう利用するのか? という話は今年2月に安藤先生が記事になさっているので、こちらをご覧いただく方が説明が早い。ということで、以後は安藤先生の記事を読んでいることを前提に説明する。

TSXは粗粒度のロック機構を提供するHLE(Hardware Lock Elision)と、細粒度のロック機構を提供するRTM(Restricted Transaction Memory)の2種類が用意される。HLEはXACQUIRE/XRELEASE、RTMはXBEGIN/XENDで、他にXTEST/XABORTという命令が追加されている(Photo23)。

Photo23: XTEST/XABORTはRTM専用で、前者は現在トランザクション中かを確認するもの、後者はトランザクションを破棄(Abort)するための命令である。

使い方は比較的簡単である。HLEの場合、従来のlock命令の際にXACQUIREを付加し、最後にXABORTで締めてやるだけだ(Photo24)。従来だと複数のThreadがこのMutexでシリアライズされる形になっていたが、HLEを使うと各Threadは直ちにMutexを確保できたと理解して処理に移るので、処理が並行して行えることになり、性能が上がるという訳だ。

Photo24: これは複数スレッド間でmutexを使って同期を取るためのコードで、まずTryでlock xchgを使ってMutex書き換えを試し、成功したらSuccessに飛ぶが、失敗したらMutexの状態を見ながらひたすらループして待機し、Mutexが開放されたら再びMutex書き換えを試みるというものだ。

ただ勿論、中にはCritical Sectionをいじる為にMutexを使っている場合もあって、こうしたケースでHLEを使うとシステムが混乱する。このケースではRTMを使うことになる。この場合は通常のトランザクション制御と同じ形で記述されることになる(Photo25~27)。

Photo25: これが元コード。

Photo26: まずmutexを取得しに行き、失敗したらAbort:に分岐することになる。ここでEAXにTransaction失敗のステータスコードが入るので、これを判断してSpinでmutex獲得待ちとを行うというもの。

Photo27: xabortはtransactionそのものが失敗した(単にMutexが確保できないという意味ではなく)場合の処理となる。

このTSX命令を使うことによる性能の改善を模式図で示したのがPhoto28・29である。実データというよりは「こうなるだろう」的なデータだけに、あまり精度を求めても仕方が無いのだが、特にThread数が増えて同期を取る頻度が増すと、TSXによるトランザクション制御が有効、というのがIntelの説明である。

Photo28: 粗粒度の場合、並列処理が出来る分Thread数が多いと性能が上がりやすい。また細粒度でもTSXを使うことでトランザクション制御のオーバーヘッドを減らせる分、やはり性能が若干上がるとしている。

Photo29: 並列度を高めるためにはなるべくLock-Freeのアルゴリズムを使うほうが効果的であるが、ある程度のThread数になるとむしろ弊害が出てくる。なので、スケーラビリティを確保するためにはTSXを組み合わせてLockベースとしたほうが有効というのがここでの主張。

ところで安藤先生の記事の最後に実装方法に関する疑問があったが、今回もこれに直接答える資料はなかった。ただ、こちら(Photo30)の最後にL1を使って管理している事が示されていたのが唯一のヒントである。

Photo30: 安藤先生の疑問である"Write Bufferをどこにおくか"は今回も不明なままである。ただ、HELなりRTMなりのStateはL1(恐らくData L1)に置かれ、ここが溢れない限り幾らでもTransactionを生成できるということは明らかになった。

ということで、Haswellにおける命令拡張はこのあたりである。将来的には、TSXは例えばGPGPU的な処理にも利用できるかもしれないが、短期的にはXeonなど向けにのみ利用される事になるだろう。ただそのXeon向けのHaswellのSkewの話が今回のIDFでは(Technical Sessionを含めて)一切出てきてないあたり、折角拡張命令を定義しても当分利用できる機会がなさそうなのがちょっと残念ではある。

ということで次はGPUの話をご紹介したい。