Skip to content

Commit

Permalink
lstopo/draw: add factorizing of identical children
Browse files Browse the repository at this point in the history
Whenever there are more than 4 objects, show the first, second and last ones,
and replace others with dots.

This is enabled by default, but may be configured with --no-factorize
and --factorize, either globally or on a per-type basis:
one may change the number of objects before factorizing gets enabled,
and how many first and last children to keep out of the dots.

The 'f' shortcut now toggles factorizing and PCI collapsing.
'c' doesn't toggle collapsing anymore.

Factorizing only applies to normal CPU-side children.
It is similar to PCI collapsing, but the latter is pretty much always
enabled, hence we don't want to always toggle them simultaneously.

Closes #228

Signed-off-by: Valentin Hoyet <Valentin.Hoyet@inria.fr>
Signed-off-by: Brice Goglin <Brice.Goglin@inria.fr>
  • Loading branch information
Valentin Hoyet authored and bgoglin committed Apr 11, 2019
1 parent 8f629b7 commit 31b14e4
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 9 deletions.
4 changes: 4 additions & 0 deletions NEWS
Expand Up @@ -51,6 +51,10 @@ Version 2.1.0
kernel prior to 2.6.16.
* Tools
+ lstopo
- lstopo factorizes objects by default in the graphical output when
there are more than 4 identical children.
New options --no-factorize and --factorize may be used to configure this.
Also hit the 'f' key to disable factorizing in interactive outputs.
- Both logical and OS/physical indexes are now displayed by default
for PU and NUMA nodes.
- The X11 and Windows interactive outputs support many keyboard
Expand Down
8 changes: 6 additions & 2 deletions contrib/completion/hwloc-completion.bash
Expand Up @@ -25,6 +25,8 @@ _lstopo() {
--no-icaches
--merge
--no-collapse
--factorize --factorize=
--no-factorize --no-factorize=
--restrict
--restrict-flags
--no-io
Expand Down Expand Up @@ -71,11 +73,13 @@ _lstopo() {
COMPREPLY=( `compgen -W "${FILTERKINDS[*]}"` )
elif [[ "$ppprev" == "--filter" && "$prev" == ":" ]] ; then
COMPREPLY=( `compgen -W "${FILTERKINDS[*]}" -- "$cur"` )
elif [[ "$cur" == "=" && " --horiz --vert --rect --text --no-text --index --no-index --attrs --no-attrs " =~ " $prev " ]] ; then
elif [[ "$cur" == "=" && " --horiz --vert --rect --text --no-text --index --no-index --attrs --no-attrs --no-factorize " =~ " $prev " ]] ; then
COMPREPLY=( `compgen -W "${TYPES[*]}"` )
# we could also support "<type1>,<type2>,..." for --index/attrs/text but "," is not a completion word separator
elif [[ "$prev" == "=" && " --horiz --vert --rect --text --no-text --index --no-index --attrs --no-attrs " =~ " $pprev " ]] ; then
elif [[ "$prev" == "=" && " --horiz --vert --rect --text --no-text --index --no-index --attrs --no-attrs --no-factorize --factorize " =~ " $pprev " ]] ; then
COMPREPLY=( `compgen -W "${TYPES[*]}" -- "$cur"` )
elif [[ "$cur" == "=" && "--factorize" = "$prev" ]] ; then
COMPREPLY=( `compgen -W "${TYPES[*]}"` "<N>" "<N,F,L>" )
else
case "$prev" in
--of | --output-format)
Expand Down
16 changes: 13 additions & 3 deletions utils/lstopo/lstopo-cairo.c
Expand Up @@ -518,9 +518,19 @@ output_x11(struct lstopo_output *loutput, const char *dummy __hwloc_attribute_un
disp->needs_redraw = 1;
move_x11(disp);
break;
case XK_c:
loutput->pci_collapse_enabled ^= 1;
printf("%s collapsing of identical PCI devices\n", loutput->pci_collapse_enabled ? "enabled" : "disabled");
case XK_f:
/* alternate between factorize+collapse, collapse only, and none */
if (loutput->factorize_enabled && loutput->pci_collapse_enabled) {
loutput->factorize_enabled = 0;
printf("factorizing disabled, PCI collapsing still enabled\n");
} else if (!loutput->factorize_enabled && loutput->pci_collapse_enabled) {
loutput->pci_collapse_enabled = 0;
printf("factorizing and PCI collapsing disabled\n");
} else {
loutput->factorize_enabled = 1;
loutput->pci_collapse_enabled = 1;
printf("factorizing and PCI collapsing enabled\n");
}
disp->needs_redraw = 1;
move_x11(disp);
break;
Expand Down
77 changes: 77 additions & 0 deletions utils/lstopo/lstopo-draw.c
Expand Up @@ -199,6 +199,13 @@ static hwloc_obj_t next_child(struct lstopo_output *loutput, hwloc_obj_t parent,
if (!obj)
return NULL;

if (loutput->factorize_enabled && parent->arity > loutput->factorize_min[obj->type]) {
if (((struct lstopo_obj_userdata *)obj->userdata)->factorized < 0) {
obj = obj->next_sibling;
goto again;
}
}

if (obj->type == HWLOC_OBJ_PU && loutput->ignore_pus) {
obj = obj->next_sibling;
goto again;
Expand Down Expand Up @@ -521,6 +528,15 @@ place_children(struct lstopo_output *loutput, hwloc_obj_t parent,
if (parent->type == HWLOC_OBJ_BRIDGE)
orient = LSTOPO_ORIENT_VERT;

/* if factorizing children, use horizontal by default */
if (orient == LSTOPO_ORIENT_NONE
&& parent->symmetric_subtree
&& parent->first_child
&& loutput->factorize_enabled
&& parent->arity > loutput->factorize_min[parent->first_child->type]) {
orient = LSTOPO_ORIENT_HORIZ;
}

/* recurse into children to prepare their sizes */
for(i = 0, child = next_child(loutput, parent, LSTOPO_CHILD_KIND_ALL, NULL, &ncstate);
child;
Expand Down Expand Up @@ -1169,13 +1185,67 @@ bridge_draw(struct lstopo_output *loutput, hwloc_obj_t level, unsigned depth, un
}
}

static void
factorized_draw(struct lstopo_output *loutput, hwloc_obj_t level, unsigned depth, unsigned x, unsigned y)
{
struct lstopo_obj_userdata *lud = level->userdata;
unsigned gridsize = loutput->gridsize;
unsigned fontsize = loutput->fontsize;
unsigned linespacing = loutput->linespacing;
unsigned missingseparator;

/* we need a separator even between PUs */
if ((unsigned)level->depth == loutput->depth-1)
missingseparator = gridsize;
else
missingseparator = 0;

if (loutput->drawing == LSTOPO_DRAWING_PREPARE) {
/* compute children size and position, our size, and save it */
unsigned n, textwidth;
lud->width = gridsize*5; /* space, box, space, box, space */
lud->height = gridsize*2 + linespacing + fontsize + gridsize; /* space, box, linespace, text, gridsize */
sprintf(lud->text[0].text, "%ux total", level->parent->arity);
n = strlen(lud->text[0].text);
textwidth = get_textwidth(loutput, lud->text[0].text, n, fontsize);
lud->text[0].width = textwidth;
if (textwidth > lud->width) {
lud->width = textwidth;
lud->text[0].xoffset = 0;
} else {
lud->text[0].xoffset = (lud->width - textwidth)/2;
}
lud->ntext = 1;
lud->width += 2*missingseparator;

} else { /* LSTOPO_DRAWING_DRAW */
struct draw_methods *methods = loutput->methods;
struct lstopo_style boxstyle, textstyle;
unsigned boxoffset = (lud->width - 5*gridsize - 2*missingseparator) / 2;
/* boxes use object style, but the text outside uses the parent style */
lstopo_set_object_color(loutput, level, &boxstyle);
lstopo_set_object_color(loutput, level->parent, &textstyle);
methods->box(loutput, boxstyle.bg, depth, x + missingseparator + boxoffset, gridsize, y + gridsize, gridsize, level, 0);
methods->box(loutput, boxstyle.bg, depth, x + missingseparator + boxoffset + 2*gridsize, gridsize, y + gridsize, gridsize, level, 0);
methods->box(loutput, boxstyle.bg, depth, x + missingseparator + boxoffset + 4*gridsize, gridsize, y + gridsize, gridsize, level, 0);
methods->text(loutput, textstyle.t, fontsize, depth, x + missingseparator + lud->text[0].xoffset, y + 2 * gridsize + linespacing, lud->text[0].text, level, 0);
}
}

static void
cache_draw(struct lstopo_output *loutput, hwloc_obj_t level, unsigned depth, unsigned x, unsigned y)
{
struct lstopo_obj_userdata *lud = level->userdata;
unsigned gridsize = loutput->gridsize;
unsigned fontsize = loutput->fontsize;

if (loutput->factorize_enabled
&& lud->factorized == 1
&& level->parent->arity > loutput->factorize_min[level->type]) {
factorized_draw(loutput, level, depth, x, y);
return;
}

if (loutput->drawing == LSTOPO_DRAWING_PREPARE) {
/* compute children size and position, our size, and save it */
prepare_text(loutput, level);
Expand Down Expand Up @@ -1229,6 +1299,13 @@ normal_draw(struct lstopo_output *loutput, hwloc_obj_t level, unsigned depth, un
unsigned fontsize = loutput->fontsize;
unsigned linespacing = loutput->linespacing;

if (loutput->factorize_enabled
&& lud->factorized == 1
&& level->parent->arity > loutput->factorize_min[level->type]) {
factorized_draw(loutput, level, depth, x, y);
return;
}

if (loutput->drawing == LSTOPO_DRAWING_PREPARE) {
/* compute children size and position, our size, and save it */
if (level->type != HWLOC_OBJ_PU) /* PU already computed in output_compute_pu_min_textwidth() earlier */
Expand Down
17 changes: 17 additions & 0 deletions utils/lstopo/lstopo-no-graphics.1in
Expand Up @@ -174,6 +174,23 @@ Do not show levels that do not have a hierarchical impact.
This sets HWLOC_TYPE_FILTER_KEEP_STRUCTURE for all object types.
This is identical to \fB\-\-filter all:structure\fR.
.TP
\fB\-\-no-factorize\fR \fB\-\-no-factorize\fR=<type>
Never factorize identical objects in the graphical output.

If an object type is given, only factorizing of these objects is disabled.
This only applies to normal CPU-side objects, it is independent from PCI collapsing.
.TP
\fB\-\-factorize\fR \fB\-\-factorize\fR=[<type>,]<N>[,<L>[,<F>]
Factorize identical children in the graphical output (enabled by default).

If <N> is specified (4 by default), factorizing only occurs when there are strictly
more than N identical children.
If <L> and <F> are specified, they set the numbers of first and last children to keep
after factorizing.

If an object type is given, only factorizing of these objects is configured.
This only applies to normal CPU-side object, it is independent from PCI collapsing.
.TP
\fB\-\-no\-collapse\fR
Do not collapse identical PCI devices.
By default, identical sibling PCI devices (such as many virtual functions
Expand Down
16 changes: 13 additions & 3 deletions utils/lstopo/lstopo-windows.c
Expand Up @@ -113,9 +113,19 @@ WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
printf("%s legend\n", loutput->legend ? "enabled" : "disabled");
redraw = 1;
break;
case 'c':
loutput->pci_collapse_enabled ^= 1;
printf("%s collapsing of identical PCI devices\n", loutput->pci_collapse_enabled ? "enabled" : "disabled");
case 'f':
/* alternate between factorize+collapse, collapse only, and none */
if (loutput->factorize_enabled && loutput->pci_collapse_enabled) {
loutput->factorize_enabled = 0;
printf("factorizing disabled, PCI collapsing still enabled\n");
} else if (!loutput->factorize_enabled && loutput->pci_collapse_enabled) {
loutput->pci_collapse_enabled = 0;
printf("factorizing and PCI collapsing disabled\n");
} else {
loutput->factorize_enabled = 1;
loutput->pci_collapse_enabled = 1;
printf("factorizing and PCI collapsing enabled\n");
}
redraw = 1;
break;
case 'E':
Expand Down

0 comments on commit 31b14e4

Please sign in to comment.