Skip to content

Commit ee97501

Browse files
lemirejaja360
authored andcommitted
the -D flags allow us to derive some interesting statistics
1 parent 61fdd6e commit ee97501

File tree

1 file changed

+107
-1
lines changed

1 file changed

+107
-1
lines changed

benchmarks/benchmark.cpp

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,113 @@ cxxopts::Options
141141
options("benchmark",
142142
"Compute the parsing speed of different number parsers.");
143143

144+
145+
// Checks if a floating-point number is exactly representable as the specified integer type
146+
template <std::integral int_type, std::floating_point float_type>
147+
bool is_exact_integer(float_type x) {
148+
if (!std::isfinite(x)) {
149+
return false;
150+
}
151+
int_type i = static_cast<int_type>(x);
152+
return static_cast<float_type>(i) == x;
153+
}
154+
155+
// Nouvelle version template de describe
156+
template <typename T>
157+
void describe(const std::variant<std::vector<TestCase<float>>, std::vector<TestCase<double>>> &numbers,
158+
const std::vector<BenchArgs<T>> &args,
159+
const std::vector<std::string> &algo_filter) {
160+
std::visit([&args, &algo_filter](const auto &lines) {
161+
size_t integers64 = 0;
162+
size_t integers32 = 0;
163+
for (const auto &d : lines) {
164+
integers64 += is_exact_integer<int64_t>(d.value) ? 1 : 0;
165+
integers32 += is_exact_integer<int32_t>(d.value) ? 1 : 0;
166+
}
167+
std::vector<size_t> sizes(lines.size(), std::numeric_limits<size_t>::max());
168+
std::vector<std::string> shortest(lines.size());
169+
std::vector<std::tuple<std::string, size_t, double, bool>> results;
170+
size_t min_size = std::numeric_limits<size_t>::max();
171+
for (const auto &algo : args) {
172+
if (!algo.used) continue;
173+
if (algo_filtered_out(algo.name, algo_filter)) continue;
174+
size_t total_size = 0;
175+
std::vector<char> buffer(100);
176+
std::span<char> bufspan(buffer);
177+
bool precise = true;
178+
for(size_t i = 0; i < lines.size(); ++i) {
179+
const auto &d = lines[i];
180+
int len = algo.func(d.value, bufspan);
181+
if(sizes[i] > len) {
182+
sizes[i] = len;
183+
shortest[i].assign(bufspan.data(), len);
184+
}
185+
total_size += len;
186+
std::string_view sv(buffer.data(), len);
187+
auto parsed = parse_float<T>(sv);
188+
if (!parsed.has_value() || parsed.value() != d.value) {
189+
precise = false;
190+
break;
191+
}
192+
}
193+
double avg = total_size / double(lines.size());
194+
results.emplace_back(algo.name, total_size, avg, precise);
195+
if (precise && total_size < min_size) min_size = total_size;
196+
}
197+
constexpr size_t warning_max = 1;
198+
for (const auto &algo : args) {
199+
if (!algo.used) continue;
200+
if (algo_filtered_out(algo.name, algo_filter)) continue;
201+
size_t howmany = 0;
202+
std::vector<char> buffer(100);
203+
std::span<char> bufspan(buffer);
204+
size_t worse_than_shortest = 0;
205+
for(size_t i = 0; i < lines.size(); ++i) {
206+
const auto &d = lines[i];
207+
int len = algo.func(d.value, bufspan);
208+
if(sizes[i] < len) {
209+
howmany++;
210+
bool new_record = (len > worse_than_shortest + sizes[i]);
211+
worse_than_shortest = (std::max)(worse_than_shortest, len - sizes[i]);
212+
if(new_record || howmany <= warning_max) {
213+
fmt::print(stderr, "Warning: algorithm {} produced a longer string ({}) than the shortest ({}) for value {}\n",
214+
algo.name, len, sizes[i], d.value);
215+
fmt::print(stderr, " Shortest: '{}'\n", shortest[i]);
216+
std::string_view this_answer(bufspan.data(), len);
217+
fmt::print(stderr, " Produced: '{}'\n", this_answer);
218+
auto parsed_ref = parse_float<T>(shortest[i]);
219+
auto parsed_this = parse_float<T>(this_answer);
220+
if(!parsed_ref.has_value() || !parsed_this.has_value()) {
221+
fmt::print(stderr, " BUG! Parsing failed for one of the strings.\n");
222+
} else if (parsed_ref.value() != parsed_this.value()) {
223+
fmt::print(stderr, " BUG! Parsed values differ: {} vs {}\n",
224+
parsed_ref.value(), parsed_this.value());
225+
}
226+
227+
}
228+
}
229+
}
230+
if(howmany > warning_max) {
231+
fmt::print(stderr, "Warning: algorithm {} produced longer strings than the shortest for {} values, worst gap is {} characters\n",
232+
algo.name, howmany, worse_than_shortest);
233+
}
234+
}
235+
for (const auto &[name, total_size, avg, precise] : results) {
236+
bool is_min = (precise && total_size == min_size);
237+
fmt::print("{:<18} {:>12} ({:>5.3f} chars/f){}{}\n", name, total_size, avg, is_min ? "[minimal]" : "", precise ? "[precise]" : " [imprecise]");
238+
}
239+
fmt::println("count: {}, 32-bit ints: {}, 64-bit ints: {}", lines.size(), integers32, integers64);
240+
}, numbers);
241+
}
242+
144243
int main(int argc, char **argv) {
145244
try {
146245
options.add_options()
147246
("f,file", "File name.",
148247
cxxopts::value<std::string>()->default_value(""))
149248
("F,fixed", "Fixed-point representation.",
150249
cxxopts::value<size_t>()->default_value("0"))
250+
("D,data", "Description of the data.")
151251
("v,volume", "Volume (number of floats generated).",
152252
cxxopts::value<size_t>()->default_value("100000"))
153253
("m,model", "Random Model.",
@@ -205,7 +305,13 @@ int main(int argc, char **argv) {
205305
algorithms = initArgs<float>(errol, repeat, fixed_size);
206306
else
207307
algorithms = initArgs<double>(errol, repeat, fixed_size);
208-
308+
if (result["data"].as<bool>()) {
309+
if (single)
310+
describe<float>(numbers, std::get<std::vector<BenchArgs<float>>>(algorithms), filter);
311+
else
312+
describe<double>(numbers, std::get<std::vector<BenchArgs<double>>>(algorithms), filter);
313+
return EXIT_SUCCESS;
314+
}
209315
const bool test = result["test"].as<bool>();
210316
const bool string_eval = result["string-eval"].as<bool>();
211317
std::visit([test, string_eval, &filter](const auto &lines, const auto &args) {

0 commit comments

Comments
 (0)