[kvm-devel] [Virtio-for-kvm] [PATCH 8/13] [Mostly resend] virtio additions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From aad0cb3074950a49714cf98562a0602d11ebb3d1 Mon Sep 17 00:00:00 2001
From: Anthony Liguori <aliguori@xxxxxxxxxx>
Date: Mon, 12 Nov 2007 21:30:26 -0600
Subject: [PATCH] virtio: add debug/performance stats to network driver

ifconfig down or remove the module to get the statistics dump.
---
drivers/net/virtio_net.c | 120 +++++++++++++++++++++++++++++++++++++++-------
1 files changed, 103 insertions(+), 17 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index c4f970e..538cc37 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -49,6 +49,32 @@ struct virtnet_info
    /* Receive & send queues. */
    struct sk_buff_head recv;
    struct sk_buff_head send;
+
+    struct {
+        unsigned int free_old_xmit_skbs_manual;
+        unsigned int free_old_xmit_skbs_tasklet;
+        unsigned int hrtimer_starts;
+        unsigned int hrtimer_fires;
+        unsigned int hrtimer_cancels;
+        unsigned int sendq_kicks;
+        unsigned int sendq_packets;
+        unsigned int sendq_partial_csum;
+        unsigned int sendq_gso;
+        unsigned int sendq_sglen;
+        unsigned int sendq_full;
+        unsigned int sendq_restarted;
+        unsigned int sendq_restart_failed;
+        unsigned int sendq_cancelled;
+        unsigned int recvq_packets;
+        unsigned int recvq_refills;
+        unsigned int recvq_restarted;
+        unsigned int recvq_restart_failed;
+        unsigned int recvq_reschedule_failed;
+        unsigned int recvq_partial_csum;
+        unsigned int recvq_gso;
+        unsigned int recvq_kicks;
+        unsigned int poll;
+    } stats;
};

static inline struct virtio_net_hdr *skb_vnet_hdr(struct sk_buff *skb)
@@ -84,6 +110,7 @@ static void xmit_free(unsigned long data)
    netif_tx_lock(vi->dev);
    free_old_xmit_skbs(vi);
    netif_tx_unlock(vi->dev);
+    vi->stats.free_old_xmit_skbs_tasklet++;

    /* In case we were waiting for output buffers. */
    netif_wake_queue(vi->dev);
@@ -97,28 +124,31 @@ static bool skb_xmit_done(struct virtqueue *rvq)
    return false;
}

-static void receive_skb(struct net_device *dev, struct sk_buff *skb,
+static void receive_skb(struct virtnet_info *vi, struct sk_buff *skb,
            unsigned len)
{
    struct virtio_net_hdr *hdr = skb_vnet_hdr(skb);

+    vi->stats.recvq_packets++;
+
    if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
-        pr_debug("%s: short packet %i\n", dev->name, len);
-        dev->stats.rx_length_errors++;
+        pr_debug("%s: short packet %i\n", vi->dev->name, len);
+        vi->dev->stats.rx_length_errors++;
        goto drop;
    }
    len -= sizeof(struct virtio_net_hdr);
    BUG_ON(len > MAX_PACKET_LEN);

    skb_trim(skb, len);
-    skb->protocol = eth_type_trans(skb, dev);
+    skb->protocol = eth_type_trans(skb, vi->dev);
    pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
         ntohs(skb->protocol), skb->len, skb->pkt_type);
-    dev->stats.rx_bytes += skb->len;
-    dev->stats.rx_packets++;
+    vi->dev->stats.rx_bytes += skb->len;
+    vi->dev->stats.rx_packets++;

    if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
        pr_debug("Needs csum!\n");
+        vi->stats.recvq_partial_csum++;
        skb->ip_summed = CHECKSUM_PARTIAL;
        skb->csum_start = hdr->csum_start;
        skb->csum_offset = hdr->csum_offset;
@@ -126,7 +156,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
            || skb->csum_offset > skb->len - 2) {
            if (net_ratelimit())
                printk(KERN_WARNING "%s: csum=%u/%u len=%u\n",
-                       dev->name, skb->csum_start,
+                       vi->dev->name, skb->csum_start,
                       skb->csum_offset, skb->len);
            goto frame_err;
        }
@@ -134,6 +164,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,

    if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
        pr_debug("GSO!\n");
+        vi->stats.recvq_gso++;
        switch (hdr->gso_type) {
        case VIRTIO_NET_HDR_GSO_TCPV4:
            skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
@@ -150,7 +181,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
        default:
            if (net_ratelimit())
                printk(KERN_WARNING "%s: bad gso type %u.\n",
-                       dev->name, hdr->gso_type);
+                       vi->dev->name, hdr->gso_type);
            goto frame_err;
        }

@@ -158,7 +189,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
        if (skb_shinfo(skb)->gso_size == 0) {
            if (net_ratelimit())
                printk(KERN_WARNING "%s: zero gso size.\n",
-                       dev->name);
+                       vi->dev->name);
            goto frame_err;
        }

@@ -171,7 +202,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
    return;

frame_err:
-    dev->stats.rx_frame_errors++;
+    vi->dev->stats.rx_frame_errors++;
drop:
    dev_kfree_skb(skb);
}
@@ -203,6 +234,7 @@ static void try_fill_recv(struct virtnet_info *vi)
    }
    if (unlikely(vi->num > vi->max))
        vi->max = vi->num;
+    vi->stats.recvq_kicks++;
    vi->rvq->vq_ops->kick(vi->rvq);
}

@@ -220,26 +252,33 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
    struct sk_buff *skb = NULL;
    unsigned int len, received = 0;

+    vi->stats.poll++;
again:
    while (received < budget &&
           (skb = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
        __skb_unlink(skb, &vi->recv);
-        receive_skb(vi->dev, skb, len);
+        receive_skb(vi, skb, len);
        vi->num--;
        received++;
    }

    /* FIXME: If we oom and completely run out of inbufs, we need
     * to start a timer trying to fill more. */
-    if (vi->num < vi->max / 2)
+    if (vi->num < vi->max / 2) {
+        vi->stats.recvq_refills++;
        try_fill_recv(vi);
+    }

    /* Out of packets? */
    if (received < budget) {
        netif_rx_complete(vi->dev, napi);
-        if (unlikely(!vi->rvq->vq_ops->restart(vi->rvq))
-            && netif_rx_reschedule(vi->dev, napi))
-            goto again;
+        vi->stats.recvq_restarted++;
+        if (unlikely(!vi->rvq->vq_ops->restart(vi->rvq))) {
+            vi->stats.recvq_restart_failed++;
+            if (netif_rx_reschedule(vi->dev, napi))
+                goto again;
+            vi->stats.recvq_reschedule_failed++;
+        }
    }

    return received;
@@ -249,9 +288,11 @@ static enum hrtimer_restart kick_xmit(struct hrtimer *t)
{
    struct virtnet_info *vi = container_of(t,struct virtnet_info,tx_timer);

+    vi->stats.hrtimer_fires++;
    BUG_ON(!in_softirq());
    BUG_ON(in_irq());
    netif_tx_lock(vi->dev);
+    vi->stats.sendq_kicks++;
    vi->svq->vq_ops->kick(vi->svq);
    vi->out_num = 0;
    netif_tx_unlock(vi->dev);
@@ -272,12 +313,14 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)

    pr_debug("%s: xmit %p %s\n", dev->name, skb, print_mac(mac, dest));

+    vi->stats.sendq_packets++;
    /* Encode metadata header at front. */
    hdr = skb_vnet_hdr(skb);
    if (skb->ip_summed == CHECKSUM_PARTIAL) {
        hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
        hdr->csum_start = skb->csum_start - skb_headroom(skb);
        hdr->csum_offset = skb->csum_offset;
+        vi->stats.sendq_partial_csum++;
    } else {
        hdr->flags = 0;
        hdr->csum_offset = hdr->csum_start = 0;
@@ -285,6 +328,7 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)

    if (skb_is_gso(skb)) {
        hdr->gso_size = skb_shinfo(skb)->gso_size;
+        vi->stats.sendq_gso++;
        if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
            hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4_ECN;
        else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
@@ -303,18 +347,23 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
    vnet_hdr_to_sg(sg, skb);
    num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
    __skb_queue_head(&vi->send, skb);
+    vi->stats.sendq_sglen += num;

again:
    err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
    if (err) {
+        vi->stats.sendq_full++;
+
        /* Can we free any used skbs? */
+        vi->stats.free_old_xmit_skbs_manual++;
        if (free_old_xmit_skbs(vi))
            goto again;

        /* Activate callback for using skbs: if this fails it
         * means some were used in the meantime. */
+        vi->stats.sendq_restarted++;
        if (unlikely(!vi->svq->vq_ops->restart(vi->svq))) {
-            printk("Unlikely: restart svq failed\n");
+            vi->stats.sendq_restart_failed++;
            goto again;
        }

@@ -326,20 +375,28 @@ again:
                   dev->name, vi->out_max, vi->out_num);
        vi->out_max = vi->out_num;
        vi->out_num = 0;
+        vi->stats.sendq_cancelled++;
+
        /* Kick off send immediately. */
+        vi->stats.hrtimer_cancels++;
        hrtimer_cancel(&vi->tx_timer);
+        vi->stats.sendq_kicks++;
        vi->svq->vq_ops->kick(vi->svq);
        netif_stop_queue(dev);
        return NETDEV_TX_BUSY;
    }

    if (++vi->out_num == vi->out_max) {
+        vi->stats.hrtimer_cancels++;
        hrtimer_cancel(&vi->tx_timer);
+        vi->stats.sendq_kicks++;
        vi->svq->vq_ops->kick(vi->svq);
        vi->out_num = 0;
-    } else
+    } else {
+        vi->stats.hrtimer_starts++;
        hrtimer_start(&vi->tx_timer, ktime_set(0,500000),
                  HRTIMER_MODE_REL);
+    }
    return 0;
}

@@ -376,6 +433,35 @@ static int virtnet_close(struct net_device *dev)
        kfree_skb(skb);

    BUG_ON(vi->num != 0);
+
+    printk("Stats for %s\n", dev->name);
+    printk("free_old_xmit_skbs_manual = %u\n",
+           vi->stats.free_old_xmit_skbs_manual);
+    printk("free_old_xmit_skbs_tasklet = %u\n",
+           vi->stats.free_old_xmit_skbs_tasklet);
+    printk("hrtimer_starts = %u\n", vi->stats.hrtimer_starts);
+    printk("hrtimer_fires = %u\n", vi->stats.hrtimer_fires);
+    printk("hrtimer_cancels = %u\n", vi->stats.hrtimer_cancels);
+    printk("sendq_kicks = %u\n", vi->stats.sendq_kicks);
+    printk("sendq_packets = %u\n", vi->stats.sendq_packets);
+    printk("sendq_partial_csum = %u\n", vi->stats.sendq_partial_csum);
+    printk("sendq_gso = %u\n", vi->stats.sendq_gso);
+    printk("sendq_sglen = %u\n", vi->stats.sendq_sglen);
+    printk("sendq_full = %u\n", vi->stats.sendq_full);
+    printk("sendq_restarted = %u\n", vi->stats.sendq_restarted);
+    printk("sendq_restart_failed = %u\n", vi->stats.sendq_restart_failed);
+    printk("sendq_cancelled = %u\n", vi->stats.sendq_cancelled);
+    printk("recvq_packets = %u\n", vi->stats.recvq_packets);
+    printk("recvq_refills = %u\n", vi->stats.recvq_refills);
+    printk("recvq_restarted = %u\n", vi->stats.recvq_restarted);
+    printk("recvq_restart_failed = %u\n", vi->stats.recvq_restart_failed);
+    printk("recvq_reschedule_failed = %u\n",
+           vi->stats.recvq_reschedule_failed);
+    printk("recvq_partial_csum = %u\n", vi->stats.recvq_partial_csum);
+    printk("recvq_gso = %u\n", vi->stats.recvq_gso);
+    printk("recvq_kicks = %u\n", vi->stats.recvq_kicks);
+    printk("poll = %u\n", vi->stats.poll);
+
    return 0;
}

--
1.5.3.3

_______________________________________________
Virtualization mailing list
Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx
https://lists.linux-foundation.org/mailman/listinfo/virtualization

[Index of Archives]     [KVM Development]     [Libvirt Development]     [Libvirt Users]     [CentOS Virtualization]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux