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,则数字保持不变。

函数调用的性能成本仍然存在。

AggressiveInlining何时适用于简单的包装

秒表不是评估代码是否内联的正确工具。它只是提供了一个性能度量。

首先,要使代码内联,必须在启用优化的情况下执行构建。使用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方法是内联的,它将返回调用方的名称。