为什么F#直列原因11X的性能改进(why does F# inline cause 11x per

2019-08-05 01:24发布

我工作的一些沉重的CPU绑定的问题。 我看到一个大的性能提升,当我使用inline关键字。 我创建标准的.NET库字典传递一个自定义键比较看下面的代码和时序结果

https://gist.github.com/4409734

而对Eq_cmp inline关键字

> perf_run 10000000 ;;
Real: 00:00:11.039, CPU: 00:00:11.029, GC gen0: 771, gen1: 3, gen2: 1
val it : unit = ()

使用上Eq_cmp inline关键字

perf_run 10000000 ;;
Real: 00:00:01.319, CPU: 00:00:01.388, GC gen0: 1, gen1: 1, gen2: 1
val it : unit = ()
> 

我也注意到在第0 GC与内嵌代码和非联的代码量的巨大差异。

有人能解释一下为什么会出现如此巨大的差异?

Answer 1:

加入后,我可以重现我的机器有3倍的性能提升上的行为inline关键字。

下反编译两个版本并排ILSpy给出几乎相同的C#代码。 值得注意的区别是两个平等的测试:

// Version without inline
bool IEqualityComparer<Program.Pair<a>>.System-Collections-Generic-IEqualityComparer(Program.Pair<a> x, Program.Pair<a> y)
{
    a v@ = x.v@;
    a v@2 = y.v@;
    if (LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<a>(v@, v@2))
    {
        a w@ = x.w@;
        a w@2 = y.w@;
        return LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<a>(w@, w@2);
    }
    return false;
}

// Version with inline
bool IEqualityComparer<Program.Pair<int>>.System-Collections-Generic-IEqualityComparer(Program.Pair<int> x, Program.Pair<int> y)
{
    int v@ = x.v@;
    int v@2 = y.v@;
    if (v@ == v@2)
    {
        int w@ = x.w@;
        int w@2 = y.w@;
        return w@ == w@2;
    }
    return false;
}

通用平等比专业版的效率要低得多。

我也注意到在第0 GC与内嵌代码和非联的代码量的巨大差异。

有人能解释一下为什么会出现如此巨大的差异?

考虑看看GenericEqualityIntrinsic函数F#源代码 :

let rec GenericEqualityIntrinsic (x : 'T) (y : 'T) : bool = 
    fsEqualityComparer.Equals((box x), (box y))

它的参数拳,这也解释了垃圾在你的第一个例子中,显著量。 当GC进场过于频繁,这将显着减慢计算。 (使用第二示例inline )几乎不产生垃圾时Pair是结构体。

这就是说,它是预期的行为inline在一个专门的版本是在调用点使用的关键字。 我的建议是总是设法优化和测量在相同的基准测试你的代码。

你可能有兴趣在一个非常类似的线程这是为什么F#代码这么慢? 。



Answer 2:

专业化型

如果没有inline ,你正在使用通用的比较,这是非常低效的。 与inline ,所述通用性是去除和int比较直接使用。



文章来源: why does F# inline cause 11x performance improvement