From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 7A660A317C for ; Thu, 17 Oct 2019 13:51:50 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B79B81E943; Thu, 17 Oct 2019 13:51:49 +0200 (CEST) Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by dpdk.org (Postfix) with ESMTP id 886031E942 for ; Thu, 17 Oct 2019 13:51:47 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 17 Oct 2019 04:51:46 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.67,307,1566889200"; d="scan'208";a="189999851" Received: from irsmsx153.ger.corp.intel.com ([163.33.192.75]) by orsmga008.jf.intel.com with ESMTP; 17 Oct 2019 04:51:43 -0700 Received: from irsmsx104.ger.corp.intel.com ([169.254.5.252]) by IRSMSX153.ger.corp.intel.com ([169.254.9.119]) with mapi id 14.03.0439.000; Thu, 17 Oct 2019 12:51:42 +0100 From: "Ananyev, Konstantin" To: Honnappa Nagarahalli , "olivier.matz@6wind.com" , "sthemmin@microsoft.com" , "jerinj@marvell.com" , "Richardson, Bruce" , "david.marchand@redhat.com" , "pbhagavatula@marvell.com" CC: "dev@dpdk.org" , Dharmik Thakkar , "Ruifeng Wang (Arm Technology China)" , "Gavin Hu (Arm Technology China)" , "stephen@networkplumber.org" , nd , nd Thread-Topic: [PATCH v4 1/2] lib/ring: apis to support configurable element size Thread-Index: AQHVfkvmrG5Kyu6ZXEWJeUYrxswBkqdVxOuAgASfoeCAAGP4AIAAqIDwgALNTICAAIYKsA== Date: Thu, 17 Oct 2019 11:51:41 +0000 Message-ID: <2601191342CEEE43887BDE71AB97725801A8C6A2DA@IRSMSX104.ger.corp.intel.com> References: <20190906190510.11146-1-honnappa.nagarahalli@arm.com> <20191009024709.38144-1-honnappa.nagarahalli@arm.com> <20191009024709.38144-2-honnappa.nagarahalli@arm.com> <2601191342CEEE43887BDE71AB97725801A8C68545@IRSMSX104.ger.corp.intel.com> <2601191342CEEE43887BDE71AB97725801A8C68A99@IRSMSX104.ger.corp.intel.com> In-Reply-To: Accept-Language: en-IE, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiZDQyNThmNGQtOGM5My00MWZlLWE3OWItMGM2YzBlYzE1MDY5IiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX05UIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjEwLjE4MDQuNDkiLCJUcnVzdGVkTGFiZWxIYXNoIjoiYkNvYklGUTdqMU1JdVQ2ZXhCYXJ1QXdZUUltXC9mTU5JSGZzd2ZyU1FPSjZad3U5N0ZJVlhYWGFkb3JHcWlpcnYifQ== x-ctpclassification: CTP_NT dlp-product: dlpe-windows dlp-version: 11.2.0.6 dlp-reaction: no-action x-originating-ip: [163.33.239.180] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dpdk-dev] [PATCH v4 1/2] lib/ring: apis to support configurable element size X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" > > > > > > Current APIs assume ring elements to be pointers. However, in > > > > > > many use cases, the size can be different. Add new APIs to > > > > > > support configurable ring element sizes. > > > > > > > > > > > > Signed-off-by: Honnappa Nagarahalli > > > > > > > > > > > > Reviewed-by: Dharmik Thakkar > > > > > > Reviewed-by: Gavin Hu > > > > > > Reviewed-by: Ruifeng Wang > > > > > > --- > > > > > > lib/librte_ring/Makefile | 3 +- > > > > > > lib/librte_ring/meson.build | 3 + > > > > > > lib/librte_ring/rte_ring.c | 45 +- > > > > > > lib/librte_ring/rte_ring.h | 1 + > > > > > > lib/librte_ring/rte_ring_elem.h | 946 > > +++++++++++++++++++++++++++ > > > > > > lib/librte_ring/rte_ring_version.map | 2 + > > > > > > 6 files changed, 991 insertions(+), 9 deletions(-) create mod= e > > > > > > 100644 lib/librte_ring/rte_ring_elem.h > > > > > > > > > > > > diff --git a/lib/librte_ring/Makefile b/lib/librte_ring/Makefil= e > > > > > > index 21a36770d..515a967bb 100644 > > > > > > --- a/lib/librte_ring/Makefile > > > > > > +++ b/lib/librte_ring/Makefile >=20 > >=20 > > > > > > + > > > > > > +# rte_ring_create_elem and rte_ring_get_memsize_elem are > > > > > > +experimental allow_experimental_apis =3D true > > > > > > diff --git a/lib/librte_ring/rte_ring.c > > > > > > b/lib/librte_ring/rte_ring.c index d9b308036..6fed3648b 100644 > > > > > > --- a/lib/librte_ring/rte_ring.c > > > > > > +++ b/lib/librte_ring/rte_ring.c > > > > > > @@ -33,6 +33,7 @@ > > > > > > #include > > > > > > > > > > > > #include "rte_ring.h" > > > > > > +#include "rte_ring_elem.h" > > > > > > >=20 > >=20 > > > > > > diff --git a/lib/librte_ring/rte_ring_elem.h > > > > > > b/lib/librte_ring/rte_ring_elem.h new file mode 100644 index > > > > > > 000000000..860f059ad > > > > > > --- /dev/null > > > > > > +++ b/lib/librte_ring/rte_ring_elem.h > > > > > > @@ -0,0 +1,946 @@ > > > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > > > + * > > > > > > + * Copyright (c) 2019 Arm Limited > > > > > > + * Copyright (c) 2010-2017 Intel Corporation > > > > > > + * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org > > > > > > + * All rights reserved. > > > > > > + * Derived from FreeBSD's bufring.h > > > > > > + * Used as BSD-3 Licensed with permission from Kip Macy. > > > > > > + */ > > > > > > + > > > > > > +#ifndef _RTE_RING_ELEM_H_ > > > > > > +#define _RTE_RING_ELEM_H_ > > > > > > + >=20 > >=20 > > > > > > + > > > > > > +/* the actual enqueue of pointers on the ring. > > > > > > + * Placed here since identical code needed in both > > > > > > + * single and multi producer enqueue functions. > > > > > > + */ > > > > > > +#define ENQUEUE_PTRS_ELEM(r, ring_start, prod_head, obj_table, > > > > > > +esize, n) > > > > > > do { \ > > > > > > + if (esize =3D=3D 4) \ > > > > > > + ENQUEUE_PTRS_32(r, ring_start, prod_head, > > obj_table, n); \ > > > > > > + else if (esize =3D=3D 8) \ > > > > > > + ENQUEUE_PTRS_64(r, ring_start, prod_head, > > obj_table, n); \ > > > > > > + else if (esize =3D=3D 16) \ > > > > > > + ENQUEUE_PTRS_128(r, ring_start, prod_head, > > obj_table, n); > > > > \ } > > > > > > while > > > > > > +(0) > > > > > > + > > > > > > +#define ENQUEUE_PTRS_32(r, ring_start, prod_head, obj_table, n= ) > > do { \ > > > > > > + unsigned int i; \ > > > > > > + const uint32_t size =3D (r)->size; \ > > > > > > + uint32_t idx =3D prod_head & (r)->mask; \ > > > > > > + uint32_t *ring =3D (uint32_t *)ring_start; \ > > > > > > + uint32_t *obj =3D (uint32_t *)obj_table; \ > > > > > > + if (likely(idx + n < size)) { \ > > > > > > + for (i =3D 0; i < (n & ((~(unsigned)0x7))); i +=3D 8, idx += =3D 8) > > { \ > > > > > > + ring[idx] =3D obj[i]; \ > > > > > > + ring[idx + 1] =3D obj[i + 1]; \ > > > > > > + ring[idx + 2] =3D obj[i + 2]; \ > > > > > > + ring[idx + 3] =3D obj[i + 3]; \ > > > > > > + ring[idx + 4] =3D obj[i + 4]; \ > > > > > > + ring[idx + 5] =3D obj[i + 5]; \ > > > > > > + ring[idx + 6] =3D obj[i + 6]; \ > > > > > > + ring[idx + 7] =3D obj[i + 7]; \ > > > > > > + } \ > > > > > > + switch (n & 0x7) { \ > > > > > > + case 7: \ > > > > > > + ring[idx++] =3D obj[i++]; /* fallthrough */ \ > > > > > > + case 6: \ > > > > > > + ring[idx++] =3D obj[i++]; /* fallthrough */ \ > > > > > > + case 5: \ > > > > > > + ring[idx++] =3D obj[i++]; /* fallthrough */ \ > > > > > > + case 4: \ > > > > > > + ring[idx++] =3D obj[i++]; /* fallthrough */ \ > > > > > > + case 3: \ > > > > > > + ring[idx++] =3D obj[i++]; /* fallthrough */ \ > > > > > > + case 2: \ > > > > > > + ring[idx++] =3D obj[i++]; /* fallthrough */ \ > > > > > > + case 1: \ > > > > > > + ring[idx++] =3D obj[i++]; /* fallthrough */ \ > > > > > > + } \ > > > > > > + } else { \ > > > > > > + for (i =3D 0; idx < size; i++, idx++)\ > > > > > > + ring[idx] =3D obj[i]; \ > > > > > > + for (idx =3D 0; i < n; i++, idx++) \ > > > > > > + ring[idx] =3D obj[i]; \ > > > > > > + } \ > > > > > > +} while (0) > > > > > > + > > > > > > +#define ENQUEUE_PTRS_64(r, ring_start, prod_head, obj_table, n= ) > > do { \ > > > > > > + unsigned int i; \ > > > > > > + const uint32_t size =3D (r)->size; \ > > > > > > + uint32_t idx =3D prod_head & (r)->mask; \ > > > > > > + uint64_t *ring =3D (uint64_t *)ring_start; \ > > > > > > + uint64_t *obj =3D (uint64_t *)obj_table; \ > > > > > > + if (likely(idx + n < size)) { \ > > > > > > + for (i =3D 0; i < (n & ((~(unsigned)0x3))); i +=3D 4, idx += =3D 4) > > { \ > > > > > > + ring[idx] =3D obj[i]; \ > > > > > > + ring[idx + 1] =3D obj[i + 1]; \ > > > > > > + ring[idx + 2] =3D obj[i + 2]; \ > > > > > > + ring[idx + 3] =3D obj[i + 3]; \ > > > > > > + } \ > > > > > > + switch (n & 0x3) { \ > > > > > > + case 3: \ > > > > > > + ring[idx++] =3D obj[i++]; /* fallthrough */ \ > > > > > > + case 2: \ > > > > > > + ring[idx++] =3D obj[i++]; /* fallthrough */ \ > > > > > > + case 1: \ > > > > > > + ring[idx++] =3D obj[i++]; \ > > > > > > + } \ > > > > > > + } else { \ > > > > > > + for (i =3D 0; idx < size; i++, idx++)\ > > > > > > + ring[idx] =3D obj[i]; \ > > > > > > + for (idx =3D 0; i < n; i++, idx++) \ > > > > > > + ring[idx] =3D obj[i]; \ > > > > > > + } \ > > > > > > +} while (0) > > > > > > + > > > > > > +#define ENQUEUE_PTRS_128(r, ring_start, prod_head, obj_table, > > > > > > +n) do > > > > { \ > > > > > > + unsigned int i; \ > > > > > > + const uint32_t size =3D (r)->size; \ > > > > > > + uint32_t idx =3D prod_head & (r)->mask; \ > > > > > > + __uint128_t *ring =3D (__uint128_t *)ring_start; \ > > > > > > + __uint128_t *obj =3D (__uint128_t *)obj_table; \ > > > > > > + if (likely(idx + n < size)) { \ > > > > > > + for (i =3D 0; i < (n >> 1); i +=3D 2, idx +=3D 2) { \ > > > > > > + ring[idx] =3D obj[i]; \ > > > > > > + ring[idx + 1] =3D obj[i + 1]; \ > > > > > > + } \ > > > > > > + switch (n & 0x1) { \ > > > > > > + case 1: \ > > > > > > + ring[idx++] =3D obj[i++]; \ > > > > > > + } \ > > > > > > + } else { \ > > > > > > + for (i =3D 0; idx < size; i++, idx++)\ > > > > > > + ring[idx] =3D obj[i]; \ > > > > > > + for (idx =3D 0; i < n; i++, idx++) \ > > > > > > + ring[idx] =3D obj[i]; \ > > > > > > + } \ > > > > > > +} while (0) > > > > > > + > > > > > > +/* the actual copy of pointers on the ring to obj_table. > > > > > > + * Placed here since identical code needed in both > > > > > > + * single and multi consumer dequeue functions. > > > > > > + */ > > > > > > +#define DEQUEUE_PTRS_ELEM(r, ring_start, cons_head, obj_table, > > > > > > +esize, n) > > > > > > do { \ > > > > > > + if (esize =3D=3D 4) \ > > > > > > + DEQUEUE_PTRS_32(r, ring_start, cons_head, > > obj_table, n); \ > > > > > > + else if (esize =3D=3D 8) \ > > > > > > + DEQUEUE_PTRS_64(r, ring_start, cons_head, > > obj_table, n); \ > > > > > > + else if (esize =3D=3D 16) \ > > > > > > + DEQUEUE_PTRS_128(r, ring_start, cons_head, > > obj_table, n); > > > > \ } > > > > > > while > > > > > > +(0) > > > > > > + > > > > > > +#define DEQUEUE_PTRS_32(r, ring_start, cons_head, obj_table, n= ) do > > { \ > > > > > > + unsigned int i; \ > > > > > > + uint32_t idx =3D cons_head & (r)->mask; \ > > > > > > + const uint32_t size =3D (r)->size; \ > > > > > > + uint32_t *ring =3D (uint32_t *)ring_start; \ > > > > > > + uint32_t *obj =3D (uint32_t *)obj_table; \ > > > > > > + if (likely(idx + n < size)) { \ > > > > > > + for (i =3D 0; i < (n & (~(unsigned)0x7)); i +=3D 8, idx +=3D= 8) > > {\ > > > > > > + obj[i] =3D ring[idx]; \ > > > > > > + obj[i + 1] =3D ring[idx + 1]; \ > > > > > > + obj[i + 2] =3D ring[idx + 2]; \ > > > > > > + obj[i + 3] =3D ring[idx + 3]; \ > > > > > > + obj[i + 4] =3D ring[idx + 4]; \ > > > > > > + obj[i + 5] =3D ring[idx + 5]; \ > > > > > > + obj[i + 6] =3D ring[idx + 6]; \ > > > > > > + obj[i + 7] =3D ring[idx + 7]; \ > > > > > > + } \ > > > > > > + switch (n & 0x7) { \ > > > > > > + case 7: \ > > > > > > + obj[i++] =3D ring[idx++]; /* fallthrough */ \ > > > > > > + case 6: \ > > > > > > + obj[i++] =3D ring[idx++]; /* fallthrough */ \ > > > > > > + case 5: \ > > > > > > + obj[i++] =3D ring[idx++]; /* fallthrough */ \ > > > > > > + case 4: \ > > > > > > + obj[i++] =3D ring[idx++]; /* fallthrough */ \ > > > > > > + case 3: \ > > > > > > + obj[i++] =3D ring[idx++]; /* fallthrough */ \ > > > > > > + case 2: \ > > > > > > + obj[i++] =3D ring[idx++]; /* fallthrough */ \ > > > > > > + case 1: \ > > > > > > + obj[i++] =3D ring[idx++]; /* fallthrough */ \ > > > > > > + } \ > > > > > > + } else { \ > > > > > > + for (i =3D 0; idx < size; i++, idx++) \ > > > > > > + obj[i] =3D ring[idx]; \ > > > > > > + for (idx =3D 0; i < n; i++, idx++) \ > > > > > > + obj[i] =3D ring[idx]; \ > > > > > > + } \ > > > > > > +} while (0) > > > > > > + > > > > > > +#define DEQUEUE_PTRS_64(r, ring_start, cons_head, obj_table, n= ) do > > { \ > > > > > > + unsigned int i; \ > > > > > > + uint32_t idx =3D cons_head & (r)->mask; \ > > > > > > + const uint32_t size =3D (r)->size; \ > > > > > > + uint64_t *ring =3D (uint64_t *)ring_start; \ > > > > > > + uint64_t *obj =3D (uint64_t *)obj_table; \ > > > > > > + if (likely(idx + n < size)) { \ > > > > > > + for (i =3D 0; i < (n & (~(unsigned)0x3)); i +=3D 4, idx +=3D= 4) > > {\ > > > > > > + obj[i] =3D ring[idx]; \ > > > > > > + obj[i + 1] =3D ring[idx + 1]; \ > > > > > > + obj[i + 2] =3D ring[idx + 2]; \ > > > > > > + obj[i + 3] =3D ring[idx + 3]; \ > > > > > > + } \ > > > > > > + switch (n & 0x3) { \ > > > > > > + case 3: \ > > > > > > + obj[i++] =3D ring[idx++]; /* fallthrough */ \ > > > > > > + case 2: \ > > > > > > + obj[i++] =3D ring[idx++]; /* fallthrough */ \ > > > > > > + case 1: \ > > > > > > + obj[i++] =3D ring[idx++]; \ > > > > > > + } \ > > > > > > + } else { \ > > > > > > + for (i =3D 0; idx < size; i++, idx++) \ > > > > > > + obj[i] =3D ring[idx]; \ > > > > > > + for (idx =3D 0; i < n; i++, idx++) \ > > > > > > + obj[i] =3D ring[idx]; \ > > > > > > + } \ > > > > > > +} while (0) > > > > > > + > > > > > > +#define DEQUEUE_PTRS_128(r, ring_start, cons_head, obj_table, > > > > > > +n) do > > > > { \ > > > > > > + unsigned int i; \ > > > > > > + uint32_t idx =3D cons_head & (r)->mask; \ > > > > > > + const uint32_t size =3D (r)->size; \ > > > > > > + __uint128_t *ring =3D (__uint128_t *)ring_start; \ > > > > > > + __uint128_t *obj =3D (__uint128_t *)obj_table; \ > > > > > > + if (likely(idx + n < size)) { \ > > > > > > + for (i =3D 0; i < (n >> 1); i +=3D 2, idx +=3D 2) { \ > > > > > > + obj[i] =3D ring[idx]; \ > > > > > > + obj[i + 1] =3D ring[idx + 1]; \ > > > > > > + } \ > > > > > > + switch (n & 0x1) { \ > > > > > > + case 1: \ > > > > > > + obj[i++] =3D ring[idx++]; /* fallthrough */ \ > > > > > > + } \ > > > > > > + } else { \ > > > > > > + for (i =3D 0; idx < size; i++, idx++) \ > > > > > > + obj[i] =3D ring[idx]; \ > > > > > > + for (idx =3D 0; i < n; i++, idx++) \ > > > > > > + obj[i] =3D ring[idx]; \ > > > > > > + } \ > > > > > > +} while (0) > > > > > > + > > > > > > +/* Between load and load. there might be cpu reorder in weak > > > > > > +model > > > > > > + * (powerpc/arm). > > > > > > + * There are 2 choices for the users > > > > > > + * 1.use rmb() memory barrier > > > > > > + * 2.use one-direction load_acquire/store_release > > > > > > +barrier,defined by > > > > > > + * CONFIG_RTE_USE_C11_MEM_MODEL=3Dy > > > > > > + * It depends on performance test results. > > > > > > + * By default, move common functions to rte_ring_generic.h */ > > > > > > +#ifdef RTE_USE_C11_MEM_MODEL #include "rte_ring_c11_mem.h" > > > > > > +#else > > > > > > +#include "rte_ring_generic.h" > > > > > > +#endif > > > > > > + > > > > > > +/** > > > > > > + * @internal Enqueue several objects on the ring > > > > > > + * > > > > > > + * @param r > > > > > > + * A pointer to the ring structure. > > > > > > + * @param obj_table > > > > > > + * A pointer to a table of void * pointers (objects). > > > > > > + * @param esize > > > > > > + * The size of ring element, in bytes. It must be a multiple= of 4. > > > > > > + * Currently, sizes 4, 8 and 16 are supported. This should b= e the > > same > > > > > > + * as passed while creating the ring, otherwise the results = are > > undefined. > > > > > > + * @param n > > > > > > + * The number of objects to add in the ring from the obj_tab= le. > > > > > > + * @param behavior > > > > > > + * RTE_RING_QUEUE_FIXED: Enqueue a fixed number of items > > from a > > > > ring > > > > > > + * RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possibl= e > > > > from > > > > > > ring > > > > > > + * @param is_sp > > > > > > + * Indicates whether to use single producer or multi-produce= r head > > > > update > > > > > > + * @param free_space > > > > > > + * returns the amount of space after the enqueue operation h= as > > > > finished > > > > > > + * @return > > > > > > + * Actual number of objects enqueued. > > > > > > + * If behavior =3D=3D RTE_RING_QUEUE_FIXED, this will be 0 o= r n only. > > > > > > + */ > > > > > > +static __rte_always_inline unsigned int > > > > > > +__rte_ring_do_enqueue_elem(struct rte_ring *r, void * const > > obj_table, > > > > > > + unsigned int esize, unsigned int n, > > > > > > + enum rte_ring_queue_behavior behavior, unsigned > > int is_sp, > > > > > > + unsigned int *free_space) > > > > > > > > > > > > I like the idea to add esize as an argument to the public API, so > > > > the compiler can do it's jib optimizing calls with constant esize. > > > > Though I am not very happy with the rest of implementation: > > > > 1. It doesn't really provide configurable elem size - only 4/8/16B > > > > elems are supported. > > > Agree. I was thinking other sizes can be added on need basis. > > > However, I am wondering if we should just provide for 4B and then the > > users can use bulk operations to construct whatever they need? > > > > I suppose it could be plan B... if there would be no agreement on gener= ic case. > > And for 4B elems, I guess you do have a particular use-case? > Yes >=20 > > > > > It > > > would mean extra work for the users. > > > > > > > 2. A lot of code duplication with these 3 copies of ENQUEUE/DEQUEUE > > > > macros. > > > > > > > > Looking at ENQUEUE/DEQUEUE macros, I can see that main loop always > > > > does 32B copy per iteration. > > > Yes, I tried to keep it the same as the existing one (originally, I > > > guess the intention was to allow for 256b vector instructions to be > > > generated) > > > > > > > So wonder can we make a generic function that would do 32B copy per > > > > iteration in a main loop, and copy tail by 4B chunks? > > > > That would avoid copy duplication and will allow user to have any > > > > elem size (multiple of 4B) he wants. > > > > Something like that (note didn't test it, just a rough idea): > > > > > > > > static inline void > > > > copy_elems(uint32_t du32[], const uint32_t su32[], uint32_t num, > > > > uint32_t > > > > esize) { > > > > uint32_t i, sz; > > > > > > > > sz =3D (num * esize) / sizeof(uint32_t); > > > If 'num' is a compile time constant, 'sz' will be a compile time cons= tant. > > Otherwise, this will result in a multiplication operation. > > > > Not always. > > If esize is compile time constant, then for esize as power of 2 (4,8,16= ,...), it > > would be just one shift. > > For other constant values it could be a 'mul' or in many cases just 2 s= hifts plus > > 'add' (if compiler is smart enough). > > I.E. let say for 24B elem is would be either num * 6 or (num << 2) + (n= um << > > 1). > With num * 15 it has to be (num << 3) + (num << 2) + (num << 1) + num > Not sure if the compiler will do this. For 15, it can be just (num << 4) - num >=20 > > I suppose for non-power of 2 elems it might be ok to get such small per= f hit. > Agree, should be ok not to focus on right now. >=20 > > > > >I have tried > > > to avoid the multiplication operation and try to use shift and mask > > operations (just like how the rest of the ring code does). > > > > > > > > > > > for (i =3D 0; i < (sz & ~7); i +=3D 8) > > > > memcpy(du32 + i, su32 + i, 8 * sizeof(uint32_t)); > > > I had used memcpy to start with (for the entire copy operation), > > > performance is not the same for 64b elements when compared with the > > existing ring APIs (some cases more and some cases less). > > > > I remember that from one of your previous mails, that's why here I sugg= est to > > use in a loop memcpy() with fixed size. > > That way for each iteration complier will replace memcpy() with instruc= tions > > to copy 32B in a way he thinks is optimal (same as for original macro, = I think). > I tried this. On x86 (Xeon(R) Gold 6132 CPU @ 2.60GHz), the results are a= s follows. The numbers in brackets are with the code on master. > gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0 >=20 > RTE>>ring_perf_elem_autotest > ### Testing single element and burst enq/deq ### > SP/SC single enq/dequeue: 5 > MP/MC single enq/dequeue: 40 (35) > SP/SC burst enq/dequeue (size: 8): 2 > MP/MC burst enq/dequeue (size: 8): 6 > SP/SC burst enq/dequeue (size: 32): 1 (2) > MP/MC burst enq/dequeue (size: 32): 2 >=20 > ### Testing empty dequeue ### > SC empty dequeue: 2.11 > MC empty dequeue: 1.41 (2.11) >=20 > ### Testing using a single lcore ### > SP/SC bulk enq/dequeue (size: 8): 2.15 (2.86) > MP/MC bulk enq/dequeue (size: 8): 6.35 (6.91) > SP/SC bulk enq/dequeue (size: 32): 1.35 (2.06) > MP/MC bulk enq/dequeue (size: 32): 2.38 (2.95) >=20 > ### Testing using two physical cores ### > SP/SC bulk enq/dequeue (size: 8): 73.81 (15.33) > MP/MC bulk enq/dequeue (size: 8): 75.10 (71.27) > SP/SC bulk enq/dequeue (size: 32): 21.14 (9.58) > MP/MC bulk enq/dequeue (size: 32): 25.74 (20.91) >=20 > ### Testing using two NUMA nodes ### > SP/SC bulk enq/dequeue (size: 8): 164.32 (50.66) > MP/MC bulk enq/dequeue (size: 8): 176.02 (173.43) > SP/SC bulk enq/dequeue (size: 32): 50.78 (23) > MP/MC bulk enq/dequeue (size: 32): 63.17 (46.74) >=20 > On one of the Arm platform > MP/MC bulk enq/dequeue (size: 32): 0.37 (0.33) (~12% hit, the rest are ok= ) So it shows better numbers for one core, but worse on 2, right? =20 > On another Arm platform, all numbers are same or slightly better. >=20 > I can post the patch with this change if you want to run some benchmarks = on your platform. Sure, please do. I'll try to run on my boxes. > I have not used the same code you have suggested, instead I have used the= same logic in a single macro with memcpy. >=20