blob: 0074180991ec134c14cb66492210a265af235b6a [file] [log] [blame]
Jan Stancekcfdc4f72012-06-28 11:03:15 +02001/*
2 * Copyright (C) 2012 Linux Test Project, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12 * the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include "config.h"
20#include <errno.h>
21#if HAVE_NUMA_H
22#include <numa.h>
23#endif
24#if HAVE_NUMAIF_H
25#include <numaif.h>
26#endif
27#include <stdarg.h>
28#include <stdio.h>
29#include <string.h>
Jan Stancek78de6502012-08-09 14:15:37 +080030#include <stdlib.h>
Jan Stancekcfdc4f72012-06-28 11:03:15 +020031#include <unistd.h>
32#include <errno.h>
33
34#include "test.h"
Jan Stancekcfdc4f72012-06-28 11:03:15 +020035#include "safe_macros.h"
36#include "numa_helper.h"
37#include "linux_syscall_numbers.h"
38
Jan Stancek7312c442012-10-26 15:31:15 +020039unsigned long get_max_node(void)
Jan Stancek78de6502012-08-09 14:15:37 +080040{
41 unsigned long max_node = 0;
Jan Stancek7312c442012-10-26 15:31:15 +020042#if HAVE_NUMA_H
Jan Stancek7bf70142012-07-12 16:09:47 +020043#if !defined(LIBNUMA_API_VERSION) || LIBNUMA_API_VERSION < 2
44 max_node = NUMA_NUM_NODES;
45 /*
46 * NUMA_NUM_NODES is not reliable, libnuma >=2 is looking
47 * at /proc/self/status to figure out correct number.
48 * If buffer is not large enough get_mempolicy will fail with EINVAL.
49 */
50 if (max_node < 1024)
51 max_node = 1024;
52#else
53 max_node = numa_max_possible_node() + 1;
Jan Stancekcfdc4f72012-06-28 11:03:15 +020054#endif
Jan Stancek7312c442012-10-26 15:31:15 +020055#endif /* HAVE_NUMA_H */
Jan Stancek78de6502012-08-09 14:15:37 +080056 return max_node;
57}
Jan Stancek7bf70142012-07-12 16:09:47 +020058
Jan Stancek7312c442012-10-26 15:31:15 +020059#if HAVE_NUMA_H
Wanlong Gao354ebb42012-12-07 10:10:04 +080060static void get_nodemask_allnodes(nodemask_t * nodemask, unsigned long max_node)
Jan Stancek78de6502012-08-09 14:15:37 +080061{
Stanislav Kholmanskikh7037cea2013-08-27 16:49:52 +040062 unsigned long nodemask_size = max_node / 8;
Jan Stancek78de6502012-08-09 14:15:37 +080063 int i;
64 char fn[64];
65 struct stat st;
Jan Stancekcfdc4f72012-06-28 11:03:15 +020066
Jan Stancek78de6502012-08-09 14:15:37 +080067 memset(nodemask, 0, nodemask_size);
68 for (i = 0; i < max_node; i++) {
69 sprintf(fn, "/sys/devices/system/node/node%d", i);
70 if (stat(fn, &st) == 0)
71 nodemask_set(nodemask, i);
Jan Stancekcfdc4f72012-06-28 11:03:15 +020072 }
Jan Stancek78de6502012-08-09 14:15:37 +080073}
Jan Stancekcfdc4f72012-06-28 11:03:15 +020074
Wanlong Gao354ebb42012-12-07 10:10:04 +080075static int filter_nodemask_mem(nodemask_t * nodemask, unsigned long max_node)
Jan Stancek78de6502012-08-09 14:15:37 +080076{
Jan Stancek7bf70142012-07-12 16:09:47 +020077#if MPOL_F_MEMS_ALLOWED
Stanislav Kholmanskikh7037cea2013-08-27 16:49:52 +040078 unsigned long nodemask_size = max_node / 8;
Jan Stancek78de6502012-08-09 14:15:37 +080079 memset(nodemask, 0, nodemask_size);
Jan Stancekcfdc4f72012-06-28 11:03:15 +020080 /*
81 * avoid numa_get_mems_allowed(), because of bug in getpol()
82 * utility function in older versions:
83 * http://www.spinics.net/lists/linux-numa/msg00849.html
84 */
Jan Stancek359980f2013-02-15 10:16:05 +010085 if (ltp_syscall(__NR_get_mempolicy, NULL, nodemask->n,
Wanlong Gao354ebb42012-12-07 10:10:04 +080086 max_node, 0, MPOL_F_MEMS_ALLOWED) < 0)
Jan Stancekcfdc4f72012-06-28 11:03:15 +020087 return -2;
Jan Stancek7bf70142012-07-12 16:09:47 +020088#else
Jan Stancek78de6502012-08-09 14:15:37 +080089 int i;
Jan Stancek7bf70142012-07-12 16:09:47 +020090 /*
91 * old libnuma/kernel don't have MPOL_F_MEMS_ALLOWED, so let's assume
92 * that we can use any node with memory > 0
93 */
Jan Stancek7bf70142012-07-12 16:09:47 +020094 for (i = 0; i < max_node; i++) {
Jan Stancek78de6502012-08-09 14:15:37 +080095 if (!nodemask_isset(nodemask, i))
96 continue;
97 if (numa_node_size64(i, NULL) <= 0)
98 nodemask_clr(nodemask, i);
99 }
100#endif /* MPOL_F_MEMS_ALLOWED */
101 return 0;
102}
103
104static int cpumask_has_cpus(char *cpumask, size_t len)
105{
106 int j;
107 for (j = 0; j < len; j++)
108 if (cpumask[j] == '\0')
109 return 0;
110 else if ((cpumask[j] > '0' && cpumask[j] <= '9') ||
Wanlong Gao354ebb42012-12-07 10:10:04 +0800111 (cpumask[j] >= 'a' && cpumask[j] <= 'f'))
Jan Stancek78de6502012-08-09 14:15:37 +0800112 return 1;
113 return 0;
114
115}
116
Wanlong Gao354ebb42012-12-07 10:10:04 +0800117static void filter_nodemask_cpu(nodemask_t * nodemask, unsigned long max_node)
Jan Stancek78de6502012-08-09 14:15:37 +0800118{
119 char *cpumask = NULL;
120 char fn[64];
121 FILE *f;
122 size_t len;
123 int i, ret;
124
125 for (i = 0; i < max_node; i++) {
126 if (!nodemask_isset(nodemask, i))
127 continue;
128 sprintf(fn, "/sys/devices/system/node/node%d/cpumap", i);
129 f = fopen(fn, "r");
130 if (f) {
131 ret = getdelim(&cpumask, &len, '\n', f);
132 if ((ret > 0) && (!cpumask_has_cpus(cpumask, len)))
133 nodemask_clr(nodemask, i);
134 fclose(f);
Jan Stancekcfdc4f72012-06-28 11:03:15 +0200135 }
136 }
Jan Stancek78de6502012-08-09 14:15:37 +0800137 free(cpumask);
138}
Jan Stancek7bf70142012-07-12 16:09:47 +0200139#endif /* HAVE_NUMA_H */
Jan Stancek78de6502012-08-09 14:15:37 +0800140
141/*
142 * get_allowed_nodes_arr - get number and array of available nodes
143 * @num_nodes: pointer where number of available nodes will be stored
144 * @nodes: array of available node ids, this is MPOL_F_MEMS_ALLOWED
145 * node bitmask compacted (without holes), so that each field
146 * contains node number. If NULL only num_nodes is
147 * returned, otherwise it cotains new allocated array,
148 * which caller is responsible to free.
149 * RETURNS:
150 * 0 on success
151 * -1 on allocation failure
152 * -2 on get_mempolicy failure
153 */
154int get_allowed_nodes_arr(int flag, int *num_nodes, int **nodes)
155{
156 int ret = 0;
157#if HAVE_NUMA_H
158 int i;
159 nodemask_t *nodemask = NULL;
160#endif
161 *num_nodes = 0;
162 if (nodes)
163 *nodes = NULL;
164
165#if HAVE_NUMA_H
Stanislav Kholmanskikh7037cea2013-08-27 16:49:52 +0400166 unsigned long max_node = LTP_ALIGN(get_max_node(),
167 sizeof(unsigned long)*8);
168 unsigned long nodemask_size = max_node / 8;
Jan Stancek78de6502012-08-09 14:15:37 +0800169
170 nodemask = malloc(nodemask_size);
171 if (nodes)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800172 *nodes = malloc(sizeof(int) * max_node);
Jan Stancek78de6502012-08-09 14:15:37 +0800173
174 do {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800175 if (nodemask == NULL || (nodes && (*nodes == NULL))) {
Jan Stancek78de6502012-08-09 14:15:37 +0800176 ret = -1;
177 break;
178 }
179
180 /* allow all nodes at start, then filter based on flags */
181 get_nodemask_allnodes(nodemask, max_node);
182 if ((flag & NH_MEMS) == NH_MEMS) {
183 ret = filter_nodemask_mem(nodemask, max_node);
184 if (ret < 0)
185 break;
186 }
187 if ((flag & NH_CPUS) == NH_CPUS)
188 filter_nodemask_cpu(nodemask, max_node);
189
Wanlong Gao354ebb42012-12-07 10:10:04 +0800190 for (i = 0; i < max_node; i++) {
Jan Stancek78de6502012-08-09 14:15:37 +0800191 if (nodemask_isset(nodemask, i)) {
192 if (nodes)
193 (*nodes)[*num_nodes] = i;
194 (*num_nodes)++;
195 }
196 }
197 } while (0);
198 free(nodemask);
199#endif
200 return ret;
Jan Stancekcfdc4f72012-06-28 11:03:15 +0200201}
202
203/*
204 * get_allowed_nodes - convenience function to get fixed number of nodes
205 * @count: how many nodes to get
206 * @...: int pointers, where node ids will be stored
207 * RETURNS:
208 * 0 on success
209 * -1 on allocation failure
210 * -2 on get_mempolicy failure
211 * -3 on not enough allowed nodes
212 */
Jan Stancek78de6502012-08-09 14:15:37 +0800213int get_allowed_nodes(int flag, int count, ...)
Jan Stancekcfdc4f72012-06-28 11:03:15 +0200214{
215 int ret;
216 int i, *nodep;
217 va_list ap;
218 int num_nodes = 0;
219 int *nodes = NULL;
220
Jan Stancek78de6502012-08-09 14:15:37 +0800221 ret = get_allowed_nodes_arr(flag, &num_nodes, &nodes);
Wanlong Gao6d1110b2012-07-13 14:57:46 +0800222 if (ret < 0)
Jan Stancekcfdc4f72012-06-28 11:03:15 +0200223 return ret;
224
225 va_start(ap, count);
226 for (i = 0; i < count; i++) {
227 nodep = va_arg(ap, int *);
228 if (i < num_nodes) {
229 *nodep = nodes[i];
230 } else {
231 ret = -3;
232 errno = EINVAL;
233 break;
234 }
235 }
236 free(nodes);
237 va_end(ap);
238
239 return ret;
240}
Jan Stancek78de6502012-08-09 14:15:37 +0800241
242static void print_node_info(int flag)
243{
244 int *allowed_nodes = NULL;
245 int i, ret, num_nodes;
246
247 ret = get_allowed_nodes_arr(flag, &num_nodes, &allowed_nodes);
248 printf("nodes (flag=%d): ", flag);
249 if (ret == 0) {
250 for (i = 0; i < num_nodes; i++)
251 printf("%d ", allowed_nodes[i]);
252 printf("\n");
253 } else
254 printf("error(%d)\n", ret);
255 free(allowed_nodes);
256}
257
258/*
259 * nh_dump_nodes - dump info about nodes to stdout
260 */
Mike Frysingere948e1d2014-07-22 07:31:29 -0400261void nh_dump_nodes(void)
Jan Stancek78de6502012-08-09 14:15:37 +0800262{
263 print_node_info(0);
264 print_node_info(NH_MEMS);
265 print_node_info(NH_CPUS);
266 print_node_info(NH_MEMS | NH_CPUS);
267}
Zhouping Liu798adcd2013-03-19 11:40:51 +0800268
269/*
270 * is_numa - judge a system is NUMA system or not
271 * NOTE: the function is designed to try to find more than
272 * 1 available node, at least each node contains memory.
273 * WARN: Don't use this func in child, as it calls tst_brkm()
274 * RETURNS:
275 * 0 - it's not a NUMA system
276 * 1 - it's a NUMA system
277 */
278int is_numa(void (*cleanup_fn)(void))
279{
280 int ret;
281 int numa_nodes = 0;
282
283 ret = get_allowed_nodes_arr(NH_MEMS, &numa_nodes, NULL);
284 if (ret < 0)
285 tst_brkm(TBROK | TERRNO, cleanup_fn, "get_allowed_nodes_arr");
286
287 if (numa_nodes > 1)
288 return 1;
289 else
290 return 0;
291}