1 /*
2 * Copyright © 2009 CNRS
3 * Copyright © 2009-2017 Inria. All rights reserved.
4 * Copyright © 2009-2010, 2012 Université Bordeaux
5 * See COPYING in top-level directory.
6 */
7
8 /** \file
9 * \brief Macros to help interaction between hwloc and Linux libnuma.
10 *
11 * Applications that use both Linux libnuma and hwloc may want to
12 * include this file so as to ease conversion between their respective types.
13 */
14
15 #ifndef HWLOC_LINUX_LIBNUMA_H
16 #define HWLOC_LINUX_LIBNUMA_H
17
18 #include "hwloc.h"
19
20 #include <numa.h>
21
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27
28 /** \defgroup hwlocality_linux_libnuma_ulongs Interoperability with Linux libnuma unsigned long masks
29 *
30 * This interface helps converting between Linux libnuma unsigned long masks
31 * and hwloc cpusets and nodesets.
32 *
33 * \note Topology \p topology must match the current machine.
34 *
35 * \note The behavior of libnuma is undefined if the kernel is not NUMA-aware.
36 * (when CONFIG_NUMA is not set in the kernel configuration).
37 * This helper and libnuma may thus not be strictly compatible in this case,
38 * which may be detected by checking whether numa_available() returns -1.
39 *
40 * @{
41 */
42
43
44 /** \brief Convert hwloc CPU set \p cpuset into the array of unsigned long \p mask
45 *
46 * \p mask is the array of unsigned long that will be filled.
47 * \p maxnode contains the maximal node number that may be stored in \p mask.
48 * \p maxnode will be set to the maximal node number that was found, plus one.
49 *
50 * This function may be used before calling set_mempolicy, mbind, migrate_pages
51 * or any other function that takes an array of unsigned long and a maximal
52 * node number as input parameter.
53 */
54 static __hwloc_inline int
hwloc_cpuset_to_linux_libnuma_ulongs(hwloc_topology_t topology,hwloc_const_cpuset_t cpuset,unsigned long * mask,unsigned long * maxnode)55 hwloc_cpuset_to_linux_libnuma_ulongs(hwloc_topology_t topology, hwloc_const_cpuset_t cpuset,
56 unsigned long *mask, unsigned long *maxnode)
57 {
58 int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
59 unsigned long outmaxnode = -1;
60 hwloc_obj_t node = NULL;
61
62 /* round-up to the next ulong and clear all bytes */
63 *maxnode = (*maxnode + 8*sizeof(*mask) - 1) & ~(8*sizeof(*mask) - 1);
64 memset(mask, 0, *maxnode/8);
65
66 while ((node = hwloc_get_next_obj_covering_cpuset_by_depth(topology, cpuset, depth, node)) != NULL) {
67 if (node->os_index >= *maxnode)
68 continue;
69 mask[node->os_index/sizeof(*mask)/8] |= 1UL << (node->os_index % (sizeof(*mask)*8));
70 if (outmaxnode == (unsigned long) -1 || outmaxnode < node->os_index)
71 outmaxnode = node->os_index;
72 }
73
74 *maxnode = outmaxnode+1;
75 return 0;
76 }
77
78 /** \brief Convert hwloc NUMA node set \p nodeset into the array of unsigned long \p mask
79 *
80 * \p mask is the array of unsigned long that will be filled.
81 * \p maxnode contains the maximal node number that may be stored in \p mask.
82 * \p maxnode will be set to the maximal node number that was found, plus one.
83 *
84 * This function may be used before calling set_mempolicy, mbind, migrate_pages
85 * or any other function that takes an array of unsigned long and a maximal
86 * node number as input parameter.
87 */
88 static __hwloc_inline int
hwloc_nodeset_to_linux_libnuma_ulongs(hwloc_topology_t topology,hwloc_const_nodeset_t nodeset,unsigned long * mask,unsigned long * maxnode)89 hwloc_nodeset_to_linux_libnuma_ulongs(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset,
90 unsigned long *mask, unsigned long *maxnode)
91 {
92 int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
93 unsigned long outmaxnode = -1;
94 hwloc_obj_t node = NULL;
95
96 /* round-up to the next ulong and clear all bytes */
97 *maxnode = (*maxnode + 8*sizeof(*mask) - 1) & ~(8*sizeof(*mask) - 1);
98 memset(mask, 0, *maxnode/8);
99
100 while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL) {
101 if (node->os_index >= *maxnode)
102 continue;
103 if (!hwloc_bitmap_isset(nodeset, node->os_index))
104 continue;
105 mask[node->os_index/sizeof(*mask)/8] |= 1UL << (node->os_index % (sizeof(*mask)*8));
106 if (outmaxnode == (unsigned long) -1 || outmaxnode < node->os_index)
107 outmaxnode = node->os_index;
108 }
109
110 *maxnode = outmaxnode+1;
111 return 0;
112 }
113
114 /** \brief Convert the array of unsigned long \p mask into hwloc CPU set
115 *
116 * \p mask is a array of unsigned long that will be read.
117 * \p maxnode contains the maximal node number that may be read in \p mask.
118 *
119 * This function may be used after calling get_mempolicy or any other function
120 * that takes an array of unsigned long as output parameter (and possibly
121 * a maximal node number as input parameter).
122 */
123 static __hwloc_inline int
hwloc_cpuset_from_linux_libnuma_ulongs(hwloc_topology_t topology,hwloc_cpuset_t cpuset,const unsigned long * mask,unsigned long maxnode)124 hwloc_cpuset_from_linux_libnuma_ulongs(hwloc_topology_t topology, hwloc_cpuset_t cpuset,
125 const unsigned long *mask, unsigned long maxnode)
126 {
127 int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
128 hwloc_obj_t node = NULL;
129 hwloc_bitmap_zero(cpuset);
130 while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL)
131 if (node->os_index < maxnode
132 && (mask[node->os_index/sizeof(*mask)/8] & (1UL << (node->os_index % (sizeof(*mask)*8)))))
133 hwloc_bitmap_or(cpuset, cpuset, node->cpuset);
134 return 0;
135 }
136
137 /** \brief Convert the array of unsigned long \p mask into hwloc NUMA node set
138 *
139 * \p mask is a array of unsigned long that will be read.
140 * \p maxnode contains the maximal node number that may be read in \p mask.
141 *
142 * This function may be used after calling get_mempolicy or any other function
143 * that takes an array of unsigned long as output parameter (and possibly
144 * a maximal node number as input parameter).
145 */
146 static __hwloc_inline int
hwloc_nodeset_from_linux_libnuma_ulongs(hwloc_topology_t topology,hwloc_nodeset_t nodeset,const unsigned long * mask,unsigned long maxnode)147 hwloc_nodeset_from_linux_libnuma_ulongs(hwloc_topology_t topology, hwloc_nodeset_t nodeset,
148 const unsigned long *mask, unsigned long maxnode)
149 {
150 int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
151 hwloc_obj_t node = NULL;
152 hwloc_bitmap_zero(nodeset);
153 while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL)
154 if (node->os_index < maxnode
155 && (mask[node->os_index/sizeof(*mask)/8] & (1UL << (node->os_index % (sizeof(*mask)*8)))))
156 hwloc_bitmap_set(nodeset, node->os_index);
157 return 0;
158 }
159
160 /** @} */
161
162
163
164 /** \defgroup hwlocality_linux_libnuma_bitmask Interoperability with Linux libnuma bitmask
165 *
166 * This interface helps converting between Linux libnuma bitmasks
167 * and hwloc cpusets and nodesets.
168 *
169 * \note Topology \p topology must match the current machine.
170 *
171 * \note The behavior of libnuma is undefined if the kernel is not NUMA-aware.
172 * (when CONFIG_NUMA is not set in the kernel configuration).
173 * This helper and libnuma may thus not be strictly compatible in this case,
174 * which may be detected by checking whether numa_available() returns -1.
175 *
176 * @{
177 */
178
179
180 /** \brief Convert hwloc CPU set \p cpuset into the returned libnuma bitmask
181 *
182 * The returned bitmask should later be freed with numa_bitmask_free.
183 *
184 * This function may be used before calling many numa_ functions
185 * that use a struct bitmask as an input parameter.
186 *
187 * \return newly allocated struct bitmask.
188 */
189 static __hwloc_inline struct bitmask *
190 hwloc_cpuset_to_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_const_cpuset_t cpuset) __hwloc_attribute_malloc;
191 static __hwloc_inline struct bitmask *
hwloc_cpuset_to_linux_libnuma_bitmask(hwloc_topology_t topology,hwloc_const_cpuset_t cpuset)192 hwloc_cpuset_to_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_const_cpuset_t cpuset)
193 {
194 int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
195 hwloc_obj_t node = NULL;
196 struct bitmask *bitmask = numa_allocate_cpumask();
197 if (!bitmask)
198 return NULL;
199 while ((node = hwloc_get_next_obj_covering_cpuset_by_depth(topology, cpuset, depth, node)) != NULL)
200 if (node->attr->numanode.local_memory)
201 numa_bitmask_setbit(bitmask, node->os_index);
202 return bitmask;
203 }
204
205 /** \brief Convert hwloc NUMA node set \p nodeset into the returned libnuma bitmask
206 *
207 * The returned bitmask should later be freed with numa_bitmask_free.
208 *
209 * This function may be used before calling many numa_ functions
210 * that use a struct bitmask as an input parameter.
211 *
212 * \return newly allocated struct bitmask.
213 */
214 static __hwloc_inline struct bitmask *
215 hwloc_nodeset_to_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset) __hwloc_attribute_malloc;
216 static __hwloc_inline struct bitmask *
hwloc_nodeset_to_linux_libnuma_bitmask(hwloc_topology_t topology,hwloc_const_nodeset_t nodeset)217 hwloc_nodeset_to_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset)
218 {
219 int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
220 hwloc_obj_t node = NULL;
221 struct bitmask *bitmask = numa_allocate_cpumask();
222 if (!bitmask)
223 return NULL;
224 while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL)
225 if (hwloc_bitmap_isset(nodeset, node->os_index) && node->attr->numanode.local_memory)
226 numa_bitmask_setbit(bitmask, node->os_index);
227 return bitmask;
228 }
229
230 /** \brief Convert libnuma bitmask \p bitmask into hwloc CPU set \p cpuset
231 *
232 * This function may be used after calling many numa_ functions
233 * that use a struct bitmask as an output parameter.
234 */
235 static __hwloc_inline int
hwloc_cpuset_from_linux_libnuma_bitmask(hwloc_topology_t topology,hwloc_cpuset_t cpuset,const struct bitmask * bitmask)236 hwloc_cpuset_from_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_cpuset_t cpuset,
237 const struct bitmask *bitmask)
238 {
239 int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
240 hwloc_obj_t node = NULL;
241 hwloc_bitmap_zero(cpuset);
242 while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL)
243 if (numa_bitmask_isbitset(bitmask, node->os_index))
244 hwloc_bitmap_or(cpuset, cpuset, node->cpuset);
245 return 0;
246 }
247
248 /** \brief Convert libnuma bitmask \p bitmask into hwloc NUMA node set \p nodeset
249 *
250 * This function may be used after calling many numa_ functions
251 * that use a struct bitmask as an output parameter.
252 */
253 static __hwloc_inline int
hwloc_nodeset_from_linux_libnuma_bitmask(hwloc_topology_t topology,hwloc_nodeset_t nodeset,const struct bitmask * bitmask)254 hwloc_nodeset_from_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_nodeset_t nodeset,
255 const struct bitmask *bitmask)
256 {
257 int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
258 hwloc_obj_t node = NULL;
259 hwloc_bitmap_zero(nodeset);
260 while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL)
261 if (numa_bitmask_isbitset(bitmask, node->os_index))
262 hwloc_bitmap_set(nodeset, node->os_index);
263 return 0;
264 }
265
266 /** @} */
267
268
269 #ifdef __cplusplus
270 } /* extern "C" */
271 #endif
272
273
274 #endif /* HWLOC_LINUX_NUMA_H */
275