From b5766028a8747e19241cc9ae4e711df3f0de29d3 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 29 Aug 2023 08:33:19 +0100 Subject: [PATCH] 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 --- virtio-devices/src/block.rs | 52 ++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/virtio-devices/src/block.rs b/virtio-devices/src/block.rs index 91b404237..9cc7d4bd3 100644 --- a/virtio-devices/src/block.rs +++ b/virtio-devices/src/block.rs @@ -106,13 +106,13 @@ impl Default for 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)), + read_latency_max: Arc::new(AtomicU64::new(u64::MAX)), + read_latency_avg: Arc::new(AtomicU64::new(u64::MAX)), 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)), + write_latency_max: Arc::new(AtomicU64::new(u64::MAX)), + write_latency_avg: Arc::new(AtomicU64::new(u64::MAX)), } } } @@ -281,10 +281,10 @@ 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 read_ops_last = self.counters.read_ops.load(Ordering::Relaxed); + let write_ops_last = self.counters.write_ops.load(Ordering::Relaxed); + let mut read_avg = self.counters.read_latency_avg.load(Ordering::Relaxed); + let mut write_avg = self.counters.write_latency_avg.load(Ordering::Relaxed); let (status, len) = if result >= 0 { match request.request_type { RequestType::In => { @@ -297,14 +297,22 @@ impl BlockEpollHandler { .read_latency_min .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 .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); + + // Special case the first real latency report + read_avg = if read_avg == u64::MAX { + latency + } else { + read_avg + + ((latency * LATENCY_SCALE) - read_avg) + / (read_ops_last + read_ops.0) + }; } RequestType::Out => { if !request.writeback { @@ -319,25 +327,33 @@ impl BlockEpollHandler { .write_latency_min .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 .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); + + // Special case the first real latency report + write_avg = if write_avg == u64::MAX { + latency + } else { + write_avg + + ((latency * LATENCY_SCALE) - write_avg) + / (write_ops_last + write_ops.0) + }; } _ => {} } self.counters .read_latency_avg - .store(read_avg as u64, Ordering::Relaxed); + .store(read_avg, Ordering::Relaxed); self.counters .write_latency_avg - .store(write_avg as u64, Ordering::Relaxed); + .store(write_avg, Ordering::Relaxed); (VIRTIO_BLK_S_OK, result as u32) } else {