From aad0cb3074950a49714cf98562a0602d11ebb3d1 Mon Sep 17 00:00:00 2001
From: Anthony Liguori <[EMAIL PROTECTED]>
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


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to