[WIP] Improve performance of Utf8Parser.TryParseInt32D by GrabYourPitchforks · Pull Request #32843 · dotnet/runtime (original) (raw)

I was experimenting a bit with @AndyAyersMS's change at #33004. Preliminary investigations show that his change has two positive effects: (a) it provides some good optimizations in its own right, and (b) it provides a solid foundation on which we can build additional improvements.

The numbers and codegen below are from three runs. The master run is the current master branch with no changes. The utf8parser_1 run is from Andy's PR only, with no changes to any of the Utf8Parser code paths. The utf8parser_2 run is from Andy's PR, plus changes to the Utf8Parser.TryParse(..., out int value, ...) method which contains the switch statement. Other methods like TryParseInt32D were left unchanged from their master implementation. Any changes we make to TryParseInt32D and related methods would just be goodness on top of this.

Method Toolchain Mean Error StdDev Ratio RatioSD
TryParseInt32 master 1,224.1 ns 24.13 ns 45.33 ns 1.00 0.00
TryParseInt32 utf8parser_1 1,022.3 ns 20.25 ns 17.95 ns 0.84 0.03
TryParseInt32 utf8parser_2 733.7 ns 13.82 ns 11.54 ns 0.60 0.02

; TryParse(..., out int value, ...) in current master branch

00007ffe4c6cb1e0 57 push rdi 00007ffe4c6cb1e1 56 push rsi 00007ffe4c6cb1e2 53 push rbx 00007ffe4c6cb1e3 4883ec30 sub rsp,30h 00007ffe4c6cb1e7 33c0 xor eax,eax 00007ffe4c6cb1e9 4889442420 mov qword ptr [rsp+20h],rax 00007ffe4c6cb1ee 488b31 mov rsi,qword ptr [rcx] 00007ffe4c6cb1f1 8b7908 mov edi,dword ptr [rcx+8] 00007ffe4c6cb1f4 410fb7d9 movzx ebx,r9w 00007ffe4c6cb1f8 83fb4e cmp ebx,4Eh 00007ffe4c6cb1fb 7758 ja System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db9355 (00007ffe4c6cb255) 00007ffe4c6cb1fd 83fb44 cmp ebx,44h 00007ffe4c6cb200 772b ja System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db932d (00007ffe4c6cb22d) 00007ffe4c6cb202 85db test ebx,ebx 00007ffe4c6cb204 7409 je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db930f (00007ffe4c6cb20f) 00007ffe4c6cb206 83fb44 cmp ebx,44h 00007ffe4c6cb209 0f8588000000 jne System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db9397 (00007ffe4c6cb297) 00007ffe4c6cb20f 488d4c2420 lea rcx,[rsp+20h] 00007ffe4c6cb214 488931 mov qword ptr [rcx],rsi 00007ffe4c6cb217 897908 mov dword ptr [rcx+8],edi 00007ffe4c6cb21a 488d4c2420 lea rcx,[rsp+20h] 00007ffe4c6cb21f e89ce3ffff call CLRStub[MethodDescPrestub]@7ffe4c6c95c0 (00007ffe4c6c95c0) 00007ffe4c6cb224 90 nop 00007ffe4c6cb225 4883c430 add rsp,30h 00007ffe4c6cb229 5b pop rbx 00007ffe4c6cb22a 5e pop rsi 00007ffe4c6cb22b 5f pop rdi 00007ffe4c6cb22c c3 ret 00007ffe4c6cb22d 83fb47 cmp ebx,47h 00007ffe4c6cb230 74dd je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db930f (00007ffe4c6cb20f) 00007ffe4c6cb232 83fb4e cmp ebx,4Eh 00007ffe4c6cb235 7560 jne System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db9397 (00007ffe4c6cb297) 00007ffe4c6cb237 488d4c2420 lea rcx,[rsp+20h] 00007ffe4c6cb23c 488931 mov qword ptr [rcx],rsi 00007ffe4c6cb23f 897908 mov dword ptr [rcx+8],edi 00007ffe4c6cb242 488d4c2420 lea rcx,[rsp+20h] 00007ffe4c6cb247 e894e3ffff call CLRStub[MethodDescPrestub]@7ffe4c6c95e0 (00007ffe4c6c95e0) 00007ffe4c6cb24c 90 nop 00007ffe4c6cb24d 4883c430 add rsp,30h 00007ffe4c6cb251 5b pop rbx 00007ffe4c6cb252 5e pop rsi 00007ffe4c6cb253 5f pop rdi 00007ffe4c6cb254 c3 ret 00007ffe4c6cb255 83fb64 cmp ebx,64h 00007ffe4c6cb258 770c ja System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db9366 (00007ffe4c6cb266) 00007ffe4c6cb25a 83fb58 cmp ebx,58h 00007ffe4c6cb25d 7416 je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db9375 (00007ffe4c6cb275) 00007ffe4c6cb25f 83fb64 cmp ebx,64h 00007ffe4c6cb262 7533 jne System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db9397 (00007ffe4c6cb297) 00007ffe4c6cb264 eba9 jmp System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db930f (00007ffe4c6cb20f) 00007ffe4c6cb266 83fb67 cmp ebx,67h 00007ffe4c6cb269 74a4 je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db930f (00007ffe4c6cb20f) 00007ffe4c6cb26b 83fb6e cmp ebx,6Eh 00007ffe4c6cb26e 74c7 je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db9337 (00007ffe4c6cb237) 00007ffe4c6cb270 83fb78 cmp ebx,78h 00007ffe4c6cb273 7522 jne System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4db9397 (00007ffe4c6cb297) 00007ffe4c6cb275 33c9 xor ecx,ecx 00007ffe4c6cb277 890a mov dword ptr [rdx],ecx 00007ffe4c6cb279 488d4c2420 lea rcx,[rsp+20h] 00007ffe4c6cb27e 488931 mov qword ptr [rcx],rsi 00007ffe4c6cb281 897908 mov dword ptr [rcx+8],edi 00007ffe4c6cb284 488d4c2420 lea rcx,[rsp+20h] 00007ffe4c6cb289 e8d2e3ffff call CLRStub[MethodDescPrestub]@7ffe4c6c9660 (00007ffe4c6c9660) 00007ffe4c6cb28e 90 nop 00007ffe4c6cb28f 4883c430 add rsp,30h 00007ffe4c6cb293 5b pop rbx 00007ffe4c6cb294 5e pop rsi 00007ffe4c6cb295 5f pop rdi 00007ffe4c6cb296 c3 ret 00007ffe4c6cb297 33c0 xor eax,eax 00007ffe4c6cb299 8902 mov dword ptr [rdx],eax 00007ffe4c6cb29b 418900 mov dword ptr [r8],eax 00007ffe4c6cb29e e88deed8ff call CLRStub[MethodDescPrestub]@7ffe4c45a130 (00007ffe4c45a130) 00007ffe`4c6cb2a3 cc int 3

; TryParse(..., out int value, ...) with Andy's pending PR

00007ffe4c69b320 56 push rsi 00007ffe4c69b321 4883ec20 sub rsp,20h 00007ffe4c69b325 410fb7f1 movzx esi,r9w 00007ffe4c69b329 83fe4e cmp esi,4Eh 00007ffe4c69b32c 772c ja System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d6948a (00007ffe4c69b35a) 00007ffe4c69b32e 83fe44 cmp esi,44h 00007ffe4c69b331 7713 ja System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d69476 (00007ffe4c69b346) 00007ffe4c69b333 85f6 test esi,esi 00007ffe4c69b335 7405 je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d6946c (00007ffe4c69b33c) 00007ffe4c69b337 83fe44 cmp esi,44h 00007ffe4c69b33a 754c jne System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d694b8 (00007ffe4c69b388) 00007ffe4c69b33c 4883c420 add rsp,20h 00007ffe4c69b340 5e pop rsi 00007ffe4c69b341 e9badaffff jmp CLRStub[MethodDescPrestub]@7ffe4c698e00 (00007ffe4c698e00) 00007ffe4c69b346 83fe47 cmp esi,47h 00007ffe4c69b349 74f1 je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d6946c (00007ffe4c69b33c) 00007ffe4c69b34b 83fe4e cmp esi,4Eh 00007ffe4c69b34e 7538 jne System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d694b8 (00007ffe4c69b388) 00007ffe4c69b350 4883c420 add rsp,20h 00007ffe4c69b354 5e pop rsi 00007ffe4c69b355 e9c6daffff jmp CLRStub[MethodDescPrestub]@7ffe4c698e20 (00007ffe4c698e20) 00007ffe4c69b35a 83fe64 cmp esi,64h 00007ffe4c69b35d 770c ja System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d6949b (00007ffe4c69b36b) 00007ffe4c69b35f 83fe58 cmp esi,58h 00007ffe4c69b362 7416 je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d694aa (00007ffe4c69b37a) 00007ffe4c69b364 83fe64 cmp esi,64h 00007ffe4c69b367 751f jne System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d694b8 (00007ffe4c69b388) 00007ffe4c69b369 ebd1 jmp System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d6946c (00007ffe4c69b33c) 00007ffe4c69b36b 83fe67 cmp esi,67h 00007ffe4c69b36e 74cc je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d6946c (00007ffe4c69b33c) 00007ffe4c69b370 83fe6e cmp esi,6Eh 00007ffe4c69b373 74db je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d69480 (00007ffe4c69b350) 00007ffe4c69b375 83fe78 cmp esi,78h 00007ffe4c69b378 750e jne System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4d694b8 (00007ffe4c69b388) 00007ffe4c69b37a 33c0 xor eax,eax 00007ffe4c69b37c 8902 mov dword ptr [rdx],eax 00007ffe4c69b37e 4883c420 add rsp,20h 00007ffe4c69b382 5e pop rsi 00007ffe4c69b383 e918dbffff jmp CLRStub[MethodDescPrestub]@7ffe4c698ea0 (00007ffe4c698ea0) 00007ffe4c69b388 33c0 xor eax,eax 00007ffe4c69b38a 8902 mov dword ptr [rdx],eax 00007ffe4c69b38c 418900 mov dword ptr [r8],eax 00007ffe4c69b38f e89cedd8ff call CLRStub[MethodDescPrestub]@7ffe4c42a130 (00007ffe4c42a130) 00007ffe`4c69b394 cc int 3

; TryParse(..., out int value, ...) with Andy's PR and some refactoring of the switch statement

00007ffe4c6db320 410fb7c1 movzx eax,r9w 00007ffe4c6db324 85c0 test eax,eax 00007ffe4c6db326 7505 jne System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4da93cd (00007ffe4c6db32d) 00007ffe4c6db328 e9d3daffff jmp CLRStub[MethodDescPrestub]@7ffe4c6d8e00 (00007ffe4c6d8e00) 00007ffe4c6db32d 410fb7c1 movzx eax,r9w 00007ffe4c6db331 83c820 or eax,20h 00007ffe4c6db334 83f867 cmp eax,67h 00007ffe4c6db337 7f0c jg System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4da93e5 (00007ffe4c6db345) 00007ffe4c6db339 83f864 cmp eax,64h 00007ffe4c6db33c 74ea je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4da93c8 (00007ffe4c6db328) 00007ffe4c6db33e 83f867 cmp eax,67h 00007ffe4c6db341 74e5 je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4da93c8 (00007ffe4c6db328) 00007ffe4c6db343 eb16 jmp System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4da93fb (00007ffe4c6db35b) 00007ffe4c6db345 83f86e cmp eax,6Eh 00007ffe4c6db348 7407 je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4da93f1 (00007ffe4c6db351) 00007ffe4c6db34a 83f878 cmp eax,78h 00007ffe4c6db34d 7407 je System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4da93f6 (00007ffe4c6db356) 00007ffe4c6db34f eb0a jmp System_Private_CoreLib!System.Buffers.Text.Utf8Parser.TryParse(System.ReadOnlySpan1<Byte>, Int32 ByRef, Int32 ByRef, Char)+0xffffffffa4da93fb (00007ffe4c6db35b) 00007ffe4c6db351 e9cadaffff jmp CLRStub[MethodDescPrestub]@7ffe4c6d8e20 (00007ffe4c6d8e20) 00007ffe4c6db356 e945dbffff jmp CLRStub[MethodDescPrestub]@7ffe4c6d8ea0 (00007ffe4c6d8ea0) 00007ffe4c6db35b e980f3ffff jmp CLRStub[MethodDescPrestub]@7ffe4c6da6e0 (00007ffe`4c6da6e0)