googlefonts / googlefonts/fontc
Enable Link-Time Optimization (LTO) and codegen-units = 1 (+ some Profile-Guided Optimization (PGO) benchmarks)
- Dominant language
- Rust
- Stars
- 193
- Forks
- 21
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 65
Description
Hi! I found the project after reading an [article](https://developer.chrome.com/blog/memory-safety-fonts) - thank you for your work!
I noticed that in the `Cargo.toml` file Link-Time Optimization (LTO) for the project is not enabled. I suggest switching it on since it will reduce the binary size (always a good thing to have) and will likely improve the application's performance. If you want to read more about LTO and its possible modes, I recommend starting from [this](https://doc.rust-lang.org/rustc/codegen-options/index.html#lto) Rustc documentation.
I think you can enable LTO only for the Release builds so as not to sacrifice the developers' experience while working on the project, since LTO consumes an additional amount of time to finish the compilation routine. In this case, we can create a dedicated `[profile.optimized-dev]` profile where LTO will be disabled (so developers experience will not be affected). If we enable it on the Cargo profile level for the Release profile, users, who install the tools with `cargo install`, will get the LTO-optimized version of the app "automatically". E.g., check `cargo-outdated` Release [profile](https://github.com/kbknapp/cargo-outdated/blob/master/Cargo.toml#L48). You also could be interested in other optimization options like `codegen-units = 1` - it also brings improvements over the current defaults.
Basically, it can be enabled with the following lines:
```
[profile.release]
codegen-units = 1
lto = true
```
I have made quick tests (AMD Ryzen 5900x, Fedora 41, Rust 1.85.1, the latest version of the project at the moment, `cargo build --release` command) - here are the results. I don't know which binaries are more or less important so I report all the results.
| Binary\Build mode | fontc | fontc_crater | fea-lsp | highlight | otl-normalizer | libascii_plist_derive.so |
| --- | --- | --- | --- | --- | --- | --- |
| Release | 20 Mib | 5.6 Mib | 7.3 Mib | 813 Kib | 1.8 Mib | 3.5 Mib |
| Release + `codegen-units = 1` + ThinLTO | 16 Mib | 4.5 Mib | 5.2 Mib | 708 Kib | 1.4 Mib | 3.3 Mib |
| Release + `codegen-units = 1` + FatLTO | 14 Mib | 4.2 Mib | 4.8 Mib | 636 Kib | 1.3 Mib | 3.3 Mib |
Clean build times:
* Release: 41s
* Release + `codegen-units = 1` + ThinLTO: 1m 09s
* Release + `codegen-units = 1` + FatLTO: 1m 46s
I also did quick performance benchmarks with a command from the README file:
```
hyperfine --warmup 25 --runs 250 --prepare 'rm -rf build/' 'taskset -c 0 original_release/fontc --source OswaldFont/sources/Oswald.glyphs' 'taskset -c 0 thin_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs' 'taskset -c 0 fat_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs'
Benchmark 1: taskset -c 0 original_release/fontc --source OswaldFont/sources/Oswald.glyphs
Time (mean ± σ): 106.8 ms ± 1.4 ms [User: 77.6 ms, System: 28.4 ms]
Range (min … max): 101.5 ms … 113.4 ms 250 runs
Benchmark 2: taskset -c 0 thin_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs
Time (mean ± σ): 100.7 ms ± 1.4 ms [User: 71.3 ms, System: 28.7 ms]
Range (min … max): 94.9 ms … 105.3 ms 250 runs
Benchmark 3: taskset -c 0 fat_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs
Time (mean ± σ): 100.1 ms ± 1.4 ms [User: 70.2 ms, System: 29.2 ms]
Range (min … max): 94.5 ms … 104.4 ms 250 runs
Summary
taskset -c 0 fat_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs ran
1.01 ± 0.02 times faster than taskset -c 0 thin_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs
1.07 ± 0.02 times faster than taskset -c 0 original_release/fontc --source OswaldFont/sources/Oswald.glyphs
```
where we also can see improvements in performance from enabling LTO.
In addition to Fat LTO and CG1 I decided to apply Profile-Guided Optimization (PGO) to the `fontc` compiler. Since it's a compiler, I decided that PGO can help with performance improvement even more (as I found many times in other PGO [benchmarks](https://github.com/zamazan4ik/awesome-pgo) for many other apps including compilers). So I trained `fontc` on the same workload as above with `cargo pgo` (`cargo pgo build` + a training run + `cargo pgo optimize` commands), and ran the benchmarks again. Here are the results:
```
hyperfine --warmup 25 --runs 250 --prepare 'rm -rf build/' 'taskset -c 0 original_release/fontc --source OswaldFont/sources/Oswald.glyphs' 'taskset -c 0 thin_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs' 'taskset -c 0 fat_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs' 'taskset -c 0 ./fontc_fat_lto_and_pgo_optimized --source OswaldFont/sources/Oswald.glyphs'
Benchmark 1: taskset -c 0 original_release/fontc --source OswaldFont/sources/Oswald.glyphs
Time (mean ± σ): 107.8 ms ± 2.2 ms [User: 78.3 ms, System: 28.7 ms]
Range (min … max): 104.5 ms … 133.9 ms 250 runs
Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs.
Benchmark 2: taskset -c 0 thin_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs
Time (mean ± σ): 102.4 ms ± 1.9 ms [User: 73.2 ms, System: 28.4 ms]
Range (min … max): 95.2 ms … 109.4 ms 250 runs
Benchmark 3: taskset -c 0 fat_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs
Time (mean ± σ): 100.9 ms ± 1.9 ms [User: 71.9 ms, System: 28.3 ms]
Range (min … max): 94.2 ms … 108.9 ms 250 runs
Benchmark 4: taskset -c 0 ./fontc_fat_lto_and_pgo_optimized --source OswaldFont/sources/Oswald.glyphs
Time (mean ± σ): 94.5 ms ± 1.9 ms [User: 65.2 ms, System: 28.6 ms]
Range (min … max): 88.5 ms … 104.8 ms 250 runs
Summary
taskset -c 0 ./fontc_fat_lto_and_pgo_optimized --source OswaldFont/sources/Oswald.glyphs ran
1.07 ± 0.03 times faster than taskset -c 0 fat_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs
1.08 ± 0.03 times faster than taskset -c 0 thin_lto_release/fontc --source OswaldFont/sources/Oswald.glyphs
1.14 ± 0.03 times faster than taskset -c 0 original_release/fontc --source OswaldFont/sources/Oswald.glyphs
```
At least in this example, we see further improvements from applying LTO and PGO together. However, more tests are appreciated like using more fonts as a training set, etc.
Thank you.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with Cargo.toml and the existing release profile, then run the README benchmark command used with hyperfine. Compare release, codegen-units = 1, LTO, and the proposed PGO workflow, including build time, binary size, and runtime across representative workloads. Done means the supported optimization settings and benchmark results are agreed and reproducible.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- build-system, performance
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100