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.bura...@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        | 77 ++++++++++++++++++++++++++++++
 lib/librte_eal/common/malloc_elem.h        |  6 +++
 lib/librte_eal/common/malloc_heap.c        | 11 +++++
 lib/librte_eal/common/rte_malloc.c         |  2 +
 5 files changed, 97 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_malloc.h 
b/lib/librte_eal/common/include/rte_malloc.h
index a9fb7e4..2553201 100644
--- a/lib/librte_eal/common/include/rte_malloc.h
+++ b/lib/librte_eal/common/include/rte_malloc.h
@@ -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 */
diff --git a/lib/librte_eal/common/malloc_elem.c 
b/lib/librte_eal/common/malloc_elem.c
index 9bfe9b9..d330fb1 100644
--- a/lib/librte_eal/common/malloc_elem.c
+++ b/lib/librte_eal/common/malloc_elem.c
@@ -18,10 +18,87 @@
 #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"
 
+size_t
+malloc_elem_find_max_iova_contig(struct malloc_elem *elem, size_t align)
+{
+       void *cur_page, *contig_seg_start, *page_end, *cur_seg_end;
+       void *data_start, *data_end;
+       rte_iova_t expected_iova;
+       struct rte_memseg *ms;
+       size_t page_sz, cur, max;
+
+       page_sz = (size_t)elem->msl->page_sz;
+       data_start = RTE_PTR_ADD(elem, MALLOC_ELEM_HEADER_LEN);
+       data_end = RTE_PTR_ADD(elem, elem->size - MALLOC_ELEM_TRAILER_LEN);
+       /* segment must start after header and with specified alignment */
+       contig_seg_start = RTE_PTR_ALIGN_CEIL(data_start, align);
+
+       /* 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 RTE_PTR_DIFF(data_end, contig_seg_start);
+
+       cur_page = RTE_PTR_ALIGN_FLOOR(contig_seg_start, page_sz);
+       ms = rte_mem_virt2memseg(cur_page, elem->msl);
+
+       /* do first iteration outside the loop */
+       page_end = RTE_PTR_ADD(cur_page, page_sz);
+       cur_seg_end = RTE_MIN(page_end, data_end);
+       cur = RTE_PTR_DIFF(cur_seg_end, contig_seg_start) -
+                       MALLOC_ELEM_TRAILER_LEN;
+       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 < data_end) {
+               page_end = RTE_PTR_ADD(cur_page, page_sz);
+               cur_seg_end = RTE_MIN(page_end, data_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) {
+                       /* next contiguous segment must start at specified
+                        * alignment.
+                        */
+                       contig_seg_start = RTE_PTR_ALIGN(cur_page, align);
+                       /* new segment start may be on a different page, so find
+                        * the page and skip to next iteration to make sure
+                        * we're not blowing past data end.
+                        */
+                       ms = rte_mem_virt2memseg(contig_seg_start, elem->msl);
+                       cur_page = ms->addr;
+                       /* don't trigger another recalculation */
+                       expected_iova = ms->iova;
+                       continue;
+               }
+               cur = RTE_PTR_DIFF(cur_seg_end, contig_seg_start) -
+                               MALLOC_ELEM_TRAILER_LEN;
+               /* 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
  */
diff --git a/lib/librte_eal/common/malloc_elem.h 
b/lib/librte_eal/common/malloc_elem.h
index 7331af9..e2bda4c 100644
--- a/lib/librte_eal/common/malloc_elem.h
+++ b/lib/librte_eal/common/malloc_elem.h
@@ -179,4 +179,10 @@ malloc_elem_free_list_index(size_t size);
 void
 malloc_elem_free_list_insert(struct malloc_elem *elem);
 
+/*
+ * Find biggest IOVA-contiguous zone within an element with specified 
alignment.
+ */
+size_t
+malloc_elem_find_max_iova_contig(struct malloc_elem *elem, size_t align);
+
 #endif /* MALLOC_ELEM_H_ */
diff --git a/lib/librte_eal/common/malloc_heap.c 
b/lib/librte_eal/common/malloc_heap.c
index d6cf3af..9305b38 100644
--- a/lib/librte_eal/common/malloc_heap.c
+++ b/lib/librte_eal/common/malloc_heap.c
@@ -803,16 +803,27 @@ 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,
+                                                       RTE_CACHE_LINE_SIZE);
+                       /* find_max_iova_contig doesn't include overhead */
+                       iova_contig_sz += MALLOC_ELEM_OVERHEAD;
+                       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 */
diff --git a/lib/librte_eal/common/rte_malloc.c 
b/lib/librte_eal/common/rte_malloc.c
index b51a6d1..b4e87a3 100644
--- a/lib/librte_eal/common/rte_malloc.c
+++ b/lib/librte_eal/common/rte_malloc.c
@@ -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);
        }
-- 
2.7.4

Reply via email to