1

我曾经认为如果一个方法是内联的,那么理论上它与方法和调用方法的合并是相同的,但基准测试显示性能略有不同

例如,这需要 100 毫秒

    public long TestA()
    {
        long ret = 0;
        for (int n = 0; n < testSize; n++)
        {
            for (int i = 0; i < a; i++)
                for (int j = 0; j < b; j++)
                {
                    ret += myArray[i][j];
                }
        }
        return ret;
    }

这需要 110 毫秒(如果我强制MethodImplOptions.NoInlining打开,GetIt那么它将是 400 毫秒,所以我假设它是自动内联的)

    public long TestB()
    {
        long ret = 0;
        for (int n = 0; n < testSize; n++)
        {
            for (int i = 0; i < a; i++)
                for (int j = 0; j < b; j++)
                {
                    ret += GetIt(i, j);
                }
        }
        return ret;
    }

    int GetIt(int x, int y)
    {
        return myArray[x][y];
    }

好的,我附上我使用的基准函数片段

    public static void RunTests(Func<long> myTest)
    {
        const int numTrials = 100;
        Stopwatch sw = new Stopwatch();
        double[] sample = new double[numTrials];

        Console.WriteLine("Checksum is {0:N0}", myTest());

        sw.Start();
        myTest();
        sw.Stop();

        Console.WriteLine("Estimated time per test is {0:N0} ticks\n", sw.ElapsedTicks);
        if (sw.ElapsedTicks < 100)
        {
            Console.WriteLine("Ticks per test is less than 100 ticks. Suggest increase testSize.");
            return;
        }

        if (sw.ElapsedTicks > 10000)
        {
            Console.WriteLine("Ticks per test is more than 10,000 ticks. Suggest decrease testSize.");
            return;
        }

        for (int i = 0; i < numTrials / 3; i++)
        {
            myTest();
        }

        string testName = myTest.Method.Name;
        Console.WriteLine("----> Starting benchmark {0}\n", myTest.Method.Name);
        for (int i = 0; i < numTrials; i++)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();

            sw.Restart();
            myTest();
            sw.Stop();
            sample[i] = sw.ElapsedTicks;
        }
        double testResult = DataSetAnalysis.Report(sample);
        DataSetAnalysis.ConsistencyAnalyze(sample, 0.1);
        Console.WriteLine();

        for (int j = 0; j < numTrials; j = j + 5)
            Console.WriteLine("{0,8:N0} {1,8:N0} {2,8:N0} {3,8:N0} {4,8:N0}", sample[j], sample[j + 1], sample[j + 2], sample[j + 3], sample[j + 4]);
        Console.WriteLine("\n----> End of benchmark");
    } 
4

2 回答 2

1

生成的 IL 指令数略有不同,maxstack 显着不同:

TestA:
// Code size       78 (0x4e)
.maxstack  2


TestB:
// Code size       88 (0x58)
.maxstack  4

GetIt:
// Code size       7 (0x7)
.maxstack  1
于 2012-09-14T11:33:10.093 回答
0

C#在JIT处内联,因此无论是否内IL都不会改变。

MethodImplOptions.NoInlininginlineF# 中的关键字不同

于 2012-09-14T23:10:37.667 回答