Add usage counter helpers
Subsystems (2)
cover Add usage counter helpers
There is a recurring pattern in DPDK code: on first use, do something, on last use, undo something. In a lot of cases, these reference counters are atomic or otherwise thread-safe, but in cases where they're not, we use raw integers and do manual checks and counter updates instead.
This patchset attempts to provide a really minimal "usage counter" library that does *only* that: track usage of resources. The patchset does not do a full DPDK conversion to these counters, but it does convert a few things to demonstrate what it would look like if we had them.
Anatoly Burakov (8):
eal: add usage count helpers
vfio: use usage counters
dev: replace raw refcount with usage count
vhost: use usage counters for vchan tracking
acl: use usage counters for ref counting
thash: use usage counters for ref counting
lpm: use usage counters for ref counting
net/nbl: track devices with usage counters
doc/api/doxy-api-index.md | 1 + drivers/net/nbl/nbl_common/nbl_userdev.c | 22 +++--- lib/acl/acl.h | 4 +- lib/acl/acl_bld.c | 9 +-- lib/eal/include/meson.build | 1 + lib/eal/include/rte_usage_count.h | 96 ++++++++++++++++++++++++ lib/eal/linux/eal_dev.c | 20 +++-- lib/eal/linux/eal_vfio.c | 7 +- lib/eal/linux/eal_vfio.h | 5 +- lib/eal/linux/eal_vfio_group.c | 11 +-- lib/hash/rte_thash.c | 10 +-- lib/lpm/rte_lpm6.c | 13 ++-- lib/vhost/vhost.c | 5 +- lib/vhost/vhost.h | 3 +- 14 files changed, 151 insertions(+), 56 deletions(-) create mode 100644 lib/eal/include/rte_usage_count.h
Signature · 1 line
2.52.0
RFC PATCH 1/8 eal: add usage count helpers
In writing DPDK code, one of the often-seen pattern is counting usage of resources - programming a HW block on first/last flow rule, or even just tracking references to software structures. In a lot of cases, a simple usage count is not a good fit because of atomicity/thread safety requirements, but for trivial/already synchronized cases it can be useful.
Add a "usage count" library to EAL to enable such use cases.
--- doc/api/doxy-api-index.md | 1 + lib/eal/include/meson.build | 1 + lib/eal/include/rte_usage_count.h | 96 +++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 lib/eal/include/rte_usage_count.h
doc/api/doxy-api-index.md +1 -0
@@ -177,6 +177,7 @@ The public API headers are grouped by topics: [soring](@ref rte_soring.h), [stack](@ref rte_stack.h), [tailq](@ref rte_tailq.h), + [usage count](@ref rte_usage_count.h), [bitset](@ref rte_bitset.h), [bitmap](@ref rte_bitmap.h)
lib/eal/include/meson.build +1 -0
@@ -53,6 +53,7 @@ headers += files( 'rte_trace.h', 'rte_trace_point.h', 'rte_trace_point_register.h', + 'rte_usage_count.h', 'rte_uuid.h', 'rte_version.h', )
lib/eal/include/rte_usage_count.h new file +96 -0
96 lines not on this page · raw message
Signature · 1 line
2.52.0
RFC PATCH 2/8 vfio: use usage counters
In reply to Anatoly BurakovCurrently, resources in VFIO (such as groups or devices) are tracked for first/last usage due to things needing to happen on first/last reference. Use EAL usage counters instead of manual arithmetic and checks.
--- lib/eal/linux/eal_vfio.c | 7 ++----- lib/eal/linux/eal_vfio.h | 5 +++-- lib/eal/linux/eal_vfio_group.c | 11 ++++------- 3 files changed, 9 insertions(+), 14 deletions(-)
lib/eal/linux/eal_vfio.c +2 -5
@@ -1125,11 +1125,8 @@ dev_vfio_release_device(const char *sysfs_base __rte_unused, const char *dev_add/* close device handle */ vfio_device_erase (cfg, dev); -/* remove device from group */ - grp->n_devices--; - -/* was this the last device? */ -if (grp->n_devices ==0 ) +/* remove device from group, erase the group if it was the last device */ +if (rte_usage_count_release (&grp->n_devices))vfio_group_erase (cfg, grp);/* if no more groups left, remove callback */
lib/eal/linux/eal_vfio.h +3 -2
@@ -7,6 +7,7 @@#include <rte_common.h> #include <rte_spinlock.h> +#include <rte_usage_count.h> #include <stdint.h>
@@ -42,7 +43,7 @@ struct vfio_group {bool active;int group_num;int fd; -int n_devices; +rte_usage_count_t n_devices; };/* device tracking (common for group and cdev modes) */
@@ -66,7 +67,7 @@ struct vfio_device {struct vfio_group_config {bool iommu_type_set;bool mem_event_clb_set; -size_t n_groups; +rte_usage_count_t n_groups;struct vfio_group groups[RTE_MAX_VFIO_GROUPS ]; };
lib/eal/linux/eal_vfio_group.c +4 -7
@@ -508,7 +508,7 @@ vfio_group_create(struct vfio_container *cfg, int iommu_group) VFIO_GROUP_FOREACH(cfg, grp) {if (grp->active)continue ; - cfg->group_cfg.n_groups++; +rte_usage_count_claim (&cfg->group_cfg.n_groups); grp->active = true; grp->group_num = iommu_group; grp->fd =-1 ;
@@ -527,10 +527,8 @@ vfio_group_erase(struct vfio_container *cfg, struct vfio_group *grp)EAL_LOG (ERR ,"Error when closing group fd %d" , grp->fd); *grp = (struct vfio_group ){0 }; - group_cfg->n_groups--; - -/* if this was the last group in config, erase IOMMU setup and unregister callback */ -if (group_cfg->n_groups ==0 ) { +/* if this was the last group in config, erase IOMMU setup */ +if (rte_usage_count_release (&group_cfg->n_groups)) { cfg->dma_setup_done = false; group_cfg->iommu_type_set = false; }
@@ -880,8 +878,7 @@ vfio_group_setup_device_fd(const char *dev_addr, struct vfio_group *grp, struct dev->fd = fd;/* store backreference to group */ dev->group = grp->group_num; -/* increment number of devices in group */ - grp->n_devices++; +rte_usage_count_claim (&grp->n_devices);return 0 ; }
Signature · 1 line
2.52.0
RFC PATCH 3/8 dev: replace raw refcount with usage count
In reply to Anatoly BurakovUse EAL usage counter to track number of dev monitors.
--- lib/eal/linux/eal_dev.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-)
lib/eal/linux/eal_dev.c +9 -11
@@ -17,13 +17,14 @@#include <bus_driver.h> #include <rte_spinlock.h> #include <rte_errno.h> +#include <rte_usage_count.h> #include <eal_export.h> #include "eal_private.h" static struct rte_intr_handle *intr_handle;static rte_rwlock_t monitor_lock =RTE_RWLOCK_INITIALIZER ; -static uint32_t monitor_refcount; +static rte_usage_count_t monitor_refcount;static bool hotplug_handle;#define EAL_UEV_MSG_LEN 4096
@@ -342,10 +343,8 @@ rte_dev_event_monitor_start(void)rte_rwlock_write_lock (&monitor_lock); -if (monitor_refcount) { - monitor_refcount++; +if (!rte_usage_count_claim (&monitor_refcount)) goto exit; - } intr_handle =rte_intr_instance_alloc (RTE_INTR_INSTANCE_F_PRIVATE );if (intr_handle ==NULL ) {
@@ -370,12 +369,11 @@ rte_dev_event_monitor_start(void) goto exit; } - monitor_refcount++; - exit:if (ret) {rte_intr_instance_free (intr_handle); intr_handle =NULL ; +rte_usage_count_release (&monitor_refcount); }rte_rwlock_write_unlock (&monitor_lock);return ret;
@@ -389,14 +387,13 @@ rte_dev_event_monitor_stop(void)rte_rwlock_write_lock (&monitor_lock); -if (!monitor_refcount) { +if (monitor_refcount ==0 ) {EAL_LOG (ERR ,"device event monitor already stopped" ); goto exit; } -if (monitor_refcount >1 ) { - monitor_refcount--; - goto exit; +if (!rte_usage_count_is_last (&monitor_refcount)) { + goto release; } ret = rte_intr_callback_unregister(intr_handle, dev_uev_handler,
@@ -411,7 +408,8 @@ rte_dev_event_monitor_stop(void) intr_handle =NULL ; ret =0 ; - monitor_refcount--; +release: +rte_usage_count_release (&monitor_refcount); exit:rte_rwlock_write_unlock (&monitor_lock);
Signature · 1 line
2.52.0
RFC PATCH 4/8 vhost: use usage counters for vchan tracking
In reply to Anatoly BurakovUse EAL usage counters instead of raw integers for vchan tracking.
--- lib/vhost/vhost.c | 5 ++--- lib/vhost/vhost.h | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-)
lib/vhost/vhost.c +2 -3
@@ -2152,7 +2152,7 @@ rte_vhost_async_dma_configure(int16_t dma_id, uint16_t vchan_id) dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr = pkts_cmpl_flag_addr; dma_copy_track[dma_id].vchans[vchan_id].ring_size = max_desc; dma_copy_track[dma_id].vchans[vchan_id].ring_mask = max_desc -1 ; - dma_copy_track[dma_id].nr_vchans++; +rte_usage_count_claim (&dma_copy_track[dma_id].nr_vchans);pthread_mutex_unlock (&vhost_dma_lock);return 0 ;
@@ -2437,9 +2437,8 @@ rte_vhost_async_dma_unconfigure(int16_t dma_id, uint16_t vchan_id)rte_free (dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr); dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr =NULL ; - dma_copy_track[dma_id].nr_vchans--; -if (dma_copy_track[dma_id].nr_vchans ==0 ) { +if (rte_usage_count_release (&dma_copy_track[dma_id].nr_vchans)) {rte_free (dma_copy_track[dma_id].vchans); dma_copy_track[dma_id].vchans =NULL ; }
lib/vhost/vhost.h +2 -1
@@ -19,6 +19,7 @@#include <rte_ether.h> #include <rte_malloc.h> #include <rte_dmadev.h> +#include <rte_usage_count.h> #include "rte_vhost.h" #include "vdpa_driver.h"
@@ -202,7 +203,7 @@ struct async_dma_vchan_info {struct async_dma_info {struct async_dma_vchan_info *vchans;/* number of registered virtual channels */ -uint16_t nr_vchans; +rte_usage_count_t nr_vchans; };extern struct async_dma_info dma_copy_track[RTE_DMADEV_DEFAULT_MAX ];
Signature · 1 line
2.52.0
RFC PATCH 5/8 acl: use usage counters for ref counting
In reply to Anatoly BurakovReplace raw integer refcounts with EAL usage counters.
--- lib/acl/acl.h | 4 +++- lib/acl/acl_bld.c | 9 ++++----- 2 files changed, 7 insertions(+), 6 deletions(-)
lib/acl/acl.h +3 -1
@@ -5,6 +5,8 @@ #ifndef _ACL_H_ #define _ACL_H_ +#include <rte_usage_count.h> + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */
@@ -104,7 +106,7 @@ struct rte_acl_match_results {struct rte_acl_node {uint64_t node_index;/* index for this node */ uint32_t level;/* level 0-n in the trie */ -uint32_t ref_count;/* ref count for this node */ +rte_usage_count_t ref_count;/* ref count for this node */ struct rte_acl_bitset values;/* set of all values that map to another node * (union of bits in each transition.
lib/acl/acl_bld.c +4 -5
@@ -296,7 +296,7 @@ acl_add_ptr(struct acl_build_context *context,acl_include (&node->ptrs[n].values, bits,0 );acl_include (&node->values, bits,-1 );if (ptr !=NULL ) - ptr->ref_count++; +rte_usage_count_claim (&ptr->ref_count);if (node->num_ptrs <= n) node->num_ptrs = n +1 ;return 0 ;
@@ -411,7 +411,7 @@ acl_dup_node(struct acl_build_context *context, struct rte_acl_node *node)for (n =0 ; n < node->num_ptrs; n++) {if (node->ptrs[n].ptr !=NULL ) { next->ptrs[n].ptr = node->ptrs[n].ptr; - next->ptrs[n].ptr->ref_count++; +rte_usage_count_claim (&next->ptrs[n].ptr->ref_count);acl_include (&next->ptrs[n].values, &node->ptrs[n].values,-1 ); }
@@ -449,8 +449,7 @@ acl_deref_ptr(struct acl_build_context *context,/* De-reference the node at the specified pointer */ if (node !=NULL && node->ptrs[index].ptr !=NULL ) { ref_node = node->ptrs[index].ptr; - ref_node->ref_count--; -if (ref_node->ref_count ==0 ) +if (rte_usage_count_release (&ref_node->ref_count))acl_free_node (context, ref_node); } }
@@ -966,7 +965,7 @@ build_trie(struct acl_build_context *context, struct rte_acl_build_rule *head, root =acl_alloc_node (context,0 ); - root->ref_count =1 ; +rte_usage_count_claim (&root->ref_count); end = root;for (n =0 ; n < rule->config->num_fields; n++) {
Signature · 1 line
2.52.0
RFC PATCH 7/8 lpm: use usage counters for ref counting
In reply to Anatoly BurakovUse EAL usage counters instead of raw integers for ref counting.
--- lib/lpm/rte_lpm6.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
lib/lpm/rte_lpm6.c +7 -6
@@ -20,6 +20,7 @@#include <assert.h> #include <rte_jhash.h> #include <rte_tailq.h> +#include <rte_usage_count.h> #include "rte_lpm6.h" #include "lpm_log.h"
@@ -87,7 +88,7 @@ struct rte_lpm_tbl8_hdr {uint32_t owner_entry_ind;/**< index of the owner table entry where * pointer to the tbl8 is stored */ -uint32_t ref_cnt;/**< table reference counter */ +rte_usage_count_t ref_cnt;/**< table reference counter */ };/** LPM6 structure. */
@@ -676,7 +677,7 @@ add_step(struct rte_lpm6 *lpm, struct rte_lpm6_tbl_entry *tbl,/* update tbl8 rule reference counter */ if (tbl_ind !=TBL24_IND && is_new_rule) - lpm->tbl8_hdrs[tbl_ind].ref_cnt++; +rte_usage_count_claim (&lpm->tbl8_hdrs[tbl_ind].ref_cnt);return 0 ; }
@@ -717,7 +718,7 @@ add_step(struct rte_lpm6 *lpm, struct rte_lpm6_tbl_entry *tbl,/* update the current table's reference counter */ if (tbl_ind !=TBL24_IND ) - lpm->tbl8_hdrs[tbl_ind].ref_cnt++; +rte_usage_count_claim (&lpm->tbl8_hdrs[tbl_ind].ref_cnt); }/* * If it's valid but not extended the rule that was stored
@@ -768,7 +769,7 @@ add_step(struct rte_lpm6 *lpm, struct rte_lpm6_tbl_entry *tbl,/* update the current table's reference counter */ if (tbl_ind !=TBL24_IND ) - lpm->tbl8_hdrs[tbl_ind].ref_cnt++; +rte_usage_count_claim (&lpm->tbl8_hdrs[tbl_ind].ref_cnt); } *next_tbl_ind = tbl[entry_ind].lpm6_tbl8_gindex;
@@ -1231,7 +1232,7 @@ remove_tbl(struct rte_lpm6 *lpm, struct rte_lpm_tbl8_hdr *tbl_hdr,struct rte_lpm_tbl8_hdr *owner_tbl_hdr = &lpm->tbl8_hdrs[owner_tbl_ind]; -if (--owner_tbl_hdr->ref_cnt ==0 ) +if (rte_usage_count_release (&owner_tbl_hdr->ref_cnt))remove_tbl (lpm, owner_tbl_hdr, owner_tbl_ind, lsp_rule); }
@@ -1306,7 +1307,7 @@ rte_lpm6_delete(struct rte_lpm6 *lpm, const struct rte_ipv6_addr *ip, uint8_t de*/ if (tbl_ind !=TBL24_IND ) {struct rte_lpm_tbl8_hdr *tbl_hdr = &lpm->tbl8_hdrs[tbl_ind]; -if (--tbl_hdr->ref_cnt ==0 ) { +if (rte_usage_count_release (&tbl_hdr->ref_cnt)) {/* remove the table */ remove_tbl (lpm, tbl_hdr, tbl_ind, lsp_rule);return 0 ;
Signature · 1 line
2.52.0
RFC PATCH 6/8 thash: use usage counters for ref counting
In reply to Anatoly BurakovUse EAL usage counters instead of raw integers for ref counting.
--- lib/hash/rte_thash.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
lib/hash/rte_thash.c +5 -5
@@ -15,6 +15,7 @@#include <rte_log.h> #include <rte_malloc.h> #include <rte_cpuflags.h> +#include <rte_usage_count.h> RTE_LOG_REGISTER_SUFFIX (thash_logtype, thash,INFO );#define RTE_LOGTYPE_HASH thash_logtype
@@ -34,7 +35,7 @@ static struct rte_tailq_elem rte_thash_tailq = {EAL_REGISTER_TAILQ (rte_thash_tailq) struct thash_lfsr { -uint32_t ref_cnt; +rte_usage_count_t ref_cnt;uint32_t poly;/**< polynomial associated with the lfsr */ uint32_t rev_poly;
@@ -187,7 +188,7 @@ alloc_lfsr(uint32_t poly_degree)/* clear bits_cnt after rev_state was inited */ lfsr->bits_cnt =0 ; - lfsr->ref_cnt =1 ; +rte_usage_count_claim (&lfsr->ref_cnt);return lfsr; }
@@ -195,15 +196,14 @@ alloc_lfsr(uint32_t poly_degree)static void attach_lfsr (struct rte_thash_subtuple_helper *h,struct thash_lfsr *lfsr) { - lfsr->ref_cnt++; +rte_usage_count_claim (&lfsr->ref_cnt); h->lfsr = lfsr; }static void free_lfsr (struct thash_lfsr *lfsr) { - lfsr->ref_cnt--; -if (lfsr->ref_cnt ==0 ) +if (rte_usage_count_release (&lfsr->ref_cnt))rte_free (lfsr); }
Signature · 1 line
2.52.0
RFC PATCH 8/8 net/nbl: track devices with usage counters
In reply to Anatoly BurakovUse EAL usage counters to track VFIO device references.
--- drivers/net/nbl/nbl_common/nbl_userdev.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)
drivers/net/nbl/nbl_common/nbl_userdev.c +12 -10
@@ -4,6 +4,8 @@#include <uapi/linux/vfio.h> +#include <rte_usage_count.h> +#include "nbl_userdev.h" #include <dev_vfio.h>
@@ -26,7 +28,7 @@ struct nbl_userdev_map_record { };static int nbl_default_container =-1 ; -static int nbl_group_count; +static rte_usage_count_t nbl_group_count;TAILQ_HEAD (nbl_adapter_list_head, nbl_adapter); static struct nbl_adapter_list_head nbl_adapter_list =
@@ -423,7 +425,7 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter)u64 dma_limit =NBL_USERDEV_DMA_LIMIT ;int ret, container_create =0 , container_set =0 ;int vfio_group_fd, container = nbl_default_container; -bool new_group = false; +bool new_group = false, first_group = false;rte_pci_device_name (&pci_dev->addr, dev_name,RTE_DEV_NAME_MAX_LEN ); snprintf(pathname, sizeof(pathname),
@@ -481,11 +483,11 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) goto free_group; } - nbl_group_count++; + first_group =rte_usage_count_claim (&nbl_group_count); container_set =1 ;/* set an IOMMU type for container */ -if (container_create || nbl_group_count ==1 ) { +if (container_create || first_group) {if (ioctl (container,VFIO_CHECK_EXTENSION , VFIO_TYPE1v2_IOMMU)) { ret =ioctl (container,VFIO_SET_IOMMU , VFIO_TYPE1v2_IOMMU);if (ret) {
@@ -548,13 +550,13 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) close_fd:close (common->devfd); unregister_mem_event: -if (container_set && nbl_group_count ==1 ) { +if (first_group) {rte_mcfg_mem_read_lock ();rte_mem_event_callback_unregister (NBL_USERDEV_EVENT_CLB_NAME ,NULL );rte_mcfg_mem_read_unlock (); } free_dma_map: -if (container_set && nbl_group_count ==1 ) { +if (first_group) {rte_mcfg_mem_read_lock ();nbl_userdev_dma_free ();rte_mcfg_mem_read_unlock ();
@@ -562,7 +564,7 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) unset_container:if (container_set) {ioctl (vfio_group_fd,VFIO_GROUP_UNSET_CONTAINER , &container); - nbl_group_count--; +rte_usage_count_release (&nbl_group_count); } free_group:if (new_group)
@@ -577,7 +579,7 @@ static int nbl_mdev_unmap_device(struct nbl_adapter *adapter) {struct nbl_common_info *common = &adapter->common;int vfio_group_fd, ret; -bool last_group_user; +bool last_group_user, last_group = false;rte_mcfg_mem_read_lock ();TAILQ_REMOVE (&nbl_adapter_list, adapter, next);
@@ -591,11 +593,11 @@ static int nbl_mdev_unmap_device(struct nbl_adapter *adapter)if (ret)NBL_LOG (ERR ,"unset container, error %i (%s) %d" , errno,strerror (errno), ret); - nbl_group_count--; + last_group =rte_usage_count_release (&nbl_group_count);close (vfio_group_fd); common->groupfd =-1 ; } -if (!nbl_group_count) { +if (last_group) {rte_mem_event_callback_unregister (NBL_USERDEV_EVENT_CLB_NAME ,NULL );nbl_userdev_dma_free (); }
Signature · 1 line
2.52.0