mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 19:03:27 +00:00
Enhance OSDK performance by reusing existing base, bundle and build
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
3bbdc68d39
commit
858e95ed4d
@ -8,7 +8,7 @@ use std::{
|
||||
ffi::OsString,
|
||||
path::{Path, PathBuf},
|
||||
process,
|
||||
time::{Duration, SystemTime},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
use bin::make_elf_for_qemu;
|
||||
@ -19,6 +19,7 @@ use crate::{
|
||||
base_crate::new_base_crate,
|
||||
bundle::{
|
||||
bin::{AsterBin, AsterBinType, AsterElfMeta},
|
||||
file::BundleFile,
|
||||
Bundle,
|
||||
},
|
||||
cli::BuildArgs,
|
||||
@ -88,6 +89,31 @@ pub fn create_base_and_cached_build(
|
||||
bundle
|
||||
}
|
||||
|
||||
fn get_reusable_existing_bundle(
|
||||
bundle_path: impl AsRef<Path>,
|
||||
config: &Config,
|
||||
action: ActionChoice,
|
||||
) -> Option<Bundle> {
|
||||
let existing_bundle = Bundle::load(&bundle_path);
|
||||
let Some(existing_bundle) = existing_bundle else {
|
||||
info!("Building a new bundle: No cached bundle found or validation of the existing bundle failed");
|
||||
return None;
|
||||
};
|
||||
if let Err(e) = existing_bundle.can_run_with_config(config, action) {
|
||||
info!("Building a new bundle: {}", e);
|
||||
return None;
|
||||
}
|
||||
let workspace_root = {
|
||||
let meta = get_cargo_metadata(None::<&str>, None::<&[&str]>).unwrap();
|
||||
PathBuf::from(meta.get("workspace_root").unwrap().as_str().unwrap())
|
||||
};
|
||||
if existing_bundle.last_modified_time() < get_last_modified_time(&workspace_root) {
|
||||
info!("Building a new bundle: workspace_root has been updated");
|
||||
return None;
|
||||
}
|
||||
Some(existing_bundle)
|
||||
}
|
||||
|
||||
/// If the source is not since modified and the last build is recent, we can reuse the existing bundle.
|
||||
pub fn do_cached_build(
|
||||
bundle_path: impl AsRef<Path>,
|
||||
@ -97,54 +123,6 @@ pub fn do_cached_build(
|
||||
action: ActionChoice,
|
||||
rustflags: &[&str],
|
||||
) -> Bundle {
|
||||
let build_a_new_one = || {
|
||||
do_build(
|
||||
&bundle_path,
|
||||
&osdk_output_directory,
|
||||
&cargo_target_directory,
|
||||
config,
|
||||
action,
|
||||
rustflags,
|
||||
)
|
||||
};
|
||||
|
||||
let existing_bundle = Bundle::load(&bundle_path);
|
||||
let Some(existing_bundle) = existing_bundle else {
|
||||
return build_a_new_one();
|
||||
};
|
||||
if existing_bundle.can_run_with_config(config, action).is_err() {
|
||||
return build_a_new_one();
|
||||
}
|
||||
let Ok(built_since) = SystemTime::now().duration_since(existing_bundle.last_modified_time())
|
||||
else {
|
||||
return build_a_new_one();
|
||||
};
|
||||
if built_since > Duration::from_secs(600) {
|
||||
return build_a_new_one();
|
||||
}
|
||||
let workspace_root = {
|
||||
let meta = get_cargo_metadata(None::<&str>, None::<&[&str]>).unwrap();
|
||||
PathBuf::from(meta.get("workspace_root").unwrap().as_str().unwrap())
|
||||
};
|
||||
if get_last_modified_time(workspace_root) < existing_bundle.last_modified_time() {
|
||||
return existing_bundle;
|
||||
}
|
||||
build_a_new_one()
|
||||
}
|
||||
|
||||
pub fn do_build(
|
||||
bundle_path: impl AsRef<Path>,
|
||||
osdk_output_directory: impl AsRef<Path>,
|
||||
cargo_target_directory: impl AsRef<Path>,
|
||||
config: &Config,
|
||||
action: ActionChoice,
|
||||
rustflags: &[&str],
|
||||
) -> Bundle {
|
||||
if bundle_path.as_ref().exists() {
|
||||
std::fs::remove_dir_all(&bundle_path).unwrap();
|
||||
}
|
||||
let mut bundle = Bundle::new(&bundle_path, config, action);
|
||||
|
||||
let (build, boot) = match action {
|
||||
ActionChoice::Run => (&config.run.build, &config.run.boot),
|
||||
ActionChoice::Test => (&config.test.build, &config.test.boot),
|
||||
@ -160,6 +138,21 @@ pub fn do_build(
|
||||
rustflags,
|
||||
);
|
||||
|
||||
// Check the existing bundle's reusability
|
||||
if let Some(existing_bundle) = get_reusable_existing_bundle(&bundle_path, config, action) {
|
||||
if get_last_modified_time(aster_elf.path()) < existing_bundle.last_modified_time() {
|
||||
info!("Reusing existing bundle: aster_elf is unchanged");
|
||||
return existing_bundle;
|
||||
}
|
||||
}
|
||||
|
||||
// Build a new bundle
|
||||
info!("Building a new bundle");
|
||||
if bundle_path.as_ref().exists() {
|
||||
std::fs::remove_dir_all(&bundle_path).unwrap();
|
||||
}
|
||||
let mut bundle = Bundle::new(&bundle_path, config, action);
|
||||
|
||||
match boot.method {
|
||||
BootMethod::GrubRescueIso | BootMethod::GrubQcow2 => {
|
||||
info!("Building boot device image");
|
||||
@ -274,6 +267,9 @@ fn build_kernel_elf(
|
||||
}
|
||||
|
||||
fn get_last_modified_time(path: impl AsRef<Path>) -> SystemTime {
|
||||
if path.as_ref().is_file() {
|
||||
return path.as_ref().metadata().unwrap().modified().unwrap();
|
||||
}
|
||||
let mut last_modified = SystemTime::UNIX_EPOCH;
|
||||
for entry in std::fs::read_dir(path).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
|
@ -47,9 +47,10 @@ fn add_manifest_dependencies(cargo_metadata: &serde_json::Value, crate_name: &st
|
||||
fs::write(manifest_path, content).unwrap();
|
||||
}
|
||||
|
||||
// Add `target/osdk/base` to `exclude` array of the workspace manifest
|
||||
// Add `target/osdk/base` and `target/osdk/test-base` to `exclude` array of the workspace manifest
|
||||
fn exclude_osdk_base(metadata: &serde_json::Value) {
|
||||
let osdk_base_path = "target/osdk/base";
|
||||
let osdk_run_base_path = "target/osdk/base";
|
||||
let osdk_test_base_path = "target/osdk/test-base";
|
||||
|
||||
let workspace_manifest_path = {
|
||||
let workspace_root = metadata.get("workspace_root").unwrap().as_str().unwrap();
|
||||
@ -64,17 +65,25 @@ fn exclude_osdk_base(metadata: &serde_json::Value) {
|
||||
|
||||
if let Some(exclude) = workspace.get_mut("exclude") {
|
||||
let exclude = exclude.as_array_mut().unwrap();
|
||||
if exclude.contains(&toml::Value::String(osdk_base_path.to_string())) {
|
||||
if exclude.contains(&toml::Value::String(osdk_run_base_path.to_string()))
|
||||
|| exclude.contains(&toml::Value::String(osdk_test_base_path.to_string()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
exclude.push(toml::Value::String(osdk_base_path.to_string()));
|
||||
exclude.push(toml::Value::String(osdk_run_base_path.to_string()));
|
||||
exclude.push(toml::Value::String(osdk_test_base_path.to_string()));
|
||||
} else {
|
||||
let exclude = vec![toml::Value::String(osdk_base_path.to_string())];
|
||||
let exclude = vec![
|
||||
toml::Value::String(osdk_run_base_path.to_string()),
|
||||
toml::Value::String(osdk_test_base_path.to_string()),
|
||||
];
|
||||
workspace.insert("exclude".to_string(), toml::Value::Array(exclude));
|
||||
}
|
||||
} else {
|
||||
let exclude = toml::Table::from_str(r#"exclude = ["target/osdk/base"]"#).unwrap();
|
||||
let exclude =
|
||||
toml::Table::from_str(r#"exclude = ["target/osdk/base", "target/osdk/test-base"]"#)
|
||||
.unwrap();
|
||||
manifest_toml.insert("workspace".to_string(), toml::Value::Table(exclude));
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,8 @@ pub fn test_current_crate(config: &Config, args: &TestArgs) {
|
||||
let current_crate = get_current_crate_info();
|
||||
let cargo_target_directory = get_target_directory();
|
||||
let osdk_output_directory = cargo_target_directory.join(DEFAULT_TARGET_RELPATH);
|
||||
let target_crate_dir = osdk_output_directory.join("base");
|
||||
// Use a different name for better separation and reusability of `run` and `test`
|
||||
let target_crate_dir = osdk_output_directory.join("test-base");
|
||||
|
||||
// A special case is that we use OSDK to test the OSDK test runner crate
|
||||
// itself. We check it by name.
|
||||
|
Reference in New Issue
Block a user