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