1 /*
2 * Copyright © 2009 CNRS
3 * Copyright © 2009-2020 Inria. All rights reserved.
4 * Copyright © 2009-2012 Université Bordeaux
5 * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
6 * See COPYING in top-level directory.
7 */
8
9 #ifndef HWLOC_UTILS_MISC_H
10 #define HWLOC_UTILS_MISC_H
11
12 #include "private/autogen/config.h"
13 #include "hwloc.h"
14 #include "private/misc.h" /* for hwloc_strncasecmp() */
15
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/stat.h>
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif
23 #ifdef HAVE_STDINT_H
24 #include <stdint.h>
25 #endif
26 #include <assert.h>
27
28 extern void usage(const char *name, FILE *where);
29
30 static __hwloc_inline void
hwloc_utils_check_api_version(const char * callname)31 hwloc_utils_check_api_version(const char *callname)
32 {
33 unsigned version = hwloc_get_api_version();
34 if ((version >> 16) != (HWLOC_API_VERSION >> 16)) {
35 fprintf(stderr,
36 "%s compiled for hwloc API 0x%x but running on library API 0x%x.\n"
37 "You may need to point LD_LIBRARY_PATH to the right hwloc library.\n"
38 "Aborting since the new ABI is not backward compatible.\n",
39 callname, (unsigned) HWLOC_API_VERSION, version);
40 exit(EXIT_FAILURE);
41 }
42 }
43
44 static __hwloc_inline void
hwloc_utils_input_format_usage(FILE * where,int addspaces)45 hwloc_utils_input_format_usage(FILE *where, int addspaces)
46 {
47 fprintf (where, " --input <XML file>\n");
48 fprintf (where, " -i <XML file> %*sRead topology from XML file <path>\n",
49 addspaces, " ");
50 #ifdef HWLOC_LINUX_SYS
51 fprintf (where, " --input <directory>\n");
52 fprintf (where, " -i <directory> %*sRead topology from chroot containing the /proc and /sys\n",
53 addspaces, " ");
54 fprintf (where, " %*sof another system\n",
55 addspaces, " ");
56 #endif
57 #ifdef HWLOC_HAVE_X86_CPUID
58 fprintf (where, " --input <directory>\n");
59 fprintf (where, " -i <directory> %*sRead topology from directory containing a CPUID dump\n",
60 addspaces, " ");
61 #endif
62 fprintf (where, " --input \"node:2 2\"\n");
63 fprintf (where, " -i \"node:2 2\" %*sSimulate a fake hierarchy, here with 2 NUMA nodes of 2\n",
64 addspaces, " ");
65 fprintf (where, " %*sprocessors\n",
66 addspaces, " ");
67 fprintf (where, " --input-format <format>\n");
68 fprintf (where, " --if <format> %*sEnforce input format among "
69 "xml, "
70 #ifdef HWLOC_LINUX_SYS
71 "fsroot, "
72 #endif
73 #ifdef HWLOC_HAVE_X86_CPUID
74 "cpuid, "
75 #endif
76 "synthetic\n",
77 addspaces, " ");
78 }
79
80 enum hwloc_utils_input_format {
81 HWLOC_UTILS_INPUT_DEFAULT,
82 HWLOC_UTILS_INPUT_XML,
83 HWLOC_UTILS_INPUT_FSROOT,
84 HWLOC_UTILS_INPUT_SYNTHETIC,
85 HWLOC_UTILS_INPUT_CPUID,
86 HWLOC_UTILS_INPUT_SHMEM
87 };
88
89 static __hwloc_inline enum hwloc_utils_input_format
hwloc_utils_parse_input_format(const char * name,const char * callname)90 hwloc_utils_parse_input_format(const char *name, const char *callname)
91 {
92 if (!hwloc_strncasecmp(name, "default", 3))
93 return HWLOC_UTILS_INPUT_DEFAULT;
94 else if (!hwloc_strncasecmp(name, "xml", 1))
95 return HWLOC_UTILS_INPUT_XML;
96 else if (!hwloc_strncasecmp(name, "fsroot", 1))
97 return HWLOC_UTILS_INPUT_FSROOT;
98 else if (!hwloc_strncasecmp(name, "shmem", 5))
99 return HWLOC_UTILS_INPUT_SHMEM;
100 else if (!hwloc_strncasecmp(name, "synthetic", 1))
101 return HWLOC_UTILS_INPUT_SYNTHETIC;
102 else if (!hwloc_strncasecmp(name, "cpuid", 1))
103 return HWLOC_UTILS_INPUT_CPUID;
104
105 fprintf(stderr, "input format `%s' not supported\n", name);
106 usage(callname, stderr);
107 exit(EXIT_FAILURE);
108 }
109
110 static __hwloc_inline int
hwloc_utils_lookup_input_option(char * argv[],int argc,int * consumed_opts,char ** inputp,enum hwloc_utils_input_format * input_formatp,const char * callname)111 hwloc_utils_lookup_input_option(char *argv[], int argc, int *consumed_opts,
112 char **inputp, enum hwloc_utils_input_format *input_formatp,
113 const char *callname)
114 {
115 if (!strcmp (argv[0], "--input")
116 || !strcmp (argv[0], "-i")) {
117 if (argc <= 1) {
118 usage (callname, stderr);
119 exit(EXIT_FAILURE);
120 }
121 if (strlen(argv[1]))
122 *inputp = argv[1];
123 else
124 *inputp = NULL;
125 *consumed_opts = 1;
126 return 1;
127 }
128 else if (!strcmp (argv[0], "--input-format")
129 || !strcmp (argv[0], "--if")) {
130 if (argc <= 1) {
131 usage (callname, stderr);
132 exit(EXIT_FAILURE);
133 }
134 *input_formatp = hwloc_utils_parse_input_format (argv[1], callname);
135 *consumed_opts = 1;
136 return 1;
137 }
138
139 /* backward compat with 1.0 */
140 else if (!strcmp (argv[0], "--synthetic")) {
141 if (argc <= 1) {
142 usage (callname, stderr);
143 exit(EXIT_FAILURE);
144 }
145 *inputp = argv[1];
146 *input_formatp = HWLOC_UTILS_INPUT_SYNTHETIC;
147 *consumed_opts = 1;
148 return 1;
149 } else if (!strcmp (argv[0], "--xml")) {
150 if (argc <= 1) {
151 usage (callname, stderr);
152 exit(EXIT_FAILURE);
153 }
154 *inputp = argv[1];
155 *input_formatp = HWLOC_UTILS_INPUT_XML;
156 *consumed_opts = 1;
157 return 1;
158 } else if (!strcmp (argv[0], "--fsys-root")) {
159 if (argc <= 1) {
160 usage (callname, stderr);
161 exit(EXIT_FAILURE);
162 }
163 *inputp = argv[1];
164 *input_formatp = HWLOC_UTILS_INPUT_FSROOT;
165 *consumed_opts = 1;
166 return 1;
167 }
168
169 return 0;
170 }
171
172 static __hwloc_inline enum hwloc_utils_input_format
hwloc_utils_autodetect_input_format(const char * input,int verbose)173 hwloc_utils_autodetect_input_format(const char *input, int verbose)
174 {
175 struct stat inputst;
176 int err;
177 err = stat(input, &inputst);
178 if (err < 0) {
179 if (verbose > 0)
180 printf("assuming `%s' is a synthetic topology description\n", input);
181 return HWLOC_UTILS_INPUT_SYNTHETIC;
182 }
183 if (S_ISREG(inputst.st_mode)) {
184 size_t len = strlen(input);
185 if (len >= 6 && !strcmp(input+len-6, ".shmem")) {
186 if (verbose > 0)
187 printf("assuming `%s' is a shmem topology file\n", input);
188 return HWLOC_UTILS_INPUT_SHMEM;
189 }
190 if (verbose > 0)
191 printf("assuming `%s' is a XML file\n", input);
192 return HWLOC_UTILS_INPUT_XML;
193 }
194 if (S_ISDIR(inputst.st_mode)) {
195 char *childpath;
196 struct stat childst;
197 childpath = malloc(strlen(input) + 10); /* enough for appending /sys, /proc or /pu0 */
198 if (childpath) {
199 snprintf(childpath, strlen(input) + 10, "%s/pu0", input);
200 if (stat(childpath, &childst) == 0 && S_ISREG(childst.st_mode)) {
201 if (verbose > 0)
202 printf("assuming `%s' is a cpuid dump\n", input);
203 free(childpath);
204 return HWLOC_UTILS_INPUT_CPUID;
205 }
206 snprintf(childpath, strlen(input) + 10, "%s/proc", input);
207 if (stat(childpath, &childst) == 0 && S_ISDIR(childst.st_mode)) {
208 if (verbose > 0)
209 printf("assuming `%s' is a file-system root\n", input);
210 free(childpath);
211 return HWLOC_UTILS_INPUT_FSROOT;
212 }
213 }
214 free(childpath);
215 }
216 fprintf (stderr, "Unrecognized input file: %s\n", input);
217 return HWLOC_UTILS_INPUT_DEFAULT;
218 }
219
220 static __hwloc_inline int
hwloc_utils_enable_input_format(struct hwloc_topology * topology,unsigned long flags,const char * input,enum hwloc_utils_input_format * input_format,int verbose,const char * callname)221 hwloc_utils_enable_input_format(struct hwloc_topology *topology, unsigned long flags,
222 const char *input,
223 enum hwloc_utils_input_format *input_format,
224 int verbose, const char *callname)
225 {
226 if (*input_format == HWLOC_UTILS_INPUT_DEFAULT && !strcmp(input, "-.xml")) {
227 *input_format = HWLOC_UTILS_INPUT_XML;
228 input = "-";
229 }
230
231 if (*input_format == HWLOC_UTILS_INPUT_DEFAULT) {
232 *input_format = hwloc_utils_autodetect_input_format(input, verbose);
233 if (*input_format == HWLOC_UTILS_INPUT_DEFAULT) {
234 usage (callname, stderr);
235 return EXIT_FAILURE;
236 }
237 }
238
239 switch (*input_format) {
240 case HWLOC_UTILS_INPUT_XML:
241 if (!strcmp(input, "-"))
242 input = "/dev/stdin";
243 if (hwloc_topology_set_xml(topology, input)) {
244 perror("Setting source XML file");
245 return EXIT_FAILURE;
246 }
247 break;
248
249 case HWLOC_UTILS_INPUT_FSROOT: {
250 #ifdef HWLOC_LINUX_SYS
251 char *env;
252 if (asprintf(&env, "HWLOC_FSROOT=%s", input) < 0)
253 fprintf(stderr, "Failed to pass input filesystem root directory to HWLOC_FSROOT environment variable\n");
254 else
255 putenv(env);
256 putenv((char *) "HWLOC_DUMPED_HWDATA_DIR=/var/run/hwloc");
257 env = getenv("HWLOC_COMPONENTS");
258 if (env)
259 fprintf(stderr, "Cannot force linux component first because HWLOC_COMPONENTS environment variable is already set to %s.\n", env);
260 else
261 putenv((char *) "HWLOC_COMPONENTS=linux,pci,stop");
262 /* normally-set flags are overriden by envvar-forced backends */
263 if (flags & HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)
264 putenv((char *) "HWLOC_THISSYSTEM=1");
265 #else /* HWLOC_LINUX_SYS */
266 fprintf(stderr, "This installation of hwloc does not support changing the file-system root, sorry.\n");
267 exit(EXIT_FAILURE);
268 #endif /* HWLOC_LINUX_SYS */
269 break;
270 }
271
272 case HWLOC_UTILS_INPUT_CPUID: {
273 #ifdef HWLOC_HAVE_X86_CPUID
274 size_t len = strlen("HWLOC_CPUID_PATH=")+strlen(input)+1;
275 char *env = malloc(len);
276 if (!env) {
277 fprintf(stderr, "Failed to pass input cpuid dump path to HWLOC_CPUID_PATH environment variable\n");
278 } else {
279 snprintf(env, len, "HWLOC_CPUID_PATH=%s", input);
280 putenv(env);
281 }
282 env = getenv("HWLOC_COMPONENTS");
283 if (env)
284 fprintf(stderr, "Cannot force x86 component first because HWLOC_COMPONENTS environment variable is already set to %s.\n", env);
285 else
286 putenv((char *) "HWLOC_COMPONENTS=x86,stop");
287 /* normally-set flags are overriden by envvar-forced backends */
288 if (flags & HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)
289 putenv((char *) "HWLOC_THISSYSTEM=1");
290 #else
291 fprintf(stderr, "This installation of hwloc does not support loading from a cpuid dump, sorry.\n");
292 exit(EXIT_FAILURE);
293 #endif
294 break;
295 }
296
297 case HWLOC_UTILS_INPUT_SYNTHETIC:
298 if (hwloc_topology_set_synthetic(topology, input)) {
299 perror("Setting synthetic topology description");
300 return EXIT_FAILURE;
301 }
302 break;
303
304 case HWLOC_UTILS_INPUT_SHMEM:
305 break;
306
307 case HWLOC_UTILS_INPUT_DEFAULT:
308 assert(0);
309 }
310
311 return 0;
312 }
313
314 static __hwloc_inline void
hwloc_utils_print_distance_matrix(FILE * output,unsigned nbobjs,hwloc_obj_t * objs,hwloc_uint64_t * matrix,int logical,int show_types)315 hwloc_utils_print_distance_matrix(FILE *output, unsigned nbobjs, hwloc_obj_t *objs, hwloc_uint64_t *matrix, int logical, int show_types)
316 {
317 unsigned i, j;
318
319 /* column header */
320 fprintf(output, " index");
321 for(j=0; j<nbobjs; j++) {
322 if (show_types)
323 fprintf(output, " %s:%d",
324 hwloc_obj_type_string(objs[j]->type),
325 (int) (logical ? objs[j]->logical_index : objs[j]->os_index));
326 else
327 fprintf(output, " % 5d",
328 (int) (logical ? objs[j]->logical_index : objs[j]->os_index));
329 }
330 fprintf(output, "\n");
331
332 /* each line */
333 for(i=0; i<nbobjs; i++) {
334 /* row header */
335 fprintf(output, " % 5d",
336 (int) (logical ? objs[i]->logical_index : objs[i]->os_index));
337
338 /* row values */
339 for(j=0; j<nbobjs; j++) {
340 for(j=0; j<nbobjs; j++)
341 fprintf(output, " % 5d", (int) matrix[i*nbobjs+j]);
342 fprintf(output, "\n");
343 }
344 }
345 }
346
347 static __hwloc_inline int
hwloc_pid_from_number(hwloc_pid_t * pidp,int pid_number,int set_info __hwloc_attribute_unused,int verbose __hwloc_attribute_unused)348 hwloc_pid_from_number(hwloc_pid_t *pidp, int pid_number, int set_info __hwloc_attribute_unused, int verbose __hwloc_attribute_unused)
349 {
350 hwloc_pid_t pid;
351 #ifdef HWLOC_WIN_SYS
352 pid = OpenProcess(set_info ? PROCESS_SET_INFORMATION : PROCESS_QUERY_INFORMATION, FALSE, pid_number);
353 if (!pid) {
354 if (verbose) {
355 DWORD error = GetLastError();
356 char *message;
357 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
358 NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *)&message, 0, NULL);
359 fprintf(stderr, "OpenProcess %d failed %lu: %s\n", pid_number, (unsigned long) error, message);
360 }
361 return -1;
362 }
363 #else
364 pid = pid_number;
365 #endif
366 *pidp = pid;
367 return 0;
368 }
369
370 static __hwloc_inline void
hwloc_lstopo_show_summary_depth(FILE * output,size_t prefixmaxlen,hwloc_topology_t topology,int depth)371 hwloc_lstopo_show_summary_depth(FILE *output, size_t prefixmaxlen, hwloc_topology_t topology, int depth)
372 {
373 hwloc_obj_type_t type = hwloc_get_depth_type(topology, depth);
374 unsigned nbobjs = hwloc_get_nbobjs_by_depth(topology, depth);
375 if (nbobjs) {
376 size_t prefixlen;
377 char _types[64];
378 const char *types;
379
380 if (depth < 0)
381 prefixlen = fprintf(output, "Special depth %d:", depth);
382 else
383 prefixlen = fprintf(output, "%*sdepth %d:", depth, "", depth);
384
385 if (depth < 0) {
386 /* use plain type, we don't want OSdev subtype since it may differ for other objects in the level */
387 types = hwloc_obj_type_string(type);
388 } else {
389 /* use verbose type name, those are identical for all objects on normal levels */
390 hwloc_obj_type_snprintf(_types, sizeof(_types), hwloc_get_obj_by_depth(topology, depth, 0), 1);
391 types = _types;
392 }
393
394 fprintf(output, "%*s%u %s (type #%d)\n",
395 (int)(prefixmaxlen-prefixlen), "",
396 nbobjs, types, (int) type);
397 }
398 }
399
400 static __hwloc_inline void
hwloc_lstopo_show_summary(FILE * output,hwloc_topology_t topology)401 hwloc_lstopo_show_summary(FILE *output, hwloc_topology_t topology)
402 {
403 int topodepth = hwloc_topology_get_depth(topology);
404 int depth;
405 size_t prefixmaxlen, sdepthmaxlen;
406
407 prefixmaxlen = topodepth-1 + strlen("depth xyz: ");
408 sdepthmaxlen = strlen("Special depth -x: ");
409 if (prefixmaxlen < sdepthmaxlen)
410 prefixmaxlen = sdepthmaxlen;
411
412 for (depth = 0; depth < topodepth; depth++)
413 hwloc_lstopo_show_summary_depth(output, prefixmaxlen, topology, depth);
414 /* FIXME: which order? */
415 hwloc_lstopo_show_summary_depth(output, prefixmaxlen, topology, HWLOC_TYPE_DEPTH_NUMANODE);
416 hwloc_lstopo_show_summary_depth(output, prefixmaxlen, topology, HWLOC_TYPE_DEPTH_MEMCACHE);
417 hwloc_lstopo_show_summary_depth(output, prefixmaxlen, topology, HWLOC_TYPE_DEPTH_BRIDGE);
418 hwloc_lstopo_show_summary_depth(output, prefixmaxlen, topology, HWLOC_TYPE_DEPTH_PCI_DEVICE);
419 hwloc_lstopo_show_summary_depth(output, prefixmaxlen, topology, HWLOC_TYPE_DEPTH_OS_DEVICE);
420 hwloc_lstopo_show_summary_depth(output, prefixmaxlen, topology, HWLOC_TYPE_DEPTH_MISC);
421 }
422
423
424 /*************************
425 * Importing/exporting userdata buffers without understanding/decoding/modifying them
426 * Caller must putenv("HWLOC_XML_USERDATA_NOT_DECODED=1") before loading the topology.
427 */
428
429 struct hwloc_utils_userdata {
430 char *name;
431 size_t length;
432 char *buffer; /* NULL if userdata entry in the list is not meant to be exported to XML (added by somebody else) */
433 struct hwloc_utils_userdata *next;
434 };
435
436 static __hwloc_inline void
hwloc_utils_userdata_import_cb(hwloc_topology_t topology __hwloc_attribute_unused,hwloc_obj_t obj,const char * name,const void * buffer,size_t length)437 hwloc_utils_userdata_import_cb(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj, const char *name, const void *buffer, size_t length)
438 {
439 struct hwloc_utils_userdata *u, **up = (struct hwloc_utils_userdata **) &obj->userdata;
440 while (*up)
441 up = &((*up)->next);
442 *up = u = malloc(sizeof(struct hwloc_utils_userdata));
443 u->name = strdup(name);
444 u->length = length;
445 u->buffer = strdup(buffer);
446 u->next = NULL;
447 }
448
449 static __hwloc_inline void
hwloc_utils_userdata_export_cb(void * reserved,hwloc_topology_t topology,hwloc_obj_t obj)450 hwloc_utils_userdata_export_cb(void *reserved, hwloc_topology_t topology, hwloc_obj_t obj)
451 {
452 struct hwloc_utils_userdata *u = obj->userdata;
453 while (u) {
454 if (u->buffer) /* not meant to be exported to XML (added by somebody else) */
455 hwloc_export_obj_userdata(reserved, topology, obj, u->name, u->buffer, u->length);
456 u = u->next;
457 }
458 }
459
460 /* to be called when importing from shmem with non-NULL userdata pointing to stuff in the other process */
461 static __hwloc_inline void
hwloc_utils_userdata_clear_recursive(hwloc_obj_t obj)462 hwloc_utils_userdata_clear_recursive(hwloc_obj_t obj)
463 {
464 hwloc_obj_t child;
465 obj->userdata= NULL;
466 for_each_child(child, obj)
467 hwloc_utils_userdata_clear_recursive(child);
468 for_each_memory_child(child, obj)
469 hwloc_utils_userdata_clear_recursive(child);
470 for_each_io_child(child, obj)
471 hwloc_utils_userdata_clear_recursive(child);
472 for_each_misc_child(child, obj)
473 hwloc_utils_userdata_clear_recursive(child);
474 }
475
476 /* must be called once the caller has removed its own userdata */
477 static __hwloc_inline void
hwloc_utils_userdata_free(hwloc_obj_t obj)478 hwloc_utils_userdata_free(hwloc_obj_t obj)
479 {
480 struct hwloc_utils_userdata *u = obj->userdata, *next;
481 while (u) {
482 next = u->next;
483 assert(u->buffer);
484 free(u->name);
485 free(u->buffer);
486 free(u);
487 u = next;
488 }
489 obj->userdata = NULL;
490 }
491
492 /* must be called once the caller has removed its own userdata */
493 static __hwloc_inline void
hwloc_utils_userdata_free_recursive(hwloc_obj_t obj)494 hwloc_utils_userdata_free_recursive(hwloc_obj_t obj)
495 {
496 hwloc_obj_t child;
497 hwloc_utils_userdata_free(obj);
498 for_each_child(child, obj)
499 hwloc_utils_userdata_free_recursive(child);
500 for_each_memory_child(child, obj)
501 hwloc_utils_userdata_free_recursive(child);
502 for_each_io_child(child, obj)
503 hwloc_utils_userdata_free_recursive(child);
504 for_each_misc_child(child, obj)
505 hwloc_utils_userdata_free_recursive(child);
506 }
507
508 struct hwloc_utils_parsing_flag
509 {
510 unsigned long ulong_flag;
511 const char *str_flag;
512 };
513
514 #define HWLOC_UTILS_PARSING_FLAG(flag){ flag, #flag }
515
516 static __hwloc_inline void
hwloc_utils_parsing_flag_error(const char * err_message,struct hwloc_utils_parsing_flag possible_flags[],int len_possible_flags)517 hwloc_utils_parsing_flag_error(const char *err_message, struct hwloc_utils_parsing_flag possible_flags[], int len_possible_flags) {
518 int i;
519 fprintf(stderr, "Supported %s flags are substrings of:\n", err_message);
520 for(i = 0; i < len_possible_flags; i++) {
521 fprintf(stderr, " ");
522 fprintf(stderr, "%s", possible_flags[i].str_flag);
523 fprintf(stderr, "\n");
524 }
525 }
526
527 static __hwloc_inline unsigned long
hwloc_utils_parse_flags(char * str,struct hwloc_utils_parsing_flag possible_flags[],int len_possible_flags,const char * kind)528 hwloc_utils_parse_flags(char * str, struct hwloc_utils_parsing_flag possible_flags[], int len_possible_flags, const char * kind) {
529 char *ptr;
530 char *end;
531 int ul_flag;
532 int i;
533 int j = 0;
534 unsigned long ul_flags = 0;
535
536 ul_flag = strtoul(str, &end, 0);
537 if(end != str && *end == '\0')
538 return ul_flag;
539
540 while (str[j]) {
541 str[j] = toupper(str[j]);
542 j++;
543 }
544
545 if(strcmp(str, "NONE") == 0)
546 return 0;
547
548 ptr = str;
549 while (ptr) {
550 int count = 0;
551 unsigned long prv_flags = ul_flags;
552 char *pch;
553 int nosuffix = 0;
554
555 /* skip separators at the beginning */
556 ptr += strspn(ptr, ",|+");
557
558 /* find separator after next token */
559 j = strcspn(ptr, " ,|+");
560 if (!j)
561 break;
562
563 if (ptr[j]) {
564 /* mark the end of the token */
565 ptr[j] = '\0';
566 /* mark beginning of next token */
567 end = ptr + j + 1;
568 } else {
569 /* no next token */
570 end = NULL;
571 }
572
573 /* '$' means matching the end of a flag */
574 pch = strchr(ptr, '$');
575 if(pch) {
576 nosuffix = 1;
577 *pch = '\0';
578 }
579
580 for(i = 0; i < len_possible_flags; i++) {
581 if(nosuffix == 1) {
582 /* match the end */
583 if(strcmp(ptr, possible_flags[i].str_flag + strlen(possible_flags[i].str_flag) - strlen(ptr)))
584 continue;
585 } else {
586 /* match anywhere */
587 if(!strstr(possible_flags[i].str_flag, ptr))
588 continue;
589 }
590
591 if(count){
592 fprintf(stderr, "Duplicate match for %s flag `%s'.\n", kind, ptr);
593 hwloc_utils_parsing_flag_error(kind, possible_flags, len_possible_flags);
594 return (unsigned long) - 1;
595 }
596
597 ul_flags |= possible_flags[i].ulong_flag;
598 count++;
599 }
600
601 if(prv_flags == ul_flags) {
602 fprintf(stderr, "Failed to parse %s flag `%s'.\n", kind, ptr);
603 hwloc_utils_parsing_flag_error(kind, possible_flags, len_possible_flags);
604 return (unsigned long) - 1;
605 }
606
607 ptr = end;
608 }
609
610 return ul_flags;
611 }
612
613 static __hwloc_inline hwloc_memattr_id_t
hwloc_utils_parse_memattr_name(hwloc_topology_t topo,const char * str)614 hwloc_utils_parse_memattr_name(hwloc_topology_t topo, const char *str)
615 {
616 const char *name;
617 hwloc_memattr_id_t id;
618 int err;
619 /* try by name, case insensitive */
620 for(id=0; ; id++) {
621 err = hwloc_memattr_get_name(topo, id, &name);
622 if (err < 0)
623 break;
624 if (!strcasecmp(name, str))
625 return id;
626 }
627 /* try by id */
628 if (*str < '0' || *str > '9')
629 return (hwloc_memattr_id_t) -1;
630 id = atoi(str);
631 err = hwloc_memattr_get_name(topo, id, &name);
632 if (err < 0)
633 return (hwloc_memattr_id_t) -1;
634 else
635 return id;
636 }
637
638 static __hwloc_inline int
hwloc_utils_get_best_node_in_array_by_memattr(hwloc_topology_t topology,hwloc_memattr_id_t id,unsigned nbnodes,hwloc_obj_t * nodes,struct hwloc_location * initiator)639 hwloc_utils_get_best_node_in_array_by_memattr(hwloc_topology_t topology, hwloc_memattr_id_t id,
640 unsigned nbnodes, hwloc_obj_t *nodes,
641 struct hwloc_location *initiator)
642 {
643 unsigned nbtgs, i, j;
644 hwloc_obj_t *tgs;
645 int best;
646 hwloc_uint64_t *values, bestvalue;
647 unsigned long mflags;
648 int err;
649
650 err = hwloc_memattr_get_flags(topology, id, &mflags);
651 if (err < 0)
652 goto out;
653
654 nbtgs = 0;
655 err = hwloc_memattr_get_targets(topology, id, initiator, 0, &nbtgs, NULL, NULL);
656 if (err < 0)
657 goto out;
658
659 tgs = malloc(nbtgs * sizeof(*tgs));
660 values = malloc(nbtgs * sizeof(*values));
661 if (!tgs || !values)
662 goto out_with_arrays;
663
664 err = hwloc_memattr_get_targets(topology, id, initiator, 0, &nbtgs, tgs, values);
665 if (err < 0)
666 goto out_with_arrays;
667
668 best = -1;
669 bestvalue = 0;
670 for(i=0; i<nbnodes; i++) {
671 for(j=0; j<nbtgs; j++)
672 if (tgs[j] == nodes[i])
673 break;
674 if (j==nbtgs)
675 /* no target info for this node */
676 continue;
677 if (best == -1) {
678 best = i;
679 bestvalue = values[j];
680 } else if (mflags & HWLOC_MEMATTR_FLAG_HIGHER_FIRST) {
681 if (values[j] > bestvalue) {
682 best = i;
683 bestvalue = values[j];
684 }
685 } else {
686 assert(mflags & HWLOC_MEMATTR_FLAG_LOWER_FIRST);
687 if (values[j] < bestvalue) {
688 best = i;
689 bestvalue = values[j];
690 }
691 }
692 }
693
694 free(tgs);
695 free(values);
696 return best;
697
698 out_with_arrays:
699 free(tgs);
700 free(values);
701 out:
702 return -1;
703 }
704
705 static __hwloc_inline int
hwloc_utils_get_best_node_in_nodeset_by_memattr(hwloc_topology_t topology,hwloc_memattr_id_t id,hwloc_nodeset_t nodeset,struct hwloc_location * initiator)706 hwloc_utils_get_best_node_in_nodeset_by_memattr(hwloc_topology_t topology, hwloc_memattr_id_t id,
707 hwloc_nodeset_t nodeset,
708 struct hwloc_location *initiator)
709 {
710 unsigned nbtgs, i, j;
711 hwloc_obj_t *tgs;
712 int best;
713 hwloc_uint64_t *values, bestvalue;
714 unsigned long mflags;
715 int err;
716
717 err = hwloc_memattr_get_flags(topology, id, &mflags);
718 if (err < 0)
719 goto out;
720
721 nbtgs = 0;
722 err = hwloc_memattr_get_targets(topology, id, initiator, 0, &nbtgs, NULL, NULL);
723 if (err < 0)
724 goto out;
725
726 tgs = malloc(nbtgs * sizeof(*tgs));
727 values = malloc(nbtgs * sizeof(*values));
728 if (!tgs || !values)
729 goto out_with_arrays;
730
731 err = hwloc_memattr_get_targets(topology, id, initiator, 0, &nbtgs, tgs, values);
732 if (err < 0)
733 goto out_with_arrays;
734
735 best = -1;
736 bestvalue = 0;
737 hwloc_bitmap_foreach_begin(i, nodeset) {
738 for(j=0; j<nbtgs; j++)
739 if (tgs[j]->os_index == i)
740 break;
741 if (j==nbtgs)
742 /* no target info for this node */
743 continue;
744 if (best == -1) {
745 best = i;
746 bestvalue = values[j];
747 } else if (mflags & HWLOC_MEMATTR_FLAG_HIGHER_FIRST) {
748 if (values[j] > bestvalue) {
749 best = i;
750 bestvalue = values[j];
751 }
752 } else {
753 assert(mflags & HWLOC_MEMATTR_FLAG_LOWER_FIRST);
754 if (values[j] < bestvalue) {
755 best = i;
756 bestvalue = values[j];
757 }
758 }
759 } hwloc_bitmap_foreach_end();
760
761 if (best == -1)
762 hwloc_bitmap_zero(nodeset);
763 else
764 hwloc_bitmap_only(nodeset, best);
765
766 free(tgs);
767 free(values);
768 return 0;
769
770 out_with_arrays:
771 free(tgs);
772 free(values);
773 out:
774 return -1;
775 }
776
777 static __hwloc_inline unsigned long
hwloc_utils_parse_restrict_flags(char * str)778 hwloc_utils_parse_restrict_flags(char * str){
779 struct hwloc_utils_parsing_flag possible_flags[] = {
780 HWLOC_UTILS_PARSING_FLAG(HWLOC_RESTRICT_FLAG_REMOVE_CPULESS),
781 HWLOC_UTILS_PARSING_FLAG(HWLOC_RESTRICT_FLAG_BYNODESET),
782 HWLOC_UTILS_PARSING_FLAG(HWLOC_RESTRICT_FLAG_REMOVE_MEMLESS),
783 HWLOC_UTILS_PARSING_FLAG(HWLOC_RESTRICT_FLAG_ADAPT_MISC),
784 HWLOC_UTILS_PARSING_FLAG(HWLOC_RESTRICT_FLAG_ADAPT_IO)
785 };
786
787 return hwloc_utils_parse_flags(str, possible_flags, (int) sizeof(possible_flags) / sizeof(possible_flags[0]), "restrict");
788 }
789
790 static __hwloc_inline unsigned long
hwloc_utils_parse_topology_flags(char * str)791 hwloc_utils_parse_topology_flags(char * str) {
792 struct hwloc_utils_parsing_flag possible_flags[] = {
793 HWLOC_UTILS_PARSING_FLAG(HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED),
794 HWLOC_UTILS_PARSING_FLAG(HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM),
795 HWLOC_UTILS_PARSING_FLAG(HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES),
796 HWLOC_UTILS_PARSING_FLAG(HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT)
797 };
798
799 return hwloc_utils_parse_flags(str, possible_flags, (int) sizeof(possible_flags) / sizeof(possible_flags[0]), "topology");
800 }
801
802 static __hwloc_inline unsigned long
hwloc_utils_parse_allow_flags(char * str)803 hwloc_utils_parse_allow_flags(char * str) {
804 struct hwloc_utils_parsing_flag possible_flags[] = {
805 HWLOC_UTILS_PARSING_FLAG(HWLOC_ALLOW_FLAG_ALL),
806 HWLOC_UTILS_PARSING_FLAG(HWLOC_ALLOW_FLAG_LOCAL_RESTRICTIONS),
807 HWLOC_UTILS_PARSING_FLAG(HWLOC_ALLOW_FLAG_CUSTOM)
808 };
809
810 return hwloc_utils_parse_flags(str, possible_flags, (int) sizeof(possible_flags) / sizeof(possible_flags[0]), "allow");
811 }
812
813 static __hwloc_inline unsigned long
hwloc_utils_parse_export_synthetic_flags(char * str)814 hwloc_utils_parse_export_synthetic_flags(char * str) {
815 struct hwloc_utils_parsing_flag possible_flags[] = {
816 HWLOC_UTILS_PARSING_FLAG(HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_EXTENDED_TYPES),
817 HWLOC_UTILS_PARSING_FLAG(HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_ATTRS),
818 HWLOC_UTILS_PARSING_FLAG(HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_V1),
819 HWLOC_UTILS_PARSING_FLAG(HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_IGNORE_MEMORY)
820 };
821
822 return hwloc_utils_parse_flags(str, possible_flags, (int) sizeof(possible_flags) / sizeof(possible_flags[0]), "synthetic");
823 }
824
825 static __hwloc_inline unsigned long
hwloc_utils_parse_export_xml_flags(char * str)826 hwloc_utils_parse_export_xml_flags(char * str) {
827 struct hwloc_utils_parsing_flag possible_flags[] = {
828 HWLOC_UTILS_PARSING_FLAG(HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1)
829 };
830
831 return hwloc_utils_parse_flags(str, possible_flags, (int) sizeof(possible_flags) / sizeof(possible_flags[0]), "xml");
832 }
833
834 static __hwloc_inline unsigned long
hwloc_utils_parse_distances_add_flags(char * str)835 hwloc_utils_parse_distances_add_flags(char * str) {
836 struct hwloc_utils_parsing_flag possible_flags[] = {
837 HWLOC_UTILS_PARSING_FLAG(HWLOC_DISTANCES_ADD_FLAG_GROUP),
838 HWLOC_UTILS_PARSING_FLAG(HWLOC_DISTANCES_ADD_FLAG_GROUP_INACCURATE)
839 };
840
841 return hwloc_utils_parse_flags(str, possible_flags, (int) sizeof(possible_flags) / sizeof(possible_flags[0]), "distances_add");
842 }
843
844 static __hwloc_inline unsigned long
hwloc_utils_parse_memattr_flags(char * str)845 hwloc_utils_parse_memattr_flags(char *str) {
846 struct hwloc_utils_parsing_flag possible_flags[] = {
847 HWLOC_UTILS_PARSING_FLAG(HWLOC_MEMATTR_FLAG_HIGHER_FIRST),
848 HWLOC_UTILS_PARSING_FLAG(HWLOC_MEMATTR_FLAG_LOWER_FIRST),
849 HWLOC_UTILS_PARSING_FLAG(HWLOC_MEMATTR_FLAG_NEED_INITIATOR)
850 };
851
852 return hwloc_utils_parse_flags(str, possible_flags, (int) sizeof(possible_flags) / sizeof(possible_flags[0]), "memattr");
853 }
854
855 static __hwloc_inline unsigned long
hwloc_utils_parse_local_numanode_flags(char * str)856 hwloc_utils_parse_local_numanode_flags(char *str) {
857 struct hwloc_utils_parsing_flag possible_flags[] = {
858 HWLOC_UTILS_PARSING_FLAG(HWLOC_LOCAL_NUMANODE_FLAG_LARGER_LOCALITY),
859 HWLOC_UTILS_PARSING_FLAG(HWLOC_LOCAL_NUMANODE_FLAG_SMALLER_LOCALITY),
860 HWLOC_UTILS_PARSING_FLAG(HWLOC_LOCAL_NUMANODE_FLAG_ALL)
861 };
862
863 return hwloc_utils_parse_flags(str, possible_flags, (int) sizeof(possible_flags) / sizeof(possible_flags[0]), "local_numanode");
864 }
865
866 #endif /* HWLOC_UTILS_MISC_H */
867