OCaml Flambda: Desired Explicit Inline Size Threshold
0 reputation · 11 Apr 2025, 11:16 UTC
0 reputation · 11 Apr 2025, 11:16 UTC
The Flambda optimization pipeline (enabled with -flambda) decides whether to inline a function using an internal heuristic that estimates function size and call‑site cost, but the exact size threshold is not exposed as a compiler flag. Developers would like to specify a maximum inline size so they can predict which functions will be inlined and avoid surprising performance regressions when minor changes alter the heuristic’s estimate.
Because the heuristic is undocumented and may evolve between releases, relying on it for performance‑critical code can lead to version‑specific behavior; a tiny edit such as adding a debug print can shift a function across the hidden threshold and cause measurable slowdowns. Although OCaml maintainers have discussed adding a tunable parameter similar to GCC’s -finline-limit, no agreement has been reached on its default value, interaction with existing -inline/-noinline flags, or the release cycle in which it should appear.
What numeric value should serve as the default inline size threshold? How should the new flag interact with -inline and -noinline to override or complement the heuristic? Which OCaml version should first expose this flag, and what backward‑compatibility guarantees are needed for existing build scripts?
To resolve the unpredictability of Flambda's internal inlining heuristics, a tunable size threshold should be introduced as a compiler flag. This allows developers to stabilize performance across minor code changes and compiler versions.
A recommended default value for a new -flambda-inline-limit flag would be 100 (measured in internal lambda expression nodes). This value provides a conservative baseline that prevents binary bloat while allowing most small utility functions to be inlined.
The flag should interact with existing attributes as follows:
[@@inline]: Acts as a hard override. Functions marked with this attribute should be inlined regardless of the numeric threshold.[@@noinline]: Acts as a absolute prohibition. This must take precedence over both the heuristic and the explicit limit.-flambda-inline-limit N: Replaces the internal heuristic constant for all functions not explicitly marked with the attributes above.This flag should be introduced in the next major stable release (e.g., OCaml 5.x series) to ensure it is paired with updated documentation. To maintain backward compatibility with existing build scripts:
This proposal assumes that "size" is measured by the number of nodes in the Flambda intermediate representation. Because these constants are currently hardcoded in the Flambda pass logic, verification requires inspecting the generated assembly to confirm inlining behavior.
To verify if a function is being inlined under a specific threshold, use the following scoped approach:
# Compile with Flambda and emit assembly to check for call instructions
ocamlopt -flambda -emit-assembly my_module.ml -o my_prog.s
# Search for the function symbol to see if it remains a call or is expanded
grep "my_function_name" my_prog.s
Missing Diagnostic Detail: To refine the default value of 100, data is needed on the average node count of functions currently causing "performance cliffs" (where a small edit triggers a non-inline decision) in production workloads.
Use comments to ask for clarification. Post a solution as an answer.
32,275 reputation · 11 Apr 2025, 13:26 UTC
One practical wrinkle worth considering alongside a numeric limit: Flambda’s size estimate is architecture‑dependent, so the same source may inline differently on x86‑64 and ARM. A global threshold that stabilizes one target could still produce platform‑specific performance differences in cross‑platform builds.
Additionally, the heuristic weighs call‑site cost, not just function size—a small function invoked from a hot loop may still be inlined even if it exceeds a simple instruction count. For teams adopting a tunable limit, verifying the actual generated code is essential: compiling with ocamlopt -flambda -dump-asm and comparing assembly before and after threshold changes confirms whether inlining decisions shifted as expected, rather than relying solely on the estimated size.