Hi, I am submitting a patch for a realloc function that might be useful. The proposed numa_realloc() is merely a wrapper to mremap(), which it calls with the flag MREMAP_MAYMOVE. The policy of the vm area is copied by the kernel in case of moving. I am also submitting a test program, that keeps expanding an initial allocation until a limit is reached and checks the mempolicy of the expanded area in every iteration. My use case is a dynamic array implementation which uses realloc() to dynamically expand the array and I want to convert it to a numa-aware implementation. PS: I could also submit a brief manpage entry for the new function, if you agree. Best regards, -- Vasileios Karakasis
diff -urN numactl-2.0.6-rc4-orig/libnuma.c numactl-2.0.6-rc4/libnuma.c --- numactl-2.0.6-rc4-orig/libnuma.c 2011-01-02 16:01:07.000000000 +0200 +++ numactl-2.0.6-rc4/libnuma.c 2011-01-02 16:01:14.000000000 +0200 @@ -871,6 +871,16 @@ return mem; } +void *numa_realloc(void *old_addr, size_t old_size, size_t new_size) +{ + char *mem; + mem = mremap(old_addr, old_size, new_size, MREMAP_MAYMOVE); + if (mem == (char *)-1) + return NULL; + /* Policy and binding of the vm segment are preserved by the kernel */ + return mem; +} + void *numa_alloc_interleaved_subset_v1(size_t size, const nodemask_t *mask) { char *mem; diff -urN numactl-2.0.6-rc4-orig/Makefile numactl-2.0.6-rc4/Makefile --- numactl-2.0.6-rc4-orig/Makefile 2010-12-22 13:29:50.000000000 +0200 +++ numactl-2.0.6-rc4/Makefile 2011-01-02 13:32:36.000000000 +0200 @@ -31,7 +31,7 @@ test/after test/before threadtest test_move_pages \ test/mbind_mig_pages test/migrate_pages \ migratepages migspeed migspeed.o libnuma.a \ - test/move_pages + test/move_pages test/realloc_test SOURCES := bitops.c libnuma.c distance.c memhog.c numactl.c numademo.c \ numamon.c shm.c stream_lib.c stream_main.c syscall.c util.c mt.c \ clearcache.c test/*.c @@ -43,7 +43,7 @@ all: numactl migratepages migspeed libnuma.so numademo numamon memhog \ test/tshared stream test/mynode test/pagesize test/ftok test/prefered \ test/randmap test/nodemap test/distance test/tbitmap test/move_pages \ - test/mbind_mig_pages test/migrate_pages libnuma.a + test/mbind_mig_pages test/migrate_pages test/realloc_test libnuma.a numactl: numactl.o util.o shm.o bitops.o libnuma.so @@ -123,6 +123,8 @@ test/migrate_pages: test/migrate_pages.c libnuma.so +test/realloc_test: test/realloc_test.c libnuma.so + .PHONY: install all clean html depend MANPAGES := numa.3 numactl.8 numastat.8 migratepages.8 migspeed.8 diff -urN numactl-2.0.6-rc4-orig/numa.h numactl-2.0.6-rc4/numa.h --- numactl-2.0.6-rc4-orig/numa.h 2010-12-22 13:29:50.000000000 +0200 +++ numactl-2.0.6-rc4/numa.h 2010-12-22 13:45:42.000000000 +0200 @@ -212,6 +212,8 @@ void *numa_alloc_local(size_t size); /* Allocation with current policy */ void *numa_alloc(size_t size); +/* Realloc memory, binding properties are preserved. */ +void *numa_realloc(void *old_addr, size_t old_size, size_t new_size); /* Free memory allocated by the functions above */ void numa_free(void *mem, size_t size); diff -urN numactl-2.0.6-rc4-orig/test/realloc_test.c numactl-2.0.6-rc4/test/realloc_test.c --- numactl-2.0.6-rc4-orig/test/realloc_test.c 1970-01-01 02:00:00.000000000 +0200 +++ numactl-2.0.6-rc4/test/realloc_test.c 2011-01-02 13:25:13.000000000 +0200 @@ -0,0 +1,109 @@ +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/mman.h> +#include "numa.h" +#include "numaif.h" + +#define DEFAULT_NR_PAGES 1024 + +static int parse_int(const char *str) +{ + char *endptr; + long ret = strtol(str, &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, "[error] strtol() failed: parse error: %s\n", endptr); + exit(1); + } + + if (errno == ERANGE) + fprintf(stderr, "[warning] strtol() out of range\n"); + + if (ret > INT_MAX || ret < INT_MIN) { + fprintf(stderr, "[warning] parse_int() out of range\n"); + ret = (ret > 0) ? INT_MAX : INT_MIN; + } + + return (int) ret; +} + +int main(int argc, char **argv) +{ + char *mem; + int page_size = numa_pagesize(); + int node = 0; + int nr_pages = DEFAULT_NR_PAGES; + + if (numa_available() < 0) { + fprintf(stderr, "numa is not available"); + exit(1); + } + + if (argc > 1) + node = parse_int(argv[1]); + if (argc > 2) + nr_pages = parse_int(argv[2]); + + mem = numa_alloc_onnode(page_size, node); + + /* Store the policy of the newly allocated area */ + unsigned long nodemask; + int mode; + int nr_nodes = numa_num_possible_nodes(); + if (get_mempolicy(&mode, &nodemask, nr_nodes, mem, + MPOL_F_NODE | MPOL_F_ADDR) < 0) { + perror("get_mempolicy() failed"); + exit(1); + } + + /* Print some info */ + printf("Page size: %d\n", page_size); + printf("Pages realloc'ed: %d\n", nr_pages); + printf("Allocate data in node: %d\n", node); + + /* Request pages until a realloc moves the data */ + int i; + int nr_inplace = 0; + int nr_moved = 0; + for (i = 0; i < nr_pages; i++) { + /* Enlarge mem with one more page */ + char *new_mem = numa_realloc(mem, (i+1)*page_size, (i+2)*page_size); + if (!new_mem) { + perror("numa_realloc() failed"); + exit(1); + } + + if (new_mem == mem) + ++nr_inplace; + else + ++nr_moved; + mem = new_mem; + + /* Check the policy of the realloc'ed area */ + unsigned long realloc_nodemask; + int realloc_mode; + if (get_mempolicy(&realloc_mode, &realloc_nodemask, + nr_nodes, mem, MPOL_F_NODE | MPOL_F_ADDR) < 0) { + perror("get_mempolicy() failed"); + exit(1); + } + + assert(realloc_nodemask == nodemask && + realloc_mode == mode && "policy changed"); + } + + /* Shrink to the original size */ + mem = numa_realloc(mem, (nr_pages + 1)*page_size, page_size); + if (!mem) { + perror("numa_realloc() failed"); + exit(1); + } + + numa_free(mem, page_size); + printf("In-place reallocs: %d\n", nr_inplace); + printf("Moved reallocs: %d\n", nr_moved); + return 0; +} diff -urN numactl-2.0.6-rc4-orig/versions.ldscript numactl-2.0.6-rc4/versions.ldscript --- numactl-2.0.6-rc4-orig/versions.ldscript 2010-12-22 13:29:50.000000000 +0200 +++ numactl-2.0.6-rc4/versions.ldscript 2010-12-22 20:41:22.000000000 +0200 @@ -87,6 +87,7 @@ numa_alloc_interleaved_subset; numa_alloc_local; numa_alloc_onnode; + numa_realloc; numa_allocate_cpumask; numa_allocate_nodemask; numa_available;
Attachment:
0x17A67A9C.asc
Description: application/pgp-keys
Attachment:
signature.asc
Description: OpenPGP digital signature