Skip to content

Commit 4198273

Browse files
authored
multi bench (#95)
* all bench * diffable .asm * private
1 parent ec05a78 commit 4198273

17 files changed

+201
-16
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
namespace BenchmarkDotNet.AsmSlicer;
2+
3+
public class AsmFileProcessor
4+
{
5+
private string filePath;
6+
public AsmFileProcessor(string file)
7+
{
8+
this.filePath = file;
9+
}
10+
11+
public void Process()
12+
{
13+
string path = Path.GetDirectoryName(filePath) ?? throw new InvalidOperationException("File path does not contain a directory name");
14+
string fileName = Path.GetFileName(filePath);
15+
string benchmark = fileName.Substring(0, fileName.Length-7);
16+
string outputPath = Path.Combine(path, benchmark);
17+
18+
if (Directory.Exists(outputPath))
19+
{
20+
Directory.Delete(outputPath, true);
21+
}
22+
23+
Directory.CreateDirectory(outputPath);
24+
25+
BenchMethodAsmWriter? bw = null;
26+
27+
using (var sr = new StreamReader(filePath))
28+
{
29+
string? line = sr.ReadLine();
30+
31+
while (line != null)
32+
{
33+
if (line.StartsWith("##"))
34+
{
35+
var framework = line.TrimStart('#', ' ');
36+
sr.ReadLine(); // ```assembly
37+
line = sr.ReadLine(); // benchmarkname
38+
39+
string? methodName = line?.TrimStart(';', ' ').TrimEnd('(', ')');
40+
41+
if (bw != null)
42+
{
43+
bw.Dispose();
44+
}
45+
46+
string frameworkPath = Path.Combine(outputPath, framework);
47+
if (!Directory.Exists(frameworkPath))
48+
{
49+
Directory.CreateDirectory(frameworkPath);
50+
}
51+
52+
bw = new BenchMethodAsmWriter(frameworkPath, methodName);
53+
}
54+
else
55+
{
56+
bw?.WriteLine(line);
57+
}
58+
59+
line = sr.ReadLine();
60+
}
61+
}
62+
}
63+
}
64+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
namespace BenchmarkDotNet.AsmSlicer;
2+
3+
public class BenchMethodAsmWriter : IDisposable
4+
{
5+
private readonly StreamWriter writer;
6+
7+
// 1 .asm file per method name
8+
public BenchMethodAsmWriter(string path, string? methodName)
9+
{
10+
string filePath = Path.Combine(path, $"{DeNamespace(methodName)}-asm.md");
11+
12+
FileStreamOptions fileStreamOptions = new FileStreamOptions();
13+
fileStreamOptions.Access = FileAccess.Write;
14+
fileStreamOptions.Mode = FileMode.Create;
15+
16+
this.writer = new StreamWriter(filePath, fileStreamOptions);
17+
this.writer.WriteLine("```assembly");
18+
this.writer.WriteLine($"; {methodName}()"); // reconstruct
19+
}
20+
21+
private static string? DeNamespace(string? methodName)
22+
{
23+
int s = methodName?.LastIndexOf(".") ?? 0;
24+
return methodName?.Substring(s + 1);
25+
}
26+
27+
public void WriteLine(string line)
28+
{
29+
this.writer.WriteLine(line);
30+
}
31+
32+
public void Dispose()
33+
{
34+
this.writer.Dispose();
35+
}
36+
}
37+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net6.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
</Project>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
global using BenchmarkDotNet.AsmSlicer;
2+
3+
// Break down the .asm markdown files into 1 file per benchmark method, making it easy to diff
4+
string resultPath = args[0];
5+
Console.WriteLine($"Searching {resultPath} for .asm files");
6+
7+
try
8+
{
9+
string[] files = System.IO.Directory.GetFiles(resultPath, "*asm.md");
10+
11+
Console.WriteLine($"Found {files.Length} .asm files");
12+
13+
foreach (var file in files)
14+
{
15+
Console.WriteLine($"Processing {file}");
16+
17+
try
18+
{
19+
var s = new AsmFileProcessor(file);
20+
s.Process();
21+
}
22+
catch (Exception ex)
23+
{
24+
Console.WriteLine($"Failed to process {file}");
25+
Console.WriteLine(ex.Message);
26+
}
27+
}
28+
}
29+
catch (Exception ex)
30+
{
31+
Console.WriteLine($"Failed to process {resultPath}");
32+
Console.WriteLine(ex.Message);
33+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"profiles": {
3+
"AsmSlicer": {
4+
"commandName": "Project",
5+
"commandLineArgs": "C:\\repo\\BitFaster.Caching\\BenchmarkDotNet.Artifacts\\results"
6+
}
7+
}
8+
}

BitFaster.Caching.Benchmarks/BitFaster.Caching.Benchmarks.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net6.0</TargetFramework>
5+
<TargetFrameworks>net472;net48;netstandard2.0;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
66
</PropertyGroup>
77

88
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">

BitFaster.Caching.Benchmarks/DataStructureBenchmarks.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using BenchmarkDotNet.Attributes;
2+
using BenchmarkDotNet.Jobs;
23
using System;
34
using System.Collections.Concurrent;
45
using System.Collections.Generic;
@@ -9,6 +10,8 @@
910

1011
namespace BitFaster.Caching.Benchmarks
1112
{
13+
[SimpleJob(RuntimeMoniker.Net48)]
14+
[SimpleJob(RuntimeMoniker.Net60)]
1215
[MemoryDiagnoser]
1316
public class DataStructureBenchmarks
1417
{

BitFaster.Caching.Benchmarks/DisposerBench.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
using System.Runtime.CompilerServices;
44
using System.Text;
55
using BenchmarkDotNet.Attributes;
6+
using BenchmarkDotNet.Jobs;
67
using Microsoft.CodeAnalysis.CSharp.Syntax;
78
using Microsoft.Diagnostics.Runtime.Interop;
89

910
namespace BitFaster.Caching.Benchmarks
1011
{
1112
// Is it possible to write a class to eliminate the dispose code for types that are not IDisposable?
1213
// https://github.com/dotnet/runtime/issues/4920
13-
[DisassemblyDiagnoser(printSource: true)]
14+
[SimpleJob(RuntimeMoniker.Net48)]
15+
[SimpleJob(RuntimeMoniker.Net60)]
16+
[DisassemblyDiagnoser(printSource: true, maxDepth:3)]
1417
[MemoryDiagnoser]
1518
public class DisposerBench
1619
{

BitFaster.Caching.Benchmarks/Lru/LruCycleBench.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Text;
55
using System.Threading.Tasks;
66
using BenchmarkDotNet.Attributes;
7+
using BenchmarkDotNet.Jobs;
78
using BitFaster.Caching.Lru;
89

910
namespace BitFaster.Caching.Benchmarks.Lru
@@ -22,15 +23,17 @@ namespace BitFaster.Caching.Benchmarks.Lru
2223
//| FastConcurrentTLru | 32.17 us | 0.463 us | 0.433 us | 1.38 | 0.02 | 2.3193 | 6 KB | 10 KB |
2324
//| ConcurrentTLru | 32.52 us | 0.386 us | 0.361 us | 1.40 | 0.02 | 2.3193 | 6 KB | 10 KB |
2425
//| ClassicLru | 16.29 us | 0.195 us | 0.163 us | 0.70 | 0.01 | 3.2959 | 5 KB | 14 KB |
26+
[SimpleJob(RuntimeMoniker.Net48)]
27+
[SimpleJob(RuntimeMoniker.Net60)]
2528
[DisassemblyDiagnoser(printSource: true, maxDepth: 5)]
2629
[MemoryDiagnoser]
2730
public class LruCycleBench
2831
{
29-
private static readonly ClassicLru<int, int> classicLru = new(8, 9, EqualityComparer<int>.Default);
30-
private static readonly ConcurrentLru<int, int> concurrentLru = new(8, 9, EqualityComparer<int>.Default);
31-
private static readonly ConcurrentTLru<int, int> concurrentTlru = new(8, 9, EqualityComparer<int>.Default, TimeSpan.FromMinutes(10));
32-
private static readonly FastConcurrentLru<int, int> fastConcurrentLru = new(8, 9, EqualityComparer<int>.Default);
33-
private static readonly FastConcurrentTLru<int, int> fastConcurrentTLru = new(8, 9, EqualityComparer<int>.Default, TimeSpan.FromMinutes(1));
32+
private static readonly ClassicLru<int, int> classicLru = new ClassicLru<int, int>(8, 9, EqualityComparer<int>.Default);
33+
private static readonly ConcurrentLru<int, int> concurrentLru = new ConcurrentLru<int, int>(8, 9, EqualityComparer<int>.Default);
34+
private static readonly ConcurrentTLru<int, int> concurrentTlru = new ConcurrentTLru<int, int>(8, 9, EqualityComparer<int>.Default, TimeSpan.FromMinutes(10));
35+
private static readonly FastConcurrentLru<int, int> fastConcurrentLru = new FastConcurrentLru<int, int>(8, 9, EqualityComparer<int>.Default);
36+
private static readonly FastConcurrentTLru<int, int> fastConcurrentTLru = new FastConcurrentTLru<int, int>(8, 9, EqualityComparer<int>.Default, TimeSpan.FromMinutes(1));
3437

3538
[Benchmark(Baseline = true)]
3639
public void FastConcurrentLru()

BitFaster.Caching.Benchmarks/Lru/LruJustGetOrAdd.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using BenchmarkDotNet.Attributes;
2+
using BenchmarkDotNet.Jobs;
23
using BitFaster.Caching;
34
using BitFaster.Caching.Benchmarks.Lru;
45
using BitFaster.Caching.Lru;
@@ -29,17 +30,19 @@ namespace BitFaster.Caching.Benchmarks
2930
//| ClassicLru | 49.041 ns | 0.8575 ns | 0.8021 ns | 6.23 | 0.11 | 3,013 B | - | - |
3031
//| RuntimeMemoryCacheGet | 107.769 ns | 1.1901 ns | 0.9938 ns | 13.69 | 0.15 | 49 B | 0.0074 | 32 B |
3132
//| ExtensionsMemoryCacheGet | 93.188 ns | 0.2321 ns | 0.2171 ns | 11.85 | 0.07 | 78 B | 0.0055 | 24 B |
33+
[SimpleJob(RuntimeMoniker.Net48)]
34+
[SimpleJob(RuntimeMoniker.Net60)]
3235
[DisassemblyDiagnoser(printSource: true, maxDepth: 5)]
3336
[MemoryDiagnoser]
3437
public class LruJustGetOrAdd
3538
{
36-
private static readonly ConcurrentDictionary<int, int> dictionary = new(8, 9, EqualityComparer<int>.Default);
39+
private static readonly ConcurrentDictionary<int, int> dictionary = new ConcurrentDictionary<int, int>(8, 9, EqualityComparer<int>.Default);
3740

38-
private static readonly ClassicLru<int, int> classicLru = new(8, 9, EqualityComparer<int>.Default);
39-
private static readonly ConcurrentLru<int, int> concurrentLru = new(8, 9, EqualityComparer<int>.Default);
40-
private static readonly ConcurrentTLru<int, int> concurrentTlru = new(8, 9, EqualityComparer<int>.Default, TimeSpan.FromMinutes(10));
41-
private static readonly FastConcurrentLru<int, int> fastConcurrentLru = new(8, 9, EqualityComparer<int>.Default);
42-
private static readonly FastConcurrentTLru<int, int> fastConcurrentTLru = new(8, 9, EqualityComparer<int>.Default, TimeSpan.FromMinutes(1));
41+
private static readonly ClassicLru<int, int> classicLru = new ClassicLru<int, int>(8, 9, EqualityComparer<int>.Default);
42+
private static readonly ConcurrentLru<int, int> concurrentLru = new ConcurrentLru<int, int>(8, 9, EqualityComparer<int>.Default);
43+
private static readonly ConcurrentTLru<int, int> concurrentTlru = new ConcurrentTLru<int, int>(8, 9, EqualityComparer<int>.Default, TimeSpan.FromMinutes(10));
44+
private static readonly FastConcurrentLru<int, int> fastConcurrentLru = new FastConcurrentLru<int, int>(8, 9, EqualityComparer<int>.Default);
45+
private static readonly FastConcurrentTLru<int, int> fastConcurrentTLru = new FastConcurrentTLru<int, int>(8, 9, EqualityComparer<int>.Default, TimeSpan.FromMinutes(1));
4346

4447
private static readonly int key = 1;
4548
private static System.Runtime.Caching.MemoryCache memoryCache = System.Runtime.Caching.MemoryCache.Default;

0 commit comments

Comments
 (0)