mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-26 09:51:15 +00:00
virto-device: add latency account for virtio-block
Add new latency counters for virtio-block device, including minimal latency, maximal latency, and average latency for block read and write. The average latency is calculated based on cumulative average. Signed-off-by: Yong He <alexyonghe@tencent.com>
This commit is contained in:
parent
e2ea9e2821
commit
0dc122a9a9
@ -56,6 +56,9 @@ const COMPLETION_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2;
|
|||||||
// New 'wake up' event from the rate limiter
|
// New 'wake up' event from the rate limiter
|
||||||
const RATE_LIMITER_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3;
|
const RATE_LIMITER_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3;
|
||||||
|
|
||||||
|
// latency scale, for reduce precision loss in calculate.
|
||||||
|
const LATENCY_SCALE: u64 = 10000;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Failed to parse the request: {0}")]
|
#[error("Failed to parse the request: {0}")]
|
||||||
@ -80,12 +83,37 @@ pub enum Error {
|
|||||||
|
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
// latency will be records as microseconds, average latency
|
||||||
|
// will be save as scaled value.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct BlockCounters {
|
pub struct BlockCounters {
|
||||||
read_bytes: Arc<AtomicU64>,
|
read_bytes: Arc<AtomicU64>,
|
||||||
read_ops: Arc<AtomicU64>,
|
read_ops: Arc<AtomicU64>,
|
||||||
|
read_latency_min: Arc<AtomicU64>,
|
||||||
|
read_latency_max: Arc<AtomicU64>,
|
||||||
|
read_latency_avg: Arc<AtomicU64>,
|
||||||
write_bytes: Arc<AtomicU64>,
|
write_bytes: Arc<AtomicU64>,
|
||||||
write_ops: Arc<AtomicU64>,
|
write_ops: Arc<AtomicU64>,
|
||||||
|
write_latency_min: Arc<AtomicU64>,
|
||||||
|
write_latency_max: Arc<AtomicU64>,
|
||||||
|
write_latency_avg: Arc<AtomicU64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BlockCounters {
|
||||||
|
fn default() -> Self {
|
||||||
|
BlockCounters {
|
||||||
|
read_bytes: Arc::new(AtomicU64::new(0)),
|
||||||
|
read_ops: Arc::new(AtomicU64::new(0)),
|
||||||
|
read_latency_min: Arc::new(AtomicU64::new(u64::MAX)),
|
||||||
|
read_latency_max: Arc::new(AtomicU64::new(0)),
|
||||||
|
read_latency_avg: Arc::new(AtomicU64::new(0)),
|
||||||
|
write_bytes: Arc::new(AtomicU64::new(0)),
|
||||||
|
write_ops: Arc::new(AtomicU64::new(0)),
|
||||||
|
write_latency_min: Arc::new(AtomicU64::new(u64::MAX)),
|
||||||
|
write_latency_max: Arc::new(AtomicU64::new(0)),
|
||||||
|
write_latency_avg: Arc::new(AtomicU64::new(0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlockEpollHandler {
|
struct BlockEpollHandler {
|
||||||
@ -251,6 +279,11 @@ impl BlockEpollHandler {
|
|||||||
|
|
||||||
request.complete_async().map_err(Error::RequestCompleting)?;
|
request.complete_async().map_err(Error::RequestCompleting)?;
|
||||||
|
|
||||||
|
let latency = request.start.elapsed().as_micros() as u64;
|
||||||
|
let read_ops_last = self.counters.read_ops.load(Ordering::Relaxed) as i64;
|
||||||
|
let write_ops_last = self.counters.write_ops.load(Ordering::Relaxed) as i64;
|
||||||
|
let mut read_avg = self.counters.read_latency_avg.load(Ordering::Relaxed) as i64;
|
||||||
|
let mut write_avg = self.counters.write_latency_avg.load(Ordering::Relaxed) as i64;
|
||||||
let (status, len) = if result >= 0 {
|
let (status, len) = if result >= 0 {
|
||||||
match request.request_type {
|
match request.request_type {
|
||||||
RequestType::In => {
|
RequestType::In => {
|
||||||
@ -258,6 +291,19 @@ impl BlockEpollHandler {
|
|||||||
read_bytes += Wrapping(*data_len as u64);
|
read_bytes += Wrapping(*data_len as u64);
|
||||||
}
|
}
|
||||||
read_ops += Wrapping(1);
|
read_ops += Wrapping(1);
|
||||||
|
if latency < self.counters.read_latency_min.load(Ordering::Relaxed) {
|
||||||
|
self.counters
|
||||||
|
.read_latency_min
|
||||||
|
.store(latency, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
if latency > self.counters.read_latency_max.load(Ordering::Relaxed) {
|
||||||
|
self.counters
|
||||||
|
.read_latency_max
|
||||||
|
.store(latency, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
read_avg = read_avg
|
||||||
|
+ ((latency * LATENCY_SCALE) as i64 - read_avg)
|
||||||
|
/ (read_ops_last + read_ops.0 as i64);
|
||||||
}
|
}
|
||||||
RequestType::Out => {
|
RequestType::Out => {
|
||||||
if !request.writeback {
|
if !request.writeback {
|
||||||
@ -267,10 +313,31 @@ impl BlockEpollHandler {
|
|||||||
write_bytes += Wrapping(*data_len as u64);
|
write_bytes += Wrapping(*data_len as u64);
|
||||||
}
|
}
|
||||||
write_ops += Wrapping(1);
|
write_ops += Wrapping(1);
|
||||||
|
if latency < self.counters.write_latency_min.load(Ordering::Relaxed) {
|
||||||
|
self.counters
|
||||||
|
.write_latency_min
|
||||||
|
.store(latency, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
if latency > self.counters.write_latency_max.load(Ordering::Relaxed) {
|
||||||
|
self.counters
|
||||||
|
.write_latency_max
|
||||||
|
.store(latency, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
write_avg = write_avg
|
||||||
|
+ ((latency * LATENCY_SCALE) as i64 - write_avg)
|
||||||
|
/ (write_ops_last + write_ops.0 as i64);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.counters
|
||||||
|
.read_latency_avg
|
||||||
|
.store(read_avg as u64, Ordering::Relaxed);
|
||||||
|
|
||||||
|
self.counters
|
||||||
|
.write_latency_avg
|
||||||
|
.store(write_avg as u64, Ordering::Relaxed);
|
||||||
|
|
||||||
(VIRTIO_BLK_S_OK, result as u32)
|
(VIRTIO_BLK_S_OK, result as u32)
|
||||||
} else {
|
} else {
|
||||||
error!(
|
error!(
|
||||||
@ -728,6 +795,30 @@ impl VirtioDevice for Block {
|
|||||||
"write_ops",
|
"write_ops",
|
||||||
Wrapping(self.counters.write_ops.load(Ordering::Acquire)),
|
Wrapping(self.counters.write_ops.load(Ordering::Acquire)),
|
||||||
);
|
);
|
||||||
|
counters.insert(
|
||||||
|
"write_latency_min",
|
||||||
|
Wrapping(self.counters.write_latency_min.load(Ordering::Acquire)),
|
||||||
|
);
|
||||||
|
counters.insert(
|
||||||
|
"write_latency_max",
|
||||||
|
Wrapping(self.counters.write_latency_max.load(Ordering::Acquire)),
|
||||||
|
);
|
||||||
|
counters.insert(
|
||||||
|
"write_latency_avg",
|
||||||
|
Wrapping(self.counters.write_latency_avg.load(Ordering::Acquire) / LATENCY_SCALE),
|
||||||
|
);
|
||||||
|
counters.insert(
|
||||||
|
"read_latency_min",
|
||||||
|
Wrapping(self.counters.read_latency_min.load(Ordering::Acquire)),
|
||||||
|
);
|
||||||
|
counters.insert(
|
||||||
|
"read_latency_max",
|
||||||
|
Wrapping(self.counters.read_latency_max.load(Ordering::Acquire)),
|
||||||
|
);
|
||||||
|
counters.insert(
|
||||||
|
"read_latency_avg",
|
||||||
|
Wrapping(self.counters.read_latency_avg.load(Ordering::Acquire) / LATENCY_SCALE),
|
||||||
|
);
|
||||||
|
|
||||||
Some(counters)
|
Some(counters)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user