Skip to content

Commit e728974

Browse files
Add v0.12.1 highlights
1 parent 53d090a commit e728974

File tree

1 file changed

+292
-1
lines changed

1 file changed

+292
-1
lines changed

docs/_changelog/header/v0.12.1.md

Lines changed: 292 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,294 @@
11
## Highlights
22

3-
TODO
3+
* **.NET 5 support**
4+
As you probably, now, .NET Core 5 was officially [rebranded](https://github.com/dotnet/runtime/pull/33694) to .NET 5.
5+
The new version of BenchmarkDotNet supports the new runtime after rebranding.
6+
[#1399](https://github.com/dotnet/BenchmarkDotNet/pull/1399)
7+
[465ebf](https://github.com/dotnet/BenchmarkDotNet/commit/465ebf3fdbf20f0e9219c4c957fb33c13256fdcd)
8+
* **Perfolizer adoption**
9+
The internal statistical engine of BenchmarkDotNet became mature enough to be transformed into an independent project.
10+
Meet [perfolizer](https://github.com/AndreyAkinshin/perfolizer) — a toolkit for performance analysis!
11+
While BenchmarkDotNet focuses on obtaining reliable measurements, perfolizer focuses on the decent analysis of measured data.
12+
You still can use all the statistical algorithms from BenchmarkDotNet,
13+
but you can also install perfolizer as a [standalone NuGet package](https://www.nuget.org/packages/Perfolizer/).
14+
You can find more details in the [official announcement](https://aakinshin.net/posts/introducing-perfolizer/).
15+
[#1386](https://github.com/dotnet/BenchmarkDotNet/pull/1386)
16+
[54a061](https://github.com/dotnet/BenchmarkDotNet/commit/54a06102a6e0cc4169d23c6f9cd2779ee408d2bf)
17+
* **Cross-platform disassembler**
18+
Now the `DisassemblyDiagnoser` is cross-platform!
19+
The disassembling logic was also improved, now it handles runtime helper methods and references to method tables properly.
20+
Internally, it uses the [Iced](https://github.com/0xd4d/iced) library for formatting assembly code.
21+
Special thanks to [@adamsitnik](https://github.com/adamsitnik) for the implementation and [@0xd4d](https://github.com/0xd4d) for Iced!
22+
[#1332](https://github.com/dotnet/BenchmarkDotNet/pull/1332)
23+
[#899](https://github.com/dotnet/BenchmarkDotNet/issues/899)
24+
[#1316](https://github.com/dotnet/BenchmarkDotNet/issues/1316)
25+
[#1364](https://github.com/dotnet/BenchmarkDotNet/issues/1364)
26+
[294320](https://github.com/dotnet/BenchmarkDotNet/commit/294320be9525b0ecfefd0351381756d3a3b77211)
27+
* **EventPipe-based cross-platform profiler**
28+
Now you can easily profiler your benchmarks on Windows, Linux, and macOS!
29+
Just mark your class with the `[EventPipeProfiler(...)]` attribute and get a `.speedscope.json` file that you can browse in [SpeedScope](https://www.speedscope.app/).
30+
Special thanks to [@WojciechNagorski](https://github.com/WojciechNagorski) for the implementation!
31+
[#1321](https://github.com/dotnet/BenchmarkDotNet/pull/1321)
32+
[#1315](https://github.com/dotnet/BenchmarkDotNet/issues/1315)
33+
[c648ff](https://github.com/dotnet/BenchmarkDotNet/commit/c648ff956662abae512c579ffa7f1dc12178f6c3)
34+
* **New fluent API**
35+
We continue to improve our API and make it easier for reading and writing.
36+
Special thanks to [@WojciechNagorski](https://github.com/WojciechNagorski) for the implementation!
37+
[#1273](https://github.com/dotnet/BenchmarkDotNet/pull/1273)
38+
[#1234](https://github.com/dotnet/BenchmarkDotNet/issues/1234)
39+
[640d88](https://github.com/dotnet/BenchmarkDotNet/commit/640d885ae0daddcee7c9ba9b5f1bf5790b9b5ae3)
40+
* **Ref readonly support**
41+
Now you can use `ref readonly` in benchmark signatures.
42+
Special thanks to [@adamsitnik](https://github.com/adamsitnik) for the implementation!
43+
[#1389](https://github.com/dotnet/BenchmarkDotNet/pull/1389)
44+
[#1388](https://github.com/dotnet/BenchmarkDotNet/issues/1388)
45+
[9ac777](https://github.com/dotnet/BenchmarkDotNet/commit/9ac7770682a45afb6cf4ec353f9fa3c69ece67ce)
46+
47+
## Cross-platform disassembler
48+
49+
Just mark your benchmark class with the `[DisassemblyDiagnoser]` attribute
50+
and you will get the disassembly listings for all the benchmarks.
51+
The formatting looks pretty nice thanks to [Iced](https://github.com/0xd4d/iced).
52+
It works like a charm on Windows, Linux, and macOS.
53+
54+
```cs
55+
[DisassemblyDiagnoser]
56+
public class IntroDisassembly
57+
{
58+
private int[] field = Enumerable.Range(0, 100).ToArray();
59+
60+
[Benchmark]
61+
public int SumLocal()
62+
{
63+
var local = field; // we use local variable that points to the field
64+
65+
int sum = 0;
66+
for (int i = 0; i < local.Length; i++)
67+
sum += local[i];
68+
69+
return sum;
70+
}
71+
72+
[Benchmark]
73+
public int SumField()
74+
{
75+
int sum = 0;
76+
for (int i = 0; i < field.Length; i++)
77+
sum += field[i];
78+
79+
return sum;
80+
}
81+
}
82+
```
83+
84+
**.NET Core 2.1.16 (CoreCLR 4.6.28516.03, CoreFX 4.6.28516.10), X64 RyuJIT**
85+
86+
```x86asm
87+
; BenchmarkDotNet.Samples.IntroDisassembly.SumLocal()
88+
mov rax,[rcx+8]
89+
xor edx,edx
90+
xor ecx,ecx
91+
mov r8d,[rax+8]
92+
test r8d,r8d
93+
jle short M00_L01
94+
M00_L00:
95+
movsxd r9,ecx
96+
add edx,[rax+r9*4+10]
97+
inc ecx
98+
cmp r8d,ecx
99+
jg short M00_L00
100+
M00_L01:
101+
mov eax,edx
102+
ret
103+
; Total bytes of code 35
104+
```
105+
106+
**.NET Core 2.1.16 (CoreCLR 4.6.28516.03, CoreFX 4.6.28516.10), X64 RyuJIT**
107+
108+
```x86asm
109+
; BenchmarkDotNet.Samples.IntroDisassembly.SumField()
110+
sub rsp,28
111+
xor eax,eax
112+
xor edx,edx
113+
mov rcx,[rcx+8]
114+
cmp dword ptr [rcx+8],0
115+
jle short M00_L01
116+
M00_L00:
117+
mov r8,rcx
118+
cmp edx,[r8+8]
119+
jae short M00_L02
120+
movsxd r9,edx
121+
add eax,[r8+r9*4+10]
122+
inc edx
123+
cmp [rcx+8],edx
124+
jg short M00_L00
125+
M00_L01:
126+
add rsp,28
127+
ret
128+
M00_L02:
129+
call CORINFO_HELP_RNGCHKFAIL
130+
int 3
131+
; Total bytes of code 53
132+
```
133+
134+
Now we handle runtime helper methods and references to method tables properly. Example:
135+
136+
Before:
137+
138+
```x86asm
139+
; MicroBenchmarks.WithCallsAfter.Benchmark(Int32)
140+
push rsi
141+
sub rsp,20h
142+
mov rsi,rcx
143+
cmp edx,7FFFFFFFh
144+
jne M00_L00
145+
call MicroBenchmarks.WithCallsAfter.Static()
146+
mov rcx,rsi
147+
call MicroBenchmarks.WithCallsAfter.Instance()
148+
mov rcx,rsi
149+
call MicroBenchmarks.WithCallsAfter.Recursive()
150+
mov rcx,rsi
151+
mov rax,qword ptr [rsi]
152+
mov rax,qword ptr [rax+40h]
153+
call qword ptr [rax+20h]
154+
mov rcx,rsi
155+
mov edx,1
156+
mov rax,7FF8F4217050h
157+
add rsp,20h
158+
pop rsi
159+
jmp rax
160+
M00_L00:
161+
mov rcx,offset System_Private_CoreLib+0xa31d48
162+
call coreclr!MetaDataGetDispenser+0x322a0
163+
mov rsi,rax
164+
mov ecx,0ACFAh
165+
mov rdx,7FF8F42F4680h
166+
call coreclr!MetaDataGetDispenser+0x17140
167+
mov rdx,rax
168+
mov rcx,rsi
169+
call System.InvalidOperationException..ctor(System.String)
170+
mov rcx,rsi
171+
call coreclr!coreclr_shutdown_2+0x39f0
172+
int 3
173+
add byte ptr [rax],al
174+
sbb dword ptr [00007ff9`26284e30],eax
175+
add dword ptr [rax+40h],esp
176+
add byte ptr [rax],al
177+
add byte ptr [rax],al
178+
add byte ptr [rax],al
179+
add byte ptr [rax-70BC4CCh],ah
180+
; Total bytes of code 157
181+
```
182+
183+
After:
184+
185+
```x86asm
186+
; BenchmarkDotNet.Samples.WithCallsAfter.Benchmark(Int32)
187+
push rsi
188+
sub rsp,20
189+
mov rsi,rcx
190+
cmp edx,7FFFFFFF
191+
jne M00_L00
192+
call BenchmarkDotNet.Samples.WithCallsAfter.Static()
193+
mov rcx,rsi
194+
call BenchmarkDotNet.Samples.WithCallsAfter.Instance()
195+
mov rcx,rsi
196+
call BenchmarkDotNet.Samples.WithCallsAfter.Recursive()
197+
mov rcx,rsi
198+
mov rax,[rsi]
199+
mov rax,[rax+40]
200+
call qword ptr [rax+20]
201+
mov rcx,rsi
202+
mov edx,1
203+
mov rax BenchmarkDotNet.Samples.WithCallsAfter.Benchmark(Boolean)
204+
add rsp,20
205+
pop rsi
206+
jmp rax
207+
M00_L00:
208+
mov rcx MT_System.InvalidOperationException
209+
call CORINFO_HELP_NEWSFAST
210+
mov rsi,rax
211+
mov ecx,12D
212+
mov rdx,7FF954FF83F0
213+
call CORINFO_HELP_STRCNS
214+
mov rdx,rax
215+
mov rcx,rsi
216+
call System.InvalidOperationException..ctor(System.String)
217+
mov rcx,rsi
218+
call CORINFO_HELP_THROW
219+
int 3
220+
; Total bytes of code 134
221+
```
222+
223+
See also: [Cross-runtime .NET disassembly with BenchmarkDotNet](https://aakinshin.net/posts/dotnet-crossruntime-disasm/).
224+
225+
Special thanks to [@adamsitnik](https://github.com/adamsitnik) for the implementation and [@0xd4d](https://github.com/0xd4d) for Iced!
226+
227+
## EventPipe-based cross-platform profiler
228+
229+
Now you can easily profiler your benchmarks on Windows, Linux, and macOS!
230+
231+
If you want to use the new profiler, you should just mark your benchmark class with the `[EventPipeProfiler(...)]` attribute:
232+
233+
```
234+
[EventPipeProfiler(EventPipeProfile.CpuSampling)] // <-- Enables new profiler
235+
public class IntroEventPipeProfiler
236+
{
237+
[Benchmark]
238+
public void Sleep() => Thread.Sleep(2000);
239+
}
240+
```
241+
242+
Once the benchmark run is finished, you get a `.speedscope.json` file that can be opened in [SpeedScope](https://www.speedscope.app/):
243+
244+
![](https://wojciechnagorski.com/images/EventPipeProfiler/SpeedScope.png#mid)
245+
246+
The new profiler supports several modes:
247+
248+
* `CpuSampling` - Useful for tracking CPU usage and general .NET runtime information. This is the default option.
249+
* `GcVerbose` - Tracks GC collections and samples object allocations.
250+
* `GcCollect` - Tracks GC collections only at very low overhead.
251+
* `Jit` - Logging when Just in time (JIT) compilation occurs. Logging of the internal workings of the Just In Time compiler. This is fairly verbose. It details decisions about interesting optimization (like inlining and tail call)
252+
253+
Please see Wojciech Nagórski's [blog post](https://wojciechnagorski.com/2020/04/cross-platform-profiling-.net-code-with-benchmarkdotnet/) for all the details.
254+
255+
Special thanks to [@WojciechNagorski](https://github.com/WojciechNagorski) for the implementation!
256+
257+
## New fluent API
258+
259+
We continue to improve our API and make it easier for reading and writing.
260+
The old API is still existing, but it is marked as obsolete and will be removed in the further library versions.
261+
The most significant changes:
262+
263+
**Changes in Job configuration**
264+
265+
![](https://user-images.githubusercontent.com/17333903/66208963-b49af000-e6b6-11e9-87b3-1e4bb5519273.PNG)
266+
267+
**Changes in IConfig/ManualConfig**
268+
269+
![](https://user-images.githubusercontent.com/17333903/66208975-b6fd4a00-e6b6-11e9-94cd-85c73ae0ec27.PNG)
270+
271+
**Full fluent API**
272+
273+
![](https://user-images.githubusercontent.com/17333903/66208977-b8c70d80-e6b6-11e9-8e43-6dac3921c121.PNG)
274+
275+
Special thanks to [@WojciechNagorski](https://github.com/WojciechNagorski) for the implementation!
276+
277+
## Ref readonly support
278+
279+
Now you can use `ref readonly` in benchmark signatures.
280+
Here is an example:
281+
282+
```cs
283+
public class RefReadonlyBenchmark
284+
{
285+
static readonly int[] array = { 1 };
286+
287+
[Benchmark]
288+
public ref readonly int RefReadonly() => ref RefReadonlyMethod();
289+
290+
static ref readonly int RefReadonlyMethod() => ref array[0];
291+
}
292+
```
293+
294+
Special thanks to [@adamsitnik](https://github.com/adamsitnik) for the implementation!

0 commit comments

Comments
 (0)