aboutsummaryrefslogtreecommitdiffstats
path: root/usemem_migrate.c
blob: 39d4882cdc2eb97bc7d576a4a8e61dd673b1a34e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * perform page migration across nodes .
 * Part of the code is from numactl's test code migrate_pages.c.
 * Copyright (C) 2006 Silicon Graphics, Inc.
 *		Christoph Lameter <clameter@sgi.com>
 * Copyright (C) 2010-2015 Intel Corporation
 */
#include <numaif.h>
#include <stdio.h>
#include <stdlib.h>
#include <numa.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>

#define PAGES_TO_MIGRATE	1024

unsigned int pagesize;
unsigned int page_count = PAGES_TO_MIGRATE;

char *pages;

void **addr;
int *status;
int *nodes;
int errors;
int nr_nodes;

struct bitmask *old_nodes;
struct bitmask *new_nodes;

void print_status(char *message, char *start_addr, int *status,
		  unsigned long maxnode, int desired)
{

	int i;

	printf("%s\n", message);
	printf("---------------------------------\n");

	/* get page status for each page */
	for (i = 0; i < page_count; i++) {
		if (get_mempolicy(&status[i], NULL, maxnode,
				  (unsigned long *)(start_addr + (i * pagesize)),
				  MPOL_F_NODE|MPOL_F_ADDR) < 0) {
			perror("move_pages");
			exit(1);
		}
	}

	/* print page status for each page */
	for (i = 0; i < page_count; i++) {
		printf("Page %d vaddr=%p node=%d\n", i, pages + i * pagesize, status[i]);

		if (((char *)pages)[ i* pagesize ] != (char) i) {
			printf("*** Page content corrupted.\n");
			errors++;
		} else if (status[i] != desired) {
			printf("Bad page state. Page %d status %d\n", i, status[i]);
			exit(1);
		}
	}
}

int main(int argc, char **argv)
{
	int i, rc;

	pagesize = getpagesize();

	nr_nodes = numa_max_node()+1;

	old_nodes = numa_bitmask_alloc(nr_nodes);
	new_nodes = numa_bitmask_alloc(nr_nodes);
	numa_bitmask_setbit(old_nodes, 1);
	numa_bitmask_setbit(new_nodes, 0);

	/* check if atleast two nodes available for migration */
	if (nr_nodes < 2) {
		printf("A minimum of 2 nodes is required for this test.\n");
		exit(1);
	}

	setbuf(stdout, NULL);
	if (argc > 1)
		sscanf(argv[1], "%d", &page_count);

	/* Allocate pages */
	if ((pages = mmap(NULL, ((pagesize + 1) * page_count), PROT_READ|PROT_WRITE,
			  MAP_POPULATE|MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
		fprintf(stderr, "anon  mmap failed: %s\n", strerror(errno));
		exit(1);
	}

	addr = malloc(sizeof(char *) * page_count);
	status = malloc(sizeof(int *) * page_count);
	nodes = malloc(sizeof(int *) * page_count);
	if (!addr || !status || !nodes) {
		printf("Unable to allocate memory\n");
		exit(1);
	}

	for (i = 0; i < page_count; i++) {
		pages[ i * pagesize ] = (char) i;
		addr[i] = pages + i * pagesize;
		nodes[i] = 1;
		status[i] = -123;
	}

	/* Move to starting node */
	rc = numa_move_pages(0, page_count, addr, nodes, status, MPOL_MF_MOVE_ALL);
	if (rc < 0 && errno != ENOENT) {
		perror("move_pages");
		exit(1);
	}

	/* Print page status before page migration */
	print_status("Page location before migration", pages, status, old_nodes->size + 1, 1);

	/* Migrate pages across nodes */
	if ((rc = numa_migrate_pages(0, old_nodes, new_nodes)) < 0) {
		perror("numa_migrate_pages failed");
		errors++;
	}

	/* Print page locations after migration */
	print_status("Page location after migration", pages, status, new_nodes->size + 1, 0);

	/* Free allocated memory */
	free(addr);
	free(status);
	free(nodes);

	if (!errors)
		printf("Test successful.\n");
	else
		printf("%d errors.\n", errors);

	return errors > 0 ? 1 : 0;
}