netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] virtio-net: per cpu 64 bit stats
@ 2011-06-15 15:43 Stephen Hemminger
  2011-06-15 15:58 ` Eric Dumazet
  2011-06-15 18:33 ` [PATCH] virtio-net: per cpu 64 bit stats Michael S. Tsirkin
  0 siblings, 2 replies; 6+ messages in thread
From: Stephen Hemminger @ 2011-06-15 15:43 UTC (permalink / raw)
  To: Rusty Russell, Michael S. Tsirkin; +Cc: virtualization, netdev

Use per-cpu variables to maintain 64 bit statistics.
Compile tested only.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/drivers/net/virtio_net.c	2011-06-14 15:18:46.448596355 -0400
+++ b/drivers/net/virtio_net.c	2011-06-15 09:54:22.914426067 -0400
@@ -40,6 +40,15 @@ module_param(gso, bool, 0444);
 
 #define VIRTNET_SEND_COMMAND_SG_MAX    2
 
+struct virtnet_stats {
+	struct u64_stats_sync syncp;
+	u64 tx_bytes;
+	u64 tx_packets;
+
+	u64 rx_bytes;
+	u64 rx_packets;
+};
+
 struct virtnet_info {
 	struct virtio_device *vdev;
 	struct virtqueue *rvq, *svq, *cvq;
@@ -56,6 +65,9 @@ struct virtnet_info {
 	/* Host will merge rx buffers for big packets (shake it! shake it!) */
 	bool mergeable_rx_bufs;
 
+	/* Active statistics */
+	struct virtnet_stats __percpu *stats;
+
 	/* Work struct for refilling if we run low on memory. */
 	struct delayed_work refill;
 
@@ -209,7 +221,6 @@ static int receive_mergeable(struct virt
 			skb->dev->stats.rx_length_errors++;
 			return -EINVAL;
 		}
-
 		page = virtqueue_get_buf(vi->rvq, &len);
 		if (!page) {
 			pr_debug("%s: rx error: %d buffers missing\n",
@@ -217,6 +228,7 @@ static int receive_mergeable(struct virt
 			skb->dev->stats.rx_length_errors++;
 			return -EINVAL;
 		}
+
 		if (len > PAGE_SIZE)
 			len = PAGE_SIZE;
 
@@ -230,6 +242,7 @@ static int receive_mergeable(struct virt
 static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
 {
 	struct virtnet_info *vi = netdev_priv(dev);
+	struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
 	struct sk_buff *skb;
 	struct page *page;
 	struct skb_vnet_hdr *hdr;
@@ -265,8 +278,11 @@ static void receive_buf(struct net_devic
 
 	hdr = skb_vnet_hdr(skb);
 	skb->truesize += skb->data_len;
-	dev->stats.rx_bytes += skb->len;
-	dev->stats.rx_packets++;
+
+	u64_stats_update_begin(&stats->syncp);
+	stats->rx_bytes += skb->len;
+	stats->rx_packets++;
+	u64_stats_update_begin(&stats->syncp);
 
 	if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
 		pr_debug("Needs csum!\n");
@@ -515,11 +531,16 @@ static unsigned int free_old_xmit_skbs(s
 {
 	struct sk_buff *skb;
 	unsigned int len, tot_sgs = 0;
+	struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
 
 	while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) {
 		pr_debug("Sent skb %p\n", skb);
-		vi->dev->stats.tx_bytes += skb->len;
-		vi->dev->stats.tx_packets++;
+
+		u64_stats_update_begin(&stats->syncp);
+		stats->tx_bytes += skb->len;
+		stats->tx_packets++;
+		u64_stats_update_begin(&stats->syncp);
+
 		tot_sgs += skb_vnet_hdr(skb)->num_sg;
 		dev_kfree_skb_any(skb);
 	}
@@ -641,6 +662,40 @@ static int virtnet_set_mac_address(struc
 	return 0;
 }
 
+static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+					       struct rtnl_link_stats64 *tot)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	int cpu;
+	unsigned int start;
+
+	for_each_possible_cpu(cpu) {
+		struct virtnet_stats __percpu *stats
+			= per_cpu_ptr(vi->stats, cpu);
+		u64 tpackets, tbytes, rpackets, rbytes;
+
+		do {
+			start = u64_stats_fetch_begin(&stats->syncp);
+			tpackets = stats->tx_packets;
+			tbytes   = stats->tx_bytes;
+			rpackets = stats->rx_packets;
+			rbytes   = stats->rx_bytes;
+		} while (u64_stats_fetch_retry(&stats->syncp, start));
+
+		tot->rx_packets += rpackets;
+		tot->tx_packets += tpackets;
+		tot->rx_bytes   += rbytes;
+		tot->tx_bytes   += tbytes;
+	}
+
+	tot->tx_dropped = dev->stats.tx_dropped;
+	tot->rx_dropped = dev->stats.rx_dropped;
+	tot->rx_length_errors = dev->stats.rx_length_errors;
+	tot->rx_frame_errors = dev->stats.rx_frame_errors;
+
+	return tot;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void virtnet_netpoll(struct net_device *dev)
 {
@@ -650,6 +705,14 @@ static void virtnet_netpoll(struct net_d
 }
 #endif
 
+static void virtnet_free(struct net_device *dev)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+
+	free_percpu(vi->stats);
+	free_netdev(dev);
+}
+
 static int virtnet_open(struct net_device *dev)
 {
 	struct virtnet_info *vi = netdev_priv(dev);
@@ -835,6 +898,7 @@ static const struct net_device_ops virtn
 	.ndo_set_mac_address = virtnet_set_mac_address,
 	.ndo_set_rx_mode     = virtnet_set_rx_mode,
 	.ndo_change_mtu	     = virtnet_change_mtu,
+	.ndo_get_stats64     = virtnet_stats,
 	.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -895,6 +959,8 @@ static int virtnet_probe(struct virtio_d
 	/* Set up network device as normal. */
 	dev->netdev_ops = &virtnet_netdev;
 	dev->features = NETIF_F_HIGHDMA;
+	dev->destructor = virtnet_free;
+
 	SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
 	SET_NETDEV_DEV(dev, &vdev->dev);
 
@@ -939,6 +1005,11 @@ static int virtnet_probe(struct virtio_d
 	vi->vdev = vdev;
 	vdev->priv = vi;
 	vi->pages = NULL;
+	vi->stats = alloc_percpu(struct virtnet_stats);
+	err = -ENOMEM;
+	if (vi->stats == NULL)
+		goto free;
+
 	INIT_DELAYED_WORK(&vi->refill, refill_work);
 	sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg));
 	sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg));
@@ -958,7 +1029,7 @@ static int virtnet_probe(struct virtio_d
 
 	err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
 	if (err)
-		goto free;
+		goto free_stats;
 
 	vi->rvq = vqs[0];
 	vi->svq = vqs[1];
@@ -1003,6 +1074,8 @@ unregister:
 	cancel_delayed_work_sync(&vi->refill);
 free_vqs:
 	vdev->config->del_vqs(vdev);
+free_stats:
+	free_percpu(vi->stats);
 free:
 	free_netdev(dev);
 	return err;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] virtio-net: per cpu 64 bit stats
  2011-06-15 15:43 [PATCH] virtio-net: per cpu 64 bit stats Stephen Hemminger
@ 2011-06-15 15:58 ` Eric Dumazet
  2011-06-15 16:36   ` [PATCH] virtio-net: per cpu 64 bit stats (v2) Stephen Hemminger
  2011-06-15 18:33 ` [PATCH] virtio-net: per cpu 64 bit stats Michael S. Tsirkin
  1 sibling, 1 reply; 6+ messages in thread
From: Eric Dumazet @ 2011-06-15 15:58 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Rusty Russell, Michael S. Tsirkin, virtualization, netdev

Le mercredi 15 juin 2011 à 11:43 -0400, Stephen Hemminger a écrit :
> Use per-cpu variables to maintain 64 bit statistics.
> Compile tested only.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> 
> --- a/drivers/net/virtio_net.c	2011-06-14 15:18:46.448596355 -0400
> +++ b/drivers/net/virtio_net.c	2011-06-15 09:54:22.914426067 -0400
> @@ -40,6 +40,15 @@ module_param(gso, bool, 0444);
>  
>  #define VIRTNET_SEND_COMMAND_SG_MAX    2
>  
> +struct virtnet_stats {
> +	struct u64_stats_sync syncp;
> +	u64 tx_bytes;
> +	u64 tx_packets;
> +
> +	u64 rx_bytes;
> +	u64 rx_packets;
> +};
> +
>  struct virtnet_info {
>  	struct virtio_device *vdev;
>  	struct virtqueue *rvq, *svq, *cvq;
> @@ -56,6 +65,9 @@ struct virtnet_info {
>  	/* Host will merge rx buffers for big packets (shake it! shake it!) */
>  	bool mergeable_rx_bufs;
>  
> +	/* Active statistics */
> +	struct virtnet_stats __percpu *stats;
> +
>  	/* Work struct for refilling if we run low on memory. */
>  	struct delayed_work refill;
>  
> @@ -209,7 +221,6 @@ static int receive_mergeable(struct virt
>  			skb->dev->stats.rx_length_errors++;
>  			return -EINVAL;
>  		}
> -
>  		page = virtqueue_get_buf(vi->rvq, &len);
>  		if (!page) {
>  			pr_debug("%s: rx error: %d buffers missing\n",
> @@ -217,6 +228,7 @@ static int receive_mergeable(struct virt
>  			skb->dev->stats.rx_length_errors++;
>  			return -EINVAL;
>  		}
> +
>  		if (len > PAGE_SIZE)
>  			len = PAGE_SIZE;
>  
> @@ -230,6 +242,7 @@ static int receive_mergeable(struct virt
>  static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
>  {
>  	struct virtnet_info *vi = netdev_priv(dev);
> +	struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
>  	struct sk_buff *skb;
>  	struct page *page;
>  	struct skb_vnet_hdr *hdr;
> @@ -265,8 +278,11 @@ static void receive_buf(struct net_devic
>  
>  	hdr = skb_vnet_hdr(skb);
>  	skb->truesize += skb->data_len;
> -	dev->stats.rx_bytes += skb->len;
> -	dev->stats.rx_packets++;
> +
> +	u64_stats_update_begin(&stats->syncp);
> +	stats->rx_bytes += skb->len;
> +	stats->rx_packets++;
> +	u64_stats_update_begin(&stats->syncp);

	u64_stats_update_end(&stats->syncp);


>  
>  	if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
>  		pr_debug("Needs csum!\n");
> @@ -515,11 +531,16 @@ static unsigned int free_old_xmit_skbs(s
>  {
>  	struct sk_buff *skb;
>  	unsigned int len, tot_sgs = 0;
> +	struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
>  
>  	while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) {
>  		pr_debug("Sent skb %p\n", skb);
> -		vi->dev->stats.tx_bytes += skb->len;
> -		vi->dev->stats.tx_packets++;
> +
> +		u64_stats_update_begin(&stats->syncp);
> +		stats->tx_bytes += skb->len;
> +		stats->tx_packets++;
> +		u64_stats_update_begin(&stats->syncp);

	u64_stats_update_end(&stats->syncp);

> +
>  		tot_sgs += skb_vnet_hdr(skb)->num_sg;
>  		dev_kfree_skb_any(skb);
>  	}
> @@ -641,6 +662,40 @@ static int virtnet_set_mac_address(struc
>  	return 0;
>  }
>  



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] virtio-net: per cpu 64 bit stats (v2)
  2011-06-15 15:58 ` Eric Dumazet
@ 2011-06-15 16:36   ` Stephen Hemminger
  2011-06-17 19:18     ` David Miller
  0 siblings, 1 reply; 6+ messages in thread
From: Stephen Hemminger @ 2011-06-15 16:36 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Rusty Russell, Michael S. Tsirkin, virtualization, netdev

Use per-cpu variables to maintain 64 bit statistics.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/drivers/net/virtio_net.c	2011-06-14 15:18:46.448596355 -0400
+++ b/drivers/net/virtio_net.c	2011-06-15 12:02:54.860667443 -0400
@@ -40,6 +40,15 @@ module_param(gso, bool, 0444);
 
 #define VIRTNET_SEND_COMMAND_SG_MAX    2
 
+struct virtnet_stats {
+	struct u64_stats_sync syncp;
+	u64 tx_bytes;
+	u64 tx_packets;
+
+	u64 rx_bytes;
+	u64 rx_packets;
+};
+
 struct virtnet_info {
 	struct virtio_device *vdev;
 	struct virtqueue *rvq, *svq, *cvq;
@@ -56,6 +65,9 @@ struct virtnet_info {
 	/* Host will merge rx buffers for big packets (shake it! shake it!) */
 	bool mergeable_rx_bufs;
 
+	/* Active statistics */
+	struct virtnet_stats __percpu *stats;
+
 	/* Work struct for refilling if we run low on memory. */
 	struct delayed_work refill;
 
@@ -209,7 +221,6 @@ static int receive_mergeable(struct virt
 			skb->dev->stats.rx_length_errors++;
 			return -EINVAL;
 		}
-
 		page = virtqueue_get_buf(vi->rvq, &len);
 		if (!page) {
 			pr_debug("%s: rx error: %d buffers missing\n",
@@ -217,6 +228,7 @@ static int receive_mergeable(struct virt
 			skb->dev->stats.rx_length_errors++;
 			return -EINVAL;
 		}
+
 		if (len > PAGE_SIZE)
 			len = PAGE_SIZE;
 
@@ -230,6 +242,7 @@ static int receive_mergeable(struct virt
 static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
 {
 	struct virtnet_info *vi = netdev_priv(dev);
+	struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
 	struct sk_buff *skb;
 	struct page *page;
 	struct skb_vnet_hdr *hdr;
@@ -265,8 +278,11 @@ static void receive_buf(struct net_devic
 
 	hdr = skb_vnet_hdr(skb);
 	skb->truesize += skb->data_len;
-	dev->stats.rx_bytes += skb->len;
-	dev->stats.rx_packets++;
+
+	u64_stats_update_begin(&stats->syncp);
+	stats->rx_bytes += skb->len;
+	stats->rx_packets++;
+	u64_stats_update_end(&stats->syncp);
 
 	if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
 		pr_debug("Needs csum!\n");
@@ -515,11 +531,16 @@ static unsigned int free_old_xmit_skbs(s
 {
 	struct sk_buff *skb;
 	unsigned int len, tot_sgs = 0;
+	struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
 
 	while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) {
 		pr_debug("Sent skb %p\n", skb);
-		vi->dev->stats.tx_bytes += skb->len;
-		vi->dev->stats.tx_packets++;
+
+		u64_stats_update_begin(&stats->syncp);
+		stats->tx_bytes += skb->len;
+		stats->tx_packets++;
+		u64_stats_update_end(&stats->syncp);
+
 		tot_sgs += skb_vnet_hdr(skb)->num_sg;
 		dev_kfree_skb_any(skb);
 	}
@@ -641,6 +662,40 @@ static int virtnet_set_mac_address(struc
 	return 0;
 }
 
+static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+					       struct rtnl_link_stats64 *tot)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	int cpu;
+	unsigned int start;
+
+	for_each_possible_cpu(cpu) {
+		struct virtnet_stats __percpu *stats
+			= per_cpu_ptr(vi->stats, cpu);
+		u64 tpackets, tbytes, rpackets, rbytes;
+
+		do {
+			start = u64_stats_fetch_begin(&stats->syncp);
+			tpackets = stats->tx_packets;
+			tbytes   = stats->tx_bytes;
+			rpackets = stats->rx_packets;
+			rbytes   = stats->rx_bytes;
+		} while (u64_stats_fetch_retry(&stats->syncp, start));
+
+		tot->rx_packets += rpackets;
+		tot->tx_packets += tpackets;
+		tot->rx_bytes   += rbytes;
+		tot->tx_bytes   += tbytes;
+	}
+
+	tot->tx_dropped = dev->stats.tx_dropped;
+	tot->rx_dropped = dev->stats.rx_dropped;
+	tot->rx_length_errors = dev->stats.rx_length_errors;
+	tot->rx_frame_errors = dev->stats.rx_frame_errors;
+
+	return tot;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void virtnet_netpoll(struct net_device *dev)
 {
@@ -650,6 +705,14 @@ static void virtnet_netpoll(struct net_d
 }
 #endif
 
+static void virtnet_free(struct net_device *dev)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+
+	free_percpu(vi->stats);
+	free_netdev(dev);
+}
+
 static int virtnet_open(struct net_device *dev)
 {
 	struct virtnet_info *vi = netdev_priv(dev);
@@ -835,6 +898,7 @@ static const struct net_device_ops virtn
 	.ndo_set_mac_address = virtnet_set_mac_address,
 	.ndo_set_rx_mode     = virtnet_set_rx_mode,
 	.ndo_change_mtu	     = virtnet_change_mtu,
+	.ndo_get_stats64     = virtnet_stats,
 	.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -895,6 +959,8 @@ static int virtnet_probe(struct virtio_d
 	/* Set up network device as normal. */
 	dev->netdev_ops = &virtnet_netdev;
 	dev->features = NETIF_F_HIGHDMA;
+	dev->destructor = virtnet_free;
+
 	SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
 	SET_NETDEV_DEV(dev, &vdev->dev);
 
@@ -939,6 +1005,11 @@ static int virtnet_probe(struct virtio_d
 	vi->vdev = vdev;
 	vdev->priv = vi;
 	vi->pages = NULL;
+	vi->stats = alloc_percpu(struct virtnet_stats);
+	err = -ENOMEM;
+	if (vi->stats == NULL)
+		goto free;
+
 	INIT_DELAYED_WORK(&vi->refill, refill_work);
 	sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg));
 	sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg));
@@ -958,7 +1029,7 @@ static int virtnet_probe(struct virtio_d
 
 	err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
 	if (err)
-		goto free;
+		goto free_stats;
 
 	vi->rvq = vqs[0];
 	vi->svq = vqs[1];
@@ -1003,6 +1074,8 @@ unregister:
 	cancel_delayed_work_sync(&vi->refill);
 free_vqs:
 	vdev->config->del_vqs(vdev);
+free_stats:
+	free_percpu(vi->stats);
 free:
 	free_netdev(dev);
 	return err;
 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] virtio-net: per cpu 64 bit stats
  2011-06-15 15:43 [PATCH] virtio-net: per cpu 64 bit stats Stephen Hemminger
  2011-06-15 15:58 ` Eric Dumazet
@ 2011-06-15 18:33 ` Michael S. Tsirkin
  2011-06-17 19:13   ` Stephen Hemminger
  1 sibling, 1 reply; 6+ messages in thread
From: Michael S. Tsirkin @ 2011-06-15 18:33 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: Rusty Russell, virtualization, netdev

On Wed, Jun 15, 2011 at 11:43:37AM -0400, Stephen Hemminger wrote:
> Use per-cpu variables to maintain 64 bit statistics.
> Compile tested only.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

Interesting. Does this help speed at all?

> --- a/drivers/net/virtio_net.c	2011-06-14 15:18:46.448596355 -0400
> +++ b/drivers/net/virtio_net.c	2011-06-15 09:54:22.914426067 -0400
> @@ -40,6 +40,15 @@ module_param(gso, bool, 0444);
>  
>  #define VIRTNET_SEND_COMMAND_SG_MAX    2
>  
> +struct virtnet_stats {
> +	struct u64_stats_sync syncp;
> +	u64 tx_bytes;
> +	u64 tx_packets;
> +
> +	u64 rx_bytes;
> +	u64 rx_packets;
> +};
> +
>  struct virtnet_info {
>  	struct virtio_device *vdev;
>  	struct virtqueue *rvq, *svq, *cvq;
> @@ -56,6 +65,9 @@ struct virtnet_info {
>  	/* Host will merge rx buffers for big packets (shake it! shake it!) */
>  	bool mergeable_rx_bufs;
>  
> +	/* Active statistics */
> +	struct virtnet_stats __percpu *stats;
> +
>  	/* Work struct for refilling if we run low on memory. */
>  	struct delayed_work refill;
>  
> @@ -209,7 +221,6 @@ static int receive_mergeable(struct virt
>  			skb->dev->stats.rx_length_errors++;
>  			return -EINVAL;
>  		}
> -
>  		page = virtqueue_get_buf(vi->rvq, &len);
>  		if (!page) {
>  			pr_debug("%s: rx error: %d buffers missing\n",
> @@ -217,6 +228,7 @@ static int receive_mergeable(struct virt
>  			skb->dev->stats.rx_length_errors++;
>  			return -EINVAL;
>  		}
> +
>  		if (len > PAGE_SIZE)
>  			len = PAGE_SIZE;
>

Let's not tweak whitespace unnecessarily.
  
> @@ -230,6 +242,7 @@ static int receive_mergeable(struct virt
>  static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
>  {
>  	struct virtnet_info *vi = netdev_priv(dev);
> +	struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
>  	struct sk_buff *skb;
>  	struct page *page;
>  	struct skb_vnet_hdr *hdr;
> @@ -265,8 +278,11 @@ static void receive_buf(struct net_devic
>  
>  	hdr = skb_vnet_hdr(skb);
>  	skb->truesize += skb->data_len;
> -	dev->stats.rx_bytes += skb->len;
> -	dev->stats.rx_packets++;
> +
> +	u64_stats_update_begin(&stats->syncp);
> +	stats->rx_bytes += skb->len;
> +	stats->rx_packets++;
> +	u64_stats_update_begin(&stats->syncp);
>  
>  	if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
>  		pr_debug("Needs csum!\n");
> @@ -515,11 +531,16 @@ static unsigned int free_old_xmit_skbs(s
>  {
>  	struct sk_buff *skb;
>  	unsigned int len, tot_sgs = 0;
> +	struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
>  
>  	while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) {
>  		pr_debug("Sent skb %p\n", skb);
> -		vi->dev->stats.tx_bytes += skb->len;
> -		vi->dev->stats.tx_packets++;
> +
> +		u64_stats_update_begin(&stats->syncp);
> +		stats->tx_bytes += skb->len;
> +		stats->tx_packets++;
> +		u64_stats_update_begin(&stats->syncp);
> +
>  		tot_sgs += skb_vnet_hdr(skb)->num_sg;
>  		dev_kfree_skb_any(skb);
>  	}
> @@ -641,6 +662,40 @@ static int virtnet_set_mac_address(struc
>  	return 0;
>  }
>  
> +static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
> +					       struct rtnl_link_stats64 *tot)
> +{
> +	struct virtnet_info *vi = netdev_priv(dev);
> +	int cpu;
> +	unsigned int start;
> +
> +	for_each_possible_cpu(cpu) {
> +		struct virtnet_stats __percpu *stats
> +			= per_cpu_ptr(vi->stats, cpu);
> +		u64 tpackets, tbytes, rpackets, rbytes;
> +
> +		do {
> +			start = u64_stats_fetch_begin(&stats->syncp);
> +			tpackets = stats->tx_packets;
> +			tbytes   = stats->tx_bytes;
> +			rpackets = stats->rx_packets;
> +			rbytes   = stats->rx_bytes;
> +		} while (u64_stats_fetch_retry(&stats->syncp, start));
> +
> +		tot->rx_packets += rpackets;
> +		tot->tx_packets += tpackets;
> +		tot->rx_bytes   += rbytes;
> +		tot->tx_bytes   += tbytes;
> +	}
> +
> +	tot->tx_dropped = dev->stats.tx_dropped;
> +	tot->rx_dropped = dev->stats.rx_dropped;
> +	tot->rx_length_errors = dev->stats.rx_length_errors;
> +	tot->rx_frame_errors = dev->stats.rx_frame_errors;
> +
> +	return tot;
> +}
> +
>  #ifdef CONFIG_NET_POLL_CONTROLLER
>  static void virtnet_netpoll(struct net_device *dev)
>  {
> @@ -650,6 +705,14 @@ static void virtnet_netpoll(struct net_d
>  }
>  #endif
>  
> +static void virtnet_free(struct net_device *dev)
> +{
> +	struct virtnet_info *vi = netdev_priv(dev);
> +
> +	free_percpu(vi->stats);
> +	free_netdev(dev);
> +}
> +
>  static int virtnet_open(struct net_device *dev)
>  {
>  	struct virtnet_info *vi = netdev_priv(dev);
> @@ -835,6 +898,7 @@ static const struct net_device_ops virtn
>  	.ndo_set_mac_address = virtnet_set_mac_address,
>  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
>  	.ndo_change_mtu	     = virtnet_change_mtu,
> +	.ndo_get_stats64     = virtnet_stats,
>  	.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
>  	.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
>  #ifdef CONFIG_NET_POLL_CONTROLLER
> @@ -895,6 +959,8 @@ static int virtnet_probe(struct virtio_d
>  	/* Set up network device as normal. */
>  	dev->netdev_ops = &virtnet_netdev;
>  	dev->features = NETIF_F_HIGHDMA;
> +	dev->destructor = virtnet_free;
> +
>  	SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
>  	SET_NETDEV_DEV(dev, &vdev->dev);
>  
> @@ -939,6 +1005,11 @@ static int virtnet_probe(struct virtio_d
>  	vi->vdev = vdev;
>  	vdev->priv = vi;
>  	vi->pages = NULL;
> +	vi->stats = alloc_percpu(struct virtnet_stats);
> +	err = -ENOMEM;
> +	if (vi->stats == NULL)
> +		goto free;
> +
>  	INIT_DELAYED_WORK(&vi->refill, refill_work);
>  	sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg));
>  	sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg));
> @@ -958,7 +1029,7 @@ static int virtnet_probe(struct virtio_d
>  
>  	err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
>  	if (err)
> -		goto free;
> +		goto free_stats;
>  
>  	vi->rvq = vqs[0];
>  	vi->svq = vqs[1];
> @@ -1003,6 +1074,8 @@ unregister:
>  	cancel_delayed_work_sync(&vi->refill);
>  free_vqs:
>  	vdev->config->del_vqs(vdev);
> +free_stats:
> +	free_percpu(vi->stats);
>  free:
>  	free_netdev(dev);
>  	return err;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] virtio-net: per cpu 64 bit stats
  2011-06-15 18:33 ` [PATCH] virtio-net: per cpu 64 bit stats Michael S. Tsirkin
@ 2011-06-17 19:13   ` Stephen Hemminger
  0 siblings, 0 replies; 6+ messages in thread
From: Stephen Hemminger @ 2011-06-17 19:13 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: Rusty Russell, virtualization, netdev

On Wed, 15 Jun 2011 21:33:16 +0300
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Wed, Jun 15, 2011 at 11:43:37AM -0400, Stephen Hemminger wrote:
> > Use per-cpu variables to maintain 64 bit statistics.
> > Compile tested only.
> > 
> > Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> 
> Interesting. Does this help speed at all?
> 
> > --- a/drivers/net/virtio_net.c	2011-06-14 15:18:46.448596355 -0400
> > +++ b/drivers/net/virtio_net.c	2011-06-15 09:54:22.914426067 -0400
> > @@ -40,6 +40,15 @@ module_param(gso, bool, 0444);
> >  
> >  #define VIRTNET_SEND_COMMAND_SG_MAX    2
> >  
> > +struct virtnet_stats {
> > +	struct u64_stats_sync syncp;
> > +	u64 tx_bytes;
> > +	u64 tx_packets;
> > +
> > +	u64 rx_bytes;
> > +	u64 rx_packets;
> > +};
> > +
> >  struct virtnet_info {
> >  	struct virtio_device *vdev;
> >  	struct virtqueue *rvq, *svq, *cvq;
> > @@ -56,6 +65,9 @@ struct virtnet_info {
> >  	/* Host will merge rx buffers for big packets (shake it! shake it!) */
> >  	bool mergeable_rx_bufs;
> >  
> > +	/* Active statistics */
> > +	struct virtnet_stats __percpu *stats;
> > +
> >  	/* Work struct for refilling if we run low on memory. */
> >  	struct delayed_work refill;
> >  
> > @@ -209,7 +221,6 @@ static int receive_mergeable(struct virt
> >  			skb->dev->stats.rx_length_errors++;
> >  			return -EINVAL;
> >  		}
> > -
> >  		page = virtqueue_get_buf(vi->rvq, &len);
> >  		if (!page) {
> >  			pr_debug("%s: rx error: %d buffers missing\n",
> > @@ -217,6 +228,7 @@ static int receive_mergeable(struct virt
> >  			skb->dev->stats.rx_length_errors++;
> >  			return -EINVAL;
> >  		}
> > +
> >  		if (len > PAGE_SIZE)
> >  			len = PAGE_SIZE;
> >
> 
> Let's not tweak whitespace unnecessarily.
>   
> > @@ -230,6 +242,7 @@ static int receive_mergeable(struct virt
> >  static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
> >  {
> >  	struct virtnet_info *vi = netdev_priv(dev);
> > +	struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
> >  	struct sk_buff *skb;
> >  	struct page *page;
> >  	struct skb_vnet_hdr *hdr;
> > @@ -265,8 +278,11 @@ static void receive_buf(struct net_devic
> >  
> >  	hdr = skb_vnet_hdr(skb);
> >  	skb->truesize += skb->data_len;
> > -	dev->stats.rx_bytes += skb->len;
> > -	dev->stats.rx_packets++;
> > +
> > +	u64_stats_update_begin(&stats->syncp);
> > +	stats->rx_bytes += skb->len;
> > +	stats->rx_packets++;
> > +	u64_stats_update_begin(&stats->syncp);
> >  
> >  	if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
> >  		pr_debug("Needs csum!\n");
> > @@ -515,11 +531,16 @@ static unsigned int free_old_xmit_skbs(s
> >  {
> >  	struct sk_buff *skb;
> >  	unsigned int len, tot_sgs = 0;
> > +	struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
> >  
> >  	while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) {
> >  		pr_debug("Sent skb %p\n", skb);
> > -		vi->dev->stats.tx_bytes += skb->len;
> > -		vi->dev->stats.tx_packets++;
> > +
> > +		u64_stats_update_begin(&stats->syncp);
> > +		stats->tx_bytes += skb->len;
> > +		stats->tx_packets++;
> > +		u64_stats_update_begin(&stats->syncp);
> > +
> >  		tot_sgs += skb_vnet_hdr(skb)->num_sg;
> >  		dev_kfree_skb_any(skb);
> >  	}
> > @@ -641,6 +662,40 @@ static int virtnet_set_mac_address(struc
> >  	return 0;
> >  }
> >  
> > +static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
> > +					       struct rtnl_link_stats64 *tot)
> > +{
> > +	struct virtnet_info *vi = netdev_priv(dev);
> > +	int cpu;
> > +	unsigned int start;
> > +
> > +	for_each_possible_cpu(cpu) {
> > +		struct virtnet_stats __percpu *stats
> > +			= per_cpu_ptr(vi->stats, cpu);
> > +		u64 tpackets, tbytes, rpackets, rbytes;
> > +
> > +		do {
> > +			start = u64_stats_fetch_begin(&stats->syncp);
> > +			tpackets = stats->tx_packets;
> > +			tbytes   = stats->tx_bytes;
> > +			rpackets = stats->rx_packets;
> > +			rbytes   = stats->rx_bytes;
> > +		} while (u64_stats_fetch_retry(&stats->syncp, start));
> > +
> > +		tot->rx_packets += rpackets;
> > +		tot->tx_packets += tpackets;
> > +		tot->rx_bytes   += rbytes;
> > +		tot->tx_bytes   += tbytes;
> > +	}
> > +
> > +	tot->tx_dropped = dev->stats.tx_dropped;
> > +	tot->rx_dropped = dev->stats.rx_dropped;
> > +	tot->rx_length_errors = dev->stats.rx_length_errors;
> > +	tot->rx_frame_errors = dev->stats.rx_frame_errors;
> > +
> > +	return tot;
> > +}
> > +
> >  #ifdef CONFIG_NET_POLL_CONTROLLER
> >  static void virtnet_netpoll(struct net_device *dev)
> >  {
> > @@ -650,6 +705,14 @@ static void virtnet_netpoll(struct net_d
> >  }
> >  #endif
> >  
> > +static void virtnet_free(struct net_device *dev)
> > +{
> > +	struct virtnet_info *vi = netdev_priv(dev);
> > +
> > +	free_percpu(vi->stats);
> > +	free_netdev(dev);
> > +}
> > +
> >  static int virtnet_open(struct net_device *dev)
> >  {
> >  	struct virtnet_info *vi = netdev_priv(dev);
> > @@ -835,6 +898,7 @@ static const struct net_device_ops virtn
> >  	.ndo_set_mac_address = virtnet_set_mac_address,
> >  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
> >  	.ndo_change_mtu	     = virtnet_change_mtu,
> > +	.ndo_get_stats64     = virtnet_stats,
> >  	.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
> >  	.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
> >  #ifdef CONFIG_NET_POLL_CONTROLLER
> > @@ -895,6 +959,8 @@ static int virtnet_probe(struct virtio_d
> >  	/* Set up network device as normal. */
> >  	dev->netdev_ops = &virtnet_netdev;
> >  	dev->features = NETIF_F_HIGHDMA;
> > +	dev->destructor = virtnet_free;
> > +
> >  	SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
> >  	SET_NETDEV_DEV(dev, &vdev->dev);
> >  
> > @@ -939,6 +1005,11 @@ static int virtnet_probe(struct virtio_d
> >  	vi->vdev = vdev;
> >  	vdev->priv = vi;
> >  	vi->pages = NULL;
> > +	vi->stats = alloc_percpu(struct virtnet_stats);
> > +	err = -ENOMEM;
> > +	if (vi->stats == NULL)
> > +		goto free;
> > +
> >  	INIT_DELAYED_WORK(&vi->refill, refill_work);
> >  	sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg));
> >  	sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg));
> > @@ -958,7 +1029,7 @@ static int virtnet_probe(struct virtio_d
> >  
> >  	err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
> >  	if (err)
> > -		goto free;
> > +		goto free_stats;
> >  
> >  	vi->rvq = vqs[0];
> >  	vi->svq = vqs[1];
> > @@ -1003,6 +1074,8 @@ unregister:
> >  	cancel_delayed_work_sync(&vi->refill);
> >  free_vqs:
> >  	vdev->config->del_vqs(vdev);
> > +free_stats:
> > +	free_percpu(vi->stats);
> >  free:
> >  	free_netdev(dev);
> >  	return err;

Haven't done any performance tests on this.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] virtio-net: per cpu 64 bit stats (v2)
  2011-06-15 16:36   ` [PATCH] virtio-net: per cpu 64 bit stats (v2) Stephen Hemminger
@ 2011-06-17 19:18     ` David Miller
  0 siblings, 0 replies; 6+ messages in thread
From: David Miller @ 2011-06-17 19:18 UTC (permalink / raw)
  To: shemminger; +Cc: eric.dumazet, rusty, mst, virtualization, netdev

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Wed, 15 Jun 2011 12:36:29 -0400

> Use per-cpu variables to maintain 64 bit statistics.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

I'll apply this, thanks.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-06-17 19:18 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-06-15 15:43 [PATCH] virtio-net: per cpu 64 bit stats Stephen Hemminger
2011-06-15 15:58 ` Eric Dumazet
2011-06-15 16:36   ` [PATCH] virtio-net: per cpu 64 bit stats (v2) Stephen Hemminger
2011-06-17 19:18     ` David Miller
2011-06-15 18:33 ` [PATCH] virtio-net: per cpu 64 bit stats Michael S. Tsirkin
2011-06-17 19:13   ` Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).