swiftlang / swift-foundation

The Foundation project
Apache License 2.0
2.4k stars 160 forks source link

Short-circuit logic to get locale that requires special case handling. #937

Closed itingliu closed 1 month ago

itingliu commented 1 month ago

This fix targets at __CFLocaleGetDoesNotRequireSpecialCaseHandling. Currently, this function calls into class _NSSwiftLocale, then struct Locale, then any LocaleProtocol (LocaleICU here), which calls into a static func of struct Locale. All the hoop jumping contributes to a lot of retain and release calls.

It turns out that this function is only used by this one call site (_CFStrGetSpecialCaseHandlingLanguageIdentifierForLocale). This change simplifies the calling chain so that we call the static function directly from _NSSwiftLocale, and the result is cached inside this class directly.

I've verified that this change brings down the time spent in CFStringCompareWithOptionsAndLocale of the reproducable case in the radar down from 904ms to 397ms.

Also added a BenchmarkLocale target.

CFStringCompareWithOptionsAndLocale benchmark result before the change:

╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       0 │       0 │       0 │       0 │       0 │       0 │       0 │     448 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (M)    │     163 │     153 │     150 │     146 │     144 │     129 │     123 │     448 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) *   │       6 │       7 │       7 │       7 │       7 │       7 │       8 │     448 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (wall clock) (ns) *  │       6 │       7 │       7 │       7 │       7 │       8 │       8 │     448 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

And after the change:

╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       0 │       0 │       0 │       0 │       0 │       0 │       0 │     476 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (M)    │     172 │     161 │     158 │     156 │     155 │     153 │     136 │     476 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) *   │       6 │       6 │       6 │       6 │       6 │       7 │       7 │     476 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (wall clock) (ns) *  │       6 │       6 │       6 │       6 │       6 │       7 │       7 │     476 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

Resolves rdar://134912852

itingliu commented 1 month ago

@swift-ci please test