Skip to main content

qemu_command_builder/args/
smp.rs

1use crate::parsers::ARG_SMP;
2use crate::parsers::DELIM_COMMA;
3use crate::shell_string::ShellStringError;
4use crate::to_command::ToCommand;
5use crate::{pco, qao};
6use bon::Builder;
7use proptest_derive::Arbitrary;
8use std::str::FromStr;
9use winnow::ascii::{dec_uint, digit1};
10use winnow::combinator::opt;
11use winnow::token::literal;
12use winnow::{ModalResult, Parser};
13
14const KEY_MAXCPUS: &str = "maxcpus=";
15const KEY_DRAWERS: &str = "drawers=";
16const KEY_BOOKS: &str = "books=";
17const KEY_SOCKETS: &str = "sockets=";
18const KEY_DIES: &str = "dies=";
19const KEY_CLUSTERS: &str = "clusters=";
20const KEY_MODULES: &str = "modules=";
21const KEY_CORES: &str = "cores=";
22const KEY_THREADS: &str = "threads=";
23
24/// Simulate a SMP system with ``n`` CPUs initially present on
25/// the machine type board. On boards supporting CPU hotplug, the optional
26/// ``maxcpus`` parameter can be set to enable further CPUs to be
27/// added at runtime. When both parameters are omitted, the maximum number
28/// of CPUs will be calculated from the provided topology members and the
29/// initial CPU count will match the maximum number. When only one of them
30/// is given then the omitted one will be set to its counterpart's value.
31/// Both parameters may be specified, but the maximum number of CPUs must
32/// be equal to or greater than the initial CPU count. Product of the
33/// CPU topology hierarchy must be equal to the maximum number of CPUs.
34/// Both parameters are subject to an upper limit that is determined by
35/// the specific machine type chosen.
36///
37/// To control reporting of CPU topology information, values of the topology
38/// parameters can be specified. Machines may only support a subset of the
39/// parameters and different machines may have different subsets supported
40/// which vary depending on capacity of the corresponding CPU targets. So
41/// for a particular machine type board, an expected topology hierarchy can
42/// be defined through the supported sub-option. Unsupported parameters can
43/// also be provided in addition to the sub-option, but their values must be
44/// set as 1 in the purpose of correct parsing.
45///
46/// Either the initial CPU count, or at least one of the topology parameters
47/// must be specified. The specified parameters must be greater than zero,
48/// explicit configuration like "cpus=0" is not allowed. Values for any
49/// omitted parameters will be computed from those which are given.
50///
51/// For example, the following sub-option defines a CPU topology hierarchy
52/// (2 sockets totally on the machine, 2 cores per socket, 2 threads per
53/// core) for a machine that only supports sockets/cores/threads.
54/// Some members of the option can be omitted but their values will be
55/// automatically computed:
56#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder, Arbitrary)]
57pub struct SMP {
58    /// set the number of initial CPUs to 'n' [default=1]
59    cpus: u64,
60    /// maximum number of total CPUs, including offline CPUs for hotplug, etc
61    maxcpus: Option<usize>,
62    /// number of drawers on the machine board
63    drawers: Option<usize>,
64    /// number of books in one drawer
65    books: Option<usize>,
66    /// number of sockets in one book
67    sockets: Option<usize>,
68    /// number of dies in one socket
69    dies: Option<usize>,
70    /// number of clusters in one die
71    clusters: Option<usize>,
72    /// number of modules in one cluster
73    modules: Option<usize>,
74    /// number of cores in one module
75    cores: Option<usize>,
76    /// number of threads in one core
77    threads: Option<usize>,
78}
79
80impl Default for SMP {
81    fn default() -> Self {
82        SMP::new(1)
83    }
84}
85
86impl SMP {
87    pub fn new(cpus: u64) -> Self {
88        Self {
89            cpus,
90            maxcpus: None,
91            drawers: None,
92            books: None,
93            sockets: None,
94            dies: None,
95            clusters: None,
96            modules: None,
97            cores: None,
98            threads: None,
99        }
100    }
101}
102
103impl ToCommand for SMP {
104    fn command(&self) -> String {
105        ARG_SMP.to_string()
106    }
107    fn to_args(&self) -> Vec<String> {
108        let mut args = vec![self.cpus.to_string()];
109
110        qao!(self.maxcpus, args, KEY_MAXCPUS);
111        qao!(self.drawers, args, KEY_DRAWERS);
112        qao!(self.books, args, KEY_BOOKS);
113        qao!(self.sockets, args, KEY_SOCKETS);
114        qao!(self.dies, args, KEY_DIES);
115        qao!(self.clusters, args, KEY_CLUSTERS);
116        qao!(self.modules, args, KEY_MODULES);
117        qao!(self.cores, args, KEY_CORES);
118        qao!(self.threads, args, KEY_THREADS);
119
120        vec![args.join(DELIM_COMMA)]
121    }
122}
123
124impl FromStr for SMP {
125    type Err = ShellStringError;
126
127    fn from_str(s: &str) -> Result<Self, Self::Err> {
128        smp.parse(s).map_err(|e| ShellStringError::from_parse(e))
129    }
130}
131
132pco!(maxcpus, digit1, usize, KEY_MAXCPUS);
133pco!(drawers, digit1, usize, KEY_DRAWERS);
134pco!(books, digit1, usize, KEY_BOOKS);
135pco!(sockets, digit1, usize, KEY_SOCKETS);
136pco!(dies, digit1, usize, KEY_DIES);
137pco!(clusters, digit1, usize, KEY_CLUSTERS);
138pco!(modules, digit1, usize, KEY_MODULES);
139pco!(cores, digit1, usize, KEY_CORES);
140pco!(threads, digit1, usize, KEY_THREADS);
141
142fn smp(s: &mut &str) -> ModalResult<SMP> {
143    let cpus = dec_uint.parse_next(s)?;
144    let maxcpus = opt(maxcpus).parse_next(s)?;
145    let drawers = opt(drawers).parse_next(s)?;
146    let books = opt(books).parse_next(s)?;
147    let sockets = opt(sockets).parse_next(s)?;
148    let dies = opt(dies).parse_next(s)?;
149    let clusters = opt(clusters).parse_next(s)?;
150    let modules = opt(modules).parse_next(s)?;
151    let cores = opt(cores).parse_next(s)?;
152    let threads = opt(threads).parse_next(s)?;
153    Ok(SMP {
154        cpus,
155        maxcpus,
156        drawers,
157        books,
158        sockets,
159        dies,
160        clusters,
161        modules,
162        cores,
163        threads,
164    })
165}