diff --git a/performance-metrics/src/performance_tests.rs b/performance-metrics/src/performance_tests.rs index c8fc5e245..c286bc03f 100644 --- a/performance-metrics/src/performance_tests.rs +++ b/performance-metrics/src/performance_tests.rs @@ -105,7 +105,7 @@ pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 { let r = std::panic::catch_unwind(|| { guest.wait_vm_boot(None).unwrap(); - measure_virtio_net_throughput(test_timeout, num_queues / 2, &guest, rx).unwrap() + measure_virtio_net_throughput(test_timeout, num_queues / 2, &guest, rx, true).unwrap() }); let _ = child.kill(); @@ -429,7 +429,7 @@ mod tests { } "#; assert_eq!( - parse_iperf3_output(output.as_bytes(), true).unwrap(), + parse_iperf3_output(output.as_bytes(), true, true).unwrap(), 23957198874.604115 ); @@ -448,9 +448,31 @@ mod tests { } "#; assert_eq!( - parse_iperf3_output(output.as_bytes(), false).unwrap(), + parse_iperf3_output(output.as_bytes(), false, true).unwrap(), 39520744482.79 ); + let output = r#" +{ + "end": { + "sum": { + "start": 0, + "end": 5.000036, + "seconds": 5.000036, + "bytes": 29944971264, + "bits_per_second": 47911877363.396217, + "jitter_ms": 0.0038609822983198556, + "lost_packets": 16, + "packets": 913848, + "lost_percent": 0.0017508382137948542, + "sender": true + } + } +} + "#; + assert_eq!( + parse_iperf3_output(output.as_bytes(), true, false).unwrap(), + 182765.08409139456 + ); } #[test] diff --git a/test_infra/src/lib.rs b/test_infra/src/lib.rs index 44235d9b9..fa7137c16 100644 --- a/test_infra/src/lib.rs +++ b/test_infra/src/lib.rs @@ -1311,22 +1311,36 @@ pub fn clh_command(cmd: &str) -> String { ) } -pub fn parse_iperf3_output(output: &[u8], sender: bool) -> Result { +pub fn parse_iperf3_output(output: &[u8], sender: bool, bandwidth: bool) -> Result { std::panic::catch_unwind(|| { let s = String::from_utf8_lossy(output); let v: Value = serde_json::from_str(&s).expect("'iperf3' parse error: invalid json output"); - let bps: f64 = if sender { - v["end"]["sum_sent"]["bits_per_second"] - .as_f64() - .expect("'iperf3' parse error: missing entry 'end.sum_sent.bits_per_second'") + if bandwidth { + if sender { + v["end"]["sum_sent"]["bits_per_second"] + .as_f64() + .expect("'iperf3' parse error: missing entry 'end.sum_sent.bits_per_second'") + } else { + v["end"]["sum_received"]["bits_per_second"].as_f64().expect( + "'iperf3' parse error: missing entry 'end.sum_received.bits_per_second'", + ) + } } else { - v["end"]["sum_received"]["bits_per_second"] - .as_f64() - .expect("'iperf3' parse error: missing entry 'end.sum_received.bits_per_second'") - }; + // iperf does not distinguish sent vs received in this case. - bps + let lost_packets = v["end"]["sum"]["lost_packets"] + .as_f64() + .expect("'iperf3' parse error: missing entry 'end.sum.lost_packets'"); + let packets = v["end"]["sum"]["packets"] + .as_f64() + .expect("'iperf3' parse error: missing entry 'end.sum.packets'"); + let seconds = v["end"]["sum"]["seconds"] + .as_f64() + .expect("'iperf3' parse error: missing entry 'end.sum.seconds'"); + + (packets - lost_packets) / seconds + } }) .map_err(|_| { eprintln!( @@ -1495,6 +1509,7 @@ pub fn measure_virtio_net_throughput( queue_pairs: u32, guest: &Guest, receive: bool, + bandwidth: bool, ) -> Result { let default_port = 5201; @@ -1525,6 +1540,11 @@ pub fn measure_virtio_net_throughput( if !receive { cmd.args(["-R"]); } + // Use UDP stream to measure packets per second. The bitrate is set to + // 1T to make sure it saturates the link. + if !bandwidth { + cmd.args(["-u", "-b", "1T"]); + } let client = cmd .stderr(Stdio::piped()) .stdout(Stdio::piped()) @@ -1535,7 +1555,7 @@ pub fn measure_virtio_net_throughput( } let mut err: Option = None; - let mut bps = Vec::new(); + let mut results = Vec::new(); let mut failed = false; for c in clients { let mut c = c; @@ -1547,7 +1567,7 @@ pub fn measure_virtio_net_throughput( if !failed { // Safe to unwrap as we know the child has terminated succesffully let output = c.wait_with_output().unwrap(); - bps.push(parse_iperf3_output(&output.stdout, receive)?); + results.push(parse_iperf3_output(&output.stdout, receive, bandwidth)?); } else { let _ = c.kill(); let output = c.wait_with_output().unwrap(); @@ -1561,7 +1581,7 @@ pub fn measure_virtio_net_throughput( if let Some(e) = err { Err(e) } else { - Ok(bps.iter().sum()) + Ok(results.iter().sum()) } } diff --git a/tests/integration.rs b/tests/integration.rs index 22ebcfc2e..376a66bf4 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -9423,7 +9423,8 @@ mod rate_limiter { let r = std::panic::catch_unwind(|| { guest.wait_vm_boot(None).unwrap(); let measured_bps = - measure_virtio_net_throughput(test_timeout, num_queues / 2, &guest, rx).unwrap(); + measure_virtio_net_throughput(test_timeout, num_queues / 2, &guest, rx, true) + .unwrap(); assert!(check_rate_limit(measured_bps, limit_bps, 0.1)); });