Компиляция IORef и STRef

Чтобы измерить производительность этих ссылок, я поместил сборку, созданную GHC, в следующий код:

import Data.IORef

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

Я ожидал, что IORef будет полностью оптимизирован, оставив только системный вызов для записи stdout со строкой "18". Вместо этого я получаю 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?

1 ответ

Решение

Начиная с пары ссылок:

cmm а также C источники не особенно читабельны, если вы еще не знакомы с макросами и праймпами. К сожалению, я не знаю хорошего способа просмотра сборки, сгенерированной для cmm primops, если не смотреть на исполняемый файл с помощью objdump или другого дизассемблера.

Тем не менее, я могу обобщить семантику времени выполнения IORef,

IORef это обертка вокруг MutVar# от GHC.Prim, Как говорит док, MutVar# это как одноэлементный изменяемый массив. Он занимает два машинных слова, первое - заголовок, второе - сохраненное значение (которое является указателем на объект GHC). Значение MutVar# сам по себе является указателем на этот объект из двух слов.

MutVar -s отличаются от обычных неизменяемых объектов наиболее заметно тем, что участвуют в механизме барьера записи. GHC имеет сборку мусора поколений, поэтому любой MutVar который живет в старшем поколении, должен также быть корнем GC при сборе младшего поколения, поскольку MutVar может привести к тому, что более молодые объекты станут доступными. Поэтому всякий раз, когда MutVar продвигается из поколения 0 (самое молодое), оно добавляется в так называемый "изменяемый список", который содержит ссылки на все такие изменяемые объекты. Изменяемый список перестраивается во время GC старых поколений. Короче, MutVar -s в старых поколениях всегда присутствуют в списке изменяемых.

Это довольно упрощенный способ работы с изменяемыми переменными, и если у нас их много в старых поколениях, незначительная сборка мусора замедляется из-за раздутого изменяемого списка, и в результате вся программа замедляется.

Поскольку изменяемые переменные не используются в производственном коде на видном месте, не было особого спроса или давления для оптимизации RTS для их интенсивного использования.

Если вам нужно большое количество изменяемых переменных, вам следует вместо этого использовать один изменяемый массив в штучной упаковке, потому что это всего лишь одна ссылка в списке изменяемых элементов, а также имеется оптимизация на основе растровых изображений для обхода элементов GC, которые могли быть изменены.

Кроме того, как вы видите newMutVar# является только статически связанным, но не встроенным, хотя это довольно небольшой кусок кода. В результате это также не оптимизировано далеко. Это опять-таки в основном из-за отсутствия усилий и внимания для оптимизации изменяющегося кода. В отличие от этого, выделение и копирование небольших примитивных массивов известного размера в настоящее время встроено и значительно оптимизировано, потому что Йохан Тибелл, который проделал большую работу по реализации unordered-containers библиотека сделала это так (чтобы сделать unordered-containers Быстрее).

Другие вопросы по тегам