diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml new file mode 100644 index 0000000..9d5f41a --- /dev/null +++ b/.github/workflows/bench.yml @@ -0,0 +1,90 @@ +name: Bench + +# TODO: Change back to dispatch +on: + [push, pull_request, workflow_dispatch] + +jobs: + bench: + name: Bench ${{matrix.os}} + runs-on: ${{matrix.os}} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: dtolnay/rust-toolchain@stable + + # VERSION/DIAGNOSTICS + + - if: matrix.os == 'ubuntu-latest' + name: Get Linux CPU Info + run: cat /proc/cpuinfo + shell: bash + + - if: matrix.os == 'macos-latest' + name: Get macOS CPU Info + run: sysctl -a | grep cpu + shell: bash + + - if: matrix.os == 'windows-latest' + name: Get Windows CPU Info + run: wmic cpu list /format:list + shell: bash + + - run: cargo --version + - run: cmake --version + + # RUST + + - run: | + cd extras/simple-bench + cargo build --release + name: Build Rust + + - run: | + cd extras/simple-bench + cargo run --release -- file ext/data/canada.txt + cargo run --release -- file ext/data/mesh.txt + cargo run --release -- random uniform + cargo run --release -- random one_over_rand32 + cargo run --release -- random simple_uniform32 + cargo run --release -- random simple_int32 + cargo run --release -- random simple_int64 + cargo run --release -- random int_e_int + cargo run --release -- random int_e_int + cargo run --release -- random bigint_int_dot_int + cargo run --release -- random big_ints + name: Bench Rust + shell: bash + + # C++ + + - run: | + cd extras/simple-bench/ext + cmake -DCMAKE_BUILD_TYPE=Release -B build . + cmake --build build --config Release + name: Build C/C++ + + - run: | + cd extras/simple-bench/ext + if [[ -f build/benchmarks/Release/benchmark.exe ]]; then + exe=build/benchmarks/Release/benchmark.exe + else + exe=build/benchmarks/benchmark + fi + "${exe}" -f data/canada.txt + "${exe}" -f data/mesh.txt + "${exe}" -m uniform + "${exe}" -m one_over_rand32 + "${exe}" -m simple_uniform32 + "${exe}" -m simple_int32 + "${exe}" -m simple_int64 + "${exe}" -m int_e_int + "${exe}" -m bigint_int_dot_int + "${exe}" -m big_ints + name: Bench C/C++ + shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f03cf60..1493009 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: matrix: rust: [1.63.0, stable, nightly] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: recursive - uses: dtolnay/rust-toolchain@master diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0da680d..c769c69 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,7 +8,7 @@ jobs: name: Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: recursive - uses: dtolnay/rust-toolchain@master diff --git a/README.md b/README.md index 4160045..49ea134 100644 --- a/README.md +++ b/README.md @@ -104,25 +104,98 @@ C++ library, here are few brief notes: ## Benchmarks -Below are tables of best timings in nanoseconds for parsing a single number -into a 64-bit float (using the median score). +Below are tables of best timings in nanoseconds for parsing a single number into a 64-bit float (using the median score, lower is better). -### Intel i7-14700K + -| | `canada` | `mesh` | `uniform` | `bi` | `iei` | `rec32` | -| ---------------------- | -------- | -------- | --------- | ----- | ------ | ------- | -| fast-float2 | 9.98 | 5.56 | 10.08 | 56.19 | 14.52 | 15.09 | -| fast-float | 9.77 | 5.04 | 9.05 | 57.52 | 14.40 | 14.23 | -| lexical | 10.62 | 4.93 | 9.92 | 26.40 | 12.43 | 14.40 | -| from_str | 11.59 | 5.92 | 11.23 | 35.92 | 14.75 | 16.76 | +### Intel i7-14700K + +- CPU: Intel i7-14700K 3.40GHz +- OS: Ubuntu 24.04 (WSL2) +- Rust: 1.81 +- C++: GCC 13.2.0 + +| | `canada` | `mesh` | `uniform` | `bi` | `iei` | `rec32` | +| ---------------------- | -------- | -------- | --------- | ------ | ------ | ------- | +| fast-float2 | 9.98 | 5.56 | 10.08 | 56.19 | 14.52 | 15.09 | +| fast-float | 9.77 | 5.04 | 9.05 | 57.52 | 14.40 | 14.23 | +| lexical | 10.62 | 4.93 | 9.92 | 26.40 | 12.43 | 14.40 | +| from_str | 11.59 | 5.92 | 11.23 | 35.92 | 14.75 | 16.76 | | fast_float (C++) | 12.58 | 6.35 | 11.86 | 31.55 | 12.22 | 11.97 | | abseil (C++) | 25.32 | 15.70 | 25.88 | 43.42 | 23.54 | 26.75 | | netlib (C) | 35.10 | 10.22 | 37.72 | 68.63 | 23.07 | 38.23 | | strtod (C) | 52.63 | 26.47 | 46.51 | 88.11 | 33.37 | 53.36 | | doubleconversion (C++) | 32.50 | 14.69 | 47.80 | 70.01 | 205.72 | 45.66 | +### AMD EPYC 7763 64-Core Processor (Linux) + +- CPU: AMD EPYC 7763 64-Core Processor 3.20GHz +- OS: Ubuntu 24.04.1 +- Rust: 1.83 +- C++: GCC 13.2.0 +- Environment: Github Actions (2.321.0) + +| | `canada` | `mesh` | `uniform` | `bi` | `iei` | `rec32` | +| ---------------------- | -------- | -------- | --------- | ------ | ------ | ------- | +| fast-float2 | 19.83 | 10.42 | 18.64 | 80.03 | 26.12 | 27.70 | +| fast-float | 19.17 | 9.89 | 17.34 | 82.37 | 25.26 | 27.22 | +| lexical | 18.89 | 8.41 | 16.83 | 47.66 | 22.08 | 26.99 | +| from_str | 22.90 | 12.72 | 22.10 | 62.20 | 27.51 | 30.80 | +| fast_float (C++) | 20.71 | 10.72 | 24.63 | 82.85 | 24.24 | 19.60 | +| abseil (C++) | 31.03 | 23.78 | 32.82 | 76.05 | 28.41 | 35.03 | +| netlib (C) | 54.22 | 20.12 | 68.68 | 82.64 | 32.81 | 69.43 | +| strtod (C) | 100.10 | 52.08 | 85.32 | 192.31 | 75.08 | 97.85 | +| doubleconversion (C++) | 75.13 | 31.98 | 87.64 | 170.06 | 124.69 | 87.26 | + +### AMD EPYC 7763 64-Core Processor (Windows) + +- CPU: AMD EPYC 7763 64-Core Processor 3.20GHz +- OS: Windows Server 2022 (10.0.20348) +- Rust: 1.83 +- C++: MSVC 19.42.34435.0 +- Environment: Github Actions (2.321.0) + +| | `canada` | `mesh` | `uniform` | `bi` | `iei` | `rec32` | +| ---------------------- | -------- | -------- | --------- | ------ | ------ | ------- | +| fast-float2 | 20.92 | 10.02 | 19.34 | 94.37 | 27.09 | 30.84 | +| fast-float | 19.72 | 9.65 | 18.46 | 86.85 | 25.75 | 30.05 | +| lexical | 19.15 | 8.80 | 17.92 | 51.14 | 22.16 | 28.34 | +| from_str | 25.93 | 13.49 | 23.36 | 78.82 | 27.80 | 35.58 | +| fast_float (C++) | 64.89 | 47.46 | 64.40 | 104.36 | 55.44 | 69.29 | +| abseil (C++) | 37.77 | 33.10 | 41.24 | 136.86 | 37.11 | 47.32 | +| netlib (C) | 53.76 | 28.78 | 60.96 | 76.35 | 44.33 | 62.96 | +| strtod (C) | 181.47 | 85.95 | 192.35 | 262.81 | 125.37 | 204.94 | +| doubleconversion (C++) | 119.02 | 28.78 | 128.16 | 232.35 | 110.97 | 129.63 | + +### Apple M1 (macOS) + +- CPU: AMD EPYC 7763 64-Core Processor 3.20GHz +- OS: macOS (14.7.1) +- Rust: 1.83 +- C++: Clang (Apple) 15.0.0.15000309 +- Environment: Github Actions + +| | `canada` | `mesh` | `uniform` | `bi` | `iei` | `rec32` | +| ---------------------- | -------- | -------- | --------- | ------ | ------ | ------- | +| fast-float2 | 15.47 | 6.54 | 11.62 | 94.35 | 20.55 | 17.78 | +| fast-float | 14.56 | 6.40 | 11.09 | 92.89 | 21.19 | 17.06 | +| lexical | 14.13 | 6.55 | 11.96 | 35.99 | 15.93 | 18.91 | +| from_str | 17.67 | 7.93 | 13.88 | 58.60 | 19.68 | 19.92 | +| fast_float (C++) | 17.42 | 10.40 | 15.14 | 87.33 | 21.82 | 14.53 | +| abseil (C++) | 20.94 | 17.31 | 22.50 | 63.86 | 24.69 | 25.19 | +| netlib (C) | 45.05 | 13.79 | 52.38 | 156.25 | 36.10 | 51.36 | +| strtod (C) | 25.88 | 14.25 | 27.08 | 85.32 | 23.03 | 26.86 | +| doubleconversion (C++) | 53.39 | 21.50 | 73.15 | 120.63 | 52.88 | 70.47 | + Note that the random number generation seems to differ between C/C++ and Rust, since the Rust implementations are slightly faster for pre-determined datasets like `canada` and `mesh`, but equivalent random number generators are slightly slower. Any performance penalty with `fast-float2` occurred due to fixing the UB in [check_len](https://github.com/aldanor/fast-float-rust/issues/28). The massive performance differences between `fast-float` (Rust) and `fast_float` (C++) are expected due to a faster fallback algorithms ([#96](https://github.com/fastfloat/fast_float/pull/96) and [#104](https://github.com/fastfloat/fast_float/pull/104)) used in these cases. #### Parsers