Skip to content

Commit ecbe39c

Browse files
OpenVMM TeamBen Hillis
authored andcommitted
ci: add kernel binary size checks to OSS CI
Extend the existing openhcl binary size check infrastructure to also compare kernel binaries between PRs and the last successful main merge. Kernels checked per architecture: - x64: Main, CVM - aarch64: Main The kernel baselines are included in the existing per-arch openhcl-baseline artifact (alongside the usermode binary), and the comparisons run in the existing 'verify openhcl binary size' jobs. No new CI jobs, artifacts, or files are added.
1 parent 5e694e9 commit ecbe39c

9 files changed

Lines changed: 182 additions & 34 deletions

File tree

.github/workflows/openvmm-ci.yaml

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/workflows/openvmm-pr.yaml

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flowey/flowey_hvlite/src/pipelines/checkin_gates.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,9 @@ impl IntoPipeline for CheckinGatesCli {
696696
all_jobs.push(job.finish());
697697
}
698698

699+
use flowey_lib_hvlite::_jobs::build_and_publish_openvmm_hcl_baseline::KernelCheck;
700+
use flowey_lib_hvlite::resolve_openhcl_kernel_package::OpenhclKernelPackageKind;
701+
699702
// emit openhcl build job
700703
for arch in [CommonArch::Aarch64, CommonArch::X86_64] {
701704
let arch_tag = match arch {
@@ -722,6 +725,23 @@ impl IntoPipeline for CheckinGatesCli {
722725
(None, None)
723726
};
724727

728+
let arch_kernel_checks: Vec<KernelCheck> = match arch {
729+
CommonArch::X86_64 => vec![
730+
KernelCheck {
731+
kind: OpenhclKernelPackageKind::Main,
732+
label: "kernel-main".into(),
733+
},
734+
KernelCheck {
735+
kind: OpenhclKernelPackageKind::Cvm,
736+
label: "kernel-cvm".into(),
737+
},
738+
],
739+
CommonArch::Aarch64 => vec![KernelCheck {
740+
kind: OpenhclKernelPackageKind::Main,
741+
label: "kernel-main".into(),
742+
}],
743+
};
744+
725745
// also build pipette musl on this job, as until we land the
726746
// refactor that allows building musl without the full openhcl
727747
// toolchain, it would require pulling in all the openhcl
@@ -802,6 +822,7 @@ impl IntoPipeline for CheckinGatesCli {
802822
artifact_dir_openhcl_igvm_extras: ctx
803823
.publish_artifact(pub_openhcl_igvm_extras),
804824
artifact_openhcl_verify_size_baseline: publish_baseline_artifact,
825+
kernel_checks_for_baseline: arch_kernel_checks.clone(),
805826
done: ctx.new_done_handle(),
806827
}
807828
})
@@ -842,6 +863,7 @@ impl IntoPipeline for CheckinGatesCli {
842863
arch,
843864
platform: CommonPlatform::LinuxMusl,
844865
},
866+
kernel_checks: arch_kernel_checks,
845867
done: ctx.new_done_handle(),
846868
pipeline_name: "openvmm-ci.yaml".into(),
847869
job_name: build_openhcl_job_tag(arch_tag),
@@ -1417,6 +1439,7 @@ impl IntoPipeline for CheckinGatesCli {
14171439
artifact_dir_openhcl_igvm_extras: ctx
14181440
.publish_artifact(pub_mi_secure_igvm_extras),
14191441
artifact_openhcl_verify_size_baseline: None,
1442+
kernel_checks_for_baseline: vec![],
14201443
done: ctx.new_done_handle(),
14211444
}
14221445
});

flowey/flowey_lib_hvlite/src/_jobs/build_and_publish_openhcl_igvm_from_recipe.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ flowey_request! {
3333
pub artifact_dir_openhcl_igvm: ReadVar<PathBuf>,
3434
pub artifact_dir_openhcl_igvm_extras: ReadVar<PathBuf>,
3535
pub artifact_openhcl_verify_size_baseline: Option<ReadVar<PathBuf>>,
36+
pub kernel_checks_for_baseline: Vec<build_and_publish_openvmm_hcl_baseline::KernelCheck>,
3637
pub done: WriteVar<SideEffect>,
3738
}
3839
}
@@ -56,6 +57,7 @@ impl SimpleFlowNode for Node {
5657
artifact_dir_openhcl_igvm,
5758
artifact_dir_openhcl_igvm_extras,
5859
artifact_openhcl_verify_size_baseline,
60+
kernel_checks_for_baseline,
5961
done,
6062
} = request;
6163

@@ -151,6 +153,7 @@ impl SimpleFlowNode for Node {
151153
did_publish.push(ctx.reqv(|v| {
152154
build_and_publish_openvmm_hcl_baseline::Request {
153155
target: custom_target,
156+
kernel_checks: kernel_checks_for_baseline,
154157
artifact_dir: sizecheck_artifact,
155158
done: v,
156159
}

flowey/flowey_lib_hvlite/src/_jobs/build_and_publish_openvmm_hcl_baseline.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
//! Builds and publishes an OpenHCL binary for size comparison with PRs.
4+
//! Builds and publishes an OpenHCL binary and kernel binaries for size
5+
//! comparison with PRs.
56
67
use crate::artifact_openvmm_hcl_sizecheck;
78
use crate::build_openhcl_igvm_from_recipe::OpenhclIgvmRecipe;
89
use crate::build_openvmm_hcl;
910
use crate::build_openvmm_hcl::OpenvmmHclBuildParams;
1011
use crate::build_openvmm_hcl::OpenvmmHclBuildProfile;
12+
use crate::resolve_openhcl_kernel_package::OpenhclKernelPackageArch;
13+
use crate::resolve_openhcl_kernel_package::OpenhclKernelPackageKind;
1114
use crate::run_cargo_build::common::CommonArch;
1215
use crate::run_cargo_build::common::CommonTriple;
1316
use flowey::node::prelude::*;
1417

18+
/// A kernel to include in the baseline artifact.
19+
#[derive(Clone, Serialize, Deserialize)]
20+
pub struct KernelCheck {
21+
pub kind: OpenhclKernelPackageKind,
22+
pub label: String,
23+
}
24+
1525
flowey_request! {
1626
pub struct Request {
1727
pub target: CommonTriple,
28+
pub kernel_checks: Vec<KernelCheck>,
1829
pub artifact_dir: ReadVar<PathBuf>,
1930
pub done: WriteVar<SideEffect>,
2031
}
@@ -28,16 +39,20 @@ impl SimpleFlowNode for Node {
2839
fn imports(ctx: &mut ImportCtx<'_>) {
2940
ctx.import::<artifact_openvmm_hcl_sizecheck::publish::Node>();
3041
ctx.import::<build_openvmm_hcl::Node>();
42+
ctx.import::<crate::resolve_openhcl_kernel_package::Node>();
3143
}
3244

3345
fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
3446
let Request {
3547
target,
48+
kernel_checks,
3649
done,
3750
artifact_dir,
3851
} = request;
3952

40-
let recipe = match target.common_arch().unwrap() {
53+
let arch = target.common_arch().unwrap();
54+
55+
let recipe = match arch {
4156
CommonArch::X86_64 => OpenhclIgvmRecipe::X64,
4257
CommonArch::Aarch64 => OpenhclIgvmRecipe::Aarch64,
4358
}
@@ -54,8 +69,32 @@ impl SimpleFlowNode for Node {
5469
openvmm_hcl_output: v,
5570
});
5671

72+
let kernel_arch = match arch {
73+
CommonArch::X86_64 => OpenhclKernelPackageArch::X86_64,
74+
CommonArch::Aarch64 => OpenhclKernelPackageArch::Aarch64,
75+
};
76+
77+
let kernel_baselines: Vec<_> = kernel_checks
78+
.into_iter()
79+
.map(|kc| {
80+
let kernel =
81+
ctx.reqv(
82+
|v| crate::resolve_openhcl_kernel_package::Request::GetKernel {
83+
kind: kc.kind,
84+
arch: kernel_arch,
85+
kernel: v,
86+
},
87+
);
88+
artifact_openvmm_hcl_sizecheck::publish::KernelBaseline {
89+
label: kc.label,
90+
kernel,
91+
}
92+
})
93+
.collect();
94+
5795
ctx.req(artifact_openvmm_hcl_sizecheck::publish::Request {
5896
openvmm_openhcl: baseline_hcl_build,
97+
kernel_baselines,
5998
artifact_dir,
6099
done,
61100
});

flowey/flowey_lib_hvlite/src/_jobs/build_openhcl_igvm_from_recipe_nix.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ impl SimpleFlowNode for Node {
5656
artifact_dir_openhcl_igvm,
5757
artifact_dir_openhcl_igvm_extras,
5858
artifact_openhcl_verify_size_baseline,
59+
kernel_checks_for_baseline: Vec::new(),
5960
done,
6061
},
6162
);

flowey/flowey_lib_hvlite/src/_jobs/check_openvmm_hcl_size.rs

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
//! Compares the size of the OpenHCL binary in the current PR with the size of the binary from the last successful merge to main.
4+
//! Compares the size of the OpenHCL binary and kernel binaries in the current
5+
//! PR with the sizes from the last successful merge to main.
56
6-
use crate::artifact_openhcl_igvm_from_recipe_extras;
7+
use crate::_jobs::build_and_publish_openvmm_hcl_baseline::KernelCheck;
78
use crate::build_openhcl_igvm_from_recipe;
89
use crate::build_openhcl_igvm_from_recipe::OpenhclIgvmRecipe;
910
use crate::build_openvmm_hcl;
1011
use crate::build_openvmm_hcl::OpenvmmHclBuildParams;
1112
use crate::build_openvmm_hcl::OpenvmmHclBuildProfile::OpenvmmHclShip;
13+
use crate::resolve_openhcl_kernel_package::OpenhclKernelPackageArch;
1214
use crate::run_cargo_build::common::CommonArch;
1315
use crate::run_cargo_build::common::CommonPlatform;
1416
use crate::run_cargo_build::common::CommonTriple;
@@ -20,6 +22,7 @@ use flowey_lib_common::git_merge_commit;
2022
flowey_request! {
2123
pub struct Request {
2224
pub target: CommonTriple,
25+
pub kernel_checks: Vec<KernelCheck>,
2326
pub done: WriteVar<SideEffect>,
2427
pub pipeline_name: String,
2528
pub job_name: String,
@@ -34,22 +37,25 @@ impl SimpleFlowNode for Node {
3437
fn imports(ctx: &mut ImportCtx<'_>) {
3538
ctx.import::<crate::build_xtask::Node>();
3639
ctx.import::<crate::git_checkout_openvmm_repo::Node>();
40+
ctx.import::<crate::resolve_openhcl_kernel_package::Node>();
3741
ctx.import::<download_gh_artifact::Node>();
3842
ctx.import::<git_merge_commit::Node>();
3943
ctx.import::<gh_workflow_id::Node>();
4044
ctx.import::<build_openhcl_igvm_from_recipe::Node>();
4145
ctx.import::<build_openvmm_hcl::Node>();
42-
ctx.import::<artifact_openhcl_igvm_from_recipe_extras::publish::Node>();
4346
}
4447

4548
fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
4649
let Request {
4750
target,
51+
kernel_checks,
4852
done,
4953
pipeline_name,
5054
job_name,
5155
} = request;
5256

57+
let arch = target.common_arch().unwrap();
58+
5359
let xtask_target = CommonTriple::Common {
5460
arch: match ctx.arch() {
5561
FlowArch::X86_64 => CommonArch::X86_64,
@@ -70,7 +76,7 @@ impl SimpleFlowNode for Node {
7076
});
7177
let openvmm_repo_path = ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir);
7278

73-
let recipe = match target.common_arch().unwrap() {
79+
let recipe = match arch {
7480
CommonArch::X86_64 => OpenhclIgvmRecipe::X64,
7581
CommonArch::Aarch64 => OpenhclIgvmRecipe::Aarch64,
7682
}
@@ -87,7 +93,27 @@ impl SimpleFlowNode for Node {
8793
openvmm_hcl_output: v,
8894
});
8995

90-
let file_name = match target.common_arch().unwrap() {
96+
let kernel_arch = match arch {
97+
CommonArch::X86_64 => OpenhclKernelPackageArch::X86_64,
98+
CommonArch::Aarch64 => OpenhclKernelPackageArch::Aarch64,
99+
};
100+
101+
let current_kernels: Vec<_> = kernel_checks
102+
.iter()
103+
.map(|kc| {
104+
let kernel =
105+
ctx.reqv(
106+
|v| crate::resolve_openhcl_kernel_package::Request::GetKernel {
107+
kind: kc.kind,
108+
arch: kernel_arch,
109+
kernel: v,
110+
},
111+
);
112+
(kc.label.clone(), kernel)
113+
})
114+
.collect();
115+
116+
let file_name = match arch {
91117
CommonArch::X86_64 => "x64-openhcl-baseline",
92118
CommonArch::Aarch64 => "aarch64-openhcl-baseline",
93119
};
@@ -121,10 +147,6 @@ impl SimpleFlowNode for Node {
121147
});
122148

123149
// Publish the built binary as an artifact for offline analysis.
124-
//
125-
// FUTURE: Flowey should have a general mechanism for this. We cannot
126-
// use the existing artifact support because all artifacts are only
127-
// published at the end of the job, if everything else succeeds.
128150
let publish_artifact = if ctx.backend() == FlowBackend::Github {
129151
let dir = ctx.emit_rust_stepv("collect openvmm_hcl files for analysis", |ctx| {
130152
let built_openvmm_hcl = built_openvmm_hcl.clone().claim(ctx);
@@ -162,13 +184,16 @@ impl SimpleFlowNode for Node {
162184
};
163185

164186
let comparison = ctx.emit_rust_step("binary size comparison", |ctx| {
165-
// Ensure the artifact is published before the analysis since this step may fail.
166187
let _publish_artifact = publish_artifact.claim(ctx);
167188
let xtask = xtask.claim(ctx);
168189
let openvmm_repo_path = openvmm_repo_path.claim(ctx);
169190
let old_openhcl = merge_head_artifact.claim(ctx);
170191
let new_openhcl = built_openvmm_hcl.claim(ctx);
171192
let merge_run = merge_run.claim(ctx);
193+
let current_kernels: Vec<_> = current_kernels
194+
.into_iter()
195+
.map(|(label, k)| (label, k.claim(ctx)))
196+
.collect();
172197

173198
move |rt| {
174199
let xtask = match rt.read(xtask) {
@@ -180,22 +205,36 @@ impl SimpleFlowNode for Node {
180205
let new_openhcl = rt.read(new_openhcl);
181206
let merge_run = rt.read(merge_run);
182207

183-
let old_path = old_openhcl.join(file_name).join("openhcl");
184-
let new_path = new_openhcl.bin;
208+
let path = rt.read(openvmm_repo_path);
209+
rt.sh.change_dir(&path);
185210

186211
println!(
187212
"comparing HEAD to merge commit {} and workflow {}",
188213
merge_run.commit, merge_run.id
189214
);
190215

191-
let path = rt.read(openvmm_repo_path);
192-
rt.sh.change_dir(path);
216+
// Compare usermode binary
217+
let old_path = old_openhcl.join(file_name).join("openhcl");
218+
let new_path = &new_openhcl.bin;
219+
println!("== openvmm_hcl usermode binary ==");
193220
flowey::shell_cmd!(
194221
rt,
195222
"{xtask} verify-size --original {old_path} --new {new_path}"
196223
)
197224
.run()?;
198225

226+
// Compare kernel binaries
227+
for (label, kernel_var) in current_kernels {
228+
let new_kernel = rt.read(kernel_var);
229+
let old_kernel = old_openhcl.join(file_name).join(&label);
230+
println!("== kernel: {label} ==");
231+
flowey::shell_cmd!(
232+
rt,
233+
"{xtask} verify-size --original {old_kernel} --new {new_kernel}"
234+
)
235+
.run()?;
236+
}
237+
199238
Ok(())
200239
}
201240
});

0 commit comments

Comments
 (0)