diff --git a/README.md b/README.md index 423d300f..d96bf721 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ High-performance numeric conversion routines for use in a `no_std` environment. **Similar Projects** -If you want a minimal, stable, and compile-time friendly version of lexical's float-parsing algorithm, see [minimal-lexical](https://github.com/Alexhuszagh/minimal-lexical). If you want a minimal, performant float parser, recent versions of the Rust standard library should be [sufficient](https://github.com/rust-lang/rust/pull/86761). +If you want a minimal, stable, and compile-time friendly version of lexical's float-parsing algorithm, see [minimal-lexical](https://github.com/Alexhuszagh/minimal-lexical). + +If you want a minimal, performant float parser, recent versions of the Rust standard library should be [sufficient](https://github.com/rust-lang/rust/pull/86761). For high-performance integer formatters, look at [itoa](https://docs.rs/itoa/latest/itoa/). The [metrics](#metrics) section contains a detailed comparison of various crates and their performance in comparison to lexical. **Table of Contents** @@ -263,7 +265,7 @@ Lexical is extensively used in production, the same float parsing algorithm has ## Metrics -Various benchmarks, binary sizes, and compile times are shown here: +Various benchmarks, binary sizes, and compile times are shown here. All the benchmarks can be found on [lexical-benchmarks](https://github.com/Alexhuszagh/lexical-benchmarks?tab=readme-ov-file#latest-results). All benchmarks used a black box to avoid optimizing out the result and leading to misleading metrics. **Build Timings** @@ -278,29 +280,76 @@ The binary sizes of stripped binaries compiled at optimization level "2". For a ![Parse Stripped - Optimization Level "2"](https://raw.githubusercontent.com/Alexhuszagh/rust-lexical/main/assets/size_parse_stripped_opt2_posix.svg) ![Write Stripped - Optimization Level "2"](https://raw.githubusercontent.com/Alexhuszagh/rust-lexical/main/assets/size_write_stripped_opt2_posix.svg) -**Benchmarks -- Parse Integer** +### Benchmarks — Parse Integer + +**Random** + +A benchmark on randomly-generated integers uniformly distributed over the entire range. + +![Uniform Random Data](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/json_random%20-%20parse%20int%20-%20core,lexical.png) + +**Simple** + +A benchmark on randomly-generated integers from 1-1000. + +![Simple Random Data](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/json_simple%20-%20parse%20int%20-%20core,lexical.png) + +### Benchmarks — Parse Float + +**Real-World Datasets** + +A benchmark on parsing floats from various real-world data sets, including Canada, Mesh, and astronomical data (earth). + +![Canada](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/canada%20-%20parse%20float%20-%20core,lexical.png) + +![Earth](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/earth%20-%20parse%20float%20-%20core,lexical.png) + +![Mesh](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/mesh%20-%20parse%20float%20-%20core,lexical.png) + +**Random** + +A benchmark on randomly-generated integers uniformly distributed over the entire range. + +![Random Big Integer](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/random_big_ints%20-%20parse%20float%20-%20core,lexical.png) + +**Simple** + +A benchmark on randomly-generated integers from 1-1000. + +![Random Simple](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/random_simple_int64%20-%20parse%20float%20-%20core,lexical.png) + +### Benchmarks — Write Integer + +**Random** + +A benchmark on randomly-generated integers uniformly distributed over the entire range. + +![Random Uniform](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/json_chain_random%20-%20write%20int%20-%20fmt,itoa,lexical.png) + +**Simple** + +![Random Simple](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/json_simple%20-%20write%20int%20-%20fmt,itoa,lexical.png) -A benchmark on randomly-generated integers uniformly distributed over the entire range. For a more fine-tuned breakdown, see [benchmarks](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-integer/docs/Benchmarks.md). +**Large** -![Uniform Random Data](https://raw.githubusercontent.com/Alexhuszagh/rust-lexical/main/lexical-parse-integer/assets/random_uniform.svg) +![Random Large](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/random_large%20-%20write%20int%20-%20fmt,itoa,lexical.png) -**Benchmarks -- Parse Float** +### Benchmarks — Write Float -A benchmark on parsing floats from various real-world data sets. For a more fine-tuned breakdown, see [benchmarks](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-float/docs/Benchmarks.md). +**Big Integer** -![Real Data](https://raw.githubusercontent.com/Alexhuszagh/rust-lexical/main/lexical-parse-float/assets/real.svg) +A benchmarks for values with a large integers. -**Benchmarks -- Write Integer** +![Big Integers](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/random_big_ints%20-%20write%20float%20-%20dtoa,fmt,lexical,ryu.png) -A benchmark on writing random integers uniformly distributed over the entire range. For a more fine-tuned breakdown, see [benchmarks](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-write-integer/docs/Benchmarks.md). +**Simple 64-Bit Inteers** -![Uniform Random Data](https://raw.githubusercontent.com/Alexhuszagh/rust-lexical/main/lexical-write-integer/assets/random_uniform.svg) +![Simple Int64](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/random_simple_int64%20-%20write%20float%20-%20dtoa,fmt,lexical,ryu.png) -**Benchmarks -- Write Float** -A benchmark on writing floats generated via a random-number generator and parsed from a JSON document. For a more fine-tuned breakdown, see [benchmarks](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-write-float/docs/Benchmarks.md). +**Random** -![Random Data](https://raw.githubusercontent.com/Alexhuszagh/rust-lexical/main/lexical-write-float/assets/json.svg) +![Random](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/da4728e/plot/json%20-%20write%20float%20-%20dtoa,fmt,lexical,ryu.png) ## Safety diff --git a/lexical-benchmark/input.rs b/lexical-benchmark/input.rs index 3bad58db..abf6f331 100644 --- a/lexical-benchmark/input.rs +++ b/lexical-benchmark/input.rs @@ -449,16 +449,11 @@ macro_rules! ryu_generator { macro_rules! itoa_generator { ($group:ident, $name:expr, $iter:expr) => {{ - use lexical_util::constants::BUFFER_SIZE; - let mut buffer = vec![b'0'; BUFFER_SIZE]; + let mut buffer = itoa::Buffer::new(); $group.bench_function($name, |bench| { bench.iter(|| { $iter.for_each(|&x| { - itoa::write(&mut buffer, x).unwrap(); - black_box(&buffer); - unsafe { - buffer.set_len(0); - } + black_box(buffer.format(x)); }) }) }); diff --git a/lexical-benchmark/parse-float/canada.rs b/lexical-benchmark/parse-float/canada.rs index 11d1b13b..643d9107 100644 --- a/lexical-benchmark/parse-float/canada.rs +++ b/lexical-benchmark/parse-float/canada.rs @@ -13,7 +13,8 @@ fn canada(criterion: &mut Criterion) { group.measurement_time(Duration::from_secs(5)); let data = input::read_lines("canada.txt"); - parse_float_generator!(group, "canada", data.iter(), f64); + parse_float_generator!(group, "f32", data.iter(), f32); + parse_float_generator!(group, "f64", data.iter(), f64); } criterion_group!(canada_benches, canada); diff --git a/lexical-benchmark/parse-float/earth.rs b/lexical-benchmark/parse-float/earth.rs index 0e956e9d..f253722d 100644 --- a/lexical-benchmark/parse-float/earth.rs +++ b/lexical-benchmark/parse-float/earth.rs @@ -13,7 +13,8 @@ fn earth(criterion: &mut Criterion) { group.measurement_time(Duration::from_secs(5)); let data = input::read_csv("earth.csv"); - parse_float_generator!(group, "earth", data.iter(), f64); + parse_float_generator!(group, "f32", data.iter(), f32); + parse_float_generator!(group, "f64", data.iter(), f64); } criterion_group!(earth_benches, earth); diff --git a/lexical-benchmark/parse-float/mesh.rs b/lexical-benchmark/parse-float/mesh.rs index b4a7dba5..fed249bb 100644 --- a/lexical-benchmark/parse-float/mesh.rs +++ b/lexical-benchmark/parse-float/mesh.rs @@ -13,7 +13,8 @@ fn mesh(criterion: &mut Criterion) { group.measurement_time(Duration::from_secs(5)); let data = input::read_lines("mesh.txt"); - parse_float_generator!(group, "mesh", data.iter(), f64); + parse_float_generator!(group, "f32", data.iter(), f32); + parse_float_generator!(group, "f64", data.iter(), f64); } criterion_group!(mesh_benches, mesh); diff --git a/lexical-benchmark/write-integer/Cargo.toml b/lexical-benchmark/write-integer/Cargo.toml index a0555bcf..fc03dc6e 100644 --- a/lexical-benchmark/write-integer/Cargo.toml +++ b/lexical-benchmark/write-integer/Cargo.toml @@ -17,7 +17,7 @@ features = [] [dev-dependencies] criterion = { version = "0.5.0", features = ["html_reports"] } -itoa = { version = "0.4", features = ["i128"] } +itoa = { version = "1.0.11" } fastrand = "2.1.0" lazy_static = "1" serde = { version = "1.0", features = ["derive"] }