Some extra bits on that topic: if we're interested in decreasing the number of global constructor called at startup, the following recipe proves to be quite helpful: ``` # 1. make sure to deactivate unified build, as it makes tracking more difficult ./mach configure --disable-unified-build # 2. compile fx ./mach build # 3. count global constructors (assuming linux x86_64) nm obj-x86_64-pc-linux-gnu/dist/bin/libxul.so | grep -c _GLOBAL__sub_ # 4. this loop gathers the actual assembly code of each initialization, which make it easier to track origin nm obj-x86_64-pc-linux-gnu/dist/bin/libxul.so | grep _GLOBAL__sub_ | while read line ; do addr=`echo $line | cut -d ' ' -f1`; echo "###### $line ######" ; gdb --batch -ex 'file obj-x86_64-pc-linux-gnu/dist/bin/libxul.so' -ex "disass 0x$addr" | c++filt ; done | tee global-symbols.log # 5. explore global-symbols.log ``` Some notes: - the perfherder metric counts constructors on unified build, so constructors are aggregated - `-Wglobal-constructors` works at a syntax level. the compiler is often capable of optimizing those away, which is why we rely on the above - `constinit` would help a lot here, but it's C++20 - the `frozen` library would help in some cases, but it's an extra 3rd party library - `constexpr` is quite often the way to go. - local static variables are not stored as global constructors, but there access is always protected by a thread-safe guard, so there's a runtime cost
Bug 74803 Comment 99 Edit History
Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.
Some extra bits on that topic: if we're interested in decreasing the number of global constructor called at startup, the following recipe proves to be quite helpful: ``` # 1. make sure to deactivate unified build, as it makes tracking more difficult ./mach configure --disable-unified-build # 2. compile fx ./mach build # 3. count global constructors (assuming linux x86_64) nm obj-x86_64-pc-linux-gnu/dist/bin/libxul.so | grep -c _GLOBAL__sub_ # 4. this loop gathers the actual assembly code of each initialization, which make it easier to track origin nm obj-x86_64-pc-linux-gnu/dist/bin/libxul.so | grep _GLOBAL__sub_ | while read line ; do addr=`echo $line | cut -d ' ' -f1`; echo "###### $line ######" ; gdb --batch -ex 'file obj-x86_64-pc-linux-gnu/dist/bin/libxul.so' -ex "disass 0x$addr" | c++filt ; done | tee global-symbols.log # 5. explore global-symbols.log ``` Some notes: - the perfherder metric counts constructors on unified build, so constructors are aggregated - `-Wglobal-constructors` works at a syntax level. the compiler is often capable of optimizing those away, which is why we rely on the above - `constinit` would help a lot here, but it's C++20 - the `frozen` library would help in some cases, but it's an extra 3rd party library - `constexpr` is quite often the way to go. - local static variables are not stored as global constructors, but there access is always protected by a thread-safe guard, so there's a runtime cost - turning data structures into POD also help - not including `<iostream>` prevents a global constructor (the one used to initialize `cout` / `cerr`). `<istream>` and `<ostream>` exist and including both doesn't add any global constructor.