[dpdk-dev,v2,1/2] malloc: add biggest free IOVA-contiguous element to stats
Checks
Commit Message
User might be interested to find out what is the biggest chunk of
IOVA-contiguous free space that can be allocated from malloc. Add
relevant malloc-internal functions and expose this through malloc
stats calculation call.
Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
---
Notes:
v2:
- Add header to newly recalculated element start
lib/librte_eal/common/include/rte_malloc.h | 1 +
lib/librte_eal/common/malloc_elem.c | 59 ++++++++++++++++++++++++++++++
lib/librte_eal/common/malloc_elem.h | 3 ++
lib/librte_eal/common/malloc_heap.c | 8 ++++
lib/librte_eal/common/rte_malloc.c | 2 +
5 files changed, 73 insertions(+)
Comments
This patchset does two things. First, it enables reserving
memzones of zero-length that are IOVA-contiguous. Second,
it fixes a long-standing race condition in reserving
zero-length memzones, where malloc heap is not locked between
stats collection and reservation, and will instead allocate
biggest element on the spot.
Some limitations are added, but they are a trade-off between
not having race conditions and user convenience. It would be
possible to lock all heaps during memzone reserve for zero-
length, and that would keep the old behavior, but given how
such allocation (especially when asking for IOVA-contiguous
memory) may take a long time, a design decision was made to
keep things simple, and only check other heaps if the
current one is completely busy.
Ideas on improvement are welcome.
Anatoly Burakov (3):
malloc: add biggest free IOVA-contiguous element to stats
malloc: allow reserving biggest element
memzone: improve zero-length memzone reserve
lib/librte_eal/common/eal_common_memzone.c | 62 ++---------
lib/librte_eal/common/include/rte_malloc.h | 1 +
lib/librte_eal/common/include/rte_memzone.h | 18 ++++
lib/librte_eal/common/malloc_elem.c | 77 ++++++++++++++
lib/librte_eal/common/malloc_elem.h | 6 ++
lib/librte_eal/common/malloc_heap.c | 137 ++++++++++++++++++++++++
lib/librte_eal/common/malloc_heap.h | 4 +
lib/librte_eal/common/rte_malloc.c | 2 +
test/test/test_memzone.c | 157 +++++++++++++++-------------
9 files changed, 342 insertions(+), 122 deletions(-)
This patchset does two things. First, it enables reserving
memzones of zero-length that are IOVA-contiguous. Second,
it fixes a long-standing race condition in reserving
zero-length memzones, where malloc heap is not locked between
stats collection and reservation, and will instead allocate
biggest element on the spot.
Some limitations are added, but they are a trade-off between
not having race conditions and user convenience. It would be
possible to lock all heaps during memzone reserve for zero-
length, and that would keep the old behavior, but given how
such allocation (especially when asking for IOVA-contiguous
memory) may take a long time, a design decision was made to
keep things simple, and only check other heaps if the
current one is completely busy.
Ideas on improvement are welcome.
v4:
- Fixes in memzone test
- Account for element padding
- Fix for wrong memzone size being returned
- Documentation fixes
Anatoly Burakov (3):
malloc: add biggest free IOVA-contiguous element to stats
malloc: allow reserving biggest element
memzone: improve zero-length memzone reserve
lib/librte_eal/common/eal_common_memzone.c | 68 +++---------
lib/librte_eal/common/include/rte_malloc.h | 1 +
lib/librte_eal/common/include/rte_memzone.h | 21 ++++
lib/librte_eal/common/malloc_elem.c | 79 +++++++++++++
lib/librte_eal/common/malloc_elem.h | 6 +
lib/librte_eal/common/malloc_heap.c | 137 +++++++++++++++++++++++
lib/librte_eal/common/malloc_heap.h | 4 +
lib/librte_eal/common/rte_malloc.c | 2 +
test/test/test_memzone.c | 165 ++++++++++++++++------------
9 files changed, 358 insertions(+), 125 deletions(-)
This patchset does two things. First, it enables reserving
memzones of zero-length that are IOVA-contiguous. Second,
it fixes a long-standing race condition in reserving
zero-length memzones, where malloc heap is not locked between
stats collection and reservation, and will instead allocate
biggest element on the spot.
Some limitations are added, but they are a trade-off between
not having race conditions and user convenience. It would be
possible to lock all heaps during memzone reserve for zero-
length, and that would keep the old behavior, but given how
such allocation (especially when asking for IOVA-contiguous
memory) may take a long time, a design decision was made to
keep things simple, and only check other heaps if the
current one is completely busy.
Ideas on improvement are welcome.
v5:
- Use bound length if reserving memzone with zero length
v4:
- Fixes in memzone test
- Account for element padding
- Fix for wrong memzone size being returned
- Documentation fixes
Anatoly Burakov (3):
malloc: add biggest free IOVA-contiguous element to stats
malloc: allow reserving biggest element
memzone: improve zero-length memzone reserve
lib/librte_eal/common/eal_common_memzone.c | 70 +++---------
lib/librte_eal/common/include/rte_malloc.h | 1 +
lib/librte_eal/common/include/rte_memzone.h | 21 ++++
lib/librte_eal/common/malloc_elem.c | 79 +++++++++++++
lib/librte_eal/common/malloc_elem.h | 6 +
lib/librte_eal/common/malloc_heap.c | 137 +++++++++++++++++++++++
lib/librte_eal/common/malloc_heap.h | 4 +
lib/librte_eal/common/rte_malloc.c | 2 +
test/test/test_memzone.c | 165 ++++++++++++++++------------
9 files changed, 360 insertions(+), 125 deletions(-)
This patchset does two things. First, it enables reserving
memzones of zero-length that are IOVA-contiguous. Second,
it fixes a long-standing race condition in reserving
zero-length memzones, where malloc heap is not locked between
stats collection and reservation, and will instead allocate
biggest element on the spot.
Some limitations are added, but they are a trade-off between
not having race conditions and user convenience. It would be
possible to lock all heaps during memzone reserve for zero-
length, and that would keep the old behavior, but given how
such allocation (especially when asking for IOVA-contiguous
memory) may take a long time, a design decision was made to
keep things simple, and only check other heaps if the
current one is completely busy.
Ideas on improvement are welcome.
v6:
- Rebase on top of 18.05
- Dropped malloc stats changes as no deprecation notice was
sent, and i would like to integrate these changes in this
release :)
v5:
- Use bound length if reserving memzone with zero length
v4:
- Fixes in memzone test
- Account for element padding
- Fix for wrong memzone size being returned
- Documentation fixes
Anatoly Burakov (3):
malloc: add finding biggest free IOVA-contiguous element
malloc: allow reserving biggest element
memzone: improve zero-length memzone reserve
lib/librte_eal/common/eal_common_memzone.c | 70 ++-------
lib/librte_eal/common/include/rte_memzone.h | 24 ++-
lib/librte_eal/common/malloc_elem.c | 79 ++++++++++
lib/librte_eal/common/malloc_elem.h | 6 +
lib/librte_eal/common/malloc_heap.c | 126 +++++++++++++++
lib/librte_eal/common/malloc_heap.h | 4 +
test/test/test_memzone.c | 165 +++++++++++---------
7 files changed, 343 insertions(+), 131 deletions(-)
31/05/2018 11:50, Anatoly Burakov:
> This patchset does two things. First, it enables reserving
> memzones of zero-length that are IOVA-contiguous. Second,
> it fixes a long-standing race condition in reserving
> zero-length memzones, where malloc heap is not locked between
> stats collection and reservation, and will instead allocate
> biggest element on the spot.
>
> Some limitations are added, but they are a trade-off between
> not having race conditions and user convenience. It would be
> possible to lock all heaps during memzone reserve for zero-
> length, and that would keep the old behavior, but given how
> such allocation (especially when asking for IOVA-contiguous
> memory) may take a long time, a design decision was made to
> keep things simple, and only check other heaps if the
> current one is completely busy.
>
> Ideas on improvement are welcome.
>
> Anatoly Burakov (3):
> malloc: add finding biggest free IOVA-contiguous element
> malloc: allow reserving biggest element
> memzone: improve zero-length memzone reserve
Applied, thanks
@@ -27,6 +27,7 @@ struct rte_malloc_socket_stats {
size_t heap_totalsz_bytes; /**< Total bytes on heap */
size_t heap_freesz_bytes; /**< Total free bytes on heap */
size_t greatest_free_size; /**< Size in bytes of largest free block */
+ size_t greatest_free_iova_contig_size; /**< Size in bytes of largest IOVA-contiguous block */
unsigned free_count; /**< Number of free elements on heap */
unsigned alloc_count; /**< Number of allocated elements on heap */
size_t heap_allocsz_bytes; /**< Total allocated bytes on heap */
@@ -18,12 +18,71 @@
#include <rte_common.h>
#include <rte_spinlock.h>
+#include "eal_internal_cfg.h"
#include "eal_memalloc.h"
#include "malloc_elem.h"
#include "malloc_heap.h"
#define MIN_DATA_SIZE (RTE_CACHE_LINE_SIZE)
+size_t
+malloc_elem_find_max_iova_contig(struct malloc_elem *elem)
+{
+ void *cur_page, *contig_seg_start, *page_end, *elem_end, *cur_seg_end;
+ rte_iova_t expected_iova;
+ struct rte_memseg *ms;
+ size_t page_sz, cur, max;
+
+ /* if we're in IOVA as VA mode, or if we're in legacy mode with
+ * hugepages, all elements are IOVA-contiguous.
+ */
+ if (rte_eal_iova_mode() == RTE_IOVA_VA ||
+ (internal_config.legacy_mem && rte_eal_has_hugepages()))
+ return elem->size;
+
+ page_sz = (size_t)elem->msl->page_sz;
+ elem_end = RTE_PTR_ADD(elem, elem->size);
+ cur_page = RTE_PTR_ALIGN_FLOOR(elem, page_sz);
+ ms = rte_mem_virt2memseg(cur_page, elem->msl);
+ contig_seg_start = elem;
+
+ /* do first iteration outside the loop */
+ page_end = RTE_PTR_ADD(cur_page, page_sz);
+ cur_seg_end = RTE_MIN(page_end, elem_end);
+ cur = RTE_PTR_DIFF(cur_seg_end, contig_seg_start);
+ max = cur;
+ expected_iova = ms->iova + page_sz;
+ /* memsegs are contiguous in memory */
+ ms++;
+
+ cur_page = RTE_PTR_ADD(cur_page, page_sz);
+
+ while (cur_page < elem_end) {
+ page_end = RTE_PTR_ADD(cur_page, page_sz);
+ cur_seg_end = RTE_MIN(page_end, elem_end);
+
+ /* reset start of contiguous segment if unexpected iova. this is
+ * a contiguous segment, and elem->size includes header len, so
+ * move element start point to where header would've started
+ */
+ if (ms->iova != expected_iova)
+ contig_seg_start = RTE_PTR_SUB(cur_page,
+ MALLOC_ELEM_HEADER_LEN);
+ cur = RTE_PTR_DIFF(cur_seg_end, contig_seg_start);
+ /* update max if cur value is bigger */
+ if (cur > max)
+ max = cur;
+
+ /* move to next page */
+ cur_page = page_end;
+ expected_iova = ms->iova + page_sz;
+ /* memsegs are contiguous in memory */
+ ms++;
+ }
+
+ return max;
+}
+
/*
* Initialize a general malloc_elem header structure
*/
@@ -177,4 +177,7 @@ malloc_elem_free_list_index(size_t size);
void
malloc_elem_free_list_insert(struct malloc_elem *elem);
+size_t
+malloc_elem_find_max_iova_contig(struct malloc_elem *elem);
+
#endif /* MALLOC_ELEM_H_ */
@@ -764,16 +764,24 @@ malloc_heap_get_stats(struct malloc_heap *heap,
socket_stats->free_count = 0;
socket_stats->heap_freesz_bytes = 0;
socket_stats->greatest_free_size = 0;
+ socket_stats->greatest_free_iova_contig_size = 0;
/* Iterate through free list */
for (idx = 0; idx < RTE_HEAP_NUM_FREELISTS; idx++) {
for (elem = LIST_FIRST(&heap->free_head[idx]);
!!elem; elem = LIST_NEXT(elem, free_list))
{
+ size_t iova_contig_sz;
socket_stats->free_count++;
socket_stats->heap_freesz_bytes += elem->size;
if (elem->size > socket_stats->greatest_free_size)
socket_stats->greatest_free_size = elem->size;
+ iova_contig_sz =
+ malloc_elem_find_max_iova_contig(elem);
+ if (iova_contig_sz >
+ socket_stats->greatest_free_iova_contig_size)
+ socket_stats->greatest_free_iova_contig_size =
+ iova_contig_sz;
}
}
/* Get stats on overall heap and allocated memory on this heap */
@@ -195,6 +195,8 @@ rte_malloc_dump_stats(FILE *f, __rte_unused const char *type)
fprintf(f, "\tAlloc_size:%zu,\n", sock_stats.heap_allocsz_bytes);
fprintf(f, "\tGreatest_free_size:%zu,\n",
sock_stats.greatest_free_size);
+ fprintf(f, "\tGreatest_free_iova_contig_size:%zu,\n",
+ sock_stats.greatest_free_iova_contig_size);
fprintf(f, "\tAlloc_count:%u,\n",sock_stats.alloc_count);
fprintf(f, "\tFree_count:%u,\n", sock_stats.free_count);
}