Library for analyzing the machine code generated by JIT (codegen). Has API for obtaining the codegen, verifying the characteristics for tests (in a similar manner to xUnit), and generating reports as benchmarks (in a similar manner to BenchmarkDotNet). Supports x86_64 on three major platforms (Windows, MacOS, Linux).
First of all, most .NET developers don't need this library. If you want to measure performance of your code, use BenchmarkDotNet.
If you're working on low-level, often HW-related project, where it's crucial if a branch or call or etc. is optimized or not, this library is for you.
static int AddAndMul(int a, int b) => a + b * a;
...
var ci = CodegenInfo.Obrain(() => AddAndMul(3, 5));
Console.WriteLine(ci);
Output:
00007FFD752E42F0 8BC2 mov eax,edx
00007FFD752E42F2 0FAFC1 imul eax,ecx
00007FFD752E42F5 03C1 add eax,ecx
00007FFD752E42F7 C3 ret
using CodegenAssertions;
using Xunit;
public class CodegenSizeTest
{
public static int SomeMethod(int a, int b)
=> a + b;
[Fact]
public void Test1()
{
CodegenInfo.Obtain(() => SomeMethod(4, 5), CompilationTier.Tier1)
.ShouldBeNotLargerThan(20);
}
}
public class Tests
{
public class A
{
public virtual int H => 3;
}
public sealed class B : A
{
public override int H => 6;
}
// this will get devirtualized at tier1, but not at tier0
static int Twice(B b) => b.H * 2;
[Fact]
public void NotDevirtTier0()
{
CodegenInfo.Obtain(() => Twice(new B()), CompilationTier.Default)
.ShouldHaveCalls(c => c >= 1);
}
[Fact]
public void DevirtTier1()
{
CodegenInfo.Obtain(() => Twice(new B()), CompilationTier.Tier1)
.ShouldHaveCalls(0);
}
}
private static readonly bool True = true;
static int SmartThing()
{
if (True)
return 5;
return 10;
}
[Fact]
public void BranchElimination()
{
CodegenInfo.Obtain(() => SmartThing())
.ShouldHaveBranches(0);
}
[MethodImpl(MethodImplOptions.NoOptimization)]
static int StupidThing()
{
if (True)
return 5;
return 10;
}
[Fact]
public void NoBranchElimination()
{
CodegenInfo.Obtain(() => StupidThing(), CompilationTier.Default)
.ShouldHaveBranches(b => b > 0);
}
CodegenBenchmarkRunner.Run<A>();
[CAJob(Tier = CompilationTier.Default),
CAJob(Tier = CompilationTier.Tier1)]
[CAColumn(CAColumn.Branches),
CAColumn(CAColumn.Calls),
CAColumn(CAColumn.CodegenSize),
CAColumn(CAColumn.StaticStackAllocations)]
[CAExport(Export.Html),
CAExport(Export.Md)]
public class A
{
[CAAnalyze(3.5f)]
[CAAnalyze(13.5f)]
public static float Heavy(float a)
{
var b = Do1(a);
var c = Do1(b);
if (a > 10)
c += Aaa(a);
return c + b;
}
[CAAnalyze(6f)]
public static float Square(float a)
{
return a * a;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static float Do1(float a)
{
return a * 2;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static float Aaa(float h)
{
return h * h * h;
}
}