TCP small packets throughput and multiqueue virtio-net
Subsystems (4)
Hello all:
I meet an issue when testing multiqueue virtio-net. When I testing guest small packets stream sending performance with netperf. I find an regression of multiqueue. When I run 2 sessions of TCP_STREAM test with 1024 byte from guest to local host, I get following result:
1q result: 3457.64
2q result: 7781.45
Statistics shows that: compared with one queue, multiqueue tends to send much more but smaller packets. Tcpdump shows single queue has a much higher possibility to produce a 64K gso packet compared to multiqueue. More but smaller packets will cause more vmexits and interrupts which lead a degradation on throughput.
Then problem only exist for small packets sending. When I test with larger size, multiqueue will gradually outperfrom single queue. And multiqueue also outperfrom in both TCP_RR and pktgen test (even with small packets). The problem disappear when I turn off both gso and tso.
I'm not sure whether it's a bug or expected since anyway we get improvement on latency. And if it's a bug, I suspect it was related to TCP GSO batching algorithm who tends to batch less in this situation. ( Jiri Pirko suspect it was the defect of virtio-net driver, but I didn't find any obvious clue on this). After some experiments, I find the it maybe related to tcp_tso_should_defer(), after
1) change the tcp_tso_win_divisor to 1
2) the following changes
the throughput were almost the same (but still a little worse) as single queue:
net/ipv4/tcp_output.c +0 -0
@@ -1777,10 +1777,12 @@ static bool tcp_tso_should_defer(struct sock
*sk, struct sk_buff *skb)
limit = min(send_win, cong_win);
+#if 0
/* If a full-sized TSO skb can be sent, do it. */
if (limit >= min_t(unsigned int, sk->sk_gso_max_size,
sk->sk_gso_max_segs * tp->mss_cache))
goto send_now;+#endif
/* Middle in queue won't get any more data, full sendable
already? */
if ((skb != tcp_write_queue_tail(sk)) && (limit >= skb->len))Git history shows this check were added for both westwood and fasttcp, I'm not familiar with tcp but looks like we can easily hit this check under when multiqueue is enabled for virtio-net. Maybe I was wrong but I wonder whether we can still do some batching here.
Any comments, thoughts are welcomed.
Thanks
Quoted 16 lines · Jason Wang
Hello all:
I meet an issue when testing multiqueue virtio-net. When I testing guest small packets stream sending performance with netperf. I find an regression of multiqueue. When I run 2 sessions of
TCP_STREAMtest with 1024 byte from guest to local host, I get following result:1q result: 3457.64
2q result: 7781.45Statistics shows that: compared with one queue, multiqueue tends to send much more but smaller packets. Tcpdump shows single queue has a much higher possibility to produce a 64K gso packet compared to multiqueue. More but smaller packets will cause more vmexits and interrupts which lead a degradation on throughput.
Quoted 5 lines
Then problem only exist for small packets sending. When I test with larger size, multiqueue will gradually outperfrom single queue. And multiqueue also outperfrom in both
TCP_RRand pktgen test (even with small packets). The problem disappear when I turn off both gso and tso.
This makes little sense to me : TCP_RR workload (assuming one byte payload) cannot use GSO or TSO anyway. Same for pktgen as it uses UDP.
Quoted 29 lines
I'm not sure whether it's a bug or expected since anyway we get improvement on latency. And if it's a bug, I suspect it was related to TCP GSO batching algorithm who tends to batch less in this situation. ( Jiri Pirko suspect it was the defect of virtio-net driver, but I didn't find any obvious clue on this). After some experiments, I find the it maybe related to
tcp_tso_should_defer(), after
1) change thetcp_tso_win_divisorto 1
2) the following changes
the throughput were almost the same (but still a little worse) as single queue:net/ipv4/tcp_output.c +2
-0@@ -1777,10 +1777,12 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) limit =min (send_win, cong_win); +#if 0 /* If a full-sized TSO skb can be sent, do it. */ if (limit >= min_t(unsigned int, sk->sk_gso_max_size, sk->sk_gso_max_segs * tp->mss_cache)) goto send_now; +#endif /* Middle in queue won't get any more data, full sendable already? */
Quoted 9 lines
if ((skb != tcp_write_queue_tail(sk)) && (limit >= skb->len))Git history shows this check were added for both westwood and fasttcp, I'm not familiar with tcp but looks like we can easily hit this check under when multiqueue is enabled for virtio-net. Maybe I was wrong but I wonder whether we can still do some batching here.
Any comments, thoughts are welcomed.
Well, the point is : if your app does write(1024) bytes, thats probably because it wants small packets from the very beginning. (See the TCP PUSH flag ?)
If the transport is slow, TCP stack will automatically collapse several write into single skbs (assuming TSO or GSO is on), and you'll see big GSO packets with tcpdump [1]. So TCP will help you to get less overhead in this case.
But if transport is fast, you'll see small packets, and thats good for latency.
So my opinion is : its exactly behaving as expected.
If you want bigger packets either :
- Make the application doing big write()
- Slow the vmexit ;)
[1] GSO fools tcpdump : Actual packets sent to the wire are not 'big packets', but they hit dev_hard_start_xmit() as GSO packets.
Quoted 5 lines
Well, the point is : if your app does write(1024) bytes, thats probably because it wants small packets from the very beginning. (See the TCP PUSH flag ?)
I think that raises the question of whether or not Jason was setting the test-specific -D option on his TCP_STREAM tests, to have netperf make a setsockopt(TCP_NODELAY) call.
happy benchmarking,
rick jones
Quoted 24 lines
If the transport is slow, TCP stack will automatically collapse several write into single skbs (assuming TSO or GSO is on), and you'll see big GSO packets with tcpdump [1]. So TCP will help you to get less overhead in this case.
But if transport is fast, you'll see small packets, and thats good for latency.
So my opinion is : its exactly behaving as expected.
If you want bigger packets either :
- Make the application doing bigwrite()
- Slow the vmexit ;)[1] GSO fools tcpdump : Actual packets sent to the wire are not 'big packets', but they hit
dev_hard_start_xmit()as GSO packets.--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 9 lines · Rick Jones
Quoted 5 lines
Well, the point is : if your app does write(1024) bytes, thats probably because it wants small packets from the very beginning. (See the TCP PUSH flag ?)
I think that raises the question of whether or not Jason was setting the test-specific -D option on his
TCP_STREAMtests, to have netperf make asetsockopt(TCP_NODELAY)call.
I didn't set the -D option to disable nagle. But I get almost the almost same result with -D (1024 byte TCP_STREAM from guest to local host).
Quoted 30 lines
happy benchmarking,
rick jones
Quoted 24 lines
If the transport is slow, TCP stack will automatically collapse several write into single skbs (assuming TSO or GSO is on), and you'll see big GSO packets with tcpdump [1]. So TCP will help you to get less overhead in this case.
But if transport is fast, you'll see small packets, and thats good for latency.
So my opinion is : its exactly behaving as expected.
If you want bigger packets either :
- Make the application doing bigwrite()
- Slow the vmexit ;)[1] GSO fools tcpdump : Actual packets sent to the wire are not 'big packets', but they hit
dev_hard_start_xmit()as GSO packets.Signature · 3 lines
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 61 lines · Eric Dumazet
Quoted 16 lines · Jason Wang
Hello all:
I meet an issue when testing multiqueue virtio-net. When I testing guest small packets stream sending performance with netperf. I find an regression of multiqueue. When I run 2 sessions of
TCP_STREAMtest with 1024 byte from guest to local host, I get following result:1q result: 3457.64
2q result: 7781.45Statistics shows that: compared with one queue, multiqueue tends to send much more but smaller packets. Tcpdump shows single queue has a much higher possibility to produce a 64K gso packet compared to multiqueue. More but smaller packets will cause more vmexits and interrupts which lead a degradation on throughput.
Quoted 5 lines
Then problem only exist for small packets sending. When I test with larger size, multiqueue will gradually outperfrom single queue. And multiqueue also outperfrom in both
TCP_RRand pktgen test (even with small packets). The problem disappear when I turn off both gso and tso.This makes little sense to me :
TCP_RRworkload (assuming one byte payload) cannot use GSO or TSO anyway. Same for pktgen as it uses UDP.Quoted 36 lines
I'm not sure whether it's a bug or expected since anyway we get improvement on latency. And if it's a bug, I suspect it was related to TCP GSO batching algorithm who tends to batch less in this situation. ( Jiri Pirko suspect it was the defect of virtio-net driver, but I didn't find any obvious clue on this). After some experiments, I find the it maybe related to
tcp_tso_should_defer(), after
1) change thetcp_tso_win_divisorto 1
2) the following changes
the throughput were almost the same (but still a little worse) as single queue:net/ipv4/tcp_output.c +2
-0@@ -1777,10 +1777,12 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) limit =min (send_win, cong_win); +#if 0 /* If a full-sized TSO skb can be sent, do it. */ if (limit >= min_t(unsigned int, sk->sk_gso_max_size, sk->sk_gso_max_segs * tp->mss_cache)) goto send_now; +#endif /* Middle in queue won't get any more data, full sendable already? */
if ((skb != tcp_write_queue_tail(sk)) && (limit >= skb->len))Git history shows this check were added for both westwood and fasttcp, I'm not familiar with tcp but looks like we can easily hit this check under when multiqueue is enabled for virtio-net. Maybe I was wrong but I wonder whether we can still do some batching here.
Quoted 5 lines
Quoted 2 lines
Any comments, thoughts are welcomed.
Well, the point is : if your app does write(1024) bytes, thats probably because it wants small packets from the very beginning. (See the TCP PUSH flag ?)
Didn't fully understand the question, but according to the tcpdump, TCP PUSH flag were seen in very few packets.
Quoted 5 lines
If the transport is slow, TCP stack will automatically collapse several write into single skbs (assuming TSO or GSO is on), and you'll see big GSO packets with tcpdump [1]. So TCP will help you to get less overhead in this case.
Quoted 8 lines
But if transport is fast, you'll see small packets, and thats good for latency.
So my opinion is : its exactly behaving as expected.
If you want bigger packets either :
- Make the application doing bigwrite()
- Slow the vmexit ;)
Good to know this, thanks for the explanation.
Quoted 5 lines
[1] GSO fools tcpdump : Actual packets sent to the wire are not 'big packets', but they hit
dev_hard_start_xmit()as GSO packets.
Quoted 53 lines · Eric Dumazet
Quoted 16 lines · Jason Wang
Hello all:
I meet an issue when testing multiqueue virtio-net. When I testing guest small packets stream sending performance with netperf. I find an regression of multiqueue. When I run 2 sessions of
TCP_STREAMtest with 1024 byte from guest to local host, I get following result:1q result: 3457.64
2q result: 7781.45Statistics shows that: compared with one queue, multiqueue tends to send much more but smaller packets. Tcpdump shows single queue has a much higher possibility to produce a 64K gso packet compared to multiqueue. More but smaller packets will cause more vmexits and interrupts which lead a degradation on throughput.
Quoted 5 lines
Then problem only exist for small packets sending. When I test with larger size, multiqueue will gradually outperfrom single queue. And multiqueue also outperfrom in both
TCP_RRand pktgen test (even with small packets). The problem disappear when I turn off both gso and tso.This makes little sense to me :
TCP_RRworkload (assuming one byte payload) cannot use GSO or TSO anyway. Same for pktgen as it uses UDP.Quoted 27 lines
I'm not sure whether it's a bug or expected since anyway we get improvement on latency. And if it's a bug, I suspect it was related to TCP GSO batching algorithm who tends to batch less in this situation. ( Jiri Pirko suspect it was the defect of virtio-net driver, but I didn't find any obvious clue on this). After some experiments, I find the it maybe related to
tcp_tso_should_defer(), after
1) change thetcp_tso_win_divisorto 1
2) the following changes
the throughput were almost the same (but still a little worse) as single queue:net/ipv4/tcp_output.c +2
-0@@ -1777,10 +1777,12 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) limit =min (send_win, cong_win); +#if 0 /* If a full-sized TSO skb can be sent, do it. */ if (limit >= min_t(unsigned int, sk->sk_gso_max_size, sk->sk_gso_max_segs * tp->mss_cache)) goto send_now; +#endif
Quoted 5 lines
Quoted 5 lines
net/ipv4/tcp_output.c +0
-0/* Middle in queue won't get any more data, full sendable already? */
if ((skb != tcp_write_queue_tail(sk)) && (limit >= skb->len))Git history shows this check were added for both westwood and fasttcp,
Hmm yes,
http://www.mail-archive.com/[email protected]/msg08738.html
How about we disable it for cubic,reno then?
Quoted 10 lines
Quoted 6 lines
I'm not familiar with tcp but looks like we can easily hit this check under when multiqueue is enabled for virtio-net. Maybe I was wrong but I wonder whether we can still do some batching here.
Any comments, thoughts are welcomed.
Well, the point is : if your app does write(1024) bytes, thats probably because it wants small packets from the very beginning. (See the TCP PUSH flag ?)
In that case the application typically won't have packets in flight (e.g. like TCP_RR) so TSO won't trigger at all, no?
It would seem that packets in flight might rather indicate that the application is trying to keep the socket buffer full by giving the kernel data as fast as it becomes available. At least, this is exactly what benchmark tools seem to be doing, right?
Quoted 7 lines
If the transport is slow, TCP stack will automatically collapse several write into single skbs (assuming TSO or GSO is on), and you'll see big GSO packets with tcpdump [1]. So TCP will help you to get less overhead in this case.
But if transport is fast, you'll see small packets, and thats good for latency.
But is a large CWND really a good indicator of a low latency link? Can't CWND grow (depending on the protocol) as long as there's no packet loss even if the latency is high?
So if a VM is using a 10G backend link in the host, it seems that (due to vmexit overhead) the latency is high so we are not gaining much from sending the packet a bit earlier, OTOH, the bandwidth is high so the per packet overhead becomes measureable. Virt workloads are probably not the only ones that are like that, it's just that it's easier for people to observe the overhead.
Quoted 9 lines
So my opinion is : its exactly behaving as expected.
If you want bigger packets either :
- Make the application doing bigwrite()
- Slow the vmexit ;)[1] GSO fools tcpdump : Actual packets sent to the wire are not 'big packets', but they hit
dev_hard_start_xmit()as GSO packets.
Signature · 1 line
MST