[PATCH v4 net-next] hv_netvsc: Add per-cpu ethtool stats for netvsc

2018-07-30 Thread Yidong Ren
From: Yidong Ren 

This patch implements following ethtool stats fields for netvsc:
cpu_tx/rx_packets/bytes
cpu_vf_tx/rx_packets/bytes

Corresponding per-cpu counters already exist in current code. Exposing
these counters will help troubleshooting performance issues.

for_each_present_cpu() was used instead of for_each_possible_cpu().
for_each_possible_cpu() would create very long and useless output.
It is still being used for internal buffer, but not for ethtool
output.

There could be an overflow if cpu was added between ethtool
call netvsc_get_sset_count() and netvsc_get_ethtool_stats() and
netvsc_get_strings(). (still safe if cpu was removed)
ethtool makes these three function calls separately.
As long as we use ethtool, I can't see any clean solution.

Currently and in foreseeable short term, Hyper-V doesn't support
cpu hot-plug. Plus, ethtool is for admin use. Unlikely the admin
would perform such combo operations.

Signed-off-by: Yidong Ren 
---
Changes in v2:
  - Remove cpp style comment
  - Resubmit after freeze

Changes in v3:
  - Reimplemented with kvmalloc instead of alloc_percpu

Changes in v4:
  - Fixed inconsistent array size
  - Use kvmalloc_array instead of kvmalloc

 drivers/net/hyperv/hyperv_net.h |  11 
 drivers/net/hyperv/netvsc_drv.c | 106 +++-
 2 files changed, 114 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 4b6e308199d2..a32ded5b4f41 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -873,6 +873,17 @@ struct netvsc_ethtool_stats {
unsigned long wake_queue;
 };
 
+struct netvsc_ethtool_pcpu_stats {
+   u64 rx_packets;
+   u64 rx_bytes;
+   u64 tx_packets;
+   u64 tx_bytes;
+   u64 vf_rx_packets;
+   u64 vf_rx_bytes;
+   u64 vf_tx_packets;
+   u64 vf_tx_bytes;
+};
+
 struct netvsc_vf_pcpu_stats {
u64 rx_packets;
u64 rx_bytes;
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index dd1d6e115145..805388bfbce7 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1118,6 +1118,64 @@ static void netvsc_get_vf_stats(struct net_device *net,
}
 }
 
+static void netvsc_get_pcpu_stats(struct net_device *net,
+ struct netvsc_ethtool_pcpu_stats *pcpu_tot)
+{
+   struct net_device_context *ndev_ctx = netdev_priv(net);
+   struct netvsc_device *nvdev = rcu_dereference_rtnl(ndev_ctx->nvdev);
+   int i;
+
+   /* fetch percpu stats of vf */
+   for_each_possible_cpu(i) {
+   const struct netvsc_vf_pcpu_stats *stats =
+   per_cpu_ptr(ndev_ctx->vf_stats, i);
+   struct netvsc_ethtool_pcpu_stats *this_tot = _tot[i];
+   unsigned int start;
+
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   this_tot->vf_rx_packets = stats->rx_packets;
+   this_tot->vf_tx_packets = stats->tx_packets;
+   this_tot->vf_rx_bytes = stats->rx_bytes;
+   this_tot->vf_tx_bytes = stats->tx_bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+   this_tot->rx_packets = this_tot->vf_rx_packets;
+   this_tot->tx_packets = this_tot->vf_tx_packets;
+   this_tot->rx_bytes   = this_tot->vf_rx_bytes;
+   this_tot->tx_bytes   = this_tot->vf_tx_bytes;
+   }
+
+   /* fetch percpu stats of netvsc */
+   for (i = 0; i < nvdev->num_chn; i++) {
+   const struct netvsc_channel *nvchan = >chan_table[i];
+   const struct netvsc_stats *stats;
+   struct netvsc_ethtool_pcpu_stats *this_tot =
+   _tot[nvchan->channel->target_cpu];
+   u64 packets, bytes;
+   unsigned int start;
+
+   stats = >tx_stats;
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   packets = stats->packets;
+   bytes = stats->bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+
+   this_tot->tx_bytes  += bytes;
+   this_tot->tx_packets+= packets;
+
+   stats = >rx_stats;
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   packets = stats->packets;
+   bytes = stats->bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+
+   this_tot->rx_bytes  += bytes;
+   this_tot->rx_packets+= packets;
+   }
+}
+
 static void netvsc_get_stats64(struct net_device *net,
   s

RE: [PATCH v3] hv_netvsc: Add per-cpu ethtool stats for netvsc

2018-07-25 Thread Yidong Ren
> From: Vitaly Kuznetsov 
> While you do for_each_present_cpu() in netvsc_get_ethtool_stats(),
> netvsc_get_pcpu_stats() does for_each_possible_cpu(). This looks
> inconsistent.

I made a mistake there.  Thanks for catch me.
 
> The allocation you're doing here is short-lived so I would suggest you use
> possible_cpus everywhere. Even knowing there's no CPU hotplug on Hyper-
> V at this moment, it can appear later and we'll get a hard-to-find issue.
> Moreover, we may consider using netvsc driver on e.g. KVM with Hyper-V
> enlightenments and KVM has CPU hotplug already.

That would cause the output to be very long and useless.
I will submit a revision that allocates for num_possible_cpus, but only copy 
out stats for each present cpu.

-Yidong
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


RE: [PATCH v3] hv_netvsc: Add per-cpu ethtool stats for netvsc

2018-07-23 Thread Yidong Ren
> From: Yidong Ren 
> Sent: Monday, July 23, 2018 6:26 PM
> + pcpu_sum = kvmalloc(sizeof(struct netvsc_ethtool_pcpu_stats) *
> + num_present_cpus(), GFP_KERNEL);

Since there is no plan for CPU hotplug in Hyper-V in short term, it is fine 
to use num_present_cpus for now. We can move to debugfs later if necessary.
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH v3] hv_netvsc: Add per-cpu ethtool stats for netvsc

2018-07-23 Thread Yidong Ren
From: Yidong Ren 

This patch implements following ethtool stats fields for netvsc:
cpu_tx/rx_packets/bytes
cpu_vf_tx/rx_packets/bytes

Corresponding per-cpu counters already exist in current code. Exposing
these counters will help troubleshooting performance issues.

Signed-off-by: Yidong Ren 
---
Changes since v2:
 * Reimplemented with kvmalloc instead of alloc_percpu
 drivers/net/hyperv/hyperv_net.h |  11 
 drivers/net/hyperv/netvsc_drv.c | 103 +++-
 2 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 4b6e308199d2..a32ded5b4f41 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -873,6 +873,17 @@ struct netvsc_ethtool_stats {
unsigned long wake_queue;
 };
 
+struct netvsc_ethtool_pcpu_stats {
+   u64 rx_packets;
+   u64 rx_bytes;
+   u64 tx_packets;
+   u64 tx_bytes;
+   u64 vf_rx_packets;
+   u64 vf_rx_bytes;
+   u64 vf_tx_packets;
+   u64 vf_tx_bytes;
+};
+
 struct netvsc_vf_pcpu_stats {
u64 rx_packets;
u64 rx_bytes;
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index dd1d6e115145..51f9cab2da5b 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1118,6 +1118,64 @@ static void netvsc_get_vf_stats(struct net_device *net,
}
 }
 
+static void netvsc_get_pcpu_stats(struct net_device *net,
+ struct netvsc_ethtool_pcpu_stats *pcpu_tot)
+{
+   struct net_device_context *ndev_ctx = netdev_priv(net);
+   struct netvsc_device *nvdev = rcu_dereference_rtnl(ndev_ctx->nvdev);
+   int i;
+
+   /* fetch percpu stats of vf */
+   for_each_possible_cpu(i) {
+   const struct netvsc_vf_pcpu_stats *stats =
+   per_cpu_ptr(ndev_ctx->vf_stats, i);
+   struct netvsc_ethtool_pcpu_stats *this_tot = _tot[i];
+   unsigned int start;
+
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   this_tot->vf_rx_packets = stats->rx_packets;
+   this_tot->vf_tx_packets = stats->tx_packets;
+   this_tot->vf_rx_bytes = stats->rx_bytes;
+   this_tot->vf_tx_bytes = stats->tx_bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+   this_tot->rx_packets = this_tot->vf_rx_packets;
+   this_tot->tx_packets = this_tot->vf_tx_packets;
+   this_tot->rx_bytes   = this_tot->vf_rx_bytes;
+   this_tot->tx_bytes   = this_tot->vf_tx_bytes;
+   }
+
+   /* fetch percpu stats of netvsc */
+   for (i = 0; i < nvdev->num_chn; i++) {
+   const struct netvsc_channel *nvchan = >chan_table[i];
+   const struct netvsc_stats *stats;
+   struct netvsc_ethtool_pcpu_stats *this_tot =
+   _tot[nvchan->channel->target_cpu];
+   u64 packets, bytes;
+   unsigned int start;
+
+   stats = >tx_stats;
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   packets = stats->packets;
+   bytes = stats->bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+
+   this_tot->tx_bytes  += bytes;
+   this_tot->tx_packets+= packets;
+
+   stats = >rx_stats;
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   packets = stats->packets;
+   bytes = stats->bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+
+   this_tot->rx_bytes  += bytes;
+   this_tot->rx_packets+= packets;
+   }
+}
+
 static void netvsc_get_stats64(struct net_device *net,
   struct rtnl_link_stats64 *t)
 {
@@ -1215,6 +1273,23 @@ static const struct {
{ "rx_no_memory", offsetof(struct netvsc_ethtool_stats, rx_no_memory) },
{ "stop_queue", offsetof(struct netvsc_ethtool_stats, stop_queue) },
{ "wake_queue", offsetof(struct netvsc_ethtool_stats, wake_queue) },
+}, pcpu_stats[] = {
+   { "cpu%u_rx_packets",
+   offsetof(struct netvsc_ethtool_pcpu_stats, rx_packets) },
+   { "cpu%u_rx_bytes",
+   offsetof(struct netvsc_ethtool_pcpu_stats, rx_bytes) },
+   { "cpu%u_tx_packets",
+   offsetof(struct netvsc_ethtool_pcpu_stats, tx_packets) },
+   { "cpu%u_tx_bytes",
+   offsetof(struct netvsc_ethtool_pcpu_stats, tx_bytes) },
+   { &

RE: [PATCH v2] hv_netvsc: Add per-cpu ethtool stats for netvsc

2018-06-13 Thread Yidong Ren
> From: devel  On Behalf
> Of Stephen Hemminger
> > +/* statistics per queue (rx/tx packets/bytes) */ #define
> > +NETVSC_PCPU_STATS_LEN (num_present_cpus() *
> ARRAY_SIZE(pcpu_stats))
> 
> Even though Hyper-V/Azure does not support hot plug cpu's it might be
> better to num_cpu_possible to avoid any possible future surprises.

That will create a very long output (num_cpu_possible = 128 on my machine) for 
ethtool,
While doesn't provide additional info.
num_present_cpus() would cause problem only if someone removed cpu 
between netvsc_get_sset_count() and netvsc_get_strings() and 
netvsc_get_ethtool_stats(). 

An alternative way could be: Check all stats, and only output if not zero. 
This need to be done in two pass. First pass to get the correct count, second 
pass to print the number.
Is there an elegant way to do this? 
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


RE: [PATCH v2] hv_netvsc: Add per-cpu ethtool stats for netvsc

2018-06-13 Thread Yidong Ren
> From: Eric Dumazet 
> You actually want to allocate memory local to this cpu, possibly in one chunk,
> not spread all over the places.
> 
> kvmalloc(nr_cpu_ids * sizeof(struct netvsc_ethtool_pcpu_stats))  should be
> really better, since it would most of the time be satisfied by a single 
> kmalloc()

Got it. I'm just trying to allocate memory for each cpu. It doesn't have to be 
__percpu variable.
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH v2] hv_netvsc: Add per-cpu ethtool stats for netvsc

2018-06-13 Thread Yidong Ren
From: Yidong Ren 

This patch implements following ethtool stats fields for netvsc:
cpu_tx/rx_packets/bytes
cpu_vf_tx/rx_packets/bytes

Corresponding per-cpu counters exist in current code. Exposing these
counters will help troubleshooting performance issues.

Signed-off-by: Yidong Ren 
---
Changes in v2:
  - Remove cpp style comment
  - Resubmit after freeze

 drivers/net/hyperv/hyperv_net.h |  11 +
 drivers/net/hyperv/netvsc_drv.c | 104 +++-
 2 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 23304ac..c825353 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -873,6 +873,17 @@ struct netvsc_ethtool_stats {
unsigned long wake_queue;
 };
 
+struct netvsc_ethtool_pcpu_stats {
+   u64 rx_packets;
+   u64 rx_bytes;
+   u64 tx_packets;
+   u64 tx_bytes;
+   u64 vf_rx_packets;
+   u64 vf_rx_bytes;
+   u64 vf_tx_packets;
+   u64 vf_tx_bytes;
+};
+
 struct netvsc_vf_pcpu_stats {
u64 rx_packets;
u64 rx_bytes;
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 7b18a8c..6803aae 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1105,6 +1105,66 @@ static void netvsc_get_vf_stats(struct net_device *net,
}
 }
 
+static void netvsc_get_pcpu_stats(struct net_device *net,
+ struct netvsc_ethtool_pcpu_stats
+   __percpu *pcpu_tot)
+{
+   struct net_device_context *ndev_ctx = netdev_priv(net);
+   struct netvsc_device *nvdev = rcu_dereference_rtnl(ndev_ctx->nvdev);
+   int i;
+
+   /* fetch percpu stats of vf */
+   for_each_possible_cpu(i) {
+   const struct netvsc_vf_pcpu_stats *stats =
+   per_cpu_ptr(ndev_ctx->vf_stats, i);
+   struct netvsc_ethtool_pcpu_stats *this_tot =
+   per_cpu_ptr(pcpu_tot, i);
+   unsigned int start;
+
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   this_tot->vf_rx_packets = stats->rx_packets;
+   this_tot->vf_tx_packets = stats->tx_packets;
+   this_tot->vf_rx_bytes = stats->rx_bytes;
+   this_tot->vf_tx_bytes = stats->tx_bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+   this_tot->rx_packets = this_tot->vf_rx_packets;
+   this_tot->tx_packets = this_tot->vf_tx_packets;
+   this_tot->rx_bytes   = this_tot->vf_rx_bytes;
+   this_tot->tx_bytes   = this_tot->vf_tx_bytes;
+   }
+
+   /* fetch percpu stats of netvsc */
+   for (i = 0; i < nvdev->num_chn; i++) {
+   const struct netvsc_channel *nvchan = >chan_table[i];
+   const struct netvsc_stats *stats;
+   struct netvsc_ethtool_pcpu_stats *this_tot =
+   per_cpu_ptr(pcpu_tot, nvchan->channel->target_cpu);
+   u64 packets, bytes;
+   unsigned int start;
+
+   stats = >tx_stats;
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   packets = stats->packets;
+   bytes = stats->bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+
+   this_tot->tx_bytes  += bytes;
+   this_tot->tx_packets+= packets;
+
+   stats = >rx_stats;
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   packets = stats->packets;
+   bytes = stats->bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+
+   this_tot->rx_bytes  += bytes;
+   this_tot->rx_packets+= packets;
+   }
+}
+
 static void netvsc_get_stats64(struct net_device *net,
   struct rtnl_link_stats64 *t)
 {
@@ -1202,6 +1262,23 @@ static const struct {
{ "rx_no_memory", offsetof(struct netvsc_ethtool_stats, rx_no_memory) },
{ "stop_queue", offsetof(struct netvsc_ethtool_stats, stop_queue) },
{ "wake_queue", offsetof(struct netvsc_ethtool_stats, wake_queue) },
+}, pcpu_stats[] = {
+   { "cpu%u_rx_packets",
+   offsetof(struct netvsc_ethtool_pcpu_stats, rx_packets) },
+   { "cpu%u_rx_bytes",
+   offsetof(struct netvsc_ethtool_pcpu_stats, rx_bytes) },
+   { "cpu%u_tx_packets",
+   offsetof(struct netvsc_ethtool_pcpu_stats, tx_packets) },
+   { "cpu%u_tx_byt

[PATCH] hv_netvsc: Add per-cpu ethtool stats for netvsc

2018-06-06 Thread Yidong Ren
From: Yidong Ren 

This patch implements following ethtool stats fields for netvsc:
cpu_tx/rx_packets/bytes
cpu_vf_tx/rx_packets/bytes

Corresponding per-cpu counters exist in current code. Exposing these
counters will help troubleshooting performance issues.

Signed-off-by: Yidong Ren 
---
 drivers/net/hyperv/hyperv_net.h |  11 
 drivers/net/hyperv/netvsc_drv.c | 104 +++-
 2 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 960f06141472..f8c798bf9418 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -710,6 +710,17 @@ struct netvsc_ethtool_stats {
unsigned long wake_queue;
 };
 
+struct netvsc_ethtool_pcpu_stats {
+   u64 rx_packets;
+   u64 rx_bytes;
+   u64 tx_packets;
+   u64 tx_bytes;
+   u64 vf_rx_packets;
+   u64 vf_rx_bytes;
+   u64 vf_tx_packets;
+   u64 vf_tx_bytes;
+};
+
 struct netvsc_vf_pcpu_stats {
u64 rx_packets;
u64 rx_bytes;
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index da07ccdf84bf..c43e64606c1a 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1104,6 +1104,66 @@ static void netvsc_get_vf_stats(struct net_device *net,
}
 }
 
+static void netvsc_get_pcpu_stats(struct net_device *net,
+ struct netvsc_ethtool_pcpu_stats
+   __percpu *pcpu_tot)
+{
+   struct net_device_context *ndev_ctx = netdev_priv(net);
+   struct netvsc_device *nvdev = rcu_dereference_rtnl(ndev_ctx->nvdev);
+   int i;
+
+   // fetch percpu stats of vf
+   for_each_possible_cpu(i) {
+   const struct netvsc_vf_pcpu_stats *stats =
+   per_cpu_ptr(ndev_ctx->vf_stats, i);
+   struct netvsc_ethtool_pcpu_stats *this_tot =
+   per_cpu_ptr(pcpu_tot, i);
+   unsigned int start;
+
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   this_tot->vf_rx_packets = stats->rx_packets;
+   this_tot->vf_tx_packets = stats->tx_packets;
+   this_tot->vf_rx_bytes = stats->rx_bytes;
+   this_tot->vf_tx_bytes = stats->tx_bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+   this_tot->rx_packets = this_tot->vf_rx_packets;
+   this_tot->tx_packets = this_tot->vf_tx_packets;
+   this_tot->rx_bytes   = this_tot->vf_rx_bytes;
+   this_tot->tx_bytes   = this_tot->vf_tx_bytes;
+   }
+
+   // fetch percpu stats of netvsc
+   for (i = 0; i < nvdev->num_chn; i++) {
+   const struct netvsc_channel *nvchan = >chan_table[i];
+   const struct netvsc_stats *stats;
+   struct netvsc_ethtool_pcpu_stats *this_tot =
+   per_cpu_ptr(pcpu_tot, nvchan->channel->target_cpu);
+   u64 packets, bytes;
+   unsigned int start;
+
+   stats = >tx_stats;
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   packets = stats->packets;
+   bytes = stats->bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+
+   this_tot->tx_bytes  += bytes;
+   this_tot->tx_packets+= packets;
+
+   stats = >rx_stats;
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   packets = stats->packets;
+   bytes = stats->bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+
+   this_tot->rx_bytes  += bytes;
+   this_tot->rx_packets+= packets;
+   }
+}
+
 static void netvsc_get_stats64(struct net_device *net,
   struct rtnl_link_stats64 *t)
 {
@@ -1201,6 +1261,23 @@ static const struct {
{ "rx_no_memory", offsetof(struct netvsc_ethtool_stats, rx_no_memory) },
{ "stop_queue", offsetof(struct netvsc_ethtool_stats, stop_queue) },
{ "wake_queue", offsetof(struct netvsc_ethtool_stats, wake_queue) },
+}, pcpu_stats[] = {
+   { "cpu%u_rx_packets",
+   offsetof(struct netvsc_ethtool_pcpu_stats, rx_packets) },
+   { "cpu%u_rx_bytes",
+   offsetof(struct netvsc_ethtool_pcpu_stats, rx_bytes) },
+   { "cpu%u_tx_packets",
+   offsetof(struct netvsc_ethtool_pcpu_stats, tx_packets) },
+   { "cpu%u_tx_bytes",
+   offsetof(struct netvsc_ethtool_pcpu_stats

RE: [PATCH] hv_netvsc: add per-cpu ethtool stats for netvsc

2018-06-06 Thread Yidong Ren
Thank you, Greg. I'm sorry for didn't read the guidelines on kernel newbies. 
Please ignore this patch. 

Thanks,
Yidong

-Original Message-
From: Greg KH  
Sent: Wednesday, June 6, 2018 1:34 AM
To: Yidong Ren 
Cc: driverdev-devel@linuxdriverproject.org; Haiyang Zhang 
; Stephen Hemminger ; Madhan 
Sivakumar 
Subject: Re: [PATCH] hv_netvsc: add per-cpu ethtool stats for netvsc

On Tue, Jun 05, 2018 at 08:14:06PM +, Yidong Ren wrote:
> This patch implements following ethtool stats fields for netvsc:
> cpu_rx_packets
> cpu_tx_packets
> cpu_rx_bytes
> cpu_tx_bytes
> cpu_vf_rx_packets
> cpu_vf_tx_packets
> cpu_vf_rx_bytes
> cpu_vf_tx_bytes
> ---

No signed-off-by line?  Always use scripts/checkpatch.pl on your patches os you 
do not get grumpy kernel maintainers telling you to run checkpatch.pl on your 
patches...

greg k-h
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH] hv_netvsc: add per-cpu ethtool stats for netvsc

2018-06-05 Thread Yidong Ren
This patch implements following ethtool stats fields for netvsc:
cpu_rx_packets
cpu_tx_packets
cpu_rx_bytes
cpu_tx_bytes
cpu_vf_rx_packets
cpu_vf_tx_packets
cpu_vf_rx_bytes
cpu_vf_tx_bytes
---
 drivers/net/hyperv/hyperv_net.h | 11 +
 drivers/net/hyperv/netvsc_drv.c | 95 -
 2 files changed, 104 insertions(+), 2 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 960f061..f8c798b 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -710,6 +710,17 @@ struct netvsc_ethtool_stats {
unsigned long wake_queue;
 };
 
+struct netvsc_ethtool_pcpu_stats {
+   u64 rx_packets;
+   u64 rx_bytes;
+   u64 tx_packets;
+   u64 tx_bytes;
+   u64 vf_rx_packets;
+   u64 vf_rx_bytes;
+   u64 vf_tx_packets;
+   u64 vf_tx_bytes;
+};
+
 struct netvsc_vf_pcpu_stats {
u64 rx_packets;
u64 rx_bytes;
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index da07ccd..ef6ea1d 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1104,6 +1104,66 @@ static void netvsc_get_vf_stats(struct net_device *net,
}
 }
 
+static void netvsc_get_pcpu_stats(struct net_device *net,
+  struct netvsc_ethtool_pcpu_stats __percpu 
*pcpu_tot)
+{
+   struct net_device_context *ndev_ctx = netdev_priv(net);
+   struct netvsc_device *nvdev = rcu_dereference_rtnl(ndev_ctx->nvdev);
+   int i;
+
+   // fetch percpu stats of vf
+   for_each_possible_cpu(i) {
+   const struct netvsc_vf_pcpu_stats *stats
+= per_cpu_ptr(ndev_ctx->vf_stats, i);
+   struct netvsc_ethtool_pcpu_stats *this_tot
+   = per_cpu_ptr(pcpu_tot, i);
+   unsigned int start;
+
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   this_tot->vf_rx_packets = stats->rx_packets;
+   this_tot->vf_tx_packets = stats->tx_packets;
+   this_tot->vf_rx_bytes = stats->rx_bytes;
+   this_tot->vf_tx_bytes = stats->tx_bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+   this_tot->rx_packets = this_tot->vf_rx_packets;
+   this_tot->tx_packets = this_tot->vf_tx_packets;
+   this_tot->rx_bytes   = this_tot->vf_rx_bytes;
+   this_tot->tx_bytes   = this_tot->vf_tx_bytes;
+   }
+
+   // fetch percpu stats of netvsc
+   for (i = 0; i < nvdev->num_chn; i++) {
+   const struct netvsc_channel *nvchan = >chan_table[i];
+   const struct netvsc_stats *stats;
+   struct netvsc_ethtool_pcpu_stats *this_tot
+   = per_cpu_ptr(pcpu_tot, nvchan->channel->target_cpu);
+   u64 packets, bytes;
+   unsigned int start;
+
+
+   stats = >tx_stats;
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   packets = stats->packets;
+   bytes = stats->bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+
+   this_tot->tx_bytes  += bytes;
+   this_tot->tx_packets+= packets;
+
+   stats = >rx_stats;
+   do {
+   start = u64_stats_fetch_begin_irq(>syncp);
+   packets = stats->packets;
+   bytes = stats->bytes;
+   } while (u64_stats_fetch_retry_irq(>syncp, start));
+
+   this_tot->rx_bytes  += bytes;
+   this_tot->rx_packets+= packets;
+   }
+}
+
 static void netvsc_get_stats64(struct net_device *net,
   struct rtnl_link_stats64 *t)
 {
@@ -1201,6 +1261,15 @@ static const struct {
{ "rx_no_memory", offsetof(struct netvsc_ethtool_stats, rx_no_memory) },
{ "stop_queue", offsetof(struct netvsc_ethtool_stats, stop_queue) },
{ "wake_queue", offsetof(struct netvsc_ethtool_stats, wake_queue) },
+}, pcpu_stats[] = {
+   { "cpu%u_rx_packets", offsetof(struct netvsc_ethtool_pcpu_stats, 
rx_packets) },
+   { "cpu%u_rx_bytes",   offsetof(struct netvsc_ethtool_pcpu_stats, 
rx_bytes) },
+   { "cpu%u_tx_packets", offsetof(struct netvsc_ethtool_pcpu_stats, 
tx_packets) },
+   { "cpu%u_tx_bytes",   offsetof(struct netvsc_ethtool_pcpu_stats, 
tx_bytes) },
+   { "cpu%u_vf_rx_packets", offsetof(struct netvsc_ethtool_pcpu_stats, 
vf_rx_packets) },
+   { "cpu%u_vf_rx_bytes",   offsetof(struct netvsc_ethtool_pcpu_stats, 
vf_rx_bytes) },
+   { "cpu%u_vf_tx_packets", offsetof(struct netvsc_ethtool_pcpu_stats, 
vf_tx_packets) },
+   { "cpu%u_vf_tx_bytes",   offsetof(struct netvsc_ethtool_pcpu_stats, 
vf_tx_bytes) },
 }, vf_stats[]