Skip to main content

flowey_lib_hvlite/
run_vmm_perf.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Run the standalone VMM.Perf runner.
5
6use flowey::node::prelude::*;
7
8pub fn all_profiles() -> Vec<String> {
9    vec![
10        "boot-time".into(),
11        "fio:vmbus".into(),
12        "fio:virtio".into(),
13        "iperf3:vmbus".into(),
14        "iperf3:virtio".into(),
15    ]
16}
17
18pub fn default_profiles() -> Vec<String> {
19    vec!["boot-time".into(), "fio".into(), "iperf3".into()]
20}
21
22#[derive(Clone, Debug, Serialize, Deserialize)]
23pub struct VmmPerfRunOutput {
24    pub results_dir: PathBuf,
25    pub success: bool,
26    pub exit_code: Option<i32>,
27}
28
29flowey_request! {
30    pub struct Request {
31        pub runner: ReadVar<crate::build_vmm_perf::VmmPerfOutput>,
32        pub openvmm: ReadVar<crate::build_openvmm::OpenvmmOutput>,
33        pub firmware: ReadVar<PathBuf>,
34        pub runtime_archive: ReadVar<PathBuf>,
35        pub output_dir: ReadVar<PathBuf>,
36        pub temp_dir: Option<ReadVar<PathBuf>>,
37        pub profiles: Vec<String>,
38        pub vm_sizes_json: Option<String>,
39        pub parameters_json: Option<String>,
40        /// Wait for host dependencies to be installed before running VMM.Perf.
41        pub pre_run_deps: Vec<ReadVar<SideEffect>>,
42        pub output: WriteVar<VmmPerfRunOutput>,
43    }
44}
45
46new_simple_flow_node!(struct Node);
47
48impl SimpleFlowNode for Node {
49    type Request = Request;
50
51    fn imports(_ctx: &mut ImportCtx<'_>) {}
52
53    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
54        let Request {
55            runner,
56            openvmm,
57            firmware,
58            runtime_archive,
59            output_dir,
60            temp_dir,
61            profiles,
62            vm_sizes_json,
63            parameters_json,
64            pre_run_deps,
65            output,
66        } = request;
67
68        ctx.emit_rust_step("run VMM.Perf", |ctx| {
69            pre_run_deps.claim(ctx);
70            let runner = runner.claim(ctx);
71            let openvmm = openvmm.claim(ctx);
72            let firmware = firmware.claim(ctx);
73            let runtime_archive = runtime_archive.claim(ctx);
74            let output_dir = output_dir.claim(ctx);
75            let temp_dir = temp_dir.map(|temp_dir| temp_dir.claim(ctx));
76            let output = output.claim(ctx);
77
78            move |rt| {
79                let runner = match rt.read(runner) {
80                    crate::build_vmm_perf::VmmPerfOutput::LinuxBin { bin, .. } => bin,
81                    crate::build_vmm_perf::VmmPerfOutput::WindowsBin { exe, .. } => exe,
82                };
83                let openvmm = match rt.read(openvmm) {
84                    crate::build_openvmm::OpenvmmOutput::LinuxBin { bin, .. } => bin,
85                    crate::build_openvmm::OpenvmmOutput::WindowsBin { exe, .. } => exe,
86                };
87                let firmware = rt.read(firmware);
88                let runtime_archive = rt.read(runtime_archive);
89                let output_dir = rt.read(output_dir).absolute()?;
90                let temp_dir = temp_dir
91                    .map(|temp_dir| rt.read(temp_dir).absolute())
92                    .transpose()?;
93
94                runner.make_executable()?;
95                openvmm.make_executable()?;
96                fs_err::create_dir_all(&output_dir)?;
97                if let Some(temp_dir) = &temp_dir {
98                    fs_err::create_dir_all(temp_dir)?;
99                }
100
101                let mut args = vec![
102                    "--openvmm".to_string(),
103                    openvmm.display().to_string(),
104                    "--firmware".to_string(),
105                    firmware.display().to_string(),
106                    "--runtime-archive".to_string(),
107                    runtime_archive.display().to_string(),
108                    "--output-dir".to_string(),
109                    output_dir.display().to_string(),
110                ];
111                if let Some(temp_dir) = &temp_dir {
112                    args.push("--temp-dir".into());
113                    args.push(temp_dir.display().to_string());
114                }
115                for profile in &profiles {
116                    args.push("--profile".into());
117                    args.push(profile.clone());
118                }
119                if let Some(vm_sizes_json) = &vm_sizes_json {
120                    args.push("--vm-sizes-json".into());
121                    args.push(vm_sizes_json.clone());
122                }
123                if let Some(parameters_json) = &parameters_json {
124                    args.push("--parameters-json".into());
125                    args.push(parameters_json.clone());
126                }
127
128                let process = flowey::shell_cmd!(rt, "{runner} {args...}")
129                    .ignore_status()
130                    .output()?;
131                if !process.stdout.is_empty() {
132                    log::info!("{}", String::from_utf8_lossy(&process.stdout));
133                }
134                if !process.stderr.is_empty() {
135                    log::warn!("{}", String::from_utf8_lossy(&process.stderr));
136                }
137
138                rt.write(
139                    output,
140                    &VmmPerfRunOutput {
141                        results_dir: output_dir,
142                        success: process.status.success(),
143                        exit_code: process.status.code(),
144                    },
145                );
146                Ok(())
147            }
148        });
149
150        Ok(())
151    }
152}