Skip to content

Conversation

@danielparks
Copy link
Owner

  • Switch to hashify phf, gain extra 20-30% unescape speed-up
    See Perfect hashing with hashify #82 for details.

  • WIP: Split unescape and entities features.

  • WIP: various unescape strategies.

  • Update unescape benchmarks.

@danielparks danielparks marked this pull request as draft November 2, 2025 00:41
@danielparks
Copy link
Owner Author

unescape violin graph

unescape graph

unescape_attribute violin graph

unescape_attribute graph

Weird that hashify is faster for unescape(), but slower for unescape_attribute(). It might just be noise from the compiler choosing different optimizations.

This allows us to use `hashify` for unescaping, and `phf` for the
`ENTITIES` map (`hashify` just generates a function, not an object).
Mostly improvements, but `unescape_attribute()` in particular regressed
in a few benchmarks. I suspect noise due to the compiler chosing
different optimizations.

    unescape/map/normal     time:   [4.7206 µs 4.7397 µs 4.7597 µs]
                            thrpt:  [3.3060 GiB/s 3.3199 GiB/s 3.3334 GiB/s]
                     change:
                            time:   [-12.523% -11.620% -10.859%] (p = 0.00 < 0.01)
                            thrpt:  [+12.182% +13.148% +14.316%]
                            Performance has improved.

    unescape/matchgen/normal
                            time:   [3.7886 µs 3.8039 µs 3.8200 µs]
                            thrpt:  [4.1193 GiB/s 4.1368 GiB/s 4.1534 GiB/s]
                     change:
                            time:   [+13.065% +14.262% +15.332%] (p = 0.00 < 0.01)
                            thrpt:  [-13.294% -12.482% -11.555%]
                            Performance has regressed.

    unescape/map/bare       time:   [8.1265 µs 8.1510 µs 8.1767 µs]
                            thrpt:  [1.9244 GiB/s 1.9305 GiB/s 1.9363 GiB/s]
                     change:
                            time:   [-12.545% -11.524% -10.738%] (p = 0.00 < 0.01)
                            thrpt:  [+12.030% +13.025% +14.344%]
                            Performance has improved.

    unescape/matchgen/bare  time:   [4.0554 µs 4.0708 µs 4.0878 µs]
                            thrpt:  [3.8494 GiB/s 3.8655 GiB/s 3.8802 GiB/s]
                     change:
                            time:   [+8.4592% +9.6087% +10.532%] (p = 0.00 < 0.01)
                            thrpt:  [-9.5282% -8.7664% -7.7994%]
                            Change within noise threshold.

    unescape/map/none       time:   [111.15 ns 111.50 ns 111.90 ns]
                            thrpt:  [140.63 GiB/s 141.12 GiB/s 141.58 GiB/s]
                     change:
                            time:   [-32.276% -31.664% -31.120%] (p = 0.00 < 0.01)
                            thrpt:  [+45.180% +46.336% +47.659%]
                            Performance has improved.

    unescape/matchgen/none  time:   [110.92 ns 111.27 ns 111.65 ns]
                            thrpt:  [140.93 GiB/s 141.41 GiB/s 141.86 GiB/s]
                     change:
                            time:   [-32.119% -31.528% -30.979%] (p = 0.00 < 0.01)
                            thrpt:  [+44.884% +46.046% +47.316%]
                            Performance has improved.

    unescape/map/invalid    time:   [8.2657 µs 8.2922 µs 8.3213 µs]
                            thrpt:  [1.8910 GiB/s 1.8976 GiB/s 1.9037 GiB/s]
                     change:
                            time:   [-42.191% -41.443% -40.916%] (p = 0.00 < 0.01)
                            thrpt:  [+69.251% +70.773% +72.982%]
                            Performance has improved.

    unescape/matchgen/invalid
                            time:   [2.0511 µs 2.0582 µs 2.0657 µs]
                            thrpt:  [7.6175 GiB/s 7.6453 GiB/s 7.6716 GiB/s]
                     change:
                            time:   [-8.8937% -8.0326% -7.2895%] (p = 0.00 < 0.01)
                            thrpt:  [+7.8626% +8.7342% +9.7619%]
                            Change within noise threshold.

    ---

    unescape_attribute/map/normal
                            time:   [4.2166 µs 4.2318 µs 4.2482 µs]
                            thrpt:  [3.7040 GiB/s 3.7184 GiB/s 3.7318 GiB/s]
                     change:
                            time:   [-20.067% -19.273% -18.634%] (p = 0.00 < 0.01)
                            thrpt:  [+22.902% +23.874% +25.105%]
                            Performance has improved.

    unescape_attribute/matchgen/normal
                            time:   [3.7959 µs 3.8122 µs 3.8300 µs]
                            thrpt:  [4.1086 GiB/s 4.1277 GiB/s 4.1454 GiB/s]
                     change:
                            time:   [+12.474% +13.614% +14.562%] (p = 0.00 < 0.01)
                            thrpt:  [-12.711% -11.983% -11.091%]
                            Performance has regressed.

    unescape_attribute/map/bare
                            time:   [7.9796 µs 8.0105 µs 8.0461 µs]
                            thrpt:  [1.9557 GiB/s 1.9644 GiB/s 1.9720 GiB/s]
                     change:
                            time:   [+14.221% +15.515% +16.562%] (p = 0.00 < 0.01)
                            thrpt:  [-14.209% -13.431% -12.451%]
                            Performance has regressed.

    unescape_attribute/matchgen/bare
                            time:   [2.6500 µs 2.6584 µs 2.6677 µs]
                            thrpt:  [5.8987 GiB/s 5.9192 GiB/s 5.9380 GiB/s]
                     change:
                            time:   [+15.336% +16.567% +17.697%] (p = 0.00 < 0.01)
                            thrpt:  [-15.036% -14.212% -13.297%]
                            Performance has regressed.

    unescape_attribute/map/none
                            time:   [109.57 ns 110.60 ns 112.92 ns]
                            thrpt:  [139.35 GiB/s 142.28 GiB/s 143.62 GiB/s]
                     change:
                            time:   [-33.038% -32.283% -31.552%] (p = 0.00 < 0.01)
                            thrpt:  [+46.096% +47.674% +49.338%]
                            Performance has improved.

    unescape_attribute/matchgen/none
                            time:   [108.92 ns 109.23 ns 109.57 ns]
                            thrpt:  [143.61 GiB/s 144.06 GiB/s 144.47 GiB/s]
                     change:
                            time:   [-33.136% -32.457% -31.867%] (p = 0.00 < 0.01)
                            thrpt:  [+46.772% +48.054% +49.556%]
                            Performance has improved.

    unescape_attribute/map/invalid
                            time:   [7.9971 µs 8.0273 µs 8.0607 µs]
                            thrpt:  [1.9521 GiB/s 1.9603 GiB/s 1.9677 GiB/s]
                     change:
                            time:   [+13.956% +15.237% +16.472%] (p = 0.00 < 0.01)
                            thrpt:  [-14.143% -13.222% -12.247%]
                            Performance has regressed.

    unescape_attribute/matchgen/invalid
                            time:   [2.0923 µs 2.1013 µs 2.1122 µs]
                            thrpt:  [7.4499 GiB/s 7.4886 GiB/s 7.5207 GiB/s]
                     change:
                            time:   [-6.9798% -6.0714% -5.3497%] (p = 0.00 < 0.01)
                            thrpt:  [+5.6520% +6.4638% +7.5036%]
                            Change within noise threshold.
`hashify` seems to generally be a little faster for `unescape()`, but
it’s often slower for `unescape_attribute()`. I can’t see why that might
be, unless the compiler is chosing different optimizations.
Quickphf is the quickest of the three hash functions in this benchmark,
then hashify, then phf. This is inconsistent with the previous
benchmarks for `unescape()` and `unescape_attribute()`.

    hash/hashmap        time:   [22.337 ns  22.432 ns  22.548 ns]
    hash/hashify        time:   [13.932 ns  14.036 ns  14.150 ns]
    hash/phf            time:   [23.504 ns  23.601 ns  23.703 ns]
    hash/quickphf       time:   [14.353 ns  14.427 ns  14.520 ns]
    hash/matchgen       time:   [9.0193 ns  9.0741 ns  9.1346 ns]

(The hashmap benchmark uses `std::collections::HashMap` for reference.)
@danielparks
Copy link
Owner Author

Added better links to the graphs in #82.

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.

3 participants