/* * Copyright © 2009 CNRS * Copyright © 2009-2021 Inria. All rights reserved. * Copyright © 2009-2012, 2015, 2017 Université Bordeaux * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2020 Hewlett Packard Enterprise. All rights reserved. * See COPYING in top-level directory. */ #include "private/autogen/config.h" #include "hwloc.h" #ifdef HWLOC_LINUX_SYS #include "hwloc/linux.h" #endif /* HWLOC_LINUX_SYS */ #include "hwloc/shmem.h" #include "private/debug.h" /* for HWLOC_BUILD_ASSERT() */ #include #include #include #ifdef HAVE_DIRENT_H #include #endif #include #include #include #ifdef HAVE_TIME_H #include #endif #ifdef LSTOPO_HAVE_GRAPHICS #ifdef HWLOC_HAVE_CAIRO #include #endif #endif #ifdef HAVE_SETLOCALE #include #endif #include "lstopo.h" #include "common-ps.h" #include "misc.h" #ifdef __MINGW32__ # ifdef HAVE_CLOCK_GETTIME # undef HAVE_CLOCK_GETTIME # endif #endif #ifdef HAVE_CLOCK_GETTIME # ifndef CLOCK_MONOTONIC /* HP-UX doesn't have CLOCK_MONOTONIC */ # define CLOCK_MONOTONIC CLOCK_REALTIME # endif #endif #ifdef ANDROID extern void setJNIEnv(); #endif FILE *open_output(const char *filename, int overwrite) { const char *extn; struct stat st; if (!filename || !strcmp(filename, "-")) return stdout; extn = strrchr(filename, '.'); if (filename[0] == '-' && extn == filename + 1) return stdout; if (!stat(filename, &st) && !overwrite) { errno = EEXIST; return NULL; } return fopen(filename, "w"); } const char *task_background_color_string = "#ffff00"; static hwloc_obj_t insert_task(hwloc_topology_t topology, hwloc_cpuset_t cpuset, const char * name, int thread) { hwloc_obj_t group, obj; hwloc_bitmap_and(cpuset, cpuset, hwloc_topology_get_topology_cpuset(topology)); if (hwloc_bitmap_iszero(cpuset)) return NULL; /* try to insert a group at exact position */ group = hwloc_topology_alloc_group_object(topology); if (!group) return NULL; group->cpuset = hwloc_bitmap_dup(cpuset); group->attr->group.kind = (unsigned) -1; group = hwloc_topology_insert_group_object(topology, group); if (!group) { /* try to insert in a larger parent */ char *s, *gs; hwloc_bitmap_asprintf(&s, cpuset); group = hwloc_get_obj_covering_cpuset(topology, cpuset); hwloc_bitmap_asprintf(&gs, group->cpuset); fprintf(stderr, "%s `%s' binding %s doesn't match any object, extended to %s before inserting the %s in the topology.\n", thread ? "Thread" : "Process", name, s, gs, thread ? "thread" : "process"); free(s); free(gs); } obj = hwloc_topology_insert_misc_object(topology, group, name); if (!obj) fprintf(stderr, "Failed to insert process `%s'\n", name); else { obj->subtype = strdup("Process"); if (strcmp(task_background_color_string, "none")) { char style[19]; snprintf(style, sizeof(style), "Background=%s", task_background_color_string); hwloc_obj_add_info(obj, "lstopoStyle", style); } } return obj; } static void foreach_process_cb(hwloc_topology_t topology, struct hwloc_ps_process *proc, void *cbdata __hwloc_attribute_unused) { char name[100]; unsigned i; snprintf(name, sizeof(name), "%ld", proc->pid); if (*proc->name) snprintf(name, sizeof(name), "%ld %s", proc->pid, proc->name); if (proc->bound) insert_task(topology, proc->cpuset, name, 0); if (proc->nthreads) for(i=0; inthreads; i++) if (proc->threads[i].cpuset && !hwloc_bitmap_isequal(proc->threads[i].cpuset, proc->cpuset)) { char task_name[150]; if (*proc->threads[i].name) snprintf(task_name, sizeof(task_name), "%s %li %s", name, proc->threads[i].tid, proc->threads[i].name); else snprintf(task_name, sizeof(task_name), "%s %li", name, proc->threads[i].tid); insert_task(topology, proc->threads[i].cpuset, task_name, 1); } } static void add_process_objects(hwloc_topology_t topology) { const struct hwloc_topology_support *support = hwloc_topology_get_support(topology); hwloc_obj_t root = hwloc_get_root_obj(topology); if (!support->cpubind->get_proc_cpubind) return; hwloc_ps_foreach_process(topology, root->cpuset, foreach_process_cb, NULL, HWLOC_PS_FLAG_THREADS | HWLOC_PS_FLAG_SHORTNAME, NULL, HWLOC_PS_ALL_UIDS, NULL); } static __hwloc_inline void lstopo_update_factorize_bounds(unsigned min, unsigned *first, unsigned *last) { switch (min) { case 0: case 1: case 2: *first = 1; *last = 0; break; case 3: *first = 1; *last = 1; break; default: *first = 2; *last = 1; break; } } static __hwloc_inline void lstopo_update_factorize_alltypes_bounds(struct lstopo_output *loutput) { hwloc_obj_type_t type; for(type = 0; type < HWLOC_OBJ_TYPE_MAX; type++) lstopo_update_factorize_bounds(loutput->factorize_min[type], &loutput->factorize_first[type], &loutput->factorize_last[type]); } static void lstopo_add_factorized_attributes(struct lstopo_output *loutput, hwloc_topology_t topology, hwloc_obj_t obj) { hwloc_obj_t child; if (!obj->first_child) return; if (obj->symmetric_subtree && obj->arity > loutput->factorize_min[obj->first_child->type]){ int may_factorize = 1; /* check that the object is in a single cpukind */ if (loutput->nr_cpukind_styles) { int err = hwloc_cpukinds_get_by_cpuset(topology, obj->cpuset, 0); if (err < 0 && errno == EXDEV) may_factorize = 0; } if (may_factorize) { /* factorize those children */ for_each_child(child, obj) { unsigned factorized; if (child->sibling_rank < loutput->factorize_first[child->type] || child->sibling_rank >= obj->arity - loutput->factorize_last[child->type]) factorized = 0; /* keep first and last */ else if (child->sibling_rank == loutput->factorize_first[child->type]) factorized = 1; /* replace with dots */ else factorized = -1; /* remove that one */ ((struct lstopo_obj_userdata *)child->userdata)->factorized = factorized; } } } /* recurse */ for_each_child(child, obj) lstopo_add_factorized_attributes(loutput, topology, child); } static void lstopo_add_collapse_attributes(hwloc_topology_t topology) { hwloc_obj_t obj, collapser = NULL; unsigned collapsed = 0; /* collapse identical PCI devs */ for(obj = hwloc_get_next_pcidev(topology, NULL); obj; obj = hwloc_get_next_pcidev(topology, obj)) { if (collapser) { if (!obj->io_arity && !obj->misc_arity && obj->parent == collapser->parent && obj->attr->pcidev.vendor_id == collapser->attr->pcidev.vendor_id && obj->attr->pcidev.device_id == collapser->attr->pcidev.device_id && obj->attr->pcidev.subvendor_id == collapser->attr->pcidev.subvendor_id && obj->attr->pcidev.subdevice_id == collapser->attr->pcidev.subdevice_id) { /* collapse another one */ ((struct lstopo_obj_userdata *)obj->userdata)->pci_collapsed = -1; collapsed++; continue; } else if (collapsed > 1) { /* end this collapsing */ ((struct lstopo_obj_userdata *)collapser->userdata)->pci_collapsed = collapsed; collapser = NULL; collapsed = 0; } } if (!obj->io_arity && !obj->misc_arity) { /* start a new collapsing */ collapser = obj; collapsed = 1; } } if (collapsed > 1) { /* end this collapsing */ ((struct lstopo_obj_userdata *)collapser->userdata)->pci_collapsed = collapsed; } } static void lstopo_add_cpukind_style(struct lstopo_output *loutput, hwloc_topology_t topology) { unsigned i, nr; hwloc_bitmap_t cpuset = hwloc_bitmap_alloc(); if (!cpuset) return; nr = hwloc_cpukinds_get_nr(topology, 0); for(i=0; iuserdata)->cpukind_style = i; } hwloc_bitmap_free(cpuset); loutput->nr_cpukind_styles = nr; } static int lstopo_check_pci_domains(hwloc_topology_t topology) { hwloc_obj_t obj; /* check PCI devices for domains. * they are listed by depth-first search, the order doesn't guarantee a domain at the end. */ obj = NULL; while ((obj = hwloc_get_next_pcidev(topology, obj)) != NULL) { if (obj->attr->pcidev.domain) return 1; } /* check PCI Bridges for domains. * they are listed by depth-first search, the order doesn't guarantee a domain at the end. */ obj = NULL; while ((obj = hwloc_get_next_bridge(topology, obj)) != NULL) { if (obj->attr->bridge.upstream_type != HWLOC_OBJ_BRIDGE_PCI) break; if (obj->attr->pcidev.domain) return 1; } return 0; } static void lstopo_populate_userdata(hwloc_obj_t parent) { hwloc_obj_t child; struct lstopo_obj_userdata *save = malloc(sizeof(*save)); save->common.buffer = NULL; /* so that it is ignored on XML export */ save->common.next = parent->userdata; save->factorized = 0; save->pci_collapsed = 0; save->cpukind_style = 0; parent->userdata = save; for_each_child(child, parent) lstopo_populate_userdata(child); for_each_memory_child(child, parent) lstopo_populate_userdata(child); for_each_io_child(child, parent) lstopo_populate_userdata(child); for_each_misc_child(child, parent) lstopo_populate_userdata(child); } static void lstopo_destroy_userdata(hwloc_obj_t parent) { hwloc_obj_t child; struct lstopo_obj_userdata *save = parent->userdata; if (save) { parent->userdata = save->common.next; free(save); } for_each_child(child, parent) lstopo_destroy_userdata(child); for_each_memory_child(child, parent) lstopo_destroy_userdata(child); for_each_io_child(child, parent) lstopo_destroy_userdata(child); for_each_misc_child(child, parent) lstopo_destroy_userdata(child); } void usage(const char *name, FILE *where) { fprintf (where, "Usage: %s [ options ] ... [ filename.format ]\n\n", name); fprintf (where, "See lstopo(1) for more details.\n"); fprintf (where, "\nDefault output is " #ifdef LSTOPO_HAVE_GRAPHICS #ifdef HWLOC_WIN_SYS "graphical" #elif (defined LSTOPO_HAVE_X11) "graphical (X11) if DISPLAY is set, console otherwise" #else "console" #endif #else "console" #endif ".\n"); fprintf (where, "Supported output file formats: console, ascii, tikz, fig" #ifdef LSTOPO_HAVE_GRAPHICS #ifdef CAIRO_HAS_PDF_SURFACE ", pdf" #endif /* CAIRO_HAS_PDF_SURFACE */ #ifdef CAIRO_HAS_PS_SURFACE ", ps" #endif /* CAIRO_HAS_PS_SURFACE */ #ifdef CAIRO_HAS_PNG_FUNCTIONS ", png" #endif /* CAIRO_HAS_PNG_FUNCTIONS */ #ifdef CAIRO_HAS_SVG_SURFACE ", svg(cairo,native)" #endif /* CAIRO_HAS_SVG_SURFACE */ #endif /* LSTOPO_HAVE_GRAPHICS */ #if !(defined LSTOPO_HAVE_GRAPHICS) || !(defined CAIRO_HAS_SVG_SURFACE) ", svg(native)" #endif ", xml, synthetic" "\n"); fprintf (where, "\nFormatting options:\n"); fprintf (where, " -l --logical Display hwloc logical object indexes\n"); fprintf (where, " -p --physical Display OS/physical object indexes\n"); fprintf (where, "Output options:\n"); fprintf (where, " --output-format \n"); fprintf (where, " --of Force the output to use the given format\n"); fprintf (where, " -f --force Overwrite the output file if it exists\n"); fprintf (where, "Textual output options:\n"); fprintf (where, " --only Only show objects of the given type in the textual output\n"); fprintf (where, " -v --verbose Include additional details\n"); fprintf (where, " -s --silent Reduce the amount of details to show\n"); fprintf (where, " --distances Only show distance matrices\n"); fprintf (where, " --memattrs Only show memory attributes\n"); fprintf (where, " --cpukinds Only show CPU kinds\n"); fprintf (where, " -c --cpuset Show the cpuset of each object\n"); fprintf (where, " -C --cpuset-only Only show the cpuset of each object\n"); fprintf (where, " --taskset Show taskset-specific cpuset strings\n"); fprintf (where, "Object filtering options:\n"); fprintf (where, " --filter : Filter objects of the given type, or all.\n"); fprintf (where, " may be `all' (keep all), `none' (remove all), `structure' or `important'\n"); fprintf (where, " --ignore Ignore objects of the given type\n"); fprintf (where, " --no-smt Ignore PUs\n"); fprintf (where, " --no-caches Do not show caches\n"); fprintf (where, " --no-useless-caches Do not show caches which do not have a hierarchical\n" " impact\n"); fprintf (where, " --no-icaches Do not show instruction caches\n"); fprintf (where, " --merge Do not show levels that do not have a hierarchical\n" " impact\n"); fprintf (where, " --no-collapse Do not collapse identical PCI devices\n"); fprintf (where, " --restrict [nodeset=]\n"); fprintf (where, " Restrict the topology to some processors or NUMA nodes.\n"); fprintf (where, " --restrict binding Restrict the topology to the current process binding\n"); fprintf (where, " --restrict-flags Set the flags to be used during restrict\n"); fprintf (where, " --no-io Do not show any I/O device or bridge\n"); fprintf (where, " --no-bridges Do not any I/O bridge except hostbridges\n"); fprintf (where, " --whole-io Show all I/O devices and bridges\n"); fprintf (where, "Input options:\n"); hwloc_utils_input_format_usage(where, 6); fprintf (where, " --thissystem Assume that the input topology provides the topology\n" " for the system on which we are running\n"); fprintf (where, " --pid Detect topology as seen by process \n"); fprintf (where, " --disallowed Include objects disallowed by administrative limitations\n"); fprintf (where, " --allow Change the set of objects marked as allowed\n"); fprintf (where, " --flags Set the topology flags\n"); fprintf (where, "Graphical output options:\n"); fprintf (where, " --children-order plain\n" " Display memory children below the parent like any other child\n"); fprintf (where, " --no-factorize Do not factorize identical objects\n"); fprintf (where, " --no-factorize= Do not factorize identical objects of type \n"); fprintf (where, " --factorize Factorize identical objects (default)\n"); fprintf (where, " --factorize=[,][,[,]]\n"); fprintf (where, " Set the minimum number of objects to factorize,\n"); fprintf (where, " the numbers of first and last to keep,\n"); fprintf (where, " for all or only the given object type \n"); fprintf (where, " --no-cpukinds Do not show CPU kinds\n"); fprintf (where, " --fontsize 10 Set size of text font\n"); fprintf (where, " --gridsize 7 Set size of margin between elements\n"); fprintf (where, " --linespacing 4 Set spacing between lines of text\n"); fprintf (where, " --thickness 1 Set thickness of lines and boxes\n"); fprintf (where, " --horiz[=] Horizontal graphical layout instead of nearly 4/3 ratio\n"); fprintf (where, " --vert[=] Vertical graphical layout instead of nearly 4/3 ratio\n"); fprintf (where, " --rect[=] Rectangular graphical layout with nearly 4/3 ratio\n"); fprintf (where, " --text[=] Display text for the given object types\n"); fprintf (where, " --no-text[=] Do not display text for the given object types\n"); fprintf (where, " --index=[] Display indexes for the given object types\n"); fprintf (where, " --no-index=[] Do not display indexes for the given object types\n"); fprintf (where, " --attrs=[] Display attributes for the given object types\n"); fprintf (where, " --no-attrs=[] Do not display attributes for the given object types\n"); fprintf (where, " --no-legend Remove all text legend lines at the bottom\n"); fprintf (where, " --no-default-legend Remove default text legend lines at the bottom\n"); fprintf (where, " --append-legend Append a new line of text at the bottom of the legend\n"); fprintf (where, " --binding-color none Do not colorize PU and NUMA nodes according to the binding\n"); fprintf (where, " --disallowed-color none Do not colorize disallowed PU and NUMA nodes\n"); fprintf (where, " --top-color Change task background color for --top\n"); fprintf (where, "Miscellaneous options:\n"); fprintf (where, " --export-xml-flags \n" " Set flags during the XML topology export\n"); fprintf (where, " --export-synthetic-flags \n" " Set flags during the synthetic topology export\n"); /* --shmem-output-addr is undocumented on purpose */ fprintf (where, " --ps --top Display processes within the hierarchy\n"); fprintf (where, " --version Report version and exit\n"); } void lstopo_show_interactive_help(void) { printf("\n"); printf("Keyboard shortcuts:\n"); printf(" Zooming, scrolling and closing:\n"); printf(" Zoom-in or out ...................... + -\n"); printf(" Reset scale to default .............. 1\n"); printf(" Try to fit scale to window .......... F\n"); printf(" Resize window to the drawing ........ r\n"); printf(" Toggle auto-resizing of the window .. R\n"); printf(" Scroll vertically ................... Up Down PageUp PageDown\n"); printf(" Scroll horizontally ................. Left Right Ctrl+PageUp/Down\n"); printf(" Scroll to the top-left corner ....... Home\n"); printf(" Scroll to the bottom-right corner ... End\n"); printf(" Refresh the topology ................ F5\n"); printf(" Show this help ...................... h H ?\n"); printf(" Exit ................................ q Q Esc\n"); printf(" Configuration tweaks:\n"); printf(" Toggle factorizing or collapsing .... f\n"); printf(" Switch display mode for indexes ..... i\n"); printf(" Toggle displaying of object text .... t\n"); printf(" Toggle displaying of obj attributes . a\n"); printf(" Toggle displaying of CPU kinds ...... k\n"); printf(" Toggle color for disallowed objects . d\n"); printf(" Toggle color for binding objects .... b\n"); printf(" Toggle displaying of legend lines ... l\n"); printf(" Export to file with current config .. E\n"); printf("\n\n"); fflush(stdout); } static void lstopo__show_interactive_cli_options(const struct lstopo_output *loutput) { if (loutput->index_type == LSTOPO_INDEX_TYPE_PHYSICAL) printf(" -p"); else if (loutput->index_type == LSTOPO_INDEX_TYPE_LOGICAL) printf(" -l"); else if (loutput->index_type == LSTOPO_INDEX_TYPE_NONE) printf(" --no-index"); if (!loutput->show_attrs_enabled) printf(" --no-attrs"); if (!loutput->show_text_enabled) printf(" --no-text"); if(!loutput->factorize_enabled) printf(" --no-factorize"); if (!loutput->pci_collapse_enabled) printf(" --no-collapse"); if (!loutput->show_cpukinds) printf(" --no-cpukinds"); if (!loutput->show_binding) printf(" --binding-color none"); if (!loutput->show_disallowed) printf(" --disallowed-color none"); if (loutput->show_legend == LSTOPO_SHOW_LEGEND_NONE) printf(" --no-legend"); else if (loutput->show_legend == LSTOPO_SHOW_LEGEND_NO_DEFAULT) printf(" --no-default-legend"); } void lstopo_show_interactive_cli_options(const struct lstopo_output *loutput) { #if (defined LSTOPO_HAVE_GRAPHICS) && (defined CAIRO_HAS_PDF_SURFACE) const char *format = "PDF"; const char *extension = "pdf"; #else const char *format = "SVG"; const char *extension = "svg"; #endif printf("\nCommand-line options for the current configuration tweaks:\n"); lstopo__show_interactive_cli_options(loutput); printf("\n\nTo export to %s:\n", format); printf(" lstopo "); lstopo__show_interactive_cli_options(loutput); printf(" topology.%s\n\n", extension); } enum output_format { LSTOPO_OUTPUT_DEFAULT, LSTOPO_OUTPUT_CONSOLE, LSTOPO_OUTPUT_SYNTHETIC, LSTOPO_OUTPUT_ASCII, LSTOPO_OUTPUT_TIKZ, LSTOPO_OUTPUT_FIG, LSTOPO_OUTPUT_PNG, LSTOPO_OUTPUT_PDF, LSTOPO_OUTPUT_PS, LSTOPO_OUTPUT_SVG, LSTOPO_OUTPUT_CAIROSVG, LSTOPO_OUTPUT_NATIVESVG, LSTOPO_OUTPUT_XML, LSTOPO_OUTPUT_SHMEM, LSTOPO_OUTPUT_ERROR }; static enum output_format parse_output_format(const char *name, char *callname __hwloc_attribute_unused) { if (!hwloc_strncasecmp(name, "default", 3)) return LSTOPO_OUTPUT_DEFAULT; else if (!hwloc_strncasecmp(name, "console", 3)) return LSTOPO_OUTPUT_CONSOLE; else if (!strcasecmp(name, "synthetic")) return LSTOPO_OUTPUT_SYNTHETIC; else if (!strcasecmp(name, "ascii") || !strcasecmp(name, "txt") /* backward compat with 1.10 */) return LSTOPO_OUTPUT_ASCII; else if (!strcasecmp(name, "tikz") || !strcasecmp(name, "tex")) return LSTOPO_OUTPUT_TIKZ; else if (!strcasecmp(name, "fig")) return LSTOPO_OUTPUT_FIG; else if (!strcasecmp(name, "png")) return LSTOPO_OUTPUT_PNG; else if (!strcasecmp(name, "pdf")) return LSTOPO_OUTPUT_PDF; else if (!strcasecmp(name, "ps")) return LSTOPO_OUTPUT_PS; else if (!strcasecmp(name, "svg")) return LSTOPO_OUTPUT_SVG; else if (!strcasecmp(name, "cairosvg") || !strcasecmp(name, "svg(cairo)")) return LSTOPO_OUTPUT_CAIROSVG; else if (!strcasecmp(name, "nativesvg") || !strcasecmp(name, "svg(native)")) return LSTOPO_OUTPUT_NATIVESVG; else if (!strcasecmp(name, "xml")) return LSTOPO_OUTPUT_XML; else if (!strcasecmp(name, "shmem")) return LSTOPO_OUTPUT_SHMEM; else return LSTOPO_OUTPUT_ERROR; } /**************************************************** * Store filters during parsing and apply them later */ struct lstopo_type_filter { enum hwloc_type_filter_e filter; int changed; }; /* if these assert fails, some types were added, * assumptions in macros below must be rechecked */ #define init_type_filters() do { \ unsigned _i; \ HWLOC_BUILD_ASSERT(HWLOC_OBJ_TYPE_MIN == 0); \ HWLOC_BUILD_ASSERT(HWLOC_OBJ_TYPE_MAX == 20); \ for(_i=HWLOC_OBJ_TYPE_MIN; _i= 1) { opt = 0; if (!strcmp (argv[0], "-v") || !strcmp (argv[0], "--verbose")) { loutput.verbose_mode++; } else if (!strcmp (argv[0], "-s") || !strcmp (argv[0], "--silent")) { loutput.verbose_mode--; } else if (!strcmp (argv[0], "--distances")) { loutput.show_distances_only = 1; } else if (!strcmp (argv[0], "--memattrs")) { loutput.show_memattrs_only = 1; } else if (!strcmp (argv[0], "--cpukinds")) { loutput.show_cpukinds_only = 1; } else if (!strcmp (argv[0], "-h") || !strcmp (argv[0], "--help")) { usage(callname, stdout); exit(EXIT_SUCCESS); } else if (!strcmp (argv[0], "-f") || !strcmp (argv[0], "--force")) loutput.overwrite = 1; else if (!strcmp (argv[0], "-l") || !strcmp (argv[0], "--logical")) loutput.index_type = LSTOPO_INDEX_TYPE_LOGICAL; else if (!strcmp (argv[0], "-p") || !strcmp (argv[0], "--physical")) loutput.index_type = LSTOPO_INDEX_TYPE_PHYSICAL; else if (!strcmp (argv[0], "-c") || !strcmp (argv[0], "--cpuset")) loutput.show_cpuset = 1; else if (!strcmp (argv[0], "-C") || !strcmp (argv[0], "--cpuset-only")) loutput.show_cpuset = 2; else if (!strcmp (argv[0], "--taskset")) { loutput.show_taskset = 1; if (!loutput.show_cpuset) loutput.show_cpuset = 1; } else if (!strcmp (argv[0], "--only")) { if (argc < 2) goto out_usagefailure; if (hwloc_type_sscanf(argv[1], &loutput.show_only, NULL, 0) < 0) fprintf(stderr, "Unsupported type `%s' passed to --only, ignoring.\n", argv[1]); opt = 1; } else if (!strcmp (argv[0], "--filter")) { hwloc_obj_type_t type = HWLOC_OBJ_TYPE_NONE; char *colon; enum hwloc_type_filter_e filter = HWLOC_TYPE_FILTER_KEEP_ALL; int all = 0; int allio = 0; int allcaches = 0; int allicaches = 0; if (argc < 2) goto out_usagefailure; colon = strchr(argv[1], ':'); if (colon) { *colon = '\0'; if (!strcmp(colon+1, "none")) filter = HWLOC_TYPE_FILTER_KEEP_NONE; else if (!strcmp(colon+1, "all")) filter = HWLOC_TYPE_FILTER_KEEP_ALL; else if (!strcmp(colon+1, "structure")) filter = HWLOC_TYPE_FILTER_KEEP_STRUCTURE; else if (!strcmp(colon+1, "important")) filter = HWLOC_TYPE_FILTER_KEEP_IMPORTANT; else { fprintf(stderr, "Unsupported filtering kind `%s' passed to --filter.\n", colon+1); goto out_usagefailure; } } if (!strcmp(argv[1], "all")) all = 1; else if (!strcmp(argv[1], "io")) allio = 1; else if (!strcmp(argv[1], "cache")) allcaches = 1; else if (!strcmp(argv[1], "icache")) allicaches = 1; else if (hwloc_type_sscanf(argv[1], &type, NULL, 0) < 0) { fprintf(stderr, "Unsupported type `%s' passed to --filter.\n", argv[1]); goto out_usagefailure; } if (type == HWLOC_OBJ_PU) { if (filter == HWLOC_TYPE_FILTER_KEEP_NONE) loutput.ignore_pus = 1; } else if (type == HWLOC_OBJ_NUMANODE) { if (filter == HWLOC_TYPE_FILTER_KEEP_NONE) loutput.ignore_numanodes = 1; } else if (all) set_all_types_filter(filter); else if (allio) set_io_types_filter(filter); else if (allcaches) { set_cache_types_filter(filter); set_type_filter(HWLOC_OBJ_MEMCACHE, filter); } else if (allicaches) set_icache_types_filter(filter); else set_type_filter(type, filter); opt = 1; } else if (!strcmp (argv[0], "--ignore")) { hwloc_obj_type_t type; if (argc < 2) goto out_usagefailure; if (!strcasecmp(argv[1], "cache")) { fprintf(stderr, "--ignore Cache not supported anymore, use --no-caches instead.\n"); goto out_usagefailure; } if (hwloc_type_sscanf(argv[1], &type, NULL, 0) < 0) fprintf(stderr, "Unsupported type `%s' passed to --ignore, ignoring.\n", argv[1]); else if (type == HWLOC_OBJ_PU) loutput.ignore_pus = 1; else if (type == HWLOC_OBJ_NUMANODE) loutput.ignore_numanodes = 1; else set_type_filter(type, HWLOC_TYPE_FILTER_KEEP_NONE); opt = 1; } else if (!strcmp (argv[0], "--no-smt")) { loutput.ignore_pus = 1; } else if (!strcmp (argv[0], "--no-caches")) { set_cache_types_filter(HWLOC_TYPE_FILTER_KEEP_NONE); set_type_filter(HWLOC_OBJ_MEMCACHE, HWLOC_TYPE_FILTER_KEEP_NONE); } else if (!strcmp (argv[0], "--no-useless-caches")) { set_cache_types_filter(HWLOC_TYPE_FILTER_KEEP_STRUCTURE); set_type_filter(HWLOC_OBJ_MEMCACHE, HWLOC_TYPE_FILTER_KEEP_STRUCTURE); } else if (!strcmp (argv[0], "--no-icaches")) { set_icache_types_filter(HWLOC_TYPE_FILTER_KEEP_NONE); } else if (!strcmp (argv[0], "--disallowed") || !strcmp (argv[0], "--whole-system")) flags |= HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED; else if (!strcmp (argv[0], "--allow")) { if (argc < 2) goto out_usagefailure; if (!strcmp(argv[1], "all")) { allow_flags = HWLOC_ALLOW_FLAG_ALL; } else if (!strcmp(argv[1], "local")) { allow_flags = HWLOC_ALLOW_FLAG_LOCAL_RESTRICTIONS; flags |= HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM; } else { hwloc_bitmap_t set = hwloc_bitmap_alloc(); const char *begin = argv[1]; if (!strncmp(begin, "nodeset=", 8)) begin += 8; hwloc_bitmap_sscanf(set, begin); if (begin == argv[1]) allow_cpuset = set; else allow_nodeset = set; allow_flags = HWLOC_ALLOW_FLAG_CUSTOM; } opt = 1; flags |= HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED; } else if (!strcmp (argv[0], "--no-io")) { set_io_types_filter(HWLOC_TYPE_FILTER_KEEP_NONE); } else if (!strcmp (argv[0], "--no-bridges")) { set_type_filter(HWLOC_OBJ_BRIDGE, HWLOC_TYPE_FILTER_KEEP_NONE); } else if (!strcmp (argv[0], "--whole-io")) { set_io_types_filter(HWLOC_TYPE_FILTER_KEEP_ALL); } else if (!strcmp (argv[0], "--merge")) { set_all_types_filter(HWLOC_TYPE_FILTER_KEEP_STRUCTURE); } else if (!strcmp (argv[0], "--no-collapse")) loutput.pci_collapse_enabled = 0; else if (!strcmp (argv[0], "--no-factorize")) { for(i=HWLOC_OBJ_TYPE_MIN; i 1, callname); if (err) goto out_with_topology; if (input_format != HWLOC_UTILS_INPUT_DEFAULT) { /* add the input path to the window title */ snprintf(loutput.title, sizeof(loutput.title), "lstopo - %s", input); #ifndef HWLOC_WIN_SYS /* try to only add the last part of the input path to the window title. * disabled on windows because it requires to deal with / or \ in both cygwin and native paths. * looks like _fullpath() is good way to replace realpath() on !cygwin. */ /* sanitize the path to avoid / ./ or ../ at the end */ char *fullpath = realpath(input, NULL); if (fullpath) { char *pos = strrchr(fullpath, '/'); /* now only keep the last part */ if (pos) pos++; else pos = fullpath; snprintf(loutput.title, sizeof(loutput.title), "lstopo - %s", pos); free(fullpath); } #endif } } if (loutput.pid_number > 0) { if (hwloc_pid_from_number(&loutput.pid, loutput.pid_number, 0, 1 /* verbose */) < 0 || hwloc_topology_set_pid(topology, loutput.pid)) { perror("Setting target pid"); goto out_with_topology; } } if (input_format == HWLOC_UTILS_INPUT_XML && output_format == LSTOPO_OUTPUT_XML) { /* must be after parsing output format and before loading the topology */ putenv((char *) "HWLOC_XML_USERDATA_NOT_DECODED=1"); hwloc_topology_set_userdata_import_callback(topology, hwloc_utils_userdata_import_cb); hwloc_topology_set_userdata_export_callback(topology, hwloc_utils_userdata_export_cb); } apply_type_filters(topology); /********************* * Build the topology */ #ifdef HAVE_CLOCK_GETTIME if (measure_load_time) clock_gettime(CLOCK_MONOTONIC, &ts1); #endif if (input_format == HWLOC_UTILS_INPUT_SHMEM) { #ifdef HWLOC_WIN_SYS fprintf(stderr, "shmem topology not supported\n"); /* this line must match the grep line in test-lstopo-shmem */ goto out_with_topology; #else /* !HWLOC_WIN_SYS */ /* load from shmem, and duplicate onto topology, so that we may modify it */ hwloc_topology_destroy(topology); err = lstopo_shmem_adopt(input, &topology); if (err < 0) goto out; hwloc_utils_userdata_clear_recursive(hwloc_get_root_obj(topology)); #endif /* !HWLOC_WIN_SYS */ } else { /* normal load */ err = hwloc_topology_load (topology); if (err) { fprintf(stderr, "hwloc_topology_load() failed (%s).\n", strerror(errno)); goto out_with_topology; } } #ifdef HAVE_CLOCK_GETTIME if (measure_load_time) { clock_gettime(CLOCK_MONOTONIC, &ts2); ms = (ts2.tv_nsec-ts1.tv_nsec)/1000000+(ts2.tv_sec-ts1.tv_sec)*1000UL; printf("hwloc_topology_load() took %lu ms\n", ms); } #endif /******************************** * Tweak the topology and output */ if (allow_flags) { if (allow_flags == HWLOC_ALLOW_FLAG_CUSTOM) { err = hwloc_topology_allow(topology, allow_cpuset, allow_nodeset, HWLOC_ALLOW_FLAG_CUSTOM); } else { err = hwloc_topology_allow(topology, NULL, NULL, allow_flags); } if (err < 0) { fprintf(stderr, "hwloc_topology_allow() failed (%s)\n", strerror(errno)); goto out_with_topology; } } hwloc_bitmap_fill(loutput.cpubind_set); if (loutput.pid_number != -1 && loutput.pid_number != 0) hwloc_get_proc_cpubind(topology, loutput.pid, loutput.cpubind_set, 0); else /* get our binding even if --pid not given, it may be used by --restrict */ hwloc_get_cpubind(topology, loutput.cpubind_set, 0); hwloc_bitmap_fill(loutput.membind_set); if (loutput.pid_number != -1 && loutput.pid_number != 0) hwloc_get_proc_membind(topology, loutput.pid, loutput.membind_set, &policy, HWLOC_MEMBIND_BYNODESET); else /* get our binding even if --pid not given, it may be used by --restrict */ hwloc_get_membind(topology, loutput.membind_set, &policy, HWLOC_MEMBIND_BYNODESET); loutput.need_pci_domain = lstopo_check_pci_domains(topology); if (top) add_process_objects(topology); if (restrictstring) { hwloc_bitmap_t restrictset = hwloc_bitmap_alloc(); if (!strcmp (restrictstring, "binding")) { hwloc_bitmap_copy(restrictset, loutput.cpubind_set); } else { hwloc_bitmap_sscanf(restrictset, restrictstring); } err = hwloc_topology_restrict (topology, restrictset, restrict_flags); if (err) { perror("Restricting the topology"); /* FALLTHRU */ } hwloc_bitmap_free(restrictset); free(restrictstring); } loutput.topology = topology; loutput.depth = hwloc_topology_get_depth(topology); loutput.file = NULL; if (output_format != LSTOPO_OUTPUT_XML) { /* there might be some xml-imported userdata in objects, add lstopo-specific userdata in front of them */ lstopo_populate_userdata(hwloc_get_root_obj(topology)); lstopo_add_cpukind_style(&loutput, topology); /* cpukinds must be before factorizing */ lstopo_add_factorized_attributes(&loutput, topology, hwloc_get_root_obj(topology)); lstopo_add_collapse_attributes(topology); } /****************** * Output for real */ err = output_func(&loutput, filename); if (output_format != LSTOPO_OUTPUT_XML) { /* remove lstopo-specific userdata in front of the list of userdata */ lstopo_destroy_userdata(hwloc_get_root_obj(topology)); } /* remove the remaining lists of xml-imported userdata */ hwloc_utils_userdata_free_recursive(hwloc_get_root_obj(topology)); hwloc_topology_destroy (topology); if (loutput.needs_topology_refresh) { loutput.refreshing = 1; goto refresh; } for(i=0; i