Changes between Version 1 and Version 2 of AnalyzingBuildPerformance


Ignore:
Timestamp:
Oct 7, 2021, 12:14:30 PM (3 years ago)
Author:
jer.noble@apple.com
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AnalyzingBuildPerformance

    v1 v2  
    1818== Building WebKit with tracing enabled ==
    1919
    20 1. Clean your build directory (but make sure it still _exists_).
     201. Clean your build directory (but make sure it still ''exists'').
    21212. `ClangBuildAnalyzer --start path/to/WebKitBuild`
    22223. `make debug ARGS='OTHER_CFLAGS=-ftime-trace OTHER_CPLUSPLUSFLAGS=-ftime-trace' `
     
    4646From this we can see that JSDOMGlobalObject.h is a very expensive header; it contributes about 3.3s of compile time, on average, to every source file which includes it. And it is included 246 times, which given the WebKit unified build system, means it is included by a majority of source files in the WebCore project. For these expensive headers, its often the case that the "expensive" header is expensive due to including other expensive headers, and one approach to make that header less expensive is to forward declare types rather than include their definitions. In cases where inline implementations of methods make forward declaration impossible, those inline definitions can be moved into a `<Type>Inlines.h` file, and the original declarations annotated with `inline`. Source files which contain references to those inline functions must include the `<Type>Inlines.h` file, or the compile will generate a `-Wundefined-inline` error.
    4747
     48=== Header Best Practices ===
     49
     50While resolving some expensive headers, a few best practices stood out to reduce compilation times without regressing runtime performance:
     51
     52==== Forward-declare all the things ====
     53
     54Forward-declaring types used by your class's methods allows clients who don't call those methods to not incur the compile-time cost of including those types' headers.
     55
     56C++ class members must be fully defined, so e.g. consider using `UniqueRef<MyClass>`, and forward-declaring `MyClass`, instead of including `MyClass.h`.
     57
     58C++ function parameters and return values do not need to be fully defined, and can be forward-declared. So e.g. if `MyClass` function parameter or return value, consider forward-declaring `MyClass`, instead of including `MyClass.h`.
     59
     60C++ virtual functions are rarely able to be inlined, even if decorated with `inline`, so avoid inline definitions of virtual functions. So e.g. if defining a virtual base class method that returns a `Ref<MyClass>`, put the default implementation inside the class implementation file.
     61
     62==== Avoid class-scoped enums ====
     63
     64When defining a public enumeration for a class, do so at namespace scope rather than inside the class, and always specify an explicit enum size. E.g.:
     65
     66Bad:
     67{{{
     68#!c++
     69// MyClass.h
     70class MyClass {
     71public:
     72    enum Options {
     73        Option1,
     74        Option2,
     75        Option3,
     76    };
     77...
     78};
     79}}}
     80
     81Good:
     82{{{
     83#!c++
     84// MyClass.h
     85enum class MyClassOptions : uint8_t {
     86    Option1,
     87    Option2,
     88    Option3,
     89};
     90class MyClass {
     91public:
     92...
     93};
     94}}}
     95
     96This allows clients to forward declare the enum type, rather than include `MyClass.h`:
     97{{{
     98#!c++
     99// YourClass.h
     100enum class MyClassOptions : uint8_t;
     101class YourClass {
     102    void functionWithMyClassOptions(MyClassOptions);
     103};
     104}}}
     105
     106==== Add Inlines.h headers ====
     107
     108When explicitly inlining a function definition for performance reasons, and that definition requires including an external header, putting the inline definition in an Inlines.h header file. Annotate the class method declaration with `inline`, which will cause a compiler warning if the Inline.h header is not included by the caller. E.g.:
     109
     110Bad:
     111{{{
     112#!c++
     113// MyClass.h
     114#include "YourClass.h"
     115class MyClass {
     116public:
     117    YourClass& yourClassGetFoo() { return YourClass::foo(); }
     118};
     119}}}
     120
     121Good:
     122{{{
     123#!c++
     124// MyClass.h
     125class MyClass {
     126public:
     127    inline YourClass& yourClassGetFoo();
     128};
     129
     130// MyClassInlines.h
     131inline YourClass& MyClass::yourClassGetFoo() { return YourClass::foo(); }
     132}}}