Skip to content

Conversation

@xwu
Copy link
Collaborator

@xwu xwu commented Oct 28, 2025

Inspired by #84826, I've dusted off and completely reworked a native implementation of integer-to-string conversion.

Besides existing tests in this repository, the core of the implementation has been comprehensively tested in a separate package for all bases between 2–36 to demonstrate identical output for all 8-bit and 16-bit values, and for randomly generated 32-bit, 64-bit, and 128-bit values.

Resolves #51902.

@xwu xwu requested a review from a team as a code owner October 28, 2025 17:50
@xwu
Copy link
Collaborator Author

xwu commented Oct 28, 2025

@swift-ci test

@xwu

This comment was marked as outdated.

@xwu
Copy link
Collaborator Author

xwu commented Oct 28, 2025

@swift-ci benchmark

@xwu xwu changed the title [stdlib][SR-9438] Re-implement integer-to-string conversion in native Swift (redux) [stdlib][SR-9438] Re-implement integer-to-string conversion (redux) Oct 28, 2025
xwu added a commit that referenced this pull request Nov 3, 2025
A companion to #85180.

<!--
If this pull request is targeting a release branch, please fill out the
following form:

https://github.com/swiftlang/.github/blob/main/PULL_REQUEST_TEMPLATE/release.md?plain=1

Otherwise, replace this comment with a description of your changes and
rationale. Provide links to external references/discussions if
appropriate.
If this pull request resolves any GitHub issues, link them like so:

  Resolves <link to issue>, resolves <link to another issue>.

For more information about linking a pull request to an issue, see:

https://docs.github.com/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue
-->

<!--
Before merging this pull request, you must run the Swift continuous
integration tests.
For information about triggering CI builds via @swift-ci, see:

https://github.com/apple/swift/blob/main/docs/ContinuousIntegration.md#swift-ci

Thank you for your contribution to Swift!
-->
@xwu
Copy link
Collaborator Author

xwu commented Nov 3, 2025

@swift-ci benchmark

@xwu
Copy link
Collaborator Author

xwu commented Nov 3, 2025

Performance (x86_64): -O

Regression OLD NEW DELTA RATIO
NSString.bridged.byteCount.ascii.utf16 0.0 0.535 +53500.0% 0.00x (?)
LessSubstringSubstringGenericComparable 24.208 32.138 +32.8% 0.75x (?)
EqualSubstringString 24.341 32.155 +32.1% 0.76x
LessSubstringSubstring 24.302 30.732 +26.5% 0.79x
EqualStringSubstring 25.755 32.146 +24.8% 0.80x
SubstringEqualString 145.8 181.75 +24.7% 0.80x
EqualSubstringSubstringGenericEquatable 26.485 32.16 +21.4% 0.82x
UTF8Decode_InitFromCustom_contiguous 146.313 177.308 +21.2% 0.83x (?)
UTF8Decode_InitFromData 150.364 181.7 +20.8% 0.83x (?)
EqualSubstringSubstring 26.674 32.155 +20.5% 0.83x
UTF8Decode_InitFromCustom_noncontiguous 175.143 210.333 +20.1% 0.83x (?)
NormalizedIterator_ascii 69.903 83.5 +19.5% 0.84x (?)
StringComparison_longSharedPrefix 212.455 252.222 +18.7% 0.84x (?)
UTF8Decode_InitDecoding 151.231 177.182 +17.2% 0.85x (?)
DataToStringEmpty 95.5 111.84 +17.1% 0.85x (?)
UTF8Decode_InitFromBytes 173.0 201.909 +16.7% 0.86x (?)
SequenceAlgosAnySequence 7984.615 9250.0 +15.8% 0.86x (?)
SubstringEquatable 293.125 332.714 +13.5% 0.88x
StringComparison_latin1 308.769 344.429 +11.5% 0.90x (?)
SortStringsUnicode 2177.0 2427.5 +11.5% 0.90x (?)
SuffixAnySeqCntRangeLazy 13700.0 15125.0 +10.4% 0.91x (?)
StringComparison_fastPrenormal 431.667 476.346 +10.4% 0.91x (?)
String.replaceSubrange.Substring 10.718 11.761 +9.7% 0.91x (?)
 
Improvement OLD NEW DELTA RATIO
IntegerToString.UInt128.decimal 418.5 155.556 -62.8% 2.69x
IntegerToString.UInt64.hex 289.75 121.133 -58.2% 2.39x
IntegerToString.UInt128.hex 434.2 196.3 -54.8% 2.21x
IntegerToString.Int.hex 168.429 97.957 -41.8% 1.72x
Breadcrumbs.CopyUTF16CodeUnits.longMixed 219.6 162.0 -26.2% 1.36x
Breadcrumbs.CopyAllUTF16CodeUnits.longMixed 213.909 159.667 -25.4% 1.34x
Breadcrumbs.CopyAllUTF16CodeUnits.Mixed 216.636 161.714 -25.4% 1.34x
IntegerToString.UInt64.decimal 195.6 148.7 -24.0% 1.32x
Dictionary2 503.864 427.143 -15.2% 1.18x (?)
StringFromLongWholeSubstring 3.118 2.733 -12.3% 1.14x (?)
StringComparison_ascii 241.6 212.818 -11.9% 1.14x (?)
StringSwitch 325.714 289.857 -11.0% 1.12x (?)
Calculator 173.286 154.333 -10.9% 1.12x (?)
Dictionary2OfObjects 972.5 867.5 -10.8% 1.12x (?)
NSString.bridged.byteCount.utf8.utf16 1.51 1.392 -7.8% 1.08x (?)
AngryPhonebook.Strasse.Small 156.8 144.6 -7.8% 1.08x (?)
StringUTF16Builder 377.903 348.657 -7.7% 1.08x (?)
StringBuilder 344.0 318.0 -7.6% 1.08x (?)
BridgeString.find.native.longNonASCII 402.5 373.0 -7.3% 1.08x (?)
Chars2 3420.833 3181.081 -7.0% 1.08x (?)

Code size: -O

Performance (x86_64): -Osize

Regression OLD NEW DELTA RATIO
EqualSubstringSubstringGenericEquatable 23.221 31.213 +34.4% 0.74x
EqualStringSubstring 24.081 32.263 +34.0% 0.75x
EqualSubstringSubstring 23.303 31.219 +34.0% 0.75x (?)
EqualSubstringString 24.212 32.154 +32.8% 0.75x
SubstringEqualString 135.188 178.385 +32.0% 0.76x (?)
LessSubstringSubstringGenericComparable 25.0 32.397 +29.6% 0.77x (?)
LessSubstringSubstring 25.0 32.385 +29.5% 0.77x
SubstringEquatable 282.0 348.667 +23.6% 0.81x (?)
UTF8Decode_InitFromCustom_noncontiguous 234.3 276.0 +17.8% 0.85x
UTF8Decode_InitFromCustom_contiguous 152.333 178.846 +17.4% 0.85x
UTF8Decode_InitFromData 157.2 181.5 +15.5% 0.87x
UTF8Decode_InitDecoding 151.417 173.778 +14.8% 0.87x (?)
NormalizedIterator_ascii 73.219 83.759 +14.4% 0.87x (?)
UTF8Decode_InitFromBytes 176.75 201.727 +14.1% 0.88x
SubstringFromLongStringGeneric2 26.449 29.733 +12.4% 0.89x (?)
StringComparison_longSharedPrefix 218.545 244.111 +11.7% 0.90x (?)
StringComparison_fastPrenormal 442.182 492.857 +11.5% 0.90x (?)
NormalizedIterator_emoji 328.286 362.815 +10.5% 0.90x (?)
StringComparison_latin1 320.286 351.538 +9.8% 0.91x (?)
String.replaceSubrange.Substring 10.831 11.764 +8.6% 0.92x (?)
DropLastAnySeqCntRangeLazy 13818.0 14976.0 +8.4% 0.92x (?)
CStringLongNonAscii 147.063 159.333 +8.3% 0.92x (?)
SequenceAlgosAnySequence 8546.154 9252.0 +8.3% 0.92x (?)
DropLastAnySeqCRangeIterLazy 14140.0 15270.0 +8.0% 0.93x (?)
SortStringsUnicode 2259.0 2437.5 +7.9% 0.93x (?)
 
Improvement OLD NEW DELTA RATIO
IntegerToString.UInt128.decimal 393.0 155.4 -60.5% 2.53x
IntegerToString.UInt64.hex 278.75 125.684 -54.9% 2.22x
IntegerToString.UInt128.hex 425.4 199.364 -53.1% 2.13x
IntegerToString.Int.hex 157.9 98.529 -37.6% 1.60x
Breadcrumbs.CopyAllUTF16CodeUnits.longMixed 213.818 159.667 -25.3% 1.34x
Breadcrumbs.CopyAllUTF16CodeUnits.Mixed 216.727 162.214 -25.2% 1.34x
Breadcrumbs.CopyUTF16CodeUnits.longMixed 219.5 165.643 -24.5% 1.33x
IntegerToString.UInt64.decimal 192.0 153.929 -19.8% 1.25x (?)
StringFromLongWholeSubstring 3.61 2.904 -19.6% 1.24x
StringSwitch 320.571 273.0 -14.8% 1.17x (?)
Dictionary2 546.875 484.25 -11.5% 1.13x (?)
ConvertFloatingPoint.MockFloat64ToInt64 618.667 550.5 -11.0% 1.12x (?)
StringInterpolationSmall 992.083 882.778 -11.0% 1.12x (?)
CharacterRecognizer.mixed 17.618 16.087 -8.7% 1.10x (?)
AngryPhonebook.Strasse.Small 156.714 143.267 -8.6% 1.09x (?)
StringAdder 341.857 313.571 -8.3% 1.09x (?)

Code size: -Osize

Performance (x86_64): -Onone

Regression OLD NEW DELTA RATIO
LessSubstringSubstring 27.4 36.017 +31.4% 0.76x
EqualStringSubstring 29.0 37.269 +28.5% 0.78x
LessSubstringSubstringGenericComparable 27.3 34.552 +26.6% 0.79x (?)
EqualSubstringSubstringGenericEquatable 27.735 34.09 +22.9% 0.81x
EqualSubstringSubstring 27.625 33.424 +21.0% 0.83x
EqualSubstringString 29.133 35.092 +20.5% 0.83x
UTF8Decode_InitFromData 154.5 182.625 +18.2% 0.85x (?)
UTF8Decode_InitDecoding 158.75 185.25 +16.7% 0.86x (?)
UTF8Decode_InitFromCustom_contiguous 161.769 188.182 +16.3% 0.86x
UTF8Decode_InitFromBytes 177.667 201.6 +13.5% 0.88x (?)
SuffixAnySeqCntRange 15606.0 17590.0 +12.7% 0.89x (?)
DropFirstAnySeqCRangeIterLazy 14728.0 16600.0 +12.7% 0.89x (?)
SequenceAlgosAnySequence 8722.222 9791.304 +12.3% 0.89x (?)
Set.subtracting.Seq.Int.Empty 549.75 617.0 +12.2% 0.89x (?)
DropFirstAnySeqCRangeIter 14806.0 16604.0 +12.1% 0.89x (?)
LazilyFilteredRange 409980.0 454590.0 +10.9% 0.90x (?)
SuffixAnyCollection 3550.0 3926.0 +10.6% 0.90x (?)
Data.init.Sequence.809B.Count.RE 17904.0 19761.0 +10.4% 0.91x (?)
SubstringEquatable 3262.0 3589.0 +10.0% 0.91x (?)
PrefixWhileAnySeqCntRangeLazy 14970.0 16392.0 +9.5% 0.91x (?)
SuffixAnySeqCRangeIter 16307.0 17770.0 +9.0% 0.92x (?)
Data.init.Sequence.64kB.Count.RE.I 14642.0 15903.0 +8.6% 0.92x (?)
PrefixAnySeqCntRange 12593.0 13670.0 +8.6% 0.92x (?)
SuffixAnySeqCRangeIterLazy 16343.0 17732.0 +8.5% 0.92x (?)
Data.append.Sequence.809B.Count0.RE.I 18080.0 19585.0 +8.3% 0.92x (?)
FatCompactMap 265910.0 287730.0 +8.2% 0.92x (?)
DropWhileAnySeqCRangeIterLazy 18134.0 19603.0 +8.1% 0.93x (?)
DropLastAnySeqCRangeIter 18935.0 20399.0 +7.7% 0.93x (?)
SortStringsUnicode 2972.5 3200.0 +7.7% 0.93x (?)
StrComplexWalk 4645.0 5000.0 +7.6% 0.93x (?)
Data.append.Sequence.64kB.Count.RE 15195.0 16352.0 +7.6% 0.93x (?)
Data.init.Sequence.809B.Count0.RE 18573.0 19986.0 +7.6% 0.93x (?)
 
Improvement OLD NEW DELTA RATIO
IntegerToString.UInt128.decimal 436.0 169.444 -61.1% 2.57x
IntegerToString.UInt128.hex 455.0 213.636 -53.0% 2.13x
IntegerToString.UInt64.hex 535.25 354.429 -33.8% 1.51x
Breadcrumbs.CopyUTF16CodeUnits.longMixed 224.9 168.0 -25.3% 1.34x
Breadcrumbs.CopyAllUTF16CodeUnits.longMixed 211.091 160.2 -24.1% 1.32x
Breadcrumbs.CopyAllUTF16CodeUnits.Mixed 232.889 178.3 -23.4% 1.31x
IntegerToString.Int.hex 406.0 331.571 -18.3% 1.22x (?)
IntegerToString.UInt64.decimal 429.6 383.8 -10.7% 1.12x (?)
SubstringRemoveFirst1 0.222 0.2 -9.9% 1.11x (?)
CharIndexing_korean_unicodeScalars 232720.0 211720.0 -9.0% 1.10x (?)
CharIndexing_chinese_unicodeScalars_Backwards 183840.0 168240.0 -8.5% 1.09x (?)
BridgeString.find.native.longNonASCII 397.0 365.0 -8.1% 1.09x (?)
FloatingPointPrinting_Double_interpolated 33466.667 30925.0 -7.6% 1.08x (?)
ObjectiveCBridgeStringHash 61.536 57.031 -7.3% 1.08x (?)
FloatingPointPrinting_Float_interpolated 29492.308 27450.0 -6.9% 1.07x (?)

Code size: -swiftlibs

How to read the data The tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.

If you see any unexpected regressions, you should consider fixing the
regressions before you merge the PR.

Noise: Sometimes the performance results (not code size!) contain false
alarms. Unexpected regressions which are marked with '(?)' are probably noise.
If you see regressions which you cannot explain you can try to run the
benchmarks again. If regressions still show up, please consult with the
performance team (@eeckstein).

Hardware Overview
  Model Name: Mac mini
  Model Identifier: Macmini8,1
  Processor Name: 6-Core Intel Core i7
  Processor Speed: 3.2 GHz
  Number of Processors: 1
  Total Number of Cores: 6
  L2 Cache (per Core): 256 KB
  L3 Cache: 12 MB
  Memory: 32 GB

@xwu
Copy link
Collaborator Author

xwu commented Nov 3, 2025

(I have seen these string benchmarks fluctuate spuriously before with no change in code generation. Otherwise looks like it's a pretty targeted improvement—lack of change for Int decimal description benchmark is likely because the test fixture contains only values that fit in 32-bit Int which would benefit less from the two-digits-at-a-time optimization.)

@xwu xwu merged commit 591fec2 into swiftlang:main Nov 4, 2025
6 checks passed
@xwu xwu deleted the sr-9438-redux branch November 4, 2025 02:23
elsakeirouz pushed a commit to elsakeirouz/swift that referenced this pull request Nov 6, 2025
A companion to swiftlang#85180.

<!--
If this pull request is targeting a release branch, please fill out the
following form:

https://github.com/swiftlang/.github/blob/main/PULL_REQUEST_TEMPLATE/release.md?plain=1

Otherwise, replace this comment with a description of your changes and
rationale. Provide links to external references/discussions if
appropriate.
If this pull request resolves any GitHub issues, link them like so:

  Resolves <link to issue>, resolves <link to another issue>.

For more information about linking a pull request to an issue, see:

https://docs.github.com/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue
-->

<!--
Before merging this pull request, you must run the Swift continuous
integration tests.
For information about triggering CI builds via @swift-ci, see:

https://github.com/apple/swift/blob/main/docs/ContinuousIntegration.md#swift-ci

Thank you for your contribution to Swift!
-->
elsakeirouz pushed a commit to elsakeirouz/swift that referenced this pull request Nov 6, 2025
…wiftlang#85180)

Inspired by swiftlang#84826, I've dusted off and completely reworked a native
implementation of integer-to-string conversion.

Besides existing tests in this repository, the core of the
implementation has been comprehensively tested in a separate package for
all bases between 2–36 to demonstrate identical output for all 8-bit and
16-bit values, and for randomly generated 32-bit, 64-bit, and 128-bit
values.

Resolves swiftlang#51902.

<!--
If this pull request is targeting a release branch, please fill out the
following form:

https://github.com/swiftlang/.github/blob/main/PULL_REQUEST_TEMPLATE/release.md?plain=1

Otherwise, replace this comment with a description of your changes and
rationale. Provide links to external references/discussions if
appropriate.
If this pull request resolves any GitHub issues, link them like so:

  Resolves <link to issue>, resolves <link to another issue>.

For more information about linking a pull request to an issue, see:

https://docs.github.com/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue
-->

<!--
Before merging this pull request, you must run the Swift continuous
integration tests.
For information about triggering CI builds via @swift-ci, see:

https://github.com/apple/swift/blob/main/docs/ContinuousIntegration.md#swift-ci

Thank you for your contribution to Swift!
-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SR-9438] Rewrite _uint64ToString etc to Swift

2 participants