-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Perf: double.ToString() 3x slower in some cases on Linux #7783
Comments
@tarekgh just to clarify: Are we tracking improvements on Linux (title says that) or on Windows (first paragraph says that). Or both? |
we are tracking to fix the perf on Linux as the title mention. thanks for the catch, I had typo in the first paragraph and I have fixed it. |
Given an |
It is not assigned to anyone, so no one is working on it (see Triage rules). Assigning to you ... |
@mazong1123 thanks for looking at this. could you please share your thoughts before applying any changes? |
@tarekgh I'm still reading the context and previous works you guys have done. Once the preparation finished, I'll list the overview of the issue from my perspective and then put my proposals here for discussion. This should be done by 7/4 CST. |
@tarekgh I've read the context of the Overview
Plan
|
@mazong1123 thanks for looking at that.
2 things we need to confirm here if we are going to use this paper:
thanks again for looking at this. |
Just to be clarified:
|
Any data that increase the size of the net core on the disk will be a concern. If the data is really small (e.g. small arrays or static data). But if the data is few KB's then we need to look at that and evaluate the benefits. We had some work to optimize the size of the net core on the disk. CC @jkotas |
I would worry about speed and correctness first. Once you have prototype that is fast and correct, we will worry about the rest (disk footprint, license, etc.) |
@jkotas I'll write a demo first so that we can examine the correctness and speed. If it does not work as expected, we can have a quick turnaround. BTW, do you have any idea other than trying the paper? |
@jkotas @tarekgh I've prototype the paper roughly. Before I go further, I'd like to share the information I've learnt so far. With the algorithm,
So I believe generally, the algorithm is more accurate than current implementation, but I need to adopt the double.ToString("R") implementation to my prototype and run the test cases again. @tarekgh BTW, in https://github.com/dotnet/coreclr/issues/10390#issuecomment-291011320 , when testing double.MinValue against |
Yes this is expected to have ToString("R") is more accurate than ToString(). this is why we have "R" guarantee the round tripping but not ToString().
We need to validate parsing back the value produced from "R" is getting exact same number we originally started with before converting to string.
I was referring to "R". we understand ToString() without "R" doesn't produce accurate numbers. it more rounded. |
I fixed several bugs of my prototype. Now the accuracy is great. The prototype code can be found at https://github.com/mazong1123/doubletonumber I'll start to refactor & optimize the code and test the performance on Linux. |
@tarekgh I just have one question regarding
Is there any particular reason preventing us to convert the double to string in precision of 17 directly? I'm asking because:
using System;
namespace lab
{
class Program
{
static void Main(string[] args)
{
double d1 = 0.84551240822557006;
string s = d1.ToString("R");
double d2 = double.Parse(s);
Console.WriteLine(d1 == d2);
}
}
} In current .NET Core (2.0.0-preview2-005905), the output is
|
@mazong1123 I don't know the history why decided to format with "R" as 15 digit precision and not 17 directly. my guess is was the old implementation with 15 digit precision was faster than 17 digits and almost all common cases can fit in 15 digit precision. The doc https://msdn.microsoft.com/en-us/library/kfsatb94(v=vs.110).aspx is stating this design but doesn't tell the rationale behind it. also the doc sample is exactly the same case mentioned in your code sample.
I think we can go with the breaking change to always format as 17 digits precision if it is really faster in the common cases. @jkotas what you think about that? and do you know why we had this design in the first place? |
I think we can give it a try. These kind of changes tend to come with compat surprises...
I do not know. |
I investigated the 'R' case and validated that the math for converting from string to double is correct. I also left a comment (see https://github.com/dotnet/coreclr/issues/13106#issuecomment-318844961) indicating that we are not meeting the IEEE round tripping requirements which states that double->string->double is only required to match when done with at least 17 digits. |
@tannergooding we have another issue tracking the parsing part https://github.com/dotnet/coreclr/issues/1316 as it looks we have other issues than just using 17 significant digits. Roslyn already introduced a new parsing implementation which conforms to IEEE which we can consider porting it to net core. |
* Re-implemented the ecvt function. Instead of leveraging snprintf, re-implement the ecvt function according to the paper: https://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf Note: 1. This commit won't fix any existing bug. 2. This is a raw implementation of the paper. The performance on Linux only gain 10%. We could tune the performance further. Fix #10651 * Resolve a cross platform header file issue. Fix #10651 * Fixed a minor bug. Improved the performance. Fix #10651 * Modified code according to code review feedback. This commit fixed most of the issue found in code review. However, some of the feedback may not be involved due to either little performance improvement or need a POC. Fix #10651 * Try to fix constexpr compile error on Windows. Fix #10651 * Fixed a potential overflow bug in BigNum::Compare. Fix #10651 * Improved multiply 10 operation. Use shift and add operation to replace actual multiply operation. Fix #10651 * Remove old _ecvt function. Fix #10651 * Documented the reason why we do not need m+ and m-. Fix #10651 * Changed exp > 0 to exp != 0 to remove any confusion. exp should fall in 1 ~ 2046 for normalized value. Denormalized value has exp = 0. Fix #10651 * Disable the _ecvt tests. Fix #10651 * Removed _ecvt tests. Fix #10651 * Re-implemented LogBase2. Fix #10651 * Use DWORD and DWORD64 for _BitScanReverse and _BitScanReverse64 Fix #10651 * Fixed x86 compile issue for _BitScanReverse64 x86 does not support _BitScanReverse64 so we have to add additional shift operations to handle it. Fix #10651 * Implemented BitScanReverse64 and BitScanReverse in pal.h Fix #10651 * Remove the confusion comment which is unrelated to BitScanReverse. Fix #10651 * Introduced wmemset to enhance the perf for 0.0 Fix #10651 * Improved the performance of converting 0.0. Fix #10651 * Renamed ecvt to DoubleToNumberWorker. Fix #10651 * Updated code according to the code review feedback. Fix #10651
We have enhanced the performance of Double.ToString when running on Linux. we used to be 7x slower on Linux than on Windows but now we are around 3x slower in some cases.this issue is tracking looking at Double.ToString performance to optimize more when running on Linux.
Note that, the current Double.ToString performance is slightly better than Windows in some cases (like when using Double.MaxValue /2) for instance.
#7700 is the original issue which has more details about what we have done so far and what more can be done.
The text was updated successfully, but these errors were encountered: