[libcxx-commits] [libcxx] [libc++] Avoid string reallocation in `std::filesystem::path::lexically_relative` (PR #152964)
Timothy Choi via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Aug 11 01:21:43 PDT 2025
https://github.com/tinnamchoi updated https://github.com/llvm/llvm-project/pull/152964
>From 38c17f320bcba4d58aa03f7ca4722ee54ac6b701 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Mon, 11 Aug 2025 12:59:06 +0800
Subject: [PATCH 1/5] [libc++] Add benchmarks for
`std::filesystem::path::lexically_relative`
---
libcxx/test/benchmarks/filesystem.bench.cpp | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/libcxx/test/benchmarks/filesystem.bench.cpp b/libcxx/test/benchmarks/filesystem.bench.cpp
index dc6b0ac537f7e..f2e596238a922 100644
--- a/libcxx/test/benchmarks/filesystem.bench.cpp
+++ b/libcxx/test/benchmarks/filesystem.bench.cpp
@@ -171,4 +171,25 @@ BENCHMARK_CAPTURE(BM_LexicallyNormal, large_path, getRandomPaths, /*PathLen*/ 32
->Range(2, 256)
->Complexity();
+template <class GenInput>
+void BM_LexicallyRelative(benchmark::State& st, GenInput gen, size_t PathLen) {
+ using fs::path;
+ auto BasePath = gen(st.range(0), PathLen);
+ auto TargetPath = gen(st.range(0), PathLen);
+ benchmark::DoNotOptimize(&BasePath);
+ benchmark::DoNotOptimize(&TargetPath);
+ while (st.KeepRunning()) {
+ benchmark::DoNotOptimize(TargetPath.lexically_relative(BasePath));
+ }
+ st.SetComplexityN(st.range(0));
+}
+BENCHMARK_CAPTURE(BM_LexicallyRelative, small_path, getRandomPaths, /*PathLen*/ 5)
+ ->RangeMultiplier(2)
+ ->Range(2, 256)
+ ->Complexity();
+BENCHMARK_CAPTURE(BM_LexicallyRelative, large_path, getRandomPaths, /*PathLen*/ 32)
+ ->RangeMultiplier(2)
+ ->Range(2, 256)
+ ->Complexity();
+
BENCHMARK_MAIN();
>From bb563429d91c4255ee7324ee44b66abe1e8b23bd Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Mon, 11 Aug 2025 12:52:31 +0800
Subject: [PATCH 2/5] [libc++] Avoid string reallocation in
`std::filesystem::path::lexically_relative`
```
Benchmark Time CPU Time Old Time New CPU Old CPU New
------------------------------------------------------------------------------------------------------------------------------------------------
BM_LexicallyRelative/small_path/2 -0.2111 -0.2082 229 181 228 180
BM_LexicallyRelative/small_path/4 -0.2579 -0.2550 455 338 452 337
BM_LexicallyRelative/small_path/8 -0.2643 -0.2616 844 621 838 619
BM_LexicallyRelative/small_path/16 -0.2582 -0.2556 1562 1158 1551 1155
BM_LexicallyRelative/small_path/32 -0.2518 -0.2496 3023 2262 3004 2254
BM_LexicallyRelative/small_path/64 -0.2806 -0.2775 6344 4564 6295 4549
BM_LexicallyRelative/small_path/128 -0.2165 -0.2137 11762 9216 11683 9186
BM_LexicallyRelative/small_path/256 -0.2672 -0.2645 24499 17953 24324 17891
BM_LexicallyRelative/large_path/2 -0.3268 -0.3236 426 287 422 285
BM_LexicallyRelative/large_path/4 -0.3274 -0.3248 734 494 729 492
BM_LexicallyRelative/large_path/8 -0.3586 -0.3560 1409 904 1399 901
BM_LexicallyRelative/large_path/16 -0.3978 -0.3951 2764 1665 2743 1659
BM_LexicallyRelative/large_path/32 -0.3934 -0.3908 5323 3229 5283 3218
BM_LexicallyRelative/large_path/64 -0.3629 -0.3605 10340 6587 10265 6564
BM_LexicallyRelative/large_path/128 -0.3450 -0.3423 19379 12694 19233 12649
BM_LexicallyRelative/large_path/256 -0.3097 -0.3054 36293 25052 35943 24965
```
---
libcxx/src/filesystem/path.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/libcxx/src/filesystem/path.cpp b/libcxx/src/filesystem/path.cpp
index 9f7dc54fdf156..624cf785577eb 100644
--- a/libcxx/src/filesystem/path.cpp
+++ b/libcxx/src/filesystem/path.cpp
@@ -292,7 +292,9 @@ path path::lexically_relative(const path& base) const {
// return a path constructed with 'n' dot-dot elements, followed by the
// elements of '*this' after the mismatch.
path Result;
- // FIXME: Reserve enough room in Result that it won't have to re-allocate.
+ constexpr size_t ElemSize = 2; // ".."
+ constexpr size_t SeparatorSize = 1; // separator is always a single char
+ Result.__reserve(ElemCount * (ElemSize + SeparatorSize) + SeparatorSize + PP.Path.size());
while (ElemCount--)
Result /= PATHSTR("..");
for (; PP; ++PP)
>From aeeccdacf116034e87ab32c9ca154e0f7764a1b7 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Mon, 11 Aug 2025 15:47:05 +0800
Subject: [PATCH 3/5] [libc++] Fix style
Forgot to run `clang-format` before.
---
libcxx/src/filesystem/path.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/src/filesystem/path.cpp b/libcxx/src/filesystem/path.cpp
index 624cf785577eb..400b6e8988569 100644
--- a/libcxx/src/filesystem/path.cpp
+++ b/libcxx/src/filesystem/path.cpp
@@ -292,7 +292,7 @@ path path::lexically_relative(const path& base) const {
// return a path constructed with 'n' dot-dot elements, followed by the
// elements of '*this' after the mismatch.
path Result;
- constexpr size_t ElemSize = 2; // ".."
+ constexpr size_t ElemSize = 2; // ".."
constexpr size_t SeparatorSize = 1; // separator is always a single char
Result.__reserve(ElemCount * (ElemSize + SeparatorSize) + SeparatorSize + PP.Path.size());
while (ElemCount--)
>From dfd2f63c5eb0a4b9368afafcd8b4935efbb44fc0 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Mon, 11 Aug 2025 16:10:24 +0800
Subject: [PATCH 4/5] [libc++] Address PR feedback
---
libcxx/test/benchmarks/filesystem.bench.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/libcxx/test/benchmarks/filesystem.bench.cpp b/libcxx/test/benchmarks/filesystem.bench.cpp
index f2e596238a922..9c20bc47b480d 100644
--- a/libcxx/test/benchmarks/filesystem.bench.cpp
+++ b/libcxx/test/benchmarks/filesystem.bench.cpp
@@ -173,12 +173,11 @@ BENCHMARK_CAPTURE(BM_LexicallyNormal, large_path, getRandomPaths, /*PathLen*/ 32
template <class GenInput>
void BM_LexicallyRelative(benchmark::State& st, GenInput gen, size_t PathLen) {
- using fs::path;
auto BasePath = gen(st.range(0), PathLen);
auto TargetPath = gen(st.range(0), PathLen);
benchmark::DoNotOptimize(&BasePath);
benchmark::DoNotOptimize(&TargetPath);
- while (st.KeepRunning()) {
+ for (auto _ : st) {
benchmark::DoNotOptimize(TargetPath.lexically_relative(BasePath));
}
st.SetComplexityN(st.range(0));
>From 8615229124b16554f6ba4ae080d1344ee31bcfe1 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Mon, 11 Aug 2025 16:20:00 +0800
Subject: [PATCH 5/5] [libc++] Fix style again
Should've ran `git clang-format HEAD~2` instead.
---
libcxx/test/benchmarks/filesystem.bench.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/benchmarks/filesystem.bench.cpp b/libcxx/test/benchmarks/filesystem.bench.cpp
index 9c20bc47b480d..c058a5d41a150 100644
--- a/libcxx/test/benchmarks/filesystem.bench.cpp
+++ b/libcxx/test/benchmarks/filesystem.bench.cpp
@@ -173,7 +173,7 @@ BENCHMARK_CAPTURE(BM_LexicallyNormal, large_path, getRandomPaths, /*PathLen*/ 32
template <class GenInput>
void BM_LexicallyRelative(benchmark::State& st, GenInput gen, size_t PathLen) {
- auto BasePath = gen(st.range(0), PathLen);
+ auto BasePath = gen(st.range(0), PathLen);
auto TargetPath = gen(st.range(0), PathLen);
benchmark::DoNotOptimize(&BasePath);
benchmark::DoNotOptimize(&TargetPath);
More information about the libcxx-commits
mailing list