Performance on Windows
Background
It is well known that Windows does not handle many small files and lots of forking as well as Linux. This issue is an attempt to point to the performance issues this can result in with meson, and hopefully spawn some discussion about any possible improvements.
As an example, I cloned glib and ran meson through cProfile on Windows using the ninja backend targeting mingw-w64:
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 145.170 145.170 meson.py:17(<module>)
538 1.252 0.002 136.814 0.254 compilers.py:747(compile)
135 0.001 0.000 82.098 0.608 c.py:323(links)
67 0.003 0.000 73.984 1.104 c.py:578(has_function)
32 0.001 0.000 28.619 0.894 c.py:327(run)
101 0.001 0.000 27.875 0.276 c.py:312(compiles)
11 0.000 0.000 7.880 0.716 c.py:411(sizeof)
56 0.001 0.000 7.573 0.135 c.py:246(has_header)
15 0.000 0.000 6.420 0.428 c.py:661(has_members)
7 0.000 0.000 4.844 0.692 c.py:449(alignment)
7 0.000 0.000 4.743 0.678 c.py:759(find_library)
9 0.000 0.000 3.870 0.430 c.py:259(has_header_symbol)
As you can see, about 94% of the 2:25 min running time is spent in compile() which runs the compiler on a small generated file.
Using the ninja backend targeting MSVC instead, I get:
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 60.610 60.610 meson.py:17(<module>)
440 1.085 0.002 50.609 0.115 compilers.py:747(compile)
At roughly 60 seconds this is a lot faster, but still 83% of the time is spent in compile() (there are fewer calls to compile due to differences in what runs in the build file).
For comparison, here is the result from Fedora running in VirtualBox on the same machine:
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 9.330 9.330 meson.py:17(<module>)
490 0.023 0.000 6.775 0.014 compilers.py:747(compile)
So, compile() is roughly an order of magnitude slower on Windows, and about twice as slow with mingw-w64 compared to MSVC.
Please note that this is not specific to meson, but rather a general problem for some UN*X tools ported to Windows, see for instance this informal comparison.
So what could improve this? Some ideas:
Try to perform all checks in one compile()
For instance, I have a project that adds 10 extra warning flags for GCC, which are present on all recent versions. So the following cut the time to run meson from about 7 seconds to 3:
if build_machine.system() == 'windows' and cc.has_multi_arguments(test_flags)
extra_flags = test_flags
else
extra_flags = cc.get_supported_arguments(test_flags)
endif
This logic could easily be built into get_supported_arguments(), but of course it means an extra call to compile() if any of the flags do not work.
More functions like get_supported_arguments()
Having a function that handles multiple checks at once makes it possible to combine checks for specific platforms. For instance, get_supported_headers() and get_supported_functions().
Run checks in parallel
Either by running compile() in parallel, or by using the fact that for instance one call to MSVC can compile multiple source files.
Thanks for taking the time to do this investigation, it is well-received. :)
I've been thinking along exactly the same lines as you, and I agree with everything you've said.
However, everything you've said has not been done yet because it's quite difficult. For instance, running compiler checks in parallel can be done with async/await + parser changes to defer evaluation of compiler results till they are actually 'used' (f.ex in conditionals, or setting configuration data, etc), and after all that, build files have to be written to actually make optimal use of this (don't immediately branch after running a compiler check, etc).
The easiest thing we can do is to add a cache for all subprocess invocations which is invalidated when a list of 'depend files' changes (the executable being run + files it needs that we know of, f.ex, headers and .pc files), and when the user runs a new ninja command called ninja wipe-reconfigure. This will greatly help reconfigure and avoid duplicate checks when building with subprojects.
Do tell me if you wish to work on any of this. I can point you in the right direction. :)
See also: https://github.com/rkern/line_profiler https://github.com/mesonbuild/meson/issues/2773