2026-11-08: Menai performance improvements

Published: 2026-11-08

One of the major performance issues with Menai has been that every value has been a heap allocation. Today I "unboxed" a few things!

Unboxing

In unboxing we're now using the lower 3 bits of a register value that were previously all zeros because these were pointers to heap-allocated objects. Now we use those 3 bits as a tag, and for small values we can store them directly in the register slot.

In this instance, none, boolean, and up to 61-bit integers are now stored directly in the register. This saves a huge amount of heap allocation and needless reference counting.

Performance numbers

BASE64-DECODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
standard-1k                       0.200          0.145
standard-64k                     10.613         10.488
url-1k                            0.146          0.144
url-64k                          10.567         10.465
──────────────────────────────────────────────────────


BASE64-ENCODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
standard-1k                       0.060          0.055
standard-64k                      4.265          4.156
unpadded-1k                       0.058          0.054
url-64k                           4.306          4.215
──────────────────────────────────────────────────────


BMP-DECODE
────────────────────────────────────────────────────────
Case                            mean (ms)       min (ms)
────────────────────────────────────────────────────────
truecolour-64x64                    0.286          0.260
truecolour-128x128                  1.196          1.183
truecolour-topdown-128x128          1.197          1.176
truecolour-alpha-128x128            1.489          1.469
padded-65x64                        0.292          0.272
────────────────────────────────────────────────────────


BMP-ENCODE
────────────────────────────────────────────────────────
Case                            mean (ms)       min (ms)
────────────────────────────────────────────────────────
truecolour-64x64                    0.741          0.716
truecolour-128x128                  7.149          7.115
truecolour-topdown-128x128          7.102          7.066
truecolour-alpha-128x128            9.864          9.692
padded-65x64                        0.780          0.776
────────────────────────────────────────────────────────


CALENDAR
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
short_5d                          0.023          0.018
month_20d                         0.074          0.071
quarter_60d                       0.219          0.217
year_250d                         0.892          0.887
months_600d                       1.552          1.508
──────────────────────────────────────────────────────


CSV-DECODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
plain-1000x10                     4.674          4.589
quoted-1000x10                    6.916          6.835
escaped-1000x10                   8.259          8.200
multiline-1000                    1.488          1.414
wide-100x100                      3.152          3.032
──────────────────────────────────────────────────────


CSV-ENCODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
plain-1000x10                     5.034          4.878
quoted-1000x10                   11.228         11.148
escaped-1000x10                   7.100          7.080
wide-100x100                      2.336          2.305
──────────────────────────────────────────────────────


DEFLATE-COMPRESS
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
text-4k                           0.781          0.753
text-32k                          3.229          3.096
incremental-16k                   4.955          4.868
runs-32k                          9.933          9.739
──────────────────────────────────────────────────────


DEFLATE-DECOMPRESS
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
text-4k                           0.301          0.290
text-32k                          0.475          0.464
incremental-16k                   0.651          0.640
stored-8k                         0.187          0.183
runs-32k                          1.544          1.499
──────────────────────────────────────────────────────


DOCX-DECODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
minimal                           0.476          0.459
document-100                      2.079          2.039
document-500                      8.626          8.532
document-2000                    33.542         33.332
styles-100                        2.986          2.918
numbering-9                       1.645          1.608
media-16                          4.279          4.229
full-500                         12.646         12.409
──────────────────────────────────────────────────────


DOCX-ENCODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
minimal                           0.073          0.063
document-100                      0.245          0.236
document-500                      0.981          0.968
styles-100                        0.379          0.372
numbering-9                       0.128          0.121
media-16                          0.275          0.264
full-500                          1.238          1.227
──────────────────────────────────────────────────────


HTML-DECODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
wide-1000                         4.866          4.840
deep-200                          0.427          0.422
attributes-500                    3.685          3.661
mixed-500                         3.898          3.874
entities-2000                    11.500         11.461
void-1000                        11.000         10.886
omitted-end-tags-1000             2.442          2.422
raw-text-500                      4.458          4.438
realistic-500                     7.968          7.905
──────────────────────────────────────────────────────


HTML-ENCODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
wide-1000                         1.739          1.678
deep-200                          0.208          0.164
attributes-500                    0.809          0.798
mixed-500                         1.939          1.932
void-1000                         3.688          3.652
escaping-2000                     4.078          4.038
declarations-1000                 0.536          0.527
──────────────────────────────────────────────────────


JSON-DECODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
object                            0.012          0.010
flat_array                        0.071          0.070
flat_object                       0.062          0.061
mixed_nested                      0.138          0.136
string_heavy                      0.052          0.051
numbers_array                     0.015          0.014
unicode_strings                   0.008          0.007
long_string                       0.061          0.060
deep_array                        0.123          0.121
──────────────────────────────────────────────────────


JSON-ENCODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
object                            0.012          0.009
flat_array                        0.013          0.012
flat_object                       0.028          0.027
mixed_nested                      0.055          0.053
string_heavy                      0.075          0.074
numbers_array                     0.009          0.007
unicode_strings                   0.003          0.002
long_string                       0.248          0.245
──────────────────────────────────────────────────────


PNG-DECODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
greyscale-64x64                   1.905          1.888
greyscale-alpha-64x64             7.206          7.150
palette-128x128                   5.272          5.242
truecolour-128x128               39.893         39.745
truecolour-alpha-128x128         53.443         53.097
truecolour-192x192               91.801         91.381
──────────────────────────────────────────────────────


PNG-ENCODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
truecolour-48x48                 18.263         18.241
truecolour-96x96                161.738        161.594
truecolour-alpha-96x96          279.464        278.855
──────────────────────────────────────────────────────


PPTX-DECODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
minimal                           0.951          0.930
slides-10                         3.743          3.718
slides-50                        15.955         15.882
slides-200                       62.064         61.754
shapes-50                        12.202         12.151
masters-8                         7.749          7.718
media-16                          7.544          7.455
theme-and-masters                 5.919          5.884
full-50                          73.211         72.881
──────────────────────────────────────────────────────


PPTX-ENCODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
minimal                           0.103          0.093
slides-10                         0.314          0.304
slides-50                         1.270          1.261
shapes-50                         1.238          1.218
masters-8                         0.639          0.630
media-16                          0.507          0.497
theme-and-masters                 0.485          0.476
full-50                           5.896          5.754
──────────────────────────────────────────────────────


REGEXP
───────────────────────────────────────────────────────
Case                           mean (ms)       min (ms)
───────────────────────────────────────────────────────
compile-per-line                   1.444          1.408
search-prefix-log                  0.031          0.030
search-class-numbers               0.034          0.032
search-alternation                 0.077          0.075
search-all-class                   9.981          9.961
search-all-prefix                  1.507          1.492
search-groups-log                  0.053          0.050
search-all-groups-numbers         34.673         34.534
split-whitespace                  12.014         11.981
replace-whitespace                70.879         70.230
replace-groups-dates              24.444         24.340
chained-per-line                   1.437          1.391
───────────────────────────────────────────────────────


RUBIKS_LIST
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
1-move                            0.061          0.056
2-move                            0.063          0.058
3-move                            0.135          0.129
4-move                            1.379          1.364
5-move                            4.602          4.588
6-move                           29.466         29.443
7-move                           65.552         65.492
──────────────────────────────────────────────────────


RUBIKS_VECTOR
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
1-move                            0.052          0.048
2-move                            0.052          0.048
3-move                            0.115          0.112
4-move                            1.163          1.157
5-move                            3.920          3.907
6-move                           25.175         25.128
7-move                           56.765         56.666
──────────────────────────────────────────────────────


SORT
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
n=10                              0.005          0.003
n=50                              0.029          0.027
n=100                             0.064          0.063
n=250                             0.188          0.187
n=500                             0.424          0.423
n=1000                            0.940          0.934
n=2500                            2.769          2.754
n=5000                            5.974          5.943
n=10000                          13.008         12.978
──────────────────────────────────────────────────────


STATS
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
vector-mean-n=100                 0.012          0.010
vector-mean-n=500                 0.054          0.050
vector-mean-n=1000                0.098          0.097
vector-mean-n=2500                0.265          0.261
vector-mean-n=5000                0.562          0.556
vector-mean-n=10000               1.142          1.121
vector-mean-n=25000               2.932          2.899
vector-summary-n=100              0.078          0.076
vector-summary-n=500              0.485          0.483
vector-summary-n=1000             1.095          1.084
vector-summary-n=2500             3.143          3.135
vector-summary-n=5000             6.762          6.733
vector-summary-n=10000           14.595         14.536
vector-summary-n=25000           40.376         40.049
list-mean-n=100                   0.011          0.010
list-mean-n=500                   0.050          0.049
list-mean-n=1000                  0.100          0.098
list-mean-n=2500                  0.281          0.277
list-mean-n=5000                  0.613          0.606
list-mean-n=10000                 1.183          1.171
list-mean-n=25000                 2.951          2.936
list-summary-n=100                0.078          0.076
list-summary-n=500                0.484          0.481
list-summary-n=1000               1.079          1.070
list-summary-n=2500               3.088          3.073
list-summary-n=5000               6.831          6.785
list-summary-n=10000             14.850         14.705
list-summary-n=25000             40.865         40.738
──────────────────────────────────────────────────────


STRING_OPS
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
search long/absent                0.019          0.016
search long/present               0.022          0.020
search short needle               0.023          0.020
search needle=haystack            0.184          0.180
hash 2000x8                       0.036          0.034
hash 2000x64                      0.096          0.095
hash 500x512                      0.199          0.198
──────────────────────────────────────────────────────


SUDOKU_LIST
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
Easy (36 givens)                 15.114         15.071
Medium (30 givens)                0.220          0.216
Hard (25 givens)               3207.785       3207.785
Expert (23 givens)              183.747        183.747
──────────────────────────────────────────────────────


SUDOKU_VECTOR
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
Easy (36 givens)                 11.012         10.965
Medium (30 givens)                0.160          0.156
Hard (25 givens)               2417.269       2417.269
Expert (23 givens)              137.213        137.213
──────────────────────────────────────────────────────


XML-DECODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
wide-1000                         2.323          2.300
deep-200                          0.215          0.211
attributes-500                    1.724          1.707
mixed-500                         2.758          2.737
entities-2000                     6.403          6.384
ooxml-500                         5.945          5.920
──────────────────────────────────────────────────────


XML-ENCODE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
wide-1000                         0.796          0.771
deep-200                          0.130          0.116
attributes-500                    0.750          0.741
mixed-500                         1.927          1.918
escaping-2000                     3.988          3.974
──────────────────────────────────────────────────────


ZIP-CREATE
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
single-deflate                    0.517          0.489
single-stored                     0.028          0.020
mixed-16                          3.643          3.616
many-128                         51.300         51.223
large-256k                       23.639         23.304
──────────────────────────────────────────────────────


ZIP-ENTRIES
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
single-deflate                    0.004          0.001
single-stored                     0.002          0.001
mixed-16                          0.013          0.011
many-128                          0.086          0.080
large-256k                        0.002          0.001
──────────────────────────────────────────────────────


ZIP-EXTRACT
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
single-deflate                    0.233          0.224
single-stored                     0.190          0.183
mixed-16                          0.532          0.524
many-128                          4.856          4.837
large-256k                        2.218          2.201
──────────────────────────────────────────────────────


ZLIB-COMPRESS
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
text-4k                           0.914          0.889
text-32k                          4.443          4.395
incremental-16k                   5.580          5.520
runs-32k                         11.314         11.158
──────────────────────────────────────────────────────


ZLIB-DECOMPRESS
──────────────────────────────────────────────────────
Case                          mean (ms)       min (ms)
──────────────────────────────────────────────────────
text-4k                           0.440          0.428
text-32k                          1.572          1.557
incremental-16k                   1.198          1.188
runs-32k                          2.610          2.579
──────────────────────────────────────────────────────

Comparisons with the results from 2026-10-25

SuiteCasesMean Δ%Old totalNew total
ZLIB-DECOMPRESS4−17.37.0825.820
ZIP-ENTRIES5−15.70.1140.107
BASE64-ENCODE4−13.810.1488.689
ZLIB-COMPRESS4−12.525.40922.251
DEFLATE-COMPRESS4−10.721.23618.898
PNG-DECODE6−9.5227.123199.520
RUBIKS_LIST7−9.3112.153101.258
BMP-DECODE5−8.44.8954.460
CSV-DECODE5−8.527.15324.489
ZIP-CREATE5−7.891.56579.127
PPTX-DECODE9−7.3203.317189.338
DOCX-DECODE8−6.971.64566.279
HTML-DECODE9−6.654.06250.244
XML-DECODE6−6.020.62919.368
DEFLATE-DECOMPRESS5−5.93.3623.158
SORT9−5.825.15023.401
BMP-ENCODE5−5.827.19325.636
REGEXP12−5.3166.990156.574
ZIP-EXTRACT5−5.18.5958.029
JSON-DECODE9−4.90.5790.542
STATS28−2.6152.480144.063
PNG-ENCODE3−2.2468.633459.465
RUBIKS_VECTOR7−1.789.15987.242
BASE64-DECODE4−1.623.65321.526
CSV-ENCODE4−1.325.93925.698
XML-ENCODE5−1.17.6307.591
DOCX-ENCODE7−1.03.3573.319
PPTX-ENCODE8−0.910.55610.452
SUDOKU_LIST4+0.23395.2763406.866
JSON-ENCODE8+0.50.4260.443
HTML-ENCODE7+0.512.91912.997
STRING_OPS7+2.10.5780.579
CALENDAR5+2.12.6992.760
SUDOKU_VECTOR4+4.72423.1352565.654