I used to think if a method is inlined, then theoretically it is identical to the merge of the method and the calling method, but the benchmark showed there is slightly difference in performance
e.g. this takes 100ms
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;
}
this takes 110ms (if I force MethodImplOptions.NoInlining on GetIt then it will be 400ms, so I assume it is auto inlined)
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];
}
OK, I attach a snippet of benchmark function i used
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");
}
C# does inline at JIT, so whether inline or not IL doesn’t change.
MethodImplOptions.NoInliningis not the same asinlinekeyword in F#