xref: /aosp_15_r20/external/ltp/libs/libltpnuma/tst_numa.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2018 Cyril Hrubis <[email protected]>
4*49cdfc7eSAndroid Build Coastguard Worker  */
5*49cdfc7eSAndroid Build Coastguard Worker 
6*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
7*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
8*49cdfc7eSAndroid Build Coastguard Worker #include <ctype.h>
9*49cdfc7eSAndroid Build Coastguard Worker #include "config.h"
10*49cdfc7eSAndroid Build Coastguard Worker #ifdef HAVE_NUMA_V2
11*49cdfc7eSAndroid Build Coastguard Worker # include <numa.h>
12*49cdfc7eSAndroid Build Coastguard Worker # include <numaif.h>
13*49cdfc7eSAndroid Build Coastguard Worker #endif
14*49cdfc7eSAndroid Build Coastguard Worker 
15*49cdfc7eSAndroid Build Coastguard Worker #define TST_NO_DEFAULT_MAIN
16*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
17*49cdfc7eSAndroid Build Coastguard Worker #include "tst_numa.h"
18*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/numaif.h"
19*49cdfc7eSAndroid Build Coastguard Worker 
tst_nodemap_print_counters(struct tst_nodemap * nodes)20*49cdfc7eSAndroid Build Coastguard Worker void tst_nodemap_print_counters(struct tst_nodemap *nodes)
21*49cdfc7eSAndroid Build Coastguard Worker {
22*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int i;
23*49cdfc7eSAndroid Build Coastguard Worker 
24*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < nodes->cnt; i++) {
25*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "Node %i allocated %u pages",
26*49cdfc7eSAndroid Build Coastguard Worker 		        nodes->map[i], nodes->counters[i]);
27*49cdfc7eSAndroid Build Coastguard Worker 	}
28*49cdfc7eSAndroid Build Coastguard Worker }
29*49cdfc7eSAndroid Build Coastguard Worker 
tst_nodemap_reset_counters(struct tst_nodemap * nodes)30*49cdfc7eSAndroid Build Coastguard Worker void tst_nodemap_reset_counters(struct tst_nodemap *nodes)
31*49cdfc7eSAndroid Build Coastguard Worker {
32*49cdfc7eSAndroid Build Coastguard Worker 	size_t arr_size = sizeof(unsigned int) * nodes->cnt;
33*49cdfc7eSAndroid Build Coastguard Worker 
34*49cdfc7eSAndroid Build Coastguard Worker 	if (!nodes->counters)
35*49cdfc7eSAndroid Build Coastguard Worker 		nodes->counters = SAFE_MALLOC(arr_size);
36*49cdfc7eSAndroid Build Coastguard Worker 
37*49cdfc7eSAndroid Build Coastguard Worker 	memset(nodes->counters, 0, arr_size);
38*49cdfc7eSAndroid Build Coastguard Worker }
39*49cdfc7eSAndroid Build Coastguard Worker 
tst_nodemap_free(struct tst_nodemap * nodes)40*49cdfc7eSAndroid Build Coastguard Worker void tst_nodemap_free(struct tst_nodemap *nodes)
41*49cdfc7eSAndroid Build Coastguard Worker {
42*49cdfc7eSAndroid Build Coastguard Worker 	free(nodes->counters);
43*49cdfc7eSAndroid Build Coastguard Worker 	free(nodes);
44*49cdfc7eSAndroid Build Coastguard Worker }
45*49cdfc7eSAndroid Build Coastguard Worker 
46*49cdfc7eSAndroid Build Coastguard Worker #ifdef HAVE_NUMA_V2
47*49cdfc7eSAndroid Build Coastguard Worker 
tst_mempolicy_mode_name(int mode)48*49cdfc7eSAndroid Build Coastguard Worker const char *tst_mempolicy_mode_name(int mode)
49*49cdfc7eSAndroid Build Coastguard Worker {
50*49cdfc7eSAndroid Build Coastguard Worker 	switch (mode) {
51*49cdfc7eSAndroid Build Coastguard Worker 	case MPOL_DEFAULT:
52*49cdfc7eSAndroid Build Coastguard Worker 		return "MPOL_DEFAULT";
53*49cdfc7eSAndroid Build Coastguard Worker 	case MPOL_PREFERRED:
54*49cdfc7eSAndroid Build Coastguard Worker 		return "MPOL_PREFERRED";
55*49cdfc7eSAndroid Build Coastguard Worker 	case MPOL_BIND:
56*49cdfc7eSAndroid Build Coastguard Worker 		return "MPOL_BIND";
57*49cdfc7eSAndroid Build Coastguard Worker 	case MPOL_INTERLEAVE:
58*49cdfc7eSAndroid Build Coastguard Worker 		return "MPOL_INTERLEAVE";
59*49cdfc7eSAndroid Build Coastguard Worker 	case MPOL_LOCAL:
60*49cdfc7eSAndroid Build Coastguard Worker 		return "MPOL_LOCAL";
61*49cdfc7eSAndroid Build Coastguard Worker 	default:
62*49cdfc7eSAndroid Build Coastguard Worker 		return "???";
63*49cdfc7eSAndroid Build Coastguard Worker 	}
64*49cdfc7eSAndroid Build Coastguard Worker }
65*49cdfc7eSAndroid Build Coastguard Worker 
66*49cdfc7eSAndroid Build Coastguard Worker 
inc_counter(unsigned int node,struct tst_nodemap * nodes)67*49cdfc7eSAndroid Build Coastguard Worker static void inc_counter(unsigned int node, struct tst_nodemap *nodes)
68*49cdfc7eSAndroid Build Coastguard Worker {
69*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int i;
70*49cdfc7eSAndroid Build Coastguard Worker 
71*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < nodes->cnt; i++) {
72*49cdfc7eSAndroid Build Coastguard Worker 		if (nodes->map[i] == node) {
73*49cdfc7eSAndroid Build Coastguard Worker 			nodes->counters[i]++;
74*49cdfc7eSAndroid Build Coastguard Worker 			break;
75*49cdfc7eSAndroid Build Coastguard Worker 		}
76*49cdfc7eSAndroid Build Coastguard Worker 	}
77*49cdfc7eSAndroid Build Coastguard Worker }
78*49cdfc7eSAndroid Build Coastguard Worker 
tst_nodemap_count_pages(struct tst_nodemap * nodes,void * ptr,size_t size)79*49cdfc7eSAndroid Build Coastguard Worker void tst_nodemap_count_pages(struct tst_nodemap *nodes,
80*49cdfc7eSAndroid Build Coastguard Worker                              void *ptr, size_t size)
81*49cdfc7eSAndroid Build Coastguard Worker {
82*49cdfc7eSAndroid Build Coastguard Worker 	size_t page_size = getpagesize();
83*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int i;
84*49cdfc7eSAndroid Build Coastguard Worker 	int node;
85*49cdfc7eSAndroid Build Coastguard Worker 	long ret;
86*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int pages = (size + page_size - 1)/page_size;
87*49cdfc7eSAndroid Build Coastguard Worker 
88*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < pages; i++) {
89*49cdfc7eSAndroid Build Coastguard Worker 		ret = get_mempolicy(&node, NULL, 0, ptr + i * page_size, MPOL_F_NODE | MPOL_F_ADDR);
90*49cdfc7eSAndroid Build Coastguard Worker 		if (ret < 0)
91*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK | TERRNO, "get_mempolicy() failed");
92*49cdfc7eSAndroid Build Coastguard Worker 
93*49cdfc7eSAndroid Build Coastguard Worker 		if (node < 0) {
94*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TWARN,
95*49cdfc7eSAndroid Build Coastguard Worker 				"get_mempolicy(...) returned invalid node %i\n", node);
96*49cdfc7eSAndroid Build Coastguard Worker 			continue;
97*49cdfc7eSAndroid Build Coastguard Worker 		}
98*49cdfc7eSAndroid Build Coastguard Worker 
99*49cdfc7eSAndroid Build Coastguard Worker 		inc_counter(node, nodes);
100*49cdfc7eSAndroid Build Coastguard Worker 	}
101*49cdfc7eSAndroid Build Coastguard Worker }
102*49cdfc7eSAndroid Build Coastguard Worker 
tst_numa_map(const char * path,size_t size)103*49cdfc7eSAndroid Build Coastguard Worker void *tst_numa_map(const char *path, size_t size)
104*49cdfc7eSAndroid Build Coastguard Worker {
105*49cdfc7eSAndroid Build Coastguard Worker 	char *ptr;
106*49cdfc7eSAndroid Build Coastguard Worker 	int fd = -1;
107*49cdfc7eSAndroid Build Coastguard Worker 	int flags = MAP_PRIVATE|MAP_ANONYMOUS;
108*49cdfc7eSAndroid Build Coastguard Worker 
109*49cdfc7eSAndroid Build Coastguard Worker 	if (path) {
110*49cdfc7eSAndroid Build Coastguard Worker 		fd = SAFE_OPEN(path, O_CREAT | O_EXCL | O_RDWR, 0666);
111*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_FTRUNCATE(fd, size);
112*49cdfc7eSAndroid Build Coastguard Worker 		flags = MAP_SHARED;
113*49cdfc7eSAndroid Build Coastguard Worker 	}
114*49cdfc7eSAndroid Build Coastguard Worker 
115*49cdfc7eSAndroid Build Coastguard Worker 	ptr = SAFE_MMAP(NULL, size,
116*49cdfc7eSAndroid Build Coastguard Worker 	                PROT_READ|PROT_WRITE, flags, fd, 0);
117*49cdfc7eSAndroid Build Coastguard Worker 
118*49cdfc7eSAndroid Build Coastguard Worker 	if (path) {
119*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(fd);
120*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_UNLINK(path);
121*49cdfc7eSAndroid Build Coastguard Worker 	}
122*49cdfc7eSAndroid Build Coastguard Worker 
123*49cdfc7eSAndroid Build Coastguard Worker 	return ptr;
124*49cdfc7eSAndroid Build Coastguard Worker }
125*49cdfc7eSAndroid Build Coastguard Worker 
node_has_enough_memory(int node,size_t min_kb)126*49cdfc7eSAndroid Build Coastguard Worker static int node_has_enough_memory(int node, size_t min_kb)
127*49cdfc7eSAndroid Build Coastguard Worker {
128*49cdfc7eSAndroid Build Coastguard Worker 	char path[1024];
129*49cdfc7eSAndroid Build Coastguard Worker 	char buf[1024];
130*49cdfc7eSAndroid Build Coastguard Worker 	long mem_total = -1;
131*49cdfc7eSAndroid Build Coastguard Worker 	long mem_used = -1;
132*49cdfc7eSAndroid Build Coastguard Worker 	long file_pages = 0;
133*49cdfc7eSAndroid Build Coastguard Worker 	long mem_avail;
134*49cdfc7eSAndroid Build Coastguard Worker 
135*49cdfc7eSAndroid Build Coastguard Worker 	/* Make sure there is some space for kernel upkeeping as well */
136*49cdfc7eSAndroid Build Coastguard Worker 	min_kb += 4096;
137*49cdfc7eSAndroid Build Coastguard Worker 
138*49cdfc7eSAndroid Build Coastguard Worker 	snprintf(path, sizeof(path), "/sys/devices/system/node/node%i/meminfo", node);
139*49cdfc7eSAndroid Build Coastguard Worker 
140*49cdfc7eSAndroid Build Coastguard Worker 	if (access(path, F_OK)) {
141*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "File '%s' does not exist! NUMA not enabled?", path);
142*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
143*49cdfc7eSAndroid Build Coastguard Worker 	}
144*49cdfc7eSAndroid Build Coastguard Worker 
145*49cdfc7eSAndroid Build Coastguard Worker 	FILE *fp = fopen(path, "r");
146*49cdfc7eSAndroid Build Coastguard Worker 	if (!fp)
147*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO, "Failed to open '%s'", path);
148*49cdfc7eSAndroid Build Coastguard Worker 
149*49cdfc7eSAndroid Build Coastguard Worker 	while (fgets(buf, sizeof(buf), fp)) {
150*49cdfc7eSAndroid Build Coastguard Worker 		long val;
151*49cdfc7eSAndroid Build Coastguard Worker 
152*49cdfc7eSAndroid Build Coastguard Worker 		if (sscanf(buf, "%*s %*i MemTotal: %li", &val) == 1)
153*49cdfc7eSAndroid Build Coastguard Worker 			mem_total = val;
154*49cdfc7eSAndroid Build Coastguard Worker 
155*49cdfc7eSAndroid Build Coastguard Worker 		if (sscanf(buf, "%*s %*i MemUsed: %li", &val) == 1)
156*49cdfc7eSAndroid Build Coastguard Worker 			mem_used = val;
157*49cdfc7eSAndroid Build Coastguard Worker 
158*49cdfc7eSAndroid Build Coastguard Worker 		if (sscanf(buf, "%*s %*i FilePages: %li", &val) == 1)
159*49cdfc7eSAndroid Build Coastguard Worker 			file_pages = val;
160*49cdfc7eSAndroid Build Coastguard Worker 	}
161*49cdfc7eSAndroid Build Coastguard Worker 
162*49cdfc7eSAndroid Build Coastguard Worker 	fclose(fp);
163*49cdfc7eSAndroid Build Coastguard Worker 
164*49cdfc7eSAndroid Build Coastguard Worker 	if (mem_total == -1 || mem_used == -1) {
165*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TWARN, "Failed to parse '%s'", path);
166*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
167*49cdfc7eSAndroid Build Coastguard Worker 	}
168*49cdfc7eSAndroid Build Coastguard Worker 
169*49cdfc7eSAndroid Build Coastguard Worker 	mem_avail = mem_total - mem_used + (9 * file_pages)/10;
170*49cdfc7eSAndroid Build Coastguard Worker 
171*49cdfc7eSAndroid Build Coastguard Worker 	if (mem_avail < (long)min_kb) {
172*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO,
173*49cdfc7eSAndroid Build Coastguard Worker 		        "Not enough free RAM on node %i, have %likB needs %zukB",
174*49cdfc7eSAndroid Build Coastguard Worker 		        node, mem_avail, min_kb);
175*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
176*49cdfc7eSAndroid Build Coastguard Worker 	}
177*49cdfc7eSAndroid Build Coastguard Worker 
178*49cdfc7eSAndroid Build Coastguard Worker 	return 1;
179*49cdfc7eSAndroid Build Coastguard Worker }
180*49cdfc7eSAndroid Build Coastguard Worker 
tst_get_nodemap(int type,size_t min_mem_kb)181*49cdfc7eSAndroid Build Coastguard Worker struct tst_nodemap *tst_get_nodemap(int type, size_t min_mem_kb)
182*49cdfc7eSAndroid Build Coastguard Worker {
183*49cdfc7eSAndroid Build Coastguard Worker 	struct bitmask *membind;
184*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_nodemap *nodes;
185*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int i, cnt;
186*49cdfc7eSAndroid Build Coastguard Worker 
187*49cdfc7eSAndroid Build Coastguard Worker 	if (type & ~(TST_NUMA_MEM))
188*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "Invalid type %i\n", type);
189*49cdfc7eSAndroid Build Coastguard Worker 
190*49cdfc7eSAndroid Build Coastguard Worker 	membind = numa_get_membind();
191*49cdfc7eSAndroid Build Coastguard Worker 
192*49cdfc7eSAndroid Build Coastguard Worker 	cnt = 0;
193*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < membind->size; i++) {
194*49cdfc7eSAndroid Build Coastguard Worker 		if (type & TST_NUMA_MEM && !numa_bitmask_isbitset(membind, i))
195*49cdfc7eSAndroid Build Coastguard Worker 			continue;
196*49cdfc7eSAndroid Build Coastguard Worker 
197*49cdfc7eSAndroid Build Coastguard Worker 		cnt++;
198*49cdfc7eSAndroid Build Coastguard Worker 	}
199*49cdfc7eSAndroid Build Coastguard Worker 
200*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "Found %u NUMA memory nodes", cnt);
201*49cdfc7eSAndroid Build Coastguard Worker 
202*49cdfc7eSAndroid Build Coastguard Worker 	nodes = SAFE_MALLOC(sizeof(struct tst_nodemap)
203*49cdfc7eSAndroid Build Coastguard Worker 	                    + sizeof(unsigned int) * cnt);
204*49cdfc7eSAndroid Build Coastguard Worker 	nodes->cnt = cnt;
205*49cdfc7eSAndroid Build Coastguard Worker 	nodes->counters = NULL;
206*49cdfc7eSAndroid Build Coastguard Worker 
207*49cdfc7eSAndroid Build Coastguard Worker 	cnt = 0;
208*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < membind->size; i++) {
209*49cdfc7eSAndroid Build Coastguard Worker 		if (type & TST_NUMA_MEM &&
210*49cdfc7eSAndroid Build Coastguard Worker 		    (!numa_bitmask_isbitset(membind, i) ||
211*49cdfc7eSAndroid Build Coastguard Worker 		     !node_has_enough_memory(i, min_mem_kb)))
212*49cdfc7eSAndroid Build Coastguard Worker 			continue;
213*49cdfc7eSAndroid Build Coastguard Worker 
214*49cdfc7eSAndroid Build Coastguard Worker 		nodes->map[cnt++] = i;
215*49cdfc7eSAndroid Build Coastguard Worker 	}
216*49cdfc7eSAndroid Build Coastguard Worker 
217*49cdfc7eSAndroid Build Coastguard Worker 	nodes->cnt = cnt;
218*49cdfc7eSAndroid Build Coastguard Worker 
219*49cdfc7eSAndroid Build Coastguard Worker 	numa_bitmask_free(membind);
220*49cdfc7eSAndroid Build Coastguard Worker 
221*49cdfc7eSAndroid Build Coastguard Worker 	return nodes;
222*49cdfc7eSAndroid Build Coastguard Worker }
223*49cdfc7eSAndroid Build Coastguard Worker 
224*49cdfc7eSAndroid Build Coastguard Worker #endif
225