You are viewing a plain text version of this content. The canonical link for it is here.
Posted to github@arrow.apache.org by "rluvaton (via GitHub)" <gi...@apache.org> on 2026/10/12 10:31:52 UTC

[PR] perf: optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation in parquet [arrow-rs]

rluvaton opened a new pull request, #11523:
URL: https://github.com/apache/arrow-rs/pull/11523

   # Which issue does this PR close?
   
   None
   
   # Rationale for this change
   
   calculating min and max should be super fast
    
   # What changes are included in this PR?
   implemented custom highly vectorized min_max for `i32`, `u32`, `i64`, `u64`, `f32`, `f64` in parquet writer
   
   # Are these changes tested?
   Yes + existing tests
   
   # Are there any significant user-facing changes?
   No
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf: optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation in parquet [arrow-rs]

Posted by "rluvaton (via GitHub)" <gi...@apache.org>.
rluvaton commented on PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#issuecomment-6124559172

   run benchmark arrow_writer
   env:
     BENCH_FILTER: default
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf(parquet): optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation [arrow-rs]

Posted by "adriangbot (via GitHub)" <gi...@apache.org>.
adriangbot commented on PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#issuecomment-6125117110

   🤖 Benchmark completed (GKE) | [trigger](https://github.com/apache/arrow-rs/pull/11523#issuecomment-6124559172)
   
   **Target:** arrow&#95;writer
   
   Comparing min-max-opt-in-parquet-writer (63baa7e894cda4ea0482635c9763f899dff1d004) to 0706d31 (merge-base) [diff](https://github.com/apache/arrow-rs/compare/0706d317a94098cec4b631031efcdf16f51ed1f5..63baa7e894cda4ea0482635c9763f899dff1d004)
   
   <details><summary>Run configuration</summary>
   
   ```yaml
   run benchmark arrow_writer
   env:
     BENCH_FILTER: default
   shards: 1
   
   ```
   
   </details>
   
   <details><summary>Details</summary>
   
   ```
   group                                              base                                    changed
   -----                                              ----                                    -------
   bool/default                                       1.00      8.9±0.05ms 111.9 MElem/sec    1.00      8.9±0.02ms 112.3 MElem/sec
   bool_dictionary/default                            1.00      9.1±0.06ms 110.0 MElem/sec    1.01      9.1±0.08ms 109.4 MElem/sec
   bool_non_null/default                              1.01      2.3±0.01ms 436.3 MElem/sec    1.00      2.3±0.01ms 442.0 MElem/sec
   bool_ree/default                                   1.00     25.2±0.09ms 39.6 MElem/sec     1.00     25.1±0.09ms 39.8 MElem/sec
   byte_array_sparse_99pct_null/default               1.04      9.0±0.21ms 111.2 MElem/sec    1.00      8.6±0.04ms 116.1 MElem/sec
   decimal/default                                    1.01     83.1±0.62ms 12.0 MElem/sec     1.00     81.9±1.41ms 12.2 MElem/sec
   decimal128_dictionary/default                      1.00     34.5±0.58ms 29.0 MElem/sec     1.00     34.4±0.73ms 29.0 MElem/sec
   decimal128_dictionary_1pct_cardinality/default     1.04     36.4±0.48ms 27.5 MElem/sec     1.00     35.1±0.79ms 28.5 MElem/sec
   decimal128_sparse/default                          1.01     30.5±0.47ms 32.7 MElem/sec     1.00     30.3±0.56ms 33.0 MElem/sec
   fixed_size_binary_non_null/default                 1.00     34.5±0.94ms 29.0 MElem/sec     1.01     34.9±0.74ms 28.6 MElem/sec
   fixed_size_binary_ree/default                      1.02     63.8±1.01ms 15.7 MElem/sec     1.00     62.5±0.53ms 16.0 MElem/sec
   fixed_size_binary_ree_low_cardinality/default      1.03     52.2±0.42ms 19.1 MElem/sec     1.00     50.6±0.67ms 19.7 MElem/sec
   float64_dictionary/default                         1.04     14.5±0.06ms 69.0 MElem/sec     1.00     13.9±0.10ms 72.0 MElem/sec
   float64_dictionary_1pct_cardinality/default        1.13     13.8±0.06ms 72.7 MElem/sec     1.00     12.2±0.04ms 81.9 MElem/sec
   float_with_nans/default                            1.18     73.7±0.28ms 13.6 MElem/sec     1.00     62.5±0.68ms 16.0 MElem/sec
   fsb/default                                        1.02     11.4±0.08ms 87.4 MElem/sec     1.00     11.2±0.10ms 89.5 MElem/sec
   int32_ree/default                                  1.06     35.4±0.15ms 28.3 MElem/sec     1.00     33.4±0.14ms 29.9 MElem/sec
   int32_ree_95pct_null/default                       1.01     21.2±0.03ms 47.2 MElem/sec     1.00     20.9±0.02ms 47.8 MElem/sec
   int64_dictionary/default                           1.03     14.0±0.13ms 71.2 MElem/sec     1.00     13.6±0.05ms 73.6 MElem/sec
   int64_dictionary_1pct_cardinality/default          1.13     13.4±0.07ms 74.9 MElem/sec     1.00     11.9±0.10ms 84.3 MElem/sec
   int64_ree_low_cardinality/default                  1.08     22.4±0.26ms 44.6 MElem/sec     1.00     20.7±0.16ms 48.4 MElem/sec
   large_string_non_null/default                      1.00     52.8±0.12ms 18.9 KElem/sec     1.00     52.6±0.06ms 19.0 KElem/sec
   list_int32_ree/default                             1.12    125.4±0.47ms  8.0 MElem/sec     1.00    111.7±0.33ms  9.0 MElem/sec
   list_int32_ree_short_runs/default                  1.09    136.9±0.90ms  7.3 MElem/sec     1.00    125.1±3.55ms  8.0 MElem/sec
   list_nested/default                                1.02    119.7±0.23ms  8.4 MElem/sec     1.00    117.7±0.17ms  8.5 MElem/sec
   list_of_int32_ree/default                          1.07    124.6±1.33ms  8.0 MElem/sec     1.00    116.3±0.41ms  8.6 MElem/sec
   list_of_int32_ree_alt_empty/default                1.04     80.0±0.36ms 12.5 MElem/sec     1.00     76.7±0.22ms 13.0 MElem/sec
   list_of_int32_ree_alt_null/default                 1.04    115.1±0.28ms  8.7 MElem/sec     1.00    110.6±0.24ms  9.0 MElem/sec
   list_of_list_int32_ree/default                     1.11    152.7±0.46ms  6.5 MElem/sec     1.00    138.0±0.37ms  7.2 MElem/sec
   list_primitive/default                             1.00    191.8±1.58ms  5.2 MElem/sec     1.06    203.8±4.67ms  4.9 MElem/sec
   list_primitive_non_null/default                    1.00    234.8±6.79ms  4.3 MElem/sec     1.09   255.3±12.02ms  3.9 MElem/sec
   list_primitive_sparse_99pct_null/default           1.00     12.5±0.09ms 80.3 MElem/sec     1.00     12.4±0.04ms 80.6 MElem/sec
   list_string_ree/default                            1.12    148.5±0.91ms  6.7 MElem/sec     1.00    132.2±8.06ms  7.6 MElem/sec
   list_struct_with_list/default                      1.02    232.3±0.60ms  4.3 MElem/sec     1.00    227.6±0.43ms  4.4 MElem/sec
   numeric_ree_of_dict/default                        1.06     33.5±0.40ms 29.9 MElem/sec     1.00     31.5±0.16ms 31.7 MElem/sec
   primitive/default                                  1.05    107.1±0.28ms  9.3 MElem/sec     1.00    102.4±0.23ms  9.8 MElem/sec
   primitive_all_null/default                         1.00    273.0±1.89µs  3.6 GElem/sec     1.00    272.6±1.57µs  3.6 GElem/sec
   primitive_dictionary/default                       1.06     18.2±0.19ms 55.0 MElem/sec     1.00     17.2±0.07ms 58.3 MElem/sec
   primitive_dictionary_1pct_cardinality/default      1.13     13.3±0.15ms 75.4 MElem/sec     1.00     11.7±0.04ms 85.4 MElem/sec
   primitive_non_null/default                         1.11     58.9±0.17ms 17.0 MElem/sec     1.00     52.9±0.17ms 18.9 MElem/sec
   primitive_sparse_99pct_null/default                1.05     10.9±0.07ms 91.9 MElem/sec     1.00     10.4±0.03ms 96.2 MElem/sec
   ree_list_ree_list/default                          1.04    303.2±2.45ms  3.3 MElem/sec     1.00    290.5±8.80ms  3.4 MElem/sec
   ree_struct_of_dict/default                         1.06     62.2±0.22ms 16.1 MElem/sec     1.00     58.5±0.21ms 17.1 MElem/sec
   short_string_non_null/default                      1.40     21.3±0.20ms 46.9 MElem/sec     1.00     15.2±0.03ms 65.6 MElem/sec
   string/default                                     1.00    108.0±4.38ms  9.3 MElem/sec     1.08   116.3±16.37ms  8.6 MElem/sec
   string_and_binary_view/default                     1.01     49.3±0.13ms 20.3 MElem/sec     1.00     48.8±0.09ms 20.5 MElem/sec
   string_dictionary/default                          1.00     88.1±1.30ms 11.4 MElem/sec     1.00     87.7±4.72ms 11.4 MElem/sec
   string_dictionary_1pct_cardinality/default         1.04     21.6±0.11ms 46.4 MElem/sec     1.00     20.8±0.08ms 48.2 MElem/sec
   string_dictionary_low_cardinality_100/default      1.04     22.3±0.05ms 44.9 MElem/sec     1.00     21.4±0.05ms 46.8 MElem/sec
   string_dictionary_low_cardinality_20/default       1.04     22.2±0.07ms 45.1 MElem/sec     1.00     21.3±0.07ms 46.9 MElem/sec
   string_dictionary_low_cardinality_400/default      1.02     23.0±0.08ms 43.5 MElem/sec     1.00     22.6±0.07ms 44.3 MElem/sec
   string_non_null/default                            1.03   114.6±12.14ms  8.7 MElem/sec     1.00    111.7±9.59ms  9.0 MElem/sec
   string_ree/default                                 1.00     84.8±1.19ms 11.8 MElem/sec     1.55    131.1±0.46ms  7.6 MElem/sec
   string_ree_95pct_null/default                      1.02     24.7±0.09ms 40.6 MElem/sec     1.00     24.1±0.05ms 41.6 MElem/sec
   string_ree_int64_run_ends/default                  1.18     41.6±0.25ms 24.1 MElem/sec     1.00     35.1±0.12ms 28.5 MElem/sec
   string_ree_low_cardinality/default                 1.19     41.6±0.21ms 24.0 MElem/sec     1.00     35.1±0.13ms 28.5 MElem/sec
   string_ree_of_dict/default                         1.02     43.8±0.13ms 22.8 MElem/sec     1.00     42.9±0.19ms 23.3 MElem/sec
   struct_all_null/default                            1.00    115.4±0.69µs  8.5 GElem/sec     1.02    117.3±0.76µs  8.3 GElem/sec
   struct_non_null/default                            1.13     28.1±0.10ms 35.6 MElem/sec     1.00     24.8±0.08ms 40.3 MElem/sec
   struct_of_list_of_int32_ree_alt_null/default       1.04    117.3±0.39ms  8.5 MElem/sec     1.00    113.3±0.32ms  8.8 MElem/sec
   struct_of_list_of_int32_ree_fragmented/default     1.07    126.2±0.86ms  7.9 MElem/sec     1.00    118.3±0.63ms  8.5 MElem/sec
   struct_of_list_of_int32_ree_single_null/default    1.07    126.1±0.78ms  7.9 MElem/sec     1.00    118.2±0.67ms  8.5 MElem/sec
   struct_ree/default                                 1.17     52.8±0.28ms 19.0 MElem/sec     1.00     45.1±0.32ms 22.2 MElem/sec
   struct_ree_short_runs/default                      1.12     65.9±0.33ms 15.2 MElem/sec     1.00     59.0±0.24ms 16.9 MElem/sec
   struct_sparse_99pct_null/default                   1.02      6.0±0.03ms 167.4 MElem/sec    1.00      5.9±0.04ms 170.8 MElem/sec
   
   ```
   
   </details>
   
   <details><summary>Per-runner information</summary>
   
   <details><summary>arrow&#95;writer — shard 1/1</summary>
   
   **Node:** gk3-benchmark-cluster-nap-1bmn2koy-36f2dfd6-f524
   
   **Instance:** c4a-highmem-16 (12 vCPU / 65 GiB)
   
   **uname:**
   
   ```text
   Linux bench-c6124559172-3337-t76p8 6.12.94+ #1 SMP Fri Aug 21 08:00:16 UTC 2026 aarch64 GNU/Linux
   ```
   
   **BENCH_COMMAND:**
   
   ```sh
   cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_writer
   ```
   
   <details><summary>CPU Details (lscpu)</summary>
   
   ```text
   Architecture:                            aarch64
   CPU op-mode(s):                          64-bit
   Byte Order:                              Little Endian
   CPU(s):                                  16
   On-line CPU(s) list:                     0-15
   Vendor ID:                               ARM
   Model name:                              Neoverse-V2
   Model:                                   1
   Thread(s) per core:                      1
   Core(s) per cluster:                     16
   Socket(s):                               -
   Cluster(s):                              1
   Stepping:                                r0p1
   BogoMIPS:                                2000.00
   Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
   L1d cache:                               1 MiB (16 instances)
   L1i cache:                               1 MiB (16 instances)
   L2 cache:                                32 MiB (16 instances)
   L3 cache:                                80 MiB (1 instance)
   NUMA node(s):                            1
   NUMA node0 CPU(s):                       0-15
   Vulnerability Gather data sampling:      Not affected
   Vulnerability Indirect target selection: Not affected
   Vulnerability Itlb multihit:             Not affected
   Vulnerability L1tf:                      Not affected
   Vulnerability Mds:                       Not affected
   Vulnerability Meltdown:                  Not affected
   Vulnerability Mmio stale data:           Not affected
   Vulnerability Reg file data sampling:    Not affected
   Vulnerability Retbleed:                  Not affected
   Vulnerability Spec rstack overflow:      Not affected
   Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
   Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
   Vulnerability Spectre v2:                Mitigation; CSV2, BHB
   Vulnerability Srbds:                     Not affected
   Vulnerability Tsa:                       Not affected
   Vulnerability Tsx async abort:           Not affected
   Vulnerability Vmscape:                   Not affected
   ```
   
   </details>
   
   <details><summary>Resource Usage</summary>
   
   **base (merge-base)**
   | Metric | Value |
   |--------|-------|
   | Wall time | 875.2s |
   | Peak memory | 1.2 GiB |
   | Avg memory | 382.8 MiB |
   | CPU user | 854.0s |
   | CPU sys | 18.8s |
   | Peak spill | 0 B |
   
   **branch**
   | Metric | Value |
   |--------|-------|
   | Wall time | 860.2s |
   | Peak memory | 891.4 MiB |
   | Avg memory | 269.3 MiB |
   | CPU user | 822.1s |
   | CPU sys | 33.9s |
   | Peak spill | 0 B |
   
   
   </details>
   
   </details>
   
   </details>
   
   ---
   [File an issue](https://github.com/adriangb/datafusion-benchmarking/issues) against this benchmark runner
   
   <!-- benchmark-request:6124559172:finish:25bfaa6fbbe5c71054ede94935812f78 -->


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf: optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation in parquet [arrow-rs]

Posted by "rluvaton (via GitHub)" <gi...@apache.org>.
rluvaton commented on PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#issuecomment-6122480655

   run benchmark arrow_writer
   env:
     BENCH_FILTER: default
   resources:
     arch: amd64


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf: optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation in parquet [arrow-rs]

Posted by "adriangbot (via GitHub)" <gi...@apache.org>.
adriangbot commented on PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#issuecomment-6122487126

   🤖 Benchmark starting (GKE) | [trigger](https://github.com/apache/arrow-rs/pull/11523#issuecomment-6122486041)
   
   **Target:** arrow&#95;writer
   
   **Sharding factor: 1** (1 workers).
   
   Comparing min-max-opt-in-parquet-writer (63baa7e894cda4ea0482635c9763f899dff1d004) to 0706d31 (merge-base) [diff](https://github.com/apache/arrow-rs/compare/0706d317a94098cec4b631031efcdf16f51ed1f5..63baa7e894cda4ea0482635c9763f899dff1d004)
   
   <details><summary>Run configuration</summary>
   
   ```yaml
   run benchmark arrow_writer
   env:
     BENCH_FILTER: default
   shards: 1
   
   ```
   
   </details>
   
   Results will be posted when all workers finish.
   
   ---
   [File an issue](https://github.com/adriangb/datafusion-benchmarking/issues) against this benchmark runner
   
   <!-- benchmark-request:6122486041:start:1ed7caac178f5bf98e9fbcdc800166b9 -->


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf: optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation in parquet [arrow-rs]

Posted by "adriangbot (via GitHub)" <gi...@apache.org>.
adriangbot commented on PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#issuecomment-6123076298

   🤖 Benchmark completed (GKE) | [trigger](https://github.com/apache/arrow-rs/pull/11523#issuecomment-6122480655)
   
   **Target:** arrow&#95;writer
   
   Comparing min-max-opt-in-parquet-writer (63baa7e894cda4ea0482635c9763f899dff1d004) to 0706d31 (merge-base) [diff](https://github.com/apache/arrow-rs/compare/0706d317a94098cec4b631031efcdf16f51ed1f5..63baa7e894cda4ea0482635c9763f899dff1d004)
   
   <details><summary>Run configuration</summary>
   
   ```yaml
   run benchmark arrow_writer
   env:
     BENCH_FILTER: default
   resources:
     arch: amd64
   shards: 1
   
   ```
   
   </details>
   
   <details><summary>Details</summary>
   
   ```
   group                                              base                                    changed
   -----                                              ----                                    -------
   bool/default                                       1.34     10.6±0.20ms 94.6 MElem/sec     1.00      7.9±0.07ms 126.8 MElem/sec
   bool_dictionary/default                            1.43      9.7±0.52ms 102.7 MElem/sec    1.00      6.8±0.07ms 147.4 MElem/sec
   bool_non_null/default                              1.25      2.5±0.03ms 407.6 MElem/sec    1.00  1966.0±44.12µs 508.6 MElem/sec
   bool_ree/default                                   1.24     28.3±0.75ms 35.3 MElem/sec     1.00     22.9±0.31ms 43.6 MElem/sec
   byte_array_sparse_99pct_null/default               1.01      8.2±0.10ms 121.9 MElem/sec    1.00      8.1±0.06ms 122.9 MElem/sec
   decimal/default                                    1.33    119.2±7.47ms  8.4 MElem/sec     1.00     89.6±2.00ms 11.2 MElem/sec
   decimal128_dictionary/default                      1.02     34.3±0.96ms 29.1 MElem/sec     1.00     33.8±0.52ms 29.6 MElem/sec
   decimal128_dictionary_1pct_cardinality/default     1.00     29.2±0.55ms 34.3 MElem/sec     1.01     29.5±0.50ms 34.0 MElem/sec
   decimal128_sparse/default                          1.00     27.2±0.37ms 36.7 MElem/sec     1.00     27.2±0.56ms 36.8 MElem/sec
   fixed_size_binary_non_null/default                 1.00     33.4±0.65ms 29.9 MElem/sec     1.00     33.4±0.42ms 29.9 MElem/sec
   fixed_size_binary_ree/default                      1.32     73.0±3.84ms 13.7 MElem/sec     1.00     55.3±0.80ms 18.1 MElem/sec
   fixed_size_binary_ree_low_cardinality/default      1.19     52.9±2.83ms 18.9 MElem/sec     1.00     44.5±0.48ms 22.5 MElem/sec
   float64_dictionary/default                         1.58     19.4±0.67ms 51.6 MElem/sec     1.00     12.2±0.41ms 81.8 MElem/sec
   float64_dictionary_1pct_cardinality/default        1.55     13.1±0.29ms 76.4 MElem/sec     1.00      8.4±0.29ms 118.4 MElem/sec
   float_with_nans/default                            1.16     63.5±1.24ms 15.8 MElem/sec     1.00     54.7±0.99ms 18.3 MElem/sec
   fsb/default                                        1.02     10.3±0.27ms 97.0 MElem/sec     1.00     10.1±0.08ms 98.9 MElem/sec
   int32_ree/default                                  1.23     35.1±0.94ms 28.5 MElem/sec     1.00     28.5±0.80ms 35.1 MElem/sec
   int32_ree_95pct_null/default                       1.15     23.1±0.71ms 43.3 MElem/sec     1.00     20.0±0.30ms 49.9 MElem/sec
   int64_dictionary/default                           1.54     17.9±0.73ms 56.0 MElem/sec     1.00     11.6±0.12ms 86.2 MElem/sec
   int64_dictionary_1pct_cardinality/default          1.42     10.9±0.68ms 92.2 MElem/sec     1.00      7.6±0.10ms 130.8 MElem/sec
   int64_ree_low_cardinality/default                  1.15     19.0±0.84ms 52.7 MElem/sec     1.00     16.6±0.23ms 60.4 MElem/sec
   large_string_non_null/default                      1.27     57.1±0.50ms 17.5 KElem/sec     1.00     44.8±0.93ms 22.3 KElem/sec
   list_int32_ree/default                             1.13     98.1±4.29ms 10.2 MElem/sec     1.00     86.4±2.14ms 11.6 MElem/sec
   list_int32_ree_short_runs/default                  1.19    110.5±5.21ms  9.0 MElem/sec     1.00     92.8±2.34ms 10.8 MElem/sec
   list_nested/default                                1.02    133.8±1.65ms  7.5 MElem/sec     1.00    131.1±0.87ms  7.6 MElem/sec
   list_of_int32_ree/default                          1.03    101.3±2.98ms  9.9 MElem/sec     1.00     98.2±1.05ms 10.2 MElem/sec
   list_of_int32_ree_alt_empty/default                1.00     66.2±1.31ms 15.1 MElem/sec     1.00     66.4±0.94ms 15.1 MElem/sec
   list_of_int32_ree_alt_null/default                 1.00    102.5±2.23ms  9.8 MElem/sec     1.00    102.6±2.67ms  9.8 MElem/sec
   list_of_list_int32_ree/default                     1.14    130.4±5.08ms  7.7 MElem/sec     1.00    114.0±1.29ms  8.8 MElem/sec
   list_primitive/default                             1.00    248.2±3.21ms  4.0 MElem/sec     1.00    247.8±2.89ms  4.0 MElem/sec
   list_primitive_non_null/default                    1.00   323.6±14.71ms  3.1 MElem/sec     1.01   327.2±16.49ms  3.1 MElem/sec
   list_primitive_sparse_99pct_null/default           1.00     11.2±0.21ms 89.3 MElem/sec     1.00     11.2±0.19ms 89.2 MElem/sec
   list_string_ree/default                            1.05    112.6±6.23ms  8.9 MElem/sec     1.00    107.0±8.59ms  9.3 MElem/sec
   list_struct_with_list/default                      1.01    252.2±3.73ms  4.0 MElem/sec     1.00    248.5±3.02ms  4.0 MElem/sec
   numeric_ree_of_dict/default                        1.23     30.7±0.48ms 32.6 MElem/sec     1.00     25.0±0.30ms 40.0 MElem/sec
   primitive/default                                  1.47    125.0±2.32ms  8.0 MElem/sec     1.00     85.1±2.17ms 11.8 MElem/sec
   primitive_all_null/default                         1.00    232.5±6.96µs  4.2 GElem/sec     1.01    234.8±5.80µs  4.2 GElem/sec
   primitive_dictionary/default                       1.53     21.7±0.54ms 46.0 MElem/sec     1.00     14.2±0.15ms 70.2 MElem/sec
   primitive_dictionary_1pct_cardinality/default      1.45     10.9±0.53ms 91.7 MElem/sec     1.00      7.5±0.23ms 132.7 MElem/sec
   primitive_non_null/default                         1.78     74.0±3.71ms 13.5 MElem/sec     1.00     41.6±0.38ms 24.1 MElem/sec
   primitive_sparse_99pct_null/default                1.00      9.6±0.14ms 104.7 MElem/sec    1.00      9.6±0.14ms 104.4 MElem/sec
   ree_list_ree_list/default                          1.10   249.8±13.79ms  4.0 MElem/sec     1.00    227.0±3.31ms  4.4 MElem/sec
   ree_struct_of_dict/default                         1.22     53.8±1.44ms 18.6 MElem/sec     1.00     44.1±1.14ms 22.7 MElem/sec
   short_string_non_null/default                      1.53     16.9±0.35ms 59.0 MElem/sec     1.00     11.1±0.15ms 90.4 MElem/sec
   string/default                                     1.26   198.4±25.18ms  5.0 MElem/sec     1.00    157.0±5.65ms  6.4 MElem/sec
   string_and_binary_view/default                     1.52     57.4±0.98ms 17.4 MElem/sec     1.00     37.9±0.45ms 26.4 MElem/sec
   string_dictionary/default                          1.32     77.2±1.02ms 13.0 MElem/sec     1.00     58.2±0.66ms 17.2 MElem/sec
   string_dictionary_1pct_cardinality/default         1.26     17.3±0.28ms 57.8 MElem/sec     1.00     13.7±0.42ms 72.9 MElem/sec
   string_dictionary_low_cardinality_100/default      1.27     18.8±0.53ms 53.1 MElem/sec     1.00     14.8±0.16ms 67.7 MElem/sec
   string_dictionary_low_cardinality_20/default       1.30     19.0±0.77ms 52.5 MElem/sec     1.00     14.6±0.19ms 68.5 MElem/sec
   string_dictionary_low_cardinality_400/default      1.25     19.1±0.39ms 52.4 MElem/sec     1.00     15.3±0.25ms 65.5 MElem/sec
   string_non_null/default                            1.05   199.7±14.38ms  5.0 MElem/sec     1.00   190.0±16.97ms  5.3 MElem/sec
   string_ree/default                                 1.17    176.6±3.60ms  5.7 MElem/sec     1.00    151.1±1.81ms  6.6 MElem/sec
   string_ree_95pct_null/default                      1.16     25.9±1.67ms 38.5 MElem/sec     1.00     22.5±0.22ms 44.5 MElem/sec
   string_ree_int64_run_ends/default                  1.17     33.4±1.30ms 30.0 MElem/sec     1.00     28.5±0.33ms 35.1 MElem/sec
   string_ree_low_cardinality/default                 1.14     31.4±1.41ms 31.8 MElem/sec     1.00     27.5±0.99ms 36.4 MElem/sec
   string_ree_of_dict/default                         1.23     39.8±0.85ms 25.1 MElem/sec     1.00     32.3±0.28ms 30.9 MElem/sec
   struct_all_null/default                            1.00     97.1±2.84µs 10.1 GElem/sec     1.03     99.6±2.57µs  9.8 GElem/sec
   struct_non_null/default                            1.11     21.9±0.49ms 45.7 MElem/sec     1.00     19.8±0.18ms 50.5 MElem/sec
   struct_of_list_of_int32_ree_alt_null/default       1.01    105.0±2.84ms  9.5 MElem/sec     1.00    104.3±2.40ms  9.6 MElem/sec
   struct_of_list_of_int32_ree_fragmented/default     1.02    102.4±2.29ms  9.8 MElem/sec     1.00    100.8±2.11ms  9.9 MElem/sec
   struct_of_list_of_int32_ree_single_null/default    1.01    102.4±1.76ms  9.8 MElem/sec     1.00    101.4±1.32ms  9.9 MElem/sec
   struct_ree/default                                 1.19     42.1±2.17ms 23.8 MElem/sec     1.00     35.3±0.99ms 28.3 MElem/sec
   struct_ree_short_runs/default                      1.16     53.2±2.55ms 18.8 MElem/sec     1.00     45.8±0.46ms 21.9 MElem/sec
   struct_sparse_99pct_null/default                   1.00      6.0±0.03ms 165.5 MElem/sec    1.01      6.1±0.06ms 163.3 MElem/sec
   
   ```
   
   </details>
   
   <details><summary>Per-runner information</summary>
   
   <details><summary>arrow&#95;writer — shard 1/1</summary>
   
   **Node:** gk3-benchmark-cluster-nap-15raeun1-f8dd49b5-bskm
   
   **Instance:** c4-standard-24 (12 vCPU / 65 GiB)
   
   **uname:**
   
   ```text
   Linux bench-c6122480655-3331-p9mxc 6.12.94+ #1 SMP Fri Aug 21 07:56:42 UTC 2026 x86_64 GNU/Linux
   ```
   
   **BENCH_COMMAND:**
   
   ```sh
   cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_writer
   ```
   
   <details><summary>CPU Details (lscpu)</summary>
   
   ```text
   Architecture:                            x86_64
   CPU op-mode(s):                          32-bit, 64-bit
   Address sizes:                           52 bits physical, 57 bits virtual
   Byte Order:                              Little Endian
   CPU(s):                                  24
   On-line CPU(s) list:                     0-23
   Vendor ID:                               GenuineIntel
   Model name:                              INTEL(R) XEON(R) PLATINUM 8581C CPU @ 2.30GHz
   CPU family:                              6
   Model:                                   207
   Thread(s) per core:                      2
   Core(s) per socket:                      12
   Socket(s):                               1
   Stepping:                                2
   BogoMIPS:                                4600.00
   Flags:                                   fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq monitor ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves avx_vnni avx512_bf16 wbnoinvd arat avx512vbmi umip avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid cldemote movdiri movdir64b fsrm md_clear serialize tsxldtrk amx_bf16 avx512_fp16 amx_tile amx_int8 arch_capabilities
   Hypervisor vendor:                       KVM
   Virtualization type:                     full
   L1d cache:                               576 KiB (12 instances)
   L1i cache:                               384 KiB (12 instances)
   L2 cache:                                24 MiB (12 instances)
   L3 cache:                                260 MiB (1 instance)
   NUMA node(s):                            1
   NUMA node0 CPU(s):                       0-23
   Vulnerability Gather data sampling:      Not affected
   Vulnerability Indirect target selection: Not affected
   Vulnerability Itlb multihit:             Not affected
   Vulnerability L1tf:                      Not affected
   Vulnerability Mds:                       Not affected
   Vulnerability Meltdown:                  Not affected
   Vulnerability Mmio stale data:           Not affected
   Vulnerability Reg file data sampling:    Not affected
   Vulnerability Retbleed:                  Not affected
   Vulnerability Spec rstack overflow:      Not affected
   Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
   Vulnerability Spectre v1:                Mitigation; usercopy/swapgs barriers and __user pointer sanitization
   Vulnerability Spectre v2:                Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S
   Vulnerability Srbds:                     Not affected
   Vulnerability Tsa:                       Not affected
   Vulnerability Tsx async abort:           Not affected
   Vulnerability Vmscape:                   Not affected
   ```
   
   </details>
   
   <details><summary>Resource Usage</summary>
   
   **base (merge-base)**
   | Metric | Value |
   |--------|-------|
   | Wall time | 875.2s |
   | Peak memory | 909.0 MiB |
   | Avg memory | 354.2 MiB |
   | CPU user | 840.7s |
   | CPU sys | 30.0s |
   | Peak spill | 0 B |
   
   **branch**
   | Metric | Value |
   |--------|-------|
   | Wall time | 865.2s |
   | Peak memory | 2.0 GiB |
   | Avg memory | 328.6 MiB |
   | CPU user | 831.9s |
   | CPU sys | 30.1s |
   | Peak spill | 0 B |
   
   
   </details>
   
   </details>
   
   </details>
   
   ---
   [File an issue](https://github.com/adriangb/datafusion-benchmarking/issues) against this benchmark runner
   
   <!-- benchmark-request:6122480655:finish:1c4183b967f48347f389bbf3a60ca583 -->


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf(parquet): optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation [arrow-rs]

Posted by "rluvaton (via GitHub)" <gi...@apache.org>.
rluvaton commented on code in PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#discussion_r4303317024


##########
parquet/src/column/writer/min_max.rs:
##########
@@ -0,0 +1,389 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::basic::SortOrder;
+use crate::column::writer::{compare_greater, is_nan};
+use crate::data_type::private::ParquetValueType;
+use crate::schema::types::BasicTypeInfo;
+
+/// Accumulators for 64 bytes of values, i.e. a cache line and one AVX-512
+/// register, or four NEON / two AVX2 registers.
+const LANES_32: usize = 16;
+const LANES_64: usize = 8;
+
+/// Returns the minimum and maximum of `values` after mapping them with `key`,
+/// or `None` if `values` is empty.
+#[inline(always)]
+fn min_max_by_key<T: Copy, K: Copy + Ord, const LANES: usize>(
+    values: &[T],
+    key: impl Fn(T) -> K,
+    key_min: K,
+    key_max: K,
+) -> Option<(K, K)> {
+    if values.is_empty() {
+        return None;
+    }
+
+    let mut mins = [key_max; LANES];
+    let mut maxs = [key_min; LANES];
+
+    let (chunks, remainder) = values.as_chunks::<LANES>();
+    for chunk in chunks {
+        for i in 0..LANES {
+            let k = key(chunk[i]);
+            mins[i] = mins[i].min(k);
+            maxs[i] = maxs[i].max(k);
+        }
+    }
+    for (i, v) in remainder.iter().enumerate() {
+        let k = key(*v);
+        mins[i] = mins[i].min(k);
+        maxs[i] = maxs[i].max(k);
+    }
+
+    let min = mins.into_iter().min().unwrap();
+    let max = maxs.into_iter().max().unwrap();
+    Some((min, max))
+}
+
+#[inline]
+fn is_unsigned(basic_type_info: &BasicTypeInfo) -> bool {
+    matches!(basic_type_info.sort_order(), SortOrder::UNSIGNED)
+}
+
+/// Returns the min and max of an `INT32` column, or `None` if `values` is empty.
+pub(crate) fn min_max_i32(basic_type_info: &BasicTypeInfo, values: &[i32]) -> Option<(i32, i32)> {
+    if is_unsigned(basic_type_info) {
+        min_max_by_key::<_, _, LANES_32>(values, |v| v as u32, u32::MIN, u32::MAX)
+            .map(|(min, max)| (min as i32, max as i32))
+    } else {
+        min_max_by_key::<_, _, LANES_32>(values, |v| v, i32::MIN, i32::MAX)
+    }
+}
+
+/// Returns the min and max of an `INT64` column, or `None` if `values` is empty.
+pub(crate) fn min_max_i64(basic_type_info: &BasicTypeInfo, values: &[i64]) -> Option<(i64, i64)> {
+    if is_unsigned(basic_type_info) {
+        min_max_by_key::<_, _, LANES_64>(values, |v| v as u64, u64::MIN, u64::MAX)
+            .map(|(min, max)| (min as i64, max as i64))
+    } else {
+        min_max_by_key::<_, _, LANES_64>(values, |v| v, i64::MIN, i64::MAX)
+    }
+}
+
+macro_rules! float_min_max {
+    ($name:ident, $float:ty, $int:ty, $uint:ty, $lanes:expr) => {
+        /// Returns the min, max and NaN count of a floating point column,
+        /// comparing by IEEE 754 total order and skipping NaN.
+        ///
+        /// Returns `None` if `values` is empty or contains only NaN, in which
+        /// case the min and max are NaN themselves and the caller falls back
+        /// to the scalar implementation.
+        pub(crate) fn $name(values: &[$float]) -> Option<($float, $float, u64)> {
+            const SIGN_SHIFT: u32 = <$int>::BITS - 1;
+
+            // Maps the bits of a float to an integer with the same ordering as
+            // `total_cmp`: negative values have their magnitude bits flipped
+            // so that they order in reverse. The mapping is its own inverse.
+            //
+            // To avoid calling `{f32,f64}::total_cmp` for both min and max values and every other comparison
+            // we transform the input once (like what rust is doing internally before comparing) and reuse it, this avoids the overhead of calling `total_cmp` twice for each value.
+            // and doing the same calculation.
+            //
+            // This is the same transformation used in Rust `f32::total_cmp` and `f64::total_cmp`
+            // but we avoid calling
+            // f32: https://github.com/rust-lang/rust/blob/b5427502dab50cb27d9327d2893ddf2337dd4388/library/core/src/num/f32.rs#L1626
+            // f64: https://github.com/rust-lang/rust/blob/b5427502dab50cb27d9327d2893ddf2337dd4388/library/core/src/num/f64.rs#L1604
+            #[inline(always)]
+            fn total_order_key(bits: $int) -> $int {

Review Comment:
   I can't take the credit for it, this was Claude



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf: optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation in parquet [arrow-rs]

Posted by "adriangbot (via GitHub)" <gi...@apache.org>.
adriangbot commented on PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#issuecomment-6124560502

   🤖 Benchmark starting (GKE) | [trigger](https://github.com/apache/arrow-rs/pull/11523#issuecomment-6124559172)
   
   **Target:** arrow&#95;writer
   
   **Sharding factor: 1** (1 workers).
   
   Comparing min-max-opt-in-parquet-writer (63baa7e894cda4ea0482635c9763f899dff1d004) to 0706d31 (merge-base) [diff](https://github.com/apache/arrow-rs/compare/0706d317a94098cec4b631031efcdf16f51ed1f5..63baa7e894cda4ea0482635c9763f899dff1d004)
   
   <details><summary>Run configuration</summary>
   
   ```yaml
   run benchmark arrow_writer
   env:
     BENCH_FILTER: default
   shards: 1
   
   ```
   
   </details>
   
   Results will be posted when all workers finish.
   
   ---
   [File an issue](https://github.com/adriangb/datafusion-benchmarking/issues) against this benchmark runner
   
   <!-- benchmark-request:6124559172:start:1739d23321404ba7bde7fc654c9c4fec -->


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf: optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation in parquet [arrow-rs]

Posted by "adriangbot (via GitHub)" <gi...@apache.org>.
adriangbot commented on PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#issuecomment-6122481646

   🤖 Benchmark starting (GKE) | [trigger](https://github.com/apache/arrow-rs/pull/11523#issuecomment-6122480655)
   
   **Target:** arrow&#95;writer
   
   **Sharding factor: 1** (1 workers).
   
   Comparing min-max-opt-in-parquet-writer (63baa7e894cda4ea0482635c9763f899dff1d004) to 0706d31 (merge-base) [diff](https://github.com/apache/arrow-rs/compare/0706d317a94098cec4b631031efcdf16f51ed1f5..63baa7e894cda4ea0482635c9763f899dff1d004)
   
   <details><summary>Run configuration</summary>
   
   ```yaml
   run benchmark arrow_writer
   env:
     BENCH_FILTER: default
   resources:
     arch: amd64
   shards: 1
   
   ```
   
   </details>
   
   Results will be posted when all workers finish.
   
   ---
   [File an issue](https://github.com/adriangb/datafusion-benchmarking/issues) against this benchmark runner
   
   <!-- benchmark-request:6122480655:start:fa524b4f0c1990d40a1b64adc545c803 -->


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf: optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation in parquet [arrow-rs]

Posted by "adriangbot (via GitHub)" <gi...@apache.org>.
adriangbot commented on PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#issuecomment-6123036381

   🤖 Benchmark completed (GKE) | [trigger](https://github.com/apache/arrow-rs/pull/11523#issuecomment-6122486041)
   
   **Target:** arrow&#95;writer
   
   Comparing min-max-opt-in-parquet-writer (63baa7e894cda4ea0482635c9763f899dff1d004) to 0706d31 (merge-base) [diff](https://github.com/apache/arrow-rs/compare/0706d317a94098cec4b631031efcdf16f51ed1f5..63baa7e894cda4ea0482635c9763f899dff1d004)
   
   <details><summary>Run configuration</summary>
   
   ```yaml
   run benchmark arrow_writer
   env:
     BENCH_FILTER: default
   shards: 1
   
   ```
   
   </details>
   
   <details><summary>Details</summary>
   
   ```
   group                                              base                                    changed
   -----                                              ----                                    -------
   bool/default                                       1.03      9.1±0.04ms 109.8 MElem/sec    1.00      8.9±0.02ms 112.8 MElem/sec
   bool_dictionary/default                            1.03      9.3±0.07ms 107.0 MElem/sec    1.00      9.0±0.07ms 110.6 MElem/sec
   bool_non_null/default                              1.01      2.3±0.01ms 438.1 MElem/sec    1.00      2.3±0.01ms 442.7 MElem/sec
   bool_ree/default                                   1.01     25.5±0.10ms 39.3 MElem/sec     1.00     25.1±0.09ms 39.9 MElem/sec
   byte_array_sparse_99pct_null/default               1.03      9.0±0.07ms 111.2 MElem/sec    1.00      8.7±0.11ms 114.4 MElem/sec
   decimal/default                                    1.00     82.1±1.15ms 12.2 MElem/sec     1.47    121.0±0.94ms  8.3 MElem/sec
   decimal128_dictionary/default                      1.00     34.0±0.63ms 29.4 MElem/sec     1.01     34.3±0.43ms 29.2 MElem/sec
   decimal128_dictionary_1pct_cardinality/default     1.02     35.7±0.63ms 28.0 MElem/sec     1.00     35.0±0.41ms 28.6 MElem/sec
   decimal128_sparse/default                          1.00     29.7±0.31ms 33.7 MElem/sec     1.02     30.2±0.29ms 33.1 MElem/sec
   fixed_size_binary_non_null/default                 1.00     33.8±0.63ms 29.5 MElem/sec     1.30     43.8±0.61ms 22.8 MElem/sec
   fixed_size_binary_ree/default                      1.00     64.4±0.40ms 15.5 MElem/sec     1.21     78.2±0.54ms 12.8 MElem/sec
   fixed_size_binary_ree_low_cardinality/default      1.00     52.4±0.40ms 19.1 MElem/sec     1.13     59.4±0.34ms 16.8 MElem/sec
   float64_dictionary/default                         1.04     14.5±0.10ms 68.9 MElem/sec     1.00     13.9±0.14ms 71.9 MElem/sec
   float64_dictionary_1pct_cardinality/default        1.15     13.9±0.09ms 71.9 MElem/sec     1.00     12.1±0.07ms 82.6 MElem/sec
   float_with_nans/default                            1.18     73.3±0.38ms 13.6 MElem/sec     1.00     62.2±0.44ms 16.1 MElem/sec
   fsb/default                                        1.00     11.3±0.05ms 88.6 MElem/sec     1.00     11.3±0.10ms 88.3 MElem/sec
   int32_ree/default                                  1.05     35.2±0.13ms 28.4 MElem/sec     1.00     33.5±0.10ms 29.9 MElem/sec
   int32_ree_95pct_null/default                       1.01     21.2±0.05ms 47.1 MElem/sec     1.00     21.0±0.05ms 47.6 MElem/sec
   int64_dictionary/default                           1.04     14.1±0.09ms 70.7 MElem/sec     1.00     13.6±0.12ms 73.3 MElem/sec
   int64_dictionary_1pct_cardinality/default          1.14     13.4±0.08ms 74.5 MElem/sec     1.00     11.8±0.07ms 84.8 MElem/sec
   int64_ree_low_cardinality/default                  1.09     22.6±0.29ms 44.3 MElem/sec     1.00     20.8±0.17ms 48.2 MElem/sec
   large_string_non_null/default                      1.01     51.9±0.18ms 19.3 KElem/sec     1.00     51.5±0.12ms 19.4 KElem/sec
   list_int32_ree/default                             1.00    125.5±0.45ms  8.0 MElem/sec     1.07    134.2±4.13ms  7.5 MElem/sec
   list_int32_ree_short_runs/default                  1.00    137.6±0.85ms  7.3 MElem/sec     1.06    145.4±4.57ms  6.9 MElem/sec
   list_nested/default                                1.00    119.2±0.34ms  8.4 MElem/sec     1.04    124.4±0.26ms  8.0 MElem/sec
   list_of_int32_ree/default                          1.05    123.2±0.50ms  8.1 MElem/sec     1.00    117.0±0.71ms  8.5 MElem/sec
   list_of_int32_ree_alt_empty/default                1.03     79.6±0.23ms 12.6 MElem/sec     1.00     76.9±0.37ms 13.0 MElem/sec
   list_of_int32_ree_alt_null/default                 1.03    114.6±0.22ms  8.7 MElem/sec     1.00    111.2±0.37ms  9.0 MElem/sec
   list_of_list_int32_ree/default                     1.00    153.1±0.72ms  6.5 MElem/sec     1.04    159.4±4.48ms  6.3 MElem/sec
   list_primitive/default                             1.00    191.9±1.56ms  5.2 MElem/sec     1.10   211.5±20.27ms  4.7 MElem/sec
   list_primitive_non_null/default                    1.00    233.4±6.45ms  4.3 MElem/sec     1.14   266.9±23.81ms  3.7 MElem/sec
   list_primitive_sparse_99pct_null/default           1.00     12.3±0.08ms 81.2 MElem/sec     1.02     12.5±0.10ms 79.8 MElem/sec
   list_string_ree/default                            1.00    147.8±0.72ms  6.8 MElem/sec     1.05    155.9±0.65ms  6.4 MElem/sec
   list_struct_with_list/default                      1.00    231.3±0.76ms  4.3 MElem/sec     1.12    259.5±0.85ms  3.9 MElem/sec
   numeric_ree_of_dict/default                        1.05     33.3±0.42ms 30.0 MElem/sec     1.00     31.7±0.29ms 31.5 MElem/sec
   primitive/default                                  1.06    107.6±0.54ms  9.3 MElem/sec     1.00    101.5±0.65ms  9.9 MElem/sec
   primitive_all_null/default                         1.00    271.1±1.68µs  3.6 GElem/sec     1.01    274.6±1.84µs  3.6 GElem/sec
   primitive_dictionary/default                       1.06     18.0±0.13ms 55.5 MElem/sec     1.00     16.9±0.04ms 59.1 MElem/sec
   primitive_dictionary_1pct_cardinality/default      1.13     13.4±0.07ms 74.8 MElem/sec     1.00     11.8±0.07ms 84.5 MElem/sec
   primitive_non_null/default                         1.12     58.1±0.42ms 17.2 MElem/sec     1.00     51.9±0.15ms 19.3 MElem/sec
   primitive_sparse_99pct_null/default                1.01     10.7±0.10ms 93.2 MElem/sec     1.00     10.6±0.10ms 94.1 MElem/sec
   ree_list_ree_list/default                          1.00    302.6±2.07ms  3.3 MElem/sec     1.04    314.7±1.56ms  3.2 MElem/sec
   ree_struct_of_dict/default                         1.00     61.8±0.89ms 16.2 MElem/sec     1.02     62.7±0.42ms 16.0 MElem/sec
   short_string_non_null/default                      1.36     20.7±0.27ms 48.2 MElem/sec     1.00     15.2±0.08ms 65.7 MElem/sec
   string/default                                     1.02    103.0±3.99ms  9.7 MElem/sec     1.00    101.4±6.73ms  9.9 MElem/sec
   string_and_binary_view/default                     1.01     48.8±0.26ms 20.5 MElem/sec     1.00     48.2±0.19ms 20.8 MElem/sec
   string_dictionary/default                          1.00     82.9±1.18ms 12.1 MElem/sec     1.02     84.8±0.48ms 11.8 MElem/sec
   string_dictionary_1pct_cardinality/default         1.04     21.5±0.10ms 46.5 MElem/sec     1.00     20.6±0.05ms 48.5 MElem/sec
   string_dictionary_low_cardinality_100/default      1.04     22.3±0.04ms 44.9 MElem/sec     1.00     21.4±0.05ms 46.8 MElem/sec
   string_dictionary_low_cardinality_20/default       1.04     22.2±0.11ms 45.0 MElem/sec     1.00     21.4±0.09ms 46.8 MElem/sec
   string_dictionary_low_cardinality_400/default      1.04     23.0±0.09ms 43.6 MElem/sec     1.00     22.0±0.11ms 45.4 MElem/sec
   string_non_null/default                            1.00   109.8±11.94ms  9.1 MElem/sec     1.08   118.5±13.43ms  8.4 MElem/sec
   string_ree/default                                 1.00     82.5±0.89ms 12.1 MElem/sec     1.53    126.4±1.18ms  7.9 MElem/sec
   string_ree_95pct_null/default                      1.02     24.6±0.09ms 40.6 MElem/sec     1.00     24.1±0.11ms 41.4 MElem/sec
   string_ree_int64_run_ends/default                  1.19     41.7±0.21ms 24.0 MElem/sec     1.00     35.1±0.13ms 28.5 MElem/sec
   string_ree_low_cardinality/default                 1.19     41.6±0.22ms 24.0 MElem/sec     1.00     35.1±0.13ms 28.5 MElem/sec
   string_ree_of_dict/default                         1.00     43.2±0.13ms 23.2 MElem/sec     1.00     43.0±0.16ms 23.2 MElem/sec
   struct_all_null/default                            1.00    115.3±0.69µs  8.5 GElem/sec     1.01    116.6±0.78µs  8.4 GElem/sec
   struct_non_null/default                            1.11     27.8±0.08ms 35.9 MElem/sec     1.00     25.0±0.10ms 40.0 MElem/sec
   struct_of_list_of_int32_ree_alt_null/default       1.03    116.7±0.38ms  8.6 MElem/sec     1.00    113.4±0.32ms  8.8 MElem/sec
   struct_of_list_of_int32_ree_fragmented/default     1.00    125.0±0.81ms  8.0 MElem/sec     1.01    126.2±1.12ms  7.9 MElem/sec
   struct_of_list_of_int32_ree_single_null/default    1.00    125.6±0.99ms  8.0 MElem/sec     1.00    125.9±1.10ms  7.9 MElem/sec
   struct_ree/default                                 1.16     52.6±0.36ms 19.0 MElem/sec     1.00     45.3±0.26ms 22.1 MElem/sec
   struct_ree_short_runs/default                      1.13     66.7±0.40ms 15.0 MElem/sec     1.00     59.2±0.36ms 16.9 MElem/sec
   struct_sparse_99pct_null/default                   1.00      5.9±0.01ms 169.7 MElem/sec    1.00      5.9±0.04ms 169.1 MElem/sec
   
   ```
   
   </details>
   
   <details><summary>Per-runner information</summary>
   
   <details><summary>arrow&#95;writer — shard 1/1</summary>
   
   **Node:** gk3-benchmark-cluster-nap-15qjie57-c718cbb7-fwjg
   
   **Instance:** c4a-highmem-16 (12 vCPU / 65 GiB)
   
   **uname:**
   
   ```text
   Linux bench-c6122486041-3332-jvjxx 6.12.94+ #1 SMP Fri Aug 21 08:00:16 UTC 2026 aarch64 GNU/Linux
   ```
   
   **BENCH_COMMAND:**
   
   ```sh
   cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_writer
   ```
   
   <details><summary>CPU Details (lscpu)</summary>
   
   ```text
   Architecture:                            aarch64
   CPU op-mode(s):                          64-bit
   Byte Order:                              Little Endian
   CPU(s):                                  16
   On-line CPU(s) list:                     0-15
   Vendor ID:                               ARM
   Model name:                              Neoverse-V2
   Model:                                   1
   Thread(s) per core:                      1
   Core(s) per cluster:                     16
   Socket(s):                               -
   Cluster(s):                              1
   Stepping:                                r0p1
   BogoMIPS:                                2000.00
   Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
   L1d cache:                               1 MiB (16 instances)
   L1i cache:                               1 MiB (16 instances)
   L2 cache:                                32 MiB (16 instances)
   L3 cache:                                80 MiB (1 instance)
   NUMA node(s):                            1
   NUMA node0 CPU(s):                       0-15
   Vulnerability Gather data sampling:      Not affected
   Vulnerability Indirect target selection: Not affected
   Vulnerability Itlb multihit:             Not affected
   Vulnerability L1tf:                      Not affected
   Vulnerability Mds:                       Not affected
   Vulnerability Meltdown:                  Not affected
   Vulnerability Mmio stale data:           Not affected
   Vulnerability Reg file data sampling:    Not affected
   Vulnerability Retbleed:                  Not affected
   Vulnerability Spec rstack overflow:      Not affected
   Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
   Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
   Vulnerability Spectre v2:                Mitigation; CSV2, BHB
   Vulnerability Srbds:                     Not affected
   Vulnerability Tsa:                       Not affected
   Vulnerability Tsx async abort:           Not affected
   Vulnerability Vmscape:                   Not affected
   ```
   
   </details>
   
   <details><summary>Resource Usage</summary>
   
   **base (merge-base)**
   | Metric | Value |
   |--------|-------|
   | Wall time | 870.2s |
   | Peak memory | 1.6 GiB |
   | Avg memory | 381.0 MiB |
   | CPU user | 848.5s |
   | CPU sys | 18.3s |
   | Peak spill | 0 B |
   
   **branch**
   | Metric | Value |
   |--------|-------|
   | Wall time | 885.2s |
   | Peak memory | 909.5 MiB |
   | Avg memory | 201.1 MiB |
   | CPU user | 811.2s |
   | CPU sys | 68.7s |
   | Peak spill | 0 B |
   
   
   </details>
   
   </details>
   
   </details>
   
   ---
   [File an issue](https://github.com/adriangb/datafusion-benchmarking/issues) against this benchmark runner
   
   <!-- benchmark-request:6122486041:finish:8600483214a56458176fa4b2181605f0 -->


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf(parquet): optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation [arrow-rs]

Posted by "alamb (via GitHub)" <gi...@apache.org>.
alamb commented on PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#issuecomment-6223814582

   This is pretty sick (in a good way)
   
   Thank you @rluvaton 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf: optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation in parquet [arrow-rs]

Posted by "rluvaton (via GitHub)" <gi...@apache.org>.
rluvaton commented on PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#issuecomment-6122486041

   run benchmark arrow_writer
   env:
     BENCH_FILTER: default


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf(parquet): optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation [arrow-rs]

Posted by "alamb (via GitHub)" <gi...@apache.org>.
alamb commented on code in PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523#discussion_r4287574586


##########
parquet/src/column/writer/min_max.rs:
##########
@@ -0,0 +1,389 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::basic::SortOrder;
+use crate::column::writer::{compare_greater, is_nan};
+use crate::data_type::private::ParquetValueType;
+use crate::schema::types::BasicTypeInfo;
+
+/// Accumulators for 64 bytes of values, i.e. a cache line and one AVX-512
+/// register, or four NEON / two AVX2 registers.
+const LANES_32: usize = 16;
+const LANES_64: usize = 8;
+
+/// Returns the minimum and maximum of `values` after mapping them with `key`,
+/// or `None` if `values` is empty.
+#[inline(always)]
+fn min_max_by_key<T: Copy, K: Copy + Ord, const LANES: usize>(

Review Comment:
   Why is this `inline(always)`? I had my agent try it locally and removing it makes no difference to binary size but I was wondering if you had some reason for adding it? 
   



##########
parquet/src/column/writer/min_max.rs:
##########
@@ -0,0 +1,389 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::basic::SortOrder;
+use crate::column::writer::{compare_greater, is_nan};
+use crate::data_type::private::ParquetValueType;
+use crate::schema::types::BasicTypeInfo;
+
+/// Accumulators for 64 bytes of values, i.e. a cache line and one AVX-512
+/// register, or four NEON / two AVX2 registers.
+const LANES_32: usize = 16;
+const LANES_64: usize = 8;
+
+/// Returns the minimum and maximum of `values` after mapping them with `key`,
+/// or `None` if `values` is empty.
+#[inline(always)]
+fn min_max_by_key<T: Copy, K: Copy + Ord, const LANES: usize>(
+    values: &[T],
+    key: impl Fn(T) -> K,
+    key_min: K,
+    key_max: K,
+) -> Option<(K, K)> {
+    if values.is_empty() {
+        return None;
+    }
+
+    let mut mins = [key_max; LANES];
+    let mut maxs = [key_min; LANES];
+
+    let (chunks, remainder) = values.as_chunks::<LANES>();
+    for chunk in chunks {
+        for i in 0..LANES {
+            let k = key(chunk[i]);
+            mins[i] = mins[i].min(k);
+            maxs[i] = maxs[i].max(k);
+        }
+    }
+    for (i, v) in remainder.iter().enumerate() {
+        let k = key(*v);
+        mins[i] = mins[i].min(k);
+        maxs[i] = maxs[i].max(k);
+    }
+
+    let min = mins.into_iter().min().unwrap();
+    let max = maxs.into_iter().max().unwrap();
+    Some((min, max))
+}
+
+#[inline]
+fn is_unsigned(basic_type_info: &BasicTypeInfo) -> bool {
+    matches!(basic_type_info.sort_order(), SortOrder::UNSIGNED)
+}
+
+/// Returns the min and max of an `INT32` column, or `None` if `values` is empty.
+pub(crate) fn min_max_i32(basic_type_info: &BasicTypeInfo, values: &[i32]) -> Option<(i32, i32)> {
+    if is_unsigned(basic_type_info) {
+        min_max_by_key::<_, _, LANES_32>(values, |v| v as u32, u32::MIN, u32::MAX)
+            .map(|(min, max)| (min as i32, max as i32))
+    } else {
+        min_max_by_key::<_, _, LANES_32>(values, |v| v, i32::MIN, i32::MAX)
+    }
+}
+
+/// Returns the min and max of an `INT64` column, or `None` if `values` is empty.
+pub(crate) fn min_max_i64(basic_type_info: &BasicTypeInfo, values: &[i64]) -> Option<(i64, i64)> {
+    if is_unsigned(basic_type_info) {
+        min_max_by_key::<_, _, LANES_64>(values, |v| v as u64, u64::MIN, u64::MAX)
+            .map(|(min, max)| (min as i64, max as i64))
+    } else {
+        min_max_by_key::<_, _, LANES_64>(values, |v| v, i64::MIN, i64::MAX)
+    }
+}
+
+macro_rules! float_min_max {
+    ($name:ident, $float:ty, $int:ty, $uint:ty, $lanes:expr) => {
+        /// Returns the min, max and NaN count of a floating point column,
+        /// comparing by IEEE 754 total order and skipping NaN.
+        ///
+        /// Returns `None` if `values` is empty or contains only NaN, in which
+        /// case the min and max are NaN themselves and the caller falls back
+        /// to the scalar implementation.
+        pub(crate) fn $name(values: &[$float]) -> Option<($float, $float, u64)> {
+            const SIGN_SHIFT: u32 = <$int>::BITS - 1;
+
+            // Maps the bits of a float to an integer with the same ordering as
+            // `total_cmp`: negative values have their magnitude bits flipped
+            // so that they order in reverse. The mapping is its own inverse.
+            //
+            // To avoid calling `{f32,f64}::total_cmp` for both min and max values and every other comparison
+            // we transform the input once (like what rust is doing internally before comparing) and reuse it, this avoids the overhead of calling `total_cmp` twice for each value.
+            // and doing the same calculation.
+            //
+            // This is the same transformation used in Rust `f32::total_cmp` and `f64::total_cmp`
+            // but we avoid calling
+            // f32: https://github.com/rust-lang/rust/blob/b5427502dab50cb27d9327d2893ddf2337dd4388/library/core/src/num/f32.rs#L1626
+            // f64: https://github.com/rust-lang/rust/blob/b5427502dab50cb27d9327d2893ddf2337dd4388/library/core/src/num/f64.rs#L1604
+            #[inline(always)]
+            fn total_order_key(bits: $int) -> $int {

Review Comment:
   this is clever -- I wonder if we can apply the same approach to the normal aggregate kernels: https://github.com/apache/arrow-rs/blob/0706d317a94098cec4b631031efcdf16f51ed1f5/arrow-arith/src/aggregate.rs#L111-L176



##########
parquet/src/column/writer/min_max.rs:
##########
@@ -0,0 +1,389 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::basic::SortOrder;
+use crate::column::writer::{compare_greater, is_nan};
+use crate::data_type::private::ParquetValueType;
+use crate::schema::types::BasicTypeInfo;
+
+/// Accumulators for 64 bytes of values, i.e. a cache line and one AVX-512
+/// register, or four NEON / two AVX2 registers.
+const LANES_32: usize = 16;
+const LANES_64: usize = 8;
+
+/// Returns the minimum and maximum of `values` after mapping them with `key`,
+/// or `None` if `values` is empty.
+#[inline(always)]
+fn min_max_by_key<T: Copy, K: Copy + Ord, const LANES: usize>(
+    values: &[T],
+    key: impl Fn(T) -> K,
+    key_min: K,
+    key_max: K,
+) -> Option<(K, K)> {
+    if values.is_empty() {
+        return None;
+    }
+
+    let mut mins = [key_max; LANES];
+    let mut maxs = [key_min; LANES];
+
+    let (chunks, remainder) = values.as_chunks::<LANES>();

Review Comment:
   
   I had my agent measure the binary size and this seems to be quite a bit larger (probably because it has a bunch of inlined loops)
   
   That being said, the performance numbers are good so 💯 
   
   ## Code size impact (`arrow_writer` bench binary, arm64 macOS, `bench` profile)
   
   | Measure | merge base (0706d31) | PR (63baa7e) | delta |
   |---|---:|---:|---:|
   | Bench binary on disk | 18,548,736 | 18,570,160 | +21,424 (+0.12%) |
   | Bench binary stripped | 14,595,408 | 14,612,048 | +16,640 |
   | `__TEXT` segment | 13,467,648 | 13,484,032 | +16,384 (one page) |
   | `libparquet` rlib | 20,772,320 | 20,803,856 | +31,536 |
   | LLVM IR lines, parquet crate (`cargo llvm-lines`) | 1,680,335 | 1,684,681 | +4,346 (+0.26%) |
   | LLVM IR functions | 20,926 | 21,043 | +117 |



##########
parquet/src/column/writer/min_max.rs:
##########
@@ -0,0 +1,389 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::basic::SortOrder;
+use crate::column::writer::{compare_greater, is_nan};
+use crate::data_type::private::ParquetValueType;
+use crate::schema::types::BasicTypeInfo;
+
+/// Accumulators for 64 bytes of values, i.e. a cache line and one AVX-512
+/// register, or four NEON / two AVX2 registers.
+const LANES_32: usize = 16;
+const LANES_64: usize = 8;
+
+/// Returns the minimum and maximum of `values` after mapping them with `key`,
+/// or `None` if `values` is empty.
+#[inline(always)]
+fn min_max_by_key<T: Copy, K: Copy + Ord, const LANES: usize>(
+    values: &[T],
+    key: impl Fn(T) -> K,
+    key_min: K,
+    key_max: K,
+) -> Option<(K, K)> {
+    if values.is_empty() {
+        return None;
+    }
+
+    let mut mins = [key_max; LANES];
+    let mut maxs = [key_min; LANES];
+
+    let (chunks, remainder) = values.as_chunks::<LANES>();
+    for chunk in chunks {
+        for i in 0..LANES {
+            let k = key(chunk[i]);
+            mins[i] = mins[i].min(k);
+            maxs[i] = maxs[i].max(k);
+        }
+    }
+    for (i, v) in remainder.iter().enumerate() {
+        let k = key(*v);
+        mins[i] = mins[i].min(k);
+        maxs[i] = maxs[i].max(k);
+    }
+
+    let min = mins.into_iter().min().unwrap();
+    let max = maxs.into_iter().max().unwrap();
+    Some((min, max))
+}
+
+#[inline]
+fn is_unsigned(basic_type_info: &BasicTypeInfo) -> bool {
+    matches!(basic_type_info.sort_order(), SortOrder::UNSIGNED)
+}
+
+/// Returns the min and max of an `INT32` column, or `None` if `values` is empty.
+pub(crate) fn min_max_i32(basic_type_info: &BasicTypeInfo, values: &[i32]) -> Option<(i32, i32)> {
+    if is_unsigned(basic_type_info) {
+        min_max_by_key::<_, _, LANES_32>(values, |v| v as u32, u32::MIN, u32::MAX)
+            .map(|(min, max)| (min as i32, max as i32))
+    } else {
+        min_max_by_key::<_, _, LANES_32>(values, |v| v, i32::MIN, i32::MAX)
+    }
+}
+
+/// Returns the min and max of an `INT64` column, or `None` if `values` is empty.
+pub(crate) fn min_max_i64(basic_type_info: &BasicTypeInfo, values: &[i64]) -> Option<(i64, i64)> {
+    if is_unsigned(basic_type_info) {
+        min_max_by_key::<_, _, LANES_64>(values, |v| v as u64, u64::MIN, u64::MAX)
+            .map(|(min, max)| (min as i64, max as i64))
+    } else {
+        min_max_by_key::<_, _, LANES_64>(values, |v| v, i64::MIN, i64::MAX)
+    }
+}
+
+macro_rules! float_min_max {
+    ($name:ident, $float:ty, $int:ty, $uint:ty, $lanes:expr) => {
+        /// Returns the min, max and NaN count of a floating point column,
+        /// comparing by IEEE 754 total order and skipping NaN.
+        ///
+        /// Returns `None` if `values` is empty or contains only NaN, in which
+        /// case the min and max are NaN themselves and the caller falls back
+        /// to the scalar implementation.
+        pub(crate) fn $name(values: &[$float]) -> Option<($float, $float, u64)> {
+            const SIGN_SHIFT: u32 = <$int>::BITS - 1;
+
+            // Maps the bits of a float to an integer with the same ordering as
+            // `total_cmp`: negative values have their magnitude bits flipped
+            // so that they order in reverse. The mapping is its own inverse.
+            //
+            // To avoid calling `{f32,f64}::total_cmp` for both min and max values and every other comparison
+            // we transform the input once (like what rust is doing internally before comparing) and reuse it, this avoids the overhead of calling `total_cmp` twice for each value.
+            // and doing the same calculation.
+            //
+            // This is the same transformation used in Rust `f32::total_cmp` and `f64::total_cmp`

Review Comment:
   thank you for these references



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] perf(parquet): optimize `i32`, `u32`, `i64`, `u64`, `f32`, `f64` min_max calculation [arrow-rs]

Posted by "alamb (via GitHub)" <gi...@apache.org>.
alamb merged PR #11523:
URL: https://github.com/apache/arrow-rs/pull/11523


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org