5

これらの Ref のパフォーマンスを測定するために、次のコードで GHC によって生成されたアセンブリをダンプしました。

import Data.IORef

main = do
  r <- newIORef 18
  v <- readIORef r
  print v

IORef が完全に最適化され、文字列 "18" を stdout に書き込むシステムコールのみが残されると予想していました。代わりに、250 行のアセンブリを取得します。実際に何人が処刑されるか知っていますか?これが私がプログラムの核心だと思うものです:

.globl Main.main1_info
Main.main1_info:
_c1Zi:
    leaq -8(%rbp),%rax
    cmpq %r15,%rax
    jb _c1Zj
_c1Zk:
    movq $block_c1Z9_info,-8(%rbp)
    movl $Main.main2_closure+1,%ebx
    addq $-8,%rbp
    jmp stg_newMutVar#
_c1Zn:
    movq $24,904(%r13)
    jmp stg_gc_unpt_r1
.align 8
    .long   S1Zo_srt-(block_c1Z9_info)+0
    .long   0
    .quad   0
    .quad   30064771104
block_c1Z9_info:
_c1Z9:
    addq $24,%r12
    cmpq 856(%r13),%r12
    ja _c1Zn
_c1Zm:
    movq 8(%rbx),%rax
    movq $sat_s1Z2_info,-16(%r12)
    movq %rax,(%r12)
    movl $GHC.Types.True_closure+2,%edi
    leaq -16(%r12),%rsi
    movl $GHC.IO.Handle.FD.stdout_closure,%r14d
    addq $8,%rbp
    jmp GHC.IO.Handle.Text.hPutStr2_info
_c1Zj:
    movl $Main.main1_closure,%ebx
    jmp *-8(%r13)

私はこれについて心配していjmp stg_newMutVar#ます。アセンブリのどこにもないので、GHC は後のリンク段階でそれを解決するかもしれません。しかし、なぜここにあり、何をするのでしょうか? 未解決の haskell シンボルなしで最終的なアセンブリをダンプできますか?

4

1 に答える 1

11

いくつかのリンクから始めます。

マクロprimopsに慣れていない場合、 と ソースは特に読みにくいcmmものです。残念ながら、objdumpやその他の逆アセンブラを使用して実行可能ファイルを調べる以外に、primops用に生成されたアセンブリを表示する良い方法を知りません。Ccmm

それでも、 のランタイム セマンティクスを要約することはできますIORef

IORefMutVar#からのラッパーGHC.Primです。ドキュメントが言うMutVar#ように、単一要素の可変配列のようなものです。これは 2 つの機械語を使用します。1 つ目はヘッダー、2 つ目は格納された値 (GHC オブジェクトへのポインター) です。の値は、MutVar#それ自体がこの 2 語オブジェクトへのポインターです。

MutVar-s は通常の不変オブジェクトとは異なり、特に書き込みバリア メカニズムに参加しています。GHC には世代別のガベージ コレクションがあるためMutVar、古い世代に存在するものは、若い世代を収集するときにも GC ルートでなければなりませんMutVar。したがって、a が世代 0 (最年少) から昇格するたびに、そのMutVarようなすべての可変オブジェクトへの参照を含む、いわゆる「可変リスト」に追加されます。変更可能なリストは、古い世代の GC 中に再構築されます。要するに、MutVar古い世代の -s は常に変更可能なリストに存在します。

これは、可変変数を処理するかなり単純な方法であり、古い世代に多数の変数がある場合、肥大化した可変リストのためにマイナー ガベージ コレクションが遅くなり、その結果、プログラム全体が遅くなります .

ミュータブル変数は本番コードでは目立って使用されないため、頻繁に使用するために RTS を最適化する必要性や圧力はあまりありませんでした。

多数の変更可能な変数が必要な場合は、代わりに単一の変更可能なボックス配列を使用する必要があります。これは、変更可能なリストの単一の参照にすぎず、変更された可能性のある要素の GC トラバーサルのビットマップ ベースの最適化も備えているためです。

また、ご覧newMutVar#のとおり、コードのかなり小さなチャンクですが、静的にリンクされているだけでインライン化されていません。その結果、最適化されていません。これも、変化するコードを最適化するための努力と注意が不足しているためです。対照的に、サイズが既知の小さなプリミティブ配列の割り当てとコピーは現在インライン化されており、大幅に最適化されています。これは、ライブラリの実装に多大な労力を費やしたJohan Tibellが (高速化unordered-containersのために) そのようにしたためです。unordered-containers

于 2016-08-29T10:23:21.850 に答える