Skip to content

fmt: slim down binary size of Temporal ISO 8601 duration printer#468

Merged
BurntSushi merged 2 commits intomasterfrom
ag/temporal-print-refactor
Dec 31, 2025
Merged

fmt: slim down binary size of Temporal ISO 8601 duration printer#468
BurntSushi merged 2 commits intomasterfrom
ag/temporal-print-refactor

Conversation

@BurntSushi
Copy link
Copy Markdown
Owner

In a simple benchmark program that prints spans, signed and unsigned
durations using jiff::fmt::temporal::SpanPrinter, the total number of
LLVM lines is reduced by about 6,000.

There is also a modest improvement in runtime performance:

$ critcmp baseline x01 -f 'iso8601.*jiff'
group                                                       baseline                               x05
-----                                                       --------                               ---
print/display/duration/iso8601/jiff                         1.61     27.4±0.24ns        ? ?/sec    1.00     17.1±0.18ns        ? ?/sec
print/display/span/iso8601/jiff                             1.79     30.6±0.36ns        ? ?/sec    1.00     17.1±0.09ns        ? ?/sec
print/iso8601_duration/long-time/duration/buffer/jiff       1.26     24.3±0.07ns        ? ?/sec    1.00     19.3±0.07ns        ? ?/sec
print/iso8601_duration/long-time/duration/to_string/jiff    2.08     52.9±0.28ns        ? ?/sec    1.00     25.4±0.08ns        ? ?/sec
print/iso8601_duration/long-time/span/buffer/jiff           1.39     29.2±0.09ns        ? ?/sec    1.00     21.0±0.04ns        ? ?/sec
print/iso8601_duration/long-time/span/to_string/jiff        2.14     59.0±0.55ns        ? ?/sec    1.00     27.6±0.07ns        ? ?/sec
print/iso8601_duration/long/span/buffer/jiff                1.76     28.1±0.08ns        ? ?/sec    1.00     16.0±0.08ns        ? ?/sec
print/iso8601_duration/long/span/to_string/jiff             1.84     40.1±0.15ns        ? ?/sec    1.00     21.8±0.06ns        ? ?/sec
print/iso8601_duration/medium/span/buffer/jiff              1.37     17.4±0.07ns        ? ?/sec    1.00     12.8±0.08ns        ? ?/sec
print/iso8601_duration/medium/span/to_string/jiff           1.65     31.6±0.14ns        ? ?/sec    1.00     19.2±0.08ns        ? ?/sec
print/iso8601_duration/short/duration/buffer/jiff           1.18     14.7±0.03ns        ? ?/sec    1.00     12.4±0.04ns        ? ?/sec
print/iso8601_duration/short/duration/to_string/jiff        1.08     22.3±0.11ns        ? ?/sec    1.00     20.6±0.08ns        ? ?/sec
print/iso8601_duration/short/span/buffer/jiff               1.27     14.9±0.06ns        ? ?/sec    1.00     11.8±0.02ns        ? ?/sec
print/iso8601_duration/short/span/to_string/jiff            1.14     22.7±0.15ns        ? ?/sec    1.00     19.9±0.10ns        ? ?/sec
print/iso8601_duration/tiny/duration/buffer/jiff            1.00      9.2±0.03ns        ? ?/sec    1.26     11.6±0.01ns        ? ?/sec
print/iso8601_duration/tiny/duration/to_string/jiff         1.00     12.0±0.05ns        ? ?/sec    1.19     14.3±0.10ns        ? ?/sec
print/iso8601_duration/tiny/span/buffer/jiff                1.04     11.4±0.11ns        ? ?/sec    1.00     11.0±0.06ns        ? ?/sec
print/iso8601_duration/tiny/span/to_string/jiff             1.01     14.1±0.08ns        ? ?/sec    1.00     14.0±0.10ns        ? ?/sec

The only regression here is on a very tiny duration (PT2S). I'm
able to eliminate most of the regression, but only by inlining the
print_unsigned_duration_impl function, which increases code size by a
few hundred LLVM lines. My feeling at present is that this isn't worth
it.

The runtime improvements widen the gap between Jiff and Chrono. Before:

$ critcmp baseline -g '(.*/)(?:jiff|chrono)$' -f 'iso8601.*buffer'
group                                                baseline/chrono                        baseline/jiff
-----                                                ---------------                        -------------
print/iso8601_duration/long-time/duration/buffer/    1.91     46.3±0.32ns        ? ?/sec    1.00     24.3±0.07ns        ? ?/sec
print/iso8601_duration/long-time/span/buffer/                                               1.00     29.2±0.09ns        ? ?/sec
print/iso8601_duration/long/span/buffer/                                                    1.00     28.1±0.08ns        ? ?/sec
print/iso8601_duration/medium/span/buffer/                                                  1.00     17.4±0.07ns        ? ?/sec
print/iso8601_duration/short/duration/buffer/        2.19     32.1±0.29ns        ? ?/sec    1.00     14.7±0.03ns        ? ?/sec
print/iso8601_duration/short/span/buffer/                                                   1.00     14.9±0.06ns        ? ?/sec
print/iso8601_duration/tiny/duration/buffer/         3.39     31.1±0.18ns        ? ?/sec    1.00      9.2±0.03ns        ? ?/sec
print/iso8601_duration/tiny/span/buffer/                                                    1.00     11.4±0.11ns        ? ?/sec

After:

$ critcmp cmp -g '(.*/)(?:jiff|chrono)$' -f 'iso8601.*buffer'
group                                                cmp/chrono                             cmp/jiff
-----                                                ----------                             --------
print/iso8601_duration/long-time/duration/buffer/    2.41     46.5±0.23ns        ? ?/sec    1.00     19.3±0.03ns        ? ?/sec
print/iso8601_duration/long-time/span/buffer/                                               1.00     21.2±0.04ns        ? ?/sec
print/iso8601_duration/long/span/buffer/                                                    1.00     16.2±0.05ns        ? ?/sec
print/iso8601_duration/medium/span/buffer/                                                  1.00     12.7±0.03ns        ? ?/sec
print/iso8601_duration/short/duration/buffer/        2.60     31.7±0.15ns        ? ?/sec    1.00     12.2±0.04ns        ? ?/sec
print/iso8601_duration/short/span/buffer/                                                   1.00     11.6±0.04ns        ? ?/sec
print/iso8601_duration/tiny/duration/buffer/         4.09     31.3±0.12ns        ? ?/sec    1.00      7.7±0.07ns        ? ?/sec
print/iso8601_duration/tiny/span/buffer/                                                    1.00      7.1±0.05ns        ? ?/sec

This also reduces code size slightly.
… buffers

In a simple benchmark program that prints spans, signed and unsigned
durations using `jiff::fmt::temporal::SpanPrinter`, the total number of
LLVM lines is reduced by about 6,000.

There is also a modest improvement in runtime performance:

```
$ critcmp baseline x01 -f 'iso8601.*jiff'
group                                                       baseline                               x05
-----                                                       --------                               ---
print/display/duration/iso8601/jiff                         1.61     27.4±0.24ns        ? ?/sec    1.00     17.1±0.18ns        ? ?/sec
print/display/span/iso8601/jiff                             1.79     30.6±0.36ns        ? ?/sec    1.00     17.1±0.09ns        ? ?/sec
print/iso8601_duration/long-time/duration/buffer/jiff       1.26     24.3±0.07ns        ? ?/sec    1.00     19.3±0.07ns        ? ?/sec
print/iso8601_duration/long-time/duration/to_string/jiff    2.08     52.9±0.28ns        ? ?/sec    1.00     25.4±0.08ns        ? ?/sec
print/iso8601_duration/long-time/span/buffer/jiff           1.39     29.2±0.09ns        ? ?/sec    1.00     21.0±0.04ns        ? ?/sec
print/iso8601_duration/long-time/span/to_string/jiff        2.14     59.0±0.55ns        ? ?/sec    1.00     27.6±0.07ns        ? ?/sec
print/iso8601_duration/long/span/buffer/jiff                1.76     28.1±0.08ns        ? ?/sec    1.00     16.0±0.08ns        ? ?/sec
print/iso8601_duration/long/span/to_string/jiff             1.84     40.1±0.15ns        ? ?/sec    1.00     21.8±0.06ns        ? ?/sec
print/iso8601_duration/medium/span/buffer/jiff              1.37     17.4±0.07ns        ? ?/sec    1.00     12.8±0.08ns        ? ?/sec
print/iso8601_duration/medium/span/to_string/jiff           1.65     31.6±0.14ns        ? ?/sec    1.00     19.2±0.08ns        ? ?/sec
print/iso8601_duration/short/duration/buffer/jiff           1.18     14.7±0.03ns        ? ?/sec    1.00     12.4±0.04ns        ? ?/sec
print/iso8601_duration/short/duration/to_string/jiff        1.08     22.3±0.11ns        ? ?/sec    1.00     20.6±0.08ns        ? ?/sec
print/iso8601_duration/short/span/buffer/jiff               1.27     14.9±0.06ns        ? ?/sec    1.00     11.8±0.02ns        ? ?/sec
print/iso8601_duration/short/span/to_string/jiff            1.14     22.7±0.15ns        ? ?/sec    1.00     19.9±0.10ns        ? ?/sec
print/iso8601_duration/tiny/duration/buffer/jiff            1.00      9.2±0.03ns        ? ?/sec    1.26     11.6±0.01ns        ? ?/sec
print/iso8601_duration/tiny/duration/to_string/jiff         1.00     12.0±0.05ns        ? ?/sec    1.19     14.3±0.10ns        ? ?/sec
print/iso8601_duration/tiny/span/buffer/jiff                1.04     11.4±0.11ns        ? ?/sec    1.00     11.0±0.06ns        ? ?/sec
print/iso8601_duration/tiny/span/to_string/jiff             1.01     14.1±0.08ns        ? ?/sec    1.00     14.0±0.10ns        ? ?/sec
```

The only regression here is on a very tiny duration (`PT2S`). I'm
able to eliminate most of the regression, but only by inlining the
`print_unsigned_duration_impl` function, which increases code size by a
few hundred LLVM lines. My feeling at present is that this isn't worth
it.

The runtime improvements widen the gap between Jiff and Chrono. Before:

```
$ critcmp baseline -g '(.*/)(?:jiff|chrono)$' -f 'iso8601.*buffer'
group                                                baseline/chrono                        baseline/jiff
-----                                                ---------------                        -------------
print/iso8601_duration/long-time/duration/buffer/    1.91     46.3±0.32ns        ? ?/sec    1.00     24.3±0.07ns        ? ?/sec
print/iso8601_duration/long-time/span/buffer/                                               1.00     29.2±0.09ns        ? ?/sec
print/iso8601_duration/long/span/buffer/                                                    1.00     28.1±0.08ns        ? ?/sec
print/iso8601_duration/medium/span/buffer/                                                  1.00     17.4±0.07ns        ? ?/sec
print/iso8601_duration/short/duration/buffer/        2.19     32.1±0.29ns        ? ?/sec    1.00     14.7±0.03ns        ? ?/sec
print/iso8601_duration/short/span/buffer/                                                   1.00     14.9±0.06ns        ? ?/sec
print/iso8601_duration/tiny/duration/buffer/         3.39     31.1±0.18ns        ? ?/sec    1.00      9.2±0.03ns        ? ?/sec
print/iso8601_duration/tiny/span/buffer/                                                    1.00     11.4±0.11ns        ? ?/sec
```

After:

```
$ critcmp cmp -g '(.*/)(?:jiff|chrono)$' -f 'iso8601.*buffer'
group                                                cmp/chrono                             cmp/jiff
-----                                                ----------                             --------
print/iso8601_duration/long-time/duration/buffer/    2.41     46.5±0.23ns        ? ?/sec    1.00     19.3±0.03ns        ? ?/sec
print/iso8601_duration/long-time/span/buffer/                                               1.00     21.2±0.04ns        ? ?/sec
print/iso8601_duration/long/span/buffer/                                                    1.00     16.2±0.05ns        ? ?/sec
print/iso8601_duration/medium/span/buffer/                                                  1.00     12.7±0.03ns        ? ?/sec
print/iso8601_duration/short/duration/buffer/        2.60     31.7±0.15ns        ? ?/sec    1.00     12.2±0.04ns        ? ?/sec
print/iso8601_duration/short/span/buffer/                                                   1.00     11.6±0.04ns        ? ?/sec
print/iso8601_duration/tiny/duration/buffer/         4.09     31.3±0.12ns        ? ?/sec    1.00      7.7±0.07ns        ? ?/sec
print/iso8601_duration/tiny/span/buffer/                                                    1.00      7.1±0.05ns        ? ?/sec
```
@BurntSushi BurntSushi force-pushed the ag/temporal-print-refactor branch from 9b72796 to d2a3b5c Compare December 31, 2025 03:11
@BurntSushi BurntSushi merged commit 91f5620 into master Dec 31, 2025
40 checks passed
@BurntSushi BurntSushi deleted the ag/temporal-print-refactor branch December 31, 2025 03:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant