1 | #include <filesystem> |
2 | |
3 | #include "GenerateInput.h" |
4 | #include "benchmark/benchmark.h" |
5 | #include "test_iterators.h" |
6 | |
7 | namespace fs = std::filesystem; |
8 | |
9 | static const size_t TestNumInputs = 1024; |
10 | |
11 | template <class GenInputs> |
12 | void 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 | } |
25 | BENCHMARK_CAPTURE(BM_PathConstructString, large_string, getRandomStringInputs)->Range(8, TestNumInputs)->Complexity(); |
26 | |
27 | template <class GenInputs> |
28 | void 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 | } |
40 | BENCHMARK_CAPTURE(BM_PathConstructCStr, large_string, getRandomStringInputs)->Arg(TestNumInputs); |
41 | |
42 | template <template <class...> class ItType, class GenInputs> |
43 | void 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 | } |
61 | template <class GenInputs> |
62 | void BM_PathConstructInputIter(benchmark::State& st, GenInputs gen) { |
63 | BM_PathConstructIter<cpp17_input_iterator>(st, gen); |
64 | } |
65 | template <class GenInputs> |
66 | void BM_PathConstructForwardIter(benchmark::State& st, GenInputs gen) { |
67 | BM_PathConstructIter<forward_iterator>(st, gen); |
68 | } |
69 | BENCHMARK_CAPTURE(BM_PathConstructInputIter, large_string, getRandomStringInputs) |
70 | ->Range(8, TestNumInputs) |
71 | ->Complexity(); |
72 | BENCHMARK_CAPTURE(BM_PathConstructForwardIter, large_string, getRandomStringInputs) |
73 | ->Range(8, TestNumInputs) |
74 | ->Complexity(); |
75 | |
76 | template <class GenInputs> |
77 | void 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 | } |
92 | BENCHMARK_CAPTURE(BM_PathIterateMultipleTimes, iterate_elements, getRandomStringInputs) |
93 | ->Range(8, TestNumInputs) |
94 | ->Complexity(); |
95 | |
96 | template <class GenInputs> |
97 | void 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 | } |
113 | BENCHMARK_CAPTURE(BM_PathIterateOnce, iterate_elements, getRandomStringInputs)->Range(8, TestNumInputs)->Complexity(); |
114 | |
115 | template <class GenInputs> |
116 | void 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 | } |
134 | BENCHMARK_CAPTURE(BM_PathIterateOnceBackwards, iterate_elements, getRandomStringInputs)->Arg(TestNumInputs); |
135 | |
136 | static 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 | |
145 | template <class GenInput> |
146 | void 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 | } |
155 | BENCHMARK_CAPTURE(BM_LexicallyNormal, small_path, getRandomPaths, /*PathLen*/ 5) |
156 | ->RangeMultiplier(2) |
157 | ->Range(2, 256) |
158 | ->Complexity(); |
159 | BENCHMARK_CAPTURE(BM_LexicallyNormal, large_path, getRandomPaths, /*PathLen*/ 32) |
160 | ->RangeMultiplier(2) |
161 | ->Range(2, 256) |
162 | ->Complexity(); |
163 | |
164 | BENCHMARK_MAIN(); |
165 | |