1 /*
2  * Copyright © 2009 CNRS
3  * Copyright © 2009-2021 Inria.  All rights reserved.
4  * Copyright © 2009-2012, 2015, 2017 Université Bordeaux
5  * Copyright © 2009-2011 Cisco Systems, Inc.  All rights reserved.
6  * Copyright © 2020 Hewlett Packard Enterprise.  All rights reserved.
7  * See COPYING in top-level directory.
8  */
9 
10 #include "private/autogen/config.h"
11 #include "hwloc.h"
12 #ifdef HWLOC_LINUX_SYS
13 #include "hwloc/linux.h"
14 #endif /* HWLOC_LINUX_SYS */
15 #include "hwloc/shmem.h"
16 
17 #include "private/debug.h" /* for HWLOC_BUILD_ASSERT() */
18 
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #ifdef HAVE_DIRENT_H
23 #include <dirent.h>
24 #endif
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <assert.h>
28 #ifdef HAVE_TIME_H
29 #include <time.h>
30 #endif
31 
32 #ifdef LSTOPO_HAVE_GRAPHICS
33 #ifdef HWLOC_HAVE_CAIRO
34 #include <cairo.h>
35 #endif
36 #endif
37 
38 #ifdef HAVE_SETLOCALE
39 #include <locale.h>
40 #endif
41 
42 #include "lstopo.h"
43 #include "common-ps.h"
44 #include "misc.h"
45 
46 #ifdef __MINGW32__
47 # ifdef HAVE_CLOCK_GETTIME
48 #  undef HAVE_CLOCK_GETTIME
49 # endif
50 #endif
51 
52 #ifdef HAVE_CLOCK_GETTIME
53 # ifndef CLOCK_MONOTONIC /* HP-UX doesn't have CLOCK_MONOTONIC */
54 #  define CLOCK_MONOTONIC CLOCK_REALTIME
55 # endif
56 #endif
57 
58 #ifdef ANDROID
59 extern void setJNIEnv();
60 #endif
61 
open_output(const char * filename,int overwrite)62 FILE *open_output(const char *filename, int overwrite)
63 {
64   const char *extn;
65   struct stat st;
66 
67   if (!filename || !strcmp(filename, "-"))
68     return stdout;
69 
70   extn = strrchr(filename, '.');
71   if (filename[0] == '-' && extn == filename + 1)
72     return stdout;
73 
74   if (!stat(filename, &st) && !overwrite) {
75     errno = EEXIST;
76     return NULL;
77   }
78 
79   return fopen(filename, "w");
80 }
81 
82 const char *task_background_color_string = "#ffff00";
83 
insert_task(hwloc_topology_t topology,hwloc_cpuset_t cpuset,const char * name,int thread)84 static hwloc_obj_t insert_task(hwloc_topology_t topology, hwloc_cpuset_t cpuset, const char * name, int thread)
85 {
86   hwloc_obj_t group, obj;
87 
88   hwloc_bitmap_and(cpuset, cpuset, hwloc_topology_get_topology_cpuset(topology));
89   if (hwloc_bitmap_iszero(cpuset))
90     return NULL;
91 
92   /* try to insert a group at exact position */
93   group = hwloc_topology_alloc_group_object(topology);
94   if (!group)
95     return NULL;
96   group->cpuset = hwloc_bitmap_dup(cpuset);
97   group->attr->group.kind = (unsigned) -1;
98   group = hwloc_topology_insert_group_object(topology, group);
99   if (!group) {
100     /* try to insert in a larger parent */
101     char *s, *gs;
102     hwloc_bitmap_asprintf(&s, cpuset);
103     group = hwloc_get_obj_covering_cpuset(topology, cpuset);
104     hwloc_bitmap_asprintf(&gs, group->cpuset);
105     fprintf(stderr, "%s `%s' binding %s doesn't match any object, extended to %s before inserting the %s in the topology.\n",
106 	    thread ? "Thread" : "Process", name, s, gs, thread ? "thread" : "process");
107     free(s);
108     free(gs);
109   }
110   obj = hwloc_topology_insert_misc_object(topology, group, name);
111   if (!obj)
112     fprintf(stderr, "Failed to insert process `%s'\n", name);
113   else {
114     obj->subtype = strdup("Process");
115     if (strcmp(task_background_color_string, "none")) {
116       char style[19];
117       snprintf(style, sizeof(style), "Background=%s", task_background_color_string);
118       hwloc_obj_add_info(obj, "lstopoStyle", style);
119     }
120   }
121 
122   return obj;
123 }
124 
foreach_process_cb(hwloc_topology_t topology,struct hwloc_ps_process * proc,void * cbdata __hwloc_attribute_unused)125 static void foreach_process_cb(hwloc_topology_t topology,
126 			       struct hwloc_ps_process *proc,
127 			       void *cbdata __hwloc_attribute_unused)
128 {
129   char name[100];
130   unsigned i;
131 
132   snprintf(name, sizeof(name), "%ld", proc->pid);
133   if (*proc->name)
134     snprintf(name, sizeof(name), "%ld %s", proc->pid, proc->name);
135 
136   if (proc->bound)
137     insert_task(topology, proc->cpuset, name, 0);
138 
139   if (proc->nthreads)
140     for(i=0; i<proc->nthreads; i++)
141       if (proc->threads[i].cpuset
142 	  && !hwloc_bitmap_isequal(proc->threads[i].cpuset, proc->cpuset)) {
143 	char task_name[150];
144 	if (*proc->threads[i].name)
145 	  snprintf(task_name, sizeof(task_name), "%s %li %s", name, proc->threads[i].tid, proc->threads[i].name);
146 	else
147 	  snprintf(task_name, sizeof(task_name), "%s %li", name, proc->threads[i].tid);
148 
149 	insert_task(topology, proc->threads[i].cpuset, task_name, 1);
150       }
151 }
152 
add_process_objects(hwloc_topology_t topology)153 static void add_process_objects(hwloc_topology_t topology)
154 {
155   const struct hwloc_topology_support *support = hwloc_topology_get_support(topology);
156   hwloc_obj_t root = hwloc_get_root_obj(topology);
157 
158   if (!support->cpubind->get_proc_cpubind)
159     return;
160 
161   hwloc_ps_foreach_process(topology, root->cpuset,
162 			   foreach_process_cb, NULL,
163 			   HWLOC_PS_FLAG_THREADS | HWLOC_PS_FLAG_SHORTNAME, NULL, HWLOC_PS_ALL_UIDS, NULL);
164 }
165 
lstopo_update_factorize_bounds(unsigned min,unsigned * first,unsigned * last)166 static __hwloc_inline void lstopo_update_factorize_bounds(unsigned min, unsigned *first, unsigned *last)
167 {
168   switch (min) {
169   case 0:
170   case 1:
171   case 2:
172     *first = 1;
173     *last = 0;
174     break;
175   case 3:
176     *first = 1;
177     *last = 1;
178     break;
179   default:
180     *first = 2;
181     *last = 1;
182     break;
183   }
184 }
185 
lstopo_update_factorize_alltypes_bounds(struct lstopo_output * loutput)186 static __hwloc_inline void lstopo_update_factorize_alltypes_bounds(struct lstopo_output *loutput)
187 {
188   hwloc_obj_type_t type;
189   for(type = 0; type < HWLOC_OBJ_TYPE_MAX; type++)
190     lstopo_update_factorize_bounds(loutput->factorize_min[type], &loutput->factorize_first[type], &loutput->factorize_last[type]);
191 }
192 
193 static void
lstopo_add_factorized_attributes(struct lstopo_output * loutput,hwloc_topology_t topology,hwloc_obj_t obj)194 lstopo_add_factorized_attributes(struct lstopo_output *loutput, hwloc_topology_t topology, hwloc_obj_t obj)
195 {
196   hwloc_obj_t child;
197 
198   if (!obj->first_child)
199     return;
200 
201   if (obj->symmetric_subtree && obj->arity > loutput->factorize_min[obj->first_child->type]){
202     int may_factorize = 1;
203     /* check that the object is in a single cpukind */
204     if (loutput->nr_cpukind_styles) {
205       int err = hwloc_cpukinds_get_by_cpuset(topology, obj->cpuset, 0);
206       if (err < 0 && errno == EXDEV)
207         may_factorize = 0;
208     }
209     if (may_factorize) {
210       /* factorize those children */
211       for_each_child(child, obj) {
212         unsigned factorized;
213         if (child->sibling_rank < loutput->factorize_first[child->type]
214             || child->sibling_rank >= obj->arity - loutput->factorize_last[child->type])
215           factorized = 0; /* keep first and last */
216         else if (child->sibling_rank == loutput->factorize_first[child->type])
217           factorized = 1; /* replace with dots */
218         else
219           factorized = -1; /* remove that one */
220         ((struct lstopo_obj_userdata *)child->userdata)->factorized = factorized;
221       }
222     }
223   }
224   /* recurse */
225   for_each_child(child, obj)
226     lstopo_add_factorized_attributes(loutput, topology, child);
227 }
228 
229 static void
lstopo_add_collapse_attributes(hwloc_topology_t topology)230 lstopo_add_collapse_attributes(hwloc_topology_t topology)
231 {
232   hwloc_obj_t obj, collapser = NULL;
233   unsigned collapsed = 0;
234   /* collapse identical PCI devs */
235   for(obj = hwloc_get_next_pcidev(topology, NULL); obj; obj = hwloc_get_next_pcidev(topology, obj)) {
236     if (collapser) {
237       if (!obj->io_arity && !obj->misc_arity
238 	  && obj->parent == collapser->parent
239 	  && obj->attr->pcidev.vendor_id == collapser->attr->pcidev.vendor_id
240 	  && obj->attr->pcidev.device_id == collapser->attr->pcidev.device_id
241 	  && obj->attr->pcidev.subvendor_id == collapser->attr->pcidev.subvendor_id
242 	  && obj->attr->pcidev.subdevice_id == collapser->attr->pcidev.subdevice_id) {
243 	/* collapse another one */
244 	((struct lstopo_obj_userdata *)obj->userdata)->pci_collapsed = -1;
245 	collapsed++;
246 	continue;
247       } else if (collapsed > 1) {
248 	/* end this collapsing */
249 	((struct lstopo_obj_userdata *)collapser->userdata)->pci_collapsed = collapsed;
250 	collapser = NULL;
251 	collapsed = 0;
252       }
253     }
254     if (!obj->io_arity && !obj->misc_arity) {
255       /* start a new collapsing */
256       collapser = obj;
257       collapsed = 1;
258     }
259   }
260   if (collapsed > 1) {
261     /* end this collapsing */
262     ((struct lstopo_obj_userdata *)collapser->userdata)->pci_collapsed = collapsed;
263   }
264 }
265 
266 static void
lstopo_add_cpukind_style(struct lstopo_output * loutput,hwloc_topology_t topology)267 lstopo_add_cpukind_style(struct lstopo_output *loutput, hwloc_topology_t topology)
268 {
269   unsigned i, nr;
270   hwloc_bitmap_t cpuset = hwloc_bitmap_alloc();
271   if (!cpuset)
272     return;
273   nr = hwloc_cpukinds_get_nr(topology, 0);
274   for(i=0; i<nr; i++) {
275     hwloc_obj_t obj;
276     hwloc_cpukinds_get_info(topology, i, cpuset, NULL, NULL, NULL, 0);
277     obj = NULL;
278     while ((obj = hwloc_get_next_obj_inside_cpuset_by_type(topology, cpuset, HWLOC_OBJ_PU, obj)) != NULL)
279       ((struct lstopo_obj_userdata *)obj->userdata)->cpukind_style = i;
280   }
281   hwloc_bitmap_free(cpuset);
282 
283   loutput->nr_cpukind_styles = nr;
284 }
285 
286 static int
lstopo_check_pci_domains(hwloc_topology_t topology)287 lstopo_check_pci_domains(hwloc_topology_t topology)
288 {
289   hwloc_obj_t obj;
290 
291   /* check PCI devices for domains.
292    * they are listed by depth-first search, the order doesn't guarantee a domain at the end.
293    */
294   obj = NULL;
295   while ((obj = hwloc_get_next_pcidev(topology, obj)) != NULL) {
296     if (obj->attr->pcidev.domain)
297       return 1;
298   }
299 
300   /* check PCI Bridges for domains.
301    * they are listed by depth-first search, the order doesn't guarantee a domain at the end.
302    */
303   obj = NULL;
304   while ((obj = hwloc_get_next_bridge(topology, obj)) != NULL) {
305     if (obj->attr->bridge.upstream_type != HWLOC_OBJ_BRIDGE_PCI)
306       break;
307     if (obj->attr->pcidev.domain)
308       return 1;
309   }
310 
311   return 0;
312 }
313 
314 static void
lstopo_populate_userdata(hwloc_obj_t parent)315 lstopo_populate_userdata(hwloc_obj_t parent)
316 {
317   hwloc_obj_t child;
318   struct lstopo_obj_userdata *save = malloc(sizeof(*save));
319 
320   save->common.buffer = NULL; /* so that it is ignored on XML export */
321   save->common.next = parent->userdata;
322   save->factorized = 0;
323   save->pci_collapsed = 0;
324   save->cpukind_style = 0;
325   parent->userdata = save;
326 
327   for_each_child(child, parent)
328     lstopo_populate_userdata(child);
329   for_each_memory_child(child, parent)
330     lstopo_populate_userdata(child);
331   for_each_io_child(child, parent)
332     lstopo_populate_userdata(child);
333   for_each_misc_child(child, parent)
334     lstopo_populate_userdata(child);
335 }
336 
337 static void
lstopo_destroy_userdata(hwloc_obj_t parent)338 lstopo_destroy_userdata(hwloc_obj_t parent)
339 {
340   hwloc_obj_t child;
341   struct lstopo_obj_userdata *save = parent->userdata;
342 
343   if (save) {
344     parent->userdata = save->common.next;
345     free(save);
346   }
347 
348   for_each_child(child, parent)
349     lstopo_destroy_userdata(child);
350   for_each_memory_child(child, parent)
351     lstopo_destroy_userdata(child);
352   for_each_io_child(child, parent)
353     lstopo_destroy_userdata(child);
354   for_each_misc_child(child, parent)
355     lstopo_destroy_userdata(child);
356 }
357 
usage(const char * name,FILE * where)358 void usage(const char *name, FILE *where)
359 {
360   fprintf (where, "Usage: %s [ options ] ... [ filename.format ]\n\n", name);
361   fprintf (where, "See lstopo(1) for more details.\n");
362 
363   fprintf (where, "\nDefault output is "
364 #ifdef LSTOPO_HAVE_GRAPHICS
365 #ifdef HWLOC_WIN_SYS
366 		  "graphical"
367 #elif (defined LSTOPO_HAVE_X11)
368 		  "graphical (X11) if DISPLAY is set, console otherwise"
369 #else
370 		  "console"
371 #endif
372 #else
373 		  "console"
374 #endif
375 		  ".\n");
376 
377   fprintf (where, "Supported output file formats: console, ascii, tikz, fig"
378 #ifdef LSTOPO_HAVE_GRAPHICS
379 #ifdef CAIRO_HAS_PDF_SURFACE
380 		  ", pdf"
381 #endif /* CAIRO_HAS_PDF_SURFACE */
382 #ifdef CAIRO_HAS_PS_SURFACE
383 		  ", ps"
384 #endif /* CAIRO_HAS_PS_SURFACE */
385 #ifdef CAIRO_HAS_PNG_FUNCTIONS
386 		  ", png"
387 #endif /* CAIRO_HAS_PNG_FUNCTIONS */
388 #ifdef CAIRO_HAS_SVG_SURFACE
389 		  ", svg(cairo,native)"
390 #endif /* CAIRO_HAS_SVG_SURFACE */
391 #endif /* LSTOPO_HAVE_GRAPHICS */
392 #if !(defined LSTOPO_HAVE_GRAPHICS) || !(defined CAIRO_HAS_SVG_SURFACE)
393 		  ", svg(native)"
394 #endif
395 		  ", xml, synthetic"
396 		  "\n");
397   fprintf (where, "\nFormatting options:\n");
398   fprintf (where, "  -l --logical          Display hwloc logical object indexes\n");
399   fprintf (where, "  -p --physical         Display OS/physical object indexes\n");
400   fprintf (where, "Output options:\n");
401   fprintf (where, "  --output-format <format>\n");
402   fprintf (where, "  --of <format>         Force the output to use the given format\n");
403   fprintf (where, "  -f --force            Overwrite the output file if it exists\n");
404   fprintf (where, "Textual output options:\n");
405   fprintf (where, "  --only <type>         Only show objects of the given type in the textual output\n");
406   fprintf (where, "  -v --verbose          Include additional details\n");
407   fprintf (where, "  -s --silent           Reduce the amount of details to show\n");
408   fprintf (where, "  --distances           Only show distance matrices\n");
409   fprintf (where, "  --memattrs            Only show memory attributes\n");
410   fprintf (where, "  --cpukinds            Only show CPU kinds\n");
411   fprintf (where, "  -c --cpuset           Show the cpuset of each object\n");
412   fprintf (where, "  -C --cpuset-only      Only show the cpuset of each object\n");
413   fprintf (where, "  --taskset             Show taskset-specific cpuset strings\n");
414   fprintf (where, "Object filtering options:\n");
415   fprintf (where, "  --filter <type>:<knd> Filter objects of the given type, or all.\n");
416   fprintf (where, "     <knd> may be `all' (keep all), `none' (remove all), `structure' or `important'\n");
417   fprintf (where, "  --ignore <type>       Ignore objects of the given type\n");
418   fprintf (where, "  --no-smt              Ignore PUs\n");
419   fprintf (where, "  --no-caches           Do not show caches\n");
420   fprintf (where, "  --no-useless-caches   Do not show caches which do not have a hierarchical\n"
421                   "                        impact\n");
422   fprintf (where, "  --no-icaches          Do not show instruction caches\n");
423   fprintf (where, "  --merge               Do not show levels that do not have a hierarchical\n"
424                   "                        impact\n");
425   fprintf (where, "  --no-collapse         Do not collapse identical PCI devices\n");
426   fprintf (where, "  --restrict [nodeset=]<bitmap>\n");
427   fprintf (where, "                        Restrict the topology to some processors or NUMA nodes.\n");
428   fprintf (where, "  --restrict binding    Restrict the topology to the current process binding\n");
429   fprintf (where, "  --restrict-flags <n>  Set the flags to be used during restrict\n");
430   fprintf (where, "  --no-io               Do not show any I/O device or bridge\n");
431   fprintf (where, "  --no-bridges          Do not any I/O bridge except hostbridges\n");
432   fprintf (where, "  --whole-io            Show all I/O devices and bridges\n");
433   fprintf (where, "Input options:\n");
434   hwloc_utils_input_format_usage(where, 6);
435   fprintf (where, "  --thissystem          Assume that the input topology provides the topology\n"
436 		  "                        for the system on which we are running\n");
437   fprintf (where, "  --pid <pid>           Detect topology as seen by process <pid>\n");
438   fprintf (where, "  --disallowed          Include objects disallowed by administrative limitations\n");
439   fprintf (where, "  --allow <all|local|...>   Change the set of objects marked as allowed\n");
440   fprintf (where, "  --flags <n>           Set the topology flags\n");
441   fprintf (where, "Graphical output options:\n");
442   fprintf (where, "  --children-order plain\n"
443 		  "                        Display memory children below the parent like any other child\n");
444   fprintf (where, "  --no-factorize        Do not factorize identical objects\n");
445   fprintf (where, "  --no-factorize=<type> Do not factorize identical objects of type <type>\n");
446   fprintf (where, "  --factorize           Factorize identical objects (default)\n");
447   fprintf (where, "  --factorize=[<type>,]<N>[,<L>[,<F>]]\n");
448   fprintf (where, "                        Set the minimum number <N> of objects to factorize,\n");
449   fprintf (where, "                        the numbers of first <F> and last <L> to keep,\n");
450   fprintf (where, "                        for all or only the given object type <type>\n");
451   fprintf (where, "  --no-cpukinds         Do not show CPU kinds\n");
452   fprintf (where, "  --fontsize 10         Set size of text font\n");
453   fprintf (where, "  --gridsize 7          Set size of margin between elements\n");
454   fprintf (where, "  --linespacing 4       Set spacing between lines of text\n");
455   fprintf (where, "  --thickness 1         Set thickness of lines and boxes\n");
456   fprintf (where, "  --horiz[=<type,...>]  Horizontal graphical layout instead of nearly 4/3 ratio\n");
457   fprintf (where, "  --vert[=<type,...>]   Vertical graphical layout instead of nearly 4/3 ratio\n");
458   fprintf (where, "  --rect[=<type,...>]   Rectangular graphical layout with nearly 4/3 ratio\n");
459   fprintf (where, "  --text[=<type,...>]   Display text for the given object types\n");
460   fprintf (where, "  --no-text[=<type,..>] Do not display text for the given object types\n");
461   fprintf (where, "  --index=[<type,...>]  Display indexes for the given object types\n");
462   fprintf (where, "  --no-index=[<type,.>] Do not display indexes for the given object types\n");
463   fprintf (where, "  --attrs=[<type,...>]  Display attributes for the given object types\n");
464   fprintf (where, "  --no-attrs=[<type,.>] Do not display attributes for the given object types\n");
465   fprintf (where, "  --no-legend           Remove all text legend lines at the bottom\n");
466   fprintf (where, "  --no-default-legend   Remove default text legend lines at the bottom\n");
467   fprintf (where, "  --append-legend <s>   Append a new line of text at the bottom of the legend\n");
468   fprintf (where, "  --binding-color none    Do not colorize PU and NUMA nodes according to the binding\n");
469   fprintf (where, "  --disallowed-color none Do not colorize disallowed PU and NUMA nodes\n");
470   fprintf (where, "  --top-color <none|#xxyyzz> Change task background color for --top\n");
471   fprintf (where, "Miscellaneous options:\n");
472   fprintf (where, "  --export-xml-flags <n>\n"
473 		  "                        Set flags during the XML topology export\n");
474   fprintf (where, "  --export-synthetic-flags <n>\n"
475 		  "                        Set flags during the synthetic topology export\n");
476   /* --shmem-output-addr is undocumented on purpose */
477   fprintf (where, "  --ps --top            Display processes within the hierarchy\n");
478   fprintf (where, "  --version             Report version and exit\n");
479 }
480 
lstopo_show_interactive_help(void)481 void lstopo_show_interactive_help(void)
482 {
483   printf("\n");
484   printf("Keyboard shortcuts:\n");
485   printf(" Zooming, scrolling and closing:\n");
486   printf("  Zoom-in or out ...................... + -\n");
487   printf("  Reset scale to default .............. 1\n");
488   printf("  Try to fit scale to window .......... F\n");
489   printf("  Resize window to the drawing ........ r\n");
490   printf("  Toggle auto-resizing of the window .. R\n");
491   printf("  Scroll vertically ................... Up Down PageUp PageDown\n");
492   printf("  Scroll horizontally ................. Left Right Ctrl+PageUp/Down\n");
493   printf("  Scroll to the top-left corner ....... Home\n");
494   printf("  Scroll to the bottom-right corner ... End\n");
495   printf("  Refresh the topology ................ F5\n");
496   printf("  Show this help ...................... h H ?\n");
497   printf("  Exit ................................ q Q Esc\n");
498   printf(" Configuration tweaks:\n");
499   printf("  Toggle factorizing or collapsing .... f\n");
500   printf("  Switch display mode for indexes ..... i\n");
501   printf("  Toggle displaying of object text .... t\n");
502   printf("  Toggle displaying of obj attributes . a\n");
503   printf("  Toggle displaying of CPU kinds ...... k\n");
504   printf("  Toggle color for disallowed objects . d\n");
505   printf("  Toggle color for binding objects .... b\n");
506   printf("  Toggle displaying of legend lines ... l\n");
507   printf("  Export to file with current config .. E\n");
508   printf("\n\n");
509   fflush(stdout);
510 }
511 
lstopo__show_interactive_cli_options(const struct lstopo_output * loutput)512 static void lstopo__show_interactive_cli_options(const struct lstopo_output *loutput)
513 {
514   if (loutput->index_type == LSTOPO_INDEX_TYPE_PHYSICAL)
515     printf(" -p");
516   else if (loutput->index_type == LSTOPO_INDEX_TYPE_LOGICAL)
517     printf(" -l");
518   else if (loutput->index_type == LSTOPO_INDEX_TYPE_NONE)
519     printf(" --no-index");
520 
521   if (!loutput->show_attrs_enabled)
522     printf(" --no-attrs");
523   if (!loutput->show_text_enabled)
524     printf(" --no-text");
525 
526   if(!loutput->factorize_enabled)
527     printf(" --no-factorize");
528   if (!loutput->pci_collapse_enabled)
529     printf(" --no-collapse");
530   if (!loutput->show_cpukinds)
531     printf(" --no-cpukinds");
532   if (!loutput->show_binding)
533     printf(" --binding-color none");
534   if (!loutput->show_disallowed)
535     printf(" --disallowed-color none");
536   if (loutput->show_legend == LSTOPO_SHOW_LEGEND_NONE)
537     printf(" --no-legend");
538   else if (loutput->show_legend == LSTOPO_SHOW_LEGEND_NO_DEFAULT)
539     printf(" --no-default-legend");
540 }
541 
lstopo_show_interactive_cli_options(const struct lstopo_output * loutput)542 void lstopo_show_interactive_cli_options(const struct lstopo_output *loutput)
543 {
544 #if (defined LSTOPO_HAVE_GRAPHICS) && (defined CAIRO_HAS_PDF_SURFACE)
545   const char *format = "PDF";
546   const char *extension = "pdf";
547 #else
548   const char *format = "SVG";
549   const char *extension = "svg";
550 #endif
551   printf("\nCommand-line options for the current configuration tweaks:\n");
552   lstopo__show_interactive_cli_options(loutput);
553   printf("\n\nTo export to %s:\n", format);
554   printf("  lstopo  <your options>");
555   lstopo__show_interactive_cli_options(loutput);
556   printf(" topology.%s\n\n", extension);
557 }
558 
559 enum output_format {
560   LSTOPO_OUTPUT_DEFAULT,
561   LSTOPO_OUTPUT_CONSOLE,
562   LSTOPO_OUTPUT_SYNTHETIC,
563   LSTOPO_OUTPUT_ASCII,
564   LSTOPO_OUTPUT_TIKZ,
565   LSTOPO_OUTPUT_FIG,
566   LSTOPO_OUTPUT_PNG,
567   LSTOPO_OUTPUT_PDF,
568   LSTOPO_OUTPUT_PS,
569   LSTOPO_OUTPUT_SVG,
570   LSTOPO_OUTPUT_CAIROSVG,
571   LSTOPO_OUTPUT_NATIVESVG,
572   LSTOPO_OUTPUT_XML,
573   LSTOPO_OUTPUT_SHMEM,
574   LSTOPO_OUTPUT_ERROR
575 };
576 
577 static enum output_format
parse_output_format(const char * name,char * callname __hwloc_attribute_unused)578 parse_output_format(const char *name, char *callname __hwloc_attribute_unused)
579 {
580   if (!hwloc_strncasecmp(name, "default", 3))
581     return LSTOPO_OUTPUT_DEFAULT;
582   else if (!hwloc_strncasecmp(name, "console", 3))
583     return LSTOPO_OUTPUT_CONSOLE;
584   else if (!strcasecmp(name, "synthetic"))
585     return LSTOPO_OUTPUT_SYNTHETIC;
586   else if (!strcasecmp(name, "ascii")
587 	   || !strcasecmp(name, "txt") /* backward compat with 1.10 */)
588     return LSTOPO_OUTPUT_ASCII;
589   else if (!strcasecmp(name, "tikz") || !strcasecmp(name, "tex"))
590     return LSTOPO_OUTPUT_TIKZ;
591   else if (!strcasecmp(name, "fig"))
592     return LSTOPO_OUTPUT_FIG;
593   else if (!strcasecmp(name, "png"))
594     return LSTOPO_OUTPUT_PNG;
595   else if (!strcasecmp(name, "pdf"))
596     return LSTOPO_OUTPUT_PDF;
597   else if (!strcasecmp(name, "ps"))
598     return LSTOPO_OUTPUT_PS;
599   else if (!strcasecmp(name, "svg"))
600     return LSTOPO_OUTPUT_SVG;
601   else if (!strcasecmp(name, "cairosvg") || !strcasecmp(name, "svg(cairo)"))
602     return LSTOPO_OUTPUT_CAIROSVG;
603   else if (!strcasecmp(name, "nativesvg") || !strcasecmp(name, "svg(native)"))
604     return LSTOPO_OUTPUT_NATIVESVG;
605   else if (!strcasecmp(name, "xml"))
606     return LSTOPO_OUTPUT_XML;
607   else if (!strcasecmp(name, "shmem"))
608     return LSTOPO_OUTPUT_SHMEM;
609   else
610     return LSTOPO_OUTPUT_ERROR;
611 }
612 
613 /****************************************************
614  * Store filters during parsing and apply them later
615  */
616 
617 struct lstopo_type_filter { enum hwloc_type_filter_e filter; int changed; };
618 
619 /* if these assert fails, some types were added,
620  * assumptions in macros below must be rechecked
621  */
622 #define init_type_filters() do { \
623   unsigned _i; \
624   HWLOC_BUILD_ASSERT(HWLOC_OBJ_TYPE_MIN == 0); \
625   HWLOC_BUILD_ASSERT(HWLOC_OBJ_TYPE_MAX == 20); \
626   for(_i=HWLOC_OBJ_TYPE_MIN; _i<HWLOC_OBJ_TYPE_MAX; _i++) \
627     type_filter[_i].changed = 0; \
628 } while (0)
629 
630 #define set_type_filter(_type, _filter) do { \
631   type_filter[_type].filter = _filter; \
632   type_filter[_type].changed = 1; \
633 } while (0)
634 
635 #define set_all_types_filter(_filter) do { \
636   unsigned _i; \
637   for(_i=HWLOC_OBJ_TYPE_MIN; _i<HWLOC_OBJ_TYPE_MAX; _i++) \
638     set_type_filter(_i, _filter);                         \
639 } while (0)
640 
641 /* must operate on same types as hwloc_topology_set_io_types_filter() */
642 #define set_io_types_filter(_filter) do { \
643   set_type_filter(HWLOC_OBJ_BRIDGE, _filter); \
644   set_type_filter(HWLOC_OBJ_PCI_DEVICE, _filter); \
645   set_type_filter(HWLOC_OBJ_OS_DEVICE, _filter); \
646 } while (0)
647 
648 /* must operate on same types as hwloc_topology_set_cache_types_filter() */
649 #define set_cache_types_filter(_filter) do { \
650   unsigned _i; \
651   for(_i=HWLOC_OBJ_L1CACHE; _i<HWLOC_OBJ_L3ICACHE; _i++) \
652     set_type_filter(_i, _filter);                        \
653 } while (0)
654 
655 /* must operate on same types as hwloc_topology_set_icache_types_filter() */
656 #define set_icache_types_filter(_filter) do { \
657   unsigned _i; \
658   for(_i=HWLOC_OBJ_L1ICACHE; _i<HWLOC_OBJ_L3ICACHE; _i++) \
659     set_type_filter(_i, _filter);                         \
660 } while (0)
661 
662 #define apply_type_filters(_topo) do { \
663   unsigned _i; \
664   for(_i=HWLOC_OBJ_TYPE_MIN; _i<HWLOC_OBJ_TYPE_MAX; _i++) \
665     if (type_filter[_i].changed) \
666       hwloc_topology_set_type_filter(_topo, _i, type_filter[_i].filter); \
667 } while (0)
668 
669 
670 #define LSTOPO_VERBOSE_MODE_DEFAULT 1
671 
672 int
main(int argc,char * argv[])673 main (int argc, char *argv[])
674 {
675   int err;
676   hwloc_topology_t topology;
677   const char *filename = NULL;
678   unsigned long flags = HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT;
679   unsigned long restrict_flags = 0;
680   unsigned long allow_flags = 0;
681   hwloc_bitmap_t allow_cpuset = NULL, allow_nodeset = NULL;
682   char * callname;
683   char * input = NULL;
684   enum hwloc_utils_input_format input_format = HWLOC_UTILS_INPUT_DEFAULT;
685   enum output_format output_format = LSTOPO_OUTPUT_DEFAULT;
686   struct lstopo_type_filter type_filter[HWLOC_OBJ_TYPE_MAX];
687   char *restrictstring = NULL;
688   struct lstopo_output loutput;
689   output_method *output_func;
690   hwloc_membind_policy_t policy;
691 #ifdef HAVE_CLOCK_GETTIME
692   struct timespec ts1, ts2;
693   unsigned long ms;
694   int measure_load_time = !!getenv("HWLOC_DEBUG_LOAD_TIME");
695 #endif
696   char *env;
697   int top = 0;
698   int opt;
699   unsigned i;
700 
701   callname = strrchr(argv[0], '/');
702   if (!callname)
703     callname = argv[0];
704   else
705     callname++;
706   /* skip argv[0], handle options */
707   argc--;
708   argv++;
709 
710   hwloc_utils_check_api_version(callname);
711 
712   loutput.refreshing = 0;
713 
714   loutput.overwrite = 0;
715 
716   loutput.index_type = LSTOPO_INDEX_TYPE_DEFAULT;
717   loutput.verbose_mode = LSTOPO_VERBOSE_MODE_DEFAULT;
718   loutput.ignore_pus = 0;
719   loutput.ignore_numanodes = 0;
720   loutput.pci_collapse_enabled = 1;
721   loutput.pid_number = -1;
722   loutput.pid = 0;
723   loutput.need_pci_domain = 0;
724 
725   init_type_filters();
726 
727   loutput.factorize_enabled = 1;
728   for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
729     loutput.factorize_min[i] = FACTORIZE_MIN_DEFAULT;
730   lstopo_update_factorize_alltypes_bounds(&loutput);
731 
732   loutput.export_synthetic_flags = 0;
733   loutput.export_xml_flags = 0;
734   loutput.shmem_output_addr = 0;
735 
736   loutput.show_legend = LSTOPO_SHOW_LEGEND_ALL;
737   loutput.legend_append = NULL;
738   loutput.legend_append_nr = 0;
739   snprintf(loutput.title, sizeof(loutput.title), "lstopo");
740 
741   loutput.show_distances_only = 0;
742   loutput.show_memattrs_only = 0;
743   loutput.show_cpukinds_only = 0;
744   loutput.show_only = HWLOC_OBJ_TYPE_NONE;
745   loutput.show_cpuset = 0;
746   loutput.show_taskset = 0;
747 
748   loutput.nr_cpukind_styles = 0;
749 
750   loutput.backend_data = NULL;
751   loutput.methods = NULL;
752 
753   loutput.no_half_lines = 0;
754   loutput.plain_children_order = 0;
755   loutput.fontsize = 10;
756   loutput.gridsize = 7;
757   loutput.linespacing = 4;
758   loutput.thickness = 1;
759 
760   loutput.text_xscale = 1.0f;
761   env = getenv("LSTOPO_TEXT_XSCALE");
762   if (env)
763     loutput.text_xscale = (float) atof(env);
764 
765   for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
766     loutput.force_orient[i] = LSTOPO_ORIENT_NONE;
767   loutput.force_orient[HWLOC_OBJ_PU] = LSTOPO_ORIENT_HORIZ;
768   for(i=HWLOC_OBJ_L1CACHE; i<=HWLOC_OBJ_L3ICACHE; i++)
769     loutput.force_orient[i] = LSTOPO_ORIENT_HORIZ;
770   loutput.force_orient[HWLOC_OBJ_NUMANODE] = LSTOPO_ORIENT_HORIZ;
771   loutput.force_orient[HWLOC_OBJ_MEMCACHE] = LSTOPO_ORIENT_HORIZ;
772   for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++) {
773     loutput.show_indexes[i] = 1;
774     loutput.show_attrs[i] = 1;
775     loutput.show_text[i] = 1;
776   }
777   loutput.show_attrs_enabled = 1;
778   loutput.show_text_enabled = 1;
779 
780   loutput.show_binding = 1;
781   loutput.show_disallowed = 1;
782   loutput.show_cpukinds = 1;
783 
784   /* enable verbose backends */
785   if (!getenv("HWLOC_XML_VERBOSE"))
786     putenv((char *) "HWLOC_XML_VERBOSE=1");
787   if (!getenv("HWLOC_SYNTHETIC_VERBOSE"))
788     putenv((char *) "HWLOC_SYNTHETIC_VERBOSE=1");
789 
790   /* Use localized time prints, and utf-8 characters in the ascii output */
791 #ifdef HAVE_SETLOCALE
792   setlocale(LC_ALL, "");
793 #endif
794 
795   loutput.cpubind_set = hwloc_bitmap_alloc();
796   loutput.membind_set = hwloc_bitmap_alloc();
797   if (!loutput.cpubind_set || !loutput.membind_set)
798     goto out;
799 
800   while (argc >= 1)
801     {
802       opt = 0;
803       if (!strcmp (argv[0], "-v") || !strcmp (argv[0], "--verbose")) {
804 	loutput.verbose_mode++;
805       } else if (!strcmp (argv[0], "-s") || !strcmp (argv[0], "--silent")) {
806 	loutput.verbose_mode--;
807       } else if (!strcmp (argv[0], "--distances")) {
808 	loutput.show_distances_only = 1;
809       } else if (!strcmp (argv[0], "--memattrs")) {
810         loutput.show_memattrs_only = 1;
811       } else if (!strcmp (argv[0], "--cpukinds")) {
812         loutput.show_cpukinds_only = 1;
813       } else if (!strcmp (argv[0], "-h") || !strcmp (argv[0], "--help")) {
814 	usage(callname, stdout);
815         exit(EXIT_SUCCESS);
816       } else if (!strcmp (argv[0], "-f") || !strcmp (argv[0], "--force"))
817 	loutput.overwrite = 1;
818       else if (!strcmp (argv[0], "-l") || !strcmp (argv[0], "--logical"))
819 	loutput.index_type = LSTOPO_INDEX_TYPE_LOGICAL;
820       else if (!strcmp (argv[0], "-p") || !strcmp (argv[0], "--physical"))
821 	loutput.index_type = LSTOPO_INDEX_TYPE_PHYSICAL;
822       else if (!strcmp (argv[0], "-c") || !strcmp (argv[0], "--cpuset"))
823 	loutput.show_cpuset = 1;
824       else if (!strcmp (argv[0], "-C") || !strcmp (argv[0], "--cpuset-only"))
825 	loutput.show_cpuset = 2;
826       else if (!strcmp (argv[0], "--taskset")) {
827 	loutput.show_taskset = 1;
828 	if (!loutput.show_cpuset)
829 	  loutput.show_cpuset = 1;
830       } else if (!strcmp (argv[0], "--only")) {
831 	if (argc < 2)
832 	  goto out_usagefailure;
833         if (hwloc_type_sscanf(argv[1], &loutput.show_only, NULL, 0) < 0)
834 	  fprintf(stderr, "Unsupported type `%s' passed to --only, ignoring.\n", argv[1]);
835 	opt = 1;
836       }
837       else if (!strcmp (argv[0], "--filter")) {
838 	hwloc_obj_type_t type = HWLOC_OBJ_TYPE_NONE;
839 	char *colon;
840 	enum hwloc_type_filter_e filter = HWLOC_TYPE_FILTER_KEEP_ALL;
841 	int all = 0;
842 	int allio = 0;
843 	int allcaches = 0;
844 	int allicaches = 0;
845 	if (argc < 2)
846 	  goto out_usagefailure;
847 	colon = strchr(argv[1], ':');
848 	if (colon) {
849 	  *colon = '\0';
850 	  if (!strcmp(colon+1, "none"))
851 	    filter = HWLOC_TYPE_FILTER_KEEP_NONE;
852 	  else if (!strcmp(colon+1, "all"))
853 	    filter = HWLOC_TYPE_FILTER_KEEP_ALL;
854 	  else if (!strcmp(colon+1, "structure"))
855 	    filter = HWLOC_TYPE_FILTER_KEEP_STRUCTURE;
856 	  else if (!strcmp(colon+1, "important"))
857 	    filter = HWLOC_TYPE_FILTER_KEEP_IMPORTANT;
858 	  else {
859 	    fprintf(stderr, "Unsupported filtering kind `%s' passed to --filter.\n", colon+1);
860 	    goto out_usagefailure;
861 	  }
862 	}
863 	if (!strcmp(argv[1], "all"))
864 	  all = 1;
865 	else if (!strcmp(argv[1], "io"))
866 	  allio = 1;
867 	else if (!strcmp(argv[1], "cache"))
868 	  allcaches = 1;
869 	else if (!strcmp(argv[1], "icache"))
870 	  allicaches = 1;
871 	else if (hwloc_type_sscanf(argv[1], &type, NULL, 0) < 0) {
872 	  fprintf(stderr, "Unsupported type `%s' passed to --filter.\n", argv[1]);
873 	  goto out_usagefailure;
874 	}
875 	if (type == HWLOC_OBJ_PU) {
876 	  if (filter == HWLOC_TYPE_FILTER_KEEP_NONE)
877 	    loutput.ignore_pus = 1;
878 	}
879 	else if (type == HWLOC_OBJ_NUMANODE) {
880 	  if (filter == HWLOC_TYPE_FILTER_KEEP_NONE)
881 	    loutput.ignore_numanodes = 1;
882 	}
883 	else if (all)
884 	  set_all_types_filter(filter);
885 	else if (allio)
886 	  set_io_types_filter(filter);
887 	else if (allcaches) {
888 	  set_cache_types_filter(filter);
889 	  set_type_filter(HWLOC_OBJ_MEMCACHE, filter);
890 	} else if (allicaches)
891 	  set_icache_types_filter(filter);
892 	else
893 	  set_type_filter(type, filter);
894 	opt = 1;
895       }
896       else if (!strcmp (argv[0], "--ignore")) {
897 	hwloc_obj_type_t type;
898 	if (argc < 2)
899 	  goto out_usagefailure;
900 	if (!strcasecmp(argv[1], "cache")) {
901 	  fprintf(stderr, "--ignore Cache not supported anymore, use --no-caches instead.\n");
902 	  goto out_usagefailure;
903 	}
904 	if (hwloc_type_sscanf(argv[1], &type, NULL, 0) < 0)
905 	  fprintf(stderr, "Unsupported type `%s' passed to --ignore, ignoring.\n", argv[1]);
906 	else if (type == HWLOC_OBJ_PU)
907 	  loutput.ignore_pus = 1;
908 	else if (type == HWLOC_OBJ_NUMANODE)
909 	  loutput.ignore_numanodes = 1;
910 	else
911           set_type_filter(type, HWLOC_TYPE_FILTER_KEEP_NONE);
912 	opt = 1;
913       }
914       else if (!strcmp (argv[0], "--no-smt")) {
915 	loutput.ignore_pus = 1;
916       }
917       else if (!strcmp (argv[0], "--no-caches")) {
918         set_cache_types_filter(HWLOC_TYPE_FILTER_KEEP_NONE);
919         set_type_filter(HWLOC_OBJ_MEMCACHE, HWLOC_TYPE_FILTER_KEEP_NONE);
920       }
921       else if (!strcmp (argv[0], "--no-useless-caches")) {
922         set_cache_types_filter(HWLOC_TYPE_FILTER_KEEP_STRUCTURE);
923         set_type_filter(HWLOC_OBJ_MEMCACHE, HWLOC_TYPE_FILTER_KEEP_STRUCTURE);
924       }
925       else if (!strcmp (argv[0], "--no-icaches")) {
926 	set_icache_types_filter(HWLOC_TYPE_FILTER_KEEP_NONE);
927       }
928       else if (!strcmp (argv[0], "--disallowed") || !strcmp (argv[0], "--whole-system"))
929 	flags |= HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED;
930       else if (!strcmp (argv[0], "--allow")) {
931 	if (argc < 2)
932 	  goto out_usagefailure;
933 	if (!strcmp(argv[1], "all")) {
934 	  allow_flags = HWLOC_ALLOW_FLAG_ALL;
935 	} else if (!strcmp(argv[1], "local")) {
936 	  allow_flags = HWLOC_ALLOW_FLAG_LOCAL_RESTRICTIONS;
937 	  flags |= HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM;
938 	} else {
939 	  hwloc_bitmap_t set = hwloc_bitmap_alloc();
940 	  const char *begin = argv[1];
941 	  if (!strncmp(begin, "nodeset=", 8))
942 	    begin += 8;
943 	  hwloc_bitmap_sscanf(set, begin);
944 	  if (begin == argv[1])
945 	    allow_cpuset = set;
946 	  else
947 	    allow_nodeset = set;
948 	  allow_flags = HWLOC_ALLOW_FLAG_CUSTOM;
949 	}
950 	opt = 1;
951 	flags |= HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED;
952 
953       } else if (!strcmp (argv[0], "--no-io")) {
954 	set_io_types_filter(HWLOC_TYPE_FILTER_KEEP_NONE);
955       } else if (!strcmp (argv[0], "--no-bridges")) {
956 	set_type_filter(HWLOC_OBJ_BRIDGE, HWLOC_TYPE_FILTER_KEEP_NONE);
957       } else if (!strcmp (argv[0], "--whole-io")) {
958 	set_io_types_filter(HWLOC_TYPE_FILTER_KEEP_ALL);
959       } else if (!strcmp (argv[0], "--merge")) {
960 	set_all_types_filter(HWLOC_TYPE_FILTER_KEEP_STRUCTURE);
961       }
962       else if (!strcmp (argv[0], "--no-collapse"))
963 	loutput.pci_collapse_enabled = 0;
964 
965       else if (!strcmp (argv[0], "--no-factorize")) {
966 	for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
967 	  loutput.factorize_min[i] = FACTORIZE_MIN_DISABLED;
968       }
969       else if (!strncmp (argv[0], "--no-factorize=", 15)) {
970 	hwloc_obj_type_t type;
971 	const char *tmp = argv[0]+15;
972 	if (hwloc_type_sscanf(tmp, &type, NULL, 0) < 0) {
973 	  fprintf(stderr, "Unsupported parameter `%s' passed to %s, ignoring.\n", tmp, argv[0]);
974 	  goto out_usagefailure;
975 	}
976 	loutput.factorize_min[type] = FACTORIZE_MIN_DISABLED;
977       }
978       else if (!strcmp (argv[0], "--factorize")) {
979 	for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
980 	  loutput.factorize_min[i] = FACTORIZE_MIN_DEFAULT;
981 	lstopo_update_factorize_alltypes_bounds(&loutput);
982       }
983       else if (!strncmp (argv[0], "--factorize=", 12)) {
984 	hwloc_obj_type_t type, type_min, type_max;
985 	unsigned min, first, last;
986 	const char *tmp = argv[0]+12;
987 	const char *sep1, *sep2, *sep3;
988 
989 	if (*tmp < '0' || *tmp > '9') {
990 	  if (hwloc_type_sscanf(tmp, &type, NULL, 0) < 0) {
991 	    fprintf(stderr, "Unsupported type `%s' passed to %s, ignoring.\n", tmp, argv[0]);
992 	    goto out_usagefailure;
993 	  }
994 	  type_min = type;
995 	  type_max = type+1;
996 	  sep1 = strchr(tmp, ',');
997 	} else {
998 	  type_min = HWLOC_OBJ_TYPE_MIN;
999 	  type_max = HWLOC_OBJ_TYPE_MAX;
1000 	  sep1 = tmp-1;
1001 	}
1002 
1003 	if (!sep1) {
1004 	  min = FACTORIZE_MIN_DEFAULT;
1005 	  lstopo_update_factorize_bounds(min, &first, &last);
1006 	} else {
1007 	  min = atoi(sep1+1);
1008 	  lstopo_update_factorize_bounds(min, &first, &last);
1009 	  sep2 = strchr(sep1+1, ',');
1010 	  if (sep2) {
1011 	    first = atoi(sep2+1);
1012 	    sep3 = strchr(sep2+1, ',');
1013 	    if (sep3)
1014 	      last = atoi(sep3+1);
1015 	  }
1016 	}
1017 
1018 	for(i=type_min; i<(unsigned)type_max; i++) {
1019 	  loutput.factorize_min[i] = min;
1020 	  loutput.factorize_first[i] = first;
1021 	  loutput.factorize_last[i] = last;
1022 	}
1023       }
1024 
1025       else if (!strcmp (argv[0], "--thissystem"))
1026 	flags |= HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM;
1027       else if (!strcmp (argv[0], "--flags")) {
1028 	if (argc < 2)
1029 	  goto out_usagefailure;
1030 	flags = hwloc_utils_parse_topology_flags(argv[1]);
1031         if(flags == (unsigned long)-1)
1032           goto out;
1033 	opt = 1;
1034       }
1035       else if (!strcmp (argv[0], "--restrict")) {
1036 	if (argc < 2)
1037 	  goto out_usagefailure;
1038         if(strncmp(argv[1], "nodeset=", 8)) {
1039           restrictstring = strdup(argv[1]);
1040         } else {
1041           restrictstring = strdup(argv[1]+8);
1042           restrict_flags |= HWLOC_RESTRICT_FLAG_BYNODESET;
1043         }
1044 	opt = 1;
1045       }
1046       else if (!strcmp (argv[0], "--restrict-flags")) {
1047 	if (argc < 2)
1048 	  goto out_usagefailure;
1049 	restrict_flags = hwloc_utils_parse_restrict_flags(argv[1]);
1050         if(restrict_flags == (unsigned long)-1)
1051           goto out;
1052 	opt = 1;
1053       }
1054       else if (!strcmp (argv[0], "--export-xml-flags")) {
1055 	if (argc < 2)
1056 	  goto out_usagefailure;
1057 	loutput.export_xml_flags = hwloc_utils_parse_export_xml_flags(argv[1]);
1058         if(loutput.export_xml_flags == (unsigned long)-1)
1059           goto out;
1060 	opt = 1;
1061       }
1062       else if (!strcmp (argv[0], "--export-synthetic-flags")) {
1063 	if (argc < 2)
1064 	  goto out_usagefailure;
1065 	loutput.export_synthetic_flags = hwloc_utils_parse_export_synthetic_flags(argv[1]);
1066         if(loutput.export_synthetic_flags == (unsigned long)-1)
1067           goto out;
1068 	opt = 1;
1069       }
1070       else if (!strcmp (argv[0], "--horiz"))
1071 	for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
1072 	  loutput.force_orient[i] = LSTOPO_ORIENT_HORIZ;
1073       else if (!strcmp (argv[0], "--vert"))
1074 	for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
1075 	  loutput.force_orient[i] = LSTOPO_ORIENT_VERT;
1076       else if (!strcmp (argv[0], "--rect"))
1077 	for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
1078 	  loutput.force_orient[i] = LSTOPO_ORIENT_RECT;
1079       else if (!strncmp (argv[0], "--horiz=", 8)
1080 	       || !strncmp (argv[0], "--vert=", 7)
1081 	       || !strncmp (argv[0], "--rect=", 7)) {
1082 	enum lstopo_orient_e orient = (argv[0][2] == 'h') ? LSTOPO_ORIENT_HORIZ : (argv[0][2] == 'v') ? LSTOPO_ORIENT_VERT : LSTOPO_ORIENT_RECT;
1083 	char *tmp = argv[0] + ((argv[0][2] == 'h') ? 8 : 7);
1084 	while (tmp) {
1085 	  char *end = strchr(tmp, ',');
1086 	  hwloc_obj_type_t type;
1087 	  if (end)
1088 	    *end = '\0';
1089 	  if (hwloc_type_sscanf(tmp, &type, NULL, 0) < 0)
1090 	    fprintf(stderr, "Unsupported type `%s' passed to %s, ignoring.\n", tmp, argv[0]);
1091 	  else
1092 	    loutput.force_orient[type] = orient;
1093 	  if (!end)
1094 	    break;
1095 	  tmp = end+1;
1096         }
1097       }
1098 
1099       else if (!strcmp (argv[0], "--binding-color")) {
1100 	if (argc < 2)
1101 	  goto out_usagefailure;
1102 	if (!strcmp(argv[1], "none"))
1103 	  loutput.show_binding = 0;
1104 	else
1105 	  fprintf(stderr, "Unsupported color `%s' passed to %s, ignoring.\n", argv[1], argv[0]);
1106 	opt = 1;
1107       }
1108       else if (!strcmp (argv[0], "--disallowed-color")) {
1109 	if (argc < 2)
1110 	  goto out_usagefailure;
1111 	if (!strcmp(argv[1], "none"))
1112 	  loutput.show_disallowed = 0;
1113 	else
1114 	  fprintf(stderr, "Unsupported color `%s' passed to %s, ignoring.\n", argv[1], argv[0]);
1115 	opt = 1;
1116       }
1117       else if (!strcmp (argv[0], "--top-color")) {
1118 	if (argc < 2)
1119 	  goto out_usagefailure;
1120 	task_background_color_string = argv[1];
1121       }
1122       else if (!strncmp (argv[0], "--no-text", 9)
1123 	       || !strncmp (argv[0], "--text", 6)
1124 	       || !strncmp (argv[0], "--no-index", 10)
1125 	       || !strncmp (argv[0], "--index", 7)
1126 	       || !strncmp (argv[0], "--no-attrs", 10)
1127 	       || !strncmp (argv[0], "--attrs", 7)) {
1128 	int enable = argv[0][2] != 'n';
1129 	const char *kind = enable ? argv[0]+2 : argv[0]+5;
1130 	const char *end;
1131 	int *array;
1132 	if (*kind == 't') {
1133 	  array = loutput.show_text;
1134 	  end = kind+4;
1135 	} else if (*kind == 'a') {
1136 	  array = loutput.show_attrs;
1137 	  end = kind+5;
1138 	} else if (*kind == 'i') {
1139 	  array = loutput.show_indexes;
1140 	  end = kind+5;
1141 	} else {
1142 	  abort();
1143 	}
1144 	if (!*end) {
1145 	  for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
1146 	    array[i] = enable;
1147 
1148 	} else if (*end == '=') {
1149 	  const char *tmp = end+1;
1150 	  while (tmp) {
1151 	    char *sep = strchr(tmp, ',');
1152 	    hwloc_obj_type_t type;
1153 	    if (sep)
1154 	      *sep = '\0';
1155 	    if (hwloc_type_sscanf(tmp, &type, NULL, 0) < 0)
1156 	      if (!hwloc_strncasecmp(tmp, "cache", 5)) {
1157 		for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
1158 		  if (hwloc_obj_type_is_cache(i))
1159 		    array[i] = enable;
1160 	      } else if (!hwloc_strncasecmp(tmp, "io", 2)) {
1161 		for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
1162 		  if (hwloc_obj_type_is_io(i))
1163 		    array[i] = enable;
1164 	      } else
1165 		fprintf(stderr, "Unsupported type `%s' passed to %s, ignoring.\n", tmp, argv[0]);
1166 	    else
1167 	      array[type] = enable;
1168 	    if (!sep)
1169 	      break;
1170 	    tmp = sep+1;
1171 	  }
1172 
1173 	} else {
1174 	  fprintf(stderr, "Unexpected character %c in option %s\n", *end, argv[0]);
1175 	  goto out_usagefailure;
1176 	}
1177       }
1178 
1179       else if (!strcmp (argv[0], "--children-order")) {
1180 	if (argc < 2)
1181 	  goto out_usagefailure;
1182 	if (!strcmp(argv[1], "plain"))
1183 	  loutput.plain_children_order = 1;
1184 	else if (strcmp(argv[1], "memoryabove"))
1185 	  fprintf(stderr, "Unsupported order `%s' passed to %s, ignoring.\n", argv[1], argv[0]);
1186 	opt = 1;
1187       }
1188       else if (!strcmp (argv[0], "--no-cpukinds")) {
1189         loutput.show_cpukinds = 0;
1190       }
1191       else if (!strcmp (argv[0], "--fontsize")) {
1192 	if (argc < 2)
1193 	  goto out_usagefailure;
1194 	loutput.fontsize = atoi(argv[1]);
1195 	opt = 1;
1196       }
1197       else if (!strcmp (argv[0], "--gridsize")) {
1198 	if (argc < 2)
1199 	  goto out_usagefailure;
1200 	loutput.gridsize = atoi(argv[1]);
1201 	opt = 1;
1202       }
1203       else if (!strcmp (argv[0], "--linespacing")) {
1204 	if (argc < 2)
1205 	  goto out_usagefailure;
1206 	loutput.linespacing = atoi(argv[1]);
1207 	opt = 1;
1208       }
1209       else if (!strcmp (argv[0], "--thickness")) {
1210 	if (argc < 2)
1211 	  goto out_usagefailure;
1212 	loutput.thickness = atoi(argv[1]);
1213 	opt = 1;
1214       }
1215       else if (!strcmp (argv[0], "--no-legend")) {
1216 	loutput.show_legend = LSTOPO_SHOW_LEGEND_NONE;
1217       }
1218       else if (!strcmp (argv[0], "--no-default-legend")) {
1219 	loutput.show_legend = LSTOPO_SHOW_LEGEND_NO_DEFAULT;
1220       }
1221       else if (!strcmp (argv[0], "--append-legend")) {
1222 	char **tmp;
1223 	if (argc < 2)
1224 	  goto out_usagefailure;
1225 	tmp = realloc(loutput.legend_append, (loutput.legend_append_nr+1) * sizeof(*loutput.legend_append));
1226 	if (!tmp) {
1227 	  fprintf(stderr, "Failed to realloc legend append array, legend ignored.\n");
1228 	} else {
1229 	  loutput.legend_append = tmp;
1230 	  loutput.legend_append[loutput.legend_append_nr] = strdup(argv[1]);
1231 	  loutput.legend_append_nr++;
1232 	}
1233 	opt = 1;
1234       }
1235 
1236       else if (!strcmp (argv[0], "--shmem-output-addr")) {
1237 	if (argc < 2)
1238 	  goto out_usagefailure;
1239 	loutput.shmem_output_addr = strtoull(argv[1], NULL, 0);
1240 	opt = 1;
1241       }
1242 
1243       else if (hwloc_utils_lookup_input_option(argv, argc, &opt,
1244 					       &input, &input_format,
1245 					       callname)) {
1246 	/* nothing to do anymore */
1247 
1248       } else if (!strcmp (argv[0], "--pid")) {
1249 	if (argc < 2)
1250 	  goto out_usagefailure;
1251 	loutput.pid_number = atoi(argv[1]); opt = 1;
1252       } else if (!strcmp (argv[0], "--ps") || !strcmp (argv[0], "--top"))
1253         top = 1;
1254       else if (!strcmp (argv[0], "--version")) {
1255           printf("%s %s\n", callname, HWLOC_VERSION);
1256           exit(EXIT_SUCCESS);
1257       } else if (!strcmp (argv[0], "--output-format") || !strcmp (argv[0], "--of")) {
1258 	if (argc < 2)
1259 	  goto out_usagefailure;
1260         output_format = parse_output_format(argv[1], callname);
1261         opt = 1;
1262       } else {
1263 	if (filename) {
1264 	  fprintf (stderr, "Unrecognized option: %s\n", argv[0]);
1265 	  goto out_usagefailure;
1266 	} else
1267 	  filename = argv[0];
1268       }
1269       argc -= opt+1;
1270       argv += opt+1;
1271     }
1272 
1273   if (!loutput.fontsize) {
1274     for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++)
1275       loutput.show_text[i] = 0;
1276     loutput.show_legend = LSTOPO_SHOW_LEGEND_NONE;
1277   }
1278 
1279   /***********************
1280    * Configure the output
1281    */
1282 
1283   /* if the output format wasn't enforced, look at the filename */
1284   if (filename && output_format == LSTOPO_OUTPUT_DEFAULT) {
1285     if (!strcmp(filename, "-")
1286 	|| !strcmp(filename, "/dev/stdout")) {
1287       output_format = LSTOPO_OUTPUT_CONSOLE;
1288     } else {
1289       char *dot = strrchr(filename, '.');
1290       if (dot)
1291         output_format = parse_output_format(dot+1, callname);
1292       else {
1293 	fprintf(stderr, "Cannot infer output type for file `%s' without any extension, using default output.\n", filename);
1294 	filename = NULL;
1295       }
1296     }
1297   }
1298   if (output_format == LSTOPO_OUTPUT_ERROR)
1299     goto out_usagefailure;
1300 
1301   /* if  the output format wasn't enforced, think a bit about what the user probably want */
1302   if (output_format == LSTOPO_OUTPUT_DEFAULT) {
1303     if (loutput.show_cpuset
1304         || loutput.show_only != HWLOC_OBJ_TYPE_NONE
1305 	|| loutput.show_distances_only
1306         || loutput.show_memattrs_only
1307         || loutput.show_cpukinds_only
1308         || loutput.verbose_mode != LSTOPO_VERBOSE_MODE_DEFAULT)
1309       output_format = LSTOPO_OUTPUT_CONSOLE;
1310   }
1311 
1312   switch (output_format) {
1313   case LSTOPO_OUTPUT_DEFAULT:
1314 #ifdef LSTOPO_HAVE_GRAPHICS
1315 #if (defined LSTOPO_HAVE_X11)
1316     if (getenv("DISPLAY")) {
1317       output_func = output_x11;
1318     } else
1319 #endif /* LSTOPO_HAVE_X11 */
1320 #ifdef HWLOC_WIN_SYS
1321     {
1322       output_func = output_windows;
1323     }
1324 #endif
1325 #endif /* !LSTOPO_HAVE_GRAPHICS */
1326 #if !defined HWLOC_WIN_SYS || !defined LSTOPO_HAVE_GRAPHICS
1327     {
1328       output_func = output_console;
1329     }
1330 #endif
1331 #ifdef ANDROID
1332     setJNIEnv();
1333     output_func = output_android;
1334 #endif
1335     break;
1336 
1337   case LSTOPO_OUTPUT_CONSOLE:
1338     output_func = output_console;
1339     break;
1340   case LSTOPO_OUTPUT_SYNTHETIC:
1341     output_func = output_synthetic;
1342     break;
1343   case LSTOPO_OUTPUT_ASCII:
1344     output_func = output_ascii;
1345     break;
1346   case LSTOPO_OUTPUT_TIKZ:
1347     output_func = output_tikz;
1348     break;
1349   case LSTOPO_OUTPUT_FIG:
1350     output_func = output_fig;
1351     break;
1352 #ifdef LSTOPO_HAVE_GRAPHICS
1353 # ifdef CAIRO_HAS_PNG_FUNCTIONS
1354   case LSTOPO_OUTPUT_PNG:
1355     output_func = output_png;
1356     break;
1357 # endif /* CAIRO_HAS_PNG_FUNCTIONS */
1358 # ifdef CAIRO_HAS_PDF_SURFACE
1359   case LSTOPO_OUTPUT_PDF:
1360     output_func = output_pdf;
1361     break;
1362 # endif /* CAIRO_HAS_PDF_SURFACE */
1363 # ifdef CAIRO_HAS_PS_SURFACE
1364   case LSTOPO_OUTPUT_PS:
1365     output_func = output_ps;
1366     break;
1367 # endif /* CAIRO_HAS_PS_SURFACE */
1368 # ifdef CAIRO_HAS_SVG_SURFACE
1369   case LSTOPO_OUTPUT_SVG:
1370   case LSTOPO_OUTPUT_CAIROSVG:
1371     output_func = output_cairosvg;
1372     break;
1373 # endif /* CAIRO_HAS_SVG_SURFACE */
1374 #endif /* LSTOPO_HAVE_GRAPHICS */
1375 #if !(defined LSTOPO_HAVE_GRAPHICS) || !(defined CAIRO_HAS_SVG_SURFACE)
1376   case LSTOPO_OUTPUT_SVG:
1377 #endif
1378   case LSTOPO_OUTPUT_NATIVESVG:
1379     output_func = output_nativesvg;
1380     break;
1381   case LSTOPO_OUTPUT_XML:
1382     output_func = output_xml;
1383     break;
1384 #ifndef HWLOC_WIN_SYS
1385   case LSTOPO_OUTPUT_SHMEM:
1386     output_func = output_shmem;
1387     break;
1388 #endif
1389   default:
1390     fprintf(stderr, "file format not supported\n");
1391     goto out_usagefailure;
1392   }
1393 
1394  refresh:
1395   loutput.needs_topology_refresh = 0;
1396 
1397   /*************************
1398    * Configure the topology
1399    */
1400 
1401   err = hwloc_topology_init (&topology);
1402   if (err)
1403     goto out;
1404   hwloc_topology_set_all_types_filter(topology, HWLOC_TYPE_FILTER_KEEP_ALL);
1405   hwloc_topology_set_io_types_filter(topology, HWLOC_TYPE_FILTER_KEEP_IMPORTANT);
1406 
1407   err = hwloc_topology_set_flags(topology, flags);
1408   if (err < 0) {
1409     fprintf(stderr, "Failed to set flags %lx (%s).\n", flags, strerror(errno));
1410     goto out_with_topology;
1411   }
1412 
1413   if (input) {
1414     err = hwloc_utils_enable_input_format(topology, flags, input, &input_format, loutput.verbose_mode > 1, callname);
1415     if (err)
1416       goto out_with_topology;
1417 
1418     if (input_format != HWLOC_UTILS_INPUT_DEFAULT) {
1419       /* add the input path to the window title */
1420       snprintf(loutput.title, sizeof(loutput.title), "lstopo - %s", input);
1421 
1422 #ifndef HWLOC_WIN_SYS
1423       /* try to only add the last part of the input path to the window title.
1424        * disabled on windows because it requires to deal with / or \ in both cygwin and native paths.
1425        * looks like _fullpath() is good way to replace realpath() on !cygwin.
1426        */
1427       /* sanitize the path to avoid / ./ or ../ at the end */
1428       char *fullpath = realpath(input, NULL);
1429       if (fullpath) {
1430 	char *pos = strrchr(fullpath, '/');
1431 	/* now only keep the last part */
1432 	if (pos)
1433 	  pos++;
1434 	else
1435 	  pos = fullpath;
1436 	snprintf(loutput.title, sizeof(loutput.title), "lstopo - %s", pos);
1437 	free(fullpath);
1438       }
1439 #endif
1440     }
1441   }
1442 
1443   if (loutput.pid_number > 0) {
1444     if (hwloc_pid_from_number(&loutput.pid, loutput.pid_number, 0, 1 /* verbose */) < 0
1445 	|| hwloc_topology_set_pid(topology, loutput.pid)) {
1446       perror("Setting target pid");
1447       goto out_with_topology;
1448     }
1449   }
1450 
1451   if (input_format == HWLOC_UTILS_INPUT_XML
1452       && output_format == LSTOPO_OUTPUT_XML) {
1453     /* must be after parsing output format and before loading the topology */
1454     putenv((char *) "HWLOC_XML_USERDATA_NOT_DECODED=1");
1455     hwloc_topology_set_userdata_import_callback(topology, hwloc_utils_userdata_import_cb);
1456     hwloc_topology_set_userdata_export_callback(topology, hwloc_utils_userdata_export_cb);
1457   }
1458 
1459   apply_type_filters(topology);
1460 
1461   /*********************
1462    * Build the topology
1463    */
1464 
1465 #ifdef HAVE_CLOCK_GETTIME
1466   if (measure_load_time)
1467     clock_gettime(CLOCK_MONOTONIC, &ts1);
1468 #endif
1469 
1470   if (input_format == HWLOC_UTILS_INPUT_SHMEM) {
1471 #ifdef HWLOC_WIN_SYS
1472     fprintf(stderr, "shmem topology not supported\n"); /* this line must match the grep line in test-lstopo-shmem */
1473     goto out_with_topology;
1474 #else /* !HWLOC_WIN_SYS */
1475     /* load from shmem, and duplicate onto topology, so that we may modify it */
1476     hwloc_topology_destroy(topology);
1477     err = lstopo_shmem_adopt(input, &topology);
1478     if (err < 0)
1479       goto out;
1480     hwloc_utils_userdata_clear_recursive(hwloc_get_root_obj(topology));
1481 #endif /* !HWLOC_WIN_SYS */
1482 
1483   } else {
1484     /* normal load */
1485     err = hwloc_topology_load (topology);
1486     if (err) {
1487       fprintf(stderr, "hwloc_topology_load() failed (%s).\n", strerror(errno));
1488       goto out_with_topology;
1489     }
1490   }
1491 
1492 #ifdef HAVE_CLOCK_GETTIME
1493   if (measure_load_time) {
1494     clock_gettime(CLOCK_MONOTONIC, &ts2);
1495     ms = (ts2.tv_nsec-ts1.tv_nsec)/1000000+(ts2.tv_sec-ts1.tv_sec)*1000UL;
1496     printf("hwloc_topology_load() took %lu ms\n", ms);
1497   }
1498 #endif
1499 
1500   /********************************
1501    * Tweak the topology and output
1502    */
1503 
1504   if (allow_flags) {
1505     if (allow_flags == HWLOC_ALLOW_FLAG_CUSTOM) {
1506       err = hwloc_topology_allow(topology, allow_cpuset, allow_nodeset, HWLOC_ALLOW_FLAG_CUSTOM);
1507     } else {
1508       err = hwloc_topology_allow(topology, NULL, NULL, allow_flags);
1509     }
1510     if (err < 0) {
1511       fprintf(stderr, "hwloc_topology_allow() failed (%s)\n", strerror(errno));
1512       goto out_with_topology;
1513     }
1514   }
1515 
1516   hwloc_bitmap_fill(loutput.cpubind_set);
1517   if (loutput.pid_number != -1 && loutput.pid_number != 0)
1518     hwloc_get_proc_cpubind(topology, loutput.pid, loutput.cpubind_set, 0);
1519   else
1520     /* get our binding even if --pid not given, it may be used by --restrict */
1521     hwloc_get_cpubind(topology, loutput.cpubind_set, 0);
1522 
1523   hwloc_bitmap_fill(loutput.membind_set);
1524   if (loutput.pid_number != -1 && loutput.pid_number != 0)
1525     hwloc_get_proc_membind(topology, loutput.pid, loutput.membind_set, &policy, HWLOC_MEMBIND_BYNODESET);
1526   else
1527     /* get our binding even if --pid not given, it may be used by --restrict */
1528     hwloc_get_membind(topology, loutput.membind_set, &policy, HWLOC_MEMBIND_BYNODESET);
1529 
1530   loutput.need_pci_domain = lstopo_check_pci_domains(topology);
1531 
1532   if (top)
1533     add_process_objects(topology);
1534 
1535   if (restrictstring) {
1536     hwloc_bitmap_t restrictset = hwloc_bitmap_alloc();
1537     if (!strcmp (restrictstring, "binding")) {
1538       hwloc_bitmap_copy(restrictset, loutput.cpubind_set);
1539     } else {
1540       hwloc_bitmap_sscanf(restrictset, restrictstring);
1541     }
1542     err = hwloc_topology_restrict (topology, restrictset, restrict_flags);
1543     if (err) {
1544       perror("Restricting the topology");
1545       /* FALLTHRU */
1546     }
1547     hwloc_bitmap_free(restrictset);
1548     free(restrictstring);
1549   }
1550 
1551   loutput.topology = topology;
1552   loutput.depth = hwloc_topology_get_depth(topology);
1553   loutput.file = NULL;
1554 
1555   if (output_format != LSTOPO_OUTPUT_XML) {
1556     /* there might be some xml-imported userdata in objects, add lstopo-specific userdata in front of them */
1557     lstopo_populate_userdata(hwloc_get_root_obj(topology));
1558     lstopo_add_cpukind_style(&loutput, topology);
1559     /* cpukinds must be before factorizing */
1560     lstopo_add_factorized_attributes(&loutput, topology, hwloc_get_root_obj(topology));
1561     lstopo_add_collapse_attributes(topology);
1562   }
1563 
1564   /******************
1565    * Output for real
1566    */
1567   err = output_func(&loutput, filename);
1568 
1569   if (output_format != LSTOPO_OUTPUT_XML) {
1570     /* remove lstopo-specific userdata in front of the list of userdata */
1571     lstopo_destroy_userdata(hwloc_get_root_obj(topology));
1572   }
1573   /* remove the remaining lists of xml-imported userdata */
1574   hwloc_utils_userdata_free_recursive(hwloc_get_root_obj(topology));
1575 
1576   hwloc_topology_destroy (topology);
1577 
1578   if (loutput.needs_topology_refresh) {
1579     loutput.refreshing = 1;
1580     goto refresh;
1581   }
1582 
1583   for(i=0; i<loutput.legend_append_nr; i++)
1584     free(loutput.legend_append[i]);
1585   free(loutput.legend_append);
1586 
1587   hwloc_bitmap_free(loutput.cpubind_set);
1588   hwloc_bitmap_free(loutput.membind_set);
1589 
1590   return err ? EXIT_FAILURE : EXIT_SUCCESS;
1591 
1592  out_usagefailure:
1593   usage (callname, stderr);
1594   goto out;
1595 
1596  out_with_topology:
1597   lstopo_destroy_userdata(hwloc_get_root_obj(topology));
1598   hwloc_topology_destroy(topology);
1599  out:
1600   hwloc_bitmap_free(allow_cpuset);
1601   hwloc_bitmap_free(allow_nodeset);
1602   hwloc_bitmap_free(loutput.cpubind_set);
1603   hwloc_bitmap_free(loutput.membind_set);
1604   return EXIT_FAILURE;
1605 }
1606