2016-05-11 7 views
1

私は、CLHロックのスループットをテストするための簡単なプログラムを作成しました。 「マルチコアプログラミングの芸術」の本で説明したようなコードがあります。次に、変化するスレッド数で10秒間カウンタを実行し、スループットとしてカウンタ/ 10.0を定義しました。SpinLockのスケーラビリティと制限

私の質問は、私が得た結果が論理的な範囲内にあるかどうかと、それが彼らの方法である理由かもしれません。私はCLHロックのスループットの低下が非常に速いので尋ねます。 これはcLHロックの結果です。左はスレッド数を指定し、右はスループット(各スレッドがCLHロックで保護されたクリティカルセクションで1度インクリメントするサイズを10で割ったもの)です。

CLH 1 2.89563825E7 2 1.33501436E7 4 5675832.3 8 15868.9 16 11114.4 32 68.4

あなたはドロップオフは非常識であると私は何か他のものまでを台無しかもしれないことを考えさせる見たよう。

これは(それが上記の本であると同じように)CLHロックのために私のコードです:他の人がロックしようとしながら

static class CLHLock implements Lock { 
    AtomicReference<QNode> tail; 
    ThreadLocal<QNode> myNode, myPred; 

    public CLHLock() { 
     tail = new AtomicReference<QNode>(new QNode()); 

     this.myNode = new ThreadLocal<QNode>() { 
      protected QNode initialValue() { 
       return new QNode(); 
      } 
     }; 

     this.myPred = new ThreadLocal<QNode>() { 
      protected QNode initialValue() { 
       return null; 
      } 
     }; 
    } 

    public void lock() { 
     QNode qnode = this.myNode.get(); 
     qnode.locked.set(true);   

     QNode pred = this.tail.getAndSet(qnode); 
     myPred.set(pred);   
     while (pred.locked.get()) {}  
    } 

    public void unlock() { 
     QNode qnode = this.myNode.get(); 
     qnode.locked.set(false);  
     this.myNode.set(this.myPred.get()); 
    } 

    static class QNode { 
     public AtomicBoolean locked = new AtomicBoolean(false); 
    } 
} 

ランは10秒間待機しているメインスレッドで構成され、インクリメントその後、揮発性のブール値が時間が上がったことを知らせるまでロックを解除します。あなたのCLHロックの実装について

+1

私の経験では、ほとんどの劣化はスピンのCPUホギングに起因しています。 'while(pred.locked.get()){}'はおそらく 'while(pred.locked.get()){Thread.yield();}'ともっと社交的になります。違いはないので、コメントしてください。 – OldCurmudgeon

答えて

1

実装は忙しいスピンを除いて、かなり標準的に見えます。あなたはおそらく降伏または駐車(より少しコードを必要としますが)より良いです。あなたのベンチマークについて

は、そのパフォーマンス・テストからいくつかのコードの正しさについての判断

をもたらし、その正しさのテストからいくつかのコードの正しさについての判断と少なくとも同じくらいの知識を必要とするタスクです。

おそらく、コードに直接関係していない多数の副作用が観察されています。これらの影響を最小限に抑えるには、JMHのようなベンチマークツールを使用してください。そうしないと、コードではないものが測定されます。

はここで間違っている可能性があり、あなたの結果について、投機的な説明、ですが、全く説得力のある:

  • 1つのスレッドでは、ロックには競合が事実上ありませんので、あなたのコードは、非常に高速な実行と全くキャッシュがありませんスラッシング。おそらく、後で最適化を行わなくても早期に分岐予測が成功し、JITが蹴られて利益を得ることができます。
  • スレッド数が2と4の場合、スループットがいくらか低下します。まだハードウェアスレッドがあるので悪いことではありませんが、キャッシュスラッシング(誤った共有)、コヒーレンシトラフィック、ブランチミス予測(ベンチマークの共有インフラストラクチャのため)が発生するようになりました。並列実行からスループットが向上するわけではありませんが、それでも問題はありません。
  • スレッド数が8と16の場合、マシン上で使用可能なハードウェアスレッドの制限を超えています。 OSのスケジューリング効果、より重要なキャッシュ・スラッシング、コード内での重大な競合を経験し始めます。
  • 32スレッドでは、高速ハードウェアキャッシュ機構(L1キャッシュ、TLB)の限界を超え、次の最も速いメカニズムにダウングレードします。これを体験するためにキャッシュサイズの制限を超える必要はありませんが、アソシエイティビティの限界を超える可能性もあります。
関連する問題