-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Coupling all xtasks into one binary can hurt performance #2
Comments
To be clear, I understand this is a |
Note that splitting it over several binaries/packages can hurt performance as well, as rustc would need to do more linking (each binary will get it's own copy of std). I wouldn't worry to much about performance, as tasks are compiled once, and should be cacheable pretty robustly. In parcticular, for CI i'd just add |
I've added some general advice about build times: 15ac41b Given that xtasks shouldn't be rebuild that often, I am inclined to close this issue! |
I disagree for CIs. I feel like caching within CIs is still very limited until we have worked out the ways to clean up a workspace's stale files. For AzDO, caching is still in preview and they discourage it for production builds. I'll leave to you the decision on whether to re-open. Less important is the impact on me as a user. I find that from time to time I do clean builds. Sometimes its to recover space from stale files but usually its for various scenarios I'm testing out. A machine-wide cache of non-workspace dependencies would be a big help for reducing the impact of clean builds. |
Yeah, let's reopen! I can't come up with nice strategy here myself (spliting xtasks over several packages seems like a pain), but perhaps somebody else will! |
I would prefer tasks to be separate binaries, as I don't want to parse arguments. Dumping my spaghetti code in |
@kornelski you'd need to define a separate alias for each xtask then, which is messy. And something like |
Yeah, I would define separate alias for each task. I expected generation of aliases to be automatic. Supporting To me ideally the workflow would be something like:
Where steps 2 and 3 would not exist if it becomes Cargo built-in solution. This maps my solution with shell files, where I have many shell files, not one with |
I think there should be a way for the new contributor to the project to figure out the list of available tasks. I'll add "multiple binaries" as an alternative, but I personally would still prefer a single binary:
|
But To me separate tasks mean each task starts as fast as it can. Merged tasks mean every task is at least as slow to start as the slowest task. |
If binaries are part of the same Cargo package, you'd still need to build all deps for any binary unfortunately :-( |
Oh, it does indeed. That's a bummer :( |
However, still I wouldn't want to be in business of having multi-purpose bin. The tasks I have are sometimes wildly different. For example for lib.rs I have following binaries:
I would not want to have all of them in one file with a giant I shall also add that I treat them as internal tools (things that would be in bash if bash was faster and could call Rust code better ;) so their code is not very pretty or DRY, since they're either write-once tools, or just a small glue of library functions that have better code and tests elsewhere. They generally don't take args, or take just one. |
You could avoid per-task entries in
|
I ended up bundling all my tasks into a single binary and found this to be kind of cumbersome for my project. I'm going to try using the xtask binary as merely dispatch for my project and see how I go with that but I'm also wondering if a consensus here has evolved much? |
I saw another approach here of putting a less used task with more dependencies behind a feature and then having the xtask rebuild itself with the required features if necessary: https://github.com/gfx-rs/wgpu/blob/55b73a9fb8421135a55f5f5f44a7deca505715cb/xtask/src/main.rs#L18 Might be useful for certain cases. |
I've used the rebuild-with-feature-flags strategy myself. 👍 It works particularly well when you really want to keep everything in a single file such as when using the new cargo script feature. example of cargo script with self-rerun feature flag#!/usr/bin/env -S cargo +nightly -Zscript
```cargo
[features]
generate = ["quick-xml", "wasmtime"]
[dependencies]
quick-xml = { version = "0.3.1", optional = true }
wasmtime = { version = "19.0.1", optional = true }
```
#[cfg(feature = "generate")]
fn generate() -> Result<(), Box<dyn std::error::Error>> {
use quick_xml::*;
use wasmtime::*;
// Do something with quick_xml and wasmtime...
Ok(())
}
fn build_release() -> Result<(), Box<dyn std::error::Error>> {
// Do the quick & easy build copy stuff.
Ok(())
}
fn test_e2e() -> Result<(), Box<dyn std::error::Error>> {
// Another easy one that requires only quick deps.
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
match std::env::args().nth(1).ok_or("no task")?.as_str() {
"generate" => {
#[cfg(feature = "generate")]
return generate();
#[cfg(not(feature = "generate"))]
return std::process::Command::new("cargo")
.args(["+nightly", "-Zscript", "run", "--manifest-path", file!()])
.args(["--features", "generate", "--", "generate"])
.status()?
.success()
.then_some(())
.ok_or("cmd failed".into());
},
"build-release" => build_release(),
"test-e2e" => test_e2e(),
_ => Err("no such task".into()),
}
} |
Some xtasks a developer will want to run regularly (like bundling up artifacts for wasm or embedded as part of their debug cycle). Some developers might rarely run, like some code-gen.
Similar for a CI. Multiple independent jobs will need to build the xtasks. Most jobs will just need the ones related to CI. Only one job will need to validate code-gen. Only a couple of jobs, conditioned on version tags, will need to call
xtask dist
.By putting all of these into a single binary, we're losing out on performance by requiring it to build dependencies or run build scripts for
xtasks
that won't be runThe text was updated successfully, but these errors were encountered: