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

Random "header hygiene" cleanups #1880

Merged
merged 20 commits into from
Oct 6, 2022
Merged

Random "header hygiene" cleanups #1880

merged 20 commits into from
Oct 6, 2022

Conversation

mosra
Copy link
Collaborator

@mosra mosra commented Sep 30, 2022

Motivation and Context

Original message on Slack:

I was switching among many habitat branches recently and noticed a funny thing:

  • rebuilding 122 targets via ninja (just what got changed after a git checkout) takes 6 minutes 40 seconds
  • while building all of magnum, which is about 1280 targets, takes 2 minutes 5 seconds, so ~30x faster(!)

So I went to improve that a bit. Mostly about using forward declarations where that's enough and deinlining functions that rely on heavy headers. Tested via Clang's -ftime-trace on ReplayBatchRenderer.cpp, top is before and bottom after. (For reference, ReplayBatchRendererTest.cpp.json.zip is the bottom trace JSON, unzip and load e.g. in https://speedscope.app.)

image

The total time varies depending on system load, so don't pay too much attention to that. What matters is the percentage spent parsing included headers, which is the "Frontend" time minus "Perform pending instantiations". Before it was ~77%, now it's ~64%. Ideally the majority of time would be spent with actual compilation and not redundant header parsing, but I got some improvement at least.

The biggest issue is Eigen, taking about a quarter of all header parsing time. I moved its includes into a dedicated header so it's not included everywhere, yet it's still used in many widely-used structures such as CoordinateFrame or AgentState, so it gets still dragged into basically all test files.

Another significant issue is the ESP_SMART_POINTERS() macro. It provides short and sweet T::ptr, T::cptr and T::uptr typedefs, but the consequence is that they need the full definition of T in order to be used. Where it made a difference, I changed those to std::shared_ptr<T>, which needs just a forward declaration of T, not the full definition.

This is just a start, and there's still a lot of unnecessary dependencies between the headers. But the main ones, like Simulator.h or ResourceManager.h including everything else, are mostly fixed now, so at the very least you could have slightly faster incremental builds due to not having to recompile that much.

I ran out of time I wanted to spend on this, so feel free to enable -ftime-trace yourself and continue :)

How Has This Been Tested

😅

@facebook-github-bot facebook-github-bot added the CLA Signed Do not delete this pull request or issue due to inactivity. label Sep 30, 2022
Copy link
Contributor

@aclegg3 aclegg3 left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for cleaning things up :)

@Skylion007
Copy link
Contributor

@mosra Seems like some of these forward declarations are triggering :( : bugprone-forward-declaration-namespace

@mosra
Copy link
Collaborator Author

mosra commented Sep 30, 2022

/home/circleci/project/habitat-sim/src/deps/magnum/src/Magnum/Trade/Trade.h:100:7: error: no definition found for 'PhongMaterialData', but a definition with the same name 'PhongMaterialData' found in another namespace 'esp::gfx' [bugprone-forward-declaration-namespace,-warnings-as-errors]

Well, how am I supposed to fix this? :D This class is in both (Clang just doesn't know because it sees only the declarations), and there's many similar cases (MeshPrimitive, MeshData, ...). I'd say let's disable this check, it doesn't really prevent any errors.

Alternatively Habitat could have its own forward declaration headers but that won't really help here, I'm afraid.

@jturner65
Copy link
Contributor

Another significant issue is the ESP_SMART_POINTERS() macro. It provides short and sweet T::ptr, T::cptr and T::uptr typedefs, but the consequence is that they need the full definition of T in order to be used. Where it made a difference, I changed those to std::shared_ptr, which needs just a forward declaration of T, not the full definition.

Wow! I had no idea about that.

Copy link
Contributor

@jturner65 jturner65 left a comment

Choose a reason for hiding this comment

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

LGTM!

Those have a hardcoded assumption that any mesh is a GL mesh, and that
any material is a Phong material. Which is kinda true now, but it won't
be going forward.

Moreover, they weren't really used anywhere anyway, so there's no point
in having them at all.
The magnum.h header now contains SceneGraph forward declarations
typedefs and only that. It doesn't and shouldn't pull in also GL or
Trade stuff.
It's still pulled into far too many places, but this way it can at least
start getting gradually removed.
Not exactly sure what is it doing, but it's quite heavy. Unfortunately
most of the tests need it to set things up anyway, so it only helps
partially.

Also, the ::ptr typedefs are nice and all, but they mean one has to
include the whole class definition. Which is not necessary in 99% of
cases, so I'm converting T::ptr to the verbose std::shared_ptr<T> where
a forward declaration is enough.
Wow, imagine changing anything in any of those headers. Boom, everything
gets recompiled.
The static will *copy* the string into each and every object file that
directly or indirectly includes Asset.h.
I'm starting to run in circles, so let's stop here.
And why do you have custom PLY parsing and writing? And why are your
eyes so big?
It only worked so far because <Magnum/configure.h> was not included in
Logging.cpp and so MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS wasn't defined.
Now it is, and the anonymous namespace is in direct conflict with the
export macro.
Looks like there needs to be some Clang Tidy Tidy to ensure sanity of
Clang Tidy implementation. Ugh.
Why it wasn't a problem when it was in the header? Was it because you
didn't know that the ::ptr type is a std::shared_ptr? That's kinda lame,
no?
@@ -1256,7 +1256,7 @@ class ResourceManager {
* being rendered, since that mesh will have its components moved into actual
* render mesh constructs.
*/
std::unique_ptr<GenericSemanticMeshData> infoSemanticMeshData_{};
std::unique_ptr<GenericSemanticMeshData> infoSemanticMeshData_;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is one of the funnier STL workarounds I came across lately.

Without the {}, the type can be forward-declared and it will work as long as all constructors, assignment operators and destructors are deinlined in the file. With the {} however, a GCC 7 build will attempt to instantiate std::default_delete<GenericSemanticMeshData> each time the header is included anywhere, failing if the type definition is not known.

@mosra
Copy link
Collaborator Author

mosra commented Oct 6, 2022

Okay, I think all CI failures are resolved now, the remaining one is related to #1890.

Let me know if this is okay to merge -- the newly added commits are just minor things, nevertheless they happened after all approvals so I want to be sure ;)

@Skylion007 I ended up disabling the bugprone-forward-declaration-namespace Clang Tidy check if that's alright. See the comment added to .clang-tidy for details.

@0mdc
Copy link
Contributor

0mdc commented Oct 6, 2022

Nice cleanup!

@mosra mosra merged commit f9d7446 into main Oct 6, 2022
@mosra mosra deleted the header-hygiene branch October 6, 2022 17:56
aclegg3 pushed a commit that referenced this pull request Oct 6, 2022
* Remove unused and wrong Magnum typedefs.

Those have a hardcoded assumption that any mesh is a GL mesh, and that
any material is a Phong material. Which is kinda true now, but it won't
be going forward.

Moreover, they weren't really used anywhere anyway, so there's no point
in having them at all.

* Don't include all of Magnum everywhere for no reason.

The magnum.h header now contains SceneGraph forward declarations
typedefs and only that. It doesn't and shouldn't pull in also GL or
Trade stuff.

* Contain Eigen into a separate header, not the main main header.

It's still pulled into far too many places, but this way it can at least
start getting gradually removed.

* Use Magnum's forward declaration headers, not manual declarations.

* Don't include MetadataMediator in Simulator.h and ResourceManager.h.

Not exactly sure what is it doing, but it's quite heavy. Unfortunately
most of the tests need it to set things up anyway, so it only helps
partially.

Also, the ::ptr typedefs are nice and all, but they mean one has to
include the whole class definition. Which is not necessary in 99% of
cases, so I'm converting T::ptr to the verbose std::shared_ptr<T> where
a forward declaration is enough.

* Remove most includes from ResourceManager.h.

Wow, imagine changing anything in any of those headers. Boom, everything
gets recompiled.

* Stop including ResourceManager from all headers.

* This is not the right way to create a string constant.

The static will *copy* the string into each and every object file that
directly or indirectly includes Asset.h.

* Disable a useless Clang Tidy check.

* Fix definition of the global logging context variable.

It only worked so far because <Magnum/configure.h> was not included in
Logging.cpp and so MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS wasn't defined.
Now it is, and the anonymous namespace is in direct conflict with the
export macro.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Do not delete this pull request or issue due to inactivity.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants