Skip to content

Commit be60618

Browse files
committed
generalize benchutils functions to any type T
1 parent b3a77a6 commit be60618

File tree

2 files changed

+100
-57
lines changed

2 files changed

+100
-57
lines changed

benchmarks/benchmark.cpp

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,10 @@
5858
#include <charconv>
5959
#endif
6060

61-
void process(std::vector<double> &lines) {
62-
pretty_print(lines, "dragon4", [](const std::vector<double> &lines) {
63-
double volume = 0;
61+
template <typename T>
62+
void process(const std::vector<T> &lines) {
63+
pretty_print(lines, "dragon4", [](const std::vector<T> &lines) -> T {
64+
T volume = 0;
6465
for (const auto d : lines) {
6566
uint64_t dmantissa;
6667
int dexp;
@@ -72,7 +73,7 @@ void process(std::vector<double> &lines) {
7273
}
7374
return volume;
7475
});
75-
76+
7677
#if ERROL_SUPPORTED
7778
pretty_print(lines, "errol3", [](const std::vector<double> &lines) {
7879
double volume = 0;
@@ -86,17 +87,18 @@ void process(std::vector<double> &lines) {
8687
#else
8788
std::cout << "# errol not supported" << std::endl;
8889
#endif // ERROL_SUPPORTED
89-
pretty_print(lines, "std::to_string", [](const std::vector<double> &lines) {
90-
double volume = 0;
90+
91+
pretty_print(lines, "std::to_string", [](const std::vector<T> &lines) -> T {
92+
T volume = 0;
9193
for (const auto d : lines) {
9294
const std::string s = std::to_string(d);
9395
volume += s.size();
9496
}
9597
return volume;
9698
});
9799

98-
pretty_print(lines, "fmt::format", [](const std::vector<double> &lines) {
99-
double volume = 0;
100+
pretty_print(lines, "fmt::format", [](const std::vector<T> &lines) -> T {
101+
T volume = 0;
100102
for (const auto d : lines) {
101103
const std::string s = fmt::format("{}", d);
102104
volume += s.size();
@@ -105,8 +107,8 @@ void process(std::vector<double> &lines) {
105107
});
106108

107109
#if NETLIB_SUPPORTED
108-
pretty_print(lines, "netlib", [](const std::vector<double> &lines) {
109-
double volume = 0;
110+
pretty_print(lines, "netlib", [](const std::vector<T> &lines) -> T {
111+
T volume = 0;
110112
char *result;
111113
int decpt, sign;
112114
char *rve;
@@ -126,17 +128,17 @@ void process(std::vector<double> &lines) {
126128
std::cout << "# netlib not supported" << std::endl;
127129
#endif
128130

129-
pretty_print(lines, "sprintf", [](const std::vector<double> &lines) {
130-
double volume = 0;
131+
pretty_print(lines, "sprintf", [](const std::vector<T> &lines) -> T {
132+
T volume = 0;
131133
char buffer[100];
132134
for (const auto d : lines) {
133135
volume += snprintf(buffer, sizeof(buffer), "%g", d);
134136
}
135137
return volume;
136138
});
137139

138-
pretty_print(lines, "grisu2", [](const std::vector<double> &lines) {
139-
double volume = 0;
140+
pretty_print(lines, "grisu2", [](const std::vector<T> &lines) -> T {
141+
T volume = 0;
140142
char buffer[100];
141143
for (const auto d : lines) {
142144
const char *newp = grisu2::to_chars(buffer, nullptr, d);
@@ -145,8 +147,8 @@ void process(std::vector<double> &lines) {
145147
return volume;
146148
});
147149

148-
pretty_print(lines, "grisu_exact", [](const std::vector<double> &lines) {
149-
double volume = 0;
150+
pretty_print(lines, "grisu_exact", [](const std::vector<T> &lines) -> T {
151+
T volume = 0;
150152
char buffer[100];
151153
for (const auto d : lines) {
152154
auto v = jkj::grisu_exact(d);
@@ -155,18 +157,54 @@ void process(std::vector<double> &lines) {
155157
return volume;
156158
});
157159

158-
pretty_print(lines, "schubfach", [](const std::vector<double> &lines) {
160+
#if FROM_CHARS_DOUBLE_SUPPORTED
161+
pretty_print(lines, "std::to_chars", [](const std::vector<double> &lines) {
159162
double volume = 0;
160163
char buffer[100];
164+
for (const auto d : lines) {
165+
const auto [p, ec] = std::to_chars(buffer, buffer + sizeof(buffer), d);
166+
if(ec != std::errc()) {
167+
std::cerr << "problem with " << d << std::endl;
168+
std::abort();
169+
}
170+
volume += p - buffer;
171+
}
172+
return volume;
173+
});
174+
#else
175+
std::cout << "# std::to_chars not supported" << std::endl;
176+
#endif
177+
178+
#if FROM_CHARS_DOUBLE_SUPPORTED
179+
pretty_print(lines, "std::to_chars", [](const std::vector<T> &lines) -> T {
180+
T volume = 0;
181+
char buffer[100];
182+
for (const auto d : lines) {
183+
const auto [p, ec] = std::to_chars(buffer, buffer + sizeof(buffer), d);
184+
if(ec != std::errc()) {
185+
std::cerr << "problem with " << d << std::endl;
186+
std::abort();
187+
}
188+
volume += p - buffer;
189+
}
190+
return volume;
191+
});
192+
#else
193+
std::cout << "# std::to_chars not supported" << std::endl;
194+
#endif
195+
196+
pretty_print(lines, "schubfach", [](const std::vector<T> &lines) -> T {
197+
T volume = 0;
198+
char buffer[100];
161199
for (const auto d : lines) {
162200
const char *end_ptr = schubfach::Dtoa(buffer, d);
163201
volume += end_ptr - &buffer[0];
164202
}
165203
return volume;
166204
});
167205

168-
pretty_print(lines, "dragonbox", [](const std::vector<double> &lines) {
169-
double volume = 0;
206+
pretty_print(lines, "dragonbox", [](const std::vector<T> &lines) -> T {
207+
T volume = 0;
170208
char buffer[100];
171209
for (const auto d : lines) {
172210
const char *end_ptr = jkj::dragonbox::to_chars(d, buffer);
@@ -175,17 +213,17 @@ void process(std::vector<double> &lines) {
175213
return volume;
176214
});
177215

178-
pretty_print(lines, "ryu", [](const std::vector<double> &lines) {
179-
double volume = 0;
216+
pretty_print(lines, "ryu", [](const std::vector<T> &lines) -> T {
217+
T volume = 0;
180218
char buffer[100];
181219
for (const auto d : lines) {
182220
volume += d2s_buffered_n(d, buffer);
183221
}
184222
return volume;
185223
});
186224

187-
pretty_print(lines, "teju_jagua", [](const std::vector<double> &lines) {
188-
double volume = 0;
225+
pretty_print(lines, "teju_jagua", [](const std::vector<T> &lines) -> T {
226+
T volume = 0;
189227
char buffer[100];
190228
for (const auto d : lines) {
191229
const auto fields = teju::traits_t<double>::teju(d);
@@ -195,8 +233,8 @@ void process(std::vector<double> &lines) {
195233
return volume;
196234
});
197235

198-
pretty_print(lines, "double_conversion", [](const std::vector<double> &lines) {
199-
double volume = 0;
236+
pretty_print(lines, "double_conversion", [](const std::vector<T> &lines) -> T {
237+
T volume = 0;
200238
const double_conversion::DoubleToStringConverter converter(
201239
double_conversion::DoubleToStringConverter::NO_FLAGS, "inf", "nan", 'e',
202240
-4, 6, 0, 0);
@@ -215,8 +253,8 @@ void process(std::vector<double> &lines) {
215253
return volume;
216254
});
217255

218-
pretty_print(lines, "abseil", [](const std::vector<double> &lines) {
219-
double volume = 0;
256+
pretty_print(lines, "abseil", [](const std::vector<T> &lines) -> T {
257+
T volume = 0;
220258
std::string buffer;
221259
for (const auto d : lines) {
222260
buffer.clear();
@@ -296,13 +334,16 @@ int main(int argc, char **argv) {
296334
cxxopts::value<size_t>()->default_value("100000"))(
297335
"m,model", "Random Model.",
298336
cxxopts::value<std::string>()->default_value("uniform"))(
337+
"s,single", "Use single precision instead of double.",
338+
cxxopts::value<bool>()->default_value("false"))(
299339
"h,help", "Print usage.");
300-
auto result = options.parse(argc, argv);
340+
const auto result = options.parse(argc, argv);
301341
if (result["help"].as<bool>()) {
302342
std::cout << options.help() << std::endl;
303343
return EXIT_SUCCESS;
304344
}
305-
auto filename = result["file"].as<std::string>();
345+
const bool single = result["single"].as<bool>();
346+
const auto filename = result["file"].as<std::string>();
306347
if (filename.empty()) {
307348
parse_random_numbers(result["volume"].as<size_t>(),
308349
result["model"].as<std::string>());

benchmarks/benchutil.h

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@
1212
#endif
1313

1414
#ifdef USING_COUNTERS
15-
template <class T>
16-
std::vector<event_count> time_it_ns(std::vector<double> &lines,
17-
T const &function, size_t repeat) {
15+
template <class T, class Func>
16+
std::vector<event_count> time_it_ns(const std::vector<T> &lines,
17+
Func&& function, size_t repeat) {
1818
std::vector<event_count> aggregate;
1919
event_collector collector;
2020
bool printed_bug = false;
2121
for (size_t i = 0; i < repeat; i++) {
2222
collector.start();
23-
double ts = function(lines);
23+
const T ts = function(lines);
2424
if (ts == 0 && !printed_bug) {
2525
printf("bug\n");
2626
printed_bug = true;
@@ -30,13 +30,13 @@ std::vector<event_count> time_it_ns(std::vector<double> &lines,
3030
return aggregate;
3131
}
3232

33-
template <class T>
34-
void pretty_print(std::vector<double> &lines, std::string name,
35-
T const &function, size_t repeat = 100) {
36-
size_t number_of_floats = lines.size();
37-
double volume = function(lines);
38-
std::vector<event_count> events = time_it_ns(lines, function, repeat);
39-
double volumeMB = volume / (1024. * 1024.);
33+
template <class T, class Func>
34+
void pretty_print(const std::vector<T> &lines, const std::string &name,
35+
Func&& function, size_t repeat = 100) {
36+
const size_t number_of_floats = lines.size();
37+
const T volume = function(lines);
38+
const double volumeMB = volume / (1024. * 1024.);
39+
const std::vector<event_count> events = time_it_ns(lines, function, repeat);
4040
double average_ns{0};
4141
double min_ns{DBL_MAX};
4242
double cycles_min{DBL_MAX};
@@ -48,24 +48,24 @@ void pretty_print(std::vector<double> &lines, std::string name,
4848
double branch_misses_min{0};
4949
double branch_misses_avg{0};
5050
for (event_count e : events) {
51-
double ns = e.elapsed_ns();
51+
const double ns = e.elapsed_ns();
5252
average_ns += ns;
5353
min_ns = min_ns < ns ? min_ns : ns;
5454

55-
double cycles = e.cycles();
55+
const double cycles = e.cycles();
5656
cycles_avg += cycles;
5757
cycles_min = cycles_min < cycles ? cycles_min : cycles;
5858

59-
double instructions = e.instructions();
59+
const double instructions = e.instructions();
6060
instructions_avg += instructions;
6161
instructions_min =
6262
instructions_min < instructions ? instructions_min : instructions;
6363

64-
double branches = e.branches();
64+
const double branches = e.branches();
6565
branches_avg += branches;
6666
branches_min = branches_min < branches ? branches_min : branches;
6767

68-
double branch_misses = e.missed_branches();
68+
const double branch_misses = e.missed_branches();
6969
branch_misses_avg += branch_misses;
7070
branch_misses_min =
7171
branch_misses_min < branch_misses ? branch_misses_min : branch_misses;
@@ -74,6 +74,7 @@ void pretty_print(std::vector<double> &lines, std::string name,
7474
instructions_avg /= events.size();
7575
average_ns /= events.size();
7676
branches_avg /= events.size();
77+
7778
printf("%-30s: %8.2f MB/s (+/- %.1f %%) ", name.data(),
7879
volumeMB * 1000000000 / min_ns,
7980
(average_ns - min_ns) * 100.0 / average_ns);
@@ -95,22 +96,22 @@ void pretty_print(std::vector<double> &lines, std::string name,
9596
printf("\n");
9697
}
9798
#else
98-
template <class T>
99-
std::pair<double, double> time_it_ns(std::vector<double> &lines,
100-
T const &function, size_t repeat) {
99+
template <class T, class Func>
100+
std::pair<double, double> time_it_ns(const std::vector<T> &lines,
101+
Func&& function, size_t repeat) {
101102
typename std::chrono::high_resolution_clock::time_point t1, t2;
102103
double average = 0;
103104
double min_value = DBL_MAX;
104105
bool printed_bug = false;
105106
for (size_t i = 0; i < repeat; i++) {
106107
t1 = std::chrono::high_resolution_clock::now();
107-
double ts = function(lines);
108+
const T ts = function(lines);
108109
if (ts == 0 && !printed_bug) {
109110
printf("bug\n");
110111
printed_bug = true;
111112
}
112113
t2 = std::chrono::high_resolution_clock::now();
113-
double dif =
114+
const double dif =
114115
std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count();
115116
average += dif;
116117
min_value = min_value < dif ? min_value : dif;
@@ -119,13 +120,14 @@ std::pair<double, double> time_it_ns(std::vector<double> &lines,
119120
return std::make_pair(min_value, average);
120121
}
121122

122-
template <class T>
123-
void pretty_print(std::vector<double> &lines, std::string name,
124-
T const &function, size_t repeat = 100) {
125-
size_t number_of_floats = lines.size();
126-
double volume = function(lines);
127-
std::pair<double, double> result = time_it_ns(lines, function, repeat);
128-
double volumeMB = volume / (1024. * 1024.);
123+
template <class T, class Func>
124+
void pretty_print(const std::vector<T> &lines, const std::string &name,
125+
Func&& function, size_t repeat = 100) {
126+
const size_t number_of_floats = lines.size();
127+
const T volume = function(lines);
128+
const double volumeMB = volume / (1024. * 1024.);
129+
const std::pair<double, double> result = time_it_ns(lines, function, repeat);
130+
129131
printf("%-30s: %8.2f MB/s (+/- %.1f %%) ", name.data(),
130132
volumeMB * 1000000000 / result.first,
131133
(result.second - result.first) * 100.0 / result.second);

0 commit comments

Comments
 (0)