.NET 7的性能改进有哪些具体细节?
摘要:原文 | Stephen Toub 翻译 | 郑子铭 循环提升和克隆 (Loop Hoisting and Cloning) 我们之前看到PGO是如何与循环提升和克隆互动的,这些优化也有其他改进。 从历史上看,JIT对提升的支持仅限于将一个
原文 | Stephen Toub
翻译 | 郑子铭
循环提升和克隆 (Loop Hoisting and Cloning)
我们之前看到PGO是如何与循环提升和克隆互动的,这些优化也有其他改进。
从历史上看,JIT对提升的支持仅限于将一个不变量提升到一个层级。
考虑一下这个例子:
[Benchmark]
public void Compute()
{
for (int thousands = 0; thousands < 10; thousands++)
{
for (int hundreds = 0; hundreds < 10; hundreds++)
{
for (int tens = 0; tens < 10; tens++)
{
for (int ones = 0; ones < 10; ones++)
{
int n = ComputeNumber(thousands, hundreds, tens, ones);
Process(n);
}
}
}
}
}
static int ComputeNumber(int thousands, int hundreds, int tens, int ones) =>
(thousands * 1000) +
(hundreds * 100) +
(tens * 10) +
ones;
[MethodImpl(MethodImplOptions.NoInlining)]
static void Process(int n) { }
乍一看,你可能会说:"有什么可提升的,n的计算需要所有的循环输入,而所有的计算都在ComputeNumber中。" 但从编译器的角度来看,ComputeNumber函数是可内联的,因此在逻辑上可以成为其调用者的一部分,n的计算实际上被分成了多块,每块都可以被提升到不同的层级,例如,十的计算可以提升出一层,百的提升出两层,千的提升出三层。下面是[DisassemblyDiagnoser]对.NET 6的输出。
