Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/whiteblackgoose/codegenanalysis

Library for obtaining and analyzing the codegen of JIT for .NET. Can be used for both tests (assertions) and making reports (benchmarks).
https://github.com/whiteblackgoose/codegenanalysis

codegen dotnet jit performance performance-analysis

Last synced: 10 days ago
JSON representation

Library for obtaining and analyzing the codegen of JIT for .NET. Can be used for both tests (assertions) and making reports (benchmarks).

Awesome Lists containing this project

README

        

# CodegenAnalysis

![](https://img.shields.io/static/v1?label=Lowest+target&message=netstandard2.0&color=purple&logo=dotnet)

![](https://img.shields.io/static/v1?label=Windows&message=Supported&color=brightgreen&logo=windows)
![](https://img.shields.io/static/v1?label=Linux&message=Supported&color=brightgreen&logo=linux)
![](https://img.shields.io/static/v1?label=MacOS&message=Supported&color=brightgreen&logo=apple)

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).

## Why should I use it?

First of all, most .NET developers don't need this library. If you want to measure performance of your code, use [BenchmarkDotNet](https://github.com/dotnet/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.

### Table of contents
- [CodegenAnalysis](#CodegenAnalysis)
- [CodegenAnalysis.Assertions](#CodegenAnalysisAssertions)
- [CodegenAnalysis.Benchmarks](#CodegenAnalysisBenchmarks)

## CodegenAnalysis

[![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/CodegenAnalysis?label=NuGet&logo=nuget)](https://www.nuget.org/packages/CodegenAnalysis)

```cs
static int AddAndMul(int a, int b) => a + b * a;

...

var ci = CodegenInfo.Obrain(() => AddAndMul(3, 5));
Console.WriteLine(ci);
```
Output:
```assembly
00007FFD752E42F0 8BC2 mov eax,edx
00007FFD752E42F2 0FAFC1 imul eax,ecx
00007FFD752E42F5 03C1 add eax,ecx
00007FFD752E42F7 C3 ret
```

## CodegenAnalysis.Assertions

[![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/CodegenAnalysis.Assertions?label=NuGet&logo=nuget)](https://www.nuget.org/packages/CodegenAnalysis.Assertions)

### Verifying the size of the codegen

```cs
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);
}
}
```

### Having calls in the codegen

```cs
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);
}
}
```

### Testing if we have branches

```cs
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);
}
```

## CodegenAnalysis.Benchmarks

[![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/CodegenAnalysis.Benchmarks?label=NuGet&logo=nuget)](https://www.nuget.org/packages/CodegenAnalysis.Benchmarks)

```cs
CodegenBenchmarkRunner.Run();

[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;
}
}
```

[See the output](./Samples/CodegenAnalysis.Benchmarks.Sample/CodegenAnalysis.Artifacts).