This patch adds the migspeed test program.
It tests the speed of migrating pages from one node to another.

Diffed against numactl-1.0.2

Signed-off-by: Christoph Lameter <clameter@sgi.com>

---
 Makefile   |   18 +++--
 migspeed.8 |   31 ++++++++++
 migspeed.c |  185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 227 insertions(+), 7 deletions(-)

Index: numactl-1.0.2/migspeed.8
===================================================================
--- /dev/null
+++ numactl-1.0.2/migspeed.8
@@ -0,0 +1,31 @@
+.\" t
+.\" Copyright 2005-2007 Christoph Lameter, Silicon Graphics, Inc.
+.\"
+.\" based on Andi Kleen's numactl manpage
+.\"
+.TH MIGSPEED 8 "April 2005" "SGI" "Linux Administrator's Manual"
+.SH NAME
+migspeed \- Test the speed of page migration
+.SH SYNOPSIS
+.B migspeed
+-p pages from-nodes to-nodes
+.SH DESCRIPTION
+.B migspeed
+attempts to move a sample of pages from the indicated node to the target node
+and measures the time it takes to perform the move.
+
+.B -p pages
+
+The default sample is 1000 pages. Override that with another number.
+
+.SH NOTES
+Requires an NUMA policy aware kernel with support for page migration
+(Linux 2.6.16 and later).
+
+.SH COPYRIGHT
+Copyright 2007 Christoph Lameter, Silicon Graphics, Inc.
+migratepages is under the GNU General Public License, v.2
+
+.SH SEE ALSO
+.I numactl(8)
+
Index: numactl-1.0.2/Makefile
===================================================================
--- numactl-1.0.2.orig/Makefile
+++ numactl-1.0.2/Makefile
@@ -22,8 +22,7 @@ CLEANFILES := numactl.o libnuma.o numact
 	      test/pagesize test/tshared test/mynode.o test/tshared.o mt.o \
 	      test/mynode test/ftok test/prefered test/randmap \
 	      .depend .depend.X test/nodemap test/distance test/tbitmap \
-		test/after test/before threadtest migratepages
-
+		test/after test/before threadtest migratepages migspeed
 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 \
 	test/*.c
@@ -32,14 +31,17 @@ prefix := /usr
 libdir := ${prefix}/$(shell ./getlibdir)
 docdir := ${prefix}/share/doc
 
-all: numactl migratepages libnuma.so numademo numamon memhog test/tshared stream \
-     test/mynode test/pagesize test/ftok test/prefered test/randmap \
-	 test/nodemap test/distance test/tbitmap
+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
 
 numactl: numactl.o util.o shm.o bitops.o libnuma.so
 
 migratepages: migratepages.c util.o bitops.o libnuma.so
 
+migspeed: migspeed.o util.o libnuma.so
+	${CC} migspeed.c -o migspeed util.o libnuma.so -lrt
+
 util.o: util.c
 
 memhog: util.o memhog.o libnuma.so
@@ -91,6 +93,7 @@ test/nodemap: test/nodemap.c libnuma.so
 
 test/distance: test/distance.c libnuma.so
 
+
 test/tbitmap: test/tbitmap.c libnuma.so
 
 .PHONY: install all clean html depend
@@ -104,12 +107,13 @@ run_on_node_mask set_bind_policy  set_in
 set_membind set_preferred set_strict setlocal_memory tonode_memory \
 tonodemask_memory distance
 
-MANPAGES := numa.3 numactl.8 numastat.8 migratepages.8
+MANPAGES := numa.3 numactl.8 numastat.8 migratepages.8 migspeed.8
 
-install: numactl migratepages numademo.c numamon memhog libnuma.so.1 numa.h numaif.h numastat ${MANPAGES}
+install: numactl migratepages migspeed numademo.c numamon memhog libnuma.so.1 numa.h numaif.h numastat ${MANPAGES}
 	mkdir -p ${prefix}/bin
 	cp numactl ${prefix}/bin
 	cp migratepages ${prefix}/bin
+	cp migspeed ${prefix}/bin
 	cp numademo ${prefix}/bin
 	cp memhog ${prefix}/bin
 	mkdir -p ${prefix}/share/man/man2 ${prefix}/share/man/man8 ${prefix}/share/man/man3
Index: numactl-1.0.2/migspeed.c
===================================================================
--- /dev/null
+++ numactl-1.0.2/migspeed.c
@@ -0,0 +1,185 @@
+/*
+ * Migration test program
+ *
+ * (C) 2007 Silicon Graphics, Inc. Christoph Lameter <clameter@sgi.com>
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "numa.h"
+#include <numaif.h>
+#include <time.h>
+#include <errno.h>
+#include <malloc.h>
+#include <unistd.h>
+#include "util.h"
+
+char *memory;
+
+unsigned long pages = 1000;
+
+unsigned long pagesize;
+
+const char *optstr = "hvp:";
+
+char *cmd;
+
+int verbose;
+struct timespec start,end;
+
+void usage(void)
+{
+	printf("usage %s [-p pages] [-h] [-v] from-nodes to-nodes\n", cmd);
+	printf("      from and to nodes may specified in form N or N-N\n");
+	printf("      -p pages  number of pages to try (defaults to %ld)\n",
+			pages);
+	printf("      -v        verbose\n");
+	printf("      -h        usage\n");
+	exit(1);
+}
+
+int numa_exit_on_error = 1;
+
+void displaymap(void)
+{
+	FILE *f = fopen("/proc/self/numa_maps","r");
+
+	if (!f) {
+		printf("/proc/self/numa_maps not accessible.\n");
+		exit(1);
+	}
+
+	while (!feof(f))
+	{
+		char buffer[2000];
+
+		if (!fgets(buffer, sizeof(buffer), f))
+			break;
+		if (!strstr(buffer, "bind"))
+			continue ;
+		printf(buffer);
+
+	}
+	fclose(f);
+}
+
+int main(int argc, char *argv[])
+{
+	char *p;
+	int option;
+	int error = 0;
+	struct timespec result;
+	unsigned long bytes;
+	double duration, mbytes;
+	nodemask_t from;
+	nodemask_t to;
+
+	pagesize = getpagesize();
+
+	/* Command line processing */
+	opterr = 1;
+	cmd = argv[0];
+
+	while ((option = getopt(argc, argv, optstr)) != EOF)
+	switch (option) {
+	case 'h' :
+	case '?' :
+		error = 1;
+		break;
+	case 'v' :
+		verbose++;
+		break;
+	case 'p' :
+		pages = strtoul(optarg, &p, 0);
+		if (p == optarg || *p)
+			usage();
+		break;
+	}
+
+	if (!argv[optind])
+		usage();
+
+	if (verbose > 1)
+		printf("numa_max_node = %d NUMA_NUM_NODES=%d\n",
+			numa_max_node(), NUMA_NUM_NODES);
+
+	from = nodemask(argv[optind]);
+	if (errno) {
+		perror("from mask");
+		exit(1);
+	}
+
+	if (verbose)
+		printmask("From", &from);
+
+	if (!argv[optind+1])
+		usage();
+
+	to = nodemask(argv[optind+1]);
+	if (errno) {
+		perror("to mask");
+		exit(1);
+	}
+
+	if (verbose)
+		printmask("To", &to);
+
+	bytes = pages * pagesize;
+
+	if (verbose)
+		printf("Allocating %lu pages of %lu bytes of memory\n",
+				pages, pagesize);
+
+	memory = memalign(pagesize, bytes);
+
+	if (!memory) {
+		printf("Out of Memory\n");
+		exit(2);
+	}
+
+	if (mbind(memory, bytes, MPOL_BIND, (unsigned long *)&from,
+				NUMA_NUM_NODES+1, 0) < 0)
+		numa_error("mbind");
+
+	if (verbose)
+		printf("Dirtying memory....\n");
+
+	for (p = memory; p <= memory + bytes; p += pagesize)
+		*p = 1;
+
+	if (verbose)
+		printf("Starting test\n");
+
+	displaymap();
+	clock_gettime(CLOCK_REALTIME, &start);
+
+	if (mbind(memory, bytes, MPOL_BIND, (unsigned long *)&to,
+			NUMA_NUM_NODES+1, MPOL_MF_MOVE)<0)
+		numa_error("memory move");
+
+	clock_gettime(CLOCK_REALTIME, &end);
+	displaymap();
+
+	result.tv_sec = end.tv_sec - start.tv_sec;
+	result.tv_nsec = end.tv_nsec - start.tv_nsec;
+
+	if (result.tv_nsec < 0) {
+		result.tv_sec--;
+		result.tv_nsec += 1000000000;
+	}
+
+	if (result.tv_nsec >= 1000000000) {
+		result.tv_sec++;
+		result.tv_nsec -= 1000000000;
+	}
+
+	duration = result.tv_sec + result.tv_nsec / 1000000000.0;
+	mbytes = bytes / (1024*1024.0);
+
+	printf("%1.1f Mbyte migrated in %1.2f secs. %3.1f Mbytes/second\n",
+			mbytes,
+			duration,
+			mbytes / duration);
+	return 0;
+}
+
