> Building mozilla-central has gotten noticeably slower. Yep. A bit over two years ago I started doing frequent browser builds for the first time; previously I'd mostly just worked with the JS shell. I was horrified by the ~25 minutes it took for a clobber build. I got a new Linux64 box and build times dropped to ~12 minutes, which made a *large* difference to my productivity.
On that same machine, I'm now back to ~25 minutes again. I've assumed it's due to "more code", specifically: 1. more code in the repository; 2. more code generated explicitly (e.g. dom bindings); 3. more code generated implicitly (i.e. templates). I don't know the relative impacts, though 1 is clearly a big part of it. Even worse, link times are through the roof. I was thrilled when, two years ago, I switched from ld to gold and linking time plummeted. The first link after rebooting was always slow, but I could link libxul back then in about 9 seconds. I haven't measured recently but I'm certain it's now *much* higher. Even the JS shell, which used to take hardly any time to link, now takes 10s or more; enough that I often switch to doing something else while waiting. If I could speed up any part of the builds, it would be linking. Waiting a long time to test a one file change sucks. > # Header dependency hell I've recently done a bunch of work on improving the header situation in SpiderMonkey. I can break it down to two main areas. == MINIMIZING #include STATEMENTS == There's a clang tool called "include-what-you-use", a.k.a. "IWYU" (http://code.google.com/p/include-what-you-use/). It tells you exactly which headers should be included in all your files. I've used it to minimize #includes somewhat already (https://bugzilla.mozilla.org/show_bug.cgi?id=634839) and I plan to do some more Real Soon Now (https://bugzilla.mozilla.org/show_bug.cgi?id=888768). There are still a couple of hundred unnecessary #include statements in SpiderMonkey. (BTW, SpiderMonkey has ~280 .cpp files and ~370 .h files.) IWYU is great, because it's really hard to figure this stuff out manually. It's also not perfect; about 5% of its suggestions are simply wrong, i.e. it says you can remove a #include that you can't. Also, there are often project-specific idioms that it doesn't know about -- there were several, but the one I remember off the top of my head is that it was constantly suggesting I remove "mozilla/StandardInteger.h" and add <stdint.h> (thankfully that's not an issue any more :) There are pragmas that you can annotate your source with, but I found them to be not always work as advertised and not really worth the effort. Although IWYU basically works, it feels a bit like software that doesn't get much maintenance. I haven't been doing rigorous measurements, but I think that these IWYU-related improvements don't do much for clobber builds, but can help significantly with partial rebuilds. It also just feels good to make these improvements. IWYU tells you the #includes that are unnecessary; it also tells you which ones are missing, i.e. which ones are being #included indirectly through another header. I've only bothered removing #includes because adding the missing ones doesn't feel worthwhile. Sometimes this means that when you remove an unnecessary |#include "a.h"|, you have to add a |#include "b.h"| because b.h was being pulled in only via a.h. Not a big deal. Relatedly, jorendorff wrote a python script that identifies cycles in header dependencies and diagnosed a cycle in SpiderMonkey that involved *11* header files. He and I broke that cycle in a series of 29 patches in https://bugzilla.mozilla.org/show_bug.cgi?id=872416, https://bugzilla.mozilla.org/show_bug.cgi?id=879831 https://bugzilla.mozilla.org/show_bug.cgi?id=886205. Prior to the last 9 patches, if you touched vm/Stack-inl.h and rebuilt, you'd rebuild 125 .cpp files. After these patches landed, it dropped to 30. The cycle-detection script has been incorporated into the |make check-style| target that is about to land in https://bugzilla.mozilla.org/show_bug.cgi?id=880088. I've also done various bits of refactoring with an eye towards simplifying the header dependencies. https://bugzilla.mozilla.org/show_bug.cgi?id=880041 is one example. These kinds of things can interact well with IWYU -- you do a clean-up, then run IWYU to find all the #includes that are no longer necessary. Gregory suggested that headers aren't something that the build config group can tackle, and I agree. Modifying #include statements en masse is much easier if you have some familiarity with the code. You need a sense of which headers should include which others, and often you have to move code around. So I encourage people to use IWYU on parts of the code they are familiar with. (Aryeh did this with editor/ in https://bugzilla.mozilla.org/show_bug.cgi?id=772807.) I should also note that this work is pretty tedious. There's lots of waiting for compilation, lots of try server runs to pick up bustage in other configurations, and then when you land you'll break additional configurations that aren't tested on try server (e.g. https://bugzilla.mozilla.org/show_bug.cgi?id=866916). That's life. == PROPER #ifndef WRAPPERS == There's one lower-hanging piece of fruit relating to headers. Many headers get #included multiple times per .cpp file. For example, in SpiderMonkey, jsapi.h gets #included literally dozens of times per .cpp file. So compilers optimize for this. With GCC and clang, if you have a canonical #ifndef wrapper in a header file, e.g.: #ifndef FOO_H__ ... #endif the compiler will avoid re-including the header if FOO_H__ is defined. But for this to work the #ifndef wrapper must have the above form (|#if defined(FOO_H__)| is also allowed, and there can't be any tokens before or afterwards (but whitespace and comments are ok). (See http://gcc.gnu.org/onlinedocs/cpp/Once_002dOnly-Headers.html#Once_002dOnly-Headers and http://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html for details.) SpiderMonkey had ~30 header files that violated this, most of them by doing something like this: #if !defined(jsion_baseline_frame_inl_h__) && defined(JS_ION) ... #endif I fixed these in https://bugzilla.mozilla.org/show_bug.cgi?id=881579. Unlike the #include minimization, these don't require domain-specific expertise and are easy to fix. They are also easy to find. clang and GCC have a -H option which tells you exactly which header files get read during compilation. IIRC, GCC even tells you (at the bottom of the output) which of these files are read multiple times because they violate the standard #ifndef wrapper form. (More generally, if you want to take any kind of measurements about header file inclusions, you should really base it off |gcc -H| or |clang -H|; if you try it any other way -- e.g. counting #includes statically via a script -- you'll probably get wildly incorrect numbers because you won't account for this optimization.) Infuriatingly, on both my Linux and Mac machines, a number of the system headers violate these forms, and so get read many more times than necessary. For SpiderMonkey, IIRC some system headers get included ~5,000 times for 280 .cpp files :( (Another annoying Linux thing is that we have these Mozilla-specific $OBJDIR/dist/system_wrappers_js/*.h that just #include a system header. I don't entirely understand what they're for, but they don't have a #ifndef wrapper and so also get included many times per .cpp file. I tried adding a #ifndef wrapper but got bustage I didn't understand. At least these files are tiny.) I'm not sure how MSVC handles #ifndef wrappers. Someone told me that it needs |#pragma once| to avoid the multiple includes, but I don't know if that's true. > One of our Q3 goals is to replace the "export tier" with something more > efficient. I just want to say that I appreciate all this effort going into the build system and think it's thoroughly worthwhile. Thanks! Nick _______________________________________________ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform