Skip to content

Base64 faster decode #1160

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 7 commits into from
Feb 25, 2025
Merged

Base64 faster decode #1160

merged 7 commits into from
Feb 25, 2025

Conversation

fabianfett
Copy link
Contributor

This PR is here to show further plans and to give a first glimpse into perf numbers that we will see.
It should land after #1157 has landed, which will make the diff significantly smaller.

@fabianfett
Copy link
Contributor Author

===================
Baseline system lib
===================

base64-decode-1MB-fromData-noOptions
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       5 │       5 │       5 │       5 │       5 │       5 │       6 │     535 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (#)    │     476 │     473 │     471 │     469 │     458 │     437 │     429 │     535 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (μs) *   │    2123 │    2138 │    2146 │    2159 │    2214 │    2316 │    2355 │     535 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-1MB-fromData-noOptions-invalidAfter257bytes
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       2 │       2 │       2 │       2 │       2 │       2 │       2 │     709 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (K)    │    1376 │    1372 │    1371 │    1367 │    1331 │    1283 │    1164 │     709 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) *   │     748 │     751 │     752 │     755 │     775 │     814 │     856 │     709 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-1MB-fromString-lineLength64
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       4 │       4 │       4 │       4 │       4 │       4 │       4 │     403 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (#)    │     284 │     282 │     274 │     272 │     266 │     257 │     253 │     403 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (μs) *   │    3545 │    3574 │    3676 │    3699 │    3777 │    3893 │    3958 │     403 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-1MB-fromString-noOptions
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       4 │       4 │       4 │       4 │       4 │       4 │       4 │     452 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (#)    │     332 │     330 │     328 │     319 │     313 │     305 │     301 │     452 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (μs) *   │    3038 │    3058 │    3076 │    3164 │    3219 │    3314 │    3347 │     452 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-jwtHeader-fromString-noOptions
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       4 │       4 │       4 │       4 │       4 │       4 │       4 │    6221 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (K)    │    2289 │    2259 │    2251 │    2243 │    2229 │    2141 │    2001 │    6221 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) *   │     459 │     465 │     467 │     469 │     471 │     490 │     522 │    6221 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

-------------------------------------------------------------------------------------------------------------
=============================
Existing Swift implementation
=============================

base64-decode-1MB-fromData-noOptions
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       2 │       2 │       2 │       2 │       2 │       2 │       2 │     983 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (#)    │     451 │     444 │     442 │     436 │     429 │     411 │     372 │     983 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (μs) *   │    2239 │    2273 │    2288 │    2316 │    2355 │    2458 │    2713 │     983 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-1MB-fromData-noOptions-invalidAfter257bytes
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       3 │       3 │       3 │       3 │       3 │       3 │       3 │     567 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (K)    │     235 │     227 │     224 │     219 │     212 │     192 │     153 │     567 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) *   │    4277 │    4428 │    4489 │    4588 │    4698 │    5153 │    5426 │     567 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-1MB-fromString-lineLength64
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       2 │       2 │       2 │       2 │       2 │       2 │       2 │     895 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (#)    │     397 │     390 │     383 │     379 │     377 │     363 │     315 │     895 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (μs) *   │    2539 │    2591 │    2634 │    2660 │    2679 │    2779 │    2893 │     895 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-1MB-fromString-noOptions
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       2 │       2 │       2 │       2 │       2 │       2 │       2 │    1014 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (#)    │     452 │     444 │     438 │     431 │     426 │     412 │     369 │    1014 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (μs) *   │    2232 │    2275 │    2304 │    2341 │    2372 │    2454 │    2540 │    1014 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-jwtHeader-fromString-noOptions
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       2 │       2 │       2 │       2 │       2 │       2 │       2 │   10000 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (K)    │    4015 │    3983 │    3915 │    3869 │    3839 │    3651 │    2688 │   10000 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) *   │     271 │     273 │     278 │     281 │     283 │     297 │     386 │   10000 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

-------------------------------------------------------------------------------------------------------------
=======
This PR
=======

base64-decode-1MB-fromData-noOptions
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       2 │       2 │       2 │       2 │       2 │       2 │       2 │    3104 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (#)    │    2595 │    2543 │    2499 │    2441 │    2391 │    2209 │    1744 │    3104 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (μs) *   │     406 │     416 │     423 │     434 │     443 │     483 │     598 │    3104 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-1MB-fromData-noOptions-invalidAfter257bytes
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       2 │       2 │       2 │       2 │       2 │       2 │       2 │     772 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (K)    │     377 │     344 │     310 │     289 │     262 │     171 │      95 │     772 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) *   │    2675 │    2904 │    3189 │    3369 │    3588 │    4051 │    4532 │     772 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-1MB-fromString-lineLength64
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       2 │       2 │       2 │       2 │       2 │       2 │       2 │    3030 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (#)    │    2208 │    2197 │    2159 │    2131 │    2113 │    2022 │    1608 │    3030 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (μs) *   │     474 │     477 │     485 │     491 │     495 │     519 │     598 │    3030 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-1MB-fromString-noOptions
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       2 │       2 │       2 │       2 │       2 │       2 │       2 │    3515 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (#)    │    2597 │    2541 │    2515 │    2487 │    2435 │    2313 │    1875 │    3515 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (μs) *   │     405 │     415 │     419 │     425 │     434 │     455 │     545 │    3515 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

base64-decode-jwtHeader-fromString-noOptions
╒═══════════════════════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╤═════════╕
│ Metric                    │      p0 │     p25 │     p50 │     p75 │     p90 │     p99 │    p100 │ Samples │
╞═══════════════════════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
│ Malloc (total) *          │       2 │       2 │       2 │       2 │       2 │       2 │       2 │   10000 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Throughput (# / s) (K)    │    6985 │    6951 │    6847 │    6739 │    6711 │    6375 │    4061 │   10000 │
├───────────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Time (total CPU) (ns) *   │     164 │     165 │     168 │     171 │     171 │     179 │     271 │   10000 │
╘═══════════════════════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╧═════════╛

@fabianfett
Copy link
Contributor Author

  • base64-decode-1MB-fromData-noOptions
    • Baseline (in Foundation today): 2123μs
    • Swift implementation: 2239μs (1.05x slower)
    • This PR: 406μs (5.2x faster)
  • base64-decode-1MB-fromData-noOptions-invalidAfter257bytes
    • Baseline (in Foundation today): 748ns
    • Swift implementation: 4277ns (5.7x slower)
    • This PR: 2675ns (3.5x slower)
  • base64-decode-1MB-fromString-lineLength64
    • Baseline (in Foundation today): 3545μs
    • Swift implementation: 2539μs (1.4x faster)
    • This PR: 474μs (7.5x faster)
  • base64-decode-1MB-fromString-noOptions
    • Baseline (in Foundation today): 3038μs
    • Swift implementation: 2232μs (1.3x faster)
    • This PR: 405μs (7.5x faster)
  • base64-decode-jwtHeader-fromString-noOptions
    • Baseline (in Foundation today): 459ns
    • Swift implementation: 271ns (1.7x faster)
    • This PR: 164ns (2.8x faster)

We should investigate where we need so much time in the unhappy path. Overall nice wins!

@fabianfett fabianfett marked this pull request as ready for review February 20, 2025 18:21
@fabianfett
Copy link
Contributor Author

@swift-ci please test

@parkera
Copy link
Contributor

parkera commented Feb 20, 2025

@swift-ci test

@fabianfett
Copy link
Contributor Author

@swift-ci please test

@fabianfett
Copy link
Contributor Author

@swift-ci please test

@fabianfett
Copy link
Contributor Author

@swift-ci please test

@parkera parkera merged commit d1ff558 into swiftlang:main Feb 25, 2025
3 checks passed
@fabianfett fabianfett deleted the ff-faster-decoding branch February 25, 2025 18:16
itingliu added a commit to itingliu/swift-foundation that referenced this pull request Mar 11, 2025
Revert swiftlang#1160 because it caused some app to fail to launch.
@itingliu itingliu mentioned this pull request Mar 11, 2025
itingliu added a commit that referenced this pull request Mar 11, 2025
Revert #1160 because it caused some app to fail to launch.
fabianfett added a commit to fabianfett/swift-foundation that referenced this pull request Apr 22, 2025
fabianfett added a commit to fabianfett/swift-foundation that referenced this pull request May 14, 2025
itingliu pushed a commit that referenced this pull request May 15, 2025
#1263)

* Reapply #1160

* Allow more than necessary padding characters

* Allow more than necessary padding characters in ignoreUnknownCharacters mode

* Removed `#if FOUNDATION_FRAMEWORK`
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.

2 participants