From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id D19A61C87B for ; Mon, 14 May 2018 15:47:33 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 14 May 2018 06:47:32 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,400,1520924400"; d="scan'208";a="55748030" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga001.jf.intel.com with ESMTP; 14 May 2018 06:47:31 -0700 Received: from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com [10.237.217.45]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id w4EDlV16028232; Mon, 14 May 2018 14:47:31 +0100 Received: from sivswdev01.ir.intel.com (localhost [127.0.0.1]) by sivswdev01.ir.intel.com with ESMTP id w4EDlVxi024166; Mon, 14 May 2018 14:47:31 +0100 Received: (from aburakov@localhost) by sivswdev01.ir.intel.com with LOCAL id w4EDlV4I024162; Mon, 14 May 2018 14:47:31 +0100 From: Anatoly Burakov To: dev@dpdk.org Cc: remy.horton@intel.com Date: Mon, 14 May 2018 14:47:28 +0100 Message-Id: <064458eb7fc48457ed4e7fed521e11e68cb32c62.1526305599.git.anatoly.burakov@intel.com> X-Mailer: git-send-email 1.7.0.7 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [PATCH v5 1/3] malloc: add biggest free IOVA-contiguous element to stats 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: , X-List-Received-Date: Mon, 14 May 2018 13:47:34 -0000 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 Acked-by: Remy Horton --- Notes: v4: - Fix comments to be more up to date with v4 code - Add comments explaining trailer handling v2: - Add header to newly recalculated element start v2: - Add header to newly recalculated element start lib/librte_eal/common/include/rte_malloc.h | 1 + lib/librte_eal/common/malloc_elem.c | 79 ++++++++++++++++++++++++++++++ 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, 99 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..f1bb4fe 100644 --- a/lib/librte_eal/common/malloc_elem.c +++ b/lib/librte_eal/common/malloc_elem.c @@ -18,10 +18,89 @@ #include #include +#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 */ + 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_seg_end ends on a page boundary or on data end. if we're + * looking at data end, then malloc trailer is already included + * in the calculations. if we're looking at page end, then we + * know there's more data past this page and thus there's space + * for malloc element trailer, so don't count it here. + */ + 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 */ 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