Skip to content

Commit

Permalink
utils/hwloc-bind: cleanup topology options management
Browse files Browse the repository at this point in the history
Enforce those options (--restrict/--disallowed/--no-smt/--no-hbm)
at the beginning of the command-line instead of reupdating the
topology later if options and locations are mixed.

Try to document this but we don't show a precise error message
if --restrict/... is given too late.

In theory smt/hbm options could be parsed later but it seemed
more clear this way.

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 May 20, 2020
1 parent 43b486c commit 136a5f1
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 122 deletions.
79 changes: 43 additions & 36 deletions utils/hwloc/hwloc-bind.1in
Expand Up @@ -14,7 +14,7 @@ and/or memory, or consult the binding of an existing program
.SH SYNOPSIS
.
.B hwloc-bind
[\fIoptions\fR] \fI<location1> [<location2> [...] ] [--] <command> \fR...
[\fItopology options\fR] [\fIoptions\fR] \fI<location1> [<location2> [...] ] [--] <command> \fR...
.
.PP
Note that hwloc(7) provides a detailed explanation of the hwloc system
Expand All @@ -23,8 +23,49 @@ it should be read before reading this man page.
.\" **************************
.\" Options Section
.\" **************************
.SH TOPOLOGY OPTIONS
.
All topology options must be given before all other options.
.
.TP 10
\fB\-\-no\-smt\fR, \fB\-\-no\-smt=<N>\fR
Only keep the first PU per core before binding.
If \fI<N>\fR is specified, keep the <N>-th instead, if any.
PUs are ordered by physical index during this filtering.
.TP
\fB\-\-restrict\fR <cpuset>
Restrict the topology to the given cpuset.
.TP
\fB\-\-restrict\fR nodeset=<nodeset>
Restrict the topology to the given nodeset, unless \fB\-\-restrict\-flags\fR specifies something different.
.TP
\fB\-\-restrict\-flags\fR <flags>
Enforce flags when restricting the topology.
Flags may be given as numeric values or as a comma-separated list of flag names
that are passed to \fIhwloc_topology_restrict()\fR.
Those names may be substrings of actual flag names as long as a single one matches,
for instance \fBbynodeset,memless\fR.
The default is \fB0\fR (or \fBnone\fR).
.TP
\fB\-\-disallowed\fR
Include objects disallowed by administrative limitations.
.TP
\fB--hbm\fR
Only take high bandwidth memory nodes (such as Intel Xeon Phi MCDRAM)
in account when looking for NUMA nodes in the input locations.

This option must be combined with NUMA node locations,
such as \fI--hbm numa:1\fR for binding on the second HBM node.
It may also be written as \fIhbm:1\fR.
.TP
\fB--no-hbm\fR
Ignore high bandwidth memory nodes (such as Intel Xeon Phi MCDRAM)
when looking for NUMA nodes in the input locations.
.
.SH OPTIONS
.
All these options must be given after all topology options above.
.
.TP 10
\fB\-\-cpubind\fR
Use following arguments for CPU binding (default).
Expand Down Expand Up @@ -97,11 +138,6 @@ No location may be given since no binding is performed.
\fB\-\-single\fR
Bind on a single CPU to prevent migration.
.TP
\fB\-\-no\-smt\fR, \fB\-\-no\-smt=<N>\fR
Only keep the first PU per core before binding.
If \fI<N>\fR is specified, keep the <N>-th instead, if any.
PUs are ordered by physical index during this filtering.
.TP
\fB\-\-strict\fR
Require strict binding.
.TP
Expand All @@ -127,35 +163,6 @@ program instead of hwloc-specific CPU set string format.
This option has no impact on the format of input CPU set strings,
both formats are always accepted.
.TP
\fB\-\-restrict\fR <cpuset>
Restrict the topology to the given cpuset.
.TP
\fB\-\-restrict\fR nodeset=<nodeset>
Restrict the topology to the given nodeset, unless \fB\-\-restrict\-flags\fR specifies something different.
.TP
\fB\-\-restrict\-flags\fR <flags>
Enforce flags when restricting the topology.
Flags may be given as numeric values or as a comma-separated list of flag names
that are passed to \fIhwloc_topology_restrict()\fR.
Those names may be substrings of actual flag names as long as a single one matches,
for instance \fBbynodeset,memless\fR.
The default is \fB0\fR (or \fBnone\fR).
.TP
\fB\-\-disallowed\fR
Include objects disallowed by administrative limitations.
.TP
\fB--hbm\fR
Only take high bandwidth memory nodes (such as Intel Xeon Phi MCDRAM)
in account when looking for NUMA nodes in the input locations.

This option must be combined with NUMA node locations,
such as \fI--hbm numa:1\fR for binding on the second HBM node.
It may also be written as \fIhbm:1\fR.
.TP
\fB--no-hbm\fR
Ignore high bandwidth memory nodes (such as Intel Xeon Phi MCDRAM)
when looking for NUMA nodes in the input locations.
.TP
\fB\-f\fR \fB\-\-force\fR
Launch the executable even if binding failed.
.TP
Expand Down Expand Up @@ -238,7 +245,7 @@ To bind on the first PU of all cores of the first package:
To bind memory on the first high-bandwidth memory node:

$ hwloc-bind --membind hbm:0 -- echo hello
$ hwloc-bind --membind --hbm numa:0 -- echo hello
$ hwloc-bind --hbm --membind numa:0 -- echo hello

Note that binding the "echo" command to multiple processors is
probably meaningless (because "echo" is likely implemented as a
Expand Down
168 changes: 82 additions & 86 deletions utils/hwloc/hwloc-bind.c
Expand Up @@ -27,10 +27,18 @@

void usage(const char *name, FILE *where)
{
fprintf(where, "Usage: %s [options] <location> -- command ...\n", name);
fprintf(where, "Usage: %s [topology options] [options] <location> -- command ...\n", name);
fprintf(where, " <location> may be a space-separated list of cpusets or objects\n");
fprintf(where, " as supported by the hwloc-calc utility, e.g:\n");
hwloc_calc_locations_usage(where);
fprintf(where, "Input topology options (must be at the beginning):\n");
fprintf(where, " --no-smt Only keep a single PU per core\n");
fprintf(where, " --restrict [nodeset=]<bitmap>\n");
fprintf(where, " Restrict the topology to some processors or NUMA nodes.\n");
fprintf(where, " --restrict-flags <n> Set the flags to be used during restrict\n");
fprintf(where, " --disallowed Include objects disallowed by administrative limitations\n");
fprintf(where, " --hbm Only consider high bandwidth memory nodes\n");
fprintf(where, " --no-hbm Ignore high-bandwidth memory nodes\n");
fprintf(where, "Options:\n");
fprintf(where, " --cpubind Use following arguments for cpu binding (default)\n");
fprintf(where, " --membind Use following arguments for memory binding\n");
Expand All @@ -49,14 +57,6 @@ void usage(const char *name, FILE *where)
fprintf(where, " --tid <tid> Operate on thread <tid>\n");
#endif
fprintf(where, " --taskset Use taskset-specific format when displaying cpuset strings\n");
fprintf(where, "Input topology options:\n");
fprintf(where, " --no-smt Only keep a single PU per core\n");
fprintf(where, " --restrict [nodeset=]<bitmap>\n");
fprintf(where, " Restrict the topology to some processors or NUMA nodes.\n");
fprintf(where, " --restrict-flags <n> Set the flags to be used during restrict\n");
fprintf(where, " --disallowed Include objects disallowed by administrative limitations\n");
fprintf(where, " --hbm Only consider high bandwidth memory nodes\n");
fprintf(where, " --no-hbm Ignore high-bandwidth memory nodes\n");
fprintf(where, "Miscellaneous options:\n");
fprintf(where, " -f --force Launch the command even if binding failed\n");
fprintf(where, " -q --quiet Hide non-fatal error messages\n");
Expand All @@ -67,7 +67,6 @@ void usage(const char *name, FILE *where)
int main(int argc, char *argv[])
{
hwloc_topology_t topology;
int loaded = 0;
int depth = -1;
hwloc_bitmap_t cpubind_set, membind_set;
int got_cpubind = 0, got_membind = 0;
Expand Down Expand Up @@ -108,29 +107,79 @@ int main(int argc, char *argv[])
cpubind_set = hwloc_bitmap_alloc();
membind_set = hwloc_bitmap_alloc();

/* don't load now, in case some options change the config before the topology is actually used */
#define LOADED() (loaded)
#define ENSURE_LOADED() do { \
if (!loaded) { \
hwloc_topology_init(&topology); \
hwloc_topology_set_all_types_filter(topology, HWLOC_TYPE_FILTER_KEEP_ALL); \
hwloc_topology_set_flags(topology, flags); \
ret = hwloc_topology_load(topology); \
if (restrictstring) { \
hwloc_bitmap_t restrictset = hwloc_bitmap_alloc(); \
hwloc_bitmap_sscanf(restrictset, restrictstring); \
if (hwloc_topology_restrict (topology, restrictset, restrict_flags)) { \
perror("Restricting the topology"); \
/* FALLTHRU */ \
} \
hwloc_bitmap_free(restrictset); \
free(restrictstring); \
} \
if (ret < 0) return EXIT_FAILURE; \
depth = hwloc_topology_get_depth(topology); \
loaded = 1; \
} \
} while (0)
while (argc >= 1) {
opt = 0;

if (!strcmp (argv[0], "--disallowed") || !strcmp (argv[0], "--whole-system")) {
flags |= HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED;
goto next_config;
}
if (!strcmp (argv[0], "--restrict")) {
if (argc < 2) {
usage (callname, stderr);
exit(EXIT_FAILURE);
}
if(strncmp(argv[1], "nodeset=", 7))
restrictstring = strdup(argv[1]);
else {
restrictstring = strdup(argv[1]+8);
restrict_flags |= HWLOC_RESTRICT_FLAG_BYNODESET;
}
argv++;
argc--;
goto next_config;
}
if (!strcmp (argv[0], "--restrict-flags")) {
if (argc < 2) {
usage (callname, stderr);
exit(EXIT_FAILURE);
}
restrict_flags = hwloc_utils_parse_restrict_flags(argv[1]);
argc--;
argv++;
goto next_config;
}
if (!strcmp(argv[0], "--no-smt")) {
no_smt = 0;
goto next_config;
}
if (!strncmp(argv[0], "--no-smt=", 9)) {
no_smt = atoi(argv[0] + 9);
goto next_config;
}
if (!strcmp(argv[0], "--hbm")) {
only_hbm = 1;
goto next_config;
}
if (!strcmp(argv[0], "--no-hbm")) {
only_hbm = 0;
goto next_config;
}

break;

next_config:
argc -= opt+1;
argv += opt+1;
}

hwloc_topology_init(&topology);
hwloc_topology_set_all_types_filter(topology, HWLOC_TYPE_FILTER_KEEP_ALL);
hwloc_topology_set_flags(topology, flags);
ret = hwloc_topology_load(topology);
if (restrictstring) {
hwloc_bitmap_t restrictset = hwloc_bitmap_alloc();
hwloc_bitmap_sscanf(restrictset, restrictstring);
if (hwloc_topology_restrict (topology, restrictset, restrict_flags)) {
perror("Restricting the topology");
/* FALLTHRU */
}
hwloc_bitmap_free(restrictset);
free(restrictstring);
}
if (ret < 0)
return EXIT_FAILURE;
depth = hwloc_topology_get_depth(topology);

while (argc >= 1) {
if (!strcmp(argv[0], "--")) {
Expand Down Expand Up @@ -158,14 +207,6 @@ int main(int argc, char *argv[])
single = 1;
goto next;
}
if (!strcmp(argv[0], "--no-smt")) {
no_smt = 0;
goto next;
}
if (!strncmp(argv[0], "--no-smt=", 9)) {
no_smt = atoi(argv[0] + 9);
goto next;
}
if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--force")) {
force = 1;
goto next;
Expand Down Expand Up @@ -251,55 +292,12 @@ int main(int argc, char *argv[])
opt = 1;
goto next;
}
if (!strcmp(argv[0], "--hbm")) {
only_hbm = 1;
goto next;
}
if (!strcmp(argv[0], "--no-hbm")) {
only_hbm = 0;
goto next;
}
if (!strcmp (argv[0], "--disallowed") || !strcmp (argv[0], "--whole-system")) {
if (loaded) {
fprintf(stderr, "Input option %s disallowed after options using the topology\n", argv[0]);
exit(EXIT_FAILURE);
}
flags |= HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED;
goto next;
}
if (!strcmp (argv[0], "--restrict")) {
if (argc < 2) {
usage (callname, stderr);
exit(EXIT_FAILURE);
}
if(strncmp(argv[1], "nodeset=", 7))
restrictstring = strdup(argv[1]);
else {
restrictstring = strdup(argv[1]+8);
restrict_flags |= HWLOC_RESTRICT_FLAG_BYNODESET;
}
argv++;
argc--;
goto next;
}
if (!strcmp (argv[0], "--restrict-flags")) {
if (argc < 2) {
usage (callname, stderr);
exit(EXIT_FAILURE);
}
restrict_flags = hwloc_utils_parse_restrict_flags(argv[1]);
argc--;
argv++;
goto next;
}

fprintf (stderr, "Unrecognized option: %s\n", argv[0]);
usage(callname, stderr);
return EXIT_FAILURE;
}

ENSURE_LOADED();

lcontext.topology = topology;
lcontext.topodepth = depth;
lcontext.only_hbm = only_hbm;
Expand All @@ -324,8 +322,6 @@ int main(int argc, char *argv[])
argv += opt+1;
}

ENSURE_LOADED();

if (pid_number > 0 && tid_number > 0) {
fprintf(stderr, "cannot operate both on tid and pid\n");
return EXIT_FAILURE;
Expand Down

0 comments on commit 136a5f1

Please sign in to comment.