12

x86/x64 での CAS の低レベルの仕組みを理解しようとしていますが、助けや洞察をいただければ幸いです。

私がこれについて考えてきた理由は、指数バックオフについて推論し、バックオフ遅延の正しい単一単位がどうあるべきかを原理的に理解しようとしているからです。

指数関数的バックオフなしでロックフリー フリーリスト ベンチマークを見ると、スレッド数が増えると、パフォーマンスが急速に横ばいになることがわかります。

Release 7 Lock-Free Freelist Benchmark #1

   M
   N
   S
  L3U
L2U L2U
L1D L1D
L1I L1I
 P   P
L L L L total ops,mean ops/sec per thread,standard deviation,scalability
0 0 0 1 310134488,31013449,0,1.00
0 1 0 1 136313300,6815665,38365,0.22

0 1 0 1 136401284,6820064,50706,0.22
1 1 1 1 111134328,2778358,23851,0.09

0 0 1 1 334747444,16737372,2421,0.54
1 1 1 1 111105898,2777647,40399,0.09

ご存知のように、各スレッドが他のスレッドの進行を妨げるライブロックが発生する可能性があります。

私の当初の考えは、今では間違っていると思いますが、CAS が CAS に干渉しているというものでした。つまり、CAS 命令自体が別の CAS と破壊的に衝突する可能性があります。どちらも失敗します。(おそらく、イーサネットについて考えていたからです)。

これは「明らかに」結果を説明しています - これらすべての CAS 命令は同時に動作しており、破壊的に中断される前に完全に実行される機会はほとんどありません。

もう少し考えてみると、そんなことはあり得ないと今では思っています。CAS 命令には、実際には障害モードがありません。宛先が比較対象と等しいか等しくないかがわかります。それで全部です。戻ってきて、「ああ、ごめんなさい、他の誰かにぶつかった」とは言いません。

破壊的な干渉は発生していますが、データ構造アルゴリズム自体のより高いレベルで発生しています。フリーリストから/へプッシュまたはポップするとき、実際にはスワップしようとしています。プッシュ/ポップを完了できるように、デスティネーションを読み取り、必要な作業を実行し、変更されていないことを確認できるように、デスティネーションが十分長く安定している必要があります。

他のスレッドが CASing を続けると、destination は安定せず、変化し続け、操作を再試行する必要が生じます。

しかし今、私は混乱しています。

1 つのスレッドが約 3,000 万回のプッシュ/ポップ操作を実行していることがわかります。操作が成功するためには、これらの操作のいずれかが実行されている間、宛先が安定している必要があるため、3,000 万の「スロット」があることがわかります。スレッドが 2 つある場合、理論上の最大パフォーマンスはスレッドあたり 1,500 万回です。各スレッドは半分のスロットを使用します。

では、CAS に戻りましょう。CAS には故障モードがありません。では、別のスレッドが既に CAS を実行しているときに、2 番目のスレッドが CAS を試行するとどうなるでしょうか? スワップが発生しなかったため、2 番目のスレッドはデータ構造レベルで失敗し、スワップを再試行します。

しかし、たくさんのスレッドがあると想像してください。CAS を開始する最初のスレッドは成功します (各 CAS にまったく同じ時間がかかると仮定すると、そうではありませんが、その仮定は基本的なものを何も変更しないため、推論しても問題ありません)。他のすべては失敗します。

ただし、最初のスレッドが終了すると、新しい宛先値を読み取る次のスレッドで CAS が成功します (さらに、まだ CAS を実行しているか、新しい CAS を開始している他のすべてのスレッドは失敗します)。

では、なぜ完全なスケーリングが見られないのでしょうか? すべての「スロット」を使用する必要があるためです。

そのため、私は CAS を正しく理解していないと思います。

Intel の Architecture Software Developer's Manual を読むと、すべてのデータがキャッシュに存在する場合 (私が興味を持っている状況)、キャッシュ コヒーレンシ プロトコルが CAS を処理することがわかりました。

Drepper は、彼のホワイト ペーパーで LL/SC と、MESI を使用してそれがどのように機能するかについて説明しています。

CAS が同様の方法で動作することは、私には理にかなっているように思えます。

2 スレッドの場合を考えてみましょう。最初のスレッドがその CAS を開始します。宛先を含むキャッシュ ラインはそのキャッシュ内にあり、排他的とマークされています。

2 番目のスレッドが CAS に開始されます。最初のコアはそのキャッシュ ラインを 2 番目のコアに送信し、両方のコアがそのキャッシュ ラインを共有とマークします。

最初のスレッドが CAS を完了し、キャッシュ ラインに書き込みます (比較が false であっても、x86/x64 では常に書き込みが発生します。元の値を書き込むだけです)。

書き込み動作は、キャッシュ ラインを変更済みとしてマークします。RFO が発生し、2 番目のコアがそのキャッシュ ラインを無効としてマークします。

2 番目のスレッドが CAS を完了するようになり、そのキャッシュ ラインが無効であることに気付きます。ARM の LL/SC ではアセンブリでこのループを実行する必要があるため、命令が成功するまで内部的にループされる CPU にあるとは信じがたいです。しかし、CAS 命令は宛先の値が変更されたことを認識しているため、その比較の結果は無効です。しかし、CAS でエラーが発生することはありません。比較に対して常に true または false を返します。しかし、命令が完了するまでループしたとしても、完璧なスケーリングが期待できます。各「スロット」は引き続き使用する必要があります。

それでどうなるの?CASに何が起こっているのですか?

私が見ているのは、スレッド数が増えるにつれて、実行される作業がますます少なくなるということです - 利用可能なすべての「スロット」は確実に使用されていません。何かがこれを引き起こしています。CAS命令間の破壊的干渉ですか?それとも、多数の RFO が CPU->ノースブリッジ バスを占有しているのでしょうか?

私が非常に興味深く注目しているのは、同じ物理コア上の 2 つのスレッドが完全にスケーリングされることです。その場合、何か特別で異なることが起こっています。別々の物理コア上の 2 つのスレッドも同様に半分にスケ​​ーリングされます。しかし、すべてを説明するには十分な手がかりではありません。

4

3 に答える 3

0

CASによると、あなたはLOCKCMPXCHGについて話していると思います

2番目のスレッドはCASを開始します。最初のコアはそのキャッシュラインを2番目のコアに送信し、両方のコアでそのキャッシュラインが共有とマークされます。

操作が開始され、中断され、続行されると思われるようです。CASは、メモリサブシステムに関してアトミックです。したがって、値を読み取り、比較し、一度に書き込みます。キャッシュラインを取得すると、別のコアへのキャッシュラインが失われるタイムスロットはありません。それはどのように機能しますか?命令の実行中にプロセッサロック信号を発生させるため、キャッシュラインが再び使用可能になるまで、他の命令がメモリサブシステムで停止します。そのため、CMPXCHG命令にLOCKプレフィックスがあります。詳細については、LOCKの説明を読むことができます。

したがって、発生する競合のほとんどは、L1がキャッシュラインの排他的所有権を取得しようとしているときに発生しますが、そのシグナルはほとんど常に発生します。L1にすでにキャッシュラインがある場合(同じコアに2つのスレッドがある場合など)、唯一の競合はCAS自体の期間であり、コア間のキャッシュラインメモリ転送は含まれません(すでに存在するため)。そして、それははるかに高速です。

于 2011-04-20T09:49:25.827 に答える
0

だから、私はこれをずっと考えてきました。

現在、CAS の処理方法について、「キャッシュ ロック」と MESI という 2 つの別々の提案があります。

この投稿は、純粋にキャッシュ ロックに関するものです。

キャッシュ ロックは、コアが特定のキャッシュ ラインをロックし、そのキャッシュ ラインで CAS を試行する他のコアが失速してもキャッシュが解放されると仮定します。

さらに、CAS は完了する前に常に結果をメモリに書き戻すとも考えています。

その理論を利用して、ベンチマークを見て結果を解釈してみましょう。

Release 7 Lock-Free Freelist Benchmark #1

   M
   N
   S
  L3U
L2U L2U
L1D L1D
L1I L1I
 P   P
L L L L total ops,mean ops/sec per thread,standard deviation,scalability
0 0 0 1 310134488,31013449,0,1.00
0 1 0 1 136313300,6815665,38365,0.22

0 1 0 1 136401284,6820064,50706,0.22
1 1 1 1 111134328,2778358,23851,0.09

0 0 1 1 334747444,16737372,2421,0.54
1 1 1 1 111105898,2777647,40399,0.09

したがって、最初にシングルスレッドのケースです。

L L L L total ops,mean ops/sec per thread,standard deviation,scalability
0 0 0 1 310134488,31013449,0,1.00

ここに最大のパフォーマンスがあります。すべての「スロット」は、単一のスレッドによって使用されます。

ここで、同じコア上に 2 つのスレッドがあります。

L L L L total ops,mean ops/sec per thread,standard deviation,scalability
0 0 1 1 334747444,16737372,2421,0.54

ここでももちろん同じ数の「スロット」があります - CAS は必要なだけの時間がかかります - しかし、それらは論理プロセッサ間で均等に分散されていることがわかります。意味あり; 1 つのコアがキャッシュ ラインをロックし、他のコアが停止し、最初のコアが完了し、2 番目のコアがロックを取得します。デスティネーションは L1 キャッシュに残り、キャッシュ ラインは変更された状態になります。宛先をメモリから再読み込みする必要はないので、その意味では 1 スレッドの場合と同じです。

これで、異なるコア上の 2 つのスレッドに到達しました。

L L L L total ops,mean ops/sec per thread,standard deviation,scalability
0 1 0 1 136401284,6820064,50706,0.22

ここで、最初の大幅な減速が見られます。理論上の最大スケーリングは 0.5 ですが、0.22 です。どうして?まあ、各スレッドは同じキャッシュラインを(もちろん独自のキャッシュで)ロックしようとしていますが、問題はコアがロックを取得したときに、メモリから宛先を再度読み取る必要があることです。行は、データのコピーを変更した他のコアによって無効とマークされます。そのため、実行しなければならないメモリ読み取りを遅くします。

これで、1 コアあたり 2 スレッドの 4 スレッドになりました。

L L L L total ops,mean ops/sec per thread,standard deviation,scalability
1 1 1 1 111105898,2777647,40399,0.09

ここでは、ops の総数が実際にはコアあたり 1 スレッドよりもわずかに少ないことがわかります。ただし、2 つではなく 4 つのスレッドがあるため、もちろんスケーリングははるかに悪くなります。

コアごとに 1 つのスレッドのシナリオでは、他のコアが CASing コアのキャッシュ ラインを無効にしているため、すべての CAS はメモリの読み取りから始まります。

このシナリオでは、コアが CAS を終了してキャッシュ ロックを解放すると、3 つのスレッドがロックをめぐって競合します。2 つのスレッドは別のコアで、1 つのスレッドは同じコアで競合します。したがって、3 分の 2 の時間は、CAS の開始時にメモリを再度読み取る必要があります。3 分の 1 の時間はそうではありません。

ですから、私たちはより速くなる必要があります。しかし、実際にはもっと遅いです。

0% memory re-reading gives 33,474,744.4 total ops per second (two threads, same core)
66% memory re-reading, gives 11,110,589.8 total ops per second (four threads, two per core)
100% memory re-reading, gives 13,640,128.4 total ops per second (two threads, one per core)

そして、これは私を困惑させます。観測された事実は理論に適合しません。

于 2011-04-22T14:22:03.803 に答える