On Wed,  6 Jun 2018 15:27:00 -0700
Yidong Ren <yid...@linuxonhyperv.com> wrote:

> From: Yidong Ren <yid...@microsoft.com>
> 
> This patch implements following ethtool stats fields for netvsc:
> cpu<n>_tx/rx_packets/bytes
> cpu<n>_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 <yid...@microsoft.com>

This patch would be targeted for net-next (davem's tree);
but net-next is currently closed until 4.19-rc1 is done.

> ---
>  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

If you ran checkpatch you would see that Linux always uses C style
comments, and not C++ style //

> +     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(&stats->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(&stats->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 = &nvdev->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 = &nvchan->tx_stats;
> +             do {
> +                     start = u64_stats_fetch_begin_irq(&stats->syncp);
> +                     packets = stats->packets;
> +                     bytes = stats->bytes;
> +             } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
> +
> +             this_tot->tx_bytes      += bytes;
> +             this_tot->tx_packets    += packets;
> +
> +             stats = &nvchan->rx_stats;
> +             do {
> +                     start = u64_stats_fetch_begin_irq(&stats->syncp);
> +                     packets = stats->packets;
> +                     bytes = stats->bytes;
> +             } while (u64_stats_fetch_retry_irq(&stats->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, 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[] = {
>       { "vf_rx_packets", offsetof(struct netvsc_vf_pcpu_stats, rx_packets) },
>       { "vf_rx_bytes",   offsetof(struct netvsc_vf_pcpu_stats, rx_bytes) },
> @@ -1212,6 +1289,9 @@ static const struct {
>  #define NETVSC_GLOBAL_STATS_LEN      ARRAY_SIZE(netvsc_stats)
>  #define NETVSC_VF_STATS_LEN  ARRAY_SIZE(vf_stats)
>  
> +/* statistics per queue (rx/tx packets/bytes) */
> +#define NETVSC_PCPU_STATS_LEN (num_present_cpus() * ARRAY_SIZE(pcpu_stats))
> +
>  /* 4 statistics per queue (rx/tx packets/bytes) */
>  #define NETVSC_QUEUE_STATS_LEN(dev) ((dev)->num_chn * 4)
>  
> @@ -1227,6 +1307,7 @@ static int netvsc_get_sset_count(struct net_device 
> *dev, int string_set)
>       case ETH_SS_STATS:
>               return NETVSC_GLOBAL_STATS_LEN
>                       + NETVSC_VF_STATS_LEN
> +                     + NETVSC_PCPU_STATS_LEN
>                       + NETVSC_QUEUE_STATS_LEN(nvdev);
>       default:
>               return -EINVAL;
> @@ -1241,9 +1322,10 @@ static void netvsc_get_ethtool_stats(struct net_device 
> *dev,
>       const void *nds = &ndc->eth_stats;
>       const struct netvsc_stats *qstats;
>       struct netvsc_vf_pcpu_stats sum;
> +     struct netvsc_ethtool_pcpu_stats __percpu *pcpu_sum;
>       unsigned int start;
>       u64 packets, bytes;
> -     int i, j;
> +     int i, j, cpu;
>  
>       if (!nvdev)
>               return;
> @@ -1255,6 +1337,17 @@ static void netvsc_get_ethtool_stats(struct net_device 
> *dev,
>       for (j = 0; j < NETVSC_VF_STATS_LEN; j++)
>               data[i++] = *(u64 *)((void *)&sum + vf_stats[j].offset);
>  
> +     pcpu_sum = alloc_percpu(struct netvsc_ethtool_pcpu_stats);
> +     netvsc_get_pcpu_stats(dev, pcpu_sum);
> +     for_each_present_cpu(cpu) {
> +             struct netvsc_ethtool_pcpu_stats *this_sum =
> +                     per_cpu_ptr(pcpu_sum, cpu);
> +             for (j = 0; j < ARRAY_SIZE(pcpu_stats); j++)
> +                     data[i++] = *(u64 *)((void *)this_sum
> +                                          + pcpu_stats[j].offset);
> +     }
> +     free_percpu(pcpu_sum);
> +
>       for (j = 0; j < nvdev->num_chn; j++) {
>               qstats = &nvdev->chan_table[j].tx_stats;
>  
> @@ -1282,7 +1375,7 @@ static void netvsc_get_strings(struct net_device *dev, 
> u32 stringset, u8 *data)
>       struct net_device_context *ndc = netdev_priv(dev);
>       struct netvsc_device *nvdev = rtnl_dereference(ndc->nvdev);
>       u8 *p = data;
> -     int i;
> +     int i, cpu;
>  
>       if (!nvdev)
>               return;
> @@ -1299,6 +1392,13 @@ static void netvsc_get_strings(struct net_device *dev, 
> u32 stringset, u8 *data)
>                       p += ETH_GSTRING_LEN;
>               }
>  
> +             for_each_present_cpu(cpu) {
> +                     for (i = 0; i < ARRAY_SIZE(pcpu_stats); i++) {
> +                             sprintf(p, pcpu_stats[i].name, cpu);
> +                             p += ETH_GSTRING_LEN;
> +                     }
> +             }
> +
>               for (i = 0; i < nvdev->num_chn; i++) {
>                       sprintf(p, "tx_queue_%u_packets", i);
>                       p += ETH_GSTRING_LEN;

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

Reply via email to