当前位置 : 主页 > 网络安全 > 测试自动化 >

性能 – IORef和STRef的汇编

来源:互联网 收集:自由互联 发布时间:2021-06-22
为了测量那些Refs的性能,我将GHC生成的组件转储到以下代码中: import Data.IORefmain = do r - newIORef 18 v - readIORef r print v 我期望IORef完全被优化掉,只留下一个系统调用来写字符串“18”的std
为了测量那些Refs的性能,我将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符号的情况下转储最终的程序集吗?

从几个链接开始:

> The MutVar object definition.
> The cmm code for newMutVar.
> A non-comprehensive but helpful summary of GHC object layout.

如果您还不熟悉macros和primops,则cmm和C源代码不是特别易读.不幸的是,我不知道查看为cmm primops生成的程序集的好方法,而不是查看可执行文件objdump或其他一些反汇编程序.

不过,我可以总结一下IORef的运行时语义.

IORef是GHC.Prim在MutVar#左右的包装.正如文档所说,MutVar#就像一个单元素的可变数组.它占用两个机器字,第一个是标题,第二个是存储值(它是指向GHC对象的指针). MutVar#的值本身就是指向这个双字对象的指针.

MutVar-s与普通的不可变对象不同,最显着的是通过参与写屏障机制. GHC具有分代垃圾收集功能,因此任何生活在老一代的MutVar在收集年轻代时都必须是GC根,因为改变MutVar可能会导致更年轻的对象变得可达.因此,每当从第0代(最年轻的)推广MutVar时,它就会被添加到所谓的“可变列表”中,该列表包含对所有此类可变对象的引用.可变列表在旧世代的GC期间重建.简而言之,老一代的MutVar-s总是存在于可变列表中.

这是处理可变变量的一种相当简单的方法,如果我们在旧代中有大量的变量,那么由于膨胀的可变列表而导致较小的垃圾收集速度减慢,结果是entire program slows down.

由于可变变量在生产代码中没有显着使用,因此对于RTS的大量使用进行优化的需求和压力并不大.

如果你需要大量的可变变量,你应该使用一个可变的盒装数组,因为这只是可变列表上的一个引用,并且还有一个bitmap-based optimization用于GC遍历可能已经变异的元素.

另外,正如您所看到的那样,newMutVar#只是静态链接但没有内联,尽管它只是一小块代码.因此,它也没有被优化掉.这又是因为缺乏优化变异代码的努力和注意力.相比之下,分配和复制小的已知大小的原始数组目前是inlined并且进行了大大优化,因为执行unordered-containers库的大量工作的Johan Tibell就这样做了(为了使无序容器更快).

网友评论