Skip to content

8365053: Refresh hotspot precompiled.hpp with headers based on current frequency #26681

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

fandreuz
Copy link
Contributor

@fandreuz fandreuz commented Aug 7, 2025

In this PR I propose to refresh the included headers in hotspot precompiled.hpp. The current set of precompiled headers was refreshed in 2018, 7 years ago. I repeated the same operations and measurements after refreshing the set of precompiled headers according to the current usage frequency.

These are the results I observed. Depending on the platform, the improvement is between 10 and 20% in terms of total work (user+sys). The results are in seconds.

linux-x64 GCC
master      real 81.39 user 3352.15 sys 287.49
JDK-8365053 real 81.94 user 3030.24 sys 295.82

linux-x64 Clang
master      real 43.44 user 2082.93 sys 130.70
JDK-8365053 real 38.44 user 1723.80 sys 117.68

linux-aarch64 GCC
master      real 1188.08 user 2015.22 sys 175.53
JDK-8365053 real 1019.85 user 1667.45 sys 171.86

linux-aarch64 clang
master      real 981.77 user 1645.05 sys 118.60
JDK-8365053 real 791.96 user 1262.92 sys 101.50

Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8365053: Refresh hotspot precompiled.hpp with headers based on current frequency (Enhancement - P4)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/26681/head:pull/26681
$ git checkout pull/26681

Update a local copy of the PR:
$ git checkout pull/26681
$ git pull https://git.openjdk.org/jdk.git pull/26681/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 26681

View PR using the GUI difftool:
$ git pr show -t 26681

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/26681.diff

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Aug 7, 2025

👋 Welcome back fandreuz! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Aug 7, 2025

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk openjdk bot added the rfr Pull request is ready for review label Aug 7, 2025
@openjdk
Copy link

openjdk bot commented Aug 7, 2025

@fandreuz To determine the appropriate audience for reviewing this pull request, one or more labels corresponding to different subsystems will normally be applied automatically. However, no automatic labelling rule matches the changes in this pull request. In order to have an "RFR" email sent to the correct mailing list, you will need to add one or more applicable labels manually using the /label pull request command.

Applicable Labels
  • build
  • client
  • compiler
  • core-libs
  • graal
  • hotspot
  • hotspot-compiler
  • hotspot-gc
  • hotspot-jfr
  • hotspot-runtime
  • i18n
  • ide-support
  • javadoc
  • jdk
  • jmx
  • net
  • nio
  • security
  • serviceability
  • shenandoah

@fandreuz
Copy link
Contributor Author

fandreuz commented Aug 7, 2025

/label hotspot build

@openjdk
Copy link

openjdk bot commented Aug 7, 2025

@fandreuz
The hotspot label was successfully added.

The build label was successfully added.

@mlbridge
Copy link

mlbridge bot commented Aug 7, 2025

@shipilev
Copy link
Member

shipilev commented Aug 7, 2025

Also, maybe check in the generation script as well? I think a subfolder here would be fine: https://github.com/openjdk/jdk/tree/master/src/utils. It would be nice if the output of that script could be simply piped into precompiled.hpp, so we can use it later without extra work.

We can, technically, hook it up a similar way SortIncludes.java is currently done, but I think it is unnecessary at this point. In a perfect world we would not be needing precompiled headers. In less ideal world, having a jtreg test that warns us that a new popular header appeared, or that older header is not as popular anymore, would be handy. Again, this is something out of scope for this PR.

@shipilev
Copy link
Member

shipilev commented Aug 7, 2025

On my M1, with some AV software that always get in the way, I am seeing 15% faster build, which saves about half a minute. This is great!

CONF=macosx-aarch64-server-fastdebug LOG=info make hotspot  
1245.30s user 230.07s system 640% cpu 3:50.49 total

CONF=macosx-aarch64-server-fastdebug LOG=info make hotspot  
1064.59s user 203.24s system 618% cpu 3:20.09 total

@erikj79
Copy link
Member

erikj79 commented Aug 7, 2025

I tried it on Windows. Build time for hotspot was basically the same before and after, so no regression at least. So I'm fine with this change.

@fandreuz
Copy link
Contributor Author

fandreuz commented Aug 7, 2025

Also, maybe check in the generation script as well? I think a subfolder here would be fine: https://github.com/openjdk/jdk/tree/master/src/utils. It would be nice if the output of that script could be simply piped into precompiled.hpp, so we can use it later without extra work.

We can, technically, hook it up a similar way SortIncludes.java is currently done, but I think it is unnecessary at this point. In a perfect world we would not be needing precompiled headers. In less ideal world, having a jtreg test that warns us that a new popular header appeared, or that older header is not as popular anymore, would be handy. Again, this is something out of scope for this PR.

I'll add the generation script, it looks like something that could be useful at some point in the future. I think there should be a human curator though and not respecting the check should not count as e.g. a test failure, because the process is not completely automatic.

For example, when the threshold is set to 50 I get this compilation error:

/jdk/src/hotspot/share/compiler/compilerEvent.cpp:59:36: error: redefinition of 'phase_names' with a different type: 'GrowableArray<const char *> *' vs 'const char *[100]'
static GrowableArray<const char*>* phase_names = nullptr;
                                   ^
/jdk/src/hotspot/share/opto/phasetype.hpp:147:20: note: previous definition is here
static const char* phase_names[] = {

It could happen with any threshold, even 130 as the codebase evolves.

@dholmes-ora
Copy link
Member

For example, when the threshold is set to 50 I get this compilation error:

How can we possibly get a compilation error when everything should build with PCH disabled?


// Count inclusion times for each header
Map<String, Integer> occurrences = new HashMap<>();
try (Stream<Path> paths = Files.walk(hotspotPath)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think walking the source tree is the wrong approach to gathering the data
about include counts. I think better is to do a build and then look at the
files /hotspot/variant-server/libjvm/objs/*.d. From that one can build
a completely accurate count of the transitive inclusions.

Copy link
Contributor Author

@fandreuz fandreuz Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed this hint, the latest version of the script checks the .d files.

Two observations:

  • The magic number is now 2460 (more includes are taken into account, which makes sense)
  • There is much less wiggle room, 2461 includes nothing, 2459 includes too much
  • Runtime does not seem to be affected negatively or positively

If anybody is interested, this file contains the inclusion count for each source file: inclusions_count.txt

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something seems wrong with these numbers.

  • There are 538 headers with include counts of 2460.
  • There are only 1121 .o.cmdline files.

So how do we get include counts that are greater (by more than a factor of 2)
than the number of .d files?

Note that precompiled.hpp has an include count of 2456. There's 1 .d file that
depends on everything - BUILD_LIBJVM.d. That probably ought to be excluded
from counting, although I guess it should just add one to every file.

Also, precompiled.hpp has an include count of 2456, so not the maximum count,
but close. Which is itself weird that it wouldn't be the most included file.
But it's hard to guess what might be going on with that until the surprising
high include count > number of .d files is understood.

That include count listing would also be more useful of sorted by count.

Copy link
Contributor Author

@fandreuz fandreuz Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that precompiled.hpp has an include count of 2456. There's 1 .d file that
depends on everything - BUILD_LIBJVM.d. That probably ought to be excluded
from counting, although I guess it should just add one to every file.

Apparently BUILD_LIBJVM.d mentions all files multiple times:

% grep "utilities/waitBarrier.hpp" build/clang/hotspot/variant-server/libjvm/objs/BUILD_LIBJVM.d | wc -l
1231

It's definitely reasonable to exclude it, I did it in the latest revision of the script.

Now, the numbers seem more reasonable:

% ls build/clang/hotspot/variant-server/libjvm/objs/*.d | grep -v BUILD | wc -l
1232

% grep "code/codeCache.hpp" build/clang/hotspot/variant-server/libjvm/objs/*.d | \
            grep -v BUILD | sort | uniq | wc -l
1230

% grep "code/codeCache.hpp" inclusions_count.txt
code/codeCache.hpp=1230

Updated inclusions_count.txt

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this means that other .d files might include a header multiple times, too. Is it reasonable to count only the number of files containing a header instead of number of appearances?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this means that other .d files might include a header multiple times, too.

From the following two numbers, I deduce code/codeCache.hpp is (transitively) included in 1230 files, with each inclusion coming from a unique .d file. Am I missing something?

% grep "code/codeCache.hpp" build/clang/hotspot/variant-server/libjvm/objs/*.d | grep -v BUILD | sort | wc -l
1230

% grep "code/codeCache.hpp" build/clang/hotspot/variant-server/libjvm/objs/*.d | grep -v BUILD | sort | uniq | wc -l
1230

I haven't checked every single file, but I'd expect each include to appear at most once in each .d file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification, I think that it is fine, then, although a comment explaining in the code would be great.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect that the multiple includes reported in the .d files are accurate. The .d file appears
to report the number of times we #include a file, however, because if the include-guard
constructs we use, the content is pulled in only once.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The number of times a header is (directly or indirectly) included by a given
source file doesn't affect the number of times that header appears in the .d
file associated with that source file. The compiler uniquifies that set
(though links might confuse things, but that's not an issue here).

The .d files consist of a set of targets, and for each target, the set of
dependencies.

For the .d files, there's one target, .o, with its
dependencies (once each).

For BUILD_LIBJVM.d, there's a target for each .o file. And for each of those
targets, it's dependencies (once each). Essentially BUILD_LIBJVM.d includes a
concatenation of all the .d files. And since there are duplicates
among the dependencies of different targets, there are many(!) duplicates in
this file.

@@ -26,52 +26,38 @@
// --disable-precompiled-headers to configure.

// These header files are included in at least 130 C++ files, as of
// measurements made in November 2018. This list excludes files named
// *.inline.hpp, since including them decreased build performance.
// measurements made in August 2025.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's anything particularly special about the number 130.

Another thing to consider when a header file has a high include count is
whether it's being overincluded. We've had lots of those, and some folks
occasionally try to poke at that problem. Some of the removals here look like
they might be a result of such efforts.

Still another thing to consider is the cost of inclusion. Some files may just
be a lot more expensive to process and benefit more for being precompiled.
File size can be an indicator, but there are others. Unfortunately, I don't
know of a good way to measure this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to modify the comment here, too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I'll wait just a bit so the discussion on how to approach the problem stabilizes :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This number is based on my original experimentation. If I tried to lower the bar by lowering the number, the PCH list grew too much and it made for a worse performance. And contrary, if I raised the number, fewer files where included which made the PCH quicker to process but less helpful. That number was the optimum I found. It seems from https://bugs.openjdk.org/browse/JDK-8365053 that this is still around the optimum. However, rather than just mentioning the number in the comment, the rationale could be specified, like the optimum number of includes.

#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#include "utilities/ticks.hpp"

#ifdef TARGET_COMPILER_visCPP

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the reported testing was on Linux. These were included specifically because measurements
said their inclusion here was beneficial. And my recollection from previous discussions is that
Visual Studio may be the compiler where precompiled headers are most beneficial.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, Visual Studio is the place where PCH is most needed. I see Erik says he tested on Windows with no difference. While he concluded that this means no regression, I see it as a missed opportunity. Giving the Windows platform a bit of extra love can probably increase compilation speed where it is needed the most.

@fandreuz
Copy link
Contributor Author

fandreuz commented Aug 8, 2025

For example, when the threshold is set to 50 I get this compilation error:

How can we possibly get a compilation error when everything should build with PCH disabled?

Possibly some includes are inside namespaces or classes? I would have to check on this though.

@@ -26,52 +26,38 @@
// --disable-precompiled-headers to configure.

// These header files are included in at least 130 C++ files, as of
// measurements made in November 2018. This list excludes files named
// *.inline.hpp, since including them decreased build performance.
// measurements made in August 2025.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to modify the comment here, too.

@erikj79
Copy link
Member

erikj79 commented Aug 8, 2025

The latest version fails for me. I'm guessing because we exclude shenandoah by default for OracleJDK builds so having those headers in precompiled.hpp messes things up. I think we need to be careful with headers that are part of optional features.

@fandreuz
Copy link
Contributor Author

fandreuz commented Aug 8, 2025

The latest version fails for me. I'm guessing because we exclude shenandoah by default for OracleJDK builds so having those headers in precompiled.hpp messes things up. I think we need to be careful with headers that are part of optional features.

The last commit (be25d34) should fix the problem. I made a build with the following configuration:

./configure \
        --with-toolchain-type=clang \
        --disable-jvm-feature-shenandoahgc \
        --disable-jvm-feature-zero \
        --disable-jvm-feature-zgc \
        --disable-jvm-feature-g1gc \
        --disable-jvm-feature-parallelgc \
        --disable-jvm-feature-epsilongc

and then I ran the script on this build to extract the inclusions count. This could be included in the README file attached to this PR.

@kimbarrett
Copy link

The latest version fails for me. I'm guessing because we exclude shenandoah by default for OracleJDK builds so having those headers in precompiled.hpp messes things up. I think we need to be careful with headers that are part of optional features.

The last commit (be25d34) should fix the problem. I made a build with the following configuration:

./configure \
        --with-toolchain-type=clang \
        --disable-jvm-feature-shenandoahgc \
        --disable-jvm-feature-zero \
        --disable-jvm-feature-zgc \
        --disable-jvm-feature-g1gc \
        --disable-jvm-feature-parallelgc \
        --disable-jvm-feature-epsilongc

and then I ran the script on this build to extract the inclusions count. This could be included in the README file attached to this PR.

Other optional features include cds, c1, jfr, and jvmci, so files from those
directories also ought to be excluded.

The (current) list of optional features is here:
https://github.com/openjdk/jdk/blame/022e29a77533aacabd56820d00ecffa9646a8362/make/autoconf/jvm-features.m4#L47-L49

cds compiler1 compiler2 dtrace epsilongc g1gc jfr jni-check \
jvmci jvmti link-time-opt management minimal opt-size parallelgc \
serialgc services shenandoahgc vm-structs zero zgc \

Not all of these have their own directories. Even where they do, the feature
name and directory name aren't always the same. (The compiler1 feature and the
c1 directory being an obvious example.)

I didn't spot any files for other optional features in the latest list, other
than the ones called out in the first sentence of this comment.

@dholmes-ora
Copy link
Member

Other optional features include cds, c1, jfr, and jvmci, so files from those directories also ought to be excluded.

Can't these just be conditionalized with an INCLUDE_xxx check instead of being excluded?

@magicus
Copy link
Member

magicus commented Aug 11, 2025

There is a handy shortcut for creating a build with all optional features disabled, --with-jvm-variants=custom.

@kimbarrett
Copy link

Other optional features include cds, c1, jfr, and jvmci, so files from those directories also ought to be excluded.

Can't these just be conditionalized with an INCLUDE_xxx check instead of being excluded?

Yeah, that might be better than excluding altogether. But still need to figure out which files to (conditionally) exclude.

@magicus
Copy link
Member

magicus commented Aug 11, 2025

Also, maybe check in the generation script as well? I think a subfolder here would be fine: https://github.com/openjdk/jdk/tree/master/src/utils.

@shipilev I'm not sure this is a proper place. The other tools in src/utils are stand-alone utilities that could be useful to end users, like hsdis and IdealGraphVisualizer. In contrast, tools that are useful for developers are put either into bin or make/scripts. Normally, I think bin is what would make most sense, and the latter is mostly a legacy result of people using make as a misc back in the bad old hg-forest days, but in this particular case I think it might be the best placement. This is after all clearly about optimizing the build speed.

@magicus
Copy link
Member

magicus commented Aug 11, 2025

But still need to figure out which files to (conditionally) exclude.

Maybe first make a baseline build with no optional features, and analyze the result with this tool. And then enable each individual feature, re-build and re-analyze, and see how it differs. If a file then makes it to the PCH list, it is useful when enabling that feature, and it is potentially only correct to include with that feature enabled, so it could be added with an include guard.

That will require a bit more manual work (unless this process too can be automated), but it will probably give the best results.

@fandreuz
Copy link
Contributor Author

But still need to figure out which files to (conditionally) exclude.

Maybe first make a baseline build with no optional features, and analyze the result with this tool. And then enable each individual feature, re-build and re-analyze, and see how it differs. If a file then makes it to the PCH list, it is useful when enabling that feature, and it is potentially only correct to include with that feature enabled, so it could be added with an include guard.

That will require a bit more manual work (unless this process too can be automated), but it will probably give the best results.

Hi @magicus, thanks for the hint. I'll give it a shot and post the results here!

@fandreuz
Copy link
Contributor Author

fandreuz commented Aug 11, 2025

Some results:

Features Time1 (s) Time2 (s) Change (s)
epsilongc 490.77 489.50 1.27
epsilongc cds 546.27 537.91 8.36
epsilongc compiler1 547.87 539.86 8.01
epsilongc compiler2 785.18 735.13 50.05
g1gc 682.44 666.40 16.04
epsilongc services 510.22 504.68 5.54
epsilongc services jfr 675.49 636.87 38.62
epsilongc jni-check 499.53 493.72 5.81
epsilongc compiler1 jvmci 589.74 591.32 -1.58
epsilongc compiler2 jvmci 852.46 806.35 46.11
epsilongc services jvmti 567.67 561.73 5.94
epsilongc link-time-opt 535.96 526.00 9.97
epsilongc management 508.63 504.53 4.10
epsilongc opt-size 507.03 498.58 8.45
parallelgc 525.78 517.38 8.40
serialgc 512.59 511.88 0.71
shenandoahgc 739.44 722.72 16.72
zgc 681.20 672.28 8.92
  • Time1 is the time (sys+user) it takes to complete make -h hotspot with the precompiled headers in be25d34 (>=400 includes in a custom build)
  • Time2: same as Time1, with the precompiled headers having >=400 includes in a custom build with all features in the first column

So, the third column measures how much we improve by taking new precompiled headers due to a specific features. I'd say the following are worth keeping behind an include guard:

@magicus
Copy link
Member

magicus commented Aug 11, 2025

  • link-time-opt

  • opt-size

I thought these should not really affect the set of files compiled (or included, which is what matters here)?

@fandreuz
Copy link
Contributor Author

fandreuz commented Aug 11, 2025

That's right @magicus, I rerun the script and I got only a 1.86s improvements for link-time-opt. I checked the includes in precompiled.hpp and indeed nothing changes when the analyzer runs on a build with link-time-opt. So, exactly the same build, just different build times. That's most likely noise.

I'd say, as a criteria we could use is:

  • Improvement > 10s (unlikely to be noise, but still possible, maybe 20s?)
  • new headers added to precompiled.hpp is not empty

@fandreuz
Copy link
Contributor Author

fandreuz commented Aug 11, 2025

Just found a bug in the script, I'm rerunning the whole thing.

@fandreuz
Copy link
Contributor Author

fandreuz commented Aug 11, 2025

Feature Baseline precompiled.hpp (Mean ±) Updated precompiled.hpp (Mean ±)
epsilongc 505.78 ± 9.08 499.36 ± 3.21
epsilongc cds 523.93 ± 9.42 510.68 ± 0.99
epsilongc compiler1 514.89 ± 2.28 518.67 ± 14.22
epsilongc compiler2 758.34 ± 5.56 736.65 ± 32.95
g1gc 674.96 ± 6.37 693.39 ± 23.25
epsilongc services jfr 707.45 ± 2.08 670.55 ± 1.50
epsilongc jni-check 522.61 ± 1.82 517.46 ± 1.67
epsilongc compiler1 jvmci 604.92 ± 4.23 600.61 ± 8.79
epsilongc compiler2 jvmci 836.85 ± 7.40 792.07 ± 16.18
epsilongc services jvmti 549.48 ± 6.87 553.74 ± 7.67
epsilongc management 486.56 ± 5.68 480.58 ± 4.59
epsilongc opt-size 476.57 ± 1.87 476.71 ± 1.23
parallelgc 497.28 ± 3.90 493.68 ± 2.19
serialgc 477.84 ± 0.86 476.14 ± 1.32
epsilongc services 476.99 ± 2.44 478.74 ± 3.47
shenandoahgc 676.10 ± 5.35 623.43 ± 3.11
zgc 620.95 ± 1.84 621.86 ± 4.35

±: maximum and minimum measurements

@magicus
Copy link
Member

magicus commented Aug 11, 2025

This looks like regressions for c1 and G1..? And/or a lot more variability in build time. Any idea what is causing that?

@fandreuz
Copy link
Contributor Author

I'm starting to think the high variability is a quirk of my environment. I ran the builds in a virtualized machine and I'm probably experiencing erratic behavior under high load.

I re-ran each combination fewer times (3, should still be enough to get an idea), and I'm observing more reasonable results:

Feature Baseline precompiled.hpp Updated precompiled.hpp
epsilongc 458.88 +/- 0.35 459.69 +/- 0.34
epsilongc cds 501.63 +/- 0.35 501.58 +/- 0.57
epsilongc compiler1 505.66 +/- 0.61 505.06 +/- 0.51
epsilongc compiler2 725.91 +/- 0.41 692.25 +/- 0.40
g1gc 630.73 +/- 0.02 624.24 +/- 0.35
epsilongc services jfr 625.54 +/- 1.45 592.37 +/- 1.00
epsilongc jni-check 461.19 +/- 0.14 461.79 +/- 0.89
epsilongc compiler1 jvmci 541.31 +/- 0.42 540.31 +/- 0.70
epsilongc compiler2 jvmci 758.13 +/- 0.71 724.80 +/- 0.21
epsilongc services jvmti 499.64 +/- 0.18 499.69 +/- 0.52
epsilongc management 450.82 +/- 0.62 451.38 +/- 0.59
epsilongc opt-size 446.44 +/- 0.56 446.16 +/- 0.12
parallelgc 467.23 +/- 0.19 466.89 +/- 0.41
serialgc 454.17 +/- 0.40 454.22 +/- 0.12
epsilongc services 453.82 +/- 0.21 453.59 +/- 0.51
shenandoahgc 658.17 +/- 0.50 647.44 +/- 0.40

This is the script I used.

@magicus
Copy link
Member

magicus commented Aug 12, 2025

Can you re-run the test with your updated and more stable testing setup with a default, out-of-the-box configured server variant, comparing the baseline PCH file with your updated one?

@magicus
Copy link
Member

magicus commented Aug 12, 2025

Your updated result seemed more reliable and probable, but they also do not differ that much from the baseline. I still saw a few improvements and no regression, so it might still be worth pursuing, but maybe your suggested change does not bring as much improvement as was first hinted at.

@fandreuz
Copy link
Contributor Author

Your updated result seemed more reliable and probable, but they also do not differ that much from the baseline. I still saw a few improvements and no regression, so it might still be worth pursuing, but maybe your suggested change does not bring as much improvement as was first hinted at.

I'd say individual improvements are a bit harder to observe in the kind of measurements I'm doing now, and the likelihood of measuring noise is higher. Also, the minimum inclusion threshold I'm using now is the same for all features, but that's unlikely to be optimal.

Maybe we could revert to the original approach (count inclusion for a typical build)? That proved to improve compile time, and I could hide non-standard headers behind an #if.

@magicus
Copy link
Member

magicus commented Aug 14, 2025

If I recall correctly the original approach was even simpler: I counted the number of #includes in the C++ source files, not in the dependency files of a particular build. Crude but effective, and left out discussions about differences between platforms and feature configurations. And then I had to do some adjustments for Windows where my approach of excluding inline files did not hold and caused a regression.

I think your approach seems more valid, but maybe we get stuck in details then instead...

But then again, this is basically an optimization problem (even if it is not about running code in the JVM, but about optimizing build speed) so there is no way around the mantra of measure, measure and measure again.

@fandreuz
Copy link
Contributor Author

If I recall correctly the original approach was even simpler: I counted the number of #includes in the C++ source files, not in the dependency files of a particular build. Crude but effective, and left out discussions about differences between platforms and feature configurations. And then I had to do some adjustments for Windows where my approach of excluding inline files did not hold and caused a regression.

That was also the initial approach in this PR, I got the suggestion from the first comments I got here.

But then again, this is basically an optimization problem (even if it is not about running code in the JVM, but about optimizing build speed) so there is no way around the mantra of measure, measure and measure again.

Yeah I see, I'll give it another shot next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

8 participants