From patchwork Sun Jan 31 18:13:29 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Xu X-Patchwork-Id: 576238 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 03261140271 for ; Mon, 1 Feb 2016 05:18:59 +1100 (AEDT) Received: from localhost ([::1]:42760 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPwaP-0002yD-3R for incoming@patchwork.ozlabs.org; Sun, 31 Jan 2016 13:18:57 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36840) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPwW0-00038N-Rn for qemu-devel@nongnu.org; Sun, 31 Jan 2016 13:14:26 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aPwVz-0006EG-1M for qemu-devel@nongnu.org; Sun, 31 Jan 2016 13:14:24 -0500 Received: from mx1.redhat.com ([209.132.183.28]:53497) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPwVy-0006E4-N5 for qemu-devel@nongnu.org; Sun, 31 Jan 2016 13:14:22 -0500 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id 6FAE9461C8 for ; Sun, 31 Jan 2016 18:14:22 +0000 (UTC) Received: from wei-thinkpad.nay.redhat.com (vpn1-6-127.pek2.redhat.com [10.72.6.127]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0VIDVgW014091; Sun, 31 Jan 2016 13:14:19 -0500 From: wexu@redhat.com To: qemu-devel@nongnu.org Date: Mon, 1 Feb 2016 02:13:29 +0800 Message-Id: <1454264009-24094-11-git-send-email-wexu@redhat.com> In-Reply-To: <1454264009-24094-1-git-send-email-wexu@redhat.com> References: <1454264009-24094-1-git-send-email-wexu@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: victork@redhat.com, mst@redhat.com, jasowang@redhat.com, yvugenfi@redhat.com, Wei Xu , marcel@redhat.com, dfleytma@redhat.com Subject: [Qemu-devel] [RFC Patch v2 10/10] virtio-net rsc: Add Receive Segment Coalesce statistics X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Wei Xu Add statistics to log what happened during the process. Signed-off-by: Wei Xu --- hw/net/virtio-net.c | 49 +++++++++++++++++++++++++++++++++++++++++++--- include/hw/virtio/virtio.h | 33 +++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index c9f6bfc..ab08b96 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -66,6 +66,7 @@ /* Global statistics */ static uint32_t rsc_chain_no_mem; +static uint64_t virtio_net_received; /* Switcher to enable/disable rsc */ static bool virtio_net_rsc_bypass; @@ -1679,10 +1680,12 @@ static void virtio_net_rsc_purge(void *opq) if (ret == 0) { /* Try next queue */ + chain->stat.purge_failed++; continue; } } + chain->stat.timer++; if (!QTAILQ_EMPTY(&chain->buffers)) { timer_mod(chain->drain_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + rsc_timeout); @@ -1715,6 +1718,7 @@ static int virtio_net_rsc_cache_buf(NetRscChain *chain, NetClientState *nc, seg = g_malloc(sizeof(NetRscSeg)); if (!seg) { + chain->stat.no_buf++; return 0; } @@ -1730,9 +1734,11 @@ static int virtio_net_rsc_cache_buf(NetRscChain *chain, NetClientState *nc, seg->nc = nc; QTAILQ_INSERT_TAIL(&chain->buffers, seg, next); + chain->stat.cache++; return size; out: + chain->stat.no_buf++; g_free(seg); return 0; } @@ -1750,27 +1756,33 @@ static int32_t virtio_net_rsc_handle_ack(NetRscChain *chain, NetRscSeg *seg, owin = htons(o_tcp->th_win); if ((nack - oack) >= TCP_WINDOW) { + chain->stat.ack_out_of_win++; return RSC_FINAL; } else if (nack == oack) { /* duplicated ack or window probe */ if (nwin == owin) { /* duplicated ack, add dup ack count due to whql test up to 1 */ + chain->stat.dup_ack++; if (seg->dup_ack_count == 0) { seg->dup_ack_count++; + chain->stat.dup_ack1++; return RSC_COALESCE; } else { /* Spec says should send it directly */ + chain->stat.dup_ack2++; return RSC_FINAL; } } else { /* Coalesce window update */ o_tcp->th_win = n_tcp->th_win; + chain->stat.win_update++; return RSC_COALESCE; } } else { /* pure ack, update ack */ o_tcp->th_ack = n_tcp->th_ack; + chain->stat.pure_ack++; return RSC_COALESCE; } } @@ -1788,13 +1800,20 @@ static int32_t virtio_net_rsc_coalesce_tcp(NetRscChain *chain, NetRscSeg *seg, nseq = htonl(n_tcp->th_seq); oseq = htonl(o_tcp->th_seq); + if (n_tcp_len > sizeof(struct tcp_header)) { + /* Log this only for debugging observation */ + chain->stat.tcp_option++; + } + /* Ignore packet with more/larger tcp options */ if (n_tcp_len > o_tcp_len) { + chain->stat.tcp_larger_option++; return RSC_FINAL; } /* out of order or retransmitted. */ if ((nseq - oseq) > TCP_WINDOW) { + chain->stat.data_out_of_win++; return RSC_FINAL; } @@ -1802,16 +1821,19 @@ static int32_t virtio_net_rsc_coalesce_tcp(NetRscChain *chain, NetRscSeg *seg, if (nseq == oseq) { if ((0 == o_data) && n_data) { /* From no payload to payload, normal case, not a dup ack or etc */ + chain->stat.data_after_pure_ack++; goto coalesce; } else { return virtio_net_rsc_handle_ack(chain, seg, buf, n_tcp, o_tcp); } } else if ((nseq - oseq) != o_data) { /* Not a consistent packet, out of order */ + chain->stat.data_out_of_order++; return RSC_FINAL; } else { coalesce: if ((o_ip_len + n_data) > max_data) { + chain->stat.over_size++; return RSC_FINAL; } @@ -1824,6 +1846,7 @@ coalesce: memmove(seg->buf + seg->size, data, n_data); seg->size += n_data; + chain->stat.coalesced++; return RSC_COALESCE; } } @@ -1855,6 +1878,7 @@ static int32_t virtio_net_rsc_try_coalesce4(NetRscChain *chain, if ((n_ip->ip_src ^ o_ip->ip_src) || (n_ip->ip_dst ^ o_ip->ip_dst) || (n_tcp->th_sport ^ o_tcp->th_sport) || (n_tcp->th_dport ^ o_tcp->th_dport)) { + chain->stat.no_match++; return RSC_NO_MATCH; } @@ -1890,6 +1914,7 @@ static int32_t virtio_net_rsc_try_coalesce6(NetRscChain *chain, || memcmp(&n_ip->ip6_dst, &o_ip->ip6_dst, sizeof(struct in6_address)) || (n_tcp->th_sport ^ o_tcp->th_sport) || (n_tcp->th_dport ^ o_tcp->th_dport)) { + chain->stat.no_match++; return RSC_NO_MATCH; } @@ -1927,6 +1952,7 @@ static size_t virtio_net_rsc_callback(NetRscChain *chain, NetClientState *nc, NetRscSeg *seg, *nseg; if (QTAILQ_EMPTY(&chain->buffers)) { + chain->stat.empty_cache++; if (!virtio_net_rsc_cache_buf(chain, nc, buf, size)) { return 0; } else { @@ -1948,6 +1974,7 @@ static size_t virtio_net_rsc_callback(NetRscChain *chain, NetClientState *nc, g_free(seg); if (ret == 0) { /* Send failed */ + chain->stat.final_failed++; return 0; } @@ -1962,6 +1989,7 @@ static size_t virtio_net_rsc_callback(NetRscChain *chain, NetClientState *nc, } } + chain->stat.no_match_cache++; return virtio_net_rsc_cache_buf(chain, nc, buf, size); } @@ -1980,8 +2008,9 @@ static size_t virtio_net_rsc_drain_one(NetRscChain *chain, NetClientState *nc, if ((chain->proto == ETH_P_IP) && seg->is_coalesced) { virtio_net_rsc_ipv4_checksum(seg); } - - virtio_net_do_receive(seg->nc, seg->buf, seg->size); + if (!virtio_net_do_receive(seg->nc, seg->buf, seg->size)) { + chain->stat.drain_failed++; + } QTAILQ_REMOVE(&chain->buffers, seg, next); g_free(seg->buf); @@ -2003,20 +2032,24 @@ static int32_t virtio_net_rsc_filter4(NetRscChain *chain, struct ip_header *ip, /* Not an ipv4 one */ if (0x4 != ((0xF0 & ip->ip_ver_len) >> 4)) { + chain->stat.ip_option++; return RSC_BYPASS; } /* Don't handle packets with ip option */ if (5 != (0xF & ip->ip_ver_len)) { + chain->stat.ip_option++; return RSC_BYPASS; } /* Don't handle packets with ip fragment */ if (!(htons(ip->ip_off) & IP_DF)) { + chain->stat.ip_frag++; return RSC_BYPASS; } if (ip->ip_p != IPPROTO_TCP) { + chain->stat.bypass_not_tcp++; return RSC_BYPASS; } @@ -2024,13 +2057,13 @@ static int32_t virtio_net_rsc_filter4(NetRscChain *chain, struct ip_header *ip, ip_len = htons(ip->ip_len); if (ip_len < (sizeof(struct ip_header) + sizeof(struct tcp_header)) || ip_len > (size - IP_OFFSET)) { + chain->stat.ip_hacked++; return RSC_BYPASS; } return RSC_WANT; } - static size_t virtio_net_rsc_receive4(void *opq, NetClientState* nc, const uint8_t *buf, size_t size) { @@ -2048,8 +2081,10 @@ static size_t virtio_net_rsc_receive4(void *opq, NetClientState* nc, ret = virtio_net_rsc_parse_tcp_ctrl((uint8_t *)ip, (0xF & ip->ip_ver_len) << 2); if (RSC_BYPASS == ret) { + chain->stat.tcp_syn++; return virtio_net_do_receive(nc, buf, size); } else if (RSC_FINAL == ret) { + chain->stat.tcp_ctrl_drain++; return virtio_net_rsc_drain_one(chain, nc, buf, size, IP4_ADDR_OFFSET, IP4_ADDR_SIZE, TCP4_PORT_OFFSET, TCP_PORT_SIZE); } @@ -2073,6 +2108,7 @@ static int32_t virtio_net_rsc_filter6(NetRscChain *chain, struct ip6_header *ip, /* Both option and protocol is checked in this */ if (ip->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) { + chain->stat.bypass_not_tcp++; return RSC_BYPASS; } @@ -2080,6 +2116,7 @@ static int32_t virtio_net_rsc_filter6(NetRscChain *chain, struct ip6_header *ip, ip_len = htons(ip->ip6_ctlun.ip6_un1.ip6_un1_plen); if (ip_len < sizeof(struct tcp_header) || ip_len > (size - TCP6_OFFSET)) { + chain->stat.ip_hacked++; return RSC_BYPASS; } @@ -2101,8 +2138,10 @@ static size_t virtio_net_rsc_receive6(void *opq, NetClientState* nc, ret = virtio_net_rsc_parse_tcp_ctrl((uint8_t *)ip, sizeof(*ip)); if (RSC_BYPASS == ret) { + chain->stat.tcp_syn++; return virtio_net_do_receive(nc, buf, size); } else if (RSC_FINAL == ret) { + chain->stat.tcp_ctrl_drain++; return virtio_net_rsc_drain_one(chain, nc, buf, size, IP6_ADDR_OFFSET, IP6_ADDR_SIZE, TCP6_PORT_OFFSET, TCP_PORT_SIZE); } @@ -2140,6 +2179,7 @@ static NetRscChain *virtio_net_rsc_lookup_chain(NetClientState *nc, chain->proto = proto; chain->drain_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, virtio_net_rsc_purge, chain); + memset(&chain->stat, 0, sizeof(chain->stat)); if (ETH_P_IP == proto) { chain->do_receive = virtio_net_rsc_receive4; } else { @@ -2168,6 +2208,7 @@ static ssize_t virtio_net_rsc_receive(NetClientState *nc, if (!chain) { return virtio_net_do_receive(nc, buf, size); } else { + chain->stat.received++; return chain->do_receive(chain, nc, buf, size); } } @@ -2175,6 +2216,8 @@ static ssize_t virtio_net_rsc_receive(NetClientState *nc, static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t size) { + virtio_net_received++; + if (virtio_net_rsc_bypass) { return virtio_net_do_receive(nc, buf, size); } else { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 1383220..fb53291 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -136,6 +136,38 @@ typedef enum { RSC_WANT /* Data want to be coalesced */ } COALESCE_STATUS; +typedef struct NetRscStat { + uint32_t received; + uint32_t coalesced; + uint32_t over_size; + uint32_t cache; + uint32_t empty_cache; + uint32_t no_match_cache; + uint32_t no_buf; + uint32_t win_update; + uint32_t no_match; + uint32_t tcp_syn; + uint32_t tcp_ctrl_drain; + uint32_t dup_ack; + uint32_t dup_ack1; + uint32_t dup_ack2; + uint32_t pure_ack; + uint32_t ack_out_of_win; + uint32_t data_out_of_win; + uint32_t data_out_of_order; + uint32_t data_after_pure_ack; + uint32_t bypass_not_tcp; + uint32_t tcp_option; + uint32_t tcp_larger_option; + uint32_t ip_frag; + uint32_t ip_hacked; + uint32_t ip_option; + uint32_t purge_failed; + uint32_t drain_failed; + uint32_t final_failed; + int64_t timer; +} NetRscStat; + /* Coalesced segmant */ typedef struct NetRscSeg { QTAILQ_ENTRY(NetRscSeg) next; @@ -157,6 +189,7 @@ typedef struct NetRscChain { VirtioNetReceive *do_receive; QEMUTimer *drain_timer; QTAILQ_HEAD(, NetRscSeg) buffers; + NetRscStat stat; } NetRscChain; void virtio_instance_init_common(Object *proxy_obj, void *data,