WolfXL vs openpyxl Benchmark Run
- Timestamp UTC:
2026-08-16T09:41:22.769698+00:00
- Git branch:
None
- Git commit:
None
- Git dirty:
None
- Python:
3.13.9
- WolfXL:
2.1.0
- openpyxl:
3.1.5
- Rounds:
3
| Case |
Engine |
Rows |
Cols |
Median seconds |
Units/sec |
Phase medians |
| write_append_plain |
openpyxl |
10,000 |
5 |
0.190021 |
263,129 |
|
| write_append_plain |
wolfxl_append |
10,000 |
5 |
0.018290 |
2,733,772 |
|
| write_append_plain |
wolfxl_write_rows |
10,000 |
5 |
0.014542 |
3,438,346 |
|
| write_append_mixed |
openpyxl |
10,000 |
5 |
0.192134 |
260,235 |
|
| write_append_mixed |
wolfxl_append |
10,000 |
5 |
0.020681 |
2,417,629 |
|
| write_append_wide |
openpyxl |
1,000 |
50 |
0.161785 |
309,053 |
|
| write_append_wide |
wolfxl_append |
1,000 |
50 |
0.013812 |
3,620,150 |
|
| write_append_formulas |
openpyxl |
2,000 |
5 |
0.039858 |
250,889 |
|
| write_append_formulas |
wolfxl_append |
2,000 |
5 |
0.005391 |
1,854,886 |
|
| write_append_formulas |
wolfxl_write_rows_fast_formula |
2,000 |
5 |
0.003991 |
2,505,533 |
|
| write_styled_cells |
openpyxl |
2,000 |
5 |
0.071640 |
139,587 |
populate_cells=0.033632s, save=0.037898s |
| write_styled_cells |
wolfxl_cell |
2,000 |
5 |
0.024934 |
401,051 |
populate_cells=0.012875s, save=0.011197s |
| write_styled_cells |
wolfxl_write_styled_rows |
2,000 |
5 |
0.011615 |
860,993 |
populate_cells=0.007701s, save=0.003548s |
| write_multi_sheet_plain |
openpyxl |
1,000 |
5 |
0.096936 |
257,903 |
|
| write_multi_sheet_plain |
wolfxl_append |
1,000 |
5 |
0.009319 |
2,682,679 |
|
| write_multi_sheet_plain |
wolfxl_write_rows_fast_multi_sheet |
1,000 |
5 |
0.005627 |
4,442,996 |
|
| write_cell_by_cell_plain |
openpyxl |
2,000 |
5 |
0.041770 |
239,406 |
construct_loop=0.007725s, save_flush=0.033760s |
| write_cell_by_cell_plain |
wolfxl_cell |
2,000 |
5 |
0.010500 |
952,347 |
construct_loop=0.007299s, save_flush=0.003014s |
| read_values_plain |
openpyxl |
10,000 |
5 |
0.231599 |
215,891 |
|
| read_values_plain |
wolfxl |
10,000 |
5 |
0.015385 |
3,249,892 |
|
| read_only_values_plain |
openpyxl |
10,000 |
5 |
0.196547 |
254,392 |
|
| read_only_values_plain |
wolfxl |
10,000 |
5 |
0.016928 |
2,953,686 |
|
| read_values_wide |
openpyxl |
1,000 |
50 |
0.183695 |
272,191 |
|
| read_values_wide |
wolfxl |
1,000 |
50 |
0.014293 |
3,498,216 |
|
| read_formula_text |
openpyxl |
2,000 |
5 |
0.042949 |
232,835 |
|
| read_formula_text |
wolfxl |
2,000 |
5 |
0.006712 |
1,489,813 |
|
| read_styled_cells |
openpyxl |
2,000 |
5 |
0.058847 |
169,932 |
|
| read_styled_cells |
wolfxl |
2,000 |
5 |
0.016429 |
608,664 |
|
| read_multi_sheet_values |
openpyxl |
5,000 |
5 |
0.114464 |
218,410 |
|
| read_multi_sheet_values |
wolfxl |
5,000 |
5 |
0.010505 |
2,379,734 |
|
| modify_two_cells_plain |
openpyxl |
10,000 |
5 |
0.680720 |
3 |
modify_save=0.431743s, setup_copy=0.000403s, verify_load=0.231801s |
| modify_two_cells_plain |
wolfxl_modify |
10,000 |
5 |
0.277661 |
7 |
modify_save=0.031171s, setup_copy=0.000393s, verify_load=0.247503s |
| large_write_append_plain |
openpyxl |
200,000 |
8 |
3.747834 |
426,913 |
|
| large_write_append_plain |
wolfxl_append |
200,000 |
8 |
0.380747 |
4,202,269 |
|
| large_write_append_plain |
wolfxl_write_rows |
200,000 |
8 |
0.293017 |
5,460,432 |
|
| large_read_values_plain |
openpyxl |
200,000 |
8 |
4.909174 |
325,920 |
|
| large_read_values_plain |
wolfxl |
200,000 |
8 |
0.331621 |
4,824,782 |
|
| large_read_only_values_plain |
openpyxl |
200,000 |
8 |
3.841151 |
416,542 |
|
| large_read_only_values_plain |
wolfxl |
200,000 |
8 |
0.289890 |
5,519,337 |
|
| large_modify_two_cells_plain |
openpyxl |
200,000 |
8 |
15.410541 |
0 |
modify_save=9.361222s, setup_copy=0.002489s, verify_load=6.046747s |
| large_modify_two_cells_plain |
wolfxl_modify |
200,000 |
8 |
6.808778 |
0 |
modify_save=0.598325s, setup_copy=0.002759s, verify_load=6.207687s |
Speedup >1.0x means WolfXL is faster (higher is better).
| Case |
WolfXL path |
Speedup vs openpyxl |
| large_modify_two_cells_plain |
wolfxl_modify |
2.26x |
| large_read_only_values_plain |
wolfxl |
13.25x |
| large_read_values_plain |
wolfxl |
14.80x |
| large_write_append_plain |
wolfxl_append |
9.84x |
| large_write_append_plain |
wolfxl_write_rows |
12.79x |
| modify_two_cells_plain |
wolfxl_modify |
2.45x |
| read_formula_text |
wolfxl |
6.40x |
| read_multi_sheet_values |
wolfxl |
10.90x |
| read_only_values_plain |
wolfxl |
11.61x |
| read_styled_cells |
wolfxl |
3.58x |
| read_values_plain |
wolfxl |
15.05x |
| read_values_wide |
wolfxl |
12.85x |
| write_append_formulas |
wolfxl_append |
7.39x |
| write_append_formulas |
wolfxl_write_rows_fast_formula |
9.99x |
| write_append_mixed |
wolfxl_append |
9.29x |
| write_append_plain |
wolfxl_append |
10.39x |
| write_append_plain |
wolfxl_write_rows |
13.07x |
| write_append_wide |
wolfxl_append |
11.71x |
| write_cell_by_cell_plain |
wolfxl_cell |
3.98x |
| write_multi_sheet_plain |
wolfxl_append |
10.40x |
| write_multi_sheet_plain |
wolfxl_write_rows_fast_multi_sheet |
17.23x |
| write_styled_cells |
wolfxl_cell |
2.87x |
| write_styled_cells |
wolfxl_write_styled_rows |
6.17x |
Phase speedups
For phased workloads, this separates setup/verification time from the operation being measured. Speedup >1.0x means WolfXL is faster for that phase.
| Case |
WolfXL path |
Phase |
openpyxl seconds |
WolfXL seconds |
Speedup |
| large_modify_two_cells_plain |
wolfxl_modify |
modify_save |
9.361222 |
0.598325 |
15.65x |
| large_modify_two_cells_plain |
wolfxl_modify |
setup_copy |
0.002489 |
0.002759 |
0.90x |
| large_modify_two_cells_plain |
wolfxl_modify |
verify_load |
6.046747 |
6.207687 |
0.97x |
| modify_two_cells_plain |
wolfxl_modify |
modify_save |
0.431743 |
0.031171 |
13.85x |
| modify_two_cells_plain |
wolfxl_modify |
setup_copy |
0.000403 |
0.000393 |
1.02x |
| modify_two_cells_plain |
wolfxl_modify |
verify_load |
0.231801 |
0.247503 |
0.94x |
| write_cell_by_cell_plain |
wolfxl_cell |
construct_loop |
0.007725 |
0.007299 |
1.06x |
| write_cell_by_cell_plain |
wolfxl_cell |
save_flush |
0.033760 |
0.003014 |
11.20x |
| write_styled_cells |
wolfxl_cell |
populate_cells |
0.033632 |
0.012875 |
2.61x |
| write_styled_cells |
wolfxl_cell |
save |
0.037898 |
0.011197 |
3.38x |
| write_styled_cells |
wolfxl_write_styled_rows |
populate_cells |
0.033632 |
0.007701 |
4.37x |
| write_styled_cells |
wolfxl_write_styled_rows |
save |
0.037898 |
0.003548 |
10.68x |
Operation speedups
For benchmarks with setup or verification phases, this table shows the library operation phase used for claim gating. The full end-to-end timing above is still reported.
| Case |
WolfXL path |
Operation phase |
openpyxl seconds |
WolfXL seconds |
Speedup |
| large_modify_two_cells_plain |
wolfxl_modify |
modify_save |
9.361222 |
0.598325 |
15.65x |
| modify_two_cells_plain |
wolfxl_modify |
modify_save |
0.431743 |
0.031171 |
13.85x |
Peak resident-set size per workload, each measured in its own subprocess (clean ru_maxrss high-water mark). Baseline is the interpreter with both libraries imported.
| Case |
Engine |
Rows |
Cols |
Peak RSS |
Delta over baseline |
| write_append_plain |
openpyxl |
10,000 |
5 |
68.7 MiB |
19.5 MiB |
| write_append_plain |
wolfxl |
10,000 |
5 |
61.6 MiB |
12.2 MiB |
| read_values_plain |
openpyxl |
10,000 |
5 |
72.5 MiB |
23.0 MiB |
| read_values_plain |
wolfxl |
10,000 |
5 |
60.4 MiB |
11.3 MiB |
| read_only_values_plain |
openpyxl |
10,000 |
5 |
51.0 MiB |
1.8 MiB |
| read_only_values_plain |
wolfxl |
10,000 |
5 |
52.0 MiB |
2.7 MiB |
| modify_two_cells_plain |
openpyxl |
10,000 |
5 |
77.1 MiB |
27.9 MiB |
| modify_two_cells_plain |
wolfxl |
10,000 |
5 |
83.0 MiB |
33.5 MiB |
| large_write_append_plain |
openpyxl |
200,000 |
8 |
429.2 MiB |
380.0 MiB |
| large_write_append_plain |
wolfxl |
200,000 |
8 |
244.5 MiB |
195.3 MiB |
| large_read_values_plain |
openpyxl |
200,000 |
8 |
505.6 MiB |
456.4 MiB |
| large_read_values_plain |
wolfxl |
200,000 |
8 |
151.5 MiB |
102.1 MiB |
| large_read_only_values_plain |
openpyxl |
200,000 |
8 |
68.0 MiB |
18.8 MiB |
| large_read_only_values_plain |
wolfxl |
200,000 |
8 |
52.3 MiB |
3.1 MiB |
| large_modify_two_cells_plain |
openpyxl |
200,000 |
8 |
592.2 MiB |
543.0 MiB |
| large_modify_two_cells_plain |
wolfxl |
200,000 |
8 |
483.0 MiB |
433.6 MiB |
Ratio <1.0x means WolfXL uses less memory (lower is better). A ratio >1.0x means WolfXL's peak RSS is higher than openpyxl's. Large-sheet WolfXL reads use the streaming path and skip eager worksheet-wide style hydration, so their peak RSS should stay bounded.
| Case |
WolfXL path |
Peak ratio |
Workload delta ratio |
Workload delta diff |
| large_modify_two_cells_plain |
wolfxl |
0.82x |
0.80x |
n/a |
| large_read_only_values_plain |
wolfxl |
0.77x |
0.16x |
n/a |
| large_read_values_plain |
wolfxl |
0.30x |
0.22x |
n/a |
| large_write_append_plain |
wolfxl |
0.57x |
0.51x |
n/a |
| modify_two_cells_plain |
wolfxl |
1.08x |
1.20x |
5.6 MiB |
| read_only_values_plain |
wolfxl |
1.02x |
1.45x |
0.8 MiB |
| read_values_plain |
wolfxl |
0.83x |
0.49x |
n/a |
| write_append_plain |
wolfxl |
0.90x |
0.62x |
n/a |