mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-21 20:15:21 +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
|
||||
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)]
|
||||
pub enum Error {
|
||||
#[error("Failed to parse the request: {0}")]
|
||||
@ -80,12 +83,37 @@ pub enum 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 {
|
||||
read_bytes: 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_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 {
|
||||
@ -251,6 +279,11 @@ impl BlockEpollHandler {
|
||||
|
||||
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 {
|
||||
match request.request_type {
|
||||
RequestType::In => {
|
||||
@ -258,6 +291,19 @@ impl BlockEpollHandler {
|
||||
read_bytes += Wrapping(*data_len as u64);
|
||||
}
|
||||
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 => {
|
||||
if !request.writeback {
|
||||
@ -267,10 +313,31 @@ impl BlockEpollHandler {
|
||||
write_bytes += Wrapping(*data_len as u64);
|
||||
}
|
||||
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)
|
||||
} else {
|
||||
error!(
|
||||
@ -728,6 +795,30 @@ impl VirtioDevice for Block {
|
||||
"write_ops",
|
||||
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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user