-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
perf: Speedup writing of Parquet primitive values #18020
perf: Speedup writing of Parquet primitive values #18020
Conversation
This improves the performance writing of primitive arrays into Parquet. Running the following program, which is made to really test this function. ```rust use std::io::Seek; use polars::frame::DataFrame; use polars::prelude::NamedFrom; use polars::series::Series; use polars_io::parquet::write::ParquetWriter; use rand::Rng; const NUM_VALUES: usize = 10_000_000; fn main() -> Result<(), Box<dyn std::error::Error>> { let mut rng = rand::thread_rng(); let mut values: Vec<f32> = Vec::with_capacity(NUM_VALUES); unsafe { values.set_len(NUM_VALUES) }; rng.fill(&mut values[..]); let values = &values[..]; let s = Series::new("a", values); let mut f = std::fs::OpenOptions::new() .write(true) .create(true) .open("output.parquet") .unwrap(); for _ in 0..100 { f.seek(std::io::SeekFrom::Start(0))?; let writer = ParquetWriter::new(&mut f) .with_compression(polars::prelude::ParquetCompression::Uncompressed); let mut df = DataFrame::new(vec![s.clone()]).unwrap(); writer.finish(&mut df)?; } Ok(()) } ``` We run around ~1.8 times faster then before: ``` Benchmark 1: ./plparbench-before Time (mean ± σ): 5.718 s ± 0.804 s [User: 4.425 s, System: 1.476 s] Range (min … max): 4.537 s … 6.458 s 5 runs Benchmark 2: ./plparbench-after Time (mean ± σ): 3.194 s ± 0.034 s [User: 1.640 s, System: 1.986 s] Range (min … max): 3.142 s … 3.228 s 5 runs Summary ./plparbench-after ran 1.79 ± 0.25 times faster than ./plparbench-before ``` This also adds specialized implementations for `MinMaxKernel::min_max_{ignore, propagate}_nan` for the Primitive Arrays. This halves the amount of work needed to calculate the column statistics.
25d914d
to
c370891
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #18020 +/- ##
==========================================
- Coverage 80.49% 80.45% -0.05%
==========================================
Files 1496 1496
Lines 196786 197027 +241
Branches 2817 2817
==========================================
+ Hits 158407 158522 +115
- Misses 37858 37984 +126
Partials 521 521 ☔ View full report in Codecov by Sentry. |
let mut offset = 0; | ||
let mut remaining_valid = array.len() - null_count; | ||
while remaining_valid > 0 { | ||
let num_valid = iter.take_leading_ones(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice trick with the take_leading_ones
/take_leading_zeros
alternation. Didn't know we had that. :)
This improves the performance writing of primitive arrays into Parquet.
Running the following program, which is made to really test this function.
We run around ~1.8 times faster then before:
This also adds specialized implementations for
MinMaxKernel::min_max_{ignore, propagate}_nan
for the Primitive Arrays. This halves the amount of work needed to calculate the column statistics.