From: Damjan Marion Date: Wed, 24 Oct 2018 15:08:26 +0000 (+0200) Subject: pmalloc: support for 4K pages X-Git-Tag: v19.04-rc0~532 X-Git-Url: https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commitdiff_plain;h=567e61d09cd00174203eff85f63a598420476951 pmalloc: support for 4K pages Change-Id: Iecceffe06a92660976ebb58cd3cbec4be8931db0 Signed-off-by: Damjan Marion --- diff --git a/src/plugins/dpdk/buffer.c b/src/plugins/dpdk/buffer.c index 770e76d398e..145221a902b 100644 --- a/src/plugins/dpdk/buffer.c +++ b/src/plugins/dpdk/buffer.c @@ -417,7 +417,7 @@ dpdk_pool_create (vlib_main_t * vm, u8 * pool_name, u32 elt_size, &min_chunk_size, &align); if ((error = vlib_physmem_shared_map_create (vm, (char *) pool_name, size, - numa, map_index))) + 0, numa, map_index))) { rte_mempool_free (mp); return error; diff --git a/src/svm/ssvm.c b/src/svm/ssvm.c index 2d9d1b3159f..73517aeb443 100644 --- a/src/svm/ssvm.c +++ b/src/svm/ssvm.c @@ -80,7 +80,7 @@ ssvm_master_init_shm (ssvm_private_t * ssvm) return SSVM_API_ERROR_SET_SIZE; } - page_size = clib_mem_vm_get_page_size (ssvm_fd); + page_size = clib_mem_get_fd_page_size (ssvm_fd); if (ssvm->requested_va) { requested_va = ssvm->requested_va; @@ -290,7 +290,7 @@ ssvm_slave_init_memfd (ssvm_private_t * memfd) memfd->i_am_master = 0; - page_size = clib_mem_vm_get_page_size (memfd->fd); + page_size = clib_mem_get_fd_page_size (memfd->fd); if (!page_size) { clib_unix_warning ("page size unknown"); diff --git a/src/vlib/buffer.c b/src/vlib/buffer.c index 22cf7999be7..ff91d3b920c 100644 --- a/src/vlib/buffer.c +++ b/src/vlib/buffer.c @@ -55,6 +55,9 @@ static u32 vlib_buffer_physmem_sz = 14 << 20; vlib_buffer_main_t buffer_main; +/* logging */ +static vlib_log_class_t buffer_log_default; + uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm, vlib_buffer_t * b_first) @@ -963,6 +966,9 @@ vlib_buffer_main_init (struct vlib_main_t * vm) clib_error_t *error; u32 physmem_map_index; u8 pool_index; + int log2_page_size = 0; + + buffer_log_default = vlib_log_register_class ("buffer", 0); if (vlib_buffer_callbacks) { @@ -981,10 +987,24 @@ vlib_buffer_main_init (struct vlib_main_t * vm) &vlib_buffer_delete_free_list_internal; clib_spinlock_init (&bm->buffer_known_hash_lockp); - if ((error = vlib_physmem_shared_map_create (vm, "buffers", - vlib_buffer_physmem_sz, - CLIB_PMALLOC_NUMA_LOCAL, - &physmem_map_index))) +retry: + error = vlib_physmem_shared_map_create (vm, "buffers", + vlib_buffer_physmem_sz, + log2_page_size, + CLIB_PMALLOC_NUMA_LOCAL, + &physmem_map_index); + + if (error && log2_page_size == 0) + { + vlib_log_warn (buffer_log_default, "%U", format_clib_error, error); + clib_error_free (error); + vlib_log_warn (buffer_log_default, "falling back to non-hugepage " + "backed buffer pool"); + log2_page_size = min_log2 (clib_mem_get_page_size ()); + goto retry; + } + + if (error) return error; pool_index = vlib_buffer_register_physmem_map (vm, physmem_map_index); diff --git a/src/vlib/linux/vfio.c b/src/vlib/linux/vfio.c index d300a683dd7..1ed99ceee55 100644 --- a/src/vlib/linux/vfio.c +++ b/src/vlib/linux/vfio.c @@ -40,7 +40,7 @@ vfio_map_physmem_page (vlib_main_t * vm, void *addr) vlib_physmem_main_t *vpm = &vm->physmem_main; linux_vfio_main_t *lvm = &vfio_main; struct vfio_iommu_type1_dma_map dm = { 0 }; - uword log2_page_size = vpm->pmalloc_main->log2_page_sz; + uword log2_page_size = vpm->pmalloc_main->def_log2_page_sz; uword physmem_start = pointer_to_uword (vpm->pmalloc_main->base); if (lvm->container_fd == -1) diff --git a/src/vlib/physmem.c b/src/vlib/physmem.c index 2599bce944d..f881e0a8e71 100755 --- a/src/vlib/physmem.c +++ b/src/vlib/physmem.c @@ -31,7 +31,8 @@ clib_error_t * vlib_physmem_shared_map_create (vlib_main_t * vm, char *name, uword size, - u32 numa_node, u32 * map_index) + u32 log2_page_sz, u32 numa_node, + u32 * map_index) { clib_pmalloc_main_t *pm = vm->physmem_main.pmalloc_main; vlib_physmem_main_t *vpm = &vm->physmem_main; @@ -41,7 +42,8 @@ vlib_physmem_shared_map_create (vlib_main_t * vm, char *name, uword size, void *va; uword i; - va = clib_pmalloc_create_shared_arena (pm, name, size, numa_node); + va = clib_pmalloc_create_shared_arena (pm, name, size, log2_page_sz, + numa_node); if (va == 0) return clib_error_return (0, "%U", format_clib_error, @@ -53,12 +55,13 @@ vlib_physmem_shared_map_create (vlib_main_t * vm, char *name, uword size, *map_index = map->index = map - vpm->maps; map->base = va; map->fd = a->fd; - map->n_pages = a->n_pages; - map->log2_page_size = a->log2_page_sz; + map->n_pages = a->n_pages * a->subpages_per_page; + map->log2_page_size = a->log2_subpage_sz; for (i = 0; i < a->n_pages; i++) { - uword pa = clib_pmalloc_get_pa (pm, (u8 *) va + (i << a->log2_page_sz)); + uword pa = + clib_pmalloc_get_pa (pm, (u8 *) va + (i << a->log2_subpage_sz)); /* maybe iova */ if (pa == 0) diff --git a/src/vlib/physmem_funcs.h b/src/vlib/physmem_funcs.h index 0082f85c70d..70fb8e74fc7 100644 --- a/src/vlib/physmem_funcs.h +++ b/src/vlib/physmem_funcs.h @@ -42,8 +42,8 @@ clib_error_t *vlib_physmem_init (vlib_main_t * vm); clib_error_t *vlib_physmem_shared_map_create (vlib_main_t * vm, char *name, - uword size, u32 numa_node, - u32 * map_index); + uword size, u32 log2_page_sz, + u32 numa_node, u32 * map_index); vlib_physmem_map_t *vlib_physmem_get_map (vlib_main_t * vm, u32 index); diff --git a/src/vppinfra/linux/mem.c b/src/vppinfra/linux/mem.c index 6a551ec0554..8edae74f9cd 100644 --- a/src/vppinfra/linux/mem.c +++ b/src/vppinfra/linux/mem.c @@ -82,7 +82,7 @@ done: } u64 -clib_mem_vm_get_page_size (int fd) +clib_mem_get_fd_page_size (int fd) { struct stat st = { 0 }; if (fstat (fd, &st) == -1) @@ -91,9 +91,9 @@ clib_mem_vm_get_page_size (int fd) } int -clib_mem_vm_get_log2_page_size (int fd) +clib_mem_get_fd_log2_page_size (int fd) { - return min_log2 (clib_mem_vm_get_page_size (fd)); + return min_log2 (clib_mem_get_fd_page_size (fd)); } void @@ -116,6 +116,26 @@ clib_mem_vm_randomize_va (uword * requested_va, u32 log2_page_size) #define MFD_HUGETLB 0x0004U #endif +clib_error_t * +clib_mem_create_fd (char *name, int *fdp) +{ + int fd; + + ASSERT (name); + + if ((fd = memfd_create (name, MFD_ALLOW_SEALING)) == -1) + return clib_error_return_unix (0, "memfd_create"); + + if ((fcntl (fd, F_ADD_SEALS, F_SEAL_SHRINK)) == -1) + { + close (fd); + return clib_error_return_unix (0, "fcntl (F_ADD_SEALS)"); + } + + *fdp = fd; + return 0; +} + clib_error_t * clib_mem_create_hugetlb_fd (char *name, int *fdp) { @@ -212,20 +232,11 @@ clib_mem_vm_ext_alloc (clib_mem_vm_alloc_t * a) } else { - if ((fd = memfd_create (a->name, MFD_ALLOW_SEALING)) == -1) - { - err = clib_error_return_unix (0, "memfd_create"); - goto error; - } - - if ((fcntl (fd, F_ADD_SEALS, F_SEAL_SHRINK)) == -1) - { - err = clib_error_return_unix (0, "fcntl (F_ADD_SEALS)"); - goto error; - } + if ((err = clib_mem_create_fd (a->name, &fd))) + goto error; } - log2_page_size = clib_mem_vm_get_log2_page_size (fd); + log2_page_size = clib_mem_get_fd_log2_page_size (fd); if (log2_page_size == 0) { err = clib_error_return_unix (0, "cannot determine page size"); diff --git a/src/vppinfra/mem.h b/src/vppinfra/mem.h index 813ff6c88d8..a2c5474a46e 100644 --- a/src/vppinfra/mem.h +++ b/src/vppinfra/mem.h @@ -386,12 +386,13 @@ typedef struct uword requested_va; /**< Request fixed position mapping */ } clib_mem_vm_alloc_t; +clib_error_t *clib_mem_create_fd (char *name, int *fdp); clib_error_t *clib_mem_create_hugetlb_fd (char *name, int *fdp); clib_error_t *clib_mem_vm_ext_alloc (clib_mem_vm_alloc_t * a); void clib_mem_vm_ext_free (clib_mem_vm_alloc_t * a); -u64 clib_mem_vm_get_page_size (int fd); +u64 clib_mem_get_fd_page_size (int fd); uword clib_mem_get_default_hugepage_size (void); -int clib_mem_vm_get_log2_page_size (int fd); +int clib_mem_get_fd_log2_page_size (int fd); u64 *clib_mem_vm_get_paddr (void *mem, int log2_page_size, int n_pages); typedef struct diff --git a/src/vppinfra/pmalloc.c b/src/vppinfra/pmalloc.c index a8b47d74c9b..5812f9fa120 100644 --- a/src/vppinfra/pmalloc.c +++ b/src/vppinfra/pmalloc.c @@ -40,6 +40,12 @@ get_chunk (clib_pmalloc_page_t * pp, u32 index) return pool_elt_at_index (pp->chunks, index); } +static inline uword +pmalloc_size2pages (uword size, u32 log2_page_sz) +{ + return round_pow2 (size, 1ULL << log2_page_sz) >> log2_page_sz; +} + static inline int pmalloc_validate_numa_node (u32 * numa_node) { @@ -60,12 +66,14 @@ clib_pmalloc_init (clib_pmalloc_main_t * pm, uword size) ASSERT (pm->error == 0); pagesize = clib_mem_get_default_hugepage_size (); - pm->log2_page_sz = min_log2 (pagesize); + pm->def_log2_page_sz = min_log2 (pagesize); + pm->sys_log2_page_sz = min_log2 (sysconf (_SC_PAGESIZE)); + pm->lookup_log2_page_sz = pm->def_log2_page_sz; size = size ? size : ((u64) DEFAULT_RESERVED_MB) << 20; size = round_pow2 (size, pagesize); - pm->max_pages = size >> pm->log2_page_sz; + pm->max_pages = size >> pm->def_log2_page_sz; /* reserve VA space for future growth */ pm->base = mmap (0, size + pagesize, PROT_NONE, @@ -95,18 +103,33 @@ static inline void * alloc_chunk_from_page (clib_pmalloc_main_t * pm, clib_pmalloc_page_t * pp, u32 n_blocks, u32 block_align, u32 numa_node) { - clib_pmalloc_chunk_t *c; + clib_pmalloc_chunk_t *c = 0; + clib_pmalloc_arena_t *a; void *va; u32 off; u32 alloc_chunk_index; + a = pool_elt_at_index (pm->arenas, pp->arena_index); + if (pp->chunks == 0) { - pool_get (pp->chunks, c); - pp->n_free_chunks = 1; - pp->first_chunk_index = c - pp->chunks; - c->prev = c->next = ~0; - c->size = pp->n_free_blocks; + u32 i, start = 0, prev = ~0; + + for (i = 0; i < a->subpages_per_page; i++) + { + pool_get (pp->chunks, c); + c->start = start; + c->prev = prev; + c->size = pp->n_free_blocks / a->subpages_per_page; + start += c->size; + if (prev == ~0) + pp->first_chunk_index = c - pp->chunks; + else + pp->chunks[prev].next = c - pp->chunks; + prev = c - pp->chunks; + } + c->next = ~0; + pp->n_free_chunks = a->subpages_per_page; } alloc_chunk_index = pp->first_chunk_index; @@ -165,7 +188,7 @@ next_chunk: pool_elt_at_index (pp->chunks, c->next)->prev = alloc_chunk_index; c = get_chunk (pp, alloc_chunk_index); - va = pm->base + ((pp - pm->pages) << pm->log2_page_sz) + + va = pm->base + ((pp - pm->pages) << pm->def_log2_page_sz) + (c->start << PMALLOC_LOG2_BLOCK_SZ); hash_set (pm->chunk_index_by_va, pointer_to_uword (va), alloc_chunk_index); pp->n_free_blocks -= n_blocks; @@ -173,17 +196,48 @@ next_chunk: return va; } +static void +pmalloc_update_lookup_table (clib_pmalloc_main_t * pm, u32 first, u32 count) +{ + uword seek, va, pa, p; + int fd; + u32 elts_per_page = 1U << (pm->def_log2_page_sz - pm->lookup_log2_page_sz); + + vec_validate_aligned (pm->lookup_table, vec_len (pm->pages) * + elts_per_page - 1, CLIB_CACHE_LINE_BYTES); + + fd = open ((char *) "/proc/self/pagemap", O_RDONLY); + + p = first * elts_per_page; + while (p < elts_per_page * count) + { + va = pointer_to_uword (pm->base) + (p << pm->lookup_log2_page_sz); + seek = (va >> pm->sys_log2_page_sz) * sizeof (pa); + if (fd != -1 && lseek (fd, seek, SEEK_SET) == seek && + read (fd, &pa, sizeof (pa)) == (sizeof (pa)) && + pa & (1ULL << 63) /* page present bit */ ) + { + pa = (pa & pow2_mask (55)) << pm->sys_log2_page_sz; + } + pm->lookup_table[p] = va - pa; + p++; + } + + if (fd != -1) + close (fd); +} + static inline clib_pmalloc_page_t * pmalloc_map_pages (clib_pmalloc_main_t * pm, clib_pmalloc_arena_t * a, u32 numa_node, u32 n_pages) { clib_pmalloc_page_t *pp = 0; - u64 seek, pa, sys_page_size; - int pagemap_fd, status, rv, i, mmap_flags; + int status, rv, i, mmap_flags; void *va; int old_mpol = -1; long unsigned int mask[16] = { 0 }; long unsigned int old_mask[16] = { 0 }; + uword size = (uword) n_pages << pm->def_log2_page_sz; clib_error_free (pm->error); @@ -193,11 +247,14 @@ pmalloc_map_pages (clib_pmalloc_main_t * pm, clib_pmalloc_arena_t * a, return 0; } - pm->error = clib_sysfs_prealloc_hugepages (numa_node, pm->log2_page_sz, - n_pages); + if (a->log2_subpage_sz != pm->sys_log2_page_sz) + { + pm->error = clib_sysfs_prealloc_hugepages (numa_node, + a->log2_subpage_sz, n_pages); - if (pm->error) - return 0; + if (pm->error) + return 0; + } rv = get_mempolicy (&old_mpol, old_mask, sizeof (old_mask) * 8 + 1, 0, 0); /* failure to get mempolicy means we can only proceed with numa 0 maps */ @@ -216,11 +273,18 @@ pmalloc_map_pages (clib_pmalloc_main_t * pm, clib_pmalloc_arena_t * a, return 0; } - mmap_flags = MAP_FIXED | MAP_HUGETLB | MAP_LOCKED | MAP_ANONYMOUS; + mmap_flags = MAP_FIXED | MAP_ANONYMOUS | MAP_LOCKED; + + if (a->log2_subpage_sz != pm->sys_log2_page_sz) + mmap_flags |= MAP_HUGETLB; + if (a->flags & CLIB_PMALLOC_ARENA_F_SHARED_MEM) { mmap_flags |= MAP_SHARED; - pm->error = clib_mem_create_hugetlb_fd ((char *) a->name, &a->fd); + if (mmap_flags & MAP_HUGETLB) + pm->error = clib_mem_create_hugetlb_fd ((char *) a->name, &a->fd); + else + pm->error = clib_mem_create_fd ((char *) a->name, &a->fd); if (a->fd == -1) goto error; } @@ -230,9 +294,9 @@ pmalloc_map_pages (clib_pmalloc_main_t * pm, clib_pmalloc_arena_t * a, a->fd = -1; } - va = pm->base + (vec_len (pm->pages) << pm->log2_page_sz); - if (mmap (va, n_pages << pm->log2_page_sz, PROT_READ | PROT_WRITE, - mmap_flags, a->fd, 0) == MAP_FAILED) + va = pm->base + (((uword) vec_len (pm->pages)) << pm->def_log2_page_sz); + if (mmap (va, size, PROT_READ | PROT_WRITE, mmap_flags, a->fd, 0) == + MAP_FAILED) { pm->error = clib_error_return_unix (0, "failed to mmap %u pages at %p " "fd %d numa %d flags 0x%x", n_pages, @@ -240,6 +304,8 @@ pmalloc_map_pages (clib_pmalloc_main_t * pm, clib_pmalloc_arena_t * a, goto error; } + clib_memset (va, 0, size); + rv = set_mempolicy (old_mpol, old_mask, sizeof (old_mask) * 8 + 1); if (rv == -1 && numa_node != 0) { @@ -259,41 +325,33 @@ pmalloc_map_pages (clib_pmalloc_main_t * pm, clib_pmalloc_arena_t * a, "%u status %d", numa_node, status); /* unmap & reesrve */ - munmap (va, n_pages << pm->log2_page_sz); - mmap (va, n_pages << pm->log2_page_sz, PROT_NONE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + munmap (va, size); + mmap (va, size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); goto error; } - clib_memset (va, 0, n_pages << pm->log2_page_sz); - sys_page_size = sysconf (_SC_PAGESIZE); - pagemap_fd = open ((char *) "/proc/self/pagemap", O_RDONLY); - for (i = 0; i < n_pages; i++) { - uword page_va = pointer_to_uword ((u8 *) va + (i << pm->log2_page_sz)); vec_add2 (pm->pages, pp, 1); - pp->n_free_blocks = 1 << (pm->log2_page_sz - PMALLOC_LOG2_BLOCK_SZ); + pp->n_free_blocks = 1 << (pm->def_log2_page_sz - PMALLOC_LOG2_BLOCK_SZ); pp->index = pp - pm->pages; pp->arena_index = a->index; - vec_add1 (a->page_indices, pp->index); a->n_pages++; - - seek = (page_va / sys_page_size) * sizeof (pa); - if (pagemap_fd != -1 && - lseek (pagemap_fd, seek, SEEK_SET) == seek && - read (pagemap_fd, &pa, sizeof (pa)) == (sizeof (pa)) && - pa & (1ULL << 63) /* page present bit */ ) - { - pp->pa = (pa & pow2_mask (55)) * sys_page_size; - } - vec_add1_aligned (pm->va_pa_diffs, pp->pa ? page_va - pp->pa : 0, - CLIB_CACHE_LINE_BYTES); } - if (pagemap_fd != -1) - close (pagemap_fd); + + /* if new arena is using smaller page size, we need to rebuild whole + lookup table */ + if (a->log2_subpage_sz < pm->lookup_log2_page_sz) + { + pm->lookup_log2_page_sz = a->log2_subpage_sz; + pmalloc_update_lookup_table (pm, vec_len (pm->pages) - n_pages, + n_pages); + } + else + pmalloc_update_lookup_table (pm, 0, vec_len (pm->pages)); /* return pointer to 1st page */ return pp - (n_pages - 1); @@ -306,12 +364,25 @@ error: void * clib_pmalloc_create_shared_arena (clib_pmalloc_main_t * pm, char *name, - uword size, u32 numa_node) + uword size, u32 log2_page_sz, u32 numa_node) { clib_pmalloc_arena_t *a; clib_pmalloc_page_t *pp; - u32 n_pages = round_pow2 (size, 1ULL << pm->log2_page_sz) >> - pm->log2_page_sz; + u32 n_pages; + + clib_error_free (pm->error); + + if (log2_page_sz == 0) + log2_page_sz = pm->def_log2_page_sz; + else if (log2_page_sz != pm->def_log2_page_sz && + log2_page_sz != pm->sys_log2_page_sz) + { + pm->error = clib_error_create ("unsupported page size (%uKB)", + 1 << (log2_page_sz - 10)); + return 0; + } + + n_pages = pmalloc_size2pages (size, pm->def_log2_page_sz); if (n_pages + vec_len (pm->pages) > pm->max_pages) return 0; @@ -324,7 +395,8 @@ clib_pmalloc_create_shared_arena (clib_pmalloc_main_t * pm, char *name, a->name = format (0, "%s%c", name, 0); a->numa_node = numa_node; a->flags = CLIB_PMALLOC_ARENA_F_SHARED_MEM; - a->log2_page_sz = pm->log2_page_sz; + a->log2_subpage_sz = log2_page_sz; + a->subpages_per_page = 1U << (pm->def_log2_page_sz - log2_page_sz); if ((pp = pmalloc_map_pages (pm, a, numa_node, n_pages)) == 0) { @@ -334,7 +406,7 @@ clib_pmalloc_create_shared_arena (clib_pmalloc_main_t * pm, char *name, return 0; } - return pm->base + (pp->index << pm->log2_page_sz); + return pm->base + (pp->index << pm->def_log2_page_sz); } static inline void * @@ -351,6 +423,9 @@ clib_pmalloc_alloc_inline (clib_pmalloc_main_t * pm, clib_pmalloc_arena_t * a, if (a == 0) { + if (size > 1ULL << pm->def_log2_page_sz) + return 0; + vec_validate_init_empty (pm->default_arena_for_numa_node, numa_node, ~0); if (pm->default_arena_for_numa_node[numa_node] == ~0) @@ -359,11 +434,15 @@ clib_pmalloc_alloc_inline (clib_pmalloc_main_t * pm, clib_pmalloc_arena_t * a, pm->default_arena_for_numa_node[numa_node] = a - pm->arenas; a->name = format (0, "default-numa-%u%c", numa_node, 0); a->numa_node = numa_node; + a->log2_subpage_sz = pm->def_log2_page_sz; + a->subpages_per_page = 1; } else a = pool_elt_at_index (pm->arenas, pm->default_arena_for_numa_node[numa_node]); } + else if (size > 1ULL << a->log2_subpage_sz) + return 0; n_blocks = round_pow2 (size, PMALLOC_BLOCK_SZ) / PMALLOC_BLOCK_SZ; block_align = align >> PMALLOC_LOG2_BLOCK_SZ; @@ -407,11 +486,34 @@ clib_pmalloc_alloc_from_arena (clib_pmalloc_main_t * pm, void *arena_va, return clib_pmalloc_alloc_inline (pm, a, size, align, 0); } +static inline int +pmalloc_chunks_mergeable (clib_pmalloc_arena_t * a, clib_pmalloc_page_t * pp, + u32 ci1, u32 ci2) +{ + clib_pmalloc_chunk_t *c1, *c2; + + if (ci1 == ~0 || ci2 == ~0) + return 0; + + c1 = get_chunk (pp, ci1); + c2 = get_chunk (pp, ci2); + + if (c1->used || c2->used) + return 0; + + if (c1->start >> (a->log2_subpage_sz - PMALLOC_LOG2_BLOCK_SZ) != + c2->start >> (a->log2_subpage_sz - PMALLOC_LOG2_BLOCK_SZ)) + return 0; + + return 1; +} + void clib_pmalloc_free (clib_pmalloc_main_t * pm, void *va) { clib_pmalloc_page_t *pp; clib_pmalloc_chunk_t *c; + clib_pmalloc_arena_t *a; uword *p; u32 chunk_index, page_index; @@ -426,12 +528,13 @@ clib_pmalloc_free (clib_pmalloc_main_t * pm, void *va) pp = vec_elt_at_index (pm->pages, page_index); c = pool_elt_at_index (pp->chunks, chunk_index); + a = pool_elt_at_index (pm->arenas, pp->arena_index); c->used = 0; pp->n_free_blocks += c->size; pp->n_free_chunks++; /* merge with next if free */ - if (c->next != ~0 && get_chunk (pp, c->next)->used == 0) + if (pmalloc_chunks_mergeable (a, pp, chunk_index, c->next)) { clib_pmalloc_chunk_t *next = get_chunk (pp, c->next); c->size += next->size; @@ -444,7 +547,7 @@ clib_pmalloc_free (clib_pmalloc_main_t * pm, void *va) } /* merge with prev if free */ - if (c->prev != ~0 && get_chunk (pp, c->prev)->used == 0) + if (pmalloc_chunks_mergeable (a, pp, c->prev, chunk_index)) { clib_pmalloc_chunk_t *prev = get_chunk (pp, c->prev); prev->size += c->size; @@ -457,6 +560,24 @@ clib_pmalloc_free (clib_pmalloc_main_t * pm, void *va) } } +static u8 * +format_log2_page_size (u8 * s, va_list * va) +{ + u32 log2_page_sz = va_arg (*va, u32); + + if (log2_page_sz >= 30) + return format (s, "%uGB", 1 << (log2_page_sz - 30)); + + if (log2_page_sz >= 20) + return format (s, "%uMB", 1 << (log2_page_sz - 20)); + + if (log2_page_sz >= 10) + return format (s, "%uKB", 1 << (log2_page_sz - 10)); + + return format (s, "%uB", 1 << log2_page_sz); +} + + static u8 * format_pmalloc_page (u8 * s, va_list * va) { @@ -506,9 +627,11 @@ format_pmalloc (u8 * s, va_list * va) clib_pmalloc_page_t *pp; clib_pmalloc_arena_t *a; - s = format (s, "used-pages %u reserved-pages %u pagesize %uKB", - vec_len (pm->pages), pm->max_pages, - 1 << (pm->log2_page_sz - 10)); + s = format (s, "used-pages %u reserved-pages %u default-page-size %U " + "lookup-page-size %U", vec_len (pm->pages), pm->max_pages, + format_log2_page_size, pm->def_log2_page_sz, + format_log2_page_size, pm->lookup_log2_page_sz); + if (verbose >= 2) s = format (s, " va-start %p", pm->base); @@ -522,9 +645,10 @@ format_pmalloc (u8 * s, va_list * va) pool_foreach (a, pm->arenas, { u32 *page_index; - s = format (s, "\n%Uarena '%s' pages %u numa-node %u", - format_white_space, indent + 2, - a->name, vec_len (a->page_indices), a->numa_node); + s = format (s, "\n%Uarena '%s' pages %u subpage-size %U numa-node %u", + format_white_space, indent + 2, a->name, + vec_len (a->page_indices), format_log2_page_size, + a->log2_subpage_sz, a->numa_node); if (a->fd != -1) s = format (s, " shared fd %d", a->fd); if (verbose >= 1) diff --git a/src/vppinfra/pmalloc.h b/src/vppinfra/pmalloc.h index 4d9906ab6e7..41b85e0c517 100644 --- a/src/vppinfra/pmalloc.h +++ b/src/vppinfra/pmalloc.h @@ -51,7 +51,8 @@ typedef struct int fd; u32 numa_node; u32 first_page_index; - u32 log2_page_sz; + u32 log2_subpage_sz; + u32 subpages_per_page; u32 n_pages; u8 *name; u32 *page_indices; @@ -59,15 +60,42 @@ typedef struct typedef struct { + /* base VA address */ u8 *base; - uword log2_page_sz; - uword *va_pa_diffs; + + /* default page size - typically 2M */ + u32 def_log2_page_sz; + + /* system page size - typically 4K */ + u32 sys_log2_page_sz; + + /* maximum number of pages, limited by VA preallocation size */ u32 max_pages; + + /* vector of pages - each page have own alloc pool and it can be split + into subpages (i.e. 2M page build out of 512 4K pages) */ clib_pmalloc_page_t *pages; + + /* hash used to find chunk index out of VA, chunk index is defined + per page */ uword *chunk_index_by_va; + + /* alloc arenas are group of pages which share same attributes + shared arenas are represented by FD and they are not grovable + private arenas are growable */ clib_pmalloc_arena_t *arenas; + + /* vector of per numa node alloc arena indices + each numa node have own default privat alloc arena */ u32 *default_arena_for_numa_node; + /* VA to PA lookup table */ + uword *lookup_table; + + /* lookup page size - equals to smalles subpage used */ + u32 lookup_log2_page_sz; + + /* last error */ clib_error_t *error; } clib_pmalloc_main_t; @@ -81,7 +109,8 @@ void *clib_pmalloc_alloc_aligned (clib_pmalloc_main_t * pm, uword size, void clib_pmalloc_free (clib_pmalloc_main_t * pm, void *va); void *clib_pmalloc_create_shared_arena (clib_pmalloc_main_t * pm, char *name, - uword size, u32 numa_node); + uword size, u32 log2_page_sz, + u32 numa_node); void *clib_pmalloc_alloc_from_arena (clib_pmalloc_main_t * pm, void *arena_va, uword size, uword align); @@ -98,7 +127,7 @@ always_inline u32 clib_pmalloc_get_page_index (clib_pmalloc_main_t * pm, void *va) { uword index = (pointer_to_uword (va) - pointer_to_uword (pm->base)) >> - pm->log2_page_sz; + pm->def_log2_page_sz; ASSERT (index < vec_len (pm->pages)); @@ -115,8 +144,9 @@ clib_pmalloc_get_arena (clib_pmalloc_main_t * pm, void *va) always_inline uword clib_pmalloc_get_pa (clib_pmalloc_main_t * pm, void *va) { - u32 index = clib_pmalloc_get_page_index (pm, va); - return pointer_to_uword (va) - pm->va_pa_diffs[index]; + uword index = (pointer_to_uword (va) - pointer_to_uword (pm->base)) >> + pm->lookup_log2_page_sz; + return pointer_to_uword (va) - pm->lookup_table[index]; } diff --git a/src/vppinfra/test_pmalloc.c b/src/vppinfra/test_pmalloc.c index c9ae01fc936..90b1775bb4f 100644 --- a/src/vppinfra/test_pmalloc.c +++ b/src/vppinfra/test_pmalloc.c @@ -29,6 +29,7 @@ typedef struct u32 arena_pages; u32 arena_numa; u32 arena_items; + u32 arena_log2_pg_sz; int verbose; clib_pmalloc_main_t pmalloc_main; } test_main_t; @@ -73,6 +74,7 @@ test_palloc (test_main_t * tm) fformat (stdout, "Allocate %d items from arena ...\n", tm->arena_items); arena = clib_pmalloc_create_shared_arena (pm, "test arena", tm->arena_pages << 21, + tm->arena_log2_pg_sz, tm->arena_numa); if (arena == 0) clib_error ("Failed to alloc shared arena: %U", format_clib_error, @@ -125,6 +127,8 @@ test_palloc_main (unformat_input_t * i) ; else if (unformat (i, "arena-items %u", &tm->arena_items)) ; + else if (unformat (i, "arena-log2-page-size %u", &tm->arena_log2_pg_sz)) + ; else if (unformat (i, "verbose")) tm->verbose = 1; else