dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.47k stars 4.77k forks source link

[Perf] Regressions in System.Tests.Perf_String.Split #51259

Open DrewScoggins opened 3 years ago

DrewScoggins commented 3 years ago

Run Information

Architecture x64
OS Windows 10.0.18362
Baseline a7ed1fd065da1b2309c07bacc1b44d2e567107c8
Compare 5bad843281caac09e18958f27d7d914eb6086e77
Diff Diff

Regressions in System.Tests.Perf_String

Benchmark Baseline Test Test/Base Baseline IR Compare IR IR Ratio Baseline ETL Compare ETL
[Split](<https://pvscmdupload.blob.core.windows.net/reports/allTestHistory/refs/heads/main_x64_Windows 10.0.18362/System.Tests.Perf_String.Split(s%3a%20%22A%20B%20C%20D%20E%20F%20G%20H%20I%20J%20K%20L%20M%20N%20O%20P%20Q%20R%20S%20T%20U%20V%20W%20X%20Y%20Z%22%2c%20arr%3a%20%5b%27%20%27%5d%2c%20options%3a%20None).html>) 447.82 ns 475.44 ns 1.06 4901.795735129068 5308.495503816714 1.0829695463997007 Trace Trace
[Split](<https://pvscmdupload.blob.core.windows.net/reports/allTestHistory/refs/heads/main_x64_Windows 10.0.18362/System.Tests.Perf_String.Split(s%3a%20%22A%20B%20C%20D%20E%20F%20G%20H%20I%20J%20K%20L%20M%20N%20O%20P%20Q%20R%20S%20T%20U%20V%20W%20X%20Y%20Z%22%2c%20arr%3a%20%5b%27%20%27%5d%2c%20options%3a%20RemoveEmptyEntries).html>) 473.54 ns 534.99 ns 1.13 5192.342616628743 5599.544937428896 1.0784236231823507 Trace Trace

graph graph Historical Data in Reporting System

Repro

git clone https://github.com/dotnet/performance.git
py .\performance\scripts\benchmarks_ci.py -f netcoreapp5.0 --filter 'System.Tests.Perf_String*'
### Payloads [Baseline]() [Compare]() ### Histogram #### System.Tests.Perf_String.Remove_Int(s: "dzsdzsDDZSDZSDZSddsz", i: 7) ```log ``` ### Baseline Jit Disasm ```assembly ; System.Tests.Perf_String.Remove_Int(System.String, Int32) mov rcx,rdx mov edx,r8d cmp [rcx],ecx jmp near ptr System.String.Remove(Int32) ; Total bytes of code 13 ``` ```assembly ; System.String.Remove(Int32) push rdi push rsi push rbx sub rsp,20 mov r8d,[rcx+8] movsxd r8,r8d mov eax,edx cmp r8,rax jl short M01_L00 mov r8d,edx xor edx,edx add rsp,20 pop rbx pop rsi pop rdi jmp near ptr System.String.Substring(Int32, Int32) M01_L00: mov rcx,1D9CCCE5AD0 mov rsi,[rcx] test edx,edx jl short M01_L01 mov rcx,1D9CCCE5AF0 mov rcx,[rcx] xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov rdi,rax jmp short M01_L02 M01_L01: mov rcx,1D9CCCE5AE8 mov rcx,[rcx] xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov rdi,rax M01_L02: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rbx,rax mov rcx,rbx mov rdx,rsi mov r8,rdi call System.ArgumentOutOfRangeException..ctor(System.String, System.String) mov rcx,rbx call CORINFO_HELP_THROW int 3 ; Total bytes of code 144 ``` ### Compare Jit Disasm ```assembly ; System.Tests.Perf_String.Remove_Int(System.String, Int32) mov rcx,rdx mov edx,r8d cmp [rcx],ecx jmp near ptr System.String.Remove(Int32) ; Total bytes of code 13 ``` ```assembly ; System.String.Remove(Int32) push rdi push rsi push rbx sub rsp,20 mov r8d,[rcx+8] movsxd r8,r8d mov eax,edx cmp r8,rax jl short M01_L00 mov r8d,edx xor edx,edx add rsp,20 pop rbx pop rsi pop rdi jmp near ptr System.String.Substring(Int32, Int32) M01_L00: mov rcx,242E2DA5AD0 mov rsi,[rcx] test edx,edx jl short M01_L01 mov rcx,242E2DA5AF0 mov rcx,[rcx] xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov rdi,rax jmp short M01_L02 M01_L01: mov rcx,242E2DA5AE8 mov rcx,[rcx] xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov rdi,rax M01_L02: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rbx,rax mov rcx,rbx mov rdx,rsi mov r8,rdi call System.ArgumentOutOfRangeException..ctor(System.String, System.String) mov rcx,rbx call CORINFO_HELP_THROW int 3 ; Total bytes of code 144 ``` #### System.Tests.Perf_String.Split(s: "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z", arr: [' '], options: None) ```log ``` ### Baseline Jit Disasm ```assembly ; System.Tests.Perf_String.Split(System.String, Char[], System.StringSplitOptions) push rsi sub rsp,30 xor eax,eax mov [rsp+20],rax cmp [rdx],edx test r8,r8 je short M00_L01 lea rcx,[r8+10] mov esi,[r8+8] M00_L00: mov [rsp+20],rcx mov [rsp+28],esi mov rcx,rdx lea rdx,[rsp+20] mov r8d,7FFFFFFF call System.String.SplitInternal(System.ReadOnlySpan`1, Int32, System.StringSplitOptions) nop add rsp,30 pop rsi ret M00_L01: xor ecx,ecx xor esi,esi jmp short M00_L00 ; Total bytes of code 68 ``` ```assembly ; System.String.SplitInternal(System.ReadOnlySpan`1, Int32, System.StringSplitOptions) push rbp push r15 push r14 push r13 push r12 push rdi push rsi push rbx sub rsp,88 vzeroupper lea rbp,[rsp+30] xor eax,eax mov [rbp+8],rax vxorps xmm4,xmm4,xmm4 vmovdqa xmmword ptr [rbp+10],xmm4 vmovdqa xmmword ptr [rbp+20],xmm4 vmovdqa xmmword ptr [rbp+30],xmm4 vmovdqa xmmword ptr [rbp+40],xmm4 mov [rbp+50],rax mov rax,74B06C2F5775 mov [rbp],rax mov rsi,rcx mov edi,r8d mov ebx,r9d test edi,edi jl near ptr M01_L17 test ebx,0FFFFFFFC jne near ptr M01_L18 cmp edi,1 jle near ptr M01_L08 cmp dword ptr [rsi+8],0 je near ptr M01_L08 cmp dword ptr [rdx+8],0 jbe near ptr M01_L15 M01_L00: add rsp,30 test [rsp],esp sub rsp,200 sub rsp,30 lea rcx,[rsp+30] lea r8,[rbp+48] mov [r8],rcx mov dword ptr [r8+8],80 xor ecx,ecx mov [rbp+38],rcx mov [rbp+40],ecx vmovdqu xmm0,xmmword ptr [rdx] vmovdqu xmmword ptr [rbp+28],xmm0 mov rcx,rsi lea rdx,[rbp+28] lea r8,[rbp+38] call System.String.MakeSeparatorList(System.ReadOnlySpan`1, System.Collections.Generic.ValueListBuilder`1 ByRef) mov eax,[rbp+40] mov ecx,eax mov edx,[rbp+50] cmp rcx,rdx ja near ptr M01_L16 mov r10,[rbp+48] test eax,eax je near ptr M01_L07 test ebx,ebx jne near ptr M01_L09 xor r14d,r14d xor r15d,r15d mov [rbp+18],r10 mov [rbp+20],eax mov [rbp+8],r14 mov [rbp+10],r15d mov [rsp+20],edi mov rcx,rsi lea rdx,[rbp+18] lea r8,[rbp+8] mov r9d,1 call System.String.SplitWithoutPostProcessing(System.ReadOnlySpan`1, System.ReadOnlySpan`1, Int32, Int32) mov r12,rax M01_L01: cmp qword ptr [rbp+38],0 jne near ptr M01_L13 M01_L02: mov rax,r12 mov rcx,74B06C2F5775 cmp [rbp],rcx je short M01_L03 call CORINFO_HELP_FAIL_FAST M01_L03: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L04: test bl,1 jne near ptr M01_L10 M01_L05: test edi,edi je near ptr M01_L11 mov rcx,offset MT_System.String[] mov edx,1 call CORINFO_HELP_NEWARR_1_OBJ mov r14,rax lea rcx,[r14+10] mov rdx,r13 call CORINFO_HELP_ASSIGN_REF mov rax,r14 mov rcx,74B06C2F5775 cmp [rbp],rcx je short M01_L06 call CORINFO_HELP_FAIL_FAST M01_L06: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L07: mov edi,1 M01_L08: mov r13,rsi test bl,2 jne near ptr M01_L14 jmp short M01_L04 M01_L09: xor r14d,r14d xor r15d,r15d mov [rbp+18],r10 mov [rbp+20],eax mov [rbp+8],r14 mov [rbp+10],r15d mov [rsp+20],edi mov [rsp+28],ebx mov rcx,rsi lea rdx,[rbp+18] lea r8,[rbp+8] mov r9d,1 call System.String.SplitWithPostProcessing(System.ReadOnlySpan`1, System.ReadOnlySpan`1, Int32, Int32, System.StringSplitOptions) mov r12,rax jmp near ptr M01_L01 M01_L10: cmp dword ptr [r13+8],0 jne near ptr M01_L05 M01_L11: mov rcx,7FFD30584540 mov edx,28 call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS mov rax,1E4BE372EF0 mov rax,[rax] mov rcx,74B06C2F5775 cmp [rbp],rcx je short M01_L12 call CORINFO_HELP_FAIL_FAST M01_L12: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L13: mov rcx,7FFD30584540 mov edx,29 call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS mov rcx,1E4BE372EF8 mov rcx,[rcx] mov rdx,[rbp+38] xor r8d,r8d cmp [rcx],ecx call qword ptr [7FFD30843DB0] xor ecx,ecx mov [rbp+38],rcx jmp near ptr M01_L02 M01_L14: test edi,edi jle near ptr M01_L04 cmp [rsi],esi mov rcx,rsi mov edx,3 call System.String.TrimWhiteSpaceHelper(System.Text.TrimType) mov r13,rax jmp near ptr M01_L04 M01_L15: and ebx,0FFFFFFFD jmp near ptr M01_L00 M01_L16: call System.ThrowHelper.ThrowArgumentOutOfRangeException() int 3 M01_L17: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,1C9 mov rdx,7FFD30474020 call CORINFO_HELP_STRCNS mov rdi,rax mov ecx,0A1B7 mov rdx,7FFD30474020 call CORINFO_HELP_STRCNS mov rcx,rax xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov r8,rax mov rdx,rdi mov rcx,rsi call System.ArgumentOutOfRangeException..ctor(System.String, System.String) mov rcx,rsi call CORINFO_HELP_THROW M01_L18: mov ecx,42 mov edx,57 call System.ThrowHelper.ThrowArgumentException(System.ExceptionResource, System.ExceptionArgument) int 3 ; Total bytes of code 813 ``` ### Compare Jit Disasm ```assembly ; System.Tests.Perf_String.Split(System.String, Char[], System.StringSplitOptions) push rsi sub rsp,30 xor eax,eax mov [rsp+20],rax cmp [rdx],edx test r8,r8 je short M00_L01 lea rcx,[r8+10] mov esi,[r8+8] M00_L00: mov [rsp+20],rcx mov [rsp+28],esi mov rcx,rdx lea rdx,[rsp+20] mov r8d,7FFFFFFF call System.String.SplitInternal(System.ReadOnlySpan`1, Int32, System.StringSplitOptions) nop add rsp,30 pop rsi ret M00_L01: xor ecx,ecx xor esi,esi jmp short M00_L00 ; Total bytes of code 68 ``` ```assembly ; System.String.SplitInternal(System.ReadOnlySpan`1, Int32, System.StringSplitOptions) push rbp push r15 push r14 push r13 push r12 push rdi push rsi push rbx sub rsp,88 vzeroupper lea rbp,[rsp+30] xor eax,eax mov [rbp+8],rax vxorps xmm4,xmm4,xmm4 vmovdqa xmmword ptr [rbp+10],xmm4 vmovdqa xmmword ptr [rbp+20],xmm4 vmovdqa xmmword ptr [rbp+30],xmm4 vmovdqa xmmword ptr [rbp+40],xmm4 mov [rbp+50],rax mov rax,66EA0E1BF416 mov [rbp],rax mov rsi,rcx mov edi,r8d mov ebx,r9d test edi,edi jl near ptr M01_L17 test ebx,0FFFFFFFC jne near ptr M01_L18 cmp edi,1 jle near ptr M01_L08 cmp dword ptr [rsi+8],0 je near ptr M01_L08 cmp dword ptr [rdx+8],0 jbe near ptr M01_L15 M01_L00: add rsp,30 test [rsp],esp sub rsp,200 sub rsp,30 lea rcx,[rsp+30] lea r8,[rbp+48] mov [r8],rcx mov dword ptr [r8+8],80 xor ecx,ecx mov [rbp+38],rcx mov [rbp+40],ecx vmovdqu xmm0,xmmword ptr [rdx] vmovdqu xmmword ptr [rbp+28],xmm0 mov rcx,rsi lea rdx,[rbp+28] lea r8,[rbp+38] call System.String.MakeSeparatorList(System.ReadOnlySpan`1, System.Collections.Generic.ValueListBuilder`1 ByRef) mov eax,[rbp+40] mov ecx,eax mov edx,[rbp+50] cmp rcx,rdx ja near ptr M01_L16 mov r10,[rbp+48] test eax,eax je near ptr M01_L07 test ebx,ebx jne near ptr M01_L09 xor r14d,r14d xor r15d,r15d mov [rbp+18],r10 mov [rbp+20],eax mov [rbp+8],r14 mov [rbp+10],r15d mov [rsp+20],edi mov rcx,rsi lea rdx,[rbp+18] lea r8,[rbp+8] mov r9d,1 call System.String.SplitWithoutPostProcessing(System.ReadOnlySpan`1, System.ReadOnlySpan`1, Int32, Int32) mov r12,rax M01_L01: cmp qword ptr [rbp+38],0 jne near ptr M01_L13 M01_L02: mov rax,r12 mov rcx,66EA0E1BF416 cmp [rbp],rcx je short M01_L03 call CORINFO_HELP_FAIL_FAST M01_L03: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L04: test bl,1 jne near ptr M01_L10 M01_L05: test edi,edi je near ptr M01_L11 mov rcx,offset MT_System.String[] mov edx,1 call CORINFO_HELP_NEWARR_1_OBJ mov r14,rax lea rcx,[r14+10] mov rdx,r13 call CORINFO_HELP_ASSIGN_REF mov rax,r14 mov rcx,66EA0E1BF416 cmp [rbp],rcx je short M01_L06 call CORINFO_HELP_FAIL_FAST M01_L06: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L07: mov edi,1 M01_L08: mov r13,rsi test bl,2 jne near ptr M01_L14 jmp short M01_L04 M01_L09: xor r14d,r14d xor r15d,r15d mov [rbp+18],r10 mov [rbp+20],eax mov [rbp+8],r14 mov [rbp+10],r15d mov [rsp+20],edi mov [rsp+28],ebx mov rcx,rsi lea rdx,[rbp+18] lea r8,[rbp+8] mov r9d,1 call System.String.SplitWithPostProcessing(System.ReadOnlySpan`1, System.ReadOnlySpan`1, Int32, Int32, System.StringSplitOptions) mov r12,rax jmp near ptr M01_L01 M01_L10: cmp dword ptr [r13+8],0 jne near ptr M01_L05 M01_L11: mov rcx,7FFF5B9D4550 mov edx,28 call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS mov rax,1F298002EF0 mov rax,[rax] mov rcx,66EA0E1BF416 cmp [rbp],rcx je short M01_L12 call CORINFO_HELP_FAIL_FAST M01_L12: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L13: mov rcx,7FFF5B9D4550 mov edx,29 call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS mov rcx,1F298002EF8 mov rcx,[rcx] mov rdx,[rbp+38] xor r8d,r8d cmp [rcx],ecx call qword ptr [7FFF5BC945C8] xor ecx,ecx mov [rbp+38],rcx jmp near ptr M01_L02 M01_L14: test edi,edi jle near ptr M01_L04 cmp [rsi],esi mov rcx,rsi mov edx,3 call System.String.TrimWhiteSpaceHelper(System.Text.TrimType) mov r13,rax jmp near ptr M01_L04 M01_L15: and ebx,0FFFFFFFD jmp near ptr M01_L00 M01_L16: call System.ThrowHelper.ThrowArgumentOutOfRangeException() int 3 M01_L17: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,1C9 mov rdx,7FFF5B8C4020 call CORINFO_HELP_STRCNS mov rdi,rax mov ecx,0A21D mov rdx,7FFF5B8C4020 call CORINFO_HELP_STRCNS mov rcx,rax xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov r8,rax mov rdx,rdi mov rcx,rsi call System.ArgumentOutOfRangeException..ctor(System.String, System.String) mov rcx,rsi call CORINFO_HELP_THROW M01_L18: mov ecx,42 mov edx,57 call System.ThrowHelper.ThrowArgumentException(System.ExceptionResource, System.ExceptionArgument) int 3 ; Total bytes of code 813 ``` #### System.Tests.Perf_String.Remove_Int(s: "dzsdzsDDZSDZSDZSddsz", i: 10) ```log ``` ### Baseline Jit Disasm ```assembly ; System.Tests.Perf_String.Remove_Int(System.String, Int32) mov rcx,rdx mov edx,r8d cmp [rcx],ecx jmp near ptr System.String.Remove(Int32) ; Total bytes of code 13 ``` ```assembly ; System.String.Remove(Int32) push rdi push rsi push rbx sub rsp,20 mov r8d,[rcx+8] movsxd r8,r8d mov eax,edx cmp r8,rax jl short M01_L00 mov r8d,edx xor edx,edx add rsp,20 pop rbx pop rsi pop rdi jmp near ptr System.String.Substring(Int32, Int32) M01_L00: mov rcx,23C27A15AD0 mov rsi,[rcx] test edx,edx jl short M01_L01 mov rcx,23C27A15AF0 mov rcx,[rcx] xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov rdi,rax jmp short M01_L02 M01_L01: mov rcx,23C27A15AE8 mov rcx,[rcx] xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov rdi,rax M01_L02: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rbx,rax mov rcx,rbx mov rdx,rsi mov r8,rdi call System.ArgumentOutOfRangeException..ctor(System.String, System.String) mov rcx,rbx call CORINFO_HELP_THROW int 3 ; Total bytes of code 144 ``` ### Compare Jit Disasm ```assembly ; System.Tests.Perf_String.Remove_Int(System.String, Int32) mov rcx,rdx mov edx,r8d cmp [rcx],ecx jmp near ptr System.String.Remove(Int32) ; Total bytes of code 13 ``` ```assembly ; System.String.Remove(Int32) push rdi push rsi push rbx sub rsp,20 mov r8d,[rcx+8] movsxd r8,r8d mov eax,edx cmp r8,rax jl short M01_L00 mov r8d,edx xor edx,edx add rsp,20 pop rbx pop rsi pop rdi jmp near ptr System.String.Substring(Int32, Int32) M01_L00: mov rcx,2119C895AD0 mov rsi,[rcx] test edx,edx jl short M01_L01 mov rcx,2119C895AF0 mov rcx,[rcx] xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov rdi,rax jmp short M01_L02 M01_L01: mov rcx,2119C895AE8 mov rcx,[rcx] xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov rdi,rax M01_L02: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rbx,rax mov rcx,rbx mov rdx,rsi mov r8,rdi call System.ArgumentOutOfRangeException..ctor(System.String, System.String) mov rcx,rbx call CORINFO_HELP_THROW int 3 ; Total bytes of code 144 ``` #### System.Tests.Perf_String.IndexerCheckBoundCheckHoist ```log ``` ### Baseline Jit Disasm ```assembly ; System.Tests.Perf_String.IndexerCheckBoundCheckHoist() sub rsp,28 mov rcx,7FFF9CD3B1C8 mov edx,18A call CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE mov rax,217EAE19428 mov rax,[rax] mov rdx,rax xor ecx,ecx mov eax,[rax+8] xor r8d,r8d test eax,eax jle short M00_L02 cmp [rdx+8],eax setge r9b movzx r9d,r9b mov r10d,eax not r10d shr r10d,1F test r10d,r9d je short M00_L01 xchg ax,ax M00_L00: movsxd r9,r8d movzx r9d,word ptr [rdx+r9*2+0C] add ecx,r9d inc r8d cmp r8d,eax jl short M00_L00 jmp short M00_L02 M00_L01: cmp r8d,[rdx+8] jae short M00_L03 movsxd r9,r8d movzx r9d,word ptr [rdx+r9*2+0C] add r9d,ecx mov ecx,r9d inc r8d cmp r8d,eax jl short M00_L01 M00_L02: mov eax,ecx add rsp,28 ret M00_L03: call CORINFO_HELP_RNGCHKFAIL int 3 ; Total bytes of code 144 ``` ### Compare Jit Disasm ```assembly ; System.Tests.Perf_String.IndexerCheckBoundCheckHoist() sub rsp,28 mov rcx,7FFD6FA5B5C8 mov edx,18A call CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE mov rax,1C759A89428 mov rax,[rax] mov rdx,rax xor ecx,ecx mov eax,[rax+8] xor r8d,r8d test eax,eax jle short M00_L02 cmp [rdx+8],eax setge r9b movzx r9d,r9b mov r10d,eax not r10d shr r10d,1F test r10d,r9d je short M00_L01 xchg ax,ax M00_L00: movsxd r9,r8d movzx r9d,word ptr [rdx+r9*2+0C] add ecx,r9d inc r8d cmp r8d,eax jl short M00_L00 jmp short M00_L02 M00_L01: cmp r8d,[rdx+8] jae short M00_L03 movsxd r9,r8d movzx r9d,word ptr [rdx+r9*2+0C] add r9d,ecx mov ecx,r9d inc r8d cmp r8d,eax jl short M00_L01 M00_L02: mov eax,ecx add rsp,28 ret M00_L03: call CORINFO_HELP_RNGCHKFAIL int 3 ; Total bytes of code 144 ``` #### System.Tests.Perf_String.Insert(s1: "dzsdzsDDZSDZSDZSddsz", i: 7, s2: "Test") ```log ``` ### Baseline Jit Disasm ```assembly ; System.Tests.Perf_String.Insert(System.String, Int32, System.String) mov rcx,rdx mov edx,r8d mov r8,r9 cmp [rcx],ecx jmp near ptr System.String.Insert(Int32, System.String) ; Total bytes of code 16 ``` ```assembly ; System.String.Insert(Int32, System.String) push r15 push r14 push r13 push r12 push rdi push rsi push rbp push rbx sub rsp,28 mov rdi,rcx mov ebx,edx mov rsi,r8 test rsi,rsi je near ptr M01_L02 mov ebp,[rdi+8] movsxd rax,ebp mov ecx,ebx cmp rax,rcx jl near ptr M01_L03 mov r14d,[rsi+8] test ebp,ebp jne short M01_L00 mov rax,rsi add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L00: test r14d,r14d jne short M01_L01 mov rax,rdi add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L01: lea ecx,[r14+rbp] call System.String.FastAllocateString(Int32) mov r15,rax cmp [r15],r15d lea r12,[r15+0C] mov rcx,r12 lea rdx,[rdi+0C] movsxd r13,ebx add r13,r13 mov r8,r13 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) mov rcx,r12 add rcx,r13 lea rdx,[rsi+0C] movsxd r8,r14d add r8,r8 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) add r14d,ebx movsxd r8,r14d lea rcx,[r12+r8*2] add rdi,0C lea rdx,[rdi+r13] sub ebp,ebx movsxd r8,ebp add r8,r8 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) mov rax,r15 add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L02: mov rcx,offset MT_System.ArgumentNullException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,305 mov rdx,7FFB09DF4020 call CORINFO_HELP_STRCNS mov rdx,rax mov rcx,rsi call System.ArgumentNullException..ctor(System.String) mov rcx,rsi call CORINFO_HELP_THROW M01_L03: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,199A mov rdx,7FFB09DF4020 call CORINFO_HELP_STRCNS mov rdx,rax mov rcx,rsi call System.ArgumentOutOfRangeException..ctor(System.String) mov rcx,rsi call CORINFO_HELP_THROW int 3 ; Total bytes of code 330 ``` ### Compare Jit Disasm ```assembly ; System.Tests.Perf_String.Insert(System.String, Int32, System.String) mov rcx,rdx mov edx,r8d mov r8,r9 cmp [rcx],ecx jmp near ptr System.String.Insert(Int32, System.String) ; Total bytes of code 16 ``` ```assembly ; System.String.Insert(Int32, System.String) push r15 push r14 push r13 push r12 push rdi push rsi push rbp push rbx sub rsp,28 mov rdi,rcx mov ebx,edx mov rsi,r8 test rsi,rsi je near ptr M01_L02 mov ebp,[rdi+8] movsxd rax,ebp mov ecx,ebx cmp rax,rcx jl near ptr M01_L03 mov r14d,[rsi+8] test ebp,ebp jne short M01_L00 mov rax,rsi add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L00: test r14d,r14d jne short M01_L01 mov rax,rdi add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L01: lea ecx,[r14+rbp] call System.String.FastAllocateString(Int32) mov r15,rax cmp [r15],r15d lea r12,[r15+0C] mov rcx,r12 lea rdx,[rdi+0C] movsxd r13,ebx add r13,r13 mov r8,r13 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) mov rcx,r12 add rcx,r13 lea rdx,[rsi+0C] movsxd r8,r14d add r8,r8 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) add r14d,ebx movsxd r8,r14d lea rcx,[r12+r8*2] add rdi,0C lea rdx,[rdi+r13] sub ebp,ebx movsxd r8,ebp add r8,r8 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) mov rax,r15 add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L02: mov rcx,offset MT_System.ArgumentNullException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,305 mov rdx,7FFC62054020 call CORINFO_HELP_STRCNS mov rdx,rax mov rcx,rsi call System.ArgumentNullException..ctor(System.String) mov rcx,rsi call CORINFO_HELP_THROW M01_L03: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,199A mov rdx,7FFC62054020 call CORINFO_HELP_STRCNS mov rdx,rax mov rcx,rsi call System.ArgumentOutOfRangeException..ctor(System.String) mov rcx,rsi call CORINFO_HELP_THROW int 3 ; Total bytes of code 330 ``` #### System.Tests.Perf_String.Trim_CharArr(s: " Test", c: [' ', ' ']) ```log ``` ### Baseline Jit Disasm ```assembly ; System.Tests.Perf_String.Trim_CharArr(System.String, Char[]) mov rcx,rdx mov rdx,r8 cmp [rcx],ecx jmp near ptr System.String.Trim(Char[]) ; Total bytes of code 13 ``` ```assembly ; System.String.Trim(Char[]) sub rsp,28 xor eax,eax mov [rsp+20],rax test rdx,rdx je short M01_L00 mov r8d,[rdx+8] test r8d,r8d je short M01_L00 add rdx,10 mov [rsp+20],rdx mov rdx,[rsp+20] mov r9d,3 call System.String.TrimHelper(Char*, Int32, System.Text.TrimType) nop add rsp,28 ret M01_L00: mov edx,3 call System.String.TrimWhiteSpaceHelper(System.Text.TrimType) nop add rsp,28 ret ; Total bytes of code 72 ``` ### Compare Jit Disasm ```assembly ; System.Tests.Perf_String.Trim_CharArr(System.String, Char[]) mov rcx,rdx mov rdx,r8 cmp [rcx],ecx jmp near ptr System.String.Trim(Char[]) ; Total bytes of code 13 ``` ```assembly ; System.String.Trim(Char[]) sub rsp,28 xor eax,eax mov [rsp+20],rax test rdx,rdx je short M01_L00 mov r8d,[rdx+8] test r8d,r8d je short M01_L00 add rdx,10 mov [rsp+20],rdx mov rdx,[rsp+20] mov r9d,3 call System.String.TrimHelper(Char*, Int32, System.Text.TrimType) nop add rsp,28 ret M01_L00: mov edx,3 call System.String.TrimWhiteSpaceHelper(System.Text.TrimType) nop add rsp,28 ret ; Total bytes of code 72 ``` #### System.Tests.Perf_String.Insert(s1: "Test", i: 2, s2: " Test") ```log ``` ### Baseline Jit Disasm ```assembly ; System.Tests.Perf_String.Insert(System.String, Int32, System.String) mov rcx,rdx mov edx,r8d mov r8,r9 cmp [rcx],ecx jmp near ptr System.String.Insert(Int32, System.String) ; Total bytes of code 16 ``` ```assembly ; System.String.Insert(Int32, System.String) push r15 push r14 push r13 push r12 push rdi push rsi push rbp push rbx sub rsp,28 mov rdi,rcx mov ebx,edx mov rsi,r8 test rsi,rsi je near ptr M01_L02 mov ebp,[rdi+8] movsxd rax,ebp mov ecx,ebx cmp rax,rcx jl near ptr M01_L03 mov r14d,[rsi+8] test ebp,ebp jne short M01_L00 mov rax,rsi add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L00: test r14d,r14d jne short M01_L01 mov rax,rdi add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L01: lea ecx,[r14+rbp] call System.String.FastAllocateString(Int32) mov r15,rax cmp [r15],r15d lea r12,[r15+0C] mov rcx,r12 lea rdx,[rdi+0C] movsxd r13,ebx add r13,r13 mov r8,r13 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) mov rcx,r12 add rcx,r13 lea rdx,[rsi+0C] movsxd r8,r14d add r8,r8 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) add r14d,ebx movsxd r8,r14d lea rcx,[r12+r8*2] add rdi,0C lea rdx,[rdi+r13] sub ebp,ebx movsxd r8,ebp add r8,r8 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) mov rax,r15 add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L02: mov rcx,offset MT_System.ArgumentNullException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,305 mov rdx,7FFB0AD64020 call CORINFO_HELP_STRCNS mov rdx,rax mov rcx,rsi call System.ArgumentNullException..ctor(System.String) mov rcx,rsi call CORINFO_HELP_THROW M01_L03: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,199A mov rdx,7FFB0AD64020 call CORINFO_HELP_STRCNS mov rdx,rax mov rcx,rsi call System.ArgumentOutOfRangeException..ctor(System.String) mov rcx,rsi call CORINFO_HELP_THROW int 3 ; Total bytes of code 330 ``` ### Compare Jit Disasm ```assembly ; System.Tests.Perf_String.Insert(System.String, Int32, System.String) mov rcx,rdx mov edx,r8d mov r8,r9 cmp [rcx],ecx jmp near ptr System.String.Insert(Int32, System.String) ; Total bytes of code 16 ``` ```assembly ; System.String.Insert(Int32, System.String) push r15 push r14 push r13 push r12 push rdi push rsi push rbp push rbx sub rsp,28 mov rdi,rcx mov ebx,edx mov rsi,r8 test rsi,rsi je near ptr M01_L02 mov ebp,[rdi+8] movsxd rax,ebp mov ecx,ebx cmp rax,rcx jl near ptr M01_L03 mov r14d,[rsi+8] test ebp,ebp jne short M01_L00 mov rax,rsi add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L00: test r14d,r14d jne short M01_L01 mov rax,rdi add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L01: lea ecx,[r14+rbp] call System.String.FastAllocateString(Int32) mov r15,rax cmp [r15],r15d lea r12,[r15+0C] mov rcx,r12 lea rdx,[rdi+0C] movsxd r13,ebx add r13,r13 mov r8,r13 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) mov rcx,r12 add rcx,r13 lea rdx,[rsi+0C] movsxd r8,r14d add r8,r8 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) add r14d,ebx movsxd r8,r14d lea rcx,[r12+r8*2] add rdi,0C lea rdx,[rdi+r13] sub ebp,ebx movsxd r8,ebp add r8,r8 call System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr) mov rax,r15 add rsp,28 pop rbx pop rbp pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 ret M01_L02: mov rcx,offset MT_System.ArgumentNullException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,305 mov rdx,7FFC68CF4020 call CORINFO_HELP_STRCNS mov rdx,rax mov rcx,rsi call System.ArgumentNullException..ctor(System.String) mov rcx,rsi call CORINFO_HELP_THROW M01_L03: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,199A mov rdx,7FFC68CF4020 call CORINFO_HELP_STRCNS mov rdx,rax mov rcx,rsi call System.ArgumentOutOfRangeException..ctor(System.String) mov rcx,rsi call CORINFO_HELP_THROW int 3 ; Total bytes of code 330 ``` #### System.Tests.Perf_String.Split(s: "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z", arr: [' '], options: RemoveEmptyEntries) ```log ``` ### Baseline Jit Disasm ```assembly ; System.Tests.Perf_String.Split(System.String, Char[], System.StringSplitOptions) push rsi sub rsp,30 xor eax,eax mov [rsp+20],rax cmp [rdx],edx test r8,r8 je short M00_L01 lea rcx,[r8+10] mov esi,[r8+8] M00_L00: mov [rsp+20],rcx mov [rsp+28],esi mov rcx,rdx lea rdx,[rsp+20] mov r8d,7FFFFFFF call System.String.SplitInternal(System.ReadOnlySpan`1, Int32, System.StringSplitOptions) nop add rsp,30 pop rsi ret M00_L01: xor ecx,ecx xor esi,esi jmp short M00_L00 ; Total bytes of code 68 ``` ```assembly ; System.String.SplitInternal(System.ReadOnlySpan`1, Int32, System.StringSplitOptions) push rbp push r15 push r14 push r13 push r12 push rdi push rsi push rbx sub rsp,88 vzeroupper lea rbp,[rsp+30] xor eax,eax mov [rbp+8],rax vxorps xmm4,xmm4,xmm4 vmovdqa xmmword ptr [rbp+10],xmm4 vmovdqa xmmword ptr [rbp+20],xmm4 vmovdqa xmmword ptr [rbp+30],xmm4 vmovdqa xmmword ptr [rbp+40],xmm4 mov [rbp+50],rax mov rax,0A468D8BE0260 mov [rbp],rax mov rsi,rcx mov edi,r8d mov ebx,r9d test edi,edi jl near ptr M01_L17 test ebx,0FFFFFFFC jne near ptr M01_L18 cmp edi,1 jle near ptr M01_L08 cmp dword ptr [rsi+8],0 je near ptr M01_L08 cmp dword ptr [rdx+8],0 jbe near ptr M01_L15 M01_L00: add rsp,30 test [rsp],esp sub rsp,200 sub rsp,30 lea rcx,[rsp+30] lea r8,[rbp+48] mov [r8],rcx mov dword ptr [r8+8],80 xor ecx,ecx mov [rbp+38],rcx mov [rbp+40],ecx vmovdqu xmm0,xmmword ptr [rdx] vmovdqu xmmword ptr [rbp+28],xmm0 mov rcx,rsi lea rdx,[rbp+28] lea r8,[rbp+38] call System.String.MakeSeparatorList(System.ReadOnlySpan`1, System.Collections.Generic.ValueListBuilder`1 ByRef) mov eax,[rbp+40] mov ecx,eax mov edx,[rbp+50] cmp rcx,rdx ja near ptr M01_L16 mov r10,[rbp+48] test eax,eax je near ptr M01_L07 test ebx,ebx jne near ptr M01_L09 xor r14d,r14d xor r15d,r15d mov [rbp+18],r10 mov [rbp+20],eax mov [rbp+8],r14 mov [rbp+10],r15d mov [rsp+20],edi mov rcx,rsi lea rdx,[rbp+18] lea r8,[rbp+8] mov r9d,1 call System.String.SplitWithoutPostProcessing(System.ReadOnlySpan`1, System.ReadOnlySpan`1, Int32, Int32) mov r12,rax M01_L01: cmp qword ptr [rbp+38],0 jne near ptr M01_L13 M01_L02: mov rax,r12 mov rcx,0A468D8BE0260 cmp [rbp],rcx je short M01_L03 call CORINFO_HELP_FAIL_FAST M01_L03: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L04: test bl,1 jne near ptr M01_L10 M01_L05: test edi,edi je near ptr M01_L11 mov rcx,offset MT_System.String[] mov edx,1 call CORINFO_HELP_NEWARR_1_OBJ mov r14,rax lea rcx,[r14+10] mov rdx,r13 call CORINFO_HELP_ASSIGN_REF mov rax,r14 mov rcx,0A468D8BE0260 cmp [rbp],rcx je short M01_L06 call CORINFO_HELP_FAIL_FAST M01_L06: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L07: mov edi,1 M01_L08: mov r13,rsi test bl,2 jne near ptr M01_L14 jmp short M01_L04 M01_L09: xor r14d,r14d xor r15d,r15d mov [rbp+18],r10 mov [rbp+20],eax mov [rbp+8],r14 mov [rbp+10],r15d mov [rsp+20],edi mov [rsp+28],ebx mov rcx,rsi lea rdx,[rbp+18] lea r8,[rbp+8] mov r9d,1 call System.String.SplitWithPostProcessing(System.ReadOnlySpan`1, System.ReadOnlySpan`1, Int32, Int32, System.StringSplitOptions) mov r12,rax jmp near ptr M01_L01 M01_L10: cmp dword ptr [r13+8],0 jne near ptr M01_L05 M01_L11: mov rcx,7FFD305B4540 mov edx,28 call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS mov rax,26F43432EF0 mov rax,[rax] mov rcx,0A468D8BE0260 cmp [rbp],rcx je short M01_L12 call CORINFO_HELP_FAIL_FAST M01_L12: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L13: mov rcx,7FFD305B4540 mov edx,29 call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS mov rcx,26F43432EF8 mov rcx,[rcx] mov rdx,[rbp+38] xor r8d,r8d cmp [rcx],ecx call qword ptr [7FFD30874528] xor ecx,ecx mov [rbp+38],rcx jmp near ptr M01_L02 M01_L14: test edi,edi jle near ptr M01_L04 cmp [rsi],esi mov rcx,rsi mov edx,3 call System.String.TrimWhiteSpaceHelper(System.Text.TrimType) mov r13,rax jmp near ptr M01_L04 M01_L15: and ebx,0FFFFFFFD jmp near ptr M01_L00 M01_L16: call System.ThrowHelper.ThrowArgumentOutOfRangeException() int 3 M01_L17: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,1C9 mov rdx,7FFD304A4020 call CORINFO_HELP_STRCNS mov rdi,rax mov ecx,0A1B7 mov rdx,7FFD304A4020 call CORINFO_HELP_STRCNS mov rcx,rax xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov r8,rax mov rdx,rdi mov rcx,rsi call System.ArgumentOutOfRangeException..ctor(System.String, System.String) mov rcx,rsi call CORINFO_HELP_THROW M01_L18: mov ecx,42 mov edx,57 call System.ThrowHelper.ThrowArgumentException(System.ExceptionResource, System.ExceptionArgument) int 3 ; Total bytes of code 813 ``` ### Compare Jit Disasm ```assembly ; System.Tests.Perf_String.Split(System.String, Char[], System.StringSplitOptions) push rsi sub rsp,30 xor eax,eax mov [rsp+20],rax cmp [rdx],edx test r8,r8 je short M00_L01 lea rcx,[r8+10] mov esi,[r8+8] M00_L00: mov [rsp+20],rcx mov [rsp+28],esi mov rcx,rdx lea rdx,[rsp+20] mov r8d,7FFFFFFF call System.String.SplitInternal(System.ReadOnlySpan`1, Int32, System.StringSplitOptions) nop add rsp,30 pop rsi ret M00_L01: xor ecx,ecx xor esi,esi jmp short M00_L00 ; Total bytes of code 68 ``` ```assembly ; System.String.SplitInternal(System.ReadOnlySpan`1, Int32, System.StringSplitOptions) push rbp push r15 push r14 push r13 push r12 push rdi push rsi push rbx sub rsp,88 vzeroupper lea rbp,[rsp+30] xor eax,eax mov [rbp+8],rax vxorps xmm4,xmm4,xmm4 vmovdqa xmmword ptr [rbp+10],xmm4 vmovdqa xmmword ptr [rbp+20],xmm4 vmovdqa xmmword ptr [rbp+30],xmm4 vmovdqa xmmword ptr [rbp+40],xmm4 mov [rbp+50],rax mov rax,501E46E3C13B mov [rbp],rax mov rsi,rcx mov edi,r8d mov ebx,r9d test edi,edi jl near ptr M01_L17 test ebx,0FFFFFFFC jne near ptr M01_L18 cmp edi,1 jle near ptr M01_L08 cmp dword ptr [rsi+8],0 je near ptr M01_L08 cmp dword ptr [rdx+8],0 jbe near ptr M01_L15 M01_L00: add rsp,30 test [rsp],esp sub rsp,200 sub rsp,30 lea rcx,[rsp+30] lea r8,[rbp+48] mov [r8],rcx mov dword ptr [r8+8],80 xor ecx,ecx mov [rbp+38],rcx mov [rbp+40],ecx vmovdqu xmm0,xmmword ptr [rdx] vmovdqu xmmword ptr [rbp+28],xmm0 mov rcx,rsi lea rdx,[rbp+28] lea r8,[rbp+38] call System.String.MakeSeparatorList(System.ReadOnlySpan`1, System.Collections.Generic.ValueListBuilder`1 ByRef) mov eax,[rbp+40] mov ecx,eax mov edx,[rbp+50] cmp rcx,rdx ja near ptr M01_L16 mov r10,[rbp+48] test eax,eax je near ptr M01_L07 test ebx,ebx jne near ptr M01_L09 xor r14d,r14d xor r15d,r15d mov [rbp+18],r10 mov [rbp+20],eax mov [rbp+8],r14 mov [rbp+10],r15d mov [rsp+20],edi mov rcx,rsi lea rdx,[rbp+18] lea r8,[rbp+8] mov r9d,1 call System.String.SplitWithoutPostProcessing(System.ReadOnlySpan`1, System.ReadOnlySpan`1, Int32, Int32) mov r12,rax M01_L01: cmp qword ptr [rbp+38],0 jne near ptr M01_L13 M01_L02: mov rax,r12 mov rcx,501E46E3C13B cmp [rbp],rcx je short M01_L03 call CORINFO_HELP_FAIL_FAST M01_L03: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L04: test bl,1 jne near ptr M01_L10 M01_L05: test edi,edi je near ptr M01_L11 mov rcx,offset MT_System.String[] mov edx,1 call CORINFO_HELP_NEWARR_1_OBJ mov r14,rax lea rcx,[r14+10] mov rdx,r13 call CORINFO_HELP_ASSIGN_REF mov rax,r14 mov rcx,501E46E3C13B cmp [rbp],rcx je short M01_L06 call CORINFO_HELP_FAIL_FAST M01_L06: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L07: mov edi,1 M01_L08: mov r13,rsi test bl,2 jne near ptr M01_L14 jmp short M01_L04 M01_L09: xor r14d,r14d xor r15d,r15d mov [rbp+18],r10 mov [rbp+20],eax mov [rbp+8],r14 mov [rbp+10],r15d mov [rsp+20],edi mov [rsp+28],ebx mov rcx,rsi lea rdx,[rbp+18] lea r8,[rbp+8] mov r9d,1 call System.String.SplitWithPostProcessing(System.ReadOnlySpan`1, System.ReadOnlySpan`1, Int32, Int32, System.StringSplitOptions) mov r12,rax jmp near ptr M01_L01 M01_L10: cmp dword ptr [r13+8],0 jne near ptr M01_L05 M01_L11: mov rcx,7FFF5B7F4550 mov edx,28 call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS mov rax,23418002EF0 mov rax,[rax] mov rcx,501E46E3C13B cmp [rbp],rcx je short M01_L12 call CORINFO_HELP_FAIL_FAST M01_L12: nop lea rsp,[rbp+58] pop rbx pop rsi pop rdi pop r12 pop r13 pop r14 pop r15 pop rbp ret M01_L13: mov rcx,7FFF5B7F4550 mov edx,29 call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS mov rcx,23418002EF8 mov rcx,[rcx] mov rdx,[rbp+38] xor r8d,r8d cmp [rcx],ecx call qword ptr [7FFF5BAB4D40] xor ecx,ecx mov [rbp+38],rcx jmp near ptr M01_L02 M01_L14: test edi,edi jle near ptr M01_L04 cmp [rsi],esi mov rcx,rsi mov edx,3 call System.String.TrimWhiteSpaceHelper(System.Text.TrimType) mov r13,rax jmp near ptr M01_L04 M01_L15: and ebx,0FFFFFFFD jmp near ptr M01_L00 M01_L16: call System.ThrowHelper.ThrowArgumentOutOfRangeException() int 3 M01_L17: mov rcx,offset MT_System.ArgumentOutOfRangeException call CORINFO_HELP_NEWSFAST mov rsi,rax mov ecx,1C9 mov rdx,7FFF5B6E4020 call CORINFO_HELP_STRCNS mov rdi,rax mov ecx,0A21D mov rdx,7FFF5B6E4020 call CORINFO_HELP_STRCNS mov rcx,rax xor edx,edx call System.SR.GetResourceString(System.String, System.String) mov r8,rax mov rdx,rdi mov rcx,rsi call System.ArgumentOutOfRangeException..ctor(System.String, System.String) mov rcx,rsi call CORINFO_HELP_THROW M01_L18: mov ecx,42 mov edx,57 call System.ThrowHelper.ThrowArgumentException(System.ExceptionResource, System.ExceptionArgument) int 3 ; Total bytes of code 813 ``` ### Docs [Profiling workflow for dotnet/runtime repository](https://github.com/dotnet/performance/blob/master/docs/profiling-workflow-dotnet-runtime.md) [Benchmarking workflow for dotnet/runtime repository](https://github.com/dotnet/performance/blob/master/docs/benchmarking-workflow-dotnet-runtime.md)
kunalspathak commented 3 years ago

https://github.com/dotnet/runtime/pull/38001 is the change that is causing this. Here are the changes that went in between - https://github.com/dotnet/runtime/compare/10ed7401853185a1dbbe24e5a56240ae293e1486...740121d09706a7e91097ddb286baf5ff539a6d13. Assigning to @danmoseley to further triage and assign as appropriate.

danmoseley commented 3 years ago

@bbartels did you run the relevant perf benchmarks in this repo on your PR? I had thought you had, but perhaps you ran only your own created benchmarks?

I'll push a up a revert and we can figure this out then get the change in again. cc @tannergooding

tannergooding commented 3 years ago

I thought we had also validated with some benchmarks @GrabYourPitchforks shared: https://github.com/dotnet/runtime/pull/38001#issuecomment-645670458 and https://github.com/dotnet/runtime/pull/38001#discussion_r602532928

Will need to investigate to see what's causing the regression in for these scenarios in particular.

danmoseley commented 3 years ago

If those other benchmarks are useful, it might be good to get them added to dotnet/performance as well.

bbartels commented 3 years ago

@bbartels did you run the relevant perf benchmarks in this repo on your PR? I had thought you had, but perhaps you ran only your own created benchmarks?

I'll push a up a revert and we can figure this out then get the change in again. cc @tannergooding

I did yeah, should be in the thread. I remember having discussed this and we concluded that the performance trade-off was worth it. Note, that the regression benchmark is splitting on a separator that occurs every other character. There is some overhead when the frequency of separators is high, such as in the example above. However, with a separator every three or more characters it does not result in regressions anymore.

GrabYourPitchforks commented 3 years ago

I agree with @bbartels. Even though this microbenchmark shows a regression, I don't believe the microbenchmark is representative of real-world inputs. Back in the original thread I gave an example showing how the PR behaves when parsing CSV - which is a very typical use case for string.Split - and it showed measurable gains. My opinion is that we should keep the PR as-is unless we can trace some aspnet or other non-microbenchmark regression to this change.

kunalspathak commented 3 years ago

If that is the case, I would recommend updating/adding the realistic microbenchmark - @DrewScoggins

danmoseley commented 3 years ago

I did yeah, should be in the thread.

My bad, it got really long 😊

My opinion is that we should keep the PR as-is

This sounds good to me, if we can replace the microbenchmark instead. @tannergooding ?

tannergooding commented 3 years ago

That sounds reasonable to me. I think we want a new benchmark (and maybe to remove the existing one) rather than replacing the existing one so things can be tracked properly, but that is likely a question for @DrewScoggins and @adamsitnik.

benaadams commented 3 years ago

The method does do a lot of stack push/pop, including 4 vectors

push r15
push r14
push r13
push r12
push rdi
push rsi
push rbp
push rbx
sub rsp, 0x88
vzeroupper
vmovaps [rsp+0x70], xmm6
vmovaps [rsp+0x60], xmm7
vmovaps [rsp+0x50], xmm8
vmovaps [rsp+0x40], xmm9

...

vmovaps xmm6, [rsp+0x70]
vmovaps xmm7, [rsp+0x60]
vmovaps xmm8, [rsp+0x50]
vmovaps xmm9, [rsp+0x40]
add rsp, 0x88
pop rbx
pop rbp
pop rsi
pop rdi
pop r12
pop r13
pop r14
pop r15
ret 

Adding an extra overload for only one separator cuts that by 2 vectors

push r15
push r14
push r13
push r12
push rdi
push rsi
push rbp
push rbx
sub rsp, 0x68
vzeroupper
vmovaps [rsp+0x50], xmm6
vmovaps [rsp+0x40], xmm7

...

vmovaps xmm6, [rsp+0x50]
vmovaps xmm7, [rsp+0x40]
add rsp, 0x68
pop rbx
pop rbp
pop rsi
pop rdi
pop r12
pop r13
pop r14
pop r15
ret

As well as dropping 4 SIMD instructions

cmp = Sse2.Or(Sse2.CompareEqual(charVector, v2), cmp);
cmp = Sse2.Or(Sse2.CompareEqual(charVector, v3), cmp);
  vmovupd xmm0, [r15+rcx*2]
+ vpcmpeqw xmm0, xmm0, xmm7
- vpcmpeqw xmm1, xmm0, xmm7

- vpcmpeqw xmm2, xmm0, xmm8
- vpor xmm1, xmm2, xmm1
- vpcmpeqw xmm0, xmm0, xmm9
- vpor xmm1, xmm0, xmm1

- vptest xmm1, xmm1
+ vptest xmm0, xmm0

So that might be worth considering as well; even though its more code?

bbartels commented 3 years ago

@benaadams I could run some benchmarks tomorrow to see if it would result in significant enough perf gains to warrant the change!

DrewScoggins commented 3 years ago

Yeah, if we have what we think are more representative Split perf tests, adding those as new tests to the perf suite should be exactly what we do.

jeffhandley commented 3 weeks ago

@PranavSenthilnathan We want to replace the existing dotnet/performance benchmarks with the ones used in the PR that implemented the change per the comments above.

Once the new benchmarks are merged in and we get some baseline data from them, we can pursue the optimization suggested. The new benchmark should be able to run against .NET 8+ too, so we'll be able to see a difference between .NET 8/9 and .NET 10 if the change proves to have a measurable effect.