mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
block: Set an option to pin virtio block threads to host cpus
Currently the only way to set the affinity for virtio block threads is to boot the VM, search for the tid of each of the virtio block threads, then set the affinity manually. This commit adds an option to pin virtio block queues to specific host cpus (similar to pinning vcpus to host cpus). A queue_affinity option has been added to the disk flag in the cli to specify a mapping of queue indices to host cpus. Signed-off-by: acarp <acarp@crusoeenergy.com>
This commit is contained in:
@@ -828,6 +828,19 @@ components:
|
||||
type: string
|
||||
rate_limiter_config:
|
||||
$ref: "#/components/schemas/RateLimiterConfig"
|
||||
|
||||
VirtQueueAffinity:
|
||||
required:
|
||||
- queue_index
|
||||
- host_cpus
|
||||
type: object
|
||||
properties:
|
||||
queue_index:
|
||||
type: integer
|
||||
host_cpus:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
|
||||
DiskConfig:
|
||||
required:
|
||||
@@ -867,6 +880,10 @@ components:
|
||||
type: string
|
||||
rate_limit_group:
|
||||
type: string
|
||||
affinity:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/VirtQueueAffinity"
|
||||
|
||||
NetConfig:
|
||||
type: object
|
||||
|
||||
@@ -1001,7 +1001,8 @@ impl DiskConfig {
|
||||
vhost_user=on|off,socket=<vhost_user_socket_path>,\
|
||||
bw_size=<bytes>,bw_one_time_burst=<bytes>,bw_refill_time=<ms>,\
|
||||
ops_size=<io_ops>,ops_one_time_burst=<io_ops>,ops_refill_time=<ms>,\
|
||||
id=<device_id>,pci_segment=<segment_id>,rate_limit_group=<group_id>\"";
|
||||
id=<device_id>,pci_segment=<segment_id>,rate_limit_group=<group_id>,\
|
||||
queue_affinity=<list_of_queue_indices_with_their_associated_cpuset>";
|
||||
|
||||
pub fn parse(disk: &str) -> Result<Self> {
|
||||
let mut parser = OptionParser::new();
|
||||
@@ -1025,7 +1026,8 @@ impl DiskConfig {
|
||||
.add("_disable_aio")
|
||||
.add("pci_segment")
|
||||
.add("serial")
|
||||
.add("rate_limit_group");
|
||||
.add("rate_limit_group")
|
||||
.add("queue_affinity");
|
||||
parser.parse(disk).map_err(Error::ParseDisk)?;
|
||||
|
||||
let path = parser.get("path").map(PathBuf::from);
|
||||
@@ -1099,6 +1101,17 @@ impl DiskConfig {
|
||||
.map_err(Error::ParseDisk)?
|
||||
.unwrap_or_default();
|
||||
let serial = parser.get("serial");
|
||||
let queue_affinity = parser
|
||||
.convert::<Tuple<u16, Vec<usize>>>("queue_affinity")
|
||||
.map_err(Error::ParseDisk)?
|
||||
.map(|v| {
|
||||
v.0.iter()
|
||||
.map(|(e1, e2)| VirtQueueAffinity {
|
||||
queue_index: *e1,
|
||||
host_cpus: e2.clone(),
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
let bw_tb_config = if bw_size != 0 && bw_refill_time != 0 {
|
||||
Some(TokenBucketConfig {
|
||||
size: bw_size,
|
||||
@@ -1142,6 +1155,7 @@ impl DiskConfig {
|
||||
disable_aio,
|
||||
pci_segment,
|
||||
serial,
|
||||
queue_affinity,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2922,6 +2936,7 @@ mod tests {
|
||||
rate_limiter_config: None,
|
||||
pci_segment: 0,
|
||||
serial: None,
|
||||
queue_affinity: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2992,6 +3007,30 @@ mod tests {
|
||||
..disk_fixture()
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
DiskConfig::parse("path=/path/to_file,queue_affinity=[0@[1],1@[2],2@[3,4],3@[5-8]]")?,
|
||||
DiskConfig {
|
||||
queue_affinity: Some(vec![
|
||||
VirtQueueAffinity {
|
||||
queue_index: 0,
|
||||
host_cpus: vec![1],
|
||||
},
|
||||
VirtQueueAffinity {
|
||||
queue_index: 1,
|
||||
host_cpus: vec![2],
|
||||
},
|
||||
VirtQueueAffinity {
|
||||
queue_index: 2,
|
||||
host_cpus: vec![3, 4],
|
||||
},
|
||||
VirtQueueAffinity {
|
||||
queue_index: 3,
|
||||
host_cpus: vec![5, 6, 7, 8],
|
||||
}
|
||||
]),
|
||||
..disk_fixture()
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ use pci::{
|
||||
use rate_limiter::group::RateLimiterGroup;
|
||||
use seccompiler::SeccompAction;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||
use std::fs::{read_link, File, OpenOptions};
|
||||
use std::io::{self, stdout, Seek, SeekFrom};
|
||||
use std::mem::zeroed;
|
||||
@@ -2512,6 +2512,15 @@ impl DeviceManager {
|
||||
None
|
||||
};
|
||||
|
||||
let queue_affinity = if let Some(queue_affinity) = disk_cfg.queue_affinity.as_ref() {
|
||||
queue_affinity
|
||||
.iter()
|
||||
.map(|a| (a.queue_index, a.host_cpus.clone()))
|
||||
.collect()
|
||||
} else {
|
||||
BTreeMap::new()
|
||||
};
|
||||
|
||||
let virtio_block = Arc::new(Mutex::new(
|
||||
virtio_devices::Block::new(
|
||||
id.clone(),
|
||||
@@ -2535,6 +2544,7 @@ impl DeviceManager {
|
||||
.map(|s| s.to_versioned_state())
|
||||
.transpose()
|
||||
.map_err(DeviceManagerError::RestoreGetState)?,
|
||||
queue_affinity,
|
||||
)
|
||||
.map_err(DeviceManagerError::CreateVirtioBlock)?,
|
||||
));
|
||||
|
||||
@@ -187,6 +187,12 @@ pub struct RateLimiterGroupConfig {
|
||||
pub rate_limiter_config: RateLimiterConfig,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct VirtQueueAffinity {
|
||||
pub queue_index: u16,
|
||||
pub host_cpus: Vec<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct DiskConfig {
|
||||
pub path: Option<PathBuf>,
|
||||
@@ -219,6 +225,8 @@ pub struct DiskConfig {
|
||||
pub pci_segment: u16,
|
||||
#[serde(default)]
|
||||
pub serial: Option<String>,
|
||||
#[serde(default)]
|
||||
pub queue_affinity: Option<Vec<VirtQueueAffinity>>,
|
||||
}
|
||||
|
||||
pub const DEFAULT_DISK_NUM_QUEUES: usize = 1;
|
||||
|
||||
Reference in New Issue
Block a user