virtio-devices: block: Make latency infinite before first op

Logically until we have handled the first operation the latency is
infinite; this logic was applied to the minimum latency originally but
this patch extends that logic to the maximum and average latency.

To prevent the initial average latency being skewed by the inclusion of
infinity the average value is initally seeded with the first measured
latency.

Fixes: #5704

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
This commit is contained in:
Rob Bradford 2023-08-29 08:33:19 +01:00 committed by Bo Chen
parent 35757ec45a
commit b5766028a8

View File

@ -106,13 +106,13 @@ impl Default for BlockCounters {
read_bytes: Arc::new(AtomicU64::new(0)), read_bytes: Arc::new(AtomicU64::new(0)),
read_ops: Arc::new(AtomicU64::new(0)), read_ops: Arc::new(AtomicU64::new(0)),
read_latency_min: Arc::new(AtomicU64::new(u64::MAX)), read_latency_min: Arc::new(AtomicU64::new(u64::MAX)),
read_latency_max: Arc::new(AtomicU64::new(0)), read_latency_max: Arc::new(AtomicU64::new(u64::MAX)),
read_latency_avg: Arc::new(AtomicU64::new(0)), read_latency_avg: Arc::new(AtomicU64::new(u64::MAX)),
write_bytes: Arc::new(AtomicU64::new(0)), write_bytes: Arc::new(AtomicU64::new(0)),
write_ops: Arc::new(AtomicU64::new(0)), write_ops: Arc::new(AtomicU64::new(0)),
write_latency_min: Arc::new(AtomicU64::new(u64::MAX)), write_latency_min: Arc::new(AtomicU64::new(u64::MAX)),
write_latency_max: Arc::new(AtomicU64::new(0)), write_latency_max: Arc::new(AtomicU64::new(u64::MAX)),
write_latency_avg: Arc::new(AtomicU64::new(0)), write_latency_avg: Arc::new(AtomicU64::new(u64::MAX)),
} }
} }
} }
@ -281,10 +281,10 @@ 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 latency = request.start.elapsed().as_micros() as u64;
let read_ops_last = self.counters.read_ops.load(Ordering::Relaxed) as i64; let read_ops_last = self.counters.read_ops.load(Ordering::Relaxed);
let write_ops_last = self.counters.write_ops.load(Ordering::Relaxed) as i64; let write_ops_last = self.counters.write_ops.load(Ordering::Relaxed);
let mut read_avg = self.counters.read_latency_avg.load(Ordering::Relaxed) as i64; let mut read_avg = self.counters.read_latency_avg.load(Ordering::Relaxed);
let mut write_avg = self.counters.write_latency_avg.load(Ordering::Relaxed) as i64; let mut write_avg = self.counters.write_latency_avg.load(Ordering::Relaxed);
let (status, len) = if result >= 0 { let (status, len) = if result >= 0 {
match request.request_type { match request.request_type {
RequestType::In => { RequestType::In => {
@ -297,14 +297,22 @@ impl BlockEpollHandler {
.read_latency_min .read_latency_min
.store(latency, Ordering::Relaxed); .store(latency, Ordering::Relaxed);
} }
if latency > self.counters.read_latency_max.load(Ordering::Relaxed) { if latency > self.counters.read_latency_max.load(Ordering::Relaxed)
|| latency == u64::MAX
{
self.counters self.counters
.read_latency_max .read_latency_max
.store(latency, Ordering::Relaxed); .store(latency, Ordering::Relaxed);
} }
read_avg = read_avg
+ ((latency * LATENCY_SCALE) as i64 - read_avg) // Special case the first real latency report
/ (read_ops_last + read_ops.0 as i64); read_avg = if read_avg == u64::MAX {
latency
} else {
read_avg
+ ((latency * LATENCY_SCALE) - read_avg)
/ (read_ops_last + read_ops.0)
};
} }
RequestType::Out => { RequestType::Out => {
if !request.writeback { if !request.writeback {
@ -319,25 +327,33 @@ impl BlockEpollHandler {
.write_latency_min .write_latency_min
.store(latency, Ordering::Relaxed); .store(latency, Ordering::Relaxed);
} }
if latency > self.counters.write_latency_max.load(Ordering::Relaxed) { if latency > self.counters.write_latency_max.load(Ordering::Relaxed)
|| latency == u64::MAX
{
self.counters self.counters
.write_latency_max .write_latency_max
.store(latency, Ordering::Relaxed); .store(latency, Ordering::Relaxed);
} }
write_avg = write_avg
+ ((latency * LATENCY_SCALE) as i64 - write_avg) // Special case the first real latency report
/ (write_ops_last + write_ops.0 as i64); write_avg = if write_avg == u64::MAX {
latency
} else {
write_avg
+ ((latency * LATENCY_SCALE) - write_avg)
/ (write_ops_last + write_ops.0)
};
} }
_ => {} _ => {}
} }
self.counters self.counters
.read_latency_avg .read_latency_avg
.store(read_avg as u64, Ordering::Relaxed); .store(read_avg, Ordering::Relaxed);
self.counters self.counters
.write_latency_avg .write_latency_avg
.store(write_avg as u64, Ordering::Relaxed); .store(write_avg, Ordering::Relaxed);
(VIRTIO_BLK_S_OK, result as u32) (VIRTIO_BLK_S_OK, result as u32)
} else { } else {