Skip to content

Optimise all C/C++ dependencies for binary size (-Os) - #447

Open
lovell wants to merge 1 commit into
mainfrom
temp-optimise-binary-size
Open

lovell wants to merge 1 commit into
mainfrom
temp-optimise-binary-size

Conversation

@lovell

@lovell lovell commented Nov 6, 2026 •

Copy link
Copy Markdown
Owner

Most dependencies were already optimised for size, this PR applies this for everything, which means the following are now smaller but possible slightly less performant:

  • zlib-ng: the hot paths are now all hand-written assembly, so we shouldn't see any benefit from compiler optimisations
  • lcms: I feel like this one might show up in performance testing, if so will look at ways to address this is within lcms itself
  • heif: gaining in size recently, perhaps colourspace conversions may suffer a little with this change, again will see if we can make improvements upstream for everyone instead of glossing over it here
  • imagequant: I added a NEON-specific version of the hot loop via lovell/libimagequant@ce5fdeb so this should no longer need compiler optimising
  • cgif: most GIF encoding time is spent in quantisation so probably minimal effect, and it's quite small already
  • highway: everything is CPU-specific runtime dispatch so no need for compiler optimisation
  • uhdr: officially still experimental 😄
  • vips: the biggest impact, I guess there's a lot of operation-related code that most people probably won't use. Focussing on making most common paths as autovectorisable (is that a word?) as possible is the best way, e.g. the recent work around premultiply

The resultant binaries weigh in at around ~12-15% smaller, here's linux-x64:

Before:

18858464 libvips-cpp.so.8.18.7

After:

16433632 libvips-cpp.so.8.18.7

Getting this in now ahead of the addition of libjxl/brotli so we can see the true impact.

/cc @kleisauke

@kleisauke

Copy link
Copy Markdown
Collaborator

Great! I'm seeing a similar size reduction in wasm-vips when trying this:

Before:

$ du -b lib/*.wasm
3818743	lib/vips-heif.wasm
2239317	lib/vips-jxl.wasm
1178633	lib/vips-resvg.wasm
5106467	lib/vips.wasm

After:

$ du -b lib/*.wasm
3579436	lib/vips-heif.wasm
1730244	lib/vips-jxl.wasm
1178566	lib/vips-resvg.wasm
4338331	lib/vips.wasm

I'm only worried about compiling libvips without -O3, since that will use a much lower vectorization cost model (i.e. -O2 / -Os uses -fvect-cost-model=very-cheap instead of -fvect-cost-model=dynamic). Fedora enabled -ftree-vectorize a while ago for similar reasons.
https://src.fedoraproject.org/rpms/vips/blob/bc84a1300187f9dac6ef4842163f329db614f497/f/vips.spec#_149
(though, that was before GCC 12 enabled -ftree-vectorize at -O2, so it's probably redundant now)

I'm aware that the auto-vectorizer can give nice speedups with 256-bit vector registers (e.g. when building with -march=x86-64-v3), but I'm less certain with 128-bit vector registers (e.g. when building with -march=x86-64-v2).

Compiling libvips locally with -O3 on this PR seems to increase the binary size by ~7.7% on linux-x64:

17699360 libvips-cpp.so.8.18.7

I'll do some benchmarking to see what the impact is. I'm also curious about the effect on WebAssembly, e.g. libjpeg-turbo still doesn't have a Wasm SIMD implementation, so perhaps the auto-vectorizer does shine there.

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.

2 participants