Optimize local cache implementation.
Signed-off-by: Petri Savolainen <[email protected]>
---
.../linux-generic/include/odp_buffer_inlines.h | 26 +-
.../linux-generic/include/odp_buffer_internal.h | 5 +-
platform/linux-generic/include/odp_internal.h | 2 -
.../linux-generic/include/odp_packet_internal.h | 4 +-
platform/linux-generic/include/odp_pool_internal.h | 143 +-------
platform/linux-generic/odp_buffer.c | 3 -
platform/linux-generic/odp_packet.c | 70 ++--
platform/linux-generic/odp_pool.c | 400 +++++++++++++++++----
platform/linux-generic/pktio/dpdk.c | 24 +-
platform/linux-generic/pktio/netmap.c | 5 +-
platform/linux-generic/pktio/pcap.c | 26 +-
platform/linux-generic/pktio/socket.c | 16 +-
platform/linux-generic/pktio/socket_mmap.c | 7 +-
platform/linux-generic/pktio/tap.c | 7 +-
14 files changed, 434 insertions(+), 304 deletions(-)
diff --git a/platform/linux-generic/include/odp_buffer_inlines.h
b/platform/linux-generic/include/odp_buffer_inlines.h
index 3f4d9fd..2b1ab42 100644
--- a/platform/linux-generic/include/odp_buffer_inlines.h
+++ b/platform/linux-generic/include/odp_buffer_inlines.h
@@ -56,30 +56,12 @@ static inline odp_buffer_hdr_t *odp_buf_to_hdr(odp_buffer_t
buf)
(pool->pool_mdata_addr + (index * ODP_CACHE_LINE_SIZE));
}
-static inline uint32_t odp_buffer_refcount(odp_buffer_hdr_t *buf)
+static inline uint32_t pool_id_from_buf(odp_buffer_t buf)
{
- return odp_atomic_load_u32(&buf->ref_count);
-}
-
-static inline uint32_t odp_buffer_incr_refcount(odp_buffer_hdr_t *buf,
- uint32_t val)
-{
- return odp_atomic_fetch_add_u32(&buf->ref_count, val) + val;
-}
-
-static inline uint32_t odp_buffer_decr_refcount(odp_buffer_hdr_t *buf,
- uint32_t val)
-{
- uint32_t tmp;
-
- tmp = odp_atomic_fetch_sub_u32(&buf->ref_count, val);
+ odp_buffer_bits_t handle;
- if (tmp < val) {
- odp_atomic_fetch_add_u32(&buf->ref_count, val - tmp);
- return 0;
- } else {
- return tmp - val;
- }
+ handle.handle = buf;
+ return handle.pool_id;
}
static inline odp_buffer_hdr_t *validate_buf(odp_buffer_t buf)
diff --git a/platform/linux-generic/include/odp_buffer_internal.h
b/platform/linux-generic/include/odp_buffer_internal.h
index f21364c..07d3e8d 100644
--- a/platform/linux-generic/include/odp_buffer_internal.h
+++ b/platform/linux-generic/include/odp_buffer_internal.h
@@ -114,7 +114,6 @@ struct odp_buffer_hdr_t {
union {
uint32_t all;
struct {
- uint32_t zeroized:1; /* Zeroize buf data on free */
uint32_t hdrdata:1; /* Data is in buffer hdr */
uint32_t sustain:1; /* Sustain order */
};
@@ -123,7 +122,6 @@ struct odp_buffer_hdr_t {
int8_t type; /* buffer type */
odp_event_type_t event_type; /* for reuse as event */
uint32_t size; /* max data size */
- odp_atomic_u32_t ref_count; /* reference count */
odp_pool_t pool_hdl; /* buffer pool handle */
union {
uint64_t buf_u64; /* user u64 */
@@ -171,9 +169,10 @@ typedef struct {
#define ODP_FREEBUF -1
/* Forward declarations */
-odp_buffer_t buffer_alloc(odp_pool_t pool, size_t size);
int buffer_alloc_multi(odp_pool_t pool_hdl, size_t size,
odp_buffer_t buf[], int num);
+void buffer_free_multi(uint32_t pool_id,
+ const odp_buffer_t buf[], int num_free);
int seg_alloc_head(odp_buffer_hdr_t *buf_hdr, int segcount);
void seg_free_head(odp_buffer_hdr_t *buf_hdr, int segcount);
int seg_alloc_tail(odp_buffer_hdr_t *buf_hdr, int segcount);
diff --git a/platform/linux-generic/include/odp_internal.h
b/platform/linux-generic/include/odp_internal.h
index d12f850..8bad450 100644
--- a/platform/linux-generic/include/odp_internal.h
+++ b/platform/linux-generic/include/odp_internal.h
@@ -119,8 +119,6 @@ int odp_tm_term_global(void);
int _odp_int_name_tbl_init_global(void);
int _odp_int_name_tbl_term_global(void);
-void _odp_flush_caches(void);
-
int cpuinfo_parser(FILE *file, system_info_t *sysinfo);
uint64_t odp_cpu_hz_current(int id);
diff --git a/platform/linux-generic/include/odp_packet_internal.h
b/platform/linux-generic/include/odp_packet_internal.h
index 4c4e36c..392d670 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -306,7 +306,9 @@ static inline int
packet_parse_not_complete(odp_packet_hdr_t *pkt_hdr)
/* Forward declarations */
int _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt);
-odp_packet_t packet_alloc(odp_pool_t pool_hdl, uint32_t len, int parse);
+/* Packet alloc of pktios */
+int packet_alloc_multi(odp_pool_t pool_hdl, uint32_t len,
+ odp_packet_t pkt[], int max_num);
/* Fill in parser metadata for L2 */
void packet_parse_l2(packet_parser_t *prs, uint32_t frame_len);
diff --git a/platform/linux-generic/include/odp_pool_internal.h
b/platform/linux-generic/include/odp_pool_internal.h
index 3317bd0..d6717ff 100644
--- a/platform/linux-generic/include/odp_pool_internal.h
+++ b/platform/linux-generic/include/odp_pool_internal.h
@@ -51,15 +51,25 @@ typedef struct _odp_buffer_pool_init_t {
void *buf_init_arg; /**< Argument to be passed to buf_init() */
} _odp_buffer_pool_init_t; /**< Type of buffer initialization struct */
+#define POOL_MAX_LOCAL_CHUNKS 4
+#define POOL_CHUNK_SIZE 32
+#define POOL_MAX_LOCAL_BUFS (POOL_MAX_LOCAL_CHUNKS * POOL_CHUNK_SIZE)
+
+struct local_cache_s {
+ uint64_t bufallocs; /* Local buffer alloc count */
+ uint64_t buffrees; /* Local buffer free count */
+
+ uint32_t num_buf;
+ odp_buffer_hdr_t *buf[POOL_MAX_LOCAL_BUFS];
+};
+
/* Local cache for buffer alloc/free acceleration */
typedef struct local_cache_t {
union {
- struct {
- odp_buffer_hdr_t *buf_freelist; /* The local cache */
- uint64_t bufallocs; /* Local buffer alloc count */
- uint64_t buffrees; /* Local buffer free count */
- };
- uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(uint64_t))];
+ struct local_cache_s s;
+
+ uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(
+ sizeof(struct local_cache_s))];
};
} local_cache_t;
@@ -214,127 +224,6 @@ static inline void ret_blk(struct pool_entry_s *pool,
void *block)
odp_atomic_inc_u64(&pool->poolstats.blkfrees);
}
-static inline odp_buffer_hdr_t *get_buf(struct pool_entry_s *pool)
-{
- odp_buffer_hdr_t *myhead;
- POOL_LOCK(&pool->buf_lock);
-
- myhead = pool->buf_freelist;
-
- if (odp_unlikely(myhead == NULL)) {
- POOL_UNLOCK(&pool->buf_lock);
- odp_atomic_inc_u64(&pool->poolstats.bufempty);
- } else {
- pool->buf_freelist = myhead->next;
- POOL_UNLOCK(&pool->buf_lock);
- uint64_t bufcount =
- odp_atomic_fetch_sub_u32(&pool->bufcount, 1) - 1;
-
- /* Check for low watermark condition */
- if (bufcount == pool->buf_low_wm && !pool->buf_low_wm_assert) {
- pool->buf_low_wm_assert = 1;
- odp_atomic_inc_u64(&pool->poolstats.buf_low_wm_count);
- }
-
- odp_atomic_inc_u64(&pool->poolstats.bufallocs);
- }
-
- return (void *)myhead;
-}
-
-static inline void ret_buf(struct pool_entry_s *pool, odp_buffer_hdr_t *buf)
-{
- if (!buf->flags.hdrdata && buf->type != ODP_EVENT_BUFFER) {
- while (buf->segcount > 0) {
- if (buffer_is_secure(buf) || pool_is_secure(pool))
- memset(buf->addr[buf->segcount - 1],
- 0, buf->segsize);
- ret_blk(pool, buf->addr[--buf->segcount]);
- }
- buf->size = 0;
- }
-
- buf->allocator = ODP_FREEBUF; /* Mark buffer free */
- POOL_LOCK(&pool->buf_lock);
- buf->next = pool->buf_freelist;
- pool->buf_freelist = buf;
- POOL_UNLOCK(&pool->buf_lock);
-
- uint64_t bufcount = odp_atomic_fetch_add_u32(&pool->bufcount, 1) + 1;
-
- /* Check if low watermark condition should be deasserted */
- if (bufcount == pool->buf_high_wm && pool->buf_low_wm_assert) {
- pool->buf_low_wm_assert = 0;
- odp_atomic_inc_u64(&pool->poolstats.buf_high_wm_count);
- }
-
- odp_atomic_inc_u64(&pool->poolstats.buffrees);
-}
-
-static inline void *get_local_buf(local_cache_t *buf_cache,
- struct pool_entry_s *pool,
- size_t totsize)
-{
- odp_buffer_hdr_t *buf = buf_cache->buf_freelist;
-
- if (odp_likely(buf != NULL)) {
- buf_cache->buf_freelist = buf->next;
-
- if (odp_unlikely(buf->size < totsize)) {
- intmax_t needed = totsize - buf->size;
-
- do {
- void *blk = get_blk(pool);
- if (odp_unlikely(blk == NULL)) {
- ret_buf(pool, buf);
- buf_cache->buffrees--;
- return NULL;
- }
- buf->addr[buf->segcount++] = blk;
- needed -= pool->seg_size;
- } while (needed > 0);
-
- buf->size = buf->segcount * pool->seg_size;
- }
-
- buf_cache->bufallocs++;
- }
-
- return buf;
-}
-
-static inline void ret_local_buf(local_cache_t *buf_cache,
- odp_buffer_hdr_t *buf)
-{
- buf->allocator = ODP_FREEBUF;
- buf->next = buf_cache->buf_freelist;
- buf_cache->buf_freelist = buf;
-
- buf_cache->buffrees++;
-}
-
-static inline void flush_cache(local_cache_t *buf_cache,
- struct pool_entry_s *pool)
-{
- odp_buffer_hdr_t *buf = buf_cache->buf_freelist;
- uint32_t flush_count = 0;
-
- while (buf != NULL) {
- odp_buffer_hdr_t *next = buf->next;
- ret_buf(pool, buf);
- buf = next;
- flush_count++;
- }
-
- odp_atomic_add_u64(&pool->poolstats.bufallocs, buf_cache->bufallocs);
- odp_atomic_add_u64(&pool->poolstats.buffrees,
- buf_cache->buffrees - flush_count);
-
- buf_cache->buf_freelist = NULL;
- buf_cache->bufallocs = 0;
- buf_cache->buffrees = 0;
-}
-
static inline odp_pool_t pool_index_to_handle(uint32_t pool_id)
{
return _odp_cast_scalar(odp_pool_t, pool_id);
diff --git a/platform/linux-generic/odp_buffer.c
b/platform/linux-generic/odp_buffer.c
index e7e4d58..ce2fdba 100644
--- a/platform/linux-generic/odp_buffer.c
+++ b/platform/linux-generic/odp_buffer.c
@@ -67,9 +67,6 @@ int odp_buffer_snprint(char *str, uint32_t n, odp_buffer_t
buf)
len += snprintf(&str[len], n-len,
" size %" PRIu32 "\n", hdr->size);
len += snprintf(&str[len], n-len,
- " ref_count %" PRIu32 "\n",
- odp_atomic_load_u32(&hdr->ref_count));
- len += snprintf(&str[len], n-len,
" type %i\n", hdr->type);
return len;
diff --git a/platform/linux-generic/odp_packet.c
b/platform/linux-generic/odp_packet.c
index 0e319d2..dfb6f56 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -76,35 +76,48 @@ static void packet_init(pool_entry_t *pool,
odp_packet_hdr_t *pkt_hdr,
pkt_hdr->input = ODP_PKTIO_INVALID;
}
-odp_packet_t packet_alloc(odp_pool_t pool_hdl, uint32_t len, int parse)
+int packet_alloc_multi(odp_pool_t pool_hdl, uint32_t len,
+ odp_packet_t pkt[], int max_num)
{
- odp_packet_t pkt;
odp_packet_hdr_t *pkt_hdr;
pool_entry_t *pool = odp_pool_to_entry(pool_hdl);
+ int num, i;
- if (pool->s.params.type != ODP_POOL_PACKET)
- return ODP_PACKET_INVALID;
-
- /* Handle special case for zero-length packets */
- if (len == 0) {
- len = pool->s.params.buf.size;
+ num = buffer_alloc_multi(pool_hdl, len, (odp_buffer_t *)pkt, max_num);
- pkt = (odp_packet_t)buffer_alloc(pool_hdl, len);
+ for (i = 0; i < num; i++) {
+ pkt_hdr = odp_packet_hdr(pkt[i]);
+ packet_init(pool, pkt_hdr, len, 1 /* do parse */);
- if (pkt == ODP_PACKET_INVALID)
- return ODP_PACKET_INVALID;
+ if (pkt_hdr->tailroom >= pkt_hdr->buf_hdr.segsize)
+ pull_tail_seg(pkt_hdr);
+ }
- pull_tail(odp_packet_hdr(pkt), len);
+ return num;
+}
- } else {
- pkt = (odp_packet_t)buffer_alloc(pool_hdl, len);
+odp_packet_t odp_packet_alloc(odp_pool_t pool_hdl, uint32_t len)
+{
+ pool_entry_t *pool = odp_pool_to_entry(pool_hdl);
+ size_t pkt_size = len ? len : pool->s.params.buf.size;
+ int count;
+ odp_packet_t pkt;
+ odp_packet_hdr_t *pkt_hdr;
- if (pkt == ODP_PACKET_INVALID)
- return ODP_PACKET_INVALID;
+ if (pool->s.params.type != ODP_POOL_PACKET) {
+ __odp_errno = EINVAL;
+ return ODP_PACKET_INVALID;
}
+ count = buffer_alloc_multi(pool_hdl, pkt_size, (odp_buffer_t *)&pkt, 1);
+
+ if (count != 1)
+ return ODP_PACKET_INVALID;
+
pkt_hdr = odp_packet_hdr(pkt);
- packet_init(pool, pkt_hdr, len, parse);
+ packet_init(pool, pkt_hdr, pkt_size, 0 /* do not parse */);
+ if (len == 0)
+ pull_tail(pkt_hdr, pkt_size);
if (pkt_hdr->tailroom >= pkt_hdr->buf_hdr.segsize)
pull_tail_seg(pkt_hdr);
@@ -112,11 +125,6 @@ odp_packet_t packet_alloc(odp_pool_t pool_hdl, uint32_t
len, int parse)
return pkt;
}
-odp_packet_t odp_packet_alloc(odp_pool_t pool_hdl, uint32_t len)
-{
- return packet_alloc(pool_hdl, len, 0);
-}
-
int odp_packet_alloc_multi(odp_pool_t pool_hdl, uint32_t len,
odp_packet_t pkt[], int num)
{
@@ -135,9 +143,12 @@ int odp_packet_alloc_multi(odp_pool_t pool_hdl, uint32_t
len,
for (i = 0; i < count; ++i) {
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt[i]);
- packet_init(pool, pkt_hdr, pkt_size, 0);
+ packet_init(pool, pkt_hdr, pkt_size, 0 /* do not parse */);
if (len == 0)
pull_tail(pkt_hdr, pkt_size);
+
+ if (pkt_hdr->tailroom >= pkt_hdr->buf_hdr.segsize)
+ pull_tail_seg(pkt_hdr);
}
return count;
@@ -145,12 +156,16 @@ int odp_packet_alloc_multi(odp_pool_t pool_hdl, uint32_t
len,
void odp_packet_free(odp_packet_t pkt)
{
- odp_buffer_free((odp_buffer_t)pkt);
+ uint32_t pool_id = pool_id_from_buf((odp_buffer_t)pkt);
+
+ buffer_free_multi(pool_id, (odp_buffer_t *)&pkt, 1);
}
void odp_packet_free_multi(const odp_packet_t pkt[], int num)
{
- odp_buffer_free_multi((const odp_buffer_t *)pkt, num);
+ uint32_t pool_id = pool_id_from_buf((odp_buffer_t)pkt[0]);
+
+ buffer_free_multi(pool_id, (const odp_buffer_t * const)pkt, num);
}
int odp_packet_reset(odp_packet_t pkt, uint32_t len)
@@ -972,10 +987,7 @@ int _odp_packet_copy_md_to_packet(odp_packet_t srcpkt,
odp_packet_t dstpkt)
srchdr->buf_hdr.uarea_size ?
dsthdr->buf_hdr.uarea_size :
srchdr->buf_hdr.uarea_size);
- odp_atomic_store_u32(
- &dsthdr->buf_hdr.ref_count,
- odp_atomic_load_u32(
- &srchdr->buf_hdr.ref_count));
+
copy_packet_parser_metadata(srchdr, dsthdr);
/* Metadata copied, but return indication of whether the packet
diff --git a/platform/linux-generic/odp_pool.c
b/platform/linux-generic/odp_pool.c
index ec6d86a..5e4b6fb 100644
--- a/platform/linux-generic/odp_pool.c
+++ b/platform/linux-generic/odp_pool.c
@@ -57,8 +57,15 @@ static const char SHM_DEFAULT_NAME[] = "odp_buffer_pools";
/* Pool entry pointers (for inlining) */
void *pool_entry_ptr[ODP_CONFIG_POOLS];
-/* Cache thread id locally for local cache performance */
-static __thread int local_id;
+/* Thread local variables */
+typedef struct pool_local_t {
+ local_cache_t *cache[ODP_CONFIG_POOLS];
+ int thr_id;
+} pool_local_t;
+
+static __thread pool_local_t local;
+
+static void flush_cache(local_cache_t *buf_cache, struct pool_entry_s *pool);
int odp_pool_init_global(void)
{
@@ -111,7 +118,19 @@ int odp_pool_init_global(void)
int odp_pool_init_local(void)
{
- local_id = odp_thread_id();
+ pool_entry_t *pool;
+ int i;
+ int thr_id = odp_thread_id();
+
+ memset(&local, 0, sizeof(pool_local_t));
+
+ for (i = 0; i < ODP_CONFIG_POOLS; i++) {
+ pool = get_pool_entry(i);
+ local.cache[i] = &pool->s.local_cache[thr_id];
+ local.cache[i]->s.num_buf = 0;
+ }
+
+ local.thr_id = thr_id;
return 0;
}
@@ -144,7 +163,14 @@ int odp_pool_term_global(void)
int odp_pool_term_local(void)
{
- _odp_flush_caches();
+ int i;
+
+ for (i = 0; i < ODP_CONFIG_POOLS; i++) {
+ pool_entry_t *pool = get_pool_entry(i);
+
+ flush_cache(local.cache[i], &pool->s);
+ }
+
return 0;
}
@@ -179,10 +205,53 @@ int odp_pool_capability(odp_pool_capability_t *capa)
return 0;
}
-/**
+static inline odp_buffer_hdr_t *get_buf(struct pool_entry_s *pool)
+{
+ odp_buffer_hdr_t *myhead;
+
+ POOL_LOCK(&pool->buf_lock);
+
+ myhead = pool->buf_freelist;
+
+ if (odp_unlikely(myhead == NULL)) {
+ POOL_UNLOCK(&pool->buf_lock);
+ odp_atomic_inc_u64(&pool->poolstats.bufempty);
+ } else {
+ pool->buf_freelist = myhead->next;
+ POOL_UNLOCK(&pool->buf_lock);
+
+ odp_atomic_fetch_sub_u32(&pool->bufcount, 1);
+ odp_atomic_inc_u64(&pool->poolstats.bufallocs);
+ }
+
+ return (void *)myhead;
+}
+
+static inline void ret_buf(struct pool_entry_s *pool, odp_buffer_hdr_t *buf)
+{
+ if (!buf->flags.hdrdata && buf->type != ODP_EVENT_BUFFER) {
+ while (buf->segcount > 0) {
+ if (buffer_is_secure(buf) || pool_is_secure(pool))
+ memset(buf->addr[buf->segcount - 1],
+ 0, buf->segsize);
+ ret_blk(pool, buf->addr[--buf->segcount]);
+ }
+ buf->size = 0;
+ }
+
+ buf->allocator = ODP_FREEBUF; /* Mark buffer free */
+ POOL_LOCK(&pool->buf_lock);
+ buf->next = pool->buf_freelist;
+ pool->buf_freelist = buf;
+ POOL_UNLOCK(&pool->buf_lock);
+
+ odp_atomic_fetch_add_u32(&pool->bufcount, 1);
+ odp_atomic_inc_u64(&pool->poolstats.buffrees);
+}
+
+/*
* Pool creation
*/
-
odp_pool_t _pool_create(const char *name,
odp_pool_param_t *params,
uint32_t shmflags)
@@ -208,9 +277,6 @@ odp_pool_t _pool_create(const char *name,
/* Restriction for v1.0: All non-packet buffers are unsegmented */
int unseg = 1;
- /* Restriction for v1.0: No zeroization support */
- const int zeroized = 0;
-
uint32_t blk_size, buf_stride, buf_num, blk_num, seg_len = 0;
uint32_t buf_align =
params->type == ODP_POOL_BUFFER ? params->buf.align : 0;
@@ -350,7 +416,6 @@ odp_pool_t _pool_create(const char *name,
POOL_UNLOCK(&pool->s.lock);
pool->s.flags.unsegmented = unseg;
- pool->s.flags.zeroized = zeroized;
pool->s.seg_size = unseg ? blk_size : seg_len;
pool->s.blk_size = blk_size;
@@ -383,9 +448,7 @@ odp_pool_t _pool_create(const char *name,
/* Iniitalize buffer metadata */
tmp->allocator = ODP_FREEBUF;
tmp->flags.all = 0;
- tmp->flags.zeroized = zeroized;
tmp->size = 0;
- odp_atomic_init_u32(&tmp->ref_count, 0);
tmp->type = params->type;
tmp->event_type = params->type;
tmp->pool_hdl = pool->s.pool_hdl;
@@ -502,6 +565,41 @@ int odp_pool_info(odp_pool_t pool_hdl, odp_pool_info_t
*info)
return 0;
}
+static inline void get_local_cache_bufs(local_cache_t *buf_cache, uint32_t idx,
+ odp_buffer_hdr_t *buf_hdr[],
+ uint32_t num)
+{
+ uint32_t i;
+
+ for (i = 0; i < num; i++) {
+ buf_hdr[i] = buf_cache->s.buf[idx + i];
+ odp_prefetch(buf_hdr[i]);
+ odp_prefetch_store(buf_hdr[i]);
+ }
+}
+
+static void flush_cache(local_cache_t *buf_cache, struct pool_entry_s *pool)
+{
+ uint32_t flush_count = 0;
+ uint32_t num;
+
+ while ((num = buf_cache->s.num_buf)) {
+ odp_buffer_hdr_t *buf;
+
+ buf = buf_cache->s.buf[num - 1];
+ ret_buf(pool, buf);
+ flush_count++;
+ buf_cache->s.num_buf--;
+ }
+
+ odp_atomic_add_u64(&pool->poolstats.bufallocs, buf_cache->s.bufallocs);
+ odp_atomic_add_u64(&pool->poolstats.buffrees,
+ buf_cache->s.buffrees - flush_count);
+
+ buf_cache->s.bufallocs = 0;
+ buf_cache->s.buffrees = 0;
+}
+
int odp_pool_destroy(odp_pool_t pool_hdl)
{
uint32_t pool_id = pool_handle_to_index(pool_hdl);
@@ -620,77 +718,157 @@ void seg_free_tail(odp_buffer_hdr_t *buf_hdr, int
segcount)
buf_hdr->size = buf_hdr->segcount * pool->s.seg_size;
}
-odp_buffer_t buffer_alloc(odp_pool_t pool_hdl, size_t size)
+static inline int get_local_bufs(local_cache_t *buf_cache,
+ odp_buffer_hdr_t *buf_hdr[], uint32_t max_num)
+{
+ uint32_t num_buf = buf_cache->s.num_buf;
+ uint32_t num = num_buf;
+
+ if (odp_unlikely(num_buf == 0))
+ return 0;
+
+ if (odp_likely(max_num < num))
+ num = max_num;
+
+ get_local_cache_bufs(buf_cache, num_buf - num, buf_hdr, num);
+ buf_cache->s.num_buf -= num;
+ buf_cache->s.bufallocs += num;
+
+ return num;
+}
+
+static inline void ret_local_buf(local_cache_t *buf_cache, uint32_t idx,
+ odp_buffer_hdr_t *buf)
+{
+ buf_cache->s.buf[idx] = buf;
+ buf_cache->s.num_buf++;
+ buf_cache->s.buffrees++;
+}
+
+static inline void ret_local_bufs(local_cache_t *buf_cache, uint32_t idx,
+ odp_buffer_hdr_t *buf[], int num_buf)
+{
+ int i;
+
+ for (i = 0; i < num_buf; i++)
+ buf_cache->s.buf[idx + i] = buf[i];
+
+ buf_cache->s.num_buf += num_buf;
+ buf_cache->s.buffrees += num_buf;
+}
+
+int buffer_alloc_multi(odp_pool_t pool_hdl, size_t size,
+ odp_buffer_t buf[], int max_num)
{
uint32_t pool_id = pool_handle_to_index(pool_hdl);
pool_entry_t *pool = get_pool_entry(pool_id);
uintmax_t totsize = pool->s.headroom + size + pool->s.tailroom;
- odp_anybuf_t *buf;
+ odp_buffer_hdr_t *buf_tbl[max_num];
+ odp_buffer_hdr_t *buf_hdr;
+ int num, i;
+ intmax_t needed;
+ void *blk;
/* Reject oversized allocation requests */
if ((pool->s.flags.unsegmented && totsize > pool->s.seg_size) ||
(!pool->s.flags.unsegmented &&
totsize > pool->s.seg_size * ODP_BUFFER_MAX_SEG))
- return ODP_BUFFER_INVALID;
+ return 0;
/* Try to satisfy request from the local cache */
- buf = (odp_anybuf_t *)
- (void *)get_local_buf(&pool->s.local_cache[local_id],
- &pool->s, totsize);
+ num = get_local_bufs(local.cache[pool_id], buf_tbl, max_num);
/* If cache is empty, satisfy request from the pool */
- if (odp_unlikely(buf == NULL)) {
- buf = (odp_anybuf_t *)(void *)get_buf(&pool->s);
+ if (odp_unlikely(num < max_num)) {
+ for (; num < max_num; num++) {
+ buf_hdr = get_buf(&pool->s);
+
+ if (odp_unlikely(buf_hdr == NULL))
+ goto pool_empty;
+
+ /* Get blocks for this buffer, if pool uses
+ * application data */
+ if (buf_hdr->size < totsize) {
+ uint32_t segcount;
+
+ needed = totsize - buf_hdr->size;
+ do {
+ blk = get_blk(&pool->s);
+ if (odp_unlikely(blk == NULL)) {
+ ret_buf(&pool->s, buf_hdr);
+ goto pool_empty;
+ }
+
+ segcount = buf_hdr->segcount++;
+ buf_hdr->addr[segcount] = blk;
+ needed -= pool->s.seg_size;
+ } while (needed > 0);
+ buf_hdr->size = buf_hdr->segcount *
+ pool->s.seg_size;
+ }
+
+ buf_tbl[num] = buf_hdr;
+ }
+ }
- if (odp_unlikely(buf == NULL))
- return ODP_BUFFER_INVALID;
+pool_empty:
+ for (i = 0; i < num; i++) {
+ buf_hdr = buf_tbl[i];
- /* Get blocks for this buffer, if pool uses application data */
- if (buf->buf.size < totsize) {
- intmax_t needed = totsize - buf->buf.size;
+ /* Mark buffer as allocated */
+ buf_hdr->allocator = local.thr_id;
+
+ /* By default, buffers are not associated with
+ * an ordered queue */
+ buf_hdr->origin_qe = NULL;
+
+ buf[i] = odp_hdr_to_buf(buf_hdr);
+
+ /* Add more segments if buffer from local cache is too small */
+ if (odp_unlikely(buf_hdr->size < totsize)) {
+ needed = totsize - buf_hdr->size;
do {
- uint8_t *blk = get_blk(&pool->s);
- if (blk == NULL) {
- ret_buf(&pool->s, &buf->buf);
- return ODP_BUFFER_INVALID;
+ blk = get_blk(&pool->s);
+ if (odp_unlikely(blk == NULL)) {
+ int j;
+
+ ret_buf(&pool->s, buf_hdr);
+ buf_hdr = NULL;
+ local.cache[pool_id]->s.buffrees--;
+
+ /* move remaining bufs up one step
+ * and update loop counters */
+ num--;
+ for (j = i; j < num; j++)
+ buf_tbl[j] = buf_tbl[j + 1];
+
+ i--;
+ break;
}
- buf->buf.addr[buf->buf.segcount++] = blk;
needed -= pool->s.seg_size;
+ buf_hdr->addr[buf_hdr->segcount++] = blk;
+ buf_hdr->size = buf_hdr->segcount *
+ pool->s.seg_size;
} while (needed > 0);
- buf->buf.size = buf->buf.segcount * pool->s.seg_size;
}
}
- /* Mark buffer as allocated */
- buf->buf.allocator = local_id;
-
- /* By default, buffers inherit their pool's zeroization setting */
- buf->buf.flags.zeroized = pool->s.flags.zeroized;
-
- /* By default, buffers are not associated with an ordered queue */
- buf->buf.origin_qe = NULL;
-
- return odp_hdr_to_buf(&buf->buf);
+ return num;
}
-int buffer_alloc_multi(odp_pool_t pool_hdl, size_t size,
- odp_buffer_t buf[], int num)
+odp_buffer_t odp_buffer_alloc(odp_pool_t pool_hdl)
{
- int count;
+ odp_buffer_t buf;
+ int num;
- for (count = 0; count < num; ++count) {
- buf[count] = buffer_alloc(pool_hdl, size);
- if (buf[count] == ODP_BUFFER_INVALID)
- break;
- }
+ num = buffer_alloc_multi(pool_hdl,
+ odp_pool_to_entry(pool_hdl)->s.params.buf.size,
+ &buf, 1);
- return count;
-}
+ if (odp_unlikely(num != 1))
+ return ODP_BUFFER_INVALID;
-odp_buffer_t odp_buffer_alloc(odp_pool_t pool_hdl)
-{
- return buffer_alloc(pool_hdl,
- odp_pool_to_entry(pool_hdl)->s.params.buf.size);
+ return buf;
}
int odp_buffer_alloc_multi(odp_pool_t pool_hdl, odp_buffer_t buf[], int num)
@@ -700,35 +878,105 @@ int odp_buffer_alloc_multi(odp_pool_t pool_hdl,
odp_buffer_t buf[], int num)
return buffer_alloc_multi(pool_hdl, buf_size, buf, num);
}
-void odp_buffer_free(odp_buffer_t buf)
+static void multi_pool_free(odp_buffer_hdr_t *buf_hdr[], int num_buf)
{
- odp_buffer_hdr_t *buf_hdr = odp_buf_to_hdr(buf);
- pool_entry_t *pool = odp_buf_to_pool(buf_hdr);
+ uint32_t pool_id, num;
+ local_cache_t *buf_cache;
+ pool_entry_t *pool;
+ int i, j, idx;
+
+ for (i = 0; i < num_buf; i++) {
+ pool_id = pool_handle_to_index(buf_hdr[i]->pool_hdl);
+ buf_cache = local.cache[pool_id];
+ num = buf_cache->s.num_buf;
- ODP_ASSERT(buf_hdr->allocator != ODP_FREEBUF);
+ if (num < POOL_MAX_LOCAL_BUFS) {
+ ret_local_buf(buf_cache, num, buf_hdr[i]);
+ continue;
+ }
+
+ idx = POOL_MAX_LOCAL_BUFS - POOL_CHUNK_SIZE;
+ pool = get_pool_entry(pool_id);
+
+ /* local cache full, return a chunk */
+ for (j = 0; j < POOL_CHUNK_SIZE; j++) {
+ odp_buffer_hdr_t *tmp;
+
+ tmp = buf_cache->s.buf[idx + i];
+ ret_buf(&pool->s, tmp);
+ }
- if (odp_unlikely(pool->s.buf_low_wm_assert ||
pool->s.blk_low_wm_assert))
- ret_buf(&pool->s, buf_hdr);
- else
- ret_local_buf(&pool->s.local_cache[local_id], buf_hdr);
+ num = POOL_MAX_LOCAL_BUFS - POOL_CHUNK_SIZE;
+ buf_cache->s.num_buf = num;
+ ret_local_buf(buf_cache, num, buf_hdr[i]);
+ }
}
-void odp_buffer_free_multi(const odp_buffer_t buf[], int num)
+void buffer_free_multi(uint32_t pool_id,
+ const odp_buffer_t buf[], int num_free)
{
- int i;
+ local_cache_t *buf_cache = local.cache[pool_id];
+ uint32_t num;
+ int i, idx;
+ pool_entry_t *pool;
+ odp_buffer_hdr_t *buf_hdr[num_free];
+ int multi_pool = 0;
+
+ for (i = 0; i < num_free; i++) {
+ uint32_t id;
+
+ buf_hdr[i] = odp_buf_to_hdr(buf[i]);
+ ODP_ASSERT(buf_hdr[i]->allocator != ODP_FREEBUF);
+ buf_hdr[i]->allocator = ODP_FREEBUF;
+ id = pool_handle_to_index(buf_hdr[i]->pool_hdl);
+ multi_pool |= (pool_id != id);
+ }
+
+ if (odp_unlikely(multi_pool)) {
+ multi_pool_free(buf_hdr, num_free);
+ return;
+ }
+
+ num = buf_cache->s.num_buf;
+
+ if (odp_likely((num + num_free) < POOL_MAX_LOCAL_BUFS)) {
+ ret_local_bufs(buf_cache, num, buf_hdr, num_free);
+ return;
+ }
+
+ pool = get_pool_entry(pool_id);
+
+ /* Return at least one chunk into the global pool */
+ if (odp_unlikely(num_free > POOL_CHUNK_SIZE)) {
+ for (i = 0; i < num_free; i++)
+ ret_buf(&pool->s, buf_hdr[i]);
+
+ return;
+ }
+
+ idx = num - POOL_CHUNK_SIZE;
+ for (i = 0; i < POOL_CHUNK_SIZE; i++)
+ ret_buf(&pool->s, buf_cache->s.buf[idx + i]);
- for (i = 0; i < num; ++i)
- odp_buffer_free(buf[i]);
+ num -= POOL_CHUNK_SIZE;
+ buf_cache->s.num_buf = num;
+ ret_local_bufs(buf_cache, num, buf_hdr, num_free);
+
+ return;
}
-void _odp_flush_caches(void)
+void odp_buffer_free(odp_buffer_t buf)
{
- int i;
+ uint32_t pool_id = pool_id_from_buf(buf);
- for (i = 0; i < ODP_CONFIG_POOLS; i++) {
- pool_entry_t *pool = get_pool_entry(i);
- flush_cache(&pool->s.local_cache[local_id], &pool->s);
- }
+ buffer_free_multi(pool_id, &buf, 1);
+}
+
+void odp_buffer_free_multi(const odp_buffer_t buf[], int num)
+{
+ uint32_t pool_id = pool_id_from_buf(buf[0]);
+
+ buffer_free_multi(pool_id, buf, num);
}
void odp_pool_print(odp_pool_t pool_hdl)
@@ -773,7 +1021,6 @@ void odp_pool_print(odp_pool_t pool_hdl)
pool->s.quiesced ? "quiesced" : "active");
ODP_DBG(" pool opts %s, %s, %s\n",
pool->s.flags.unsegmented ? "unsegmented" : "segmented",
- pool->s.flags.zeroized ? "zeroized" : "non-zeroized",
pool->s.flags.predefined ? "predefined" : "created");
ODP_DBG(" pool base %p\n", pool->s.pool_base_addr);
ODP_DBG(" pool size %zu (%zu pages)\n",
@@ -816,10 +1063,11 @@ void odp_pool_print(odp_pool_t pool_hdl)
ODP_DBG(" blk low wm count %lu\n", blklowmct);
}
-
odp_pool_t odp_buffer_pool(odp_buffer_t buf)
{
- return odp_buf_to_hdr(buf)->pool_hdl;
+ uint32_t pool_id = pool_id_from_buf(buf);
+
+ return pool_index_to_handle(pool_id);
}
void odp_pool_param_init(odp_pool_param_t *params)
diff --git a/platform/linux-generic/pktio/dpdk.c
b/platform/linux-generic/pktio/dpdk.c
index c21c703..17d63df 100644
--- a/platform/linux-generic/pktio/dpdk.c
+++ b/platform/linux-generic/pktio/dpdk.c
@@ -696,7 +696,7 @@ static int dpdk_stop(pktio_entry_t *pktio_entry)
static inline int mbuf_to_pkt(pktio_entry_t *pktio_entry,
odp_packet_t pkt_table[],
struct rte_mbuf *mbuf_table[],
- uint16_t num, odp_time_t *ts)
+ uint16_t mbuf_num, odp_time_t *ts)
{
odp_packet_t pkt;
odp_packet_hdr_t *pkt_hdr;
@@ -705,9 +705,15 @@ static inline int mbuf_to_pkt(pktio_entry_t *pktio_entry,
void *buf;
int i, j;
int nb_pkts = 0;
+ int alloc_len, num;
+ odp_pool_t pool = pktio_entry->s.pkt_dpdk.pool;
+
+ /* Allocate maximum sized packets */
+ alloc_len = pktio_entry->s.pkt_dpdk.data_room;
+
+ num = packet_alloc_multi(pool, alloc_len, pkt_table, mbuf_num);
for (i = 0; i < num; i++) {
- odp_pool_t pool = pktio_entry->s.pkt_dpdk.pool;
odp_packet_hdr_t parsed_hdr;
mbuf = mbuf_table[i];
@@ -728,18 +734,16 @@ static inline int mbuf_to_pkt(pktio_entry_t *pktio_entry,
&parsed_hdr))
goto fail;
}
- pkt = packet_alloc(pool, pkt_len, 1);
- if (pkt == ODP_PACKET_INVALID)
- goto fail;
+ pkt = pkt_table[i];
pkt_hdr = odp_packet_hdr(pkt);
+ pull_tail(pkt_hdr, alloc_len - pkt_len);
/* For now copy the data in the mbuf,
worry about zero-copy later */
- if (odp_packet_copy_from_mem(pkt, 0, pkt_len, buf) != 0) {
- odp_packet_free(pkt);
+ if (odp_packet_copy_from_mem(pkt, 0, pkt_len, buf) != 0)
goto fail;
- }
+
pkt_hdr->input = pktio_entry->s.handle;
if (pktio_cls_enabled(pktio_entry))
@@ -760,7 +764,9 @@ static inline int mbuf_to_pkt(pktio_entry_t *pktio_entry,
return nb_pkts;
fail:
- for (j = i; j < num; j++)
+ odp_packet_free_multi(&pkt_table[i], mbuf_num - i);
+
+ for (j = i; j < mbuf_num; j++)
rte_pktmbuf_free(mbuf_table[j]);
return (i > 0 ? i : -1);
diff --git a/platform/linux-generic/pktio/netmap.c
b/platform/linux-generic/pktio/netmap.c
index d69df6b..67e50b7 100644
--- a/platform/linux-generic/pktio/netmap.c
+++ b/platform/linux-generic/pktio/netmap.c
@@ -598,6 +598,7 @@ static inline int netmap_pkt_to_odp(pktio_entry_t
*pktio_entry,
odp_pool_t pool = pktio_entry->s.pkt_nm.pool;
odp_packet_hdr_t *pkt_hdr;
odp_packet_hdr_t parsed_hdr;
+ int num;
if (odp_unlikely(len > pktio_entry->s.pkt_nm.max_frame_len)) {
ODP_ERR("RX: frame too big %" PRIu16 " %zu!\n", len,
@@ -615,8 +616,8 @@ static inline int netmap_pkt_to_odp(pktio_entry_t
*pktio_entry,
len, &pool, &parsed_hdr))
return -1;
}
- pkt = packet_alloc(pool, len, 1);
- if (pkt == ODP_PACKET_INVALID)
+ num = packet_alloc_multi(pool, len, &pkt, 1);
+ if (num != 1)
return -1;
pkt_hdr = odp_packet_hdr(pkt);
diff --git a/platform/linux-generic/pktio/pcap.c
b/platform/linux-generic/pktio/pcap.c
index be9049a..f6db809 100644
--- a/platform/linux-generic/pktio/pcap.c
+++ b/platform/linux-generic/pktio/pcap.c
@@ -224,19 +224,9 @@ static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, int
index ODP_UNUSED,
pktio_entry->s.config.pktin.bit.ts_ptp)
ts = &ts_val;
- pkt = ODP_PACKET_INVALID;
- pkt_len = 0;
-
for (i = 0; i < len; ) {
int ret;
- if (pkt == ODP_PACKET_INVALID) {
- pkt = packet_alloc(pcap->pool, 0 /*default len*/, 1);
- if (odp_unlikely(pkt == ODP_PACKET_INVALID))
- break;
- pkt_len = odp_packet_len(pkt);
- }
-
ret = pcap_next_ex(pcap->rx, &hdr, &data);
/* end of file, attempt to reopen if within loop limit */
@@ -246,17 +236,17 @@ static int pcapif_recv_pkt(pktio_entry_t *pktio_entry,
int index ODP_UNUSED,
if (ret != 1)
break;
+ pkt_len = hdr->caplen;
+
+ ret = packet_alloc_multi(pcap->pool, pkt_len, &pkt, 1);
+ if (odp_unlikely(ret != 1))
+ break;
+
if (ts != NULL)
ts_val = odp_time_global();
pkt_hdr = odp_packet_hdr(pkt);
- if (!odp_packet_pull_tail(pkt, pkt_len - hdr->caplen)) {
- ODP_ERR("failed to pull tail: pkt_len: %d caplen: %d\n",
- pkt_len, hdr->caplen);
- break;
- }
-
if (odp_packet_copy_from_mem(pkt, 0, hdr->caplen, data) != 0) {
ODP_ERR("failed to copy packet data\n");
break;
@@ -269,7 +259,6 @@ static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, int
index ODP_UNUSED,
pkt_hdr->input = pktio_entry->s.handle;
pkts[i] = pkt;
- pkt = ODP_PACKET_INVALID;
i++;
}
@@ -277,9 +266,6 @@ static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, int
index ODP_UNUSED,
odp_ticketlock_unlock(&pktio_entry->s.rxl);
- if (pkt != ODP_PACKET_INVALID)
- odp_packet_free(pkt);
-
return i;
}
diff --git a/platform/linux-generic/pktio/socket.c
b/platform/linux-generic/pktio/socket.c
index 5d85ef5..58d9c5c 100644
--- a/platform/linux-generic/pktio/socket.c
+++ b/platform/linux-generic/pktio/socket.c
@@ -657,6 +657,7 @@ static int sock_mmsg_recv(pktio_entry_t *pktio_entry, int
index ODP_UNUSED,
void *base = msgvec[i].msg_hdr.msg_iov->iov_base;
struct ethhdr *eth_hdr = base;
uint16_t pkt_len = msgvec[i].msg_len;
+ int num;
/* Don't receive packets sent by ourselves */
if (odp_unlikely(ethaddrs_equal(pkt_sock->if_mac,
@@ -666,8 +667,8 @@ static int sock_mmsg_recv(pktio_entry_t *pktio_entry, int
index ODP_UNUSED,
if (cls_classify_packet(pktio_entry, base, pkt_len,
pkt_len, &pool, &parsed_hdr))
continue;
- pkt = packet_alloc(pool, pkt_len, 1);
- if (pkt == ODP_PACKET_INVALID)
+ num = packet_alloc_multi(pool, pkt_len, &pkt, 1);
+ if (num != 1)
continue;
pkt_hdr = odp_packet_hdr(pkt);
@@ -688,10 +689,15 @@ static int sock_mmsg_recv(pktio_entry_t *pktio_entry, int
index ODP_UNUSED,
[ODP_BUFFER_MAX_SEG];
for (i = 0; i < (int)len; i++) {
- pkt_table[i] = packet_alloc(pkt_sock->pool,
- 0 /*default*/, 1);
- if (odp_unlikely(pkt_table[i] == ODP_PACKET_INVALID))
+ int num;
+
+ num = packet_alloc_multi(pkt_sock->pool,
+ 1518 /* max eth frame len */,
+ &pkt_table[i], 1);
+ if (odp_unlikely(num != 1)) {
+ pkt_table[i] = ODP_PACKET_INVALID;
break;
+ }
msgvec[i].msg_hdr.msg_iovlen =
_rx_pkt_to_iovec(pkt_table[i], iovecs[i]);
diff --git a/platform/linux-generic/pktio/socket_mmap.c
b/platform/linux-generic/pktio/socket_mmap.c
index 11bb7d6..9e84e4a 100644
--- a/platform/linux-generic/pktio/socket_mmap.c
+++ b/platform/linux-generic/pktio/socket_mmap.c
@@ -169,6 +169,7 @@ static inline unsigned pkt_mmap_v2_rx(pktio_entry_t
*pktio_entry,
odp_packet_hdr_t *hdr;
odp_packet_hdr_t parsed_hdr;
odp_pool_t pool = pkt_sock->pool;
+ int num;
if (!mmap_rx_kernel_ready(ring->rd[frame_num].iov_base))
break;
@@ -206,8 +207,10 @@ static inline unsigned pkt_mmap_v2_rx(pktio_entry_t
*pktio_entry,
}
}
- pkt_table[nb_rx] = packet_alloc(pool, pkt_len, 1);
- if (odp_unlikely(pkt_table[nb_rx] == ODP_PACKET_INVALID)) {
+ num = packet_alloc_multi(pool, pkt_len, &pkt_table[nb_rx], 1);
+
+ if (odp_unlikely(num != 1)) {
+ pkt_table[nb_rx] = ODP_PACKET_INVALID;
mmap_rx_user_ready(ppd.raw); /* drop */
frame_num = next_frame_num;
continue;
diff --git a/platform/linux-generic/pktio/tap.c
b/platform/linux-generic/pktio/tap.c
index a9a8886..d758a39 100644
--- a/platform/linux-generic/pktio/tap.c
+++ b/platform/linux-generic/pktio/tap.c
@@ -185,11 +185,12 @@ static odp_packet_t pack_odp_pkt(pktio_entry_t
*pktio_entry, const void *data,
{
odp_packet_t pkt;
odp_packet_hdr_t *pkt_hdr;
+ int num;
- pkt = packet_alloc(pktio_entry->s.pkt_tap.pool, len, 1);
+ num = packet_alloc_multi(pktio_entry->s.pkt_tap.pool, len, &pkt, 1);
- if (pkt == ODP_PACKET_INVALID)
- return pkt;
+ if (num != 1)
+ return ODP_PACKET_INVALID;
if (odp_packet_copy_from_mem(pkt, 0, len, data) < 0) {
ODP_ERR("failed to copy packet data\n");
--
2.8.1