---------- Forwarded message ----------
From: Nicholas Nethercote <n.netherc...@gmail.com>
Date: Wed, Apr 5, 2017 at 8:35 PM
Subject: Re: [dev-servo] Incremental compilation and other compile time tricks
To: "dev-servo@lists.mozilla.org" <dev-servo@lists.mozilla.org>


`mach cargo check` is worth listing in Servo's README.md, IMO!

Nick

On Sat, Apr 1, 2017 at 4:43 AM, Simon Sapin <simon.sa...@exyr.org> wrote:

> If you build Servo a lot you may have noticed that compilation times have
> improved over the last few months. This is combination of multiple factors.
>
>
> # Compiler optimization
>
> Plain old optimization of the compiler’s code. Sometimes a rustup makes
> things a bit faster without us changing anything else. For example:
>
> https://blog.mozilla.org/nnethercote/2016/10/14/how-to-speed
> -up-the-rust-compiler/
> https://blog.mozilla.org/nnethercote/2016/11/23/how-to-speed
> -up-the-rust-compiler-some-more/
>
>
> # Limited parallelism
>
> Cargo can compile multiple crates at the same time, but a crate can only
> start after its dependencies are done. And in the default configuration,
> compiling one crate only uses one CPU core/thread. Servo’s dependency graph
> tends to be narrow near the end, in particular with the script crate that
> takes a lot of time to compile. This limits the overall available
> parallelism.
>
>
> # Hardware
>
> CPUs with many cores tend to make each core slower, to manage heat.
> Counter-intuitively this can make then worse for compiling Servo. If you’re
> spending (your employer’s) money on hardware, I recommend the highest
> single-thread performance you can find even if this means fewer cores.
> Currently, this is probably Intel’s i7-7700K. (4 cores, 8 threads, 4.2 GHz,
> easy to overclock to 4.6 GHz.)
>
>
> # Codegen units
>
> Compilation of a crate can be roughly split into two phases: analysis and
> code generation. The former includes parsing, type checking, borrow
> checking, etc. The latter is mostly LLVM.
>
> rustc added a feature to get parallelism in code generation. With `rustc
> -C codegen-units=4` for example, the code to generate is split into four
> parts that are given separately to LLVM in threads that run in parallel.
>
> This makes compilation faster but has a runtime cost: LLVM’s optimizer
> only sees one unit at a time, which reduces opportunities for inlining and
> other compile-time optimizations.
>
> Also, only code generation is parallelized, the analysis phase still runs
> on a single thread. So Amdahl’s law limits how much speed improvement we
> can get with this.
>
> In Servo we’ve enabled codegen-units=4 by default in debug mode, but not
> in release mode.
>
> https://github.com/servo/servo/pull/14995
>
>
> # LLVM assertions
>
> When compiling LLVM (and so when compiling rustc) we can choose to enable
> LLVM assertions. There assertions can help find bugs (in LLVM or in rustc),
> but they have a runtime cost. (LLVM’s runtime, which is Servo’s compile
> time.) This cost can be significant, especially in release mode (where
> LLVM’s optimizer does a lot of work).
>
> Official Rust builds have LLVM assertions enabled in Rust Nightly (to help
> catch bug), but not in the beta or stable release channels.
>
> At our request, the Rust team started making alternative Rust Nightly
> builds without LLVM assertions, for some platforms. We’re now using them by
> default, except for some of our Continuous Integration builders (in order
> to preserve some of the coverage).
>
> https://github.com/rust-lang/rust/pull/39754
> https://github.com/servo/servo/pull/15559
> https://github.com/servo/servo/pull/15564
>
>
> # cargo check
>
> Remember how I said a crate needs its dependencies to be compiled before
> it can start compiling? It actually only needs metadata (the results of the
> analysis phase), not the generated code.
>
> Cargo added a `cargo check` command that skips code generation entirely
> (except for build scripts and build-dependencies). This saves a lot of time
> (I’ve measured up to 5× speed from `./mach clean`), though obviously you
> don’t get an executable at the end. Still, it can help for example during a
> refactoring: run `./mach cargo check` many times until compiler error are
> resolved, and only then run `./mach build` and/or `./mach test-unit`.
>
> https://github.com/rust-lang/cargo/pull/3296
> https://github.com/servo/servo/pull/14594
>
> Follow-up work wanted: add a mach sub-command or option to do this with
> geckolib.
>
> (It would also be nice for rustc to have a mode to write both metadata and
> full build, and signal somehow as soon as the former is ready; and have
> Cargo start building dependents on that signal while codegen for the
> dependencies is still running, increasing overall parallelism.)
>
>
> # Preserving compilation output between CI runs
>
> Previously, Servo’s Continuous Integration was configured to run `git
> clean` at the start of each build, with options such that anything not
> checked into the repository was removed. This included the `target`
> directory, so each pull request was recompiled from scratch.
>
> We’ve changed the configuration to preserve files in .gitignore, which
> includes the target directory, so that some of the compilation output for
> previous builds can be reused. This makes pull requests faster to land
> after r+, and try runs faster to give results.
>
> There is a risk that preserved files could be left by a previous builds in
> a broken state, leading to failures that only happen on CI. We’re
> monitoring this and will consider reverting this change it this turns out
> to be a problem.
>
> https://github.com/servo/saltfs/pull/611
>
>
> # Incremental compilation
>
> Finally, the compiler feature everyone is waiting for.
>
> In the current default configuration, entire crates are recompiled from
> scratch whenever the smallest part of their source or dependencies is
> touched. Incremental compilation changes this, caching many intermediate
> results so that the next build hopefully doesn’t need to do that work again.
>
> Incremental compilation in Rust Nightly is currently in "beta". It mostly
> works (I’ve been using it exclusively for a couple months) but it’s buggy
> on some platforms and the speedups are not as good as one might hope. (Only
> code generation is cached, at the moment.)
>
> It also uses a lot of disk space and memory. The `target` directory in one
> of my trees takes 26 GB. (I don’t know if there’s any cache eviction, so
> running `cargo clean` occasionally may be needed.) One of our CI builders
> with "only" 8 GB of RAM and no swap is unable to build the script crate
> with incremental compilation enabled.
>
> So far we have *not* enabled incremental compilation by default in Servo.
> Still, you can try it by copying servobuild.example to .servobuild, then
> editing the latter to change `incremental = false` to `incremental = true`
> in the [build] section.
>
> Please send us any feedback!
>
> https://blog.rust-lang.org/2016/09/08/incremental.html
> https://internals.rust-lang.org/t/incremental-compilation-beta/4721
> https://github.com/servo/servo/pull/15390
> https://github.com/servo/servo/pull/15565
>
> --
> Simon Sapin
> _______________________________________________
> dev-servo mailing list
> dev-servo@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-servo
>
_______________________________________________
dev-servo mailing list
dev-servo@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-servo
_______________________________________________
dev-servo mailing list
dev-servo@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-servo

Reply via email to