This is an archive of the discontinued LLVM Phabricator instance.

[clang][NFC] Add IsAnyDestructorNoReturn field to CXXRecord instead of calculating it on demand
ClosedPublic

Authored by zero9178 on Jun 12 2021, 8:47 AM.

Details

Summary

This patch addresses a performance issue I noticed when using clang-12 to compile projects of mine. Even though the files weren't too large (around 1k cpp), the compiler was taking more than a minute to compile the source file, much longer than either GCC or MSVC.

Using a profiler it turned out the issue was the isAnyDestructorNoReturn function in CXXRecordDecl:

In particular it being recursive, recalculating the property for every invocation, for every field and base class. This showed up in tracebacks in the profiler as follows:

This patch instead adds IsAnyDestructorNoReturn as a Field to the data inside of CXXRecord and updates when a new base class, destructor, or record field member is added.

After this patch the problematic file of mine went from a compile time of 81s, down to 12s. The hotspots now look more normal as well:

The patch itself should not change any functionality, just improve performance.

Diff Detail

Event Timeline

zero9178 requested review of this revision.Jun 12 2021, 8:47 AM
zero9178 created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptJun 12 2021, 8:47 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

Was this performance hit when using the static analyzer? A quick search suggests isAnyDestructorNoReturn() is only called within the analyzer, whereas comparable CXXRecordDecl methods whose results are stored (hasIrrelevantDestructor() etc.) seem to be called somewhere by Sema.

So non-users of the analyzer would not benefit from this change, and will incur a slight cost, IIUC. Is that cost remotely noticeable? Probably not, but a quick test along those lines would be helpful.

All in all this is probably good and advisable.

Was this performance hit when using the static analyzer? A quick search suggests isAnyDestructorNoReturn() is only called within the analyzer, whereas comparable CXXRecordDecl methods whose results are stored (hasIrrelevantDestructor() etc.) seem to be called somewhere by Sema.

So non-users of the analyzer would not benefit from this change, and will incur a slight cost, IIUC. Is that cost remotely noticeable? Probably not, but a quick test along those lines would be helpful.

All in all this is probably good and advisable.

The only place where it is called in the static analyzer is in ExprEngineCXX.cpp:650. I was doing a normal compilation of a C++ file of mine, and they were coming from Analysis/CFG.cpp:1871 in addAutomaticObjDtors as well as CFG.cpp:4836 in VisitCXXBindTemporaryForDtors. So depending on the contents of the users C++ file it could improve their compilation speed as well. I suspect that in my case it was producing such a deep stacktrace due to a template class that is using a lot of layers of inheritance to preserve triviallity of constructors and more, tho that is just a guess. Nevertheless I'd wager it will more than likely improve the compile time for some other people as well.

As another test I just compared the compilation of X86ISelLowering.cpp from LLVM using clang-cl trunk, with and without this patch and could not measure any difference but margin of error. So it's definitely not guaranteed to be an improvement, but least isn't any worse.

davrec accepted this revision.Jun 12 2021, 6:17 PM
This revision is now accepted and ready to land.Jun 12 2021, 6:17 PM
This revision was landed with ongoing or failed builds.Jun 13 2021, 5:48 AM
This revision was automatically updated to reflect the committed changes.