-
-
Notifications
You must be signed in to change notification settings - Fork 965
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve Disassembly exporters and add PrettyGithubMarkdownDiffDisassemblyExporter #927
Conversation
file BenchmarkDotNet.Samples.IntroDisassemblyRyuJit-asm.pretty.diff.md: BenchmarkDotNet.Samples.IntroDisassemblyRyuJitDiff between SumLocal and SumField -; BenchmarkDotNet.Samples.IntroDisassemblyRyuJit.SumLocal()
- var local = field; // we use local variable that points to the field
- ^^^^^^^^^^^^^^^^^^
- mov rax,qword ptr [rcx+8]
+; BenchmarkDotNet.Samples.IntroDisassemblyRyuJit.SumField()
int sum = 0;
^^^^^^^^^^^^
- xor edx,edx
- for (int i = 0; i < local.Length; i++)
+ xor eax,eax
+ for (int i = 0; i < field.Length; i++)
^^^^^^^^^
- xor ecx,ecx
- for (int i = 0; i < local.Length; i++)
+ xor edx,edx
+ for (int i = 0; i < field.Length; i++)
^^^^^^^^^^^^^^^^
- mov r8d,dword ptr [rax+8]
- test r8d,r8d
+ mov rcx,qword ptr [rcx+8]
+ cmp dword ptr [rcx+8],0
jle M00_L01
- sum += local[i];
+ sum += field[i];
^^^^^^^^^^^^^^^^
M00_L00:
- movsxd r9,ecx
- add edx,dword ptr [rax+r9*4+10h]
- for (int i = 0; i < local.Length; i++)
+ mov r8,rcx
+ cmp edx,dword ptr [r8+8]
+ jae 00007ff9`0c412c1f
+ movsxd r9,edx
+ add eax,dword ptr [r8+r9*4+10h]
+ for (int i = 0; i < field.Length; i++)
^^^
- inc ecx
- cmp r8d,ecx
+ inc edx
+ cmp dword ptr [rcx+8],edx
jg M00_L00
return sum;
^^^^^^^^^^^
M00_L01:
- mov eax,edx
-; Total bytes of code 34
+ add rsp,28h
+; Total bytes of code 42
|
File BenchmarkDotNet.Samples.IntroDisassembly-asm.pretty.diff.md: BenchmarkDotNet.Samples.IntroDisassemblyDiff for Sum method between: ; BenchmarkDotNet.Samples.IntroDisassembly.Sum()
- fldz
+ vxorps xmm0,xmm0,xmm0
xor eax,eax
M00_L00:
- mov dword ptr [ebp-4],eax
- fild dword ptr [ebp-4]
- faddp st(1),st
+ vxorps xmm1,xmm1,xmm1
+ vcvtsi2sd xmm1,xmm1,eax
+ vaddsd xmm0,xmm0,xmm1
inc eax
cmp eax,40h
jl M00_L00
- mov esp,ebp
-; Total bytes of code 20
+ ret
+; Total bytes of code 30
|
File BenchmarkDotNet.Samples.IntroDisassemblyAllJits-asm.pretty.md: Mono 5.16.0 (Visual Studio), 64bit; CallVirtualMethod
converting method int BenchmarkDotNet.Samples.IntroDisassemblyAllJits:CallVirtualMethod ()
created temp 0 (R16) of type System.Int32
creating vars
created temp 1 (R17) of type System.IntPtr
return : arg R16 <-
this: arg R17 <-
creating locals
locals done
method to IR BenchmarkDotNet.Samples.IntroDisassemblyAllJits:CallVirtualMethod ()
converting (in B2: stack: 0) IL_0000: ldarg.0
converting (in B2: stack: 1) IL_0001: ldfld 0x04000005
converting (in B2: stack: 1) IL_0006: ldc.i4.s 10
converting (in B2: stack: 2) IL_0008: callvirt 0x060000fc
INLINE START 000001DBB13B8AA0 BenchmarkDotNet.Samples.IntroDisassemblyAllJits:CallVirtualMethod () -> BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)
created temp 2 (R21) of type System.Int32
method to IR BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)
created temp 3 (R22) of type System.Object
created temp 4 (R23) of type System.Int32
converting (in B7: stack: 0) IL_0000: ldarg.0
converting (in B7: stack: 1) IL_0001: ldarg.0
converting (in B7: stack: 2) IL_0002: ldarg.1
converting (in B7: stack: 3) IL_0003: callvirt 0x060000fb
inline failed: call
INLINE ABORTED BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int) (cost -1)
converting (in B2: stack: 1) IL_000d: ret
REGION BB0 IL_0000 ID_FFFFFFFF
REGION BB3 IL_0000 ID_FFFFFFFF
REGION BB2 IL_000d ID_FFFFFFFF
REGION BB1 IL_0000 ID_FFFFFFFF
AFTER METHOD-TO-IR 0: [IN: , OUT: BB3(0) ]
AFTER METHOD-TO-IR 3: [IN: BB0(0), OUT: BB2(0) ]
AFTER METHOD-TO-IR 2: [IN: BB3(0), OUT: BB1(0) ]
il_seq_point il: 0x0
move R18 <- R17
load_membase R19 <- [R18 + 0x10]
iconst R20 <- [10]
move R29 <- R19
move R30 <- R20
checkthis [R19 + 0x0]
not_null R19
call R28 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
move R16 <- R28
br [B1]
AFTER METHOD-TO-IR 1: [IN: BB2(0), OUT: ]
CCOPY/2: R18 -> R17
remove_block_if_useless, removed BB3
br removal triggered 2 -> 1
HANDLE-GLOBAL-VREGS BLOCK 0:
HANDLE-GLOBAL-VREGS BLOCK 2:
il_seq_point il: 0x0
move R18 <- R17
load_membase R19 <- [R17 + 0x10]
iconst R20 <- [10]
move R29 <- R19
iconst R30 <- [10]
checkthis [R19 + 0x0]
not_null R19
call R28 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
move R16 <- R28
nop
HANDLE-GLOBAL-VREGS BLOCK 1:
CONVERTED R21(2) TO VREG.
CONVERTED R22(3) TO VREG.
CONVERTED R23(4) TO VREG.
Reverse copyprop in BB2 on move R16 <- R28
BB0 IN:
BB2 IN: 0
BB1 IN: 2
DTREE BenchmarkDotNet.Samples.IntroDisassemblyAllJits:CallVirtualMethod () 0
BB0(dfn=0) (IDOM=BB-1): BB0
BB2(dfn=1) (IDOM=BB0): BB0 BB2
BB1(dfn=2) (IDOM=BB2): BB0 BB2 BB1
BEFORE LOWER-VTYPE-OPTS 0: [IN: , OUT: BB2(1) ]
AFTER LOWER-VTYPE-OPTS 0: [IN: , OUT: BB2(1) ]
BEFORE LOWER-VTYPE-OPTS 2: [IN: BB0(0), OUT: BB1(2) ]
il_seq_point il: 0x0
load_membase R19 <- [R17 + 0x10]
move R29 <- R19
iconst R30 <- [10]
checkthis [R19 + 0x0]
not_null R19
call R16 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
AFTER LOWER-VTYPE-OPTS 2: [IN: BB0(0), OUT: BB1(2) ]
il_seq_point il: 0x0
load_membase R19 <- [R17 + 0x10]
move R29 <- R19
iconst R30 <- [10]
checkthis [R19 + 0x0]
not_null R19
call R16 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
BEFORE LOWER-VTYPE-OPTS 1: [IN: BB2(1), OUT: ]
AFTER LOWER-VTYPE-OPTS 1: [IN: BB2(1), OUT: ]
LIVENESS:
BLOCK BB0 (BB2, ):
GEN BB0: {}
KILL BB0: {}
BLOCK BB2 (BB1, ):
1 il_seq_point il: 0x0
1 load_membase R19 <- [R17 + 0x10]
GEN: R17(1)
1 move R29 <- R19
1 iconst R30 <- [10]
1 checkthis [R19 + 0x0]
1 not_null R19
1 call R16 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
KILL: R16(0)
1 il_seq_point il: 0xd, nonempty-stack
1 il_seq_point il: 0xd
GEN BB2: {1}
KILL BB2: {0}
BLOCK BB1 ():
GEN BB1: {}
KILL BB1: {}
ITERATION:
P: BB1(2): IN: BB2 OUT:
P: BB2(1): IN: BB0 OUT:BB1
LIVE IN BB2: {1}
P: BB0(0): IN: OUT:BB2
LIVE IN BB0: {1}
IT: 3 2.
LIVE IN BB1: {}
LIVE OUT BB1: {}
LIVE IN BB2: {1}
LIVE OUT BB2: {}
LIVE IN BB0: {1}
LIVE OUT BB0: {1}
V0: [0x0 - 0x4000f]
V1: [0x0 - 0x40004]
COSTLY: R1 C1 C1 %rsi
NOT REGVAR: 1
SPILL BLOCK 0:
SPILL BLOCK 2:
il_seq_point il: 0x0
-1
1 il_seq_point il: 0x0
load_membase R19 <- [R17 + 0x10]
ii 19 17
1 load_membase R19 <- [R31 + 0x10]
move R29 <- R19
ii 29 19
1 move R29 <- R19
iconst R30 <- [10]
i 30
1 iconst R30 <- [10]
checkthis [R19 + 0x0]
i -1 19
1 checkthis [R19 + 0x0]
not_null R19
i -1 19
1 not_null R19
call R16 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
i 16
1 call %rax <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
il_seq_point il: 0xd, nonempty-stack
-1
1 il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
-1
1 il_seq_point il: 0xd
SPILL BLOCK 1:
DUMP BLOCK 0:
DUMP BLOCK 2:
il_seq_point il: 0x0
load_membase R31 <- [%rbp + 0xfffffff8]
load_membase R19 <- [R31 + 0x10]
move R29 <- R19
iconst R30 <- [10]
checkthis [R19 + 0x0]
not_null R19
call %rax <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
DUMP BLOCK 1:
LOCAL REGALLOC BLOCK 2:
1 il_seq_point il: 0x0
2 load_membase R31 <- [%rbp + 0xfffffff8]
3 load_membase R19 <- [R31 + 0x10]
4 move R29 <- R19
5 iconst R30 <- [10]
6 checkthis [R19 + 0x0]
7 not_null R19
8 call %rax <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
9 il_seq_point il: 0xd, nonempty-stack
10 il_seq_point il: 0xd
liveness: %rax [8 - 8]
liveness: R19 [3 - 3]
liveness: R29 [4 - 4]
liveness: R30 [5 - 5]
liveness: R31 [2 - 2]
processing: 10 il_seq_point il: 0xd
10 il_seq_point il: 0xd
processing: 9 il_seq_point il: 0xd, nonempty-stack
9 il_seq_point il: 0xd, nonempty-stack
processing: 8 call %rax <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
assigned arg reg %rcx to R29
assigned arg reg %rdx to R30
8 call %rax <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] [%rcx <- R29] [%rdx <- R30] clobbers: c
processing: 7 not_null R19
assigned sreg1 %rax to R19
7 not_null %rax
processing: 6 checkthis [R19 + 0x0]
6 checkthis [%rax + 0x0]
processing: 5 iconst R30 <- [10]
assigned dreg %rdx to dest R30
freeable %rdx (R30) (born in 5)
5 iconst %rdx <- [10]
processing: 4 move R29 <- R19
assigned dreg %rcx to dest R29
freeable %rcx (R29) (born in 4)
4 move %rcx <- %rax
processing: 3 load_membase R19 <- [R31 + 0x10]
assigned dreg %rax to dest R19
freeable %rax (R19) (born in 3)
assigned sreg1 %rax to R31
3 load_membase %rax <- [%rax + 0x10]
processing: 2 load_membase R31 <- [%rbp + 0xfffffff8]
assigned dreg %rax to dest R31
freeable %rax (R31) (born in 2)
2 load_membase %rax <- [%rbp + 0xfffffff8]
processing: 1 il_seq_point il: 0x0
1 il_seq_point il: 0x0
CFA: [0] def_cfa: %rsp+0x8
CFA: [0] offset: unknown at cfa-0x8
CFA: [1] def_cfa_offset: 0x10
CFA: [1] offset: %rbp at cfa-0x10
CFA: [4] def_cfa_reg: %rbp
Basic block 0 starting at offset 0xc
Basic block 2 starting at offset 0xc
Basic block 1 starting at offset 0x2b
CFA: [30] def_cfa: %rsp+0x8
'as' is not recognized as an internal or external command,
operable program or batch file.
Method int BenchmarkDotNet.Samples.IntroDisassemblyAllJits:CallVirtualMethod () emitted at 000001DBB5131290 to 000001DBB51312C1 (code length 49) [BenchmarkDotNet.Samples.dll]
'x86_64-w64-mingw32-objdump.exe' is not recognized as an internal or external command,
operable program or batch file.
; Total bytes of code 0 Mono 5.16.0 (Visual Studio), 32bit; CallVirtualMethod
converting method int BenchmarkDotNet.Samples.IntroDisassemblyAllJits:CallVirtualMethod ()
created temp 0 (R8) of type System.Int32
creating vars
created temp 1 (R9) of type System.IntPtr
return : arg R8 <-
this: arg R9 <-
creating locals
locals done
method to IR BenchmarkDotNet.Samples.IntroDisassemblyAllJits:CallVirtualMethod ()
converting (in B2: stack: 0) IL_0000: ldarg.0
converting (in B2: stack: 1) IL_0001: ldfld 0x04000005
converting (in B2: stack: 1) IL_0006: ldc.i4.s 10
converting (in B2: stack: 2) IL_0008: callvirt 0x060000fc
INLINE START 02C85990 BenchmarkDotNet.Samples.IntroDisassemblyAllJits:CallVirtualMethod () -> BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)
created temp 2 (R13) of type System.Int32
method to IR BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)
created temp 3 (R14) of type System.Object
created temp 4 (R15) of type System.Int32
converting (in B7: stack: 0) IL_0000: ldarg.0
converting (in B7: stack: 1) IL_0001: ldarg.0
converting (in B7: stack: 2) IL_0002: ldarg.1
converting (in B7: stack: 3) IL_0003: callvirt 0x060000fb
inline failed: call
INLINE ABORTED BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int) (cost -1)
converting (in B2: stack: 1) IL_000d: ret
REGION BB0 IL_0000 ID_FFFFFFFF
REGION BB3 IL_0000 ID_FFFFFFFF
REGION BB2 IL_000d ID_FFFFFFFF
REGION BB1 IL_0000 ID_FFFFFFFF
AFTER METHOD-TO-IR 0: [IN: , OUT: BB3(0) ]
AFTER METHOD-TO-IR 3: [IN: BB0(0), OUT: BB2(0) ]
AFTER METHOD-TO-IR 2: [IN: BB3(0), OUT: BB1(0) ]
il_seq_point il: 0x0
move R10 <- R9
load_membase R11 <- [R10 + 0x8]
iconst R12 <- [10]
store_membase_reg [%esp + 0x4] <- R12
store_membase_reg [%esp] <- R11
checkthis [R11 + 0x0]
not_null R11
call R20 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
move R8 <- R20
br [B1]
AFTER METHOD-TO-IR 1: [IN: BB2(0), OUT: ]
CCOPY/2: R10 -> R9
remove_block_if_useless, removed BB3
br removal triggered 2 -> 1
HANDLE-GLOBAL-VREGS BLOCK 0:
HANDLE-GLOBAL-VREGS BLOCK 2:
il_seq_point il: 0x0
move R10 <- R9
load_membase R11 <- [R9 + 0x8]
iconst R12 <- [10]
store_membase_imm [%esp + 0x4] <- [10]
store_membase_reg [%esp] <- R11
checkthis [R11 + 0x0]
not_null R11
call R20 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
move R8 <- R20
nop
HANDLE-GLOBAL-VREGS BLOCK 1:
CONVERTED R13(2) TO VREG.
CONVERTED R14(3) TO VREG.
CONVERTED R15(4) TO VREG.
Reverse copyprop in BB2 on move R8 <- R20
BB0 IN:
BB2 IN: 0
BB1 IN: 2
DTREE BenchmarkDotNet.Samples.IntroDisassemblyAllJits:CallVirtualMethod () 0
BB0(dfn=0) (IDOM=BB-1): BB0
BB2(dfn=1) (IDOM=BB0): BB0 BB2
BB1(dfn=2) (IDOM=BB2): BB0 BB2 BB1
BEFORE LOWER-VTYPE-OPTS 0: [IN: , OUT: BB2(1) ]
AFTER LOWER-VTYPE-OPTS 0: [IN: , OUT: BB2(1) ]
BEFORE LOWER-VTYPE-OPTS 2: [IN: BB0(0), OUT: BB1(2) ]
il_seq_point il: 0x0
load_membase R11 <- [R9 + 0x8]
store_membase_imm [%esp + 0x4] <- [10]
store_membase_reg [%esp] <- R11
checkthis [R11 + 0x0]
not_null R11
call R8 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
AFTER LOWER-VTYPE-OPTS 2: [IN: BB0(0), OUT: BB1(2) ]
il_seq_point il: 0x0
load_membase R11 <- [R9 + 0x8]
store_membase_imm [%esp + 0x4] <- [10]
store_membase_reg [%esp] <- R11
checkthis [R11 + 0x0]
not_null R11
call R8 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
BEFORE LOWER-VTYPE-OPTS 1: [IN: BB2(1), OUT: ]
AFTER LOWER-VTYPE-OPTS 1: [IN: BB2(1), OUT: ]
LIVENESS:
BLOCK BB0 (BB2, ):
GEN BB0: {}
KILL BB0: {}
BLOCK BB2 (BB1, ):
1 il_seq_point il: 0x0
1 load_membase R11 <- [R9 + 0x8]
GEN: R9(1)
1 store_membase_imm [%esp + 0x4] <- [10]
'as' is not recognized as an internal or external command,
operable program or batch file.
1 store_membase_reg [%esp] <- R11
1 checkthis [R11 + 0x0]
1 not_null R11
1 call R8 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
KILL: R8(0)
1 il_seq_point il: 0xd, nonempty-stack
1 il_seq_point il: 0xd
GEN BB2: {1}
KILL BB2: {0}
BLOCK BB1 ():
GEN BB1: {}
KILL BB1: {}
ITERATION:
P: BB1(2): IN: BB2 OUT:
P: BB2(1): IN: BB0 OUT:BB1
LIVE IN BB2: {1}
P: BB0(0): IN: OUT:BB2
LIVE IN BB0: {1}
IT: 3 2.
LIVE IN BB1: {}
LIVE OUT BB1: {}
LIVE IN BB2: {1}
LIVE OUT BB2: {}
LIVE IN BB0: {1}
LIVE OUT BB0: {1}
V0: [0x0 - 0x4000f]
V1: [0x0 - 0x40004]
COSTLY: R1 C1 C3 %edi
NOT REGVAR: 1
SPILL BLOCK 0:
SPILL BLOCK 2:
il_seq_point il: 0x0
-1
1 il_seq_point il: 0x0
load_membase R11 <- [R9 + 0x8]
ii 11 9
1 load_membase R11 <- [R21 + 0x8]
store_membase_imm [%esp + 0x4] <- [10]
i -1
1 store_membase_imm [%esp + 0x4] <- [10]
store_membase_reg [%esp] <- R11
ii -1 11
1 store_membase_reg [%esp] <- R11
checkthis [R11 + 0x0]
i -1 11
1 checkthis [R11 + 0x0]
not_null R11
i -1 11
1 not_null R11
call R8 <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
i 8
1 call %eax <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
il_seq_point il: 0xd, nonempty-stack
-1
1 il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
-1
1 il_seq_point il: 0xd
SPILL BLOCK 1:
DUMP BLOCK 0:
DUMP BLOCK 2:
il_seq_point il: 0x0
load_membase R21 <- [%ebp + 0x8]
load_membase R11 <- [R21 + 0x8]
store_membase_imm [%esp + 0x4] <- [10]
store_membase_reg [%esp] <- R11
checkthis [R11 + 0x0]
not_null R11
call %eax <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
il_seq_point il: 0xd, nonempty-stack
il_seq_point il: 0xd
DUMP BLOCK 1:
LOCAL REGALLOC BLOCK 2:
1 il_seq_point il: 0x0
2 load_membase R21 <- [%ebp + 0x8]
3 load_membase R11 <- [R21 + 0x8]
4 store_membase_imm [%esp + 0x4] <- [10]
5 store_membase_reg [%esp] <- R11
6 checkthis [R11 + 0x0]
7 not_null R11
8 call %eax <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
9 il_seq_point il: 0xd, nonempty-stack
10 il_seq_point il: 0xd
liveness: %eax [8 - 8]
liveness: %esp [4 - 0]
liveness: R11 [3 - 3]
liveness: R21 [2 - 2]
processing: 10 il_seq_point il: 0xd
10 il_seq_point il: 0xd
processing: 9 il_seq_point il: 0xd, nonempty-stack
9 il_seq_point il: 0xd, nonempty-stack
processing: 8 call %eax <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
8 call %eax <- [BenchmarkDotNet.Samples.IntroDisassemblyAllJits/Operation:OperateTwice (int)] clobbers: c
processing: 7 not_null R11
assigned sreg1 %eax to R11
7 not_null %eax
processing: 6 checkthis [R11 + 0x0]
6 checkthis [%eax + 0x0]
processing: 5 store_membase_reg [%esp] <- R11
5 store_membase_reg [%esp] <- %eax
processing: 4 store_membase_imm [%esp + 0x4] <- [10]
4 store_membase_imm [%esp + 0x4] <- [10]
processing: 3 load_membase R11 <- [R21 + 0x8]
assigned dreg %eax to dest R11
freeable %eax (R11) (born in 3)
assigned sreg1 %eax to R21
3 load_membase %eax <- [%eax + 0x8]
processing: 2 load_membase R21 <- [%ebp + 0x8]
assigned dreg %eax to dest R21
freeable %eax (R21) (born in 2)
2 load_membase %eax <- [%ebp + 0x8]
processing: 1 il_seq_point il: 0x0
1 il_seq_point il: 0x0
CFA: [0] def_cfa: %esp+0x4
CFA: [0] offset: unknown at cfa-0x4
CFA: [1] def_cfa_offset: 0x8
CFA: [1] offset: %ebp at cfa-0x8
CFA: [3] def_cfa_reg: %ebp
Basic block 0 starting at offset 0x6
Basic block 2 starting at offset 0x6
Basic block 1 starting at offset 0x20
Method int BenchmarkDotNet.Samples.IntroDisassemblyAllJits:CallVirtualMethod () emitted at 05EB1198 to 05EB11BA (code length 34) [BenchmarkDotNet.Samples.dll]
'objdump' is not recognized as an internal or external command,
operable program or batch file.
; Total bytes of code 0 .NET Framework 4.7.2 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0; BenchmarkDotNet.Samples.IntroDisassemblyAllJits.CallVirtualMethod()
mov rax,qword ptr [rcx+8]
mov eax,dword ptr [rax+8]
lea edx,[rax+0Ah]
add eax,edx
ret
add byte ptr [rax],al
add byte ptr [rcx],bl
add byte ptr [rax],al
add byte ptr [rax],al
add byte ptr [rax],al
sbb byte ptr [rax-80h],al
adc cl,bh
jg M00_L00
M00_L00:
add bl,al
add byte ptr [rax],al
add byte ptr [rcx],bl
add byte ptr [rax],al
add byte ptr [rax],al
add byte ptr [rax],al
; Total bytes of code 44 Method got most probably inlined .NET Framework 4.7.2 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.3190.0; BenchmarkDotNet.Samples.IntroDisassemblyAllJits.CallVirtualMethod()
push ebp
mov ebp,esp
push esi
mov esi,dword ptr [ecx+4]
mov ecx,esi
mov edx,0Ah
mov eax,dword ptr [ecx]
mov eax,dword ptr [eax+28h]
call dword ptr [eax+10h]
mov edx,eax
mov ecx,esi
mov eax,dword ptr [ecx]
mov eax,dword ptr [eax+28h]
call dword ptr [eax+10h]
pop esi
pop ebp
ret
add byte ptr [eax],al
add byte ptr [eax],al
add byte ptr [eax],al
add byte ptr [eax],al
add byte ptr [eax],al
add ah,dl
dec esi
cmc
push es
add byte ptr [eax],al
add byte ptr [eax],al
int 3
dec esi
cmc
push es
pop esp
jmp 518B:C28B06B4
; Total bytes of code 68 Method got most probably inlined .NET Framework 4.7.2 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0; BenchmarkDotNet.Samples.IntroDisassemblyAllJits.CallVirtualMethod()
mov rax,qword ptr [rcx+8]
mov eax,dword ptr [rax+8]
lea edx,[rax+0Ah]
add eax,edx
ret
add byte ptr [rax],al
add byte ptr [rcx],bl
add byte ptr [rax],al
add byte ptr [rax],al
add byte ptr [rax],al
sbb byte ptr [rax+7Eh],al
adc cl,bh
jg M00_L00
M00_L00:
add bl,al
add byte ptr [rax],al
add byte ptr [rcx],bl
add byte ptr [rax],al
add byte ptr [rax],al
add byte ptr [rax],al
; Total bytes of code 44 Method got most probably inlined .NET Core 2.0.9 (CoreCLR 4.6.26614.01, CoreFX 4.6.26614.01), 64bit RyuJIT; BenchmarkDotNet.Samples.IntroDisassemblyAllJits.CallVirtualMethod()
push rsi
sub rsp,20h
mov rsi,qword ptr [rcx+8]
mov rcx,rsi
mov edx,0Ah
mov rax,qword ptr [rsi]
mov rax,qword ptr [rax+40h]
call qword ptr [rax+20h]
mov edx,eax
mov rcx,rsi
mov rax,qword ptr [rsi]
mov rax,qword ptr [rax+40h]
mov rax,qword ptr [rax+20h]
add rsp,20h
pop rsi
jmp rax
add byte ptr [rcx],bl
add eax,32050002h
add dword ptr [rax+3Eh],esp
add byte ptr [rax],al
add byte ptr [rax],al
add byte ptr [rax],al
add byte ptr [rax],al
add byte ptr [rax],al
add byte ptr [rax-73AA3DDh],cl
; Total bytes of code 77 Method got most probably inlined .NET Core 2.1.4 (CoreCLR 4.6.26814.03, CoreFX 4.6.26814.02), 64bit RyuJIT; BenchmarkDotNet.Samples.IntroDisassemblyAllJits.CallVirtualMethod()
mov rax,qword ptr [rcx+8]
mov eax,dword ptr [rax+8]
lea edx,[rax+0Ah]
add eax,edx
ret
add byte ptr [rax],al
add byte ptr [rcx],bl
add byte ptr [rax],al
add byte ptr [rax],al
add byte ptr [rax],al
jo 00007ff9`0c41295f
push rbp
or al,0F9h
jg M00_L00
M00_L00:
add bl,al
add byte ptr [rax],al
add byte ptr [rcx],bl
add byte ptr [rax],al
add byte ptr [rax],al
add byte ptr [rax],al
; Total bytes of code 44 No ILOffsetMap found |
@adamsitnik When will you be able to look at this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wojtpl2 another great PR! I am truly impressed!
I had few comments, mostly modulo ones.
Please change the behavior so we produce the diff only for the same benchmark executed for multiple runtimes. As soon as we have that and the CI is green, I merge it.
And big thanks for solving the file name conflict issue!
public string Name => nameof(PrettyHtmlDisassemblyExporter); | ||
|
||
public void ExportToLog(Summary summary, ILogger logger) { } | ||
private static int referenceIndex; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the idea of introducing a static state. Could you please create a local variable with the same name in ExportToLog
and pass it via reference to the Export
method?
{ | ||
var benchmarksCases = summary.BenchmarksCases |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this local variable is a good candidate for inlining.
so it would be just:
- foreach (var benchmarkCase in benchmarksCases)
+ foreach (var benchmarkCase in summary.BenchmarksCases).Where(results.ContainsKey))
|
||
public void ExportToLog(Summary summary, ILogger logger) { } | ||
public RawDisassemblyExporter(IReadOnlyDictionary<BenchmarkCase, DisassemblyResult> results) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: please keep =>
|
||
using (var stream = StreamWriter.FromPath(filePath)) | ||
foreach (var benchmarkCase in benchmarksCases) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: please inline benchmarksCases
@@ -141,5 +135,6 @@ internal static string FormatMethodAddress(ulong nativeCode) | |||
|
|||
return buffer.ToString(); | |||
} | |||
private static string GetImportantInfo(BenchmarkReport benchmarkReport) => benchmarkReport.GetRuntimeInfo(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: if this method is called only from one place, then it should also be inlined
|
||
namespace BenchmarkDotNet.Exporters | ||
{ | ||
public abstract class PrettyGithubMarkdownDisassemblyExporterBase : ExporterBase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am guilty of creating too many classes and too deep inheritance hierarchy in BenchmarkDotNet. We should not be doing this anymore (Composition over inheritance).
Could you put this method back to PrettyGithubMarkdownDisassemblyExporter
and do the following;
- make it static internal
- make
PrettyGithubMarkdownDisassemblyExporter
andPrettyGithubMarkdownDiffDisassemblyExporter
inherit directly fromExporterBase
- reuse
PrettyGithubMarkdownDisassemblyExporter.Export
inPrettyGithubMarkdownDiffDisassemblyExporter
|
||
private static void RunGitDiff(string firstFile, string secondFile, StringBuilder result) | ||
{ | ||
var startInfo = new ProcessStartInfo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to reuse ProcessHelper.RunAndReadOutput
here and simplify the code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can reuse ProcessHelper.RunAndReadOutputLineByLine
because ProcessHelper.RunAndReadOutput
doesn't throw exception in case git is not installed on the system. There is a problem:
BenchmarkDotNet/src/BenchmarkDotNet/Helpers/ProcessHelper.cs
Lines 29 to 36 in c724e94
try | |
{ | |
process.Start(); | |
} | |
catch (Exception) | |
{ | |
return null; | |
} |
I can refactor ProcessHelper but I think it should be a different task.
public override void ExportToLog(Summary summary, ILogger logger) | ||
{ | ||
var benchmarksCases = summary.BenchmarksCases | ||
.Where(results.ContainsKey).ToList(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: if you don't intend to add any elements to a materialized collection, you should prefer array over list. The best choice would be ImmutableArray
- materialized, fast and immutable
protected override string FileCaption => "asm.pretty.diff"; | ||
|
||
public PrettyGithubMarkdownDiffDisassemblyExporter(IReadOnlyDictionary<BenchmarkCase, DisassemblyResult> results) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: =>
|
||
RunGitDiff(firstFileName, secondFileName, builder); | ||
|
||
if (firstBenchmarkCase.Descriptor.WorkloadMethod == secondBenchmarkCase.Descriptor.WorkloadMethod) // diff between the same method for different JITs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this is the only case when we should be producing the diff if we want to have it enabled by default.
Example: a ListBenchmarks
type with 3 benchmarks: Add
, AddRange
and Insert
. When we use the disassembly diagnoser we want to get the disassembly for all 3 of them. But we are rather not interested in diff.
When we run it for few different Runtime settings, then we want to get the diff.
@wojtpl2 excellent! thank you!! |
@adamsitnik I can take another task. Do you have any preferences? Maybe this #678 ? In this task I found a weak point. This is because BenchmarkDotNet/src/BenchmarkDotNet/Exporters/ExporterBase.cs Lines 41 to 44 in a76f438
|
@wojtpl2 I have an idea: maybe producing the |
Great idea. Ok, I'll do it. |
Fixes for #544
I've changed all dissassembly exporters because the generated files were overwritten for each JIT.
I've used
git diff --no-index --no-color --text
to generate diff. I couldn't find any diff algorithm on MIT licence.In the next comments I will add examples of the reports that were published after my changes.