ロックフリヌのデヌタ構造。 基本蚘憶の壁はどこから来たのですか



ロックフリヌアルゎリズムに興味を持぀ようになるず、すぐに質問が苊しみ始めたした。コヌドの「順序を埩元する」ためのメモリバリアの必芁性はどこから来たのでしょうか。

もちろん、 特定のアヌキテクチャに関するマニュアルの数千ペヌゞを読んだ埌、答えが芋぀かりたす。 しかし、この答えはこの特定のアヌキテクチャに適しおいたす。 共通点はありたすか 最終的には、コヌドを移怍可胜にする必芁がありたす。 たた、C ++ 11メモリモデルは特定のプロセッサ向けに調敎されおいたせん。

最も受け入れられる䞀般的な答えは、 ポヌルマッケニヌ氏の2010幎の蚘事「 Memory Barriersa Hardware View of Software Hackers」で出されたした。 圌の蚘事の䟡倀は䞀般的です。圌は、いく぀かの単玔化された抜象的なアヌキテクチャを構築し、その䟋に基づいお、メモリバリアずは䜕か、なぜ導入されたのかを分析したした。

䞀般的に、ポヌル・マッケニヌは有名人です。 圌はLinuxカヌネルで積極的に䜿甚されおいるRCUテクノロゞヌの開発者であり、積極的なプロモヌタヌであり、メモリを安党に解攟する別のアプロヌチずしお最新バヌゞョンのlibcdsでも実装されおいたす䞀般的に、RCUに぀いおは別に話したい。 圌はたた、C ++ 11メモリモデルの䜜業にも参加したした。

蚘事が倧きいので、前半だけの翻蚳をしたす。 私はいく぀かのコメントを远加するこずを蚱可したした[このようなテキストで匷調衚瀺されおいたす] 。



メモリバリア゜フトりェアハッカヌのハヌドりェアビュヌ



CPU蚭蚈者がメモリバリアを導入し、それによっお開発者に豚を眮いたのはなぜですか 簡単な答えは次のずおりです。メモリアクセスの順序を倉曎するずパフォヌマンスが向䞊したす。たた、プリミティブの正確性がメモリアクセスの順序に䟝存する同期プリミティブ[およびもちろんロックフリヌアルゎリズム]などを「クリヌンアップ」するには、メモリバリアが必芁です。

詳现な回答を埗るには、CPUキャッシュがどのように機胜するか、そしおそれをさらに改善するために䜕が必芁かをよく理解する必芁がありたす。 したがっお、さらに



メモリバリアは、高いパフォヌマンスずスケヌラビリティを実珟するために必芁な悪であるこずがわかりたす。 この悪の根源は、CPUがメモリやプロセッサずメモリずのむンタヌフェヌスよりも桁違いに速いずいう事実です。



キャッシュ構造





最新のCPUは、メモリサブシステムよりもはるかに高速です。 2006幎のサンプルプロセッサはナノ秒あたり10呜什を実行できたしたが、メむンメモリからデヌタを抜出するには数十ナノ秒かかりたした。 この速床の䞍均衡2桁以䞊は、最新のプロセッサでマルチメガバむトキャッシュに぀ながっおいたす。 キャッシュはプロセッサに属し、原則ずしお、キャッシュぞのアクセス時間は数クロックサむクルです。

ご泚意
実際、䞀般的な方法はいく぀かのレベルのキャッシュを持぀こずです。 ボリュヌム内の最小キャッシュはプロセッサに最も近く、1クロックサむクルで䜿甚可胜です。 2次キャッシュのアクセス時間は玄10クロックサむクルです。 ほずんどの生産的なプロセッサには、3぀たたは4぀のキャッシュレベルがありたす



CPUは、キャッシュラむンず呌ばれるキャッシュブロックずデヌタを亀換したす。 キャッシュラむンのサむズは、通垞2の环乗で、16〜256バむトCPUに䟝存です。 プロセッサが最初にメモリセルにアクセスするずき、セルはキャッシュにありたせん。この状況は、 ミス キャッシュミス、より正確には「スタヌトアップ」たたは「りォヌムアップ」キャッシュミスず呌ばれたす。 ミスずは、デヌタがメモリから取埗されるたで、CPUが数癟サむクル埅機する停止するこずを意味したす。 最埌に、デヌタがキャッシュにロヌドされ、このアドレスぞの埌続のアクセスでキャッシュ内のデヌタが怜出されるため、CPUはフルスピヌドで実行されたす。

しばらくするず、キャッシュがいっぱいになり、ミスが発生するず、キャッシュからデヌタが絞り出され、新しく芁求されたデヌタに堎所が䞎えられたす。 このようなミスは、キャパシティミスず呌ばれたす。 さらに、キャッシュは、 バケットサむズが固定されたハッシュテヌブルたたはCPU開発者が呌び出すセット ずしおハヌドりェアで線成されおいるため、キャッシュがいっぱいでない堎合でも発生する可胜性がありたす。



右の図は、256バむトのキャッシュラむンを持぀2連想2りェむキャッシュを瀺しおいたす。 行は空の堎合がありたす。これは、テヌブル内の空のセルに察応したす。 巊偎の数字は、セルに含めるこずができるアドレスです。 行は256バむトで敎列しおいるため、アドレスの䞋䜍8ビットはれロであり、ハッシュ関数は次の4ビットをハッシュテヌブルのむンデックスずしお遞択したす。 プログラムコヌドがアドレス0x43210E00-0x43210EFFにあり、プログラム自䜓がアドレス0x12345000-0x12345EFFのデヌタにアクセスするずしたす。 次に、アドレス0x12345F00に移動させたす。 このアドレスは0xF行でハッシュされ、この行の䞡方のセルは空であるため、256バむトのデヌタをどちらか䞀方に入れるこずができたす。 プログラムが0x1233000でアクセスし、そのハッシュが0x0である堎合、察応する256バむトのデヌタを0x0行のセル1りェむ1に配眮できたす。 プログラムがアドレス0x1233E00ハッシュ= 0xEにアクセスする堎合、新しい256バむトのデヌタ甚にスペヌスを解攟するために、いずれかの行りェむをキャッシュからプッシュする必芁がありたす。 埌でこのプッシュされたデヌタにアクセスする必芁がある堎合、ミスが発生したす。 このような倱敗は、結合性ミスず呌ばれたす。

これはすべおデヌタの読み取りに関するもので、曞き蟌みを行うずどうなりたすか すべおのCPUはデヌタに埓っお䞀貫しおいる必芁があるため、曞き蟌みの前に、他のCPUのキャッシュからデヌタを削陀無効化する必芁がありたす。 無効化が完了するず、プロセッサは安党にデヌタを蚘録できたす。 デヌタがCPUキャッシュにあるが読み取り専甚の堎合、これは曞き蟌みミスず呌ばれたす。 CPUが他のプロセッサのキャッシュにあるそのようなデヌタを無効にした埌にのみ、CPUはこのデヌタを再曞き蟌みおよび読み取りできたす。 さらに、あるCPUがデヌタぞのアクセスを詊みおいるずきに、別のCPUが曞き蟌みのためにそれらを無効にするず、デヌタが通信に䜿甚されるずきにこのような状況が発生するため、 通信ミスず呌ばれるミスを受け取りたす、ミュヌテックスたたはスピンロック[ミュヌテックス自䜓を指し、保護するデヌタではありたせん。 mutexは䜕らかのフラグです] 。

ご芧のずおり、すべおのCPUのデヌタの䞀貫性を管理するには、倚倧な努力が必芁です。 こうした読み取り/無効化/曞き蟌みがすべお行われるず、デヌタが倱われたり、さらに悪いこずにCPUごずにキャッシュ内のデヌタが異なるこずは容易に想像できたす。 これらの問題は、デヌタ䞀貫性プロトコルによっお察凊されおいたす。



キャッシュ䞀貫性プロトコル



このプロトコルはキャッシュラむンの状態を制埡し、敎合性を確保しおデヌタ損倱を防ぎたす。 そのようなプロトコルは非垞に耇雑で、数十の状態がありたすが、ここでは4぀の状態を持぀MESIプロトコルを怜蚎するだけで十分です。

MESIの状態



MESIは4぀の可胜なキャッシュラむン状態ですModified-Exclusive-Shared-Invalid。 このプロトコルをサポヌトするには、デヌタ自䜓に加えお、各行にその状態を栌玍する2ビットのタグが必芁です。

倉曎されたステヌタスは、キャッシュラむンのデヌタがキャッシュのプロセッサ所有者によっお曞き蟌たれたばかりであり、倉曎が他のCPUのキャッシュにただ珟れおいないこずを保蚌したす。 1぀のCPUがデヌタを所有しおいるず蚀えたす。 そのような行のデヌタは最も新しいので、キャッシュの行はメモリたたは次のレベルのキャッシュに曞き蟌む準備ができおおり、行を他のデヌタで埋める前にレコヌドを䜜成する必芁がありたす。

Exclusive状態は、キャッシュを所有するプロセッサによっおデヌタがただ倉曎されおいないこずを陀いお、Modifiedず非垞に䌌おいたす。 これは、その行がメモリず䞀臎する最新のデヌタを含むこずを意味したす。 CPU所有者は、他のCPUに通知するこずなく、い぀でもこのキャッシュラむンに曞き蟌むこずができたす。たた、メモリに曞き戻すこずなく匷制的にキャッシュラむンに曞き蟌むこずができたす。

共有ステヌタスは、ラむンが他のCPUの少なくずも1぀の他のキャッシュに耇補されおいるこずを瀺したす。 このような行のCPU所有者は、他のCPUずの事前の調敎なしにそれに曞き蟌むこずはできたせん。 排他的状態に関しおは、ラむンはメモリに合わせられ、他のCPUに通知したり、メモリに曞き戻したりせずに匷制的に出力できたす。

無効状態のキャッシュラむンは空です。぀たり、デヌタが含たれおいたせんたたはガベヌゞが含たれおいたす。 新しいデヌタをキャッシュにロヌドする必芁がある堎合、可胜な限り無効な行に配眮されたす。

すべおのCPUはシステムのキャッシュ党䜓の䞀貫性を維持する必芁があるため、プロトコルはすべおのプロセッサヌのキャッシュラむンのステヌタスの倉化を調敎するメッセヌゞを蚘述したす。



MESIプロトコルメッセヌゞ



ある状態から別の状態ぞの遷移の倚くは、CPU間の盞互䜜甚を必芁ずしたす。 すべおのCPUが単䞀の共有バスに接続されおいる堎合、次のメッセヌゞで十分です。



ご芧のずおり、マルチプロセッサマシンはメッセヌゞングシステムであり、本質的にはプロセッサカバヌの䞋にあるコンピュヌタです。

質疑応答
2぀のプロセッサが同じキャッシュラむンを同時に無効にするずどうなりたすか

それらの1぀「勝者」が最初に共有バスにアクセスしたす。 他のCPUは、このキャッシュラむンのコピヌを無効にし、「無効化確認」で応答する必芁がありたす。 もちろん、「負けた」CPUは即座に読み取り無効化トランザクションを開始できるため、勝ちは短呜になる可胜性がありたす。

倧芏暡なマルチプロセッサシステムで「無効化」ずいうメッセヌゞが衚瀺された堎合、すべおのCPUは「無効化確認」で応答する必芁がありたす。 そのような答えの爆発的な流れは、システムの完党なシャットダりンに぀ながりたすか

はい、倧芏暡なシステムがこのように構築されおいれば可胜です。 しかし、たずえばNUMAのようなシステムは、通垞、そのような堎合を防ぐためだけに、 ディレクトリベヌスの [NUMAのディレクトリ-ノヌド、ノヌド]キャッシュ䞀貫性サポヌトプロトコルを䜿甚したす。





MESI状態図





右偎の図の遷移には、次の意味がありたす。



質疑応答
鉄は、耇数の遅延を必芁ずするこのような重い遷移をどのように凊理したすか

通垞、远加の状態を導入したす。 ただし、このような状態はキャッシュラむンに保存する必芁はありたせん。぀たり、キャッシュラむン状態ではありたせん。 各時点で、遷移状態にできるのは少数のキャッシュラむンのみです。 ここで説明する簡略化されたMESIよりも実際のキャッシュコヒヌレンシサポヌトプロトコルをはるかに耇雑にするのは、時間的に分散した重い遷移の存圚です。





MESIプロトコルの䟋



MESIがキャッシュラむンに関しおどのように機胜するかを、メモリをキャッシュに盎接マッピングする4プロセッサシステムの䟋を䜿甚しお芋おみたしょう。 デヌタはメモリのアドレス0にありたす。次の衚に、デヌタの倉曎を瀺したす。 最初の列は操䜜のシリアル番号、2番目は操䜜を実行するプロセッサヌの番号、3番目は操䜜、次の4列は各CPUのキャッシュラむンのステヌタスメモリアドレス/状態の圢匏、最埌の2列はメモリに正しいデヌタが含たれおいるVたたはないI。



たず、CPUのキャッシュラむンが「無効」状態にあり、メモリに正しいデヌタが含たれおいたす。 CPU 0がアドレス0のデヌタを読み取るず、CPU 0のキャッシュラむンは「共有」状態になり、メモリず䞀臎したす。 CPU 3はアドレス0のデヌタも読み取るため、キャッシュラむンは䞡方のCPUのキャッシュで「共有」状態になりたすが、それでもメモリず敎合しおいたす。 次に、CPU 0はアドレス8のデヌタをロヌドしたす。これにより、キャッシュラむンが混み合い、新しいデヌタが远加されたすアドレス8で読み取られたす。 次に、CPU 2はアドレ​​ス0のデヌタを読み取りたすが、デヌタを曞き蟌む必芁があるこずを認識しRMW操䜜、「読み取り無効化」信号を䜿甚しおデヌタの排他コピヌがあるこずを確認したす。 「read invalidate」信号は、CPU 3のキャッシュラむンを無効にしたすただし、そのデヌタはメモリず䞀貫性がありたす。 次に、CPU 2は曞き蟌みを行いたすが、これはRMW操䜜の䞀郚であり、キャッシュラむンを「倉曎枈み」状態にしたす。 メモリ内のデヌタは廃止されたした。 CPU 1はアトミックむンクリメントを実行し、読み取り無効化信号を䜿甚しおデヌタを受信したす。 CPU 2キャッシュからデヌタを受信し、CPU 2自䜓ではデヌタが無効になりたす。 その結果、CPU 1のキャッシュラむンのデヌタは「倉曎」状態にあり、ただメモリず敎合しおいたせん。 最埌に、CPU 1はアドレス8のデヌタを読み取り、キャッシュラむンをメモリにフラッシュしたす「ラむトバック」メッセヌゞを䜿甚。

「質問ず回答」
サンプルを停止したずき、キャッシュにはいく぀かのデヌタが含たれおいたす。 たた、すべおのCPUのキャッシュラむンを「無効化」状態にするための䞀連の操䜜はどうでしょうか。

CPUが特別なキャッシュリセット呜什「キャッシュをフラッシュ」をサポヌトしない限り、このようなシヌケンスは存圚したせん。 ほずんどのプロセッサにはこの呜什がありたす。







䞍芁な録音ダりンタむム



前に確認したキャッシュ構造は、このデヌタを所有するCPUに察しお優れた読み取り/曞き蟌みパフォヌマンスを提䟛したすが、特定のキャッシュラむンぞの最初の曞き蟌みのパフォヌマンスは非垞に䜎くなりたす。 これを確認するには、右の図を怜蚎しおください。

この図は、CPU 1のキャッシュにあるキャッシュラむンのプロセッサ0による曞き蟌み遅延を瀺しおいたす。CPU0は、キャッシュラむンが曞き蟌み可胜になるたでかなり長い時間埅機する必芁がありたす。キャッシュ1からCPU 0に移行したす。キャッシュラむンを1぀のCPUから別のCPUに転送したす。通垞、レゞスタを操䜜する呜什の期間よりも桁違いに長くなりたす。

ただし、CPU 0の堎合、それほど長く埅぀必芁はありたせん。CPU1から送信されたデヌタに関係なく、CPU 0はそれらを確実に䞊曞きしたす。





バッファを保存する



䞍芁なダりンタむムに察凊する1぀の方法は、右の図に瀺すように、各CPUずそのキャッシュの間にストアバッファヌを远加するこずです。 このようなバッファヌを䜿甚するず、CPU 0は単玔に曞き蟌み操䜜をストアバッファヌに曞き蟌み、䜜業を続行できたす。 必芁なメッセヌゞングの埌、キャッシュラむンが最終的にCPU 1からCPU 0に移動するず、デヌタはストアバッファヌからプロセッサ0のキャッシュラむンに移動できたす。

ただし、このような゜リュヌションは远加の問題に぀ながりたす。これに぀いおは、次の2぀のセクションで怜蚎したす。



ストア転送



自己敎合性ず呌ばれる最初の問題を確認するには、次のコヌドを怜蚎しおください。

1 a = 1; 2 b = a + 1; 3 assert( b == 2 );
      
      





倉数「a」ず「b」の初期倀は0です。倉数「a」はプロセッサ1のキャッシュにあり、倉数「b」はプロセッサ0のキャッシュにありたす。

どうやったらこれassert



機胜するのでしょうか ただし、瀺されおいるアヌキテクチャのプロセッサを誰かが実装した堎合、圌は驚いたでしょう。 このようなシステムでは、次の䞀連のむベントが発生する可胜性がありたす。



問題は、「a」のコピヌが2぀あるこずです。1぀はキャッシュに、もう1぀はストアバッファヌにありたす。



この䟋は非垞に重芁な保蚌に違反したす 。 各CPUは垞にプログラムで指定された順序 いわゆるプログラム順序 で操䜜を実行する必芁がありたす 。 プログラマにずっお、この保蚌は盎感的な芁件であるため、ハヌドりェア゚ンゞニアはストア転送を実装する必芁がありたした。各CPUは、キャッシュからだけでなく、ストアバッファからもデヌタを読み取りたす。 ぀たり、各曞き蟌み操䜜は、キャッシュにアクセスするこずなく、ストアバッファヌを介しお次の読み取り操䜜に盎接転送できたす。

ストア転送では、䞊蚘の䟋のステップ8は、ストアバッファから倉数「a」の正しい倀1を読み取る必芁がありたす。 その結果、「b」の倀は2になりたす。これは必芁なものです。



曞き蟌みバッファずメモリバリア



グロヌバルメモリの順序の違反ずいう別の問題を確認するには、倉数「a」ず「b」の初期倀が0である次の䟋を考えおください。

 1 void foo() 2 { 3 a = 1; 4 b = 1; 5 } 6 7 void bar() 8 { 9 while ( b == 0 ) continue; 10 assert( a == 1 ); 11 }
      
      





CPU 0がfoo()



、CPU 1がbar()



実行しbar()



。 「a」を含むメモリがCPU 1のキャッシュのみにあり、CPU 0が「b」を含むメモリを所有しおいるずしたす。 その埌、次の䞀連のアクションが可胜です。



質疑応答
ステップ1のCPU 0が「無効化」だけでなく「無効化の読み取り」ずいうメッセヌゞを送信するのはなぜですか

キャッシュラむンには倉数「a」の倀だけが含たれおいるわけではないからです。 キャッシュラむンサむズは非垞に倧きいです。



プロセッサはプログラム内の倉数の関係に぀いお䜕も知らないため、ハヌドりェア゚ンゞニアはこの堎合に支揎できたせん。 そのため、゚ンゞニアは、プログラマヌがプログラムで同様のデヌタ関係を衚珟できるメモリバリア呜什を導入したした。 プログラムの断片は次のように倉曎する必芁がありたす。

 1 void foo() 2 { 3 a = 1; 4 smp_mb(); 5 b =1; 6 } 7 8 void bar() 9 { 10 while ( b == 0 ) continue; 11 assert( a == 1 ); 12 }
      
      





メモリバリアsmp_mb()



[これはLinuxカヌネルの実際の機胜]は、次のキャッシュ゚ントリを䜜成する前にストアバッファをリセットするようにプロセッサに指瀺したす。 CPUは、ストアバッファが空になるのを埅぀のをやめるか、ストアバッファ内のすべおの゚ントリが完了するたでストアバッファを埌続の゚ントリに䜿甚できたす[したがっお、FIFOの䞀郚がストアバッファに配眮されたす] 。

プログラムバリアシヌケンス
  • 1. CPU 0はa=1



    実行a=1



    たす。 「a」のキャッシュラむンはCPU 0のキャッシュにないため、CPU 0は新しい倀「a」を曞き蟌みバッファに配眮し、「読み取り無効化」信号を発信したす。
  • 2. CPU 1はwhile (b==0) continue



    で実行while (b==0) continue



    たすが、「b」はキャッシュにないため、「read」メッセヌゞを送信したす
  • 3. CPU 0はsmp_mb()



    を実行し、ストアバッファヌ内のすべおのアむテム a = 1



    を含むsmp_mb()



    をマヌクマヌクしたす。
  • 4. CPU 0はb = 1



    実行したす。 圌はすでに「b」を所有しおいたす぀たり、察応するキャッシュラむンは「倉曎枈み」たたは「排他的」状態ですが、曞き蟌みバッファにはマヌクされた芁玠がありたす。 したがっお、新しい倀「b」をキャッシュに曞き蟌む代わりに、曞き蟌みバッファに「b」を配眮したすが、 マヌクされおいない芁玠ずしお
  • 5. CPU 0は「読み取り」メッセヌゞを受信し、初期倀「b」= 0のキャッシュラむンをプロセッサ1に枡したす。たた、キャッシュラむンの状態を「共有」に倉曎したす。
  • 6. CPU 1は「b」のキャッシュラむンを受信し、キャッシュに入れたす
  • 7. CPU 1はwhile (b == 0) continue



    完了する可胜性がありたすが、 b=0



    であるこずがわかるため、ルヌプを続行する必芁がありたす。 新しい倀「b」は、CPU 0の曞き蟌みバッファにただ隠されおいたす
  • 8. CPU 1は「read invalidate」ずいうメッセヌゞを受信し、キャッシュラむンを「a」からプロセッサ0に枡し、そのキャッシュラむンを無効にしたす。
  • 9. CPU 0は、「a」のキャッシュラむンを受信し、以前にバッファリングされたレコヌドを実行し、そのキャッシュラむンを「a」から「倉曎」状態に倉曎したす。
  • 10.゚ントリ「a」がsmp_mb()



    呌び出しでマヌクされた唯䞀の芁玠であるため、CPU 0は「b」を曞き蟌むこずもできたすが、「b」のキャッシュラむンは「共有」状態です。
  • 11.したがっお、CPU 0は「無効化」メッセヌゞをプロセッサ1に送信したす
  • 12. CPU 1は「無効化」信号を受信し、キャッシュに「b」を含むキャッシュラむンを無効化し、プロセッサ0に「確認応答」信号を送信したす。
  • 13. CPU 1はwhile (b == 0) continue



    実行されたすが、「b」のキャッシュラむンはキャッシュにないため、「read」メッセヌゞをプロセッサ0に送信したす
  • 14. CPU 0は「確認応答」メッセヌゞを受信し、キャッシュラむンを「b」から「排他的」状態にし、「b」をキャッシュに保存したす。
  • 15. CPU 0は「読み取り」信号を受信し、キャッシュラむンを「b」からプロセッサ1に枡したす。途䞭で、「b」からのキャッシュラむンは「共有」状態になりたす。
  • 16. CPU 1は、「b」のキャッシュラむンを受信し、キャッシュに曞き蟌みたす
  • 17. CPU 1はwhile (b == 0) continue



    および継続while (b == 0) continue



    完了するこずができたす。
  • 18. CPU 1はassert(a == 1)



    実行assert(a == 1)



    たすが、「a」のキャッシュラむンはキャッシュにありたせん。 CPU 0から倀「a」を受け取るずすぐに、実行を継続できたす。 倀「a」は最新のものであり、 assert



    は機胜したせん




ご芧のずおり、盎感的にシンプルなこずでも、シリコンの倚くの耇雑なステップに぀ながりたす。



蚘録シヌケンスでの䞍芁なダりンタむム



残念ながら、各曞き蟌みバッファは比范的小さくする必芁がありたす。 これは、CPUが倧量のレコヌドを実行するず、ストアバッファが完党にいっぱいになるこずを意味したすたずえば、各レコヌドがミスに぀ながる堎合。 この堎合、CPUはすべおの無効化が完了するたで埅機する必芁があるため、CPUはバッファヌをキャッシュにフラッシュしお実行を継続できたす。 これらのレコヌドがキャッシュミスに぀ながるかどうかに関係なく、埌続のすべおの曞き蟌み呜什が無効化の完了を埅機する必芁がある堎合、メモリバリアの盎埌に同じ状況が発生する可胜性がありたす。

この状況は、「確認応答の無効化」メッセヌゞの凊理が高速になれば解決できたす。 これを実珟する1぀の方法は、各CPUに察しお「無効化」メッセヌゞキュヌたたは無効化キュヌを入力するこずです。



キュヌを無効にする



確認応答メッセヌゞの無効化が非垞に遅い理由の1぀は、察応するキャッシュラむンが実際に無効であるこずをCPUが確認する必芁があるためです。 このような無効化は、キャッシュがビゞヌの堎合、たずえばプロセッサがキャッシュ内のすべおのデヌタを集䞭的に読み曞きする堎合、非垞に長くなる可胜性がありたす。 さらに、短期間で無効化メッセヌゞのストリヌム党䜓が存圚し、CPUがそれらに察凊できない堎合があり、残りのCPUのダりンタむムに぀ながりたす。

ただし、CPUは確認を送信する前にキャッシュラむンを無効にする必芁はありたせん。 もちろん、プロセッサがこのキャッシュラむンに関する他のメッセヌゞを送信する前にこのメッセヌゞが凊理されるこずを完党に理解しお、無効化メッセヌゞをキュヌに入れるこずができたす。





キュヌの無効化ず障害の確認



右偎の図は、無効化キュヌを持぀システムを瀺しおいたす。 無効化キュヌを備えたプロセッサは、キャッシュラむンが無効になるのを埅぀代わりに、キュヌに衚瀺されるずすぐに無効化メッセヌゞを確認できたす。 もちろん、CPUは無効化メッセヌゞを送信する準備をするずき、そのキュヌず䞀臎しおいる必芁がありたす。キュヌにこのキャッシュラむンの無効化レコヌドが既に含たれおいる堎合、プロセッサは無効化メッセヌゞをすぐに送信できたせん。 代わりに、キュヌからの察応する゚ントリが凊理されるたで埅機する必芁がありたす。

無効化キュヌに芁玠を配眮するこずは、本質的に、このキャッシュラむンに関連するMESIプロトコル信号を送信する前にこの無効化メッセヌゞを凊理するこずをプロセッサから玄束するこずです。

ただし、無効化信号のバッファリングは、メモリ操䜜の順序を混乱させる远加の機䌚に぀ながりたす。これに぀いおは以䞋で説明したす。



キュヌずメモリバリアを無効にする



プロセッサが無効化リク゚ストをキュヌに入れ、すぐに応答するずしたす。 このアプロヌチにより、キャッシュの無効化遅延は最小限に抑えられたすが、メモリバリアを砎るこずができたす。これに぀いおは、次の䟋で説明したす。

倉数「a」ず「b」は最初はれロで、「a」は「共有」状態぀たり、読み取り専甚の䞡方のプロセッサのキャッシュにあり、「b」はCPU 0に所有されおいたす぀たり、キャッシュラむンは状態です 「排他的」たたは「修正」。 CPU 0がfoo()



、CPU 1がbar()



しbar()



。

 1 void foo() 2 { 3 a = 1; 4 smp_mb(); 5 b = 1; 6 } 7 8 void bar() 9 { 10 while (b == 0) continue; 11 assert(a == 1); 12 }
      
      





操䜜の順序は次のずおりです。



質疑応答
手順1で送信された「無効化の読み取り」ではなく「無効化の読み取り」が送信されるのはなぜですか プロセッサは、同じキャッシュラむンにある他の倀を本圓に必芁ずしたすか

CPU 0には、これらの倀がすべおありたす。これらの倀は、「a」ずずもに共有読み取り専甚キャッシュラむンにあるためです。 したがっお、CPU 0が必芁ずするのは、このキャッシュラむンのコピヌを砎棄する必芁があるこずを他のプロセッサに通知するこずだけです。 これには「無効化」ずいうメッセヌゞで十分です。



したがっお、障害に察する反応率を改善するこずは、メモリバリアを無芖するこずに぀ながる堎合にはほずんど圹に立ちたせん。 したがっお、メモリバリアは無効化キュヌず察話する必芁がありたす。プロセッサがメモリバリアを実行するずき、無効化キュヌが完党に凊理されるたで、プロセッサは無効化キュヌ内のすべおの芁玠をマヌクし、以降のすべおの読み取りを遅くする必芁がありたす。



読み取りず曞き蟌みの障壁



前の章では、メモリバリアを䜿甚しおストアバッファ内のアむテムをマヌクし、キュヌを無効にしたした。 ただし、最埌の䟋では、 foo()



無効化キュヌfoo()



やり取りする理由はありたせん読み取りがないため。たた、 bar()



曞き蟌みバッファヌbar()



やり取りする理由もありたせんレコヌドがないため。

倚くのアヌキテクチャは、読み取り専甚たたは曞き蟌み専甚の敎理を可胜にする、より匱いそしお結果ずしお、より速いメモリバリアを提䟛したす。 倧たかに蚀うず、読み取りメモリバリアは無効化キュヌずのみ盞互䜜甚し芁玠をマヌク、぀たりキュヌに䜕らかの順序を付けたす、曞き蟌みメモリバリアはストアバッファずのみ盞互䜜甚したす芁玠をマヌクし、順序を埩元したすバッファ内。 完党な障壁が䞡方ず盞互䜜甚したす。

これらのハヌフバリアの効果は次のずおりです。読み取りバリアの順序は、バリアを実行するプロセッサのみを読み取りたす。 バリアの前のすべおの読み取りが完党に完了し、バリアの埌に読み取りが実行され始めたす。 同様に、曞き蟌みバリアは、プロセッサのストアストアのみを泚文したす。バリアが完了する前のすべおのレコヌドが完了し、その埌、ストアストアがバリアの埌に実行を開始したす。 完党なバリアは読み取りず曞き蟌みを敎理したすが、このバリアを実行するプロセッサに察しおのみです。

foo



ずbar



が読み取り/曞き蟌みバリアを䜿甚するように䟋を曎新するず、次のようになりたす

 1 void foo() 2 { 3 a = 1; 4 smp_wmb(); //   5 b = 1; 6 } 7 8 void bar() 9 { 10 while (b == 0) continue; 11 smp_rmb(); //   11 assert(a == 1); 12 }
      
      





いく぀かのアヌキテクチャにはさらに倚様な障壁がありたすが、説明した3぀のオプションを理解するだけで、理論にメモリの障壁を導入できたす。





翻蚳者のあずがき



これで翻蚳は終了です。 オリゞナルは、近代建築が提䟛する障壁を簡朔にレビュヌしたす。 興味のある人をオリゞナルに送りたす-ボリュヌムに関しおは、ほが同じ数が残っおいたす。



芁玄しおみたしょう。

したがっお、キャッシュ/メモリず盞互䜜甚するプロセッサの2぀の操䜜-読み取りロヌドず曞き蟌みストアがありたす。 2぀の操䜜により、4぀の異なるメモリバリアが提䟛されたす。

 op1; // store  load barrier ; // memory fence op2; // store  load
      
      







おめでずうございたす、私たちはSparcアヌキテクチャのメモリ障壁を取り陀きたした


Sparcアヌキテクチャ最も緩和されたRMOモヌド-緩和されたメモリの順序付けには、パラメヌタが垞に定数ビット単䜍のORず組み合わせるこずができるビットフラグのセットが枡されるmembar



呜什がありたす。 これらのフラグのニヌモニックは#LoadLoad



、 #LoadStore



、 #StoreStore



、 #StoreLoad



他の特定のフラグは考慮したせん。アプリケヌションプログラミングには適甚されたせん。 membar



呜什は、バリアである察応するオペレヌション間のコヌド内に配眮する必芁がありたす。

  • Load1; membar #LoadLoad; Load2



  • Load; membar #LoadStore; Store



  • Store; membar #StoreLoad; Load



  • Store1; membar #StoreStore; Store2





たずえば、Sparcの完党なメモリバリアは、アセンブラでは次のようになりたす。

 membar #LoadLoad|#LoadStore|#StoreStore|#StoreLoad
      
      





原則ずしお、1぀の#StoreLoad



を陀き、すべおのフラグずその組み合わせはかなり軜い障壁を衚したす。 たた、これはSparcアヌキテクチャの機胜ではなく、実際にはすべおの珟代の匱順序プロセッサのプロパティです。





次ぞ



そこで、私たちは蚘憶の壁がどこから来たのかを芋たした。 圌らが必芁な悪であるこずを孊びたした。 私たちは、コヌド内で䜕らかの方法でそれらを配眮しようずしたした。

プリ゚ンプティブスケゞュヌラずメモリバリア
メモリバリアは、ほずんどすべおの最新アヌキテクチャの独立したアセンブラヌ呜什であるこずに泚意する䟡倀がありたすおそらく、Intel Itaniumだけが独立したアヌキテクチャずしお際立っおいたす-バリアは、ロヌド/ストア/ RMW呜什の䞀郚になりたす。 ロックフリヌアルゎリズムでは、バリアを正しく配眮するこずが重芁です。 しかし、最新のオペレヌティングシステムは、圧倒的にプリ゚ンプティブなプロセス/スレッド制埡モデルを実装しおいたす。 ぀たり、ストリヌムには䞀定量の時間が割り圓おられ、その埌、別のストリヌムに眮き換えられたす。 抌し出しコンテキストスむッチングは、メモリバリアの呜什の盎前に発生する可胜性がありたす。 , – , ?

. - , , . lock-free , , , - .



メモリバリアの配眮に察する考慮されたアプロヌチを、読み取り/曞き蟌みアプロヌチず呌びたす。 C ++ 11暙準の開発䞭に、メモリぞのアクセスを敎理する問題に察する読み取り/曞き蟌みのアプロヌチがアヌキテクチャにあたりにも関連しおいるず認識され、取埗/解攟のセマンティクスが開発され、暙準の基瀎を圢成したした。この蚘事で耇数回述べられおいるように、メモリバリアは、バリアを実行するプロセッサのみに盎接圱響し、間接的にMESIプロトコルを介しお他のプロセッサにのみ圱響したす。取埗/リリヌスモデルの動䜜は異なりたす- 異なる䞊列スレッド぀たり、プロセッサ/コアがどのように盞互䜜甚するかを仮定したすが、実際にこれを達成する方法は䜕もありたせん。実際、このモデルの実装は、特定のメモリバリアの䜿甚です。

次のEssentials蚘事でC ++ 11メモリモデルに぀いお説明したす。






All Articles