Skip to content
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

[resubmit] BigInteger parsing optimization for large decimal string #55121

Merged
merged 16 commits into from
Mar 23, 2022

Conversation

key-moon
Copy link
Contributor

@key-moon key-moon commented Jul 3, 2021

I accidentally deleted the forked repository, so I will resubmit the PR #51953 . Please refer to the previous discussion there. I apologize for the inconvenience.

Current BigNumer.NumberToBigInteger method is implemented using naive algorithm. It runs in Θ(N^2) time where N is number of digits. I implemented faster method known as divide-and-conquer algorithm. It runs Θ(N (log(N))^2). Since this algorithms running time has large constant factor, naive method is faster when N is small. So This method is only apply when N is large enough. (specifically, use divide-and-conquer method when N is more than 20000.)

I created branch from #47842 as it looks like #47842 will be merged shortly.

benchmark result

Previous method
BenchmarkDotNet=v0.12.1.1528-nightly, OS=Windows 10.0.19042.928 (20H2/October2020Update)
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
.NET SDK=6.0.100-preview.3.21202.5
  [Host]     : .NET 6.0.0 (6.0.21.20104), X64 RyuJIT
  Job-CHCQPG : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000  Arguments=/p:DebugType=portable  Toolchain=CoreRun  
IterationTime=250.0000 ms  MaxIterationCount=20  MinIterationCount=15  
WarmupCount=1  
Method numberString Mean Error StdDev Median Min Max Gen 0 Gen 1 Gen 2 Allocated
Parse 12345678901(...)01234567890 [20000] 2.611 ms 0.1786 ms 0.2057 ms 2.661 ms 2.208 ms 2.996 ms 26.7857 - - 56 KB
Parse 12345678901(...)01234567890 [40000] 9.028 ms 0.7436 ms 0.8265 ms 8.816 ms 8.072 ms 10.909 ms 31.2500 - - 96 KB
Parse 12345678901(...)01234567890 [60000] 18.521 ms 0.5179 ms 0.5756 ms 18.552 ms 17.349 ms 19.541 ms 71.4286 - - 151 KB
Parse 12345678901(...)01234567890 [80000] 32.904 ms 1.1486 ms 1.2290 ms 32.761 ms 30.984 ms 34.686 ms - - - 191 KB
Parse 12345678901(...)01234567890 [100000] 51.271 ms 1.7700 ms 2.0384 ms 51.186 ms 48.447 ms 54.856 ms - - - 246 KB
Parse 12345678901(...)01234567890 [120000] 74.285 ms 3.6392 ms 3.8939 ms 73.489 ms 68.604 ms 82.719 ms - - - 286 KB
Parse 12345678901(...)01234567890 [140000] 100.248 ms 5.2825 ms 5.8715 ms 98.712 ms 92.597 ms 113.046 ms - - - 341 KB
Parse 12345678901(...)01234567890 [160000] 127.443 ms 4.8226 ms 5.5537 ms 125.749 ms 120.504 ms 138.583 ms - - - 381 KB
Parse 12345678901(...)01234567890 [180000] 162.028 ms 4.9852 ms 5.7409 ms 162.142 ms 151.841 ms 171.640 ms - - - 436 KB
Parse 12345678901(...)01234567890 [200000] 224.511 ms 16.7864 ms 19.3313 ms 224.392 ms 192.558 ms 255.098 ms - - - 476 KB
Parse 12345678901(...)01234567890 [220000] 240.451 ms 10.9087 ms 12.1250 ms 234.971 ms 226.956 ms 265.072 ms - - - 531 KB
Parse 12345678901(...)01234567890 [240000] 300.378 ms 25.1560 ms 27.9608 ms 296.348 ms 267.565 ms 357.131 ms - - - 572 KB
Parse 12345678901(...)01234567890 [260000] 346.397 ms 26.8156 ms 29.8054 ms 335.024 ms 320.430 ms 412.120 ms - - - 626 KB
Parse 12345678901(...)01234567890 [280000] 384.442 ms 12.8365 ms 14.2678 ms 381.489 ms 367.624 ms 420.767 ms - - - 666 KB
Parse 12345678901(...)01234567890 [300000] 433.914 ms 9.1847 ms 10.5772 ms 433.046 ms 414.254 ms 452.394 ms - - - 721 KB
Implemented method
BenchmarkDotNet=v0.12.1.1528-nightly, OS=Windows 10.0.19042.928 (20H2/October2020Update)
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
.NET SDK=6.0.100-preview.3.21202.5
  [Host]     : .NET 6.0.0 (6.0.21.20104), X64 RyuJIT
  Job-YASIZJ : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000  Arguments=/p:DebugType=portable  Toolchain=CoreRun  
IterationTime=250.0000 ms  MaxIterationCount=20  MinIterationCount=15  
WarmupCount=1  
Method numberString Mean Error StdDev Median Min Max Gen 0 Gen 1 Gen 2 Allocated
Parse 12345678901(...)01234567890 [20000] 2.017 ms 0.0559 ms 0.0643 ms 2.024 ms 1.921 ms 2.127 ms 140.6250 - - 288 KB
Parse 12345678901(...)01234567890 [40000] 6.237 ms 0.1116 ms 0.0932 ms 6.218 ms 6.127 ms 6.434 ms 437.5000 83.3333 - 994 KB
Parse 12345678901(...)01234567890 [60000] 15.522 ms 1.3853 ms 1.5953 ms 15.153 ms 13.686 ms 18.949 ms 1062.5000 218.7500 - 2,831 KB
Parse 12345678901(...)01234567890 [80000] 20.554 ms 0.4685 ms 0.5208 ms 20.429 ms 19.880 ms 21.552 ms 1181.8182 181.8182 - 3,572 KB
Parse 12345678901(...)01234567890 [100000] 39.146 ms 1.8050 ms 1.8536 ms 38.681 ms 36.992 ms 44.189 ms 3000.0000 333.3333 - 7,680 KB
Parse 12345678901(...)01234567890 [120000] 47.999 ms 1.5866 ms 1.8271 ms 47.429 ms 46.147 ms 51.705 ms 3750.0000 250.0000 - 10,447 KB
Parse 12345678901(...)01234567890 [140000] 41.915 ms 1.3341 ms 1.3700 ms 41.657 ms 40.299 ms 44.621 ms 2166.6667 500.0000 - 6,532 KB
Parse 12345678901(...)01234567890 [160000] 67.668 ms 1.4404 ms 1.6010 ms 67.296 ms 65.587 ms 70.763 ms 4750.0000 250.0000 - 12,897 KB
Parse 12345678901(...)01234567890 [180000] 103.943 ms 2.4616 ms 2.8347 ms 103.285 ms 100.249 ms 109.843 ms 6500.0000 500.0000 - 18,962 KB
Parse 12345678901(...)01234567890 [200000] 136.343 ms 3.9093 ms 4.0146 ms 135.607 ms 131.575 ms 148.198 ms 9500.0000 500.0000 - 28,922 KB
Parse 12345678901(...)01234567890 [220000] 154.695 ms 3.6123 ms 3.7096 ms 154.182 ms 149.801 ms 163.375 ms 17500.0000 500.0000 - 40,999 KB
Parse 12345678901(...)01234567890 [240000] 184.792 ms 20.8938 ms 24.0613 ms 173.449 ms 163.513 ms 234.269 ms 16000.0000 1000.0000 - 39,244 KB
Parse 12345678901(...)01234567890 [260000] 160.434 ms 3.0439 ms 3.5053 ms 160.026 ms 155.602 ms 167.424 ms 12500.0000 500.0000 - 33,322 KB
Parse 12345678901(...)01234567890 [280000] 134.838 ms 2.4207 ms 2.2644 ms 134.531 ms 132.314 ms 139.587 ms 9500.0000 500.0000 - 22,696 KB
Parse 12345678901(...)01234567890 [300000] 140.690 ms 2.4686 ms 2.4245 ms 141.285 ms 134.758 ms 144.021 ms 7500.0000 1500.0000 1000.0000 24,318 KB

@ghost
Copy link

ghost commented Jul 3, 2021

Tagging subscribers to this area: @dotnet/area-system-numerics
See info in area-owners.md if you want to be subscribed.

Issue Details

I accidentally deleted the forked repository, so I will resubmit the PR #51953 . Please refer to the previous discussion there. I apologize for the inconvenience.

Current BigNumer.NumberToBigInteger method is implemented using naive algorithm. It runs in Θ(N^2) time where N is number of digits. I implemented faster method known as divide-and-conquer algorithm. It runs Θ(N (log(N))^2). Since this algorithms running time has large constant factor, naive method is faster when N is small. So This method is only apply when N is large enough. (specifically, use divide-and-conquer method when N is more than 20000.)

I created branch from #47842 as it looks like #47842 will be merged shortly.

benchmark result

Previous method
BenchmarkDotNet=v0.12.1.1528-nightly, OS=Windows 10.0.19042.928 (20H2/October2020Update)
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
.NET SDK=6.0.100-preview.3.21202.5
  [Host]     : .NET 6.0.0 (6.0.21.20104), X64 RyuJIT
  Job-CHCQPG : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000  Arguments=/p:DebugType=portable  Toolchain=CoreRun  
IterationTime=250.0000 ms  MaxIterationCount=20  MinIterationCount=15  
WarmupCount=1  
Method numberString Mean Error StdDev Median Min Max Gen 0 Gen 1 Gen 2 Allocated
Parse 12345678901(...)01234567890 [20000] 2.611 ms 0.1786 ms 0.2057 ms 2.661 ms 2.208 ms 2.996 ms 26.7857 - - 56 KB
Parse 12345678901(...)01234567890 [40000] 9.028 ms 0.7436 ms 0.8265 ms 8.816 ms 8.072 ms 10.909 ms 31.2500 - - 96 KB
Parse 12345678901(...)01234567890 [60000] 18.521 ms 0.5179 ms 0.5756 ms 18.552 ms 17.349 ms 19.541 ms 71.4286 - - 151 KB
Parse 12345678901(...)01234567890 [80000] 32.904 ms 1.1486 ms 1.2290 ms 32.761 ms 30.984 ms 34.686 ms - - - 191 KB
Parse 12345678901(...)01234567890 [100000] 51.271 ms 1.7700 ms 2.0384 ms 51.186 ms 48.447 ms 54.856 ms - - - 246 KB
Parse 12345678901(...)01234567890 [120000] 74.285 ms 3.6392 ms 3.8939 ms 73.489 ms 68.604 ms 82.719 ms - - - 286 KB
Parse 12345678901(...)01234567890 [140000] 100.248 ms 5.2825 ms 5.8715 ms 98.712 ms 92.597 ms 113.046 ms - - - 341 KB
Parse 12345678901(...)01234567890 [160000] 127.443 ms 4.8226 ms 5.5537 ms 125.749 ms 120.504 ms 138.583 ms - - - 381 KB
Parse 12345678901(...)01234567890 [180000] 162.028 ms 4.9852 ms 5.7409 ms 162.142 ms 151.841 ms 171.640 ms - - - 436 KB
Parse 12345678901(...)01234567890 [200000] 224.511 ms 16.7864 ms 19.3313 ms 224.392 ms 192.558 ms 255.098 ms - - - 476 KB
Parse 12345678901(...)01234567890 [220000] 240.451 ms 10.9087 ms 12.1250 ms 234.971 ms 226.956 ms 265.072 ms - - - 531 KB
Parse 12345678901(...)01234567890 [240000] 300.378 ms 25.1560 ms 27.9608 ms 296.348 ms 267.565 ms 357.131 ms - - - 572 KB
Parse 12345678901(...)01234567890 [260000] 346.397 ms 26.8156 ms 29.8054 ms 335.024 ms 320.430 ms 412.120 ms - - - 626 KB
Parse 12345678901(...)01234567890 [280000] 384.442 ms 12.8365 ms 14.2678 ms 381.489 ms 367.624 ms 420.767 ms - - - 666 KB
Parse 12345678901(...)01234567890 [300000] 433.914 ms 9.1847 ms 10.5772 ms 433.046 ms 414.254 ms 452.394 ms - - - 721 KB
Implemented method
BenchmarkDotNet=v0.12.1.1528-nightly, OS=Windows 10.0.19042.928 (20H2/October2020Update)
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
.NET SDK=6.0.100-preview.3.21202.5
  [Host]     : .NET 6.0.0 (6.0.21.20104), X64 RyuJIT
  Job-YASIZJ : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000  Arguments=/p:DebugType=portable  Toolchain=CoreRun  
IterationTime=250.0000 ms  MaxIterationCount=20  MinIterationCount=15  
WarmupCount=1  
Method numberString Mean Error StdDev Median Min Max Gen 0 Gen 1 Gen 2 Allocated
Parse 12345678901(...)01234567890 [20000] 2.017 ms 0.0559 ms 0.0643 ms 2.024 ms 1.921 ms 2.127 ms 140.6250 - - 288 KB
Parse 12345678901(...)01234567890 [40000] 6.237 ms 0.1116 ms 0.0932 ms 6.218 ms 6.127 ms 6.434 ms 437.5000 83.3333 - 994 KB
Parse 12345678901(...)01234567890 [60000] 15.522 ms 1.3853 ms 1.5953 ms 15.153 ms 13.686 ms 18.949 ms 1062.5000 218.7500 - 2,831 KB
Parse 12345678901(...)01234567890 [80000] 20.554 ms 0.4685 ms 0.5208 ms 20.429 ms 19.880 ms 21.552 ms 1181.8182 181.8182 - 3,572 KB
Parse 12345678901(...)01234567890 [100000] 39.146 ms 1.8050 ms 1.8536 ms 38.681 ms 36.992 ms 44.189 ms 3000.0000 333.3333 - 7,680 KB
Parse 12345678901(...)01234567890 [120000] 47.999 ms 1.5866 ms 1.8271 ms 47.429 ms 46.147 ms 51.705 ms 3750.0000 250.0000 - 10,447 KB
Parse 12345678901(...)01234567890 [140000] 41.915 ms 1.3341 ms 1.3700 ms 41.657 ms 40.299 ms 44.621 ms 2166.6667 500.0000 - 6,532 KB
Parse 12345678901(...)01234567890 [160000] 67.668 ms 1.4404 ms 1.6010 ms 67.296 ms 65.587 ms 70.763 ms 4750.0000 250.0000 - 12,897 KB
Parse 12345678901(...)01234567890 [180000] 103.943 ms 2.4616 ms 2.8347 ms 103.285 ms 100.249 ms 109.843 ms 6500.0000 500.0000 - 18,962 KB
Parse 12345678901(...)01234567890 [200000] 136.343 ms 3.9093 ms 4.0146 ms 135.607 ms 131.575 ms 148.198 ms 9500.0000 500.0000 - 28,922 KB
Parse 12345678901(...)01234567890 [220000] 154.695 ms 3.6123 ms 3.7096 ms 154.182 ms 149.801 ms 163.375 ms 17500.0000 500.0000 - 40,999 KB
Parse 12345678901(...)01234567890 [240000] 184.792 ms 20.8938 ms 24.0613 ms 173.449 ms 163.513 ms 234.269 ms 16000.0000 1000.0000 - 39,244 KB
Parse 12345678901(...)01234567890 [260000] 160.434 ms 3.0439 ms 3.5053 ms 160.026 ms 155.602 ms 167.424 ms 12500.0000 500.0000 - 33,322 KB
Parse 12345678901(...)01234567890 [280000] 134.838 ms 2.4207 ms 2.2644 ms 134.531 ms 132.314 ms 139.587 ms 9500.0000 500.0000 - 22,696 KB
Parse 12345678901(...)01234567890 [300000] 140.690 ms 2.4686 ms 2.4245 ms 141.285 ms 134.758 ms 144.021 ms 7500.0000 1500.0000 1000.0000 24,318 KB
Author: key-moon
Assignees: -
Labels:

area-System.Numerics

Milestone: -

@terrajobst terrajobst added the community-contribution Indicates that the PR has been added by a community member label Jul 19, 2021
@jeffhandley
Copy link
Member

@tannergooding This PR is assigned to you for follow-up/decision before the RC1 snap.

@tannergooding
Copy link
Member

Thanks for the contribution here @key-moon. Due to it being so late in the cycle, this is going to miss out on the .NET 6 release and we'll instead be able to merge it after the RC1 snap and we begin accepting changes for .NET 7 (ETA: 3-4 weeks)

@tannergooding tannergooding added this to the 7.0.0 milestone Aug 2, 2021
@jeffhandley
Copy link
Member

@key-moon I wanted to let you know we're still working on some .NET 6.0 RC2 items, so we're a bit delayed on reviewing this. It'll likely be a couple more weeks. Thanks for your contributions and patience!

try
{
foreach (ReadOnlyMemory<char> digitsChunk in number.digits.GetChunks())
if (number.digits.Length <= s_naiveThreshold)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given how big each path is, I would if it would be better to break them into 2 helper methods. Basically leaving:

if (number.digits.Length <= s_naiveThreshold)
{
    AlgorithmA(...);
}
else
{
    AlgorithmB(...);
}

-- The method is getting pretty big, which means the JIT might give up on optimizing it otherwise (haven't confirmed if it actually does).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for late replying. I think this is worth doing in terms of improving readability. I will implement it as soon as possible.

Copy link
Contributor Author

@key-moon key-moon Oct 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have implemented and benchmarked. As a result, there is no significant difference in speed and memory. However, readability has definitely been improved.

Benchmark result
  • Job-VEBSQX: before split to methods (a9942c5)
  • Job-HLAVXS: after split to methods (460664f)
BenchmarkDotNet=v0.13.1.1611-nightly, OS=Windows 10.0.22000
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=6.0.100-rc.1.21463.6
  [Host]     : .NET 5.0.9 (5.0.921.35908), X64 RyuJIT
  Job-VEBSQX : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT
  Job-HLAVXS : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000  Arguments=/p:DebugType=portable,-bl:benchmarkdotnet.binlog  IterationTime=250.0000 ms  
MaxIterationCount=20  MinIterationCount=15  WarmupCount=1  
Method Job Toolchain numberString Mean Error StdDev Median Min Max Ratio RatioSD Gen 0 Gen 1 Gen 2 Allocated
Parse Job-VEBSQX \artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [50000] 10.50 ms 0.350 ms 0.389 ms 10.56 ms 9.902 ms 11.42 ms 1.00 0.00 312.5000 93.7500 - 2 MB
Parse Job-HLAVXS \artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [50000] 10.29 ms 0.384 ms 0.427 ms 10.34 ms 9.563 ms 11.13 ms 0.98 0.03 312.5000 93.7500 - 2 MB
Parse Job-VEBSQX \artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [100000] 36.77 ms 1.531 ms 1.702 ms 36.58 ms 33.684 ms 40.74 ms 1.00 0.00 1125.0000 250.0000 - 7 MB
Parse Job-HLAVXS \artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [100000] 36.64 ms 1.445 ms 1.606 ms 36.23 ms 33.401 ms 39.95 ms 1.00 0.07 1166.6667 166.6667 - 7 MB
Parse Job-VEBSQX \artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [150000] 41.08 ms 1.350 ms 1.555 ms 40.75 ms 38.486 ms 44.25 ms 1.00 0.00 1000.0000 500.0000 - 7 MB
Parse Job-HLAVXS \artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [150000] 40.97 ms 0.742 ms 0.762 ms 41.26 ms 39.155 ms 42.20 ms 1.01 0.04 1000.0000 500.0000 - 7 MB
Parse Job-VEBSQX \artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [200000] 129.14 ms 3.434 ms 3.527 ms 129.89 ms 120.135 ms 133.89 ms 1.00 0.00 4500.0000 500.0000 - 28 MB
Parse Job-HLAVXS \artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [200000] 130.05 ms 2.571 ms 2.279 ms 130.45 ms 125.832 ms 134.43 ms 1.01 0.04 4500.0000 500.0000 - 28 MB
Parse Job-VEBSQX \artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [250000] 160.84 ms 8.920 ms 9.544 ms 158.21 ms 146.879 ms 179.63 ms 1.00 0.00 5500.0000 500.0000 - 34 MB
Parse Job-HLAVXS \artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [250000] 162.85 ms 7.046 ms 8.114 ms 161.09 ms 145.608 ms 178.37 ms 1.01 0.08 5500.0000 500.0000 - 34 MB
Parse Job-VEBSQX \artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [300000] 132.28 ms 3.731 ms 3.992 ms 131.79 ms 122.929 ms 137.93 ms 1.00 0.00 3500.0000 1500.0000 1000.0000 24 MB
Parse Job-HLAVXS \artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [300000] 134.72 ms 5.300 ms 6.103 ms 133.63 ms 123.651 ms 147.27 ms 1.03 0.06 3500.0000 1500.0000 1000.0000 24 MB
Parse Job-VEBSQX \artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [350000] 356.66 ms 20.078 ms 21.484 ms 351.60 ms 321.365 ms 406.99 ms 1.00 0.00 14000.0000 12000.0000 11000.0000 71 MB
Parse Job-HLAVXS \artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [350000] 354.54 ms 17.497 ms 19.448 ms 348.05 ms 323.012 ms 396.16 ms 0.99 0.07 15000.0000 13000.0000 12000.0000 71 MB
Parse Job-VEBSQX \artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [400000] 524.19 ms 47.271 ms 54.437 ms 510.63 ms 461.465 ms 640.54 ms 1.00 0.00 17000.0000 3000.0000 2000.0000 107 MB
Parse Job-HLAVXS \artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [400000] 553.00 ms 91.333 ms 105.179 ms 487.60 ms 444.111 ms 710.82 ms 1.06 0.21 17000.0000 3000.0000 2000.0000 107 MB
Parse Job-VEBSQX \artifacts-a9942c\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [450000] 627.40 ms 91.780 ms 105.695 ms 570.04 ms 526.129 ms 800.22 ms 1.00 0.00 24000.0000 1000.0000 - 149 MB
Parse Job-HLAVXS \artifacts-460664\bin\testhost\net6.0-windows-Release-x64\shared\Microsoft.NETCore.App\6.0.0\corerun.exe 12345678901(...)01234567890 [450000] 554.17 ms 49.428 ms 56.921 ms 542.68 ms 472.918 ms 657.23 ms 0.90 0.14 24000.0000 1000.0000 - 149 MB

@tannergooding
Copy link
Member

The overall logic LGTM.

I left a couple nits/comments about adding comments and possibly minor refactorings to help with readability when this inevitably is looked at again in the future. I likewise called out a peculiar scenario around handling fractional digits which I don't believe is possible (happy to be proven wrong here).

It would be great if this could get a second pair of eyes on it (CC. @pgovind, @stephentoub, @bartonjs since you've reviewed or worked on BigInteger semi-recently).

multiplier[0] = TenPowMaxPartial;

// This loop is executed ceil(log_2(bufferSize)) times.
while (true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this loop is executed ceil(log_2(bufferSize)), why do you not use a for loop? I think these are better optimized by the JIT.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please benchmark before/after to make sure that this is really the case.

}
}

private static volatile TypeInfo s_lazyInternalNumber;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment, which explains why this is volatile.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commits explains the reason. Actually, I didn't understand why volatile is required.
dotnet/corefx@8918578

@tannergooding
Copy link
Member

@key-moon are you still working on this?

No particular rush, just wanted to ensure that was the case since many people took a break over the holidays. There are still several pending comments above that would need to be resolved.

@tannergooding tannergooding added the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 7, 2022
@key-moon
Copy link
Contributor Author

key-moon commented Jan 8, 2022

Yes, I’m still working on this PR. Sorry for the late response. I'll resolve these conversations as soon as possible.

@ghost ghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 8, 2022
@tannergooding tannergooding added the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 24, 2022
@ghost ghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 26, 2022
@tannergooding
Copy link
Member

This has a merge conflict that needs to be resolved. I also resolved a few comments around styling concerns where the code in question isn't new, rather just being moved around.

While I do think that resolving those styling inconsistencies would be nice, since its not new code I think it can happen in an independent PR.

@tannergooding
Copy link
Member

Closing and reopening to try and get helix to pick up the changes and allow CI to actually run.

@tannergooding
Copy link
Member

This PR looks generally good, I'd just like to get CI passing before merging.

Merging with main again may allow it to pass.

@deeprobin
Copy link
Contributor

Build failures are unrelated

@tannergooding tannergooding merged commit 8ed8517 into dotnet:main Mar 23, 2022
@danmoseley
Copy link
Member

Thanks @key-moon for your work on this perf improvement!

radekdoulik pushed a commit to radekdoulik/runtime that referenced this pull request Mar 30, 2022
…otnet#55121)

* implement divide-and-conquer method for parsing digits

* fix argument order in Assert when x equals to 0

* Apply format fix

Co-authored-by: Stephen Toub <stoub@microsoft.com>

* add test for non-naive algorithm

* add description for naiveThreshold

* fix trivial part

* add check for boundary condition

* add assertions and descriptions

* change variable name

* remove inappropreate use of var

* to use ArrayPool<int>.Shared.Rent for newBuffer allocation

* move both algorithms to separate methods

* add and fix comments

* trivial fix

Co-authored-by: Stephen Toub <stoub@microsoft.com>
@ghost ghost locked as resolved and limited conversation to collaborators Apr 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Numerics community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants