[libcxx-commits] [libcxx] [libc++] Tiny optimizations for is_permutation (PR #129565)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Mar 19 11:31:21 PDT 2025
https://github.com/ldionne commented:
When I run the new benchmarks locally and compare before/after your patch, this is what I get:
<details>
<summary>Results</summary>
```
Comparing build/default/libcxx/test/benchmarks/algorithms/nonmodifying/Output/is_permutation.bench.cpp.dir/benchmark-result.json to build/candidate/libcxx/test/benchmarks/algorithms/nonmodifying/Output/is_permutation.bench.cpp.dir/benchmark-result.json
Benchmark Time CPU Time Old Time New CPU Old CPU New
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
std::is_permutation(vector<int>) (3leg) (common prefix)/8 +0.0328 +0.0303 4 4 4 4
std::is_permutation(vector<int>) (3leg) (common prefix)/1024 -0.1053 -0.1055 548 490 547 490
std::is_permutation(vector<int>) (3leg) (common prefix)/8192 +0.0017 +0.0005 3925 3931 3918 3919
std::is_permutation(deque<int>) (3leg) (common prefix)/8 +0.0026 +0.0026 7 7 7 7
std::is_permutation(deque<int>) (3leg) (common prefix)/1024 +0.0149 +0.0105 657 667 657 664
std::is_permutation(deque<int>) (3leg) (common prefix)/8192 +0.0104 +0.0070 5223 5277 5219 5256
std::is_permutation(list<int>) (3leg) (common prefix)/8 +0.0475 +0.0485 5 5 5 5
std::is_permutation(list<int>) (3leg) (common prefix)/1024 +0.4774 +0.4798 1095 1618 1092 1615
std::is_permutation(list<int>) (3leg) (common prefix)/8192 +0.0071 +0.0071 13884 13983 13860 13959
std::is_permutation(vector<int>) (3leg, pred) (common prefix)/8 +0.0399 +0.0389 4 4 4 4
std::is_permutation(vector<int>) (3leg, pred) (common prefix)/1024 -0.0139 -0.0111 461 454 459 454
std::is_permutation(vector<int>) (3leg, pred) (common prefix)/8192 +0.0212 +0.0181 3528 3603 3527 3591
std::is_permutation(deque<int>) (3leg, pred) (common prefix)/8 +0.0034 +0.0032 8 8 8 8
std::is_permutation(deque<int>) (3leg, pred) (common prefix)/1024 +0.0219 +0.0197 769 786 769 784
std::is_permutation(deque<int>) (3leg, pred) (common prefix)/8192 +0.0147 +0.0138 6121 6211 6121 6205
std::is_permutation(list<int>) (3leg, pred) (common prefix)/8 +0.0153 +0.0153 6 6 6 6
std::is_permutation(list<int>) (3leg, pred) (common prefix)/1024 +0.0654 +0.0628 1111 1184 1111 1181
std::is_permutation(list<int>) (3leg, pred) (common prefix)/8192 +0.3435 +0.3437 11485 15431 11483 15429
std::is_permutation(vector<int>) (4leg) (common prefix)/8 +0.0604 +0.0598 6 7 6 7
std::is_permutation(vector<int>) (4leg) (common prefix)/1024 +0.0248 +0.0243 572 586 572 586
std::is_permutation(vector<int>) (4leg) (common prefix)/8192 +0.0091 +0.0091 4520 4561 4520 4561
std::is_permutation(deque<int>) (4leg) (common prefix)/8 +0.0566 +0.0564 12 12 12 12
std::is_permutation(deque<int>) (4leg) (common prefix)/1024 +0.0007 +0.0004 811 811 811 811
std::is_permutation(deque<int>) (4leg) (common prefix)/8192 +0.0008 +0.0007 6440 6445 6439 6444
std::is_permutation(list<int>) (4leg) (common prefix)/8 -0.0102 -0.0102 7 7 7 7
std::is_permutation(list<int>) (4leg) (common prefix)/1024 +0.0079 +0.0079 1070 1079 1070 1078
std::is_permutation(list<int>) (4leg) (common prefix)/8192 +0.0485 +0.0481 12583 13194 12583 13189
rng::is_permutation(vector<int>) (4leg) (common prefix)/8 +0.1462 +0.1173 7 7 7 7
rng::is_permutation(vector<int>) (4leg) (common prefix)/1024 +0.0298 +0.0246 583 600 583 597
rng::is_permutation(vector<int>) (4leg) (common prefix)/8192 -0.0308 -0.0206 4738 4592 4684 4588
rng::is_permutation(deque<int>) (4leg) (common prefix)/8 +0.2257 +0.2283 10 13 10 13
rng::is_permutation(deque<int>) (4leg) (common prefix)/1024 -0.0090 -0.0062 825 817 821 816
rng::is_permutation(deque<int>) (4leg) (common prefix)/8192 +0.0046 +0.0050 6465 6495 6454 6486
rng::is_permutation(list<int>) (4leg) (common prefix)/8 +0.0054 +0.0048 7 7 7 7
rng::is_permutation(list<int>) (4leg) (common prefix)/1024 +0.0921 +0.0527 1074 1173 1074 1130
rng::is_permutation(list<int>) (4leg) (common prefix)/8192 -0.0457 -0.0489 13452 12837 13452 12795
std::is_permutation(vector<int>) (4leg, pred) (common prefix)/8 +0.1036 +0.1025 6 7 6 7
std::is_permutation(vector<int>) (4leg, pred) (common prefix)/1024 -0.0533 -0.0534 607 574 607 574
std::is_permutation(vector<int>) (4leg, pred) (common prefix)/8192 -0.0726 -0.0705 4820 4470 4808 4469
std::is_permutation(deque<int>) (4leg, pred) (common prefix)/8 +0.0179 +0.0174 11 12 11 12
std::is_permutation(deque<int>) (4leg, pred) (common prefix)/1024 -0.0014 +0.0016 854 853 851 852
std::is_permutation(deque<int>) (4leg, pred) (common prefix)/8192 +0.0032 +0.0044 6766 6788 6755 6785
std::is_permutation(list<int>) (4leg, pred) (common prefix)/8 -0.0140 -0.0148 8 8 8 8
std::is_permutation(list<int>) (4leg, pred) (common prefix)/1024 +0.0163 +0.0147 1179 1199 1179 1197
std::is_permutation(list<int>) (4leg, pred) (common prefix)/8192 -0.0326 -0.0329 14402 13932 14400 13926
rng::is_permutation(vector<int>) (4leg, pred) (common prefix)/8 +0.1177 +0.1137 6 7 6 7
rng::is_permutation(vector<int>) (4leg, pred) (common prefix)/1024 -0.0608 -0.0626 609 572 609 570
rng::is_permutation(vector<int>) (4leg, pred) (common prefix)/8192 -0.0641 -0.0643 4811 4503 4808 4499
rng::is_permutation(deque<int>) (4leg, pred) (common prefix)/8 +0.0350 +0.0347 11 12 11 12
rng::is_permutation(deque<int>) (4leg, pred) (common prefix)/1024 +0.0221 +0.0180 849 868 849 864
rng::is_permutation(deque<int>) (4leg, pred) (common prefix)/8192 +0.0028 +0.0022 6775 6794 6775 6790
rng::is_permutation(list<int>) (4leg, pred) (common prefix)/8 -0.0094 -0.0094 8 8 8 8
rng::is_permutation(list<int>) (4leg, pred) (common prefix)/1024 -0.0004 -0.0003 1182 1182 1182 1182
rng::is_permutation(list<int>) (4leg, pred) (common prefix)/8192 -0.1109 -0.1109 12824 11402 12823 11401
std::is_permutation(vector<int>) (3leg) (shuffled)/8 +0.1544 +0.1540 49 56 49 56
std::is_permutation(vector<int>) (3leg) (shuffled)/1024 -0.0041 -0.0042 417690 415998 417613 415878
std::is_permutation(deque<int>) (3leg) (shuffled)/8 +0.0312 +0.0311 72 74 72 74
std::is_permutation(deque<int>) (3leg) (shuffled)/1024 -0.0039 -0.0038 976937 973173 976905 973173
std::is_permutation(list<int>) (3leg) (shuffled)/8 +0.0698 +0.0696 60 64 60 64
std::is_permutation(list<int>) (3leg) (shuffled)/1024 +0.0014 +0.0008 2016154 2019032 2016155 2017847
std::is_permutation(vector<int>) (3leg, pred) (shuffled)/8 +0.0055 +0.0066 62 62 61 62
std::is_permutation(vector<int>) (3leg, pred) (shuffled)/1024 -0.0142 -0.0122 1070694 1055456 1068171 1055100
std::is_permutation(deque<int>) (3leg, pred) (shuffled)/8 -0.0045 -0.0024 81 81 81 81
std::is_permutation(deque<int>) (3leg, pred) (shuffled)/1024 -0.0031 -0.0026 1167616 1164036 1166812 1163794
std::is_permutation(list<int>) (3leg, pred) (shuffled)/8 -0.1736 -0.1734 91 75 91 75
std::is_permutation(list<int>) (3leg, pred) (shuffled)/1024 +0.0245 +0.0251 2229788 2284486 2228285 2284297
std::is_permutation(vector<int>) (4leg) (shuffled)/8 +0.1556 +0.1562 49 57 49 57
std::is_permutation(vector<int>) (4leg) (shuffled)/1024 -0.0037 -0.0024 413315 411780 412744 411745
std::is_permutation(deque<int>) (4leg) (shuffled)/8 +0.0179 +0.0185 78 80 78 80
std::is_permutation(deque<int>) (4leg) (shuffled)/1024 +0.0060 +0.0060 975699 981570 975697 981572
std::is_permutation(list<int>) (4leg) (shuffled)/8 +0.0390 +0.0391 60 63 60 63
std::is_permutation(list<int>) (4leg) (shuffled)/1024 -0.0042 -0.0034 2018535 2009991 2016729 2009779
rng::is_permutation(vector<int>) (4leg) (shuffled)/8 +0.1454 +0.1470 49 56 49 56
rng::is_permutation(vector<int>) (4leg) (shuffled)/1024 -0.0226 -0.0223 421068 411541 420894 411504
rng::is_permutation(deque<int>) (4leg) (shuffled)/8 +0.0739 +0.0734 76 81 76 81
rng::is_permutation(deque<int>) (4leg) (shuffled)/1024 -0.0013 -0.0017 991798 990556 990445 988751
rng::is_permutation(list<int>) (4leg) (shuffled)/8 +0.0279 +0.0286 61 63 61 63
rng::is_permutation(list<int>) (4leg) (shuffled)/1024 +0.0008 +0.0011 2013143 2014835 2011920 2014227
std::is_permutation(vector<int>) (4leg, pred) (shuffled)/8 +0.0090 +0.0091 61 61 61 61
std::is_permutation(vector<int>) (4leg, pred) (shuffled)/1024 -0.2018 -0.2012 1058702 845087 1057847 845031
std::is_permutation(deque<int>) (4leg, pred) (shuffled)/8 +0.1386 +0.1383 81 92 81 92
std::is_permutation(deque<int>) (4leg, pred) (shuffled)/1024 +0.0404 +0.0405 1164023 1211074 1163886 1211007
std::is_permutation(list<int>) (4leg, pred) (shuffled)/8 -0.0203 -0.0199 77 75 77 75
std::is_permutation(list<int>) (4leg, pred) (shuffled)/1024 -0.0073 -0.0065 2302394 2285626 2300674 2285627
rng::is_permutation(vector<int>) (4leg, pred) (shuffled)/8 -0.0040 -0.0024 61 61 61 61
rng::is_permutation(vector<int>) (4leg, pred) (shuffled)/1024 -0.1933 -0.1933 1047648 845138 1047652 845093
rng::is_permutation(deque<int>) (4leg, pred) (shuffled)/8 +0.1698 +0.1701 79 92 79 92
rng::is_permutation(deque<int>) (4leg, pred) (shuffled)/1024 +0.0406 +0.0407 1163094 1210313 1162968 1210314
rng::is_permutation(list<int>) (4leg, pred) (shuffled)/8 -0.0023 -0.0031 76 76 76 76
rng::is_permutation(list<int>) (4leg, pred) (shuffled)/1024 +0.0127 +0.0113 2294352 2323538 2292282 2318209
OVERALL_GEOMEAN +0.0188 +0.0180 0 0 0 0
```
</details>
I think that's really interesting. Observations:
1. We're doing much worse with the new implementation on `std::list` and `std::deque`. I don't understand that, that needs investigation.
2. We're not doing better on `std::vector` like we would assume since `std::mismatch` is vectorized. The root cause here seems to be that we don't properly forward the knowledge that the predicate is `std::equal_to` to the call to `std::mismatch`. I think that might be due to the use of `reference_wrapper`, which might inhibit [this check](https://github.com/llvm/llvm-project/blob/ca0fe95a5481ca526375a1b439f6d3cc8600c085/libcxx/include/__algorithm/mismatch.h#L137). If that's the case, we could avoid using `std::ref` when we call `mismatch`, but we should probably fix the underlying issue by making sure that `__desugars_to<__equal_tag, ...>` understands when it gets passed a `reference_wrapper`. That seems like a general thing we should fix if it's broken, and that's actually the target of https://github.com/llvm/llvm-project/issues/129312.
I think those are two good directions for investigating, please let me know if you have questions!
https://github.com/llvm/llvm-project/pull/129565
More information about the libcxx-commits
mailing list