* [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).