Skip to content

Commit 96c8cc5

Browse files
xokdviumRadvendii
authored andcommitted
libexpr/meson: Rice the compiler inlining heuristics to improve perf of the bison generated parser
Turns out both GCC and Clang need a bit of hand-holding to optimize the bison generated code well, otherwise parser performance tanks. (Comparisons against baseline in 7e8db2e): For GCC: Benchmark 1 (15 runs): result/bin/nix-instantiate --parse ../nixpkgs/pkgs/development/haskell-modules/hackage-packages.nix measurement mean ± σ min … max outliers delta wall_time 335ms ± 2.89ms 332ms … 342ms 0 ( 0%) 0% Benchmark 2 (16 runs): result-old/bin/nix-instantiate --parse ../nixpkgs/pkgs/development/haskell-modules/hackage-packages.nix measurement mean ± σ min … max outliers delta wall_time 330ms ± 2.87ms 326ms … 337ms 0 ( 0%) - 1.4% ± 0.6% For Clang: Benchmark 1 (15 runs): result-clang/bin/nix-instantiate --parse ../nixpkgs/pkgs/development/haskell-modules/hackage-packages.nix measurement mean ± σ min … max outliers delta wall_time 340ms ± 1.43ms 338ms … 343ms 0 ( 0%) 0% Benchmark 2 (15 runs): result-old-clang/bin/nix-instantiate --parse ../nixpkgs/pkgs/development/haskell-modules/hackage-packages.nix measurement mean ± σ min … max outliers delta wall_time 334ms ± 1.61ms 332ms … 338ms 0 ( 0%) ⚡- 1.7% ± 0.3%
1 parent 32b286e commit 96c8cc5

File tree

1 file changed

+47
-2
lines changed

1 file changed

+47
-2
lines changed

src/libexpr/meson.build

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,17 +183,62 @@ subdir('primops')
183183
subdir('nix-meson-build-support/export-all-symbols')
184184
subdir('nix-meson-build-support/windows-version')
185185

186+
# Turns out that Bison/Flex are particularly sensitive to compilers
187+
# failing to inline functions. For that reason we crank up the inlining
188+
# threshold manually for optimized builds. Yes, this can be considered 'ricing'
189+
# the compiler, but it does pay off.
190+
#
191+
# NOTE: missed inlining can be spotted (for Clang) using -Rpass-missed=inline
192+
# and -fdump-ipa-inline-missed (for GCC).
193+
parser_library_cpp_args = []
194+
195+
if not get_option('debug')
196+
if cxx.get_id() == 'clang'
197+
# The default as of LLVM 21 is 225:
198+
# llc --help-hidden | grep inline-threshold
199+
parser_library_cpp_args += [
200+
'-mllvm',
201+
'-inline-threshold=5000',
202+
]
203+
elif cxx.get_id() == 'gcc'
204+
parser_library_cpp_args += [
205+
'--param=max-inline-insns-single=1000',
206+
'--param=max-inline-insns-auto=1000',
207+
'--param=inline-unit-growth=400',
208+
]
209+
endif
210+
endif
211+
212+
# Working around https://github.com/mesonbuild/meson/issues/1367.
213+
parser_library = static_library(
214+
'nixexpr-parser',
215+
parser_tab,
216+
lexer_tab,
217+
cpp_args : parser_library_cpp_args,
218+
dependencies : deps_public + deps_private + deps_other,
219+
include_directories : include_dirs,
220+
# 1. Stdlib and regular assertions regress parser performance significantly, so build without
221+
# them for this one library when building in a release configuration.
222+
# 2. Disable LTO for GCC because then inlining flags won't apply, since LTO in GCC is done
223+
# by plonking down GIMPLE in the archive.
224+
override_options : [
225+
'b_ndebug=@0@'.format(not get_option('debug')),
226+
'b_lto=@0@'.format(cxx.get_id() != 'gcc'),
227+
],
228+
)
229+
186230
this_library = library(
187231
'nixexpr',
188232
sources,
189233
config_priv_h,
190-
parser_tab,
191-
lexer_tab,
234+
parser_tab[1],
235+
lexer_tab[1],
192236
generated_headers,
193237
soversion : nix_soversion,
194238
dependencies : deps_public + deps_private + deps_other,
195239
include_directories : include_dirs,
196240
link_args : linker_export_flags,
241+
link_whole : [ parser_library ],
197242
prelink : true, # For C++ static initializers
198243
install : true,
199244
cpp_pch : do_pch ? [ 'pch/precompiled-headers.hh' ] : [],

0 commit comments

Comments
 (0)