realloc function

Vasileios Karakasis <[email protected]> Sun, 02 Jan 2011 19:37:42 +0200
Newsgroups org.kernel.vger.linux-numa
Message-ID <[email protected]>
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
numactl-2.0.6-rc4-realloc-patch (text/plain, 5.7 KB)
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;
0x17A67A9C.asc (application/pgp-keys, 2.7 KB)
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.9 (GNU/Linux)

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
qgCdEHEBN5VcuGHZ5q/BfHeSXLcApFY=
=MPxZ
-----END PGP PUBLIC KEY BLOCK-----
signature.asc (application/pgp-signature, 197 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAk0gt+YACgkQHUHhfRemepxFNgCgoM8SlyREpOlWK41+J7+kzfSn
nAkAoOZr7naLFFksiDaBsum18gOO0aUB
=ZwE2
-----END PGP SIGNATURE-----