Open
Bug 1412077
Opened 7 years ago
Updated 2 years ago
Make style crate build faster
Categories
(Firefox Build System :: General, enhancement)
Firefox Build System
General
Tracking
(Not tracked)
NEW
People
(Reporter: gps, Unassigned)
References
(Depends on 2 open bugs)
Details
As data in bug 1411081 shows, the style crate takes a few minutes to compile with opt-level=2. It is also a long pole because it depends on bindgen, which also takes a while.
We had to change the local build default to opt-level=1 in bug 1411081 largely because waiting on the style crate was taking too long. This negatively impacts build testing because opt-level=2 makes a significant difference to performance.
I'm filing this bug to track improvements to making the style crate build faster. Ideally at opt-level=2. This not only tracks the style crate itself but its dependencies, notably bindgen.
Manish: I know you have ideas. Could you please brain dump?
Flags: needinfo?(manishearth)
Comment 1•7 years ago
|
||
Making bindgen not build clap (which is completely unused for our purposes) and expensive to compile opt, would help.
Comment 2•7 years ago
|
||
(In reply to Nathan Froyd [:froydnj] from comment #1)
> Making bindgen not build clap (which is completely unused for our purposes)
> and expensive to compile opt, would help.
Last time I checked this was blocked on https://github.com/rust-lang/cargo/issues/1982, but there's a workaround in that thread that sounds nice to me.
Comment 3•7 years ago
|
||
Short of splitting the style crate into smaller pieces, or the rust compiler finally getting faster, there is not much that can be done.
Comment 4•7 years ago
|
||
> This negatively impacts build testing because opt-level=2 makes a significant difference to performance.
I mean, I think we might wish to do opt-level=2 for try release tests, but for local builds by default do opt-level=1.
> Could you please brain dump?
- If we switch to debug mode, bindgen is compiled in debug mode. Which is slow(er). I'm unsure if most of the time bindgen spends is in libclang or in the now-unoptimized rust code. We should measure this (emilio?)
- Bindgen pulls in way too many headers. This means touching anything moderately important triggers rebuilds. This is a bad experience for folks working on the DOM or layout. We should reduce this. One way to do this is to extract the structs we care about into their own headers and make those headers depend on as few things as possible, and the original header file includes this one. This would be a lot of work. Also may not be worth it because C++ doesn't let you declare a struct and *declare* its methods out-of-line. We could use conditional compilation to make this work so that in bindgen mode we don't see any methods (so we can pull in fewer headers). Also a lot of work. There is probably low hanging fruit here though.
- Bindgen generates way too much. I'm not sure if this impacts bindgen's runtime, but reducing this may improve style's compile time. Aggressively opaque-ifying types we never access would be nice. We generate way too many bindings for what we actually use. What we basically need is field access on style structs and most of the things they contain, but that doesn't need to pull in e.g. nsINode.
- codegen-units isn't making the full use of parallelism. I don't yet know why. Alex mentioned that it can't magically parallelize and there must be that many divisions of the codegen work possible for this to work. I have to do some analysis with compiling style (also servo libscript) to see why it isn't parallelizing.
- Compiling syntex takes a lot of time, especially for opt-level=2. We probably can get away with this being opt-level=1 or 0, *if* rust let us configure this.
Flags: needinfo?(manishearth)
Comment 5•7 years ago
|
||
(In reply to Manish Goregaokar [:manishearth] from comment #4)
> - Compiling syntex takes a lot of time, especially for opt-level=2. We
> probably can get away with this being opt-level=1 or 0, *if* rust let us
> configure this.
Upstream versions of bindgen use quote instead of syntex / aster / etc, and they improved a lot bindgen's CI time. A bindgen update may fix this kind of issues.
Comment 6•7 years ago
|
||
(In reply to Manish Goregaokar [:manishearth] from comment #4)
> - Bindgen pulls in way too many headers. This means touching anything
> moderately important triggers rebuilds. This is a bad experience for folks
> working on the DOM or layout. We should reduce this. One way to do this is
> to extract the structs we care about into their own headers and make those
> headers depend on as few things as possible, and the original header file
> includes this one. This would be a lot of work. Also may not be worth it
> because C++ doesn't let you declare a struct and *declare* its methods
> out-of-line. We could use conditional compilation to make this work so that
> in bindgen mode we don't see any methods (so we can pull in fewer headers).
> Also a lot of work. There is probably low hanging fruit here though.
We can probably have the build script generate such stripped headers on the fly, and feed them into bindgen, rather than let bindgen read the headers itself. The build script is already reading the headers for dependency scanning anyway. Not exactly sure how it would work, though.
> - Bindgen generates way too much. I'm not sure if this impacts bindgen's
> runtime, but reducing this may improve style's compile time. Aggressively
> opaque-ifying types we never access would be nice. We generate way too many
> bindings for what we actually use. What we basically need is field access on
> style structs and most of the things they contain, but that doesn't need to
> pull in e.g. nsINode.
I have an idea that we can probably add a new option to bindgen to aggressively opaque everything except those specified in the whitelist. Maybe we can call it "whitelist-only" or something like that. It should be doable although that may require us to extend the whitelist in the toml file for quite a bit. We can remove the opaque type list, though.
Comment 7•7 years ago
|
||
(In reply to Manish Goregaokar [:manishearth] from comment #4)
> - Bindgen pulls in way too many headers. This means touching anything
> moderately important triggers rebuilds. This is a bad experience for folks
> working on the DOM or layout. We should reduce this. One way to do this is
> to extract the structs we care about into their own headers and make those
> headers depend on as few things as possible, and the original header file
> includes this one. This would be a lot of work. Also may not be worth it
> because C++ doesn't let you declare a struct and *declare* its methods
> out-of-line. We could use conditional compilation to make this work so that
> in bindgen mode we don't see any methods (so we can pull in fewer headers).
> Also a lot of work. There is probably low hanging fruit here though.
Another thought of this is that, if we can query clang for what types we depend on, and where are they defined, we should be able to shrink the list of headers in "cargo:rerun-if-changed". I guess that's something needs support from bindgen side.
Comment 8•7 years ago
|
||
>Another thought of this is that, if we can query clang for what types we depend on, and where are they defined, we should be able to shrink the list of headers in "cargo:rerun-if-changed".
Weeellllll *technically* no, because any header can mess with #defines or whatever. Practically; yes (I don't know how hard the implementation is). This may mean some kinds of edits to headers lead to incorrect bindings on an incremental build. I think this is something that may be doable.
> It should be doable although that may require us to extend the whitelist in the toml file for quite a bit.
I like this idea.
This might be overengineering but we could do something like `[whitelist] nsStyleFont = 3` or something, which would mean nsStyleFont is whitelisted and code will be generated for all types up to 3 levels reachable from it.
(This may complicate the opaque-type-tracking stuff enough that it doesn't speed up bindgen though it may still speed up style crate perf)
Comment 9•7 years ago
|
||
(In reply to Manish Goregaokar [:manishearth] from comment #8)
> >Another thought of this is that, if we can query clang for what types we depend on, and where are they defined, we should be able to shrink the list of headers in "cargo:rerun-if-changed".
>
> Weeellllll *technically* no, because any header can mess with #defines or
> whatever. Practically; yes (I don't know how hard the implementation is).
> This may mean some kinds of edits to headers lead to incorrect bindings on
> an incremental build. I think this is something that may be doable.
Yes, but in that case people would usually also mutate the corresponding files. Maybe clang can also tell us whether any typedef / #define involves in a type which we depends. I guess we don't really have many types involve #define.
> > It should be doable although that may require us to extend the whitelist in the toml file for quite a bit.
>
> I like this idea.
>
> This might be overengineering but we could do something like `[whitelist]
> nsStyleFont = 3` or something, which would mean nsStyleFont is whitelisted
> and code will be generated for all types up to 3 levels reachable from it.
>
> (This may complicate the opaque-type-tracking stuff enough that it doesn't
> speed up bindgen though it may still speed up style crate perf)
I don't like this... I'd rather we keep things simple and just add everything we need to the whitelist. I don't really believe we have that many things to deal with.
Comment 10•7 years ago
|
||
FWIW, the rustc compile perf tracker does include a (fixed) revision of the style crate: http://perf.rust-lang.org/ .
Comment 11•7 years ago
|
||
(In reply to Manish Goregaokar [:manishearth] from comment #4)
> - Compiling syntex takes a lot of time, especially for opt-level=2. We
> probably can get away with this being opt-level=1 or 0, *if* rust let us
> configure this.
Is syntex only used as a transitive dependency of bindgen? As it turns out, fitzgen removed the syntex dependency recently:
https://github.com/rust-lang-nursery/rust-bindgen/issues/925
That fix is in bindgen 0.31.2, which literally just got merged into m-c today:
https://github.com/servo/servo/pull/19072
https://hg.mozilla.org/mozilla-central/rev/0c00ba0de42e
Comment 12•7 years ago
|
||
> - Bindgen pulls in way too many headers. This means touching anything moderately important triggers rebuilds. This is a bad experience for folks working on the DOM or layout. We should reduce this. One way to do this is to extract the structs we care about into their own headers and make those headers depend on as few things as possible, and the original header file includes this one. This would be a lot of work. Also may not be worth it because C++ doesn't let you declare a struct and *declare* its methods out-of-line. We could use conditional compilation to make this work so that in bindgen mode we don't see any methods (so we can pull in fewer headers). Also a lot of work. There is probably low hanging fruit here though.
Would it be possible to split sets of headers apart into sub-crates that the style crate could depend on? That way ideally you'd only be rebuilding the specific bits that depend on those headers. Obviously you'd still wind up rebuilding the style crate itself, but if the bindgen-generated bindings were in separate crates you shouldn't have as much to compile. (Hopefully incremental compilation will help here as well.)
Comment 13•7 years ago
|
||
(In reply to Ted Mielczarek [:ted.mielczarek] from comment #11)
> Is syntex only used as a transitive dependency of bindgen? As it turns out,
> fitzgen removed the syntex dependency recently:
> https://github.com/rust-lang-nursery/rust-bindgen/issues/925
>
> That fix is in bindgen 0.31.2, which literally just got merged into m-c
> today:
> https://github.com/servo/servo/pull/19072
> https://hg.mozilla.org/mozilla-central/rev/0c00ba0de42e
Indeed, I think building gecko doesn’t involve building syntex anymore:
https://hg.mozilla.org/mozilla-central/rev/d480e8818314#l213.143
third_party/rust/syntex/ is still there because js/rust/ still uses bindgen 0.30. Maybe we can update that as well?
Comment 14•7 years ago
|
||
(In reply to Simon Sapin (:SimonSapin) from comment #13)
> Indeed, I think building gecko doesn’t involve building syntex anymore:
> https://hg.mozilla.org/mozilla-central/rev/d480e8818314#l213.143
>
> third_party/rust/syntex/ is still there because js/rust/ still uses bindgen
> 0.30. Maybe we can update that as well?
Probably fitzgen is the best person to ask to for that :)
Flags: needinfo?(nfitzgerald)
Comment 15•7 years ago
|
||
Only reason it hasn't been updated is because it hasn't been updated ;)
I can look into it soon.
Flags: needinfo?(nfitzgerald)
Comment 16•7 years ago
|
||
We have an older copy of the pre-processed Stylo structs header checked into the `bindgen` repo that we use as a smoke test, and occasionally time how long it takes to generate bindings for.
### Release Mode
Building `bindgen` in release mode:
Finished release [optimized] target(s) in 174.59 secs
Running the Stylo sanity test on master yields this result:
time: 492.128 ms. parse
time: 0.000 ms. process_replacements
time: 21.272 ms. deanonymize_fields
time: 553.664 ms. compute_whitelisted_and_codegen_items
time: 32.282 ms. compute_has_vtable
time: 163.831 ms. compute_sizedness
time: 31.419 ms. compute_has_destructor
time: 153.185 ms. find_used_template_parameters
time: 126.824 ms. compute_cannot_derive_debug
time: 0.000 ms. compute_cannot_derive_default
time: 191.432 ms. compute_cannot_derive_copy
time: 29.543 ms. compute_has_type_param_in_array
time: 0.000 ms. compute_has_float
time: 0.000 ms. compute_cannot_derive_hash
time: 0.000 ms. compute_cannot_derive_partialord_partialeq_or_eq
time: 264.948 ms. codegen
Generated Stylo bindings in: Duration { secs: 4, nanos: 147347796 }
Total release time: ~179 seconds.
### Dev Mode
Building `bindgen` in dev mode:
Finished dev [unoptimized + debuginfo] target(s) in 27.78 secs
Generating Stylo bindings:
time: 5025.307 ms. parse
time: 0.001 ms. process_replacements
time: 441.843 ms. deanonymize_fields
time: 19990.504 ms. compute_whitelisted_and_codegen_items
time: 1005.502 ms. compute_has_vtable
time: 5715.124 ms. compute_sizedness
time: 1046.051 ms. compute_has_destructor
time: 4887.797 ms. find_used_template_parameters
time: 4558.315 ms. compute_cannot_derive_debug
time: 0.000 ms. compute_cannot_derive_default
time: 6772.230 ms. compute_cannot_derive_copy
time: 1010.969 ms. compute_has_type_param_in_array
time: 0.000 ms. compute_has_float
time: 0.000 ms. compute_cannot_derive_hash
time: 0.000 ms. compute_cannot_derive_partialord_partialeq_or_eq
time: 9615.932 ms. codegen
Generated Stylo bindings in: Duration { secs: 64, nanos: 279007654 }
Total dev time: ~92 seconds.
--------------------------------------------------------------------------------
So build time is a significant amount of `bindgen` related time. But it only happens once, even after headers are modified. If we always build bindings with release mode, we pay the build time cost once up front, and then its only ~4 seconds to regenerate bindings.
In addition to building without `clap`, Stylo can probably build without logging and the `env_logger` dependency, which is a significant amount of `bindgen` build time. Or at least make it optional (default off) behind some config option.
The next thing to look into is how long it takes to build the `style` crate independent of `bindgen` and bindings regeneration. If it takes two minutes to rebuild the `style` crate even after (release mode) `bindgen` has already been built, then it seems like the majority of time is being spent in there.
Comment 17•7 years ago
|
||
(In reply to Nick Fitzgerald [:fitzgen] [⏰PST; UTC-8] from comment #15)
> Only reason it hasn't been updated is because it hasn't been updated ;)
>
> I can look into it soon.
Updating js/rust's bindgen dep in https://bugzilla.mozilla.org/show_bug.cgi?id=1414030
Comment 18•7 years ago
|
||
FWIW, using `CARGO_INCREMENTAL=1` with nightly Rust drops a fresh release build's time down to ~45 seconds.
https://internals.rust-lang.org/t/help-us-benchmark-incremental-compilation/6153/29
Updated•7 years ago
|
Product: Core → Firefox Build System
Updated•2 years ago
|
Severity: normal → S3
You need to log in
before you can comment on or make changes to this bug.
Description
•