Skip to content

[String] Scalar-alignment bug fixes. #23834

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

Merged
merged 4 commits into from
Jun 27, 2019
Merged

Conversation

milseman
Copy link
Member

@milseman milseman commented Apr 6, 2019

[String] Scalar-alignment bug fixes.

Fixes a general category (pun intended) of scalar-alignment bugs
surrounding exchanging non-scalar-aligned indices between views and
for slicing.

SE-0180 unifies the Index type of String and all its views and allows
non-scalar-aligned indices to be used across views. In order to
guarantee behavior, we often have to check and perform scalar
alignment. To speed up these checks, we allocate a bit denoting
known-to-be-aligned, so that the alignment check can skip the
load. The below shows what views need to check for alignment before
they can operate, and whether the indices they produce are aligned.

View Requires Alignment Produces Aligned Indices
Native UTF8 no no
Native UTF16 yes no
Foreign UTF8 yes no
Foreign UTF16 no no
UnicodeScalar yes yes
Character yes yes

The "requires alignment" applies to any operation taking a
String.Index that's not defined entirely in terms of other operations
taking a String.Index. These include:

  • index(after:)
  • index(before:)
  • subscript
  • distance(from:to:) (since to is compared against directly)
  • UTF16View._nativeGetOffset(for:)

Bugs: https://bugs.swift.org/browse/SR-9802, https://bugs.swift.org/browse/SR-10124, https://bugs.swift.org/browse/SR-10451, https://bugs.swift.org/browse/SR-10452, https://bugs.swift.org/browse/SR-10453.

@milseman
Copy link
Member Author

milseman commented Apr 6, 2019

@swift-ci please test

@milseman
Copy link
Member Author

milseman commented Apr 6, 2019

@swift-ci please benchmark

@swift-ci
Copy link
Contributor

swift-ci commented Apr 6, 2019

Build failed
Swift Test Linux Platform
Git Sha - 6d37797ab76c69378bdffdec17e517776ff756d2

@swift-ci
Copy link
Contributor

swift-ci commented Apr 6, 2019

Performance: -O

TEST OLD NEW DELTA RATIO
Regression
SubstringFromLongStringGeneric 17 28 +64.7% 0.61x
StringHasSuffixUnicode 349000 471000 +35.0% 0.74x
StringMatch 7900 9900 +25.3% 0.80x
RemoveWhereQuadraticString 394 447 +13.5% 0.88x
SubstringFromLongString 10 11 +10.0% 0.91x (?)
RomanNumbers2 680 746 +9.7% 0.91x
ObjectiveCBridgeStubFromNSDateRef 4060 4370 +7.6% 0.93x (?)
Improvement
CharIteration_ascii_unicodeScalars_Backwards 5640 4880 -13.5% 1.16x (?)
CharIteration_russian_unicodeScalars_Backwards 5680 4920 -13.4% 1.15x
CharIteration_tweet_unicodeScalars_Backwards 11160 9680 -13.3% 1.15x
CharIteration_punctuated_unicodeScalars_Backwards 1280 1120 -12.5% 1.14x (?)
CharIndexing_russian_unicodeScalars_Backwards 5680 5200 -8.5% 1.09x (?)
CharIteration_chinese_unicodeScalars_Backwards 4880 4520 -7.4% 1.08x (?)
CharIteration_korean_unicodeScalars_Backwards 6640 6160 -7.2% 1.08x (?)
CharIteration_punctuatedJapanese_unicodeScalars_Backwards 1200 1120 -6.7% 1.07x (?)

Code size: -O

TEST OLD NEW DELTA RATIO
Regression
StringMatch.o 4430 5943 +34.2% 0.75x
RomanNumbers.o 8539 9899 +15.9% 0.86x
Substring.o 18095 19933 +10.2% 0.91x
StringEdits.o 11919 13023 +9.3% 0.92x
CSVParsing.o 31201 33457 +7.2% 0.93x
StringBuilder.o 7848 8152 +3.9% 0.96x
ArrayAppend.o 38936 40184 +3.2% 0.97x
WordCount.o 45331 46619 +2.8% 0.97x
StringComparison.o 43310 44078 +1.8% 0.98x

Performance: -Osize

TEST OLD NEW DELTA RATIO
Regression
SubstringFromLongStringGeneric 17 28 +64.7% 0.61x
StringHasSuffixUnicode 347000 470000 +35.4% 0.74x
StringMatch 8200 10600 +29.3% 0.77x
RemoveWhereQuadraticString 397 463 +16.6% 0.86x
RomanNumbers2 666 747 +12.2% 0.89x
CharIteration_punctuated_unicodeScalars 680 760 +11.8% 0.89x (?)
CharIteration_chinese_unicodeScalars 3160 3480 +10.1% 0.91x
SubstringFromLongString 10 11 +10.0% 0.91x
CharIteration_russian_unicodeScalars_Backwards 5640 6120 +8.5% 0.92x
Improvement
CharIndexing_russian_unicodeScalars_Backwards 6400 5760 -10.0% 1.11x
CharIndexing_chinese_unicodeScalars_Backwards 5960 5440 -8.7% 1.10x
CharIndexing_ascii_unicodeScalars_Backwards 6480 5920 -8.6% 1.09x (?)
CharIndexing_tweet_unicodeScalars_Backwards 12760 11680 -8.5% 1.09x (?)
CharIndexing_japanese_unicodeScalars_Backwards 9680 8880 -8.3% 1.09x (?)
CharIndexing_punctuatedJapanese_unicodeScalars_Backwards 1520 1400 -7.9% 1.09x (?)
CharIndexing_korean_unicodeScalars_Backwards 7800 7200 -7.7% 1.08x
CharIndexing_punctuated_unicodeScalars_Backwards 1560 1440 -7.7% 1.08x (?)

Code size: -Osize

TEST OLD NEW DELTA RATIO
Regression
StringMatch.o 4385 4841 +10.4% 0.91x
RomanNumbers.o 8754 9218 +5.3% 0.95x
Substring.o 17152 17776 +3.6% 0.96x
CSVParsing.o 30561 31537 +3.2% 0.97x
WordCount.o 41004 41500 +1.2% 0.99x
Improvement
StringBuilder.o 7774 7438 -4.3% 1.05x

Performance: -Onone

TEST OLD NEW DELTA RATIO
Regression
SubstringFromLongString 11 23 +109.1% 0.48x
SubstringFromLongStringGeneric 28 39 +39.3% 0.72x
StringHasSuffixUnicode 351000 473000 +34.8% 0.74x
CharacterPropertiesStashed 3240 3610 +11.4% 0.90x (?)
ArrayOfPOD 773 852 +10.2% 0.91x (?)
CharIteration_tweet_unicodeScalars_Backwards 703200 770240 +9.5% 0.91x (?)
CharIteration_russian_unicodeScalars_Backwards 296520 323760 +9.2% 0.92x (?)
FatCompactMap 440180 473540 +7.6% 0.93x (?)
Improvement
StringUTF16SubstringBuilder 21130 19170 -9.3% 1.10x (?)
Breadcrumbs.MutatedIdxToUTF16.ASCII 23 21 -8.7% 1.10x (?)
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 Pro
  Model Identifier: MacPro6,1
  Processor Name: 12-Core Intel Xeon E5
  Processor Speed: 2.7 GHz
  Number of Processors: 1
  Total Number of Cores: 12
  L2 Cache (per Core): 256 KB
  L3 Cache: 30 MB
  Memory: 64 GB

@milseman
Copy link
Member Author

@swift-ci please benchmark

@swift-ci
Copy link
Contributor

Performance: -O

Regression OLD NEW DELTA RATIO
StringHasSuffixUnicode 213000 2668000 +1152.6% 0.08x
Breadcrumbs.CopyUTF16CodeUnits.ASCII 13 22 +69.2% 0.59x (?)
NSStringConversion.LongUTF8 313 420 +34.2% 0.75x (?)
NSStringConversion.UTF8 443 509 +14.9% 0.87x (?)
DistinctClassFieldAccesses 177 195 +10.2% 0.91x (?)
FlattenListFlatMap 4241 4656 +9.8% 0.91x (?)
LazilyFilteredArrayContains 21200 23000 +8.5% 0.92x (?)
ArrayInClass 805 870 +8.1% 0.93x (?)
 
Improvement OLD NEW DELTA RATIO
CharacterPropertiesPrecomputed 660 540 -18.2% 1.22x (?)
CharIteration_ascii_unicodeScalars_Backwards 3160 2600 -17.7% 1.22x (?)
CharacterPropertiesStashedMemo 780 650 -16.7% 1.20x (?)
CharacterPropertiesStashed 850 730 -14.1% 1.16x (?)
CharIndexing_russian_unicodeScalars_Backwards 3480 3000 -13.8% 1.16x (?)
CSVParsing.Char 334 289 -13.5% 1.16x (?)
CharIteration_tweet_unicodeScalars_Backwards 6000 5200 -13.3% 1.15x
CharIteration_utf16_unicodeScalars_Backwards 4800 4200 -12.5% 1.14x (?)
CharIndexing_tweet_unicodeScalars 6320 5560 -12.0% 1.14x (?)
CharIndexing_utf16_unicodeScalars 4560 4040 -11.4% 1.13x (?)
CharIteration_punctuatedJapanese_unicodeScalars_Backwards 720 640 -11.1% 1.12x (?)
CharIteration_punctuated_unicodeScalars_Backwards 720 640 -11.1% 1.12x (?)
CharIndexing_punctuated_unicodeScalars_Backwards 800 720 -10.0% 1.11x (?)
CharIndexing_korean_unicodeScalars 4160 3760 -9.6% 1.11x (?)
CharIndexing_punctuated_unicodeScalars 840 760 -9.5% 1.11x (?)
CharIndexing_chinese_unicodeScalars 3000 2720 -9.3% 1.10x (?)
CharIndexing_utf16_unicodeScalars_Backwards 4800 4360 -9.2% 1.10x (?)
CharIndexing_tweet_unicodeScalars_Backwards 5800 5280 -9.0% 1.10x
CharIndexing_ascii_unicodeScalars 3240 2960 -8.6% 1.09x (?)
CharIndexing_ascii_unicodeScalars_Backwards 2960 2720 -8.1% 1.09x (?)
CharIteration_chinese_unicodeScalars_Backwards 3000 2760 -8.0% 1.09x (?)
StringComparison_ascii 377 347 -8.0% 1.09x (?)
StrToInt 1040 970 -6.7% 1.07x (?)
CharIndexing_japanese_unicodeScalars 4840 4520 -6.6% 1.07x (?)

Code size: -O

Regression OLD NEW DELTA RATIO
StringMatch.o 4078 4576 +12.2% 0.89x
RomanNumbers.o 8027 8515 +6.1% 0.94x
StringEdits.o 11887 12455 +4.8% 0.95x
Substring.o 18079 18565 +2.7% 0.97x
StringBuilder.o 7656 7751 +1.2% 0.99x
StringInterpolation.o 7251 7339 +1.2% 0.99x
 
Improvement OLD NEW DELTA RATIO
ArrayAppend.o 38883 34971 -10.1% 1.11x
CSVParsing.o 62999 60863 -3.4% 1.04x
StringWalk.o 41490 40538 -2.3% 1.02x

Performance: -Osize

Regression OLD NEW DELTA RATIO
StringHasSuffixUnicode 215000 2695000 +1153.5% 0.08x
CharIndexing_tweet_unicodeScalars 5800 11160 +92.4% 0.52x
CharIndexing_ascii_unicodeScalars 2960 5680 +91.9% 0.52x (?)
CharIndexing_ascii_unicodeScalars_Backwards 3000 5680 +89.3% 0.53x
CharIndexing_tweet_unicodeScalars_Backwards 6080 11160 +83.6% 0.54x
CharIndexing_korean_unicodeScalars 4040 7360 +82.2% 0.55x (?)
CharIndexing_punctuated_unicodeScalars_Backwards 800 1440 +80.0% 0.56x (?)
CharIndexing_russian_unicodeScalars 3400 6000 +76.5% 0.57x (?)
CharIndexing_punctuated_unicodeScalars 800 1400 +75.0% 0.57x (?)
CharIndexing_chinese_unicodeScalars 2960 5080 +71.6% 0.58x
Breadcrumbs.CopyUTF16CodeUnits.ASCII 13 22 +69.2% 0.59x (?)
CharIndexing_korean_unicodeScalars_Backwards 4400 7440 +69.1% 0.59x
CharIndexing_japanese_unicodeScalars 4800 8000 +66.7% 0.60x (?)
CharIndexing_russian_unicodeScalars_Backwards 3560 5920 +66.3% 0.60x (?)
CharIndexing_chinese_unicodeScalars_Backwards 3240 5240 +61.7% 0.62x
CharIndexing_japanese_unicodeScalars_Backwards 5360 8440 +57.5% 0.64x
CharIndexing_punctuatedJapanese_unicodeScalars 800 1240 +55.0% 0.65x
CharIndexing_punctuatedJapanese_unicodeScalars_Backwards 880 1320 +50.0% 0.67x (?)
CharIndexing_utf16_unicodeScalars 4600 6320 +37.4% 0.73x
NSStringConversion.LongUTF8 309 410 +32.7% 0.75x (?)
CharIndexing_utf16_unicodeScalars_Backwards 5240 6840 +30.5% 0.77x (?)
Breadcrumbs.CopyUTF16CodeUnits.Mixed 36 41 +13.9% 0.88x
NSStringConversion.UTF8 450 501 +11.3% 0.90x
CharIteration_punctuated_unicodeScalars 400 440 +10.0% 0.91x (?)
DistinctClassFieldAccesses 174 191 +9.8% 0.91x (?)
CharIteration_ascii_unicodeScalars 1720 1880 +9.3% 0.91x (?)
ArrayInClass 785 850 +8.3% 0.92x (?)
CharIteration_tweet_unicodeScalars 3440 3720 +8.1% 0.92x
Breadcrumbs.MutatedUTF16ToIdx.Mixed 178 192 +7.9% 0.93x (?)
Breadcrumbs.MutatedIdxToUTF16.Mixed 180 194 +7.8% 0.93x (?)
ParseFloat.Float.Exp 13 14 +7.7% 0.93x (?)
 
Improvement OLD NEW DELTA RATIO
FlattenListLoop 2714 2151 -20.7% 1.26x (?)
PrefixCountableRangeLazy 17 14 -17.6% 1.21x (?)
CharacterPropertiesStashedMemo 920 800 -13.0% 1.15x (?)
CSVParsing.Char 335 292 -12.8% 1.15x
CharacterPropertiesStashed 960 840 -12.5% 1.14x (?)
CharacterPropertiesPrecomputed 1050 930 -11.4% 1.13x (?)
Set.subtracting.Empty.Box 9 8 -11.1% 1.12x (?)
CharIteration_tweet_unicodeScalars_Backwards 6280 5640 -10.2% 1.11x (?)
ArrayAppendUTF16Substring 10224 9252 -9.5% 1.11x (?)
ArrayAppendAsciiSubstring 10188 9252 -9.2% 1.10x (?)
CharIteration_ascii_unicodeScalars_Backwards 3080 2800 -9.1% 1.10x (?)
DataCreateEmptyArray 1700 1550 -8.8% 1.10x (?)
ArrayAppendLatin1Substring 10332 9432 -8.7% 1.10x (?)
CharIteration_utf16_unicodeScalars_Backwards 5200 4760 -8.5% 1.09x

Code size: -Osize

Regression OLD NEW DELTA RATIO
StringMatch.o 4033 4577 +13.5% 0.88x
StringEdits.o 11830 12390 +4.7% 0.95x
RomanNumbers.o 8242 8602 +4.4% 0.96x
Substring.o 17136 17528 +2.3% 0.98x
StringInterpolation.o 6906 6994 +1.3% 0.99x
StringBuilder.o 7774 7870 +1.2% 0.99x

Performance: -Onone

Regression OLD NEW DELTA RATIO
StringHasSuffixUnicode 216000 2681000 +1141.2% 0.08x
StringWalk 7280 8080 +11.0% 0.90x (?)
ExclusivityGlobal 101 112 +10.9% 0.90x (?)
NopDeinit 114100 126500 +10.9% 0.90x (?)
NSStringConversion.LongUTF8 1377 1516 +10.1% 0.91x (?)
Breadcrumbs.MutatedUTF16ToIdx.Mixed 192 207 +7.8% 0.93x (?)
 
Improvement OLD NEW DELTA RATIO
CharacterPropertiesStashed 1770 1640 -7.3% 1.08x (?)

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: 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: 64 GB

@milseman
Copy link
Member Author

Whoops, I had a stray debugging print statement that's triggering on that benchmark.

@milseman
Copy link
Member Author

@swift-ci please benchmark

@milseman
Copy link
Member Author

(still need to fix up a couple tests that should've been failing before, but weren't)

@swift-ci
Copy link
Contributor

Performance: -O

Regression OLD NEW DELTA RATIO
Breadcrumbs.CopyUTF16CodeUnits.ASCII 13 22 +69.2% 0.59x (?)
NSStringConversion.LongUTF8 313 411 +31.3% 0.76x
EqualSubstringSubstring 21 27 +28.6% 0.78x
LessSubstringSubstring 21 27 +28.6% 0.78x (?)
EqualStringSubstring 21 27 +28.6% 0.78x
EqualSubstringSubstringGenericEquatable 21 27 +28.6% 0.78x
EqualSubstringString 21 27 +28.6% 0.78x
LessSubstringSubstringGenericComparable 21 27 +28.6% 0.78x
ArrayInClass 805 1000 +24.2% 0.81x (?)
Breadcrumbs.CopyUTF16CodeUnits.Mixed 36 42 +16.7% 0.86x (?)
Breadcrumbs.MutatedIdxToUTF16.Mixed 179 206 +15.1% 0.87x (?)
NSStringConversion.UTF8 443 509 +14.9% 0.87x (?)
Breadcrumbs.MutatedUTF16ToIdx.Mixed 179 205 +14.5% 0.87x (?)
StringComparison_longSharedPrefix 320 356 +11.2% 0.90x (?)
DistinctClassFieldAccesses 176 192 +9.1% 0.92x (?)
RemoveWhereFilterInts 23 25 +8.7% 0.92x (?)
RangeOverlapsClosedRange 50 54 +8.0% 0.93x (?)
 
Improvement OLD NEW DELTA RATIO
StringHasSuffixUnicode 213000 136000 -36.2% 1.57x
CharacterPropertiesPrecomputed 660 540 -18.2% 1.22x (?)
CharIteration_ascii_unicodeScalars_Backwards 3160 2600 -17.7% 1.22x
CharacterPropertiesStashedMemo 770 650 -15.6% 1.18x
CharacterPropertiesStashed 850 730 -14.1% 1.16x (?)
CSVParsing.Char 335 288 -14.0% 1.16x (?)
CharIndexing_russian_unicodeScalars_Backwards 3480 3000 -13.8% 1.16x (?)
CharIteration_tweet_unicodeScalars_Backwards 6000 5200 -13.3% 1.15x (?)
UTF8Decode_InitDecoding 122 106 -13.1% 1.15x
CharIteration_utf16_unicodeScalars_Backwards 4800 4200 -12.5% 1.14x (?)
CharIndexing_utf16_unicodeScalars 4600 4040 -12.2% 1.14x (?)
CharIndexing_tweet_unicodeScalars 6320 5600 -11.4% 1.13x (?)
CharIteration_punctuatedJapanese_unicodeScalars_Backwards 720 640 -11.1% 1.12x (?)
CharIndexing_korean_unicodeScalars 4200 3760 -10.5% 1.12x (?)
CharIndexing_utf16_unicodeScalars_Backwards 4800 4320 -10.0% 1.11x
CharIndexing_punctuated_unicodeScalars_Backwards 800 720 -10.0% 1.11x (?)
CharIndexing_punctuated_unicodeScalars 840 760 -9.5% 1.11x (?)
CharIndexing_chinese_unicodeScalars 3000 2720 -9.3% 1.10x (?)
CharIndexing_tweet_unicodeScalars_Backwards 5800 5280 -9.0% 1.10x (?)
CharIndexing_ascii_unicodeScalars 3240 2960 -8.6% 1.09x (?)
CharIndexing_ascii_unicodeScalars_Backwards 2960 2720 -8.1% 1.09x (?)
CharIteration_chinese_unicodeScalars_Backwards 3000 2760 -8.0% 1.09x (?)
Calculator 152 141 -7.2% 1.08x (?)
CharIndexing_russian_unicodeScalars 3440 3200 -7.0% 1.07x (?)
StringComparison_ascii 372 347 -6.7% 1.07x (?)
CharIndexing_japanese_unicodeScalars 4840 4520 -6.6% 1.07x (?)

Code size: -O

Regression OLD NEW DELTA RATIO
StringMatch.o 4078 4576 +12.2% 0.89x
RomanNumbers.o 8027 8515 +6.1% 0.94x
StringEdits.o 11887 12455 +4.8% 0.95x
Substring.o 18079 18565 +2.7% 0.97x
StringBuilder.o 7656 7751 +1.2% 0.99x
StringInterpolation.o 7251 7339 +1.2% 0.99x
 
Improvement OLD NEW DELTA RATIO
ArrayAppend.o 38883 34971 -10.1% 1.11x
CSVParsing.o 62999 60863 -3.4% 1.04x
StringWalk.o 41490 40538 -2.3% 1.02x

Performance: -Osize

Regression OLD NEW DELTA RATIO
CharIndexing_tweet_unicodeScalars 5800 11160 +92.4% 0.52x
CharIndexing_ascii_unicodeScalars 2960 5680 +91.9% 0.52x
CharIndexing_ascii_unicodeScalars_Backwards 3000 5680 +89.3% 0.53x (?)
CharIndexing_tweet_unicodeScalars_Backwards 6080 11120 +82.9% 0.55x
CharIndexing_korean_unicodeScalars 4040 7360 +82.2% 0.55x
CharIndexing_punctuated_unicodeScalars_Backwards 800 1440 +80.0% 0.56x
CharIndexing_russian_unicodeScalars 3400 5960 +75.3% 0.57x
CharIndexing_punctuated_unicodeScalars 800 1400 +75.0% 0.57x (?)
CharIndexing_chinese_unicodeScalars 2960 5080 +71.6% 0.58x (?)
CharIndexing_korean_unicodeScalars_Backwards 4360 7480 +71.6% 0.58x
Breadcrumbs.CopyUTF16CodeUnits.ASCII 13 22 +69.2% 0.59x
CharIndexing_japanese_unicodeScalars 4800 8000 +66.7% 0.60x
CharIndexing_russian_unicodeScalars_Backwards 3560 5880 +65.2% 0.61x
CharIndexing_chinese_unicodeScalars_Backwards 3240 5240 +61.7% 0.62x
CharIndexing_japanese_unicodeScalars_Backwards 5320 8440 +58.6% 0.63x
CharIndexing_punctuatedJapanese_unicodeScalars 800 1240 +55.0% 0.65x (?)
CharIndexing_punctuatedJapanese_unicodeScalars_Backwards 880 1320 +50.0% 0.67x
CharIndexing_utf16_unicodeScalars 4560 6320 +38.6% 0.72x
NSStringConversion.LongUTF8 309 413 +33.7% 0.75x
EqualSubstringSubstring 21 28 +33.3% 0.75x
EqualStringSubstring 21 28 +33.3% 0.75x (?)
EqualSubstringSubstringGenericEquatable 21 28 +33.3% 0.75x (?)
EqualSubstringString 21 28 +33.3% 0.75x
CharIndexing_utf16_unicodeScalars_Backwards 5240 6840 +30.5% 0.77x
LessSubstringSubstring 21 27 +28.6% 0.78x
LessSubstringSubstringGenericComparable 21 27 +28.6% 0.78x
ArrayInClass 780 955 +22.4% 0.82x
Breadcrumbs.CopyUTF16CodeUnits.Mixed 36 42 +16.7% 0.86x (?)
NSStringConversion.UTF8 446 520 +16.6% 0.86x (?)
Breadcrumbs.MutatedUTF16ToIdx.Mixed 178 204 +14.6% 0.87x (?)
Breadcrumbs.MutatedIdxToUTF16.Mixed 179 205 +14.5% 0.87x
StringComparison_longSharedPrefix 321 357 +11.2% 0.90x (?)
CharIteration_punctuated_unicodeScalars 400 440 +10.0% 0.91x (?)
HashTest 740 810 +9.5% 0.91x (?)
CharIteration_ascii_unicodeScalars 1720 1880 +9.3% 0.91x (?)
DistinctClassFieldAccesses 175 191 +9.1% 0.92x (?)
CharIteration_tweet_unicodeScalars 3440 3720 +8.1% 0.92x (?)
ObjectiveCBridgeStubFromNSDate 2650 2860 +7.9% 0.93x (?)
 
Improvement OLD NEW DELTA RATIO
StringHasSuffixUnicode 214000 136000 -36.4% 1.57x
UTF8Decode_InitDecoding 122 105 -13.9% 1.16x (?)
CSVParsing.Char 336 292 -13.1% 1.15x (?)
CharacterPropertiesStashedMemo 920 800 -13.0% 1.15x (?)
CharacterPropertiesStashed 960 840 -12.5% 1.14x (?)
CharacterPropertiesPrecomputed 1050 930 -11.4% 1.13x
ArrayAppendAsciiSubstring 10224 9216 -9.9% 1.11x (?)
CharIteration_tweet_unicodeScalars_Backwards 6240 5640 -9.6% 1.11x (?)
ArrayAppendUTF16Substring 10224 9252 -9.5% 1.11x (?)
ArrayAppendLatin1Substring 10332 9396 -9.1% 1.10x (?)
CharIteration_utf16_unicodeScalars_Backwards 5200 4760 -8.5% 1.09x (?)
CharIteration_ascii_unicodeScalars_Backwards 3040 2800 -7.9% 1.09x (?)

Code size: -Osize

Regression OLD NEW DELTA RATIO
StringMatch.o 4033 4577 +13.5% 0.88x
StringEdits.o 11830 12390 +4.7% 0.95x
RomanNumbers.o 8242 8602 +4.4% 0.96x
Substring.o 17136 17528 +2.3% 0.98x
StringInterpolation.o 6906 6994 +1.3% 0.99x
StringBuilder.o 7774 7870 +1.2% 0.99x

Performance: -Onone

Regression OLD NEW DELTA RATIO
LessSubstringSubstring 24 31 +29.2% 0.77x (?)
EqualSubstringSubstringGenericEquatable 24 30 +25.0% 0.80x (?)
LessSubstringSubstringGenericComparable 24 30 +25.0% 0.80x (?)
ArrayAppendGenericStructs 1000 1240 +24.0% 0.81x (?)
EqualSubstringSubstring 25 31 +24.0% 0.81x
EqualStringSubstring 26 31 +19.2% 0.84x
EqualSubstringString 26 31 +19.2% 0.84x
Breadcrumbs.MutatedIdxToUTF16.Mixed 192 223 +16.1% 0.86x (?)
ArrayInClass 2235 2580 +15.4% 0.87x (?)
Breadcrumbs.MutatedUTF16ToIdx.Mixed 192 219 +14.1% 0.88x (?)
NSStringConversion.LongUTF8 1377 1553 +12.8% 0.89x (?)
ExclusivityGlobal 102 113 +10.8% 0.90x (?)
StringWalk 7280 8040 +10.4% 0.91x (?)
 
Improvement OLD NEW DELTA RATIO
StringHasSuffixUnicode 216000 138000 -36.1% 1.57x
UTF8Decode_InitDecoding 142 123 -13.4% 1.15x
ArrayOfGenericPOD2 794 729 -8.2% 1.09x (?)
CharacterPropertiesStashed 1780 1650 -7.3% 1.08x (?)
Breadcrumbs.MutatedIdxToUTF16.ASCII 15 14 -6.7% 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: 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: 64 GB

@milseman milseman requested a review from lorentey June 24, 2019 23:54
@milseman
Copy link
Member Author

@swift-ci please test

@milseman
Copy link
Member Author

@swift-ci please benchmark

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 4f983f32e09c75904a4be06f42feb4f0810a95d9

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 4f983f32e09c75904a4be06f42feb4f0810a95d9

@swift-ci
Copy link
Contributor

Build failed before running benchmark.

@milseman
Copy link
Member Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 4f983f32e09c75904a4be06f42feb4f0810a95d9

milseman added 2 commits June 26, 2019 09:22
ICU will return different results if we call with an offset into a
code unit buffer vs if we slice the buffer first and provide an offset
of zero. Slicing more closely models the semantics of SE-0180, so use
that.

Test case coming in subsequent commit enforcing index
scalar-alignment.
@milseman
Copy link
Member Author

Ah, I see something got dropped from a recent rebase.

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 4f983f32e09c75904a4be06f42feb4f0810a95d9

Copy link
Member

@lorentey lorentey left a comment

Choose a reason for hiding this comment

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

Looks good! Admittedly this is a difficult one to review well -- the intricacies of utf-8 ↔︎ utf-16 transcoding vs indices make my head hurt, and I don't think I can fully appreciate the backward/forward deployment implications.

I added some review comments/questions/nitpicks.

@@ -188,6 +197,15 @@ extension String.Index {
transcodedOffset: self.transcodedOffset &- 1)
}

@_alwaysEmitIntoClient // Swift 5.1
@inline(__always)
internal var aligned: String.Index {
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: The current name doesn't really reflect what this does, and this should probably be a function.

Perhaps scalarAligned()/isScalarAligned would work a bit better? Admittedly that still has the issue that this function doesn't actually align anything, it just sets a bit.

ensureScalarAligned() / isKnownScalarAligned?

certifiedScalarAligned() / isKnownScalarAligned?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't understand. Why a function, and why is if it's not a question?

Copy link
Member

Choose a reason for hiding this comment

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

The naming change (if any) should apply to the predicate property (currently isAligned) too; the is* parts were intended as suggestions for that.

aligned as a property feels weird to me. Its effect feels closer to Float.rounded() than Float.magnitude.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't understand how this is any different than the transcoded or encoded vars. This is an internal name, where we have terminology with specific implications in mind.

Copy link
Member

Choose a reason for hiding this comment

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

I'm merely telling you the specific implications that come to my mind when I read index.aligned do not match what the property does. You're of course free to take it or leave it, it's a nitpick.

More importantly, these names should all be underscored -- String.Index is a public type.

Copy link
Member Author

Choose a reason for hiding this comment

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

Wait, is that a new policy? Could you update the programmer's manual then? We're pretty screwed right now, but we can at least make all non-public additions to public types be underscored.

Copy link
Member

Choose a reason for hiding this comment

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

No, we have always put at least one underscore in the name of non-public types and members.

I guess this is why we need to document these things...

Copy link
Member

Choose a reason for hiding this comment

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

Update: #25810

Copy link
Member Author

Choose a reason for hiding this comment

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

No, we have always put at least one underscore in the name of non-public types and members.

Unfortunately, there are many many places in the stdlib where we have internal types or declarations without a leading underscore, predating either your or my involvement in the project.

Going forwards, sure, we'll try to do that. For now, we can fixup non-ABI internal names, and we can move ABI names to the deprecated file. I'll underscore these names from this PR, and fixing up other names can come elsewhere. We need to do an audit; do you want to open a SR for that?

I guess this is why we need to document these things...

Sure, and let's nest the rule in the programmer's manual. I'll reply to that PR on how best to integrate this.

return position == 0 ? (
endIndex == 1 ? UTF16.CodeUnit(value.value) : UTF16.leadSurrogate(value)
) : UTF16.trailSurrogate(value)
_internalInvariant((0..<self.count).contains(position))
Copy link
Member

Choose a reason for hiding this comment

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

There really should be a precondition checking for out of bounds indices here; the debug check is not strong enough to catch accidental misuse, but it's strong enough to interfere with code elsewhere in the stdlib that assumes it's okay to subscript this view with any random integer. (See my comment above.)

I can currently do this:

let sadness: UnicodeScalar = "\u{1F614}"
sadness.utf16[42]  // ⟹ 5682
sadness.utf16[-9000] // ⟹ 5682

I think we should trap instead, and fix stdlib code not to rely on this misbehavior. (Doing it in a way that's compatible with code compiled on 5.0 would be challenge, I expect.) :(

Copy link
Member Author

Choose a reason for hiding this comment

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

This change just made the control flow logic easier to understand. I can also not touch this declaration in this PR. We can trap in a future PR.

Copy link
Member

Choose a reason for hiding this comment

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

This is a functional change. With the new _internalInvariant, this no longer allows subscripting with arbitrary indices for non-BMP runes in debug stdlibs, while the original code did allow that.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's adding an assert, because it would be a bug if the stdlib does so. I don't think it's pragmatic to consider all assertions as being "functional changes" to the standard library.

Copy link
Member

Choose a reason for hiding this comment

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

AFAICT, the stdlib does indeed call this with unvalidated transcoded offsets:

https://github.com/apple/swift/pull/23834/files#diff-610243ed72b2ff2c91619cdc75fea5b1R254

Copy link
Member

Choose a reason for hiding this comment

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

My point is that _internalInvariant is not the correct way to check for coding errors outside of the stdlib.

If you intend to trap if String.UTF16View.subscript is given an index with some nonsensical transcodedOffset, then we should add a precondition checking for that, either here or there.

If you intend to continue allowing such indices there, then this check needs to be removed.

I don't think it is desirable for user code to generate _internalInvariant failures in Debug stdlibs.

Copy link
Member Author

Choose a reason for hiding this comment

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

My point is that _internalInvariant is not the correct way to check for coding errors outside of the stdlib.

I agree. I added this assertion to detect unexpected inputs coming from the stdlib itself. I could remove this assertion from this PR, but it would degrade the quality of our testing.

If you intend to trap if String.UTF16View.subscript is given an index with some nonsensical transcodedOffset, then we should add a precondition checking for that, either here or there.

For this PR, I do not intend to change the semantics or behavior of this public API from user code. That does sound like a good thing to add, though, and so we'd have two methods here:

public subscript would check and trap, and subscriptImpl (or whatever it's named) would do the _internalInvariant. The stdlib's code would call the latter.

Would you like to open a SR for that change?

I don't think it is desirable for user code to generate _internalInvariant failures in Debug stdlibs.

I do not understand this position, could you clarify? This is true of any assertions, are you arguing the stdlib shouldn't have assertions? Why is user code running with a assertions-enabled stdlib relevant to this discussion?

Copy link
Member

Choose a reason for hiding this comment

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

For this PR, I do not intend to change the semantics or behavior of this public API from user code.

I'm trying to point out that you did! The addition of that _internalInvariant is a strong value judgement on the validity of the expression ("😞" as UnicodeScalar).utf16[9000].

My position is that it's not okay to let this expression run "successfully" in release builds of the stdlib, but to make it hit an assert in debug builds. This is not a valid use of _internalInvariant.

Copy link
Member Author

Choose a reason for hiding this comment

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

My position is that it's not okay to let this expression run "successfully" in release builds of the stdlib, but to make it hit an assert in debug builds. This is not a valid use of _internalInvariant.

That's all uses of _internalInvariant. If we had a compile-time proof, we wouldn't need _internalInvariant

Copy link
Collaborator

Choose a reason for hiding this comment

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

In a debug build of the stdlib, a user error without any bugs in the stdlib itself should not trigger an _internalInvariant.

I think what @lorentey is saying is that _internalInvariant should not be used to diagnose errors on the part of the caller of a public API--even when the intention is to use this for internal diagnostics. The diagnostics cannot distinguish between calls by the stdlib itself and calls by an end user, and errors on the part of the latter cannot by themselves be in violation of an internal invariant.

let offset = __swift_stdlib_ubrk_following(
iterator, Int32(truncatingIfNeeded: i))
// ICU will gives us a different result if we feed in the whole buffer, so
// slice it appropriately.
Copy link
Member

Choose a reason for hiding this comment

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

😱 I remember hearing about this, but this still gives me goosebumps. Does it merely jump back to the nearest scalar boundary, or does it also look at previous scalars? Should we have a dedicated test for the difference in behavior?

Copy link
Member Author

Choose a reason for hiding this comment

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

We care about the behavior of String, for which we have tests. Why would we care if a detail of an ICU API that we no longer use changes?

Copy link
Member

Choose a reason for hiding this comment

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

The value of that test would be to call out the specific difference in behaviour between 5.0 and 5.1. This has an observable effect on how indexing works, doesn't it?

Copy link
Member Author

Choose a reason for hiding this comment

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

We already have that test in this PR, and it would fail on 5.0. We don't usually add test cases trying to mimic prior bugs by subverting the stdlib's interfaces.

}
return scalar.utf16[i.transcodedOffset]
startingAt: _guts.scalarAlign(idx)._encodedOffset)
return scalar.utf16[idx.transcodedOffset]
Copy link
Member

Choose a reason for hiding this comment

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

Both the original code and the new code assume that it's safe to subscript the scalar's UTF-16 view with anything we find in transcodedOffset. This is no longer the case, since we now have _internalInvariant implementing a range check there. (And I think it should actually be a precondition -- see my separate review comment.)

Is it okay to trap if there is junk in transcodedOffset?

It's rather unfortunate that indices don't hold information on which view they are coming from. Is it too late to add that? If we knew the provenance of an index we would be able to only look at transcodedOffset when the index was actually generated by an UTF-16 view.

Copy link
Member Author

Choose a reason for hiding this comment

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

What would that information give us? We could also add that in the future if we want.

Regardless, we want a dedicated bit. It's more efficient and smaller code size than OR-ing up multiple bits (let along multiple branches), and this check happens everywhere.

Transcoded indices have scalar-aligned offsets, which we already detect (and set when we move on to the next scalar). We might want to clarify the semantics of the aligned bit to mean that there could still be a transcoded offset, i.e. it means the encoded offset was aligned. Then transcoded views would also always set the bit, rather than only setting it when we advance to the next scalar. It would also clean up a branch in transcoded code unit views where we check if transcoded is zero or alignment bit is set. On the flip side, anything that needs a aligned and non-transcoded index (e.g. distance) would have to check the alignment bit and transcoded offset.

Copy link
Member Author

Choose a reason for hiding this comment

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

BTW, I added more comments and a table in the new update, such as https://github.com/apple/swift/pull/23834/files#diff-8ec9c169d4bc3c678838b4067481979eR211

@milseman
Copy link
Member Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 4f983f32e09c75904a4be06f42feb4f0810a95d9

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 4f983f32e09c75904a4be06f42feb4f0810a95d9

Fixes a general category (pun intended) of scalar-alignment bugs
surrounding exchanging non-scalar-aligned indices between views and
for slicing.

SE-0180 unifies the Index type of String and all its views and allows
non-scalar-aligned indices to be used across views. In order to
guarantee behavior, we often have to check and perform scalar
alignment. To speed up these checks, we allocate a bit denoting
known-to-be-aligned, so that the alignment check can skip the
load. The below shows what views need to check for alignment before
they can operate, and whether the indices they produce are aligned.

┌───────────────╥────────────────────┬──────────────────────────┐
│ View          ║ Requires Alignment │ Produces Aligned Indices │
╞═══════════════╬════════════════════╪══════════════════════════╡
│ Native UTF8   ║ no                 │ no                       │
├───────────────╫────────────────────┼──────────────────────────┤
│ Native UTF16  ║ yes                │ no                       │
╞═══════════════╬════════════════════╪══════════════════════════╡
│ Foreign UTF8  ║ yes                │ no                       │
├───────────────╫────────────────────┼──────────────────────────┤
│ Foreign UTF16 ║ no                 │ no                       │
╞═══════════════╬════════════════════╪══════════════════════════╡
│ UnicodeScalar ║ yes                │ yes                      │
├───────────────╫────────────────────┼──────────────────────────┤
│ Character     ║ yes                │ yes                      │
└───────────────╨────────────────────┴──────────────────────────┘

The "requires alignment" applies to any operation taking a
String.Index that's not defined entirely in terms of other operations
taking a String.Index. These include:

* index(after:)
* index(before:)
* subscript
* distance(from:to:) (since `to` is compared against directly)
* UTF16View._nativeGetOffset(for:)
@milseman
Copy link
Member Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 8bb5f0c25db1d637abeb576208465cc8c9cb6a3f

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 8bb5f0c25db1d637abeb576208465cc8c9cb6a3f

@milseman
Copy link
Member Author

CI failed with:

17:29:31 ld: warning: Could not find or use auto-linked library 'swiftXPC'
17:29:31 Undefined symbols for architecture x86_64:
17:29:31   "__swift_FORCE_LOAD_$_swiftXPC", referenced from:
17:29:31       __swift_FORCE_LOAD_$_swiftXPC_$_Foundation in Foundation.o
17:29:31      (maybe you meant: __swift_FORCE_LOAD_$_swiftXPC_$_Foundation)
17:29:31 ld: symbol(s) not found for architecture x86_64
17:29:31 
clang-7: error: linker command failed with exit code 1 (use -v to see invocation)

Seems unrelated.

@milseman
Copy link
Member Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 4cd1e81

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 4cd1e81

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.

4 participants