Hi Maxime, > -----Original Message----- > From: Maxime Coquelin <maxime.coque...@redhat.com> > Sent: Thursday, January 27, 2022 10:57 PM > To: dev@dpdk.org; Xia, Chenbo <chenbo....@intel.com>; > david.march...@redhat.com > Cc: Maxime Coquelin <maxime.coque...@redhat.com> > Subject: [PATCH 2/5] vhost: add per-virtqueue statistics support > > This patch introduces new APIs for the application > to query and reset per-virtqueue statistics. The > patch also introduces generic counters. > > Signed-off-by: Maxime Coquelin <maxime.coque...@redhat.com> > --- > lib/vhost/rte_vhost.h | 89 +++++++++++++++++++++++++++++++++ > lib/vhost/socket.c | 4 +- > lib/vhost/version.map | 5 ++ > lib/vhost/vhost.c | 109 ++++++++++++++++++++++++++++++++++++++++- > lib/vhost/vhost.h | 18 ++++++- > lib/vhost/virtio_net.c | 53 ++++++++++++++++++++ > 6 files changed, 274 insertions(+), 4 deletions(-) > > diff --git a/lib/vhost/rte_vhost.h b/lib/vhost/rte_vhost.h > index b454c05868..e739091ca0 100644 > --- a/lib/vhost/rte_vhost.h > +++ b/lib/vhost/rte_vhost.h > @@ -37,6 +37,7 @@ extern "C" { > #define RTE_VHOST_USER_LINEARBUF_SUPPORT (1ULL << 6) > #define RTE_VHOST_USER_ASYNC_COPY (1ULL << 7) > #define RTE_VHOST_USER_NET_COMPLIANT_OL_FLAGS (1ULL << 8) > +#define RTE_VHOST_USER_NET_STATS_ENABLE (1ULL << 9) > > /* Features. */ > #ifndef VIRTIO_NET_F_GUEST_ANNOUNCE > @@ -317,6 +318,32 @@ struct rte_vhost_power_monitor_cond { > uint8_t match; > }; > > +/** Maximum name length for the statistics counters */ > +#define RTE_VHOST_STATS_NAME_SIZE 64 > + > +/** > + * Vhost virtqueue statistics structure > + * > + * This structure is used by rte_vhost_vring_stats_get() to provide > + * virtqueue statistics to the calling application. > + * It maps a name ID, corresponding to an index in the array returned > + * by rte_vhost_vring_stats_get_names(), to a statistic value. > + */ > +struct rte_vhost_stat { > + uint64_t id; /**< The index in xstats name array. */ > + uint64_t value; /**< The statistic counter value. */ > +}; > + > +/** > + * Vhost virtqueue statistic name element > + * > + * This structure is used by rte_vhost_vring_stats_get_anmes() to
Anmes -> names > + * provide virtqueue statistics names to the calling application. > + */ > +struct rte_vhost_stat_name { > + char name[RTE_VHOST_STATS_NAME_SIZE]; /**< The statistic name. */ Should we consider using ethdev one? Since vhost lib already depends on ethdev lib. > +}; > + > /** > * Convert guest physical address to host virtual address > * > @@ -1059,6 +1086,68 @@ __rte_experimental > int > rte_vhost_slave_config_change(int vid, bool need_reply); > > +/** > + * Retrieve names of statistics of a Vhost virtqueue. > + * > + * There is an assumption that 'stat_names' and 'stats' arrays are > matched > + * by array index: stats_names[i].name => stats[i].value > + * > + * @param vid > + * vhost device ID > + * @param queue_id > + * vhost queue index > + * @param stats_names > + * array of at least size elements to be filled. > + * If set to NULL, the function returns the required number of elements. > + * @param size > + * The number of elements in stats_names array. > + * @return > + * A negative value on error, otherwise the number of entries filled in > the > + * stats name array. > + */ > +__rte_experimental > +int > +rte_vhost_vring_stats_get_names(int vid, uint16_t queue_id, > + struct rte_vhost_stat_name *name, unsigned int size); '@param stats_names' and 'struct rte_vhost_stat_name *name' do not align and reports error: http://mails.dpdk.org/archives/test-report/2022-March/270275.html > + > +/** > + * Retrieve statistics of a Vhost virtqueue. > + * > + * There is an assumption that 'stat_names' and 'stats' arrays are > matched > + * by array index: stats_names[i].name => stats[i].value > + * > + * @param vid > + * vhost device ID > + * @param queue_id > + * vhost queue index > + * @param stats > + * A pointer to a table of structure of type rte_vhost_stat to be > filled with > + * virtqueue statistics ids and values. > + * @param n > + * The number of elements in stats array. > + * @return > + * A negative value on error, otherwise the number of entries filled in > the > + * stats table. > + */ > +__rte_experimental > +int > +rte_vhost_vring_stats_get(int vid, uint16_t queue_id, > + struct rte_vhost_stat *stats, unsigned int n); > + > +/** > + * Reset statistics of a Vhost virtqueue. > + * > + * @param vid > + * vhost device ID > + * @param queue_id > + * vhost queue index > + * @return > + * 0 on success, a negative value on error. > + */ > +__rte_experimental > +int > +rte_vhost_vring_stats_reset(int vid, uint16_t queue_id); > + > #ifdef __cplusplus > } > #endif > diff --git a/lib/vhost/socket.c b/lib/vhost/socket.c > index c2f8013cd5..6020565fb6 100644 > --- a/lib/vhost/socket.c > +++ b/lib/vhost/socket.c > @@ -43,6 +43,7 @@ struct vhost_user_socket { > bool linearbuf; > bool async_copy; > bool net_compliant_ol_flags; > + bool stats_enabled; > > /* > * The "supported_features" indicates the feature bits the > @@ -228,7 +229,7 @@ vhost_user_add_connection(int fd, struct > vhost_user_socket *vsocket) > vhost_set_ifname(vid, vsocket->path, size); > > vhost_setup_virtio_net(vid, vsocket->use_builtin_virtio_net, > - vsocket->net_compliant_ol_flags); > + vsocket->net_compliant_ol_flags, vsocket->stats_enabled); > > vhost_attach_vdpa_device(vid, vsocket->vdpa_dev); > > @@ -864,6 +865,7 @@ rte_vhost_driver_register(const char *path, uint64_t > flags) > vsocket->linearbuf = flags & RTE_VHOST_USER_LINEARBUF_SUPPORT; > vsocket->async_copy = flags & RTE_VHOST_USER_ASYNC_COPY; > vsocket->net_compliant_ol_flags = flags & > RTE_VHOST_USER_NET_COMPLIANT_OL_FLAGS; > + vsocket->stats_enabled = flags & RTE_VHOST_USER_NET_STATS_ENABLE; > > if (vsocket->async_copy && > (flags & (RTE_VHOST_USER_IOMMU_SUPPORT | > diff --git a/lib/vhost/version.map b/lib/vhost/version.map > index a7ef7f1976..b83f79c87f 100644 > --- a/lib/vhost/version.map > +++ b/lib/vhost/version.map > @@ -84,6 +84,11 @@ EXPERIMENTAL { > > # added in 21.11 > rte_vhost_get_monitor_addr; > + > + # added in 22.03 > + rte_vhost_vring_stats_get_names; > + rte_vhost_vring_stats_get; > + rte_vhost_vring_stats_reset; > }; > > INTERNAL { > diff --git a/lib/vhost/vhost.c b/lib/vhost/vhost.c > index 42c01abf25..0c6a737aca 100644 > --- a/lib/vhost/vhost.c > +++ b/lib/vhost/vhost.c > @@ -28,6 +28,28 @@ > struct virtio_net *vhost_devices[MAX_VHOST_DEVICE]; > pthread_mutex_t vhost_dev_lock = PTHREAD_MUTEX_INITIALIZER; > > +struct vhost_vq_stats_name_off { > + char name[RTE_VHOST_STATS_NAME_SIZE]; > + unsigned int offset; > +}; > + > +static const struct vhost_vq_stats_name_off vhost_vq_stat_strings[] = { > + {"good_packets", offsetof(struct vhost_virtqueue, > stats.packets)}, > + {"good_bytes", offsetof(struct vhost_virtqueue, > stats.bytes)}, > + {"multicast_packets", offsetof(struct vhost_virtqueue, > stats.multicast)}, > + {"broadcast_packets", offsetof(struct vhost_virtqueue, > stats.broadcast)}, > + {"undersize_packets", offsetof(struct vhost_virtqueue, > stats.size_bins[0])}, > + {"size_64_packets", offsetof(struct vhost_virtqueue, > stats.size_bins[1])}, > + {"size_65_127_packets", offsetof(struct vhost_virtqueue, > stats.size_bins[2])}, > + {"size_128_255_packets", offsetof(struct vhost_virtqueue, > stats.size_bins[3])}, > + {"size_256_511_packets", offsetof(struct vhost_virtqueue, > stats.size_bins[4])}, > + {"size_512_1023_packets", offsetof(struct vhost_virtqueue, > stats.size_bins[5])}, > + {"size_1024_1518_packets", offsetof(struct vhost_virtqueue, > stats.size_bins[6])}, > + {"size_1519_max_packets", offsetof(struct vhost_virtqueue, > stats.size_bins[7])}, > +}; > + > +#define VHOST_NB_VQ_STATS RTE_DIM(vhost_vq_stat_strings) > + > /* Called with iotlb_lock read-locked */ > uint64_t > __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq, > @@ -758,7 +780,7 @@ vhost_set_ifname(int vid, const char *if_name, > unsigned int if_len) > } > > void > -vhost_setup_virtio_net(int vid, bool enable, bool compliant_ol_flags) > +vhost_setup_virtio_net(int vid, bool enable, bool compliant_ol_flags, > bool stats_enabled) > { > struct virtio_net *dev = get_device(vid); > > @@ -773,6 +795,10 @@ vhost_setup_virtio_net(int vid, bool enable, bool > compliant_ol_flags) > dev->flags |= VIRTIO_DEV_LEGACY_OL_FLAGS; > else > dev->flags &= ~VIRTIO_DEV_LEGACY_OL_FLAGS; > + if (stats_enabled) > + dev->flags |= VIRTIO_DEV_STATS_ENABLED; > + else > + dev->flags &= ~VIRTIO_DEV_STATS_ENABLED; > } > > void > @@ -1908,5 +1934,86 @@ rte_vhost_get_monitor_addr(int vid, uint16_t > queue_id, > return 0; > } > > + > +int > +rte_vhost_vring_stats_get_names(int vid, uint16_t queue_id, > + struct rte_vhost_stat_name *name, unsigned int size) > +{ > + struct virtio_net *dev = get_device(vid); > + unsigned int i; > + > + if (dev == NULL) > + return -1; > + > + if (queue_id >= dev->nr_vring) > + return -1; > + > + if (!(dev->flags & VIRTIO_DEV_STATS_ENABLED)) > + return -1; > + > + if (name == NULL || size < VHOST_NB_VQ_STATS) > + return VHOST_NB_VQ_STATS; > + > + for (i = 0; i < VHOST_NB_VQ_STATS; i++) > + snprintf(name[i].name, sizeof(name[i].name), "%s_q%u_%s", > + (queue_id & 1) ? "rx" : "tx", > + queue_id / 2, vhost_vq_stat_strings[i].name); > + > + return VHOST_NB_VQ_STATS; > +} > + > +int > +rte_vhost_vring_stats_get(int vid, uint16_t queue_id, > + struct rte_vhost_stat *stats, unsigned int n) > +{ > + struct virtio_net *dev = get_device(vid); > + struct vhost_virtqueue *vq; > + unsigned int i; > + > + if (dev == NULL) > + return -1; > + > + if (queue_id >= dev->nr_vring) > + return -1; > + > + if (!(dev->flags & VIRTIO_DEV_STATS_ENABLED)) > + return -1; > + > + if (stats == NULL || n < VHOST_NB_VQ_STATS) > + return VHOST_NB_VQ_STATS; > + > + vq = dev->virtqueue[queue_id]; > + > + rte_spinlock_lock(&vq->access_lock); > + for (i = 0; i < VHOST_NB_VQ_STATS; i++) { > + stats[i].value = > + *(uint64_t *)(((char *)vq) + > vhost_vq_stat_strings[i].offset); > + stats[i].id = i; > + } > + rte_spinlock_unlock(&vq->access_lock); > + > + return VHOST_NB_VQ_STATS; > +} > + > +int rte_vhost_vring_stats_reset(int vid, uint16_t queue_id) > +{ > + struct virtio_net *dev = get_device(vid); > + struct vhost_virtqueue *vq; > + > + if (dev == NULL) > + return -1; > + > + if (queue_id >= dev->nr_vring) > + return -1; > + Guess you forgot to check VIRTIO_DEV_STATS_ENABLED? > + vq = dev->virtqueue[queue_id]; > + > + rte_spinlock_lock(&vq->access_lock); > + memset(&vq->stats, 0, sizeof(vq->stats)); > + rte_spinlock_unlock(&vq->access_lock); > + > + return 0; > +} > + > RTE_LOG_REGISTER_SUFFIX(vhost_config_log_level, config, INFO); > RTE_LOG_REGISTER_SUFFIX(vhost_data_log_level, data, WARNING); > diff --git a/lib/vhost/vhost.h b/lib/vhost/vhost.h > index 7085e0885c..4c151244c7 100644 > --- a/lib/vhost/vhost.h > +++ b/lib/vhost/vhost.h > @@ -38,6 +38,8 @@ > #define VIRTIO_DEV_FEATURES_FAILED ((uint32_t)1 << 4) > /* Used to indicate that the virtio_net tx code should fill TX ol_flags > */ > #define VIRTIO_DEV_LEGACY_OL_FLAGS ((uint32_t)1 << 5) > +/* Used to indicate the application has requested statistics collection Should be only one space between '/*' and 'Used' :P Thanks, Chenbo