-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Use cached strings for ToString on integer values 0 to 9 #18383
Conversation
When doing ToString on single-digit integers, just return a cached string. This helps avoid string allocation/formatting costs for this very common case, while only costing one comparison for other cases.
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.
Nice
The value 10 is also a commonly used, if you wan to add one more to the cache. |
@@ -1095,6 +1097,13 @@ private static unsafe void UInt32ToNumber(uint value, ref NumberBuffer number) | |||
private static unsafe string UInt32ToDecStr(uint value, int digits) | |||
{ | |||
int bufferLength = Math.Max(digits, FormattingHelpers.CountDigits(value)); |
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.
Why do we have to call CountDigits, when we have a small 'value' 0-10 ?
Can't we first test the value and see it is range. [0-10]
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.
CountDigits is generally quite fast already and in the 0-10 case, it would be just 2 comparison instead of one (without adding the overhead of the 0-10 check for all other values):
coreclr/src/System.Private.CoreLib/shared/System/Buffers/Text/FormattingHelpers.CountDigits.cs
Line 69 in d2e2299
public static int CountDigits(uint value) |
We could experiment with that. It would entail not only adding one more string but also changing the |
// For single-digit values that are very common, especially 0 and 1, just return cached strings. | ||
if (bufferLength == 1) | ||
{ | ||
return s_singleDigitStringCache[value]; |
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.
if (value <= 10)
{
return s_smallNumberStringCache[value];
}
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.
That also needs to factor in digits. This can be called with something like digits == 5 and value == 2, and it needs to return "00002".
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.
In that case, should we be validating that digits is -1/etc., or is it safe to always return single digits as "digit" if bufferLength is 1?
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.
In that case, should we be validating that digits is -1/etc., or is it safe to always return single digits as "digit" if bufferLength is 1?
No matter what the digits
value is, there will always be at least one digit rendered.
@@ -1339,6 +1348,13 @@ private static unsafe string UInt64ToDecStr(ulong value, int digits) | |||
digits = 1; | |||
|
|||
int bufferLength = Math.Max(digits, FormattingHelpers.CountDigits(value)); | |||
|
|||
// For single-digit values that are very common, especially 0 and 1, just return cached strings. | |||
if (bufferLength == 1) |
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.
Skip range check for this one (moving bufferLength
after loop) and use
string[] ditgitCache = s_singleDigitStringCache;
if ((uint)value < (uint)ditgitCache.Length)
{
return ditgitCache[value];
}
Would also allow you to have any number in cache? (within reason)
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.
Would also allow you to have any number in cache? (within reason)
As noted earlier, it would also need to check digits
. That's why I did the comparison against bufferLength
.
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.
Ahh... leading zeros...
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.
Then we can use this:
if ((value <= s_smallNumberStringCache.Length) &&
(digits <= FormattingHelpers.CountDigits(value)))
{
return s_smallNumberStringCache[value];
}
Note value is already unsigned (a least in this variant of the method)
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.
Right, and I've been simply noting it would need to be measured.
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.
Awesome!
I'm looking into the commonality of other values, and will follow-up if it looks fruitful. For now, my goal was really just focused on 0 and 1, and 2-9 came along for the ride (cheaper to support them than to not support them). |
When doing ToString on single-digit integers, just return a cached string. This helps avoid string allocation/formatting costs for this very common case, while only costing one comparison for other cases. Signed-off-by: dotnet-bot-corefx-mirror <[email protected]>
When doing ToString on single-digit integers, just return a cached string. This helps avoid string allocation/formatting costs for this very common case, while only costing one comparison for other cases. Signed-off-by: dotnet-bot-corefx-mirror <[email protected]>
When doing ToString on single-digit integers, just return a cached string. This helps avoid string allocation/formatting costs for this very common case, while only costing one comparison for other cases. Signed-off-by: dotnet-bot <[email protected]>
When doing ToString on single-digit integers, just return a cached string. This helps avoid string allocation/formatting costs for this very common case, while only costing one comparison for other cases. Signed-off-by: dotnet-bot <[email protected]>
When doing ToString on single-digit integers, just return a cached string. This helps avoid string allocation/formatting costs for this very common case, while only costing one comparison for other cases. Commit migrated from dotnet/coreclr@12f8a27
When doing ToString on single-digit integers, just return a cached string. This helps avoid string allocation/formatting costs for this very common case, while only costing one comparison for other cases.
Microbenchmark:
Before:
After:
cc: @jkotas, @mjsabby, @ahsonkhan