1#include <filesystem>
2
3#include "GenerateInput.h"
4#include "benchmark/benchmark.h"
5#include "test_iterators.h"
6
7namespace fs = std::filesystem;
8
9static const size_t TestNumInputs = 1024;
10
11template <class GenInputs>
12void BM_PathConstructString(benchmark::State& st, GenInputs gen) {
13 using fs::path;
14 const auto in = gen(st.range(0));
15 path PP;
16 for (auto& Part : in)
17 PP /= Part;
18 benchmark::DoNotOptimize(PP.native().data());
19 while (st.KeepRunning()) {
20 const path P(PP.native());
21 benchmark::DoNotOptimize(P.native().data());
22 }
23 st.SetComplexityN(st.range(0));
24}
25BENCHMARK_CAPTURE(BM_PathConstructString, large_string, getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
26
27template <class GenInputs>
28void BM_PathConstructCStr(benchmark::State& st, GenInputs gen) {
29 using fs::path;
30 const auto in = gen(st.range(0));
31 path PP;
32 for (auto& Part : in)
33 PP /= Part;
34 benchmark::DoNotOptimize(PP.native().data());
35 while (st.KeepRunning()) {
36 const path P(PP.native().c_str());
37 benchmark::DoNotOptimize(P.native().data());
38 }
39}
40BENCHMARK_CAPTURE(BM_PathConstructCStr, large_string, getRandomStringInputs)->Arg(TestNumInputs);
41
42template <template <class...> class ItType, class GenInputs>
43void BM_PathConstructIter(benchmark::State& st, GenInputs gen) {
44 using fs::path;
45 using Iter = ItType<std::string::const_iterator>;
46 const auto in = gen(st.range(0));
47 path PP;
48 for (auto& Part : in)
49 PP /= Part;
50 auto Start = Iter(PP.native().begin());
51 auto End = Iter(PP.native().end());
52 benchmark::DoNotOptimize(PP.native().data());
53 benchmark::DoNotOptimize(Start);
54 benchmark::DoNotOptimize(End);
55 while (st.KeepRunning()) {
56 const path P(Start, End);
57 benchmark::DoNotOptimize(P.native().data());
58 }
59 st.SetComplexityN(st.range(0));
60}
61template <class GenInputs>
62void BM_PathConstructInputIter(benchmark::State& st, GenInputs gen) {
63 BM_PathConstructIter<cpp17_input_iterator>(st, gen);
64}
65template <class GenInputs>
66void BM_PathConstructForwardIter(benchmark::State& st, GenInputs gen) {
67 BM_PathConstructIter<forward_iterator>(st, gen);
68}
69BENCHMARK_CAPTURE(BM_PathConstructInputIter, large_string, getRandomStringInputs)
70 ->Range(8, TestNumInputs)
71 ->Complexity();
72BENCHMARK_CAPTURE(BM_PathConstructForwardIter, large_string, getRandomStringInputs)
73 ->Range(8, TestNumInputs)
74 ->Complexity();
75
76template <class GenInputs>
77void BM_PathIterateMultipleTimes(benchmark::State& st, GenInputs gen) {
78 using fs::path;
79 const auto in = gen(st.range(0));
80 path PP;
81 for (auto& Part : in)
82 PP /= Part;
83 benchmark::DoNotOptimize(PP.native().data());
84 while (st.KeepRunning()) {
85 for (auto const& E : PP) {
86 benchmark::DoNotOptimize(E.native().data());
87 }
88 benchmark::ClobberMemory();
89 }
90 st.SetComplexityN(st.range(0));
91}
92BENCHMARK_CAPTURE(BM_PathIterateMultipleTimes, iterate_elements, getRandomStringInputs)
93 ->Range(8, TestNumInputs)
94 ->Complexity();
95
96template <class GenInputs>
97void BM_PathIterateOnce(benchmark::State& st, GenInputs gen) {
98 using fs::path;
99 const auto in = gen(st.range(0));
100 path PP;
101 for (auto& Part : in)
102 PP /= Part;
103 benchmark::DoNotOptimize(PP.native().data());
104 while (st.KeepRunning()) {
105 const path P = PP.native();
106 for (auto const& E : P) {
107 benchmark::DoNotOptimize(E.native().data());
108 }
109 benchmark::ClobberMemory();
110 }
111 st.SetComplexityN(st.range(0));
112}
113BENCHMARK_CAPTURE(BM_PathIterateOnce, iterate_elements, getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
114
115template <class GenInputs>
116void BM_PathIterateOnceBackwards(benchmark::State& st, GenInputs gen) {
117 using fs::path;
118 const auto in = gen(st.range(0));
119 path PP;
120 for (auto& Part : in)
121 PP /= Part;
122 benchmark::DoNotOptimize(PP.native().data());
123 while (st.KeepRunning()) {
124 const path P = PP.native();
125 const auto B = P.begin();
126 auto I = P.end();
127 while (I != B) {
128 --I;
129 benchmark::DoNotOptimize(*I);
130 }
131 benchmark::DoNotOptimize(*I);
132 }
133}
134BENCHMARK_CAPTURE(BM_PathIterateOnceBackwards, iterate_elements, getRandomStringInputs)->Arg(TestNumInputs);
135
136static fs::path getRandomPaths(int NumParts, int PathLen) {
137 fs::path Result;
138 while (NumParts--) {
139 std::string Part = getRandomString(PathLen);
140 Result /= Part;
141 }
142 return Result;
143}
144
145template <class GenInput>
146void BM_LexicallyNormal(benchmark::State& st, GenInput gen, size_t PathLen) {
147 using fs::path;
148 auto In = gen(st.range(0), PathLen);
149 benchmark::DoNotOptimize(&In);
150 while (st.KeepRunning()) {
151 benchmark::DoNotOptimize(In.lexically_normal());
152 }
153 st.SetComplexityN(st.range(0));
154}
155BENCHMARK_CAPTURE(BM_LexicallyNormal, small_path, getRandomPaths, /*PathLen*/ 5)
156 ->RangeMultiplier(2)
157 ->Range(2, 256)
158 ->Complexity();
159BENCHMARK_CAPTURE(BM_LexicallyNormal, large_path, getRandomPaths, /*PathLen*/ 32)
160 ->RangeMultiplier(2)
161 ->Range(2, 256)
162 ->Complexity();
163
164BENCHMARK_MAIN();
165