www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [SAOC 2026] DMD CTFE Performance Update #2

reply Abul Hossain Khan <abulkhan19175 gmail.com> writes:
Hi everyone,

Last time I went through the CTFE entrypoints and benchmarked 
Dennis's linear memory prototype. After that we had a call and 
decided to first measure how CTFE really behaves on real code. So 
that's what I did.



The interface we want is "here is a function, it's complete, run 
it, give me the result". What breaks that is semantic analysis 
getting triggered in the middle of CTFE. To see how much that 
happens I put a counter in `ctfeInterpret` and hooks in the 
semantic functions, each hit saves a backtrace. Also counted 
which `EXP` kinds go in and come out. Ran it on the test suite, 
the Phobos build and every Phobos module with `-unittest`.

- Semantic does run inside CTFE, in about 1% of the calls. Only 5 
different paths lead there, and really just one of them matters, 
calling a function whose body isn't analysed yet, mostly 
functions from imported modules.
- ~85% of `ctfeInterpret` calls return the input untouched, it's 
just simple constant folding.
- Out of 124 `EXP` kinds, 49 go in, 80 get evaluated inside and 
only 20 come out.
- The result is complete, the compiler doesn't have to analyse it 
again.

The lists and a minimal test for each of the 5 paths are here - 
https://gist.github.com/abulgit/43f640a032c95557de959f7120d4fd69




I added a pre-pass that walks every function body the call can 
reach and analyses it first.

| | Normal | with pre-pass |
|---|--:|--:|
| semantic inside CTFE, test suite | 10,008 | 11 |
| semantic inside CTFE, Phobos unittests | 17,711 | 88 |
| failing tests if semantic inside CTFE is an error | 732 | 13 |

So it works, the only thing left is virtual calls, where the 
override that runs isn't known before. 11 tests fail with the 
pre-pass but it's only a different line after an error.

But it also breaks valid code that isn't in the test suite. Like 
a const that is read in a branch which isn't taken while that 
const is computed, or a function from an imported module that 
never runs but gives an error with `-de` or `-betterC`.



- Will try the other way, where the engine asks for semantic 
through a callback, and compare the two.
- Also add a small code example for every expression kind in the 
gist, and see if the list can be made smaller.
- Add a CTFE heavy workload to the perf bot.

If you have code where CTFE is slow or eats a lot of memory, 
please share it here. A small self contained file is best, but a 
dub package works too.

Thanks to Dennis for mentoring this. As always, feel free to 
leave any feedback or suggestions!
Oct 06
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On Tuesday, 6 October 2026 at 13:50:14 UTC, Abul Hossain Khan 
wrote:
 If you have code where CTFE is slow or eats a lot of memory, 
 please share it here. A small self contained file is best, but 
 a dub package works too.
See std.regex ct tests. In fact IIRC it is run in three parts, because running all at once eats too much ram to pass on test runner. — Dmitry Olshansky
Oct 06
parent Abul Hossain Khan <abulkhan19175 gmail.com> writes:
On Tuesday, 6 October 2026 at 16:54:49 UTC, Dmitry Olshansky 
wrote:
 On Tuesday, 6 October 2026 at 13:50:14 UTC, Abul Hossain Khan 
 wrote:

 See std.regex ct tests. In fact IIRC it is run in three parts, 
 because running all at once eats too much ram to pass on test 
 runner.

 —
 Dmitry Olshansky
Thanks Dmitry, I will try that
Oct 08