AggressiveInlining何时适用于简单的包装
本文关键字:包装 简单 适用于 何时 AggressiveInlining | 更新日期: 2023-09-27 18:24:55
当我简单地包装一个名为的数据结构时,我看不到AggressiveInlining的效果
例如:
public class WList
{
//made static just to check inlining
//otherwise inlining might not kick in since 'this' keyword will disallow it
static System.Collections.ArrayList list;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Put(object item)
{
WList.list.Add(item);
}
}
然后做这个
//Add 1000000 number of items in the list
//Run this test many times
for (int j = 0; j < 100; j++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < length; i++)
{
//ADD ITEMS IN A SIMPLE ARRAY LIST
arraylist.Add(emptyobject);
}
sw.Stop();
//clear the list
}
//Do similar test on wrapper
for (int j = 0; j < 100; j++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < length; i++)
{
//ADD ITEMS IN ARRAY LIST THROUGH WRAPPER
wrapperList.Put(emptyobject);
}
sw.Stop();
//clear the list
}
Inlinig基本上应该打开函数并将内部代码放在外部,但我从包装机上得到的号码比直拨电话要慢。
如果使用Hastable或使用get调用而不是add,则数字保持不变。
函数调用的性能成本仍然存在。
秒表不是评估代码是否内联的正确工具。它只是提供了一个性能度量。
首先,要使代码内联,必须在启用优化的情况下执行构建。使用Visual Studio最简单的方法是使用发布版本。调试构建不会被JITter优化,因此不会内联任何内容。为了查看代码是否已被JITter内联,我建议您附加调试器,并比较调试版本和发布版本之间的反汇编。如果调用是内联的,那么您会注意到不同之处。
在您的示例中,与WList.Put()
对应的call
程序集指令将在发布版本中消失,并由与ArrayList.Add()
对应的call
程序集指令替换。
值得一提的是,默认情况下,当您将Visual Studio调试器附加到任何生成时,它都会抑制优化,以允许您正确地遍历代码的每一行。要关闭此功能,您需要取消选中"工具"->"选项"->"调试"->"常规"中的"在模块加载时抑制JIT优化"选项。
其次,回答你的实际问题。该方法将不会内联,因为它是虚拟的。请参阅下面的博客文章。
http://blogs.msdn.com/b/davidnotario/archive/2004/11/01/250398.aspx
"以下是我们不会内联方法的一些原因:
- 虚拟呼叫:我们不在虚拟呼叫之间内联。不这样做的原因是我们不知道通话的最终目标。我们可能会在这里做得更好(例如,如果99%的调用最终在同一个目标中,您可以生成代码来检查虚拟调用将在其上执行的对象的方法表,如果不是99%,则执行调用,否则只执行内联代码),但与J语言不同,我们支持的主要语言中的大多数调用都不是虚拟的,所以我们不必在优化这个案例时过于激进。"
虽然这篇文章已经有近10年的历史了,但我认为这一点在任何后来的JIT编译器中都没有改变。
因为您的方法是虚拟的,JIT编译器不会内联虚拟调用,请阅读此论坛了解更多信息。此外,为了确保方法是内联的,您可以:
检查System.Reflection.MethodBase.GetCurrentMethod().Name.If方法是内联的,它将返回调用方的名称。