aboutsummaryrefslogtreecommitdiffstats
path: root/usemem_mbind.c
blob: 6e955493abbb69cb8f7f1f24840969d63cd988f1 (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
 * moves pages across nodes using numactl
 *
 * source code provided by numactl source archive
 *
 * http://numactl.sourcearchive.com/documentation/2.0.5/files.html*
 */

#include <stdio.h>
#include <stdlib.h>
#include <numa.h>
#include <numaif.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <errno.h>

#define PAGES_TO_MOVE	1024

unsigned int pagesize;
unsigned int page_count = PAGES_TO_MOVE;

char *page_base;
void *pages;
void *address;

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 = 0;

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

	for (i = 0; i < page_count; i++) {
		/* get page status for each page */
		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);
		}
	}

	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);
		}
	}
}

void do_mbind(char *message, unsigned long *nodemask, unsigned long maxnode)
{
	printf("%s\n", message);

	if (mbind(pages, page_count * pagesize, MPOL_BIND, nodemask,
			maxnode, MPOL_MF_MOVE | MPOL_MF_STRICT) < 0) {
		perror("mbind");
		errors++;
	}
}

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

	pagesize = getpagesize();

	/* probe number of nodes on the system */
	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, 0);
	numa_bitmask_setbit(new_nodes, 1);

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

	/* check if no. of pages is provided as an argument */
	setbuf(stdout, NULL);
	printf("\n");
	printf("******* mbind migration test *******\n");
	if (argc > 1)
		sscanf(argv[1], "%d", &page_count);

	/* Allocate address for variables */
	page_base = malloc((pagesize + 1) * page_count);
	addr = malloc(sizeof(char *) * page_count);
	status = malloc(sizeof(int *) * page_count);
	nodes = malloc(sizeof(int *) * page_count);
	if (!page_base || !addr || !status || !nodes) {
		printf("Unable to allocate memory\n");
		exit(1);
	}

	/* align page boundaries */
	posix_memalign(&pages, pagesize, page_count * pagesize);

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


	/* Move pages to node zero */
	if (numa_move_pages(0, page_count, addr, nodes, status, 0) < 0) {
		perror("Error moving pages to node 0\n");
		exit(1);
	}

	/* bind pages to node 0 */
	do_mbind("Moving pages via mbind to node 0 ...", old_nodes->maskp, old_nodes->size + 1);

	/* print page status before binding to node 1 */
	print_status("Page status before binding to node 1", pages, status, old_nodes->size + 1, 0);


	/* bind pages to node 1*/
	do_mbind("Moving pages via mbind from node 0 to 1 ...", new_nodes->maskp, new_nodes->size + 1);

	/* print page status after binding to node 1*/
	print_status("Page status after binding to node 1", pages, status, new_nodes->size + 1, 1);

	/* Free malloc'd memory */
	free(page_base);
	free(addr);
	free(nodes);
	free(status);

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

	return errors > 0 ? 1 : 0;
}