Skip to content

Commit 2386d79

Browse files
author
OpenVMM Team
committed
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 cf30c6f commit 2386d79

8 files changed

Lines changed: 163 additions & 22 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: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,9 @@ impl IntoPipeline for CheckinGatesCli {
680680
all_jobs.push(job.finish());
681681
}
682682

683+
use flowey_lib_hvlite::_jobs::build_and_publish_openvmm_hcl_baseline::KernelCheck;
684+
use flowey_lib_hvlite::resolve_openhcl_kernel_package::OpenhclKernelPackageKind;
685+
683686
// emit openhcl build job
684687
for arch in [CommonArch::Aarch64, CommonArch::X86_64] {
685688
let arch_tag = match arch {
@@ -706,6 +709,23 @@ impl IntoPipeline for CheckinGatesCli {
706709
(None, None)
707710
};
708711

712+
let arch_kernel_checks: Vec<KernelCheck> = match arch {
713+
CommonArch::X86_64 => vec![
714+
KernelCheck {
715+
kind: OpenhclKernelPackageKind::Main,
716+
label: "kernel-main".into(),
717+
},
718+
KernelCheck {
719+
kind: OpenhclKernelPackageKind::Cvm,
720+
label: "kernel-cvm".into(),
721+
},
722+
],
723+
CommonArch::Aarch64 => vec![KernelCheck {
724+
kind: OpenhclKernelPackageKind::Main,
725+
label: "kernel-main".into(),
726+
}],
727+
};
728+
709729
// also build pipette musl on this job, as until we land the
710730
// refactor that allows building musl without the full openhcl
711731
// toolchain, it would require pulling in all the openhcl
@@ -785,6 +805,7 @@ impl IntoPipeline for CheckinGatesCli {
785805
artifact_dir_openhcl_igvm_extras: ctx
786806
.publish_artifact(pub_openhcl_igvm_extras),
787807
artifact_openhcl_verify_size_baseline: publish_baseline_artifact,
808+
kernel_checks_for_baseline: arch_kernel_checks.clone(),
788809
done: ctx.new_done_handle(),
789810
}
790811
})
@@ -825,6 +846,7 @@ impl IntoPipeline for CheckinGatesCli {
825846
arch,
826847
platform: CommonPlatform::LinuxMusl,
827848
},
849+
kernel_checks: arch_kernel_checks,
828850
done: ctx.new_done_handle(),
829851
pipeline_name: "openvmm-ci.yaml".into(),
830852
job_name: build_openhcl_job_tag(arch_tag),

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
@@ -29,6 +29,7 @@ flowey_request! {
2929
pub artifact_dir_openhcl_igvm: ReadVar<PathBuf>,
3030
pub artifact_dir_openhcl_igvm_extras: ReadVar<PathBuf>,
3131
pub artifact_openhcl_verify_size_baseline: Option<ReadVar<PathBuf>>,
32+
pub kernel_checks_for_baseline: Vec<build_and_publish_openvmm_hcl_baseline::KernelCheck>,
3233
pub done: WriteVar<SideEffect>,
3334
}
3435
}
@@ -52,6 +53,7 @@ impl SimpleFlowNode for Node {
5253
artifact_dir_openhcl_igvm,
5354
artifact_dir_openhcl_igvm_extras,
5455
artifact_openhcl_verify_size_baseline,
56+
kernel_checks_for_baseline,
5557
done,
5658
} = request;
5759

@@ -145,6 +147,7 @@ impl SimpleFlowNode for Node {
145147
did_publish.push(ctx.reqv(|v| {
146148
build_and_publish_openvmm_hcl_baseline::Request {
147149
target: custom_target,
150+
kernel_checks: kernel_checks_for_baseline,
148151
artifact_dir: sizecheck_artifact,
149152
done: v,
150153
}

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: 61 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);
@@ -161,14 +183,19 @@ impl SimpleFlowNode for Node {
161183
None
162184
};
163185

186+
let _kernel_labels: Vec<String> = kernel_checks.into_iter().map(|kc| kc.label).collect();
187+
164188
let comparison = ctx.emit_rust_step("binary size comparison", |ctx| {
165-
// Ensure the artifact is published before the analysis since this step may fail.
166189
let _publish_artifact = publish_artifact.claim(ctx);
167190
let xtask = xtask.claim(ctx);
168191
let openvmm_repo_path = openvmm_repo_path.claim(ctx);
169192
let old_openhcl = merge_head_artifact.claim(ctx);
170193
let new_openhcl = built_openvmm_hcl.claim(ctx);
171194
let merge_run = merge_run.claim(ctx);
195+
let current_kernels: Vec<_> = current_kernels
196+
.into_iter()
197+
.map(|(label, k)| (label, k.claim(ctx)))
198+
.collect();
172199

173200
move |rt| {
174201
let xtask = match rt.read(xtask) {
@@ -180,22 +207,42 @@ impl SimpleFlowNode for Node {
180207
let new_openhcl = rt.read(new_openhcl);
181208
let merge_run = rt.read(merge_run);
182209

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

186213
println!(
187214
"comparing HEAD to merge commit {} and workflow {}",
188215
merge_run.commit, merge_run.id
189216
);
190217

191-
let path = rt.read(openvmm_repo_path);
192-
rt.sh.change_dir(path);
218+
// Compare usermode binary
219+
let old_path = old_openhcl.join(file_name).join("openhcl");
220+
let new_path = &new_openhcl.bin;
221+
println!("== openvmm_hcl usermode binary ==");
193222
flowey::shell_cmd!(
194223
rt,
195224
"{xtask} verify-size --original {old_path} --new {new_path}"
196225
)
197226
.run()?;
198227

228+
// Compare kernel binaries
229+
for (label, kernel_var) in current_kernels {
230+
let new_kernel = rt.read(kernel_var);
231+
let old_kernel = old_openhcl.join(file_name).join(&label);
232+
if old_kernel.exists() {
233+
println!("== kernel: {label} ==");
234+
flowey::shell_cmd!(
235+
rt,
236+
"{xtask} verify-size --original {old_kernel} --new {new_kernel}"
237+
)
238+
.run()?;
239+
} else {
240+
println!(
241+
"skipping kernel {label}: no baseline found (new kernel addition?)"
242+
);
243+
}
244+
}
245+
199246
Ok(())
200247
}
201248
});

0 commit comments

Comments
 (0)