Skip to content
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

Run codebase through IWYU and add a CI check. ~7-10% improvements to build times. #79631

Merged
merged 15 commits into from
Feb 12, 2025

Conversation

moxian
Copy link
Contributor

@moxian moxian commented Feb 11, 2025

Summary

None

Purpose of change

(This is a revival/continuation of #79239 following the advice from the comments therein.)
IWYU is a tool that checks that all the symbols used in C++ code are also actively #included. This is considered to be a good thing, some specific benefits being listed in their FAQ
This PR fixes [a decent chunk of the code] to include what it uses.
It also adds a CI job aimed to maintain the correct includes going forward, so as to prevent backsliding and the need for these massive sweeping PRs.

Describe the solution

  • Add the CI job
  • Add a mechanism to opt out certain files from being checked by the CI
  • Opt out literally everything initially.
  • Run IWYU on the "easy" code. Make the changes to please the tool.
    "Easy" here meaning "everything under tests/ and those files under src/ that have no define shenanigans in them whatsoever"
  • Keep automated commits separate from manual fixes, and keep track of the code size metrics througout the process (as requested in the previous CI)

Code size

step includes
src/
includes
tests/
clang -E
src/
clang -E
test/
initial 288068 171408 68567896 40671408
IWYU tests/ 288068 167044 68567896 39341957
fixes 289634 168196 69096536 40499273
IWYU src/ --safe_headers 290436 168196 69365093 40499273
fixes 290441 168196 69365837 40499273
IWYU src/ --nosafe_headers 276953 162948 65627805 38287614
fixes 278247 163745 65903054 38434408
absolute difference
start to finish
-9821 -7663 -2664842 -2237000
relative difference -3.4 % -4.5% -3.9% -5.5%

Here:

  • the "includes" column means, roughly make includes && cat obj/*.inc | wc -l - i.e. the total size of recorded include.. paths? relations? dependencies? idk how to word this properly.
  • the clang -E column representes, rougjly clang -E src/*.cpp | wc -l, i.e. the total size of the codebase after the preprocessor has run and #includes were, well, included.

The make includes was run wtih TILES=1 SOUND=1 RELEASE=1 LOCALIZE=1 BACKTRACE=1, the clang -E was run with flags from the equivalent cmake build. On WSL Ubuntu 24.04

Build times

I have measured build times without the change (matrix win) and with it (matrix win), basing on 9492421 with ccache disabled. Results:

without IWYU with IWYU diff delta
windows 43m 3s 39m 53s -3m 10s -7.4%
basic build 35m 9s 32m 6s -3m 3s -8.7%
gcc 9 lto 39m 15s 32m 23s -6m 52s -17.5%
clang 18 asan 47m 0s 42m 22s -4m 38s -9.9%
gcc 12 asan 60m 52s 55m 20s -5m 32s -9.1%
gcc 9 cmake 29m 17s 26m 30s -2m 47s -9.5%

Looks like 7-10% build time improvement (although that's perhaps not too impressive when it translates to only a couple of minutes absolute difference).

Future work

There is ample opportunity to improve:

  • Roughly 30% of the cpp files under src/ are still opted out. Some of those are really low hanging fruit and would be straightforward to fix.
  • The IWYU CI job currently runs on every PR, even json-only, but that would be easy to fix. Edit: should be fixed now
  • The CI job currently runs on every cpp file, not only those affected by the change, and that would be slightly more tricky to fix, but still not too bad. The CI runtime is ~30minutes right now, I think this is acceptable in the short term.
  • The documentation lacking.
  • Only the barebones (TILES=0 SOUND=0 etc) configuration is tested for IWYU'ness.
  • There's a minor issue with IWYU in that it recommends #include <stddef.h> for size_t which immediately triggers clang-tidy complaint to modernize stddef.h to cstddef. This is not fixable with IWYU config, but perhaps we can post-process its output and tweak the error message to the correct one.

Testing

CI

Additional context

Edit: Resolved, thanks Kevin!
There are pre-existing merge conflicts. I don't particularly want to waste more time on this if this PR is not something that's desired (because based on the previous interaction, I'm still not sure whether it is), so I won't be fixing those until there is some form of approval from whoever is willing to actually merge it.

(and also if there are requests to change the CI, it'd be easier to work on that first, and only then, after said requests are satisfied, fix the conflicts)

I don't have a PR with a failing IWYU CI handy anymore, but this is what the logs look like when it does make suggestions: https://github.com/moxian/Cataclysm-DDA/actions/runs/13210360655

For reviewers: This is perhaps more feasible to review commit-by-commit. I kept the mechanical changes separate from the manual ones, although I'm still not sure if that helps with the review.

CI status in my fork until (until CI here catches up) - moxian#22 ; https://github.com/moxian/Cataclysm-DDA/pull/22/checks?check_run_id=36989468855

If this PR is merged, then other PRs would likely get merge conflicted. I would suggest those accept all the headers, and ignore the IWYU suggestions/breakage to get unblocked, since it can get confusing. It can be fixed in a separate PR later.

I'll keep track of code size throughout this IWYU endeavor.

Two metrics:
1) include size, as measured by `make include` -> `cat *.inc | wc`
2) total preprocessed (post-processed?) source size as measured
by `clang -E` -> `cat * | wc`

All numbers are for RELEASE=1 SOUND=1 TILES=1 BACKTRACE=1 LOCALIZE=1
build on linux (WSL, ubuntu 24.04)
These might get slightly off if I end up rebasing the work (which
I hope I won't have to), but should capture the spirit of the change.

As of right now, before any contentful edits:

Code size:
includes:
cat obj/tiles/*.inc | wc
 288068  576136 17898260
cat tests/obj/tiles/*.inc | wc
 171408  342816 10682390

post-processed source (clang -E):
./make_preproc.sh src/
68567896 177775140 2134075721
./make_preproc.sh tests/
40671408 106495252 1283817257
python3 ~/github/include-what-you-use/iwyu_tool.py -j5 -p build $( find
src/ tests/ -maxdepth 1 -name '*.cpp' | grep -v -f
tools/iwyu/bad_files.txt )  --  -Xiwyu --comment_style=long -Xiwyu -
-max_line_length=1000 -Xiwyu --cxx17ns -Xiwyu
--mapping_file=../tools/iwyu/cata.imp   | tee out/iwyu/f-a-01.txt >
/dev/null

followed by

cat out/iwyu/f-a-02.txt | python3
~/github/include-what-you-use/fix_includes.py --reorder --nosafe_headers

followed by manual fixups of <stddef.h> -> <cstddef> and similar.

tests/generic_factory_test.cpp gets mangled very badly (IWYU bug) so
it's excluded from the list.

Code size:
includes:
$ cat obj/tiles/*.inc | wc
 288068  576136 17898260
$ cat tests/obj/tiles/*.inc | wc
 167044  334088 10465766

post-processed source (clang -E):
./make_preproc.sh src/
68567896 177775140 2134075721
./make_preproc.sh tests/
39341957 102891720 1243323710
Code size:
includes:
$ cat obj/tiles/*.inc | wc
 288068  576136 17898260
$ cat tests/obj/tiles/*.inc | wc
 167044  334088 10465935

post-processed source (clang -E):
./make_preproc.sh src/
68567896 177775140 2134075721
./make_preproc.sh tests/
39342173 102892081 1243328627
I'm not quite sure why IWYU stumbles over these
but clang builds the files totally fine, but oh well.

Code size:
includes:
$ cat obj/tiles/*.inc | wc
 289205  578410 17936655
$ cat tests/obj/tiles/*.inc | wc
 168063  336126 10504341

post-processed source (clang -E):
./make_preproc.sh src/
68951553 178823261 2145455631
./make_preproc.sh tests/
39688267 103830363 1253702866
because having multiple files (re-)define the same thing is confusing
and bugprone.
Note how activity_item_handling.cpp definiton was slightly different
from the rest (and also never used)

Code size:
includes:
$ cat obj/tiles/*.inc | wc
 289634  579268 17954860
$ cat tests/obj/tiles/*.inc | wc
 168196  336392 10510740
post-processed (clang -E):
cat ./out/pp/src/* | wc
69096536 179224518 2150572312
cat ./out/pp/tests/* | wc
40499273 106027071 1277878587
... three times, until it stops making new suggestions.
Run with --safe_headers (default) (i.e. headers can only
get new includes added, but can't get anything removed)
The code does not compile in current state (kinda expected),
manual fixups will follow.
--nosafe_headers commit would also follow afterwards

The "simple" files are those that don't have any sort of
define/if defined/ifndef conditional compilation in them.
Just plain old c++ with no preprocessor.

Code size:
includes:
$ cat obj/tiles/*.inc | wc
 290436  580872 17972230
$ cat tests/obj/tiles/*.inc | wc
 168196  336392 10510740
post-processed (clang -E):
cat ./out/pp/src/* | wc
69365093 179919823 2157445134
cat ./out/pp/tests/* | wc
40499273 106027071 1277878587

The code size increase is expected due to --safe_headers
Code size:
includes:
$ cat obj/tiles/*.inc | wc
 290441  580882 17972409
$ cat tests/obj/tiles/*.inc | wc
 168196  336392 10510740
post-processed (clang -E):
cat ./out/pp/src/* | wc
69365837 179921404 2157462252
cat ./out/pp/tests/* | wc
40499273 106027071 1277878587
Code most likely doesn't build anymore, will fix.

Code size:
includes:
$ cat obj/tiles/*.inc | wc
 276953  553906 17327802
$ cat tests/obj/tiles/*.inc | wc
 162948  325896 10274699

post-processed source (clang -E):
./make_preproc.sh src/
65627805 169571983 2041450272
./make_preproc.sh tests/
38287614 99918518 1211467858
.. and ensure iwyu is still happy with this
(i.e. it's not suggesting i change anything else)

Code size:
includes:
$ cat obj/tiles/*.inc | wc
 278246  556492 17375633
$ cat tests/obj/tiles/*.inc | wc
 163748  327496 10306945

post-processed source (clang -E):
./make_preproc.sh src/
65903052 170378728 2049783276
./make_preproc.sh tests/
38434368 100326839 1215848465
Code size:
includes:
$ cat obj/tiles/*.inc | wc
 278247  556494 17375710
$ cat tests/obj/tiles/*.inc | wc
 163745  327490 10307041

post-processed source (clang -E):
./make_preproc.sh src/
65903054 170378741 2049783477
./make_preproc.sh tests/
38434408 100326802 1215849078
@github-actions github-actions bot requested review from dseguin and KorGgenT February 11, 2025 09:01
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Auto-requesting reviews from non-collaborators: @jbytheway @wapcaplet @andrei8l

@github-actions github-actions bot added NPC / Factions NPCs, AI, Speech, Factions, Ownership Info / User Interface Game - player communication, menus, etc. Translation I18n Items: Magazines Ammo holding items and objects. Missions Quests and missions Bionics CBM (Compact Bionic Modules) Map / Mapgen Overmap, Mapgen, Map extras, Map display Vehicles Vehicles, parts, mechanics & interactions Items: Food / Vitamins Comestibles and drinks Items: Battery / UPS Electric power management Crafting / Construction / Recipes Includes: Uncrafting / Disassembling Mutations / Traits / Professions/ Hobbies Mutations / Traits / Professions/ Hobbies Code: Tests Measurement, self-control, statistics, balancing. [C++] Changes (can be) made in C++. Previously named `Code` Monsters Monsters both friendly and unfriendly. Fields / Furniture / Terrain / Traps Objects that are part of the map or its features. Items: Ammo / Guns Ammunition for all kinds of weapons and these weapons themselves labels Feb 11, 2025
@github-actions github-actions bot added Martial Arts Arts, Techniques, weapons and anything touching martial arts. Items: Armor / Clothing Armor and clothing Limbs Limbs, mutable limbs, and code related to them. EOC: Effects On Condition Anything concerning Effects On Condition labels Feb 11, 2025
@kevingranade
Copy link
Member

I can say up front that based on the magnitude of improvements in preprocessed files and build times, and the CI and opt-in workflows being included, I AM interested in getting this merged.

@akrieger akrieger requested review from akrieger and kevingranade and removed request for dseguin and KorGgenT February 11, 2025 19:16
@akrieger akrieger self-assigned this Feb 11, 2025
@github-actions github-actions bot requested review from dseguin and KorGgenT February 11, 2025 19:17
@github-actions github-actions bot added json-styled JSON lint passed, label assigned by github actions astyled astyled PR, label is assigned by github actions labels Feb 11, 2025
@akrieger
Copy link
Member

The github web UI just yeets itself off a cliff on this PR. Can we PR some of the noncontroversial changes separately to help ease this in (eg. the c header modernization stuff can be trivally merged by itself).

@moxian
Copy link
Contributor Author

moxian commented Feb 11, 2025

Reviewing this commit-by-commit should help.
The modernize-headers is a response to the changes in previous commit (specifically "Mechanically IWYU the tests" one) since i didn't catch those in time. It is uselesss on its own (and unmergeable really)

There only three kinds of changes here:

  • add the CI (first commit, reviewable in github web)
  • two huge mechanical passes (unreviewable)
  • manual fixups (reviewable again)

I'm not sure submitting any of those separately would help enough.

edit: well, i guess i can move out 28db853 and 0c8954a . But, again, i don't think this is quite enough to make things beter.

Copy link
Member

@akrieger akrieger left a comment

Choose a reason for hiding this comment

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

Some quick review comments before you do too much more. I got down to around src/construction.cpp and find it unlikely I'll see something else generic to suggest.

Also maybe add to flexbuffer_json.h although I haven't seen it show up as an unnecessary addition much anywhere.

#include "json_error.h" // IWYU pragma: export

tools/iwyu/cata.imp Show resolved Hide resolved
src/coordinates.h Outdated Show resolved Hide resolved
src/cata_variant.h Show resolved Hide resolved
@github-actions github-actions bot added the BasicBuildPassed This PR builds correctly, label assigned by github actions label Feb 11, 2025
@moxian
Copy link
Contributor Author

moxian commented Feb 11, 2025

Minor issue i noticed: if there are no fatal parse errors, then IWYU exits with code 0 even if it made suggestions on how to adjust includes (see the current CI run: https://github.com/CleverRaven/Cataclysm-DDA/actions/runs/13272432900/job/37054800929?pr=79631)

Easily fixable, but I shall declare this as a feature for now, for the transition period.

@akrieger
Copy link
Member

Although I can't imagine how something might decide to barf at this point (if anything the Windows build would be most susceptible to header reordering), I'm sitting on the builds until they go green before merging.

@akrieger akrieger merged commit f0569d0 into CleverRaven:master Feb 12, 2025
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
astyled astyled PR, label is assigned by github actions BasicBuildPassed This PR builds correctly, label assigned by github actions Bionics CBM (Compact Bionic Modules) [C++] Changes (can be) made in C++. Previously named `Code` Character / World Generation Issues and enhancements concerning stages of creating a character or a world Code: Tests Measurement, self-control, statistics, balancing. Code: Tooling Tooling that is not part of the main game but is part of the repo. Crafting / Construction / Recipes Includes: Uncrafting / Disassembling EOC: Effects On Condition Anything concerning Effects On Condition Fields / Furniture / Terrain / Traps Objects that are part of the map or its features. Game: Achievements / Conducts / Scores Player goals and how they are tracked. Info / User Interface Game - player communication, menus, etc. Items: Ammo / Guns Ammunition for all kinds of weapons and these weapons themselves Items: Archery Bows, crossbows, arrows, bolts Items: Armor / Clothing Armor and clothing Items: Battery / UPS Electric power management Items: Containers Things that hold other things Items: Food / Vitamins Comestibles and drinks Items: Magazines Ammo holding items and objects. json-styled JSON lint passed, label assigned by github actions Limbs Limbs, mutable limbs, and code related to them. Lore Game lore, in-game communication. Also the Lore tab. Map / Mapgen Overmap, Mapgen, Map extras, Map display Martial Arts Arts, Techniques, weapons and anything touching martial arts. Mechanics: Enchantments / Spells Enchantments and spells Mechanics: Weather Rain, snow, portal storms and non-temperature environment Melee Melee weapons, tactics, techniques, reach attack Missions Quests and missions Monsters Monsters both friendly and unfriendly. Mutations / Traits / Professions/ Hobbies Mutations / Traits / Professions/ Hobbies NPC / Factions NPCs, AI, Speech, Factions, Ownership Player Faction Base / Camp All about the player faction base/camp/site Scenarios New Scenarios, balancing, bugs with scenarios Translation I18n Vehicles Vehicles, parts, mechanics & interactions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants