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