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