Skip to content

Improwing speed and reduce code size when fast_float is using as internal parser code. #307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 102 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
b0b1954
* Added a config macro FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE…
IRainman Mar 5, 2025
63f6abe
* Added an option disallow_leading_sign and stronger constexpr / cons…
IRainman Mar 5, 2025
e35e7c7
Merge branch 'main' of https://github.com/IRainman/fast_float
IRainman Mar 6, 2025
2879564
more const
IRainman Mar 6, 2025
9ebac23
Added a config option FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN for…
IRainman Mar 6, 2025
7a38e1b
fix for 32 bit build. completely done. All other parser mode also wor…
IRainman Mar 6, 2025
bc3f331
# cleanup.
IRainman Mar 6, 2025
aba93f3
Additional compile time cleanup. When FASTFLOAT_ONLY_POSITIVE_C_NUMBE…
IRainman Mar 7, 2025
388426e
fix type conversion warning.
IRainman Mar 7, 2025
ae29a0d
PVS-Studio founds some errors, I fixed it.
IRainman Mar 7, 2025
f496321
Completely remove deprecated macroses FASTFLOAT_ALLOWS_LEADING_PLUS a…
IRainman Mar 8, 2025
ac22204
Update README.md
IRainman Mar 8, 2025
c2daa8a
Added FASTFLOAT_ASSUME for support attribute [[assume]] is declared i…
IRainman Mar 9, 2025
23a1367
Merge branch 'main' of https://github.com/IRainman/fast_float
IRainman Mar 9, 2025
5097243
Fix compilation of benchmarks
IRainman Mar 9, 2025
a22dfc6
benchmark are updated, added AST parser emulation for FASTFLOAT_ONLY_…
IRainman Mar 9, 2025
354f4c3
Compilation fix.
IRainman Mar 9, 2025
63eb578
Add FASTFLOAT_HAS_BYTESWAP check.
IRainman Mar 9, 2025
6c499fd
FASTFLOAT_ASSUME review.
IRainman Mar 10, 2025
3e86e9a
####
IRainman Mar 10, 2025
7858023
Tests are updated:
IRainman Mar 10, 2025
474cc15
Merge branch 'main' of https://github.com/IRainman/fast_float
IRainman Mar 10, 2025
681346f
Merge branch 'main' of https://github.com/fastfloat/fast_float into f…
IRainman Mar 12, 2025
cfd0963
Merge branch 'main' into main
IRainman Mar 12, 2025
3dd9a98
more const
IRainman Mar 12, 2025
1899647
GCC compilation fix.
IRainman Mar 12, 2025
e84f289
FASTFLOAT_IF_CONSTEXPR17
IRainman Mar 12, 2025
b869816
Merge branch 'main' of https://github.com/IRainman/fast_float into fa…
IRainman Mar 12, 2025
07ab87c
compilation fix in some cases.
IRainman Mar 12, 2025
3dd3712
lint
IRainman Mar 12, 2025
f3c6052
more constexpr.
IRainman Mar 12, 2025
27c0cd5
lint
IRainman Mar 12, 2025
2db26df
Remove consexpr/consteval from code that probably assumed to run in t…
IRainman Mar 12, 2025
1ab438c
Tests are updated.
IRainman Mar 12, 2025
929e981
lint
IRainman Mar 12, 2025
c08b7b1
tests updated
IRainman Mar 12, 2025
cd5db6f
lint
IRainman Mar 12, 2025
0188112
compilation fix in some old compilers.
IRainman Mar 12, 2025
ffd3590
benchmarks are improved: back to the cycle metering because when USIN…
IRainman Mar 24, 2025
c598a99
fix a warning.
IRainman Mar 24, 2025
9688b3b
improvements in benchmark.
IRainman Mar 24, 2025
1e3a135
reduce register pressure.
IRainman Mar 24, 2025
23395e4
try to compilation fix on Linux
IRainman Mar 24, 2025
a243773
try to compilation fix on Linux
IRainman Mar 24, 2025
d1617ab
Merge branch 'main' of https://github.com/IRainman/fast_float
IRainman Mar 24, 2025
3eaa7d7
compilation fix.
IRainman Mar 24, 2025
0340e8b
build fix.
IRainman Mar 24, 2025
edb51b3
.
IRainman Mar 24, 2025
922eaa1
Merge branch 'fastfloat:main' into main
IRainman Mar 27, 2025
67aeda0
Update README.md
IRainman Mar 27, 2025
82477e9
Update README.md
IRainman Mar 27, 2025
01e9d35
Tests updated and fixed.
IRainman Mar 28, 2025
a2d81d4
Merge branch 'main' of https://github.com/IRainman/fast_float
IRainman Mar 28, 2025
6687e73
Tests are updated.
IRainman Mar 28, 2025
34df2fc
Tests are updated.
IRainman Mar 28, 2025
8ebc89e
Reduce registers pressure.
IRainman Mar 28, 2025
fc9f61e
Cleanup initialization of the adjusted_mantissa.
IRainman Mar 28, 2025
ed87109
Remove FASTFLOAT_CONSTEVAL20 that I was added before and cleanup diff.
IRainman Mar 28, 2025
91e6c4d
.
IRainman Mar 28, 2025
afb54a5
Disable FASTFLOAT_ASSUME by default.
IRainman Mar 28, 2025
6aea2fb
initialization cleanup.
IRainman Mar 28, 2025
ee620a0
reduce registers pressure.
IRainman Mar 28, 2025
1651c2b
Readded FASTFLOAT_CONSTEVAL, but not used currently. Cleanup for FAST…
IRainman Apr 7, 2025
3faba01
Remove PVS.
IRainman Apr 7, 2025
4f0615b
Reduce register pressure and cleanup interface for standard.
IRainman Apr 7, 2025
8212e9e
fix warnings in the benchmark.
IRainman Apr 7, 2025
b261492
reduce register pressure.
IRainman Apr 7, 2025
a133b72
FASTFLOAT_ASSUME
IRainman Apr 8, 2025
b121f53
reduce register pressure.
IRainman Apr 8, 2025
5c61080
improvements of memory layout of parsed_number_string_t.
IRainman Apr 8, 2025
27f0265
style cleanup.
IRainman Apr 8, 2025
97bfec6
style fix.
IRainman Apr 8, 2025
b8f7771
after all sized checks is done I return the minimum registers size po…
IRainman Apr 8, 2025
f1b7f49
after all sized checks is done I return the minimum registers size po…
IRainman Apr 8, 2025
a591ca2
Merge branch 'main' of https://github.com/IRainman/fast_float
IRainman Apr 8, 2025
7c96e3a
reduce size of from_chars_result_t to 4 bytes. Cleanup for usage FAST…
IRainman Apr 9, 2025
a081ebe
reduce size of from_chars_result_t to 4 bytes. Cleanup for usage FAST…
IRainman Apr 9, 2025
8d4ca69
Merge branch 'main' of https://github.com/IRainman/fast_float
IRainman Apr 9, 2025
d32ae04
reduce size of from_chars_result_t to 4 bytes. Cleanup for usage FAST…
IRainman Apr 9, 2025
c762936
template interface cleanup for min_safe_u64 and max_digits_u64.
IRainman Apr 9, 2025
bbf4193
cleanup code generation for parse_mantissa.
IRainman Apr 9, 2025
2da25b5
trying to fix tests.
IRainman Apr 9, 2025
8e1fda5
fixes and cleanup for the parse_number_string function.
IRainman Apr 10, 2025
6cacae0
trying to fix tests.
IRainman Apr 10, 2025
68fe735
fix warnings.
IRainman Apr 10, 2025
f8625b6
fix warnings.
IRainman Apr 10, 2025
a4d1174
Merge branch 'main' of https://github.com/IRainman/fast_float
IRainman Apr 10, 2025
e71bfff
additional improve for debug runtime.
IRainman Apr 11, 2025
88b3887
benchmark cleanup.
IRainman Apr 11, 2025
563648f
* fix errors in the parse_number_string.
IRainman Apr 11, 2025
0daee75
# format
IRainman Apr 11, 2025
1aed8ee
try reordering again.
IRainman Apr 11, 2025
f3db77a
try reordering again.
IRainman Apr 11, 2025
b0bae17
* added chars_format_t for performance reason.
IRainman Apr 11, 2025
69fbbff
try additional part...
IRainman Apr 11, 2025
ba1344c
* carefully work with types in the library.
IRainman Apr 12, 2025
0a18d6b
# format.
IRainman Apr 12, 2025
17ffdff
* additional types cleanup for speedup and reduce cache pressure.
IRainman Apr 12, 2025
c99930b
added additional macro FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED for…
IRainman Apr 29, 2025
7bd3c54
benchmarks are updated.
IRainman Apr 29, 2025
4e230e8
benchmarks are updated.
IRainman Apr 29, 2025
d67876e
Merge branch 'main' of https://github.com/IRainman/fast_float
IRainman Apr 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ Jan Pharago
Maya Warrier
Taha Khokhar
Anders Dalvander
Elle Solomina
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,48 @@ int main() {
}
```

You also can use not standard options:

```C++
#include "fast_float/fast_float.h"
#include <iostream>

int main() {
std::string input = " +456";
double result;
fast_float::parse_options options{chars_format::allow_leading_plus | chars_format::skip_white_space};
auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options);
if ((answer.ec != std::errc()) || ((result != 456))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
return EXIT_SUCCESS;
}
```

For special case scenarious, like mathematical or other AST like parcer that already process minus sign
and only pasre in FastFloat positive numbers in fixed, scientific or hex format and do not have inf or nan
in input you can use macros FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN that significantly reduce
the code size and improve performance:

```C++
#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
#include "fast_float/fast_float.h"
#include <iostream>

int main() {
std::string input = "23.14069263277926900572";
double result;
auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result);
if ((answer.ec != std::errc()) || ((result != 23.14069263277927 /*properly rounded value */)))
{ std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
input = "-23.14069263277926900572";
if (answer.ec == std::errc()) { std::cerr << "parsing failure, should failed on any sign\n"; return EXIT_FAILURE; }
input = "inf";
if (answer.ec == std::errc()) { std::cerr << "parsing failure, should failed on infinity\n"; return EXIT_FAILURE; }
input = "nan";
if (answer.ec == std::errc()) { std::cerr << "parsing failure, should failed on nan in input\n"; return EXIT_FAILURE; }
return EXIT_SUCCESS;
}
```

## Users and Related Work

The fast_float library is part of:
Expand Down
85 changes: 46 additions & 39 deletions benchmarks/benchmark.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@

// #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
// #define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED

#if defined(__linux__) || (__APPLE__ && __aarch64__)
#define USING_COUNTERS
#endif
#include "event_counter.h"
#include <algorithm>
#include "fast_float/fast_float.h"
#include <chrono>
#include <climits>
#include <cmath>
#include <cstdint>
Expand All @@ -19,29 +21,17 @@
#include <sstream>
#include <stdio.h>
#include <string>
#include <vector>
#include <locale.h>

template <typename CharT>
double findmax_fastfloat64(std::vector<std::basic_string<CharT>> &s) {
double answer = 0;
double x = 0;
for (auto &st : s) {
auto [p, ec] = fast_float::from_chars(st.data(), st.data() + st.size(), x);
if (p == st.data()) {
throw std::runtime_error("bug in findmax_fastfloat");
}
answer = answer > x ? answer : x;
}
return answer;
}
#include "fast_float/fast_float.h"

template <typename CharT>
double findmax_fastfloat32(std::vector<std::basic_string<CharT>> &s) {
float answer = 0;
float x = 0;
template <typename CharT, typename Value>
Value findmax_fastfloat(std::vector<std::basic_string<CharT>> &s) {
Value answer = 0;
Value x = 0;
for (auto &st : s) {
auto [p, ec] = fast_float::from_chars(st.data(), st.data() + st.size(), x);

if (p == st.data()) {
throw std::runtime_error("bug in findmax_fastfloat");
}
Expand All @@ -50,9 +40,10 @@ double findmax_fastfloat32(std::vector<std::basic_string<CharT>> &s) {
return answer;
}

#ifdef USING_COUNTERS

event_collector collector{};

#ifdef USING_COUNTERS
template <class T, class CharT>
std::vector<event_count>
time_it_ns(std::vector<std::basic_string<CharT>> &lines, T const &function,
Expand All @@ -61,7 +52,7 @@ time_it_ns(std::vector<std::basic_string<CharT>> &lines, T const &function,
bool printed_bug = false;
for (size_t i = 0; i < repeat; i++) {
collector.start();
double ts = function(lines);
auto const ts = function(lines);
if (ts == 0 && !printed_bug) {
printf("bug\n");
printed_bug = true;
Expand All @@ -71,7 +62,7 @@ time_it_ns(std::vector<std::basic_string<CharT>> &lines, T const &function,
return aggregate;
}

void pretty_print(double volume, size_t number_of_floats, std::string name,
void pretty_print(size_t volume, size_t number_of_floats, std::string name,
std::vector<event_count> events) {
double volumeMB = volume / (1024. * 1024.);
double average_ns{0};
Expand Down Expand Up @@ -141,23 +132,23 @@ time_it_ns(std::vector<std::basic_string<CharT>> &lines, T const &function,
bool printed_bug = false;
for (size_t i = 0; i < repeat; i++) {
t1 = std::chrono::high_resolution_clock::now();
double ts = function(lines);
auto const ts = function(lines);
if (ts == 0 && !printed_bug) {
printf("bug\n");
printed_bug = true;
}
t2 = std::chrono::high_resolution_clock::now();
double dif =
std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count();
double const dif = static_cast<double>(
std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count());
average += dif;
min_value = min_value < dif ? min_value : dif;
}
average /= repeat;
return std::make_pair(min_value, average);
}

void pretty_print(double volume, size_t number_of_floats, std::string name,
std::pair<double, double> result) {
void pretty_print(size_t volume, size_t number_of_floats,
std::string const &name, std::pair<double, double> result) {
double volumeMB = volume / (1024. * 1024.);
printf("%-40s: %8.2f MB/s (+/- %.1f %%) ", name.data(),
volumeMB * 1000000000 / result.first,
Expand All @@ -168,7 +159,7 @@ void pretty_print(double volume, size_t number_of_floats, std::string name,
#endif

// this is okay, all chars are ASCII
inline std::u16string widen(std::string line) {
inline std::u16string widen(std::string const &line) {
std::u16string u16line;
u16line.resize(line.size());
for (size_t i = 0; i < line.size(); ++i) {
Expand All @@ -181,28 +172,29 @@ std::vector<std::u16string> widen(const std::vector<std::string> &lines) {
std::vector<std::u16string> u16lines;
u16lines.reserve(lines.size());
for (auto const &line : lines) {
u16lines.push_back(widen(line));
u16lines.emplace_back(widen(line));
}
return u16lines;
}

void process(std::vector<std::string> &lines, size_t volume) {
size_t repeat = 1000;
size_t const repeat = 1000;
double volumeMB = volume / (1024. * 1024.);
std::cout << "ASCII volume = " << volumeMB << " MB " << std::endl;
pretty_print(volume, lines.size(), "fastfloat (64)",
time_it_ns(lines, findmax_fastfloat64<char>, repeat));
time_it_ns(lines, findmax_fastfloat<char, double>, repeat));
pretty_print(volume, lines.size(), "fastfloat (32)",
time_it_ns(lines, findmax_fastfloat32<char>, repeat));
time_it_ns(lines, findmax_fastfloat<char, float>, repeat));

std::vector<std::u16string> lines16 = widen(lines);
volume = 2 * volume;
volumeMB = volume / (1024. * 1024.);
std::cout << "UTF-16 volume = " << volumeMB << " MB " << std::endl;
pretty_print(volume, lines.size(), "fastfloat (64)",
time_it_ns(lines16, findmax_fastfloat64<char16_t>, repeat));
pretty_print(
volume, lines.size(), "fastfloat (64)",
time_it_ns(lines16, findmax_fastfloat<char16_t, double>, repeat));
pretty_print(volume, lines.size(), "fastfloat (32)",
time_it_ns(lines16, findmax_fastfloat32<char16_t>, repeat));
time_it_ns(lines16, findmax_fastfloat<char16_t, float>, repeat));
}

void fileload(std::string filename) {
Expand All @@ -216,17 +208,30 @@ void fileload(std::string filename) {
std::cout << "#### " << std::endl;
std::string line;
std::vector<std::string> lines;
lines.reserve(10000); // let us reserve plenty of memory.
lines.reserve(120000); // let us reserve plenty of memory.
size_t volume = 0;
while (getline(inputfile, line)) {
volume += line.size();
lines.push_back(line);
#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
if (line[0] == '-') {
line.erase(0, 1);
}
#endif
volume += lines.emplace_back(line).size();
}
std::cout << "# read " << lines.size() << " lines " << std::endl;
process(lines, volume);
}

int main(int argc, char **argv) {
#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
std::cout << "# FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is enabled"
<< std::endl;
#endif
#ifdef FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED
std::cout << "# FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED is enabled"
<< std::endl;
#endif
#ifdef USING_COUNTERS
if (collector.has_events()) {
std::cout << "# Using hardware counters" << std::endl;
} else {
Expand All @@ -236,10 +241,12 @@ int main(int argc, char **argv) {
<< std::endl;
#endif
}
#endif
if (argc > 1) {
fileload(argv[1]);
return EXIT_SUCCESS;
}

fileload(std::string(BENCHMARK_DATA_DIR) + "/canada.txt");
fileload(std::string(BENCHMARK_DATA_DIR) + "/mesh.txt");
return EXIT_SUCCESS;
Expand Down
34 changes: 17 additions & 17 deletions benchmarks/event_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <cstring>

#include <chrono>
#include <vector>
#include <array>

#include "linux-perf-events.h"
#ifdef __linux__
Expand All @@ -22,26 +22,28 @@
#endif

struct event_count {
// The types of counters (so we can read the getter more easily)
enum event_counter_types {
CPU_CYCLES = 0,
INSTRUCTIONS = 1,
BRANCHES = 2,
MISSED_BRANCHES = 3,
event_counter_types_size = 4
};

std::chrono::duration<double> elapsed;
std::vector<unsigned long long> event_counts;
std::array<unsigned long long, event_counter_types_size> event_counts;

event_count() : elapsed(0), event_counts{0, 0, 0, 0, 0} {}
event_count() : elapsed(0), event_counts{0, 0, 0, 0} {}

event_count(const std::chrono::duration<double> _elapsed,
const std::vector<unsigned long long> _event_counts)
event_count(const std::chrono::duration<double> &_elapsed,
const std::array<unsigned long long, event_counter_types_size>
&_event_counts)
: elapsed(_elapsed), event_counts(_event_counts) {}

event_count(const event_count &other)
: elapsed(other.elapsed), event_counts(other.event_counts) {}

// The types of counters (so we can read the getter more easily)
enum event_counter_types {
CPU_CYCLES = 0,
INSTRUCTIONS = 1,
BRANCHES = 2,
MISSED_BRANCHES = 3
};

double elapsed_sec() const {
return std::chrono::duration<double>(elapsed).count();
}
Expand Down Expand Up @@ -79,7 +81,6 @@ struct event_count {
event_counts[1] + other.event_counts[1],
event_counts[2] + other.event_counts[2],
event_counts[3] + other.event_counts[3],
event_counts[4] + other.event_counts[4],
});
}

Expand Down Expand Up @@ -129,7 +130,7 @@ struct event_collector {
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;

event_collector()
: linux_events(std::vector<int>{
: linux_events(std::array<unsigned long long, 4>{
PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_INSTRUCTIONS,
PERF_COUNT_HW_BRANCH_INSTRUCTIONS, // Retired branch instructions
PERF_COUNT_HW_BRANCH_MISSES}) {}
Expand All @@ -142,7 +143,7 @@ struct event_collector {

bool has_events() { return setup_performance_counters(); }
#else
event_collector() {}
event_collector() = default;

bool has_events() { return false; }
#endif
Expand Down Expand Up @@ -171,7 +172,6 @@ struct event_collector {
count.event_counts[1] = diff.instructions;
count.event_counts[2] = diff.branches;
count.event_counts[3] = diff.missed_branches;
count.event_counts[4] = 0;
#endif
count.elapsed = end_clock - start_clock;
return count;
Expand Down
7 changes: 4 additions & 3 deletions benchmarks/linux-perf-events.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <cstring> // for memset
#include <stdexcept>

#include <iostream>
#include <array>
#include <vector>

template <int TYPE = PERF_TYPE_HARDWARE> class LinuxEvents {
Expand All @@ -22,7 +22,8 @@ template <int TYPE = PERF_TYPE_HARDWARE> class LinuxEvents {
std::vector<uint64_t> ids{};

public:
explicit LinuxEvents(std::vector<int> config_vec) : fd(0), working(true) {
explicit LinuxEvents(std::array<unsigned long long, 4> config_vec)
: fd(0), working(true) {
memset(&attribs, 0, sizeof(attribs));
attribs.type = TYPE;
attribs.size = sizeof(attribs);
Expand Down Expand Up @@ -75,7 +76,7 @@ template <int TYPE = PERF_TYPE_HARDWARE> class LinuxEvents {
}
}

inline void end(std::vector<unsigned long long> &results) {
inline void end(std::array<unsigned long long, 4> &results) {
if (fd != -1) {
if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
report_error("ioctl(PERF_EVENT_IOC_DISABLE)");
Expand Down
Loading