Bug 231283

Summary: [Build-time perf] Forward-declare more things in Element.h
Product: WebKit Reporter: Jer Noble <jer.noble>
Component: New BugsAssignee: Jer Noble <jer.noble>
Status: RESOLVED FIXED    
Severity: Normal CC: aboxhall, allan.jensen, andresg_22, annulen, apinheiro, berto, calvaris, cdumez, cfleizach, cgarcia, changseok, cmarcelo, darin, dbarton, dino, dmazzoni, eric.carlson, esprehn+autocc, ews-watchlist, fmalita, fred.wang, glenn, gustavo, gyuyoung.kim, hi, jamesr, japhet, jcraig, jdiggs, joepeck, kangil.han, keith_miller, kondapallykalyan, luiz, macpherson, mark.lam, menard, mifenton, mmaxfield, msaboff, pangle, pdr, philipj, ryuan.choi, saam, sabouhallawa, samuel_white, schenney, sergio, simon.fraser, tonikitoo, tzagallo, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch
none
Patch
ews-feeder: commit-queue-
Patch
none
Patch
ews-feeder: commit-queue-
Patch
none
Patch
none
Patch
none
Patch
none
Patch
ews-feeder: commit-queue-
Patch
none
Patch
none
Patch
ews-feeder: commit-queue-
Patch
none
Patch
none
Patch
ews-feeder: commit-queue-
Patch for landing none

Jer Noble
Reported 2021-10-05 23:46:47 PDT
[Build-time perf] Forward-declare more things in Element.h
Attachments
Patch (92.19 KB, patch)
2021-10-06 00:31 PDT, Jer Noble
no flags
Patch (88.42 KB, patch)
2021-10-06 01:02 PDT, Jer Noble
ews-feeder: commit-queue-
Patch (88.88 KB, patch)
2021-10-06 01:21 PDT, Jer Noble
no flags
Patch (98.90 KB, patch)
2021-10-06 09:31 PDT, Jer Noble
ews-feeder: commit-queue-
Patch (97.64 KB, patch)
2021-10-06 09:41 PDT, Jer Noble
no flags
Patch (184.62 KB, patch)
2021-10-06 11:51 PDT, Jer Noble
no flags
Patch (185.27 KB, patch)
2021-10-06 12:32 PDT, Jer Noble
no flags
Patch (185.73 KB, patch)
2021-10-06 12:47 PDT, Jer Noble
no flags
Patch (187.42 KB, patch)
2021-10-06 13:34 PDT, Jer Noble
ews-feeder: commit-queue-
Patch (190.80 KB, patch)
2021-10-06 14:58 PDT, Jer Noble
no flags
Patch (206.66 KB, patch)
2021-10-06 22:01 PDT, Jer Noble
no flags
Patch (324.25 KB, patch)
2021-10-07 14:46 PDT, Jer Noble
ews-feeder: commit-queue-
Patch (323.25 KB, patch)
2021-10-07 15:36 PDT, Jer Noble
no flags
Patch (326.99 KB, patch)
2021-10-07 15:50 PDT, Jer Noble
no flags
Patch (328.61 KB, patch)
2021-10-08 09:19 PDT, Jer Noble
ews-feeder: commit-queue-
Patch for landing (329.67 KB, patch)
2021-10-08 10:01 PDT, Jer Noble
no flags
Jer Noble
Comment 1 2021-10-06 00:31:48 PDT
Jer Noble
Comment 2 2021-10-06 01:02:15 PDT
Jer Noble
Comment 3 2021-10-06 01:21:32 PDT
Jer Noble
Comment 4 2021-10-06 09:31:58 PDT
Jer Noble
Comment 5 2021-10-06 09:41:23 PDT
Jer Noble
Comment 6 2021-10-06 11:51:37 PDT
EWS Watchlist
Comment 7 2021-10-06 11:53:00 PDT
Thanks for the patch. If this patch contains new public API please make sure it follows the guidelines for new WebKit2 GTK+ API. See https://trac.webkit.org/wiki/WebKitGTK/AddingNewWebKit2API
Darin Adler
Comment 8 2021-10-06 12:12:59 PDT
Comment on attachment 440401 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=440401&action=review Can we measure a build speed-up? I love these types of changes, and want to make sure we do them based on evidence. > Source/WebCore/ChangeLog:9 > + Replace as many #includes as possible with forward type declarations. To do so, split out the inline function > + definitions into their own ElementInlines.h header. How do we know when to add includes of ElementInines.h? Do we get compilation failures when we forget them? > Source/JavaScriptCore/heap/HandleForward.h:32 > +template <class T> class Handle; Better syntax: template<typename> class Handle; No need to include a name if it’s just "T". > Source/JavaScriptCore/heap/StrongForward.h:32 > +template <typename T, ShouldStrongDestructorGrabLock = ShouldStrongDestructorGrabLock::No> class Strong; I prefer this syntax: template<typename, ShouldStrongDestructorGrabLock = ShouldStrongDestructorGrabLock::No> class Strong; > Source/WebCore/html/HTMLMediaElement.h:588 > + void privateBrowsingStateDidChange(const PAL::SessionID&); This is an unfortunate change. Since a session ID is just a scalar, we would like to pass by value. The change to use const& should not be necessary. We should be able to compile a declaration without the class being defined, although not calls to the function. Did that not work? > Source/WebCore/html/HTMLMediaElement.h:953 > + void setControllerJSProperty(const char*, JSC::JSValue&&); This change doesn’t makes sense. JSValue is a scalar, and it doesn’t make sense to pass it by rvalue reference.
Jer Noble
Comment 9 2021-10-06 12:32:16 PDT
Joseph Pecoraro
Comment 10 2021-10-06 12:39:15 PDT
Comment on attachment 440415 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=440415&action=review > Source/WebCore/ChangeLog:22 > + With these changes in place, the net cost of Element.h during a typical build has gone from ~750s to ~57s. Nice!
Jer Noble
Comment 11 2021-10-06 12:47:43 PDT
Darin Adler
Comment 12 2021-10-06 12:55:55 PDT
Comment on attachment 440417 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=440417&action=review > Source/WebCore/dom/EventOptions.h:33 > +enum class EventIsTrusted : uint8_t { No, Yes }; > +enum class EventCanBubble : uint8_t { No, Yes }; > +enum class EventIsCancelable : uint8_t { No, Yes }; > +enum class EventIsComposed : uint8_t { No, Yes }; How about bool instead of uint8_t for these?
Jer Noble
Comment 13 2021-10-06 13:34:23 PDT
Jer Noble
Comment 14 2021-10-06 13:50:27 PDT
(Sorry Darin, not ignoring your comments; just trying to fix all the build errors first.)
Darin Adler
Comment 15 2021-10-06 14:00:41 PDT
(In reply to Jer Noble from comment #14) > (Sorry Darin, not ignoring your comments; just trying to fix all the build > errors first.) No rush.
Jer Noble
Comment 16 2021-10-06 14:01:42 PDT
(In reply to Darin Adler from comment #8) > Comment on attachment 440401 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=440401&action=review > > Can we measure a build speed-up? I love these types of changes, and want to > make sure we do them based on evidence. Clang recently added support for doing time-based profiling. Passing in the -ftime-trace flag to clang will generate .json files containing time information on a per-source-file, per-header, per-function, and per-template basis. I'm using a utility called ClangBuildAnalyzer <https://github.com/aras-p/ClangBuildAnalyzer> to pull all the .json files together for net timing information. Before these changes, that tool reported the following for Element.h: *** Expensive headers: 754617 ms: dom/Element.h (included 285 times, avg 2647 ms), included via: AttributeChangeInvalidation.cpp AttributeChangeInvalidation.h (6086 ms) RenderTreeUpdater.cpp RenderTreeUpdater.h RenderTreeBuilder.h RenderTreePosition.h RenderElement.h RenderObject.h (5736 ms) RenderTreeBuilderInline.cpp RenderTreeBuilderInline.h RenderTreeBuilder.h RenderTreePosition.h RenderElement.h RenderObject.h (5583 ms) PropertyCascade.cpp PropertyCascade.h ElementRuleCollector.h RuleSet.h RuleData.h SelectorFilter.h (5129 ms) SVGTextQuery.cpp LegacyInlineFlowBox.h LegacyInlineBox.h RenderBoxModelObject.h RenderLayerModelObject.h RenderElement.h RenderObject.h (4900 ms) StyleResolver.cpp StyleResolver.h ElementRuleCollector.h RuleSet.h RuleData.h SelectorFilter.h (4847 ms) Afterward: 57889 ms: dom/Element.h (included 287 times, avg 201 ms), included via: SelectorCompiler.cpp SelectorCompiler.h SelectorChecker.h (1171 ms) VisitedLinkState.cpp VisitedLinkState.h (1029 ms) AttributeChangeInvalidation.cpp AttributeChangeInvalidation.h (1013 ms) CachedScriptFetcher.cpp CachedResourceLoader.h CachedResourceRequest.h (1001 ms) JSHTMLOptionsCollection.cpp JSHTMLOptionsCollection.h HTMLOptionsCollection.h CachedHTMLCollection.h HTMLCollection.h LiveNodeList.h CollectionTraversal.h ElementIterator.h ElementTraversal.h (949 ms) PseudoElement.cpp PseudoElement.h (945 ms) ... > > Source/WebCore/ChangeLog:9 > > + Replace as many #includes as possible with forward type declarations. To do so, split out the inline function > > + definitions into their own ElementInlines.h header. > > How do we know when to add includes of ElementInines.h? > > Do we get compilation failures when we forget them? Unfortunately no; if you don't include ElementInlines.h you'll get a linker error, not a compile error. I'm searching for a mechanism to annotate these function declarations to generate a compiler error if you don't also include ElementInlines.h, but I haven't found it yet. > > Source/JavaScriptCore/heap/HandleForward.h:32 > > +template <class T> class Handle; > > Better syntax: > > template<typename> class Handle; > > No need to include a name if it’s just "T". Ok. > > Source/JavaScriptCore/heap/StrongForward.h:32 > > +template <typename T, ShouldStrongDestructorGrabLock = ShouldStrongDestructorGrabLock::No> class Strong; > > I prefer this syntax: > > template<typename, ShouldStrongDestructorGrabLock = > ShouldStrongDestructorGrabLock::No> class Strong; Ok. > > Source/WebCore/html/HTMLMediaElement.h:588 > > + void privateBrowsingStateDidChange(const PAL::SessionID&); > > This is an unfortunate change. Since a session ID is just a scalar, we would > like to pass by value. The change to use const& should not be necessary. We > should be able to compile a declaration without the class being defined, > although not calls to the function. Did that not work? Let me try that; I was under the impression that all function parameters had to be fully defined (but not function return types), but I absolutely could be mistaken. > > Source/WebCore/html/HTMLMediaElement.h:953 > > + void setControllerJSProperty(const char*, JSC::JSValue&&); > > This change doesn’t makes sense. JSValue is a scalar, and it doesn’t make > sense to pass it by rvalue reference. Same here. Will try.
Darin Adler
Comment 17 2021-10-06 14:06:47 PDT
(In reply to Jer Noble from comment #16) > I'm using a utility called ClangBuildAnalyzer > <https://github.com/aras-p/ClangBuildAnalyzer> to pull all the .json files > together for net timing information. One of the WebKit team best practices has been to put these kinds of analyses up where people can see them, leads to competition and teamwork to fix the problems. For example, long ago Kling put up a list of the largest functions, and we cut them down to size. I think you should consider putting this somewhere people can see it so they don’t need to learn to run the tool.
Darin Adler
Comment 18 2021-10-06 14:07:56 PDT
(In reply to Jer Noble from comment #16) > Unfortunately no; if you don't include ElementInlines.h you'll get a linker > error, not a compile error. Linker error in release builds only? Or linker error even in debug builds?
Jer Noble
Comment 19 2021-10-06 14:11:47 PDT
(In reply to Jer Noble from comment #16) > Unfortunately no; if you don't include ElementInlines.h you'll get a linker > error, not a compile error. I'm searching for a mechanism to annotate these > function declarations to generate a compiler error if you don't also include > ElementInlines.h, but I haven't found it yet. Oh duh. I was searching for things like __attribute__(always_inline), but the answer is much simpler: class Foo { public: inline void bar(); }; void test(Foo foo) { foo.bar(); } <source>:3:17: warning: inline function 'Foo::bar' is not defined [-Wundefined-inline] inline void bar(); ^ <source>:8:9: note: used here foo.bar(); ^ 1 warning generated. We just need to decorate all the inlined functions in ElementInlines.h with `inline` in Element.h.
Darin Adler
Comment 20 2021-10-06 14:15:18 PDT
(In reply to Jer Noble from comment #19) > We just need to decorate all the inlined functions in ElementInlines.h with > `inline` in Element.h. Seems like it would also be a big win to do this in the many places in JavaScriptCore that use this same idiom. And for functions where we define them in one header, but implement in another (Node.h vs. Element.h). This may not work quite as well for templates, but it sure does seem like it will help us a lot!
Jer Noble
Comment 21 2021-10-06 14:16:57 PDT
(In reply to Darin Adler from comment #17) > (In reply to Jer Noble from comment #16) > > I'm using a utility called ClangBuildAnalyzer > > <https://github.com/aras-p/ClangBuildAnalyzer> to pull all the .json files > > together for net timing information. > > One of the WebKit team best practices has been to put these kinds of > analyses up where people can see them, leads to competition and teamwork to > fix the problems. For example, long ago Kling put up a list of the largest > functions, and we cut them down to size. > > I think you should consider putting this somewhere people can see it so they > don’t need to learn to run the tool. That's a great idea. I'll put together a Wiki.
Jer Noble
Comment 22 2021-10-06 14:27:15 PDT
(In reply to Jer Noble from comment #16) > Let me try that; I was under the impression that all function parameters had > to be fully defined (but not function return types), but I absolutely could > be mistaken. And indeed I was mistaken; reverting that change (to just pass in a scalar) works just fine with a forward-definition. Will revert the other as well.
Jer Noble
Comment 23 2021-10-06 14:48:46 PDT
Decorating with `inline` revealed this fun warning/error: Source/WebCore/dom/Element.h:130:32: error: inline function 'WebCore::Element::hasAttributes' is not defined [-Werror,-Wundefined-inline] inline WEBCORE_EXPORT bool hasAttributes() const; ^ In file included from WebKitBuild/Debug/DerivedSources/WebCore/unified-sources/UnifiedSource5-mm.mm:7: In file included from ./accessibility/mac/AccessibilityObjectMac.mm:30: In file included from Source/WebCore/dom/ElementAncestorIterator.h:28: In file included from Source/WebCore/dom/ElementIterator.h:28: Source/WebCore/dom/ElementInlines.h:54:59: note: used here return is<Element>(*this) && downcast<Element>(*this).hasAttributes(); Looks like (A) this decoration works and (B) I have to make sure hasAttributes() appears first in ElementInlines.h.
Jer Noble
Comment 24 2021-10-06 14:49:45 PDT
(In reply to Jer Noble from comment #23) > Looks like (A) this decoration works and (B) I have to make sure > hasAttributes() appears first in ElementInlines.h. Disregard. (A) works but I mistakenly decorated Element::hasAttributes() instead of Node::hasAttributes().
Jer Noble
Comment 25 2021-10-06 14:58:43 PDT
Jer Noble
Comment 26 2021-10-06 22:01:12 PDT
Jer Noble
Comment 27 2021-10-07 14:46:37 PDT
Jer Noble
Comment 28 2021-10-07 15:36:30 PDT
Jer Noble
Comment 29 2021-10-07 15:50:33 PDT
Jer Noble
Comment 30 2021-10-07 15:51:08 PDT
FYI: here's the Wiki which I've been updating as I go: <https://trac.webkit.org/wiki/AnalyzingBuildPerformance>
Jer Noble
Comment 31 2021-10-08 09:19:54 PDT
Jer Noble
Comment 32 2021-10-08 10:01:43 PDT
Created attachment 440635 [details] Patch for landing
EWS
Comment 33 2021-10-08 16:32:03 PDT
Committed r283851 (242730@main): <https://commits.webkit.org/242730@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 440635 [details].
Radar WebKit Bug Importer
Comment 34 2021-10-08 16:34:01 PDT
Note You need to log in before you can comment on or make changes to this bug.