From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) by dpdk.org (Postfix) with ESMTP id D6E9B2C37 for ; Fri, 30 Jun 2017 18:12:34 +0200 (CEST) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id 8D05920B2E; Fri, 30 Jun 2017 12:12:34 -0400 (EDT) Received: from frontend1 ([10.202.2.160]) by compute1.internal (MEProxy); Fri, 30 Jun 2017 12:12:34 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=monjalon.net; h= cc:date:from:in-reply-to:message-id:references:subject:to :x-me-sender:x-me-sender:x-sasl-enc:x-sasl-enc; s=mesmtp; bh=FHg 0o05r265hfUTgRd4dOfkMDlt8T6oZm9EKVKyRV6Q=; b=YKyEaeF7538ymFvxKTc Q9jQ9R7mCdQwaEdbxmn1mOVH4K5PeKgM2f94mujcuMPL9i1yPzhEXZhNFk6QYlPE n3kOQlaPrPRHNcr5ND8iORQFpNgwWOk6S9CpHJxYFiE4bBS0ARl2ysdi+Cpt5pOn /osmNHcZJozJFYXtJtHXHVxk= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:date:from:in-reply-to:message-id :references:subject:to:x-me-sender:x-me-sender:x-sasl-enc :x-sasl-enc; s=fm1; bh=FHg0o05r265hfUTgRd4dOfkMDlt8T6oZm9EKVKyRV 6Q=; b=VD6I741JPlE3yZJyyK30DG95+DMgHgd/l7oQn5WVQFRHvywrItLTe9dG0 pJUjBPRuK5j7XlE3lyaH2XLZ/0YI7osKhy9iTmcKJQcodgdshhMM+hilyHeJ1zgG YkqcolpO3Ha1S58Lf8ANchlwtVLwvuF+Xr7Y2GMd4Zo6yFEeIha2XxqNyNFyWLI7 pA30SnVuy6vAG0QZbDh5WcCejuMRULSO0itomBZHSUmWj0awKZ4yuEtAYWt2wvsX 8lc5ovjnOQvg6o33yYVvrbnQAqP2YHdIphozNPFaqZOD3J6UHOXUtSm4zzxD8ZNv Ki+0hJrEwe4ZLZI6lmtLbUTLL7m4Q== X-ME-Sender: X-Sasl-enc: uV8MFSJ81s4u4Q6eAh8i9S0j3s+p4M6yyVM1hV4SEvW8 1498839154 Received: from xps.monjalon.net (184.203.134.77.rev.sfr.net [77.134.203.184]) by mail.messagingengine.com (Postfix) with ESMTPA id 0C0457E815; Fri, 30 Jun 2017 12:12:33 -0400 (EDT) From: Thomas Monjalon To: Ilya Maximets Cc: dev@dpdk.org Date: Fri, 30 Jun 2017 18:12:23 +0200 Message-Id: <20170630161224.7532-2-thomas@monjalon.net> X-Mailer: git-send-email 2.13.1 In-Reply-To: <20170630161224.7532-1-thomas@monjalon.net> References: <1498715960-2668-1-git-send-email-i.maximets@samsung.com> <20170630161224.7532-1-thomas@monjalon.net> Subject: [dpdk-dev] [PATCH v11 1/2] mem: balanced allocation of hugepages 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: Fri, 30 Jun 2017 16:12:35 -0000 From: Ilya Maximets Currently EAL allocates hugepages one by one not paying attention from which NUMA node allocation was done. Such behaviour leads to allocation failure if number of available hugepages for application limited by cgroups or hugetlbfs and memory requested not only from the first socket. Example: # 90 x 1GB hugepages availavle in a system cgcreate -g hugetlb:/test # Limit to 32GB of hugepages cgset -r hugetlb.1GB.limit_in_bytes=34359738368 test # Request 4GB from each of 2 sockets cgexec -g hugetlb:test testpmd --socket-mem=4096,4096 ... EAL: SIGBUS: Cannot mmap more hugepages of size 1024 MB EAL: 32 not 90 hugepages of size 1024 MB allocated EAL: Not enough memory available on socket 1! Requested: 4096MB, available: 0MB PANIC in rte_eal_init(): Cannot init memory This happens beacause all allocated pages are on socket 0. Fix this issue by setting mempolicy MPOL_PREFERRED for each hugepage to one of requested nodes using following schema: 1) Allocate essential hugepages: 1.1) Allocate as many hugepages from numa N to only fit requested memory for this numa. 1.2) repeat 1.1 for all numa nodes. 2) Try to map all remaining free hugepages in a round-robin fashion. 3) Sort pages and choose the most suitable. In this case all essential memory will be allocated and all remaining pages will be fairly distributed between all requested nodes. New config option RTE_EAL_NUMA_AWARE_HUGEPAGES introduced and enabled by default for linuxapp except armv7 and dpaa2. Enabling of this option adds libnuma as a dependency for EAL. Fixes: 77988fc08dc5 ("mem: fix allocating all free hugepages") Signed-off-by: Ilya Maximets Acked-by: Sergio Gonzalez Monroy Acked-by: Hemant Agrawal Acked-by: Jerin Jacob Tested-by: Jerin Jacob --- config/common_base | 1 + config/common_linuxapp | 1 + config/defconfig_arm-armv7a-linuxapp-gcc | 3 + config/defconfig_arm64-dpaa2-linuxapp-gcc | 3 + devtools/test-build.sh | 6 +- lib/librte_eal/linuxapp/eal/Makefile | 3 + lib/librte_eal/linuxapp/eal/eal_memory.c | 120 ++++++++++++++++++++++++++++-- mk/rte.app.mk | 3 + 8 files changed, 129 insertions(+), 11 deletions(-) diff --git a/config/common_base b/config/common_base index f6aafd17d..660588a3d 100644 --- a/config/common_base +++ b/config/common_base @@ -103,6 +103,7 @@ CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n CONFIG_RTE_EAL_IGB_UIO=n CONFIG_RTE_EAL_VFIO=n CONFIG_RTE_MALLOC_DEBUG=n +CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=n # # Recognize/ignore the AVX/AVX512 CPU flags for performance/power testing. diff --git a/config/common_linuxapp b/config/common_linuxapp index b3cf41b01..64bef87af 100644 --- a/config/common_linuxapp +++ b/config/common_linuxapp @@ -35,6 +35,7 @@ CONFIG_RTE_EXEC_ENV="linuxapp" CONFIG_RTE_EXEC_ENV_LINUXAPP=y +CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=y CONFIG_RTE_EAL_IGB_UIO=y CONFIG_RTE_EAL_VFIO=y CONFIG_RTE_KNI_KMOD=y diff --git a/config/defconfig_arm-armv7a-linuxapp-gcc b/config/defconfig_arm-armv7a-linuxapp-gcc index 19607eb67..e06b1d441 100644 --- a/config/defconfig_arm-armv7a-linuxapp-gcc +++ b/config/defconfig_arm-armv7a-linuxapp-gcc @@ -47,6 +47,9 @@ CONFIG_RTE_ARCH_STRICT_ALIGN=y CONFIG_RTE_TOOLCHAIN="gcc" CONFIG_RTE_TOOLCHAIN_GCC=y +# NUMA is not supported on ARM +CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=n + # ARM doesn't have support for vmware TSC map CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=n diff --git a/config/defconfig_arm64-dpaa2-linuxapp-gcc b/config/defconfig_arm64-dpaa2-linuxapp-gcc index 2304ab607..d17201b1e 100644 --- a/config/defconfig_arm64-dpaa2-linuxapp-gcc +++ b/config/defconfig_arm64-dpaa2-linuxapp-gcc @@ -45,6 +45,9 @@ CONFIG_RTE_CACHE_LINE_SIZE=64 CONFIG_RTE_PKTMBUF_HEADROOM=256 +# Doesn't support NUMA +CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=n + # # Compile Support Libraries for DPAA2 # diff --git a/devtools/test-build.sh b/devtools/test-build.sh index 61bdce7cc..079c8b8f8 100755 --- a/devtools/test-build.sh +++ b/devtools/test-build.sh @@ -41,7 +41,7 @@ default_path=$PATH # - DPDK_DEP_ISAL_CRYPTO (y/[n]) # - DPDK_DEP_LDFLAGS # - DPDK_DEP_MOFED (y/[n]) -# - DPDK_DEP_NUMA (y/[n]) +# - DPDK_DEP_NUMA ([y]/n) # - DPDK_DEP_PCAP (y/[n]) # - DPDK_DEP_SSL (y/[n]) # - DPDK_DEP_SZE (y/[n]) @@ -163,8 +163,8 @@ config () # sed -ri 's,(TEST_PMD_RECORD_.*=)n,\1y,' $1/.config ) # Automatic configuration - test "$DPDK_DEP_NUMA" != y || \ - sed -ri 's,(NUMA=)n,\1y,' $1/.config + test "$DPDK_DEP_NUMA" != n || \ + sed -ri 's,(NUMA.*=)y,\1n,' $1/.config sed -ri 's,(LIBRTE_IEEE1588=)n,\1y,' $1/.config sed -ri 's,(BYPASS=)n,\1y,' $1/.config test "$DPDK_DEP_ARCHIVE" != y || \ diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile index 640afd088..8651e2783 100644 --- a/lib/librte_eal/linuxapp/eal/Makefile +++ b/lib/librte_eal/linuxapp/eal/Makefile @@ -50,6 +50,9 @@ LDLIBS += -ldl LDLIBS += -lpthread LDLIBS += -lgcc_s LDLIBS += -lrt +ifeq ($(CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES),y) +LDLIBS += -lnuma +endif # specific to linuxapp exec-env SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) := eal.c diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c index e17c9cb5d..647d89c58 100644 --- a/lib/librte_eal/linuxapp/eal/eal_memory.c +++ b/lib/librte_eal/linuxapp/eal/eal_memory.c @@ -54,6 +54,10 @@ #include #include #include +#ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES +#include +#include +#endif #include #include @@ -348,6 +352,14 @@ static int huge_wrap_sigsetjmp(void) return sigsetjmp(huge_jmpenv, 1); } +#ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES +/* Callback for numa library. */ +void numa_error(char *where) +{ + RTE_LOG(ERR, EAL, "%s failed: %s\n", where, strerror(errno)); +} +#endif + /* * Mmap all hugepages of hugepage table: it first open a file in * hugetlbfs, then mmap() hugepage_sz data in it. If orig is set, the @@ -356,18 +368,78 @@ static int huge_wrap_sigsetjmp(void) * map continguous physical blocks in contiguous virtual blocks. */ static unsigned -map_all_hugepages(struct hugepage_file *hugepg_tbl, - struct hugepage_info *hpi, int orig) +map_all_hugepages(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi, + uint64_t *essential_memory __rte_unused, int orig) { int fd; unsigned i; void *virtaddr; void *vma_addr = NULL; size_t vma_len = 0; +#ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES + int node_id = -1; + int essential_prev = 0; + int oldpolicy; + struct bitmask *oldmask = numa_allocate_nodemask(); + bool have_numa = true; + unsigned long maxnode = 0; + + /* Check if kernel supports NUMA. */ + if (numa_available() != 0) { + RTE_LOG(DEBUG, EAL, "NUMA is not supported.\n"); + have_numa = false; + } + + if (orig && have_numa) { + RTE_LOG(DEBUG, EAL, "Trying to obtain current memory policy.\n"); + if (get_mempolicy(&oldpolicy, oldmask->maskp, + oldmask->size + 1, 0, 0) < 0) { + RTE_LOG(ERR, EAL, + "Failed to get current mempolicy: %s. " + "Assuming MPOL_DEFAULT.\n", strerror(errno)); + oldpolicy = MPOL_DEFAULT; + } + for (i = 0; i < RTE_MAX_NUMA_NODES; i++) + if (internal_config.socket_mem[i]) + maxnode = i + 1; + } +#endif for (i = 0; i < hpi->num_pages[0]; i++) { uint64_t hugepage_sz = hpi->hugepage_sz; +#ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES + if (maxnode) { + unsigned int j; + + for (j = 0; j < maxnode; j++) + if (essential_memory[j]) + break; + + if (j == maxnode) { + node_id = (node_id + 1) % maxnode; + while (!internal_config.socket_mem[node_id]) { + node_id++; + node_id %= maxnode; + } + essential_prev = 0; + } else { + node_id = j; + essential_prev = essential_memory[j]; + + if (essential_memory[j] < hugepage_sz) + essential_memory[j] = 0; + else + essential_memory[j] -= hugepage_sz; + } + + RTE_LOG(DEBUG, EAL, + "Setting policy MPOL_PREFERRED for socket %d\n", + node_id); + numa_set_preferred(node_id); + } +#endif + if (orig) { hugepg_tbl[i].file_id = i; hugepg_tbl[i].size = hugepage_sz; @@ -422,7 +494,7 @@ map_all_hugepages(struct hugepage_file *hugepg_tbl, if (fd < 0) { RTE_LOG(DEBUG, EAL, "%s(): open failed: %s\n", __func__, strerror(errno)); - return i; + goto out; } /* map the segment, and populate page tables, @@ -433,7 +505,7 @@ map_all_hugepages(struct hugepage_file *hugepg_tbl, RTE_LOG(DEBUG, EAL, "%s(): mmap failed: %s\n", __func__, strerror(errno)); close(fd); - return i; + goto out; } if (orig) { @@ -458,7 +530,12 @@ map_all_hugepages(struct hugepage_file *hugepg_tbl, munmap(virtaddr, hugepage_sz); close(fd); unlink(hugepg_tbl[i].filepath); - return i; +#ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES + if (maxnode) + essential_memory[node_id] = + essential_prev; +#endif + goto out; } *(int *)virtaddr = 0; } @@ -469,7 +546,7 @@ map_all_hugepages(struct hugepage_file *hugepg_tbl, RTE_LOG(DEBUG, EAL, "%s(): Locking file failed:%s \n", __func__, strerror(errno)); close(fd); - return i; + goto out; } close(fd); @@ -478,6 +555,22 @@ map_all_hugepages(struct hugepage_file *hugepg_tbl, vma_len -= hugepage_sz; } +out: +#ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES + if (maxnode) { + RTE_LOG(DEBUG, EAL, + "Restoring previous memory policy: %d\n", oldpolicy); + if (oldpolicy == MPOL_DEFAULT) { + numa_set_localalloc(); + } else if (set_mempolicy(oldpolicy, oldmask->maskp, + oldmask->size + 1) < 0) { + RTE_LOG(ERR, EAL, "Failed to restore mempolicy: %s\n", + strerror(errno)); + numa_set_localalloc(); + } + } + numa_free_cpumask(oldmask); +#endif return i; } @@ -562,6 +655,11 @@ find_numasocket(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi) if (hugepg_tbl[i].orig_va == va) { hugepg_tbl[i].socket_id = socket_id; hp_count++; +#ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES + RTE_LOG(DEBUG, EAL, + "Hugepage %s is on socket %d\n", + hugepg_tbl[i].filepath, socket_id); +#endif } } } @@ -1000,6 +1098,11 @@ rte_eal_hugepage_init(void) huge_register_sigbus(); + /* make a copy of socket_mem, needed for balanced allocation. */ + for (i = 0; i < RTE_MAX_NUMA_NODES; i++) + memory[i] = internal_config.socket_mem[i]; + + /* map all hugepages and sort them */ for (i = 0; i < (int)internal_config.num_hugepage_sizes; i ++){ unsigned pages_old, pages_new; @@ -1017,7 +1120,8 @@ rte_eal_hugepage_init(void) /* map all hugepages available */ pages_old = hpi->num_pages[0]; - pages_new = map_all_hugepages(&tmp_hp[hp_offset], hpi, 1); + pages_new = map_all_hugepages(&tmp_hp[hp_offset], hpi, + memory, 1); if (pages_new < pages_old) { RTE_LOG(DEBUG, EAL, "%d not %d hugepages of size %u MB allocated\n", @@ -1060,7 +1164,7 @@ rte_eal_hugepage_init(void) sizeof(struct hugepage_file), cmp_physaddr); /* remap all hugepages */ - if (map_all_hugepages(&tmp_hp[hp_offset], hpi, 0) != + if (map_all_hugepages(&tmp_hp[hp_offset], hpi, NULL, 0) != hpi->num_pages[0]) { RTE_LOG(ERR, EAL, "Failed to remap %u MB pages\n", (unsigned)(hpi->hugepage_sz / 0x100000)); diff --git a/mk/rte.app.mk b/mk/rte.app.mk index bcaf1b382..4fe22d1fe 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -186,6 +186,9 @@ ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),n) # The static libraries do not know their dependencies. # So linking with static library requires explicit dependencies. _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL) += -lrt +ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP)$(CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES),yy) +_LDLIBS-$(CONFIG_RTE_LIBRTE_EAL) += -lnuma +endif _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lm _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrt _LDLIBS-$(CONFIG_RTE_LIBRTE_METER) += -lm -- 2.13.1