test_infra: make measure_virtio_net_throughput & co measure PPS too

While measuring UDP PPS, we saturate the link, so there are packets
lost. We only account for the packets that are not lost.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu 2023-01-05 20:52:41 +00:00 committed by Rob Bradford
parent d50a4cbb6b
commit 08e4d1f481
3 changed files with 60 additions and 17 deletions

View File

@ -105,7 +105,7 @@ pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 {
let r = std::panic::catch_unwind(|| { let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap(); 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(); let _ = child.kill();
@ -429,7 +429,7 @@ mod tests {
} }
"#; "#;
assert_eq!( assert_eq!(
parse_iperf3_output(output.as_bytes(), true).unwrap(), parse_iperf3_output(output.as_bytes(), true, true).unwrap(),
23957198874.604115 23957198874.604115
); );
@ -448,9 +448,31 @@ mod tests {
} }
"#; "#;
assert_eq!( assert_eq!(
parse_iperf3_output(output.as_bytes(), false).unwrap(), parse_iperf3_output(output.as_bytes(), false, true).unwrap(),
39520744482.79 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] #[test]

View File

@ -1311,22 +1311,36 @@ pub fn clh_command(cmd: &str) -> String {
) )
} }
pub fn parse_iperf3_output(output: &[u8], sender: bool) -> Result<f64, Error> { pub fn parse_iperf3_output(output: &[u8], sender: bool, bandwidth: bool) -> Result<f64, Error> {
std::panic::catch_unwind(|| { std::panic::catch_unwind(|| {
let s = String::from_utf8_lossy(output); let s = String::from_utf8_lossy(output);
let v: Value = serde_json::from_str(&s).expect("'iperf3' parse error: invalid json output"); let v: Value = serde_json::from_str(&s).expect("'iperf3' parse error: invalid json output");
let bps: f64 = if sender { if bandwidth {
v["end"]["sum_sent"]["bits_per_second"] if sender {
.as_f64() v["end"]["sum_sent"]["bits_per_second"]
.expect("'iperf3' parse error: missing entry '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 { } else {
v["end"]["sum_received"]["bits_per_second"] // iperf does not distinguish sent vs received in this case.
.as_f64()
.expect("'iperf3' parse error: missing entry 'end.sum_received.bits_per_second'")
};
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(|_| { .map_err(|_| {
eprintln!( eprintln!(
@ -1495,6 +1509,7 @@ pub fn measure_virtio_net_throughput(
queue_pairs: u32, queue_pairs: u32,
guest: &Guest, guest: &Guest,
receive: bool, receive: bool,
bandwidth: bool,
) -> Result<f64, Error> { ) -> Result<f64, Error> {
let default_port = 5201; let default_port = 5201;
@ -1525,6 +1540,11 @@ pub fn measure_virtio_net_throughput(
if !receive { if !receive {
cmd.args(["-R"]); 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 let client = cmd
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
@ -1535,7 +1555,7 @@ pub fn measure_virtio_net_throughput(
} }
let mut err: Option<Error> = None; let mut err: Option<Error> = None;
let mut bps = Vec::new(); let mut results = Vec::new();
let mut failed = false; let mut failed = false;
for c in clients { for c in clients {
let mut c = c; let mut c = c;
@ -1547,7 +1567,7 @@ pub fn measure_virtio_net_throughput(
if !failed { if !failed {
// Safe to unwrap as we know the child has terminated succesffully // Safe to unwrap as we know the child has terminated succesffully
let output = c.wait_with_output().unwrap(); 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 { } else {
let _ = c.kill(); let _ = c.kill();
let output = c.wait_with_output().unwrap(); let output = c.wait_with_output().unwrap();
@ -1561,7 +1581,7 @@ pub fn measure_virtio_net_throughput(
if let Some(e) = err { if let Some(e) = err {
Err(e) Err(e)
} else { } else {
Ok(bps.iter().sum()) Ok(results.iter().sum())
} }
} }

View File

@ -9423,7 +9423,8 @@ mod rate_limiter {
let r = std::panic::catch_unwind(|| { let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap(); guest.wait_vm_boot(None).unwrap();
let measured_bps = 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)); assert!(check_rate_limit(measured_bps, limit_bps, 0.1));
}); });