Microsoft的.net CLR是否在运行时内联小功能?

时间:2012-05-04 18:22:42

标签: .net optimization f#

是否存在此功能?像Java HotSpot在服务器模式下运行,但是用于.Net应用程序。

修改 更多信息。我有一个小应用程序(用F#编写),我有很多小函数。像这样:

let printable b =
    if b >= ' 'B && b <= '~'B
    then b else '.'B

我已经意识到性能很差,在分析后我发现每个这样的功能都被称为数百万次。我做了inline并且提升了性能(5次以上,可能更多)。

好的,好的。现在表现很好。但为什么框架没有呢?它有足够的关于我的代码的信息以及调用函数的频率。为什么它没有内联一个被称为1M次的函数?

EDIT2: 用于测量内联函数差异的样本测试:

    open System

    let printableByte b =
        if b >= ' 'B && b <= '~'B
        then b else '.'B

    let foo (arr : byte[]) = 
        for i in 0..arr.Length-1 do
            arr.[i] <- printableByte (arr.[i])
        arr.Length / 1000

    let main() =
        let sum = ref 0
        let arr = Array.create 1000000 0uy

        let stopWatch = System.Diagnostics.Stopwatch()
        stopWatch.Start()
        for x in 0..5000 do
            sum := !sum + (foo arr)

        stopWatch.Stop()
        printfn "%d" !sum 
        printfn "total time = %A" stopWatch.ElapsedMilliseconds
        ()

    main()

printableByte未内联时为19.5秒,内联时为13.6秒。

EDIT3: 只有在为x86目标编译并在x64主机上运行时,才能查看此时间差。如果编译为“anycpu”或x64,则没有时间差异。

因此,“小功能”和优化没有任何问题。

3 个答案:

答案 0 :(得分:4)

是的,CLR执行一些运行时优化,正如blog所示。 请注意,根据这篇文章,虚拟方法内联。

  

这两种方法都没有内联:

     
      
  • 递归方法
  •   
  • 虚拟方法(即使密封接收器变量的静态类型)
  •   

您的代码中调用了printable函数怎么样?如果F#编译器将它包装在一个闭包中,它经常会这样做,即使在你最初可能没想到它的情况下,那么你将陷入“虚方法”的情况。

答案 1 :(得分:1)

请注意,在FSI中测试此代码与在Release模式下编译项目不一样

我的高度非科学测试表明,如果将Debug添加到inline,则printableByte的效果会更好。

但是,在inline模式下添加Release时,程序实际上执行更糟比没有它时更糟糕。我确信F#编译器团队或一些反汇编可以告诉你为什么......

根据我使用F#的经验,您很少必须手动应用内联优化。只需确保在Release中编译!

编辑:啊哈,是的!一定要在“任何CPU”模式下编译,除非你有特殊的理由不这样做(通常我的理由是必须与F#的x86 COM库进行互操作)

答案 2 :(得分:0)

是的,.net框架优化了它运行的平台的代码。它需要考虑许多因素。但是有一些事情是不会做的。例如,如果它们可用,我不相信它会使用SIMD指令。但它确实在优化方面做得很好。