4

ARM で LL/SC を使用して、ロックフリー データ構造ライブラリの次のリリースに取り組んでいます。

LL/SC の私のユースケースでは、LDREX と STREX の間の単一の STR で使用する必要があります。(CAS をエミュレートするために使用するのではなく)。

今、私はコードを書きました、そしてこれはうまくいきます。しかし、私が懸念しているのは、それが常に機能するとは限らない可能性です. LL/SC ターゲットと同じキャッシュ ラインにアクセスすると、LL/SC が壊れるという PowerPC に関する記事を読みました。

したがって、STR ターゲットが LL/SC ターゲットと同じキャッシュ ラインにある場合、私は死んでいると考えています。

現在、LL/SC ターゲットと STR ターゲットは常に異なる malloc() にあるため、それらが直接同じキャッシュ ラインにある可能性はおそらく小さいです (そして、LL/SC ターゲットをパディングして開始することでこれを保証できます)。キャッシュ ライン境界を埋め、そのキャッシュ ラインを埋めます)。

しかし、STR ターゲットがメモリ内の適切な (間違った!) 場所にある場合、誤った共有が発生する可能性があります。

LDREX/STREXのドキュメントを見ると、これは「物理アドレス」の観点から排他的アクセスを説明しています。これは、キャッシュ ライン幅の粒度ではなく、レジスタ幅の粒度を意味します。

それが私の質問です。LDREX/STREX は、レジスタ幅の粒度またはキャッシュ ライン幅の粒度を使用したメモリ アクセスに敏感ですか?

4

2 に答える 2

2

ARM は排他的モニターを使用して、ロードリンク/ストア条件によるメモリへの排他的アクセスを実装します。[1] にはすべての詳細が含まれていますが、ここで重要なのは次のことです。

エクスクルーシブ予約グラニュール

排他的モニターがアドレスにタグを付ける場合、排他的アクセス用にタグ付けできる最小領域は、Exclusives Reservation Granule (ERG) と呼ばれます。ERG は、2 バイトの倍数で、8 ~ 2048 バイトの範囲で実装定義されます。移植可能なコードは、ERG サイズについて何も想定してはなりません。

だから、私が見ているように、あなたはそこでちょっと運が悪い. とにかく、ほとんどの実際の実装はおそらく小さな値を保持しますが、私が知る限り、基本的なARMアーキテクチャでは保証されていません. :) それでも、LL/SC のすべての実装は何らかの形式の弱い LL/SC であるため、LL と SC の間のストアが常に SC を強制終了しない、またはほとんど当時、またはおそらく決して... アーキテクチャと実装に大きく依存しているため、私は個人的にLL / SCを使用してCASをタイトループで実装し、それを通常どおり使用して完了します。

[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/CJAGCFAF.html

于 2012-05-30T11:11:24.453 に答える
1

注意してください、LDREX/STREX は、多くの人が考えていることを実行しません。これらはマルチプロセッサ システム用です。ユニプロセッサ システムでは、スワップの使用を検討する必要があります。通常、ARM のドキュメントは非常に優れていますが、この特定のケースでは大きなギャップがあります。Linux はこれらの命令を不適切に使用しており、ユニプロセッサ ARM コアを持つ企業によって指摘されています (Linux には、人々が適切な調査なしにコードを追加したため、多くの ARM 関連のバグがあり、出てくるすべてのバージョンを修復する必要があります)。ユニプロセッサ システムに L1 キャッシュがある場合、キャッシュはそのアクセス タイプをサポートしているので問題ありません。AXI バスにヒットした場合、AMBA/AXI 仕様はハードウェア エンジニアに、ユニプロセッサ システムではそのトランザクション タイプをサポートする必要がないことを伝えています。残念ながら、ARM ARM/TRM は、スワップの使用をやめて LDREX/STREX の使用を開始する必要があることをソフトウェア エンジニアに伝えています。

これはあなたの質問に対する答えではなく、適切な使用法と関連するリスクについて人々を教育しようとする指示に関する一般的な情報です. (はい、そこにいた、終わった、それらの指示の使用によってやけどを負った、Linuxにパッチを当てる必要がありました(他のLinuxパッチの上に))

編集....詳細

ARM ARM では:

Historically, support for shared memory synchronization has been with the read-locked-write operations
that swap register contents with memory; the SWP and SWPB instructions described in...

...

ARMv6 provides a new mechanism to support more comprehensive non-blocking shared-memory synchronization primitives
that scale for multiple-processor system designs.

...

The swap and swap byte instructions are deprecated in ARMv6. It is recommended that all software
migrates to using the new synchronization primitives.

...

Uniprocessor systems are only required to support the non-shared memory model, allowing them to support
synchronization primitives with the minimum amount of hardware overhead.

...

Multi-processor systems are required to implement an address monitor for each processor.


STREX:

<Rd> Specifies the destination register for the returned status value. The value returned is:
0  if the operation updates memory
1 if the operation fails to update memory.


MemoryAccess(B-bit, E-bit)
if ConditionPassed(cond) then
  processor_id = ExecutingProcessor()
  physical_address = TLB(Rn)
  if IsExclusiveLocal(physical_address, processor_id, 4) then
    if Shared(Rn) == 1 then
      if IsExclusiveGlobal(physical_address, processor_id, 4) then
        Memory[Rn,4] = Rm
        Rd = 0
        ClearExclusiveByAddress(physical_address,processor_id,4)
      else
        Rd = 1
    else
      Memory[Rn,4] = Rm
      Rd = 0
  else
  Rd = 1
ClearExclusiveLocal(processor_id)

AMBA/AXI仕様

The ARLOCK[1:0] or AWLOCK[1:0] signal selects exclusive access, and the RRESP[1:0] 
or BRESP[1:0] signal (see Table 7-1 on page 7-2) indicates the success or failure 
of the exclusive access.

...

If the master attempts an exclusive read from a slave that does not support exclusive
accesses, the slave returns the OKAY response instead of the EXOKAY response. The
master can treat this as an error condition indicating that the exclusive access is not
supported. It is recommended that the master not perform the write portion of this
exclusive operation.

...

b00 OKAY
b01 EXOKAY

...

ARLOCK/AWLOCK

b00 normal access
b01 exclusive access

したがって、ソフトウェア側では、ARM ARM はスワップの代わりに LDREX/STREX を使用するように言っています。しかし、ユニプロセッサ システムは共有メモリ同期をサポートする必要がないことも示しています。したがって、ソフトウェア側からでも、よく考えるべき手がかりがあります...

STREX の説明から、排他的な rd = 0 が返された場合に機能することがわかります。rd = 1 の場合、排他的ではありません (またはその他の理由)。LDREX と STREX はペアで実行され、共有メモリ システム ロジックは同じアドレスでペアを検索し、ハードウェアはこの 2 つの間にそのアドレスへの他のアクセスがなかったことを確認します。2人の間に誰が入るのを心配していますか? 1)割り込み/スワップを行い、非常に幸運な場合 2)そのメモリを使用している別のプロセッサ。私が覚えている限り、Linux が行うことは、タイトな無限ループに入ることです。

while(1)
{
  ldrex
  strex
  if(rd==0) break;
}

現在、ユニプロセッサ システムでは、共有アクセスをサポートする必要がないという ARM ARM の提案は、より単純であるためです (なぜその複雑さを追加する必要があるのでしょうか?)。

あなたがプログラマーとして見ていないもの。ldrex と strex に対して ARLOCK または AWLOCK が設定されています。共有アクセスを実装している場合は、これらのビットに注意してください。共有アクセスを実装している場合、2 つの間にアクセスがなければ、EXOKAY を strex に返します。EXOKAY は b01 であり、strex 疑似コードでは排他的グローバルであり、rd = 0 です。ハードウェアが OKAY、b00 を返す場合、それは排他的ではなく、strex に対して rd = 1 です。次に、AMBA/AXI 仕様では、共有システムをサポートしていない場合、排他的アクセスに対して OKAY を返しても問題ないと述べています。そのため、排他的アクセスを実装していないユニプロセッサでは、strex は常に OKAY を返すことができます。また、EXOKAY を返すことはありません。これは、strex が rd = 0 になることはなく、Linux が無限ループでハングすることを意味します。

ここでの Linux の真のバグは、当時見たコードで、(ARMv6 以降) の場合は LDREX/STREX を使用し、それ以外の場合は SWP を使用すると述べていたことです。(ARMv6 以降およびマルチプロセッサ) の場合は LDREX/STREX を使用し、それ以外の場合は SWP を使用してバグを修正します。

これは、このチケットで私の目を引いた他の理由で LDREX/STREX を使用したい他の人に翻訳されます。

ここで、キャッシュはそれと何の関係があるのでしょうか? L1 キャッシュはプロセッサ コア内にあり、AXI/AMBA バスには出力されません。strex に対して EXOKAY を返すか、共有を完全に実装します。したがって、L1 キャッシュがオンになっている場合は、EXOKAY が発生します (初めてか、最終的にはわかりません)。

キャッシュ ミスが発生した場合はどうなるでしょうか。まず、L1 キャッシュがオフの場合、キャッシュ可能なビットがオンにならずに L2 キャッシュ境界にヒットします。そのため、L2 キャッシュはそれをそのまま渡し、排他的として出ます。L1 キャッシュがオンの場合、ヒットすると、上記のように EXOKAY が返されます (最終的にまたは常に、わかりません) L1 がミスの場合、L1 はキャッシュ ライン フィルを実行し、キャッシュ可能な NOT LOCKED 読み取りを実行します。これにより、L2 がヒットまたはミスします。L2 がミスした場合、ベンダー固有のロジックに送信され、この場合は OKAY が返されますが、LOCKED ではなく通常のアクセスであったため問題ありません。l2 と l1 が満たされると、L1 は元の転送を実行し、EXOKAY を返します。

ここにキッカーがあります。まず、これをハードウェアに実装するのは無駄であり、リスクがあるため、ユニプロセッサ ARMv6 以降は EXOKAY を返さないと予想されます。ケースバイケースでテストする必要があります。2 つ目は、キャッシュをオフにして Linux を実行するのは PITA です。実際には少し手間がかかりました。そのため、通常、Linux でこれを目にすることはほとんどありません。しかし、問題はそこにあります。人々はそれを見てきました。これらの指示を自分で使用するときはいつでも、それらを適切に使用するように注意する必要があります. ベアメタル プログラミングを使用してシステムがハングするかどうかをテストするのは非常に簡単で、コードを記述するのに数秒または数分かかるはずです。システムをそのコードを試すことができる状態にする (ブートローダーを中断する、jtag を使用してジャンプするなど) には、より長い時間がかかる可能性があります。

于 2012-05-30T14:36:39.120 に答える