1 /*
2  * Copyright © 2009 CNRS
3  * Copyright © 2009-2021 Inria.  All rights reserved.
4  * Copyright © 2009-2010 Université Bordeaux
5  * Copyright © 2009-2011 Cisco Systems, Inc.  All rights reserved.
6  * See COPYING in top-level directory.
7  */
8 
9 #include "private/autogen/config.h"
10 #include "hwloc.h"
11 #include "misc.h"
12 
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 
usage(const char * callname __hwloc_attribute_unused,FILE * where)17 void usage(const char *callname __hwloc_attribute_unused, FILE *where)
18 {
19   fprintf(where, "Usage: hwloc-distrib [options] number\n");
20   fprintf(where, "Distribution options:\n");
21   fprintf(where, "  --ignore <type>  Ignore objects of the given type\n");
22   fprintf(where, "  --from <type>    Distribute starting from objects of the given type\n");
23   fprintf(where, "  --to <type>      Distribute down to objects of the given type\n");
24   fprintf(where, "  --at <type>      Distribute among objects of the given type\n");
25   fprintf(where, "  --reverse        Distribute by starting from last objects\n");
26   fprintf(where, "Input topology options:\n");
27   fprintf(where, "  --restrict [nodeset=]<bitmap>\n");
28   fprintf(where, "                   Restrict the topology to some processors or NUMA nodes.\n");
29   fprintf(where, "  --restrict-flags <n>  Set the flags to be used during restrict\n");
30   fprintf(where, "  --disallowed     Include objects disallowed by administrative limitations\n");
31   hwloc_utils_input_format_usage(where, 0);
32   fprintf(where, "Formatting options:\n");
33   fprintf(where, "  --single         Singlify each output to a single CPU\n");
34   fprintf(where, "  --taskset        Show taskset-specific cpuset strings\n");
35   fprintf(where, "Miscellaneous options:\n");
36   fprintf(where, "  -v --verbose     Show verbose messages\n");
37   fprintf(where, "  --version        Report version and exit\n");
38   fprintf(where, "  -h --help        Show this usage\n");
39 }
40 
main(int argc,char * argv[])41 int main(int argc, char *argv[])
42 {
43   long n = -1;
44   char *callname;
45   char *input = NULL;
46   enum hwloc_utils_input_format input_format = HWLOC_UTILS_INPUT_DEFAULT;
47   int taskset = 0;
48   int singlify = 0;
49   int verbose = 0;
50   char *restrictstring = NULL;
51   const char *from_type = NULL, *to_type = NULL;
52   hwloc_topology_t topology;
53   unsigned long flags = HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT;
54   unsigned long restrict_flags = 0;
55   unsigned long dflags = 0;
56   int opt;
57   int err;
58 
59   callname = strrchr(argv[0], '/');
60   if (!callname)
61     callname = argv[0];
62   else
63     callname++;
64 
65   /* skip argv[0], handle options */
66   argv++;
67   argc--;
68 
69   hwloc_utils_check_api_version(callname);
70 
71   /* enable verbose backends */
72   if (!getenv("HWLOC_XML_VERBOSE"))
73     putenv((char *) "HWLOC_XML_VERBOSE=1");
74   if (!getenv("HWLOC_SYNTHETIC_VERBOSE"))
75     putenv((char *) "HWLOC_SYNTHETIC_VERBOSE=1");
76 
77   hwloc_topology_init(&topology);
78 
79   while (argc >= 1) {
80     if (!strcmp(argv[0], "--")) {
81       argc--;
82       argv++;
83       break;
84     }
85 
86     opt = 0;
87 
88     if (*argv[0] == '-') {
89       if (!strcmp(argv[0], "--single")) {
90 	singlify = 1;
91 	goto next;
92       }
93       if (!strcmp(argv[0], "--taskset")) {
94 	taskset = 1;
95 	goto next;
96       }
97       if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--verbose")) {
98 	verbose = 1;
99 	goto next;
100       }
101       if (!strcmp (argv[0], "--disallowed") || !strcmp (argv[0], "--whole-system")) {
102 	flags |= HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED;
103 	goto next;
104       }
105       if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help")) {
106 	usage(callname, stdout);
107 	return EXIT_SUCCESS;
108       }
109       if (hwloc_utils_lookup_input_option(argv, argc, &opt,
110 					  &input, &input_format,
111 					  callname)) {
112 	opt = 1;
113 	goto next;
114       }
115       else if (!strcmp (argv[0], "--ignore")) {
116 	hwloc_obj_type_t type;
117 	if (argc < 2) {
118 	  usage(callname, stderr);
119 	  exit(EXIT_FAILURE);
120 	}
121 	if (hwloc_type_sscanf(argv[1], &type, NULL, 0) < 0)
122 	  fprintf(stderr, "Unsupported type `%s' passed to --ignore, ignoring.\n", argv[1]);
123 	else
124 	  hwloc_topology_set_type_filter(topology, type, HWLOC_TYPE_FILTER_KEEP_NONE);
125 	opt = 1;
126 	goto next;
127       }
128       else if (!strcmp (argv[0], "--from")) {
129 	if (argc < 2) {
130 	  usage(callname, stderr);
131 	  exit(EXIT_FAILURE);
132 	}
133 	from_type = argv[1];
134 	opt = 1;
135 	goto next;
136       }
137       else if (!strcmp (argv[0], "--to")) {
138 	if (argc < 2) {
139 	  usage(callname, stderr);
140 	  exit(EXIT_FAILURE);
141 	}
142 	to_type = argv[1];
143 	opt = 1;
144 	goto next;
145       }
146       else if (!strcmp (argv[0], "--at")) {
147 	if (argc < 2) {
148 	  usage(callname, stderr);
149 	  exit(EXIT_FAILURE);
150 	}
151 	from_type = to_type = argv[1];
152 	opt = 1;
153 	goto next;
154       }
155       else if (!strcmp (argv[0], "--reverse")) {
156 	dflags |= HWLOC_DISTRIB_FLAG_REVERSE;
157 	goto next;
158       }
159       else if (!strcmp (argv[0], "--restrict")) {
160 	if (argc < 2) {
161 	  usage (callname, stderr);
162 	  exit(EXIT_FAILURE);
163 	}
164         if(strncmp(argv[1], "nodeset=", 8)) {
165           restrictstring = strdup(argv[1]);
166         } else {
167           restrictstring = strdup(argv[1]+8);
168           restrict_flags |= HWLOC_RESTRICT_FLAG_BYNODESET;
169         }
170 	opt = 1;
171 	goto next;
172       }
173       else if (!strcmp (argv[0], "--restrict-flags")) {
174 	if (argc < 2) {
175 	  usage (callname, stderr);
176 	  exit(EXIT_FAILURE);
177         }
178 	restrict_flags = hwloc_utils_parse_restrict_flags(argv[1]);
179         opt = 1;
180 	goto next;
181       }
182       else if (!strcmp (argv[0], "--version")) {
183           printf("%s %s\n", callname, HWLOC_VERSION);
184           exit(EXIT_SUCCESS);
185       }
186 
187       fprintf (stderr, "Unrecognized option: %s\n", argv[0]);
188       usage(callname, stderr);
189       return EXIT_FAILURE;
190     }
191 
192     if (n != -1) {
193       fprintf(stderr,"duplicate number\n");
194       usage(callname, stderr);
195       return EXIT_FAILURE;
196     }
197     n = atol(argv[0]);
198 
199   next:
200     argc -= opt+1;
201     argv += opt+1;
202   }
203 
204   if (n == -1) {
205     fprintf(stderr,"need a number\n");
206     usage(callname, stderr);
207     return EXIT_FAILURE;
208   }
209 
210   if (verbose)
211     fprintf(stderr, "distributing %ld\n", n);
212 
213   {
214     unsigned i;
215     int from_depth, to_depth;
216     unsigned chunks;
217     hwloc_bitmap_t *cpuset;
218 
219     cpuset = malloc(n * sizeof(hwloc_bitmap_t));
220 
221     if (input) {
222       err = hwloc_utils_enable_input_format(topology, flags, input, &input_format, verbose, callname);
223       if (err) {
224 	free(cpuset);
225 	return EXIT_FAILURE;
226       }
227     }
228     hwloc_topology_set_flags(topology, flags);
229     err = hwloc_topology_load(topology);
230     if (err < 0) {
231       free(cpuset);
232       return EXIT_FAILURE;
233     }
234 
235     if (restrictstring) {
236       hwloc_bitmap_t restrictset = hwloc_bitmap_alloc();
237       hwloc_bitmap_sscanf(restrictset, restrictstring);
238       err = hwloc_topology_restrict (topology, restrictset, restrict_flags);
239       if (err) {
240 	perror("Restricting the topology");
241 	/* FALLTHRU */
242       }
243       hwloc_bitmap_free(restrictset);
244       free(restrictstring);
245     }
246 
247     from_depth = 0;
248     if (from_type) {
249       if (hwloc_type_sscanf_as_depth(from_type, NULL, topology, &from_depth) < 0 || from_depth < 0) {
250 	fprintf(stderr, "Unsupported or unavailable type `%s' passed to --from, ignoring.\n", from_type);
251 	return EXIT_FAILURE;
252       }
253     }
254 
255     to_depth = INT_MAX;
256     if (to_type) {
257       if (hwloc_type_sscanf_as_depth(to_type, NULL, topology, &to_depth) < 0 || to_depth < 0) {
258 	fprintf(stderr, "Unsupported or unavailable type `%s' passed to --to, ignoring.\n", to_type);
259 	return EXIT_FAILURE;
260       }
261     }
262 
263     chunks =  hwloc_get_nbobjs_by_depth(topology, from_depth);
264     {
265       hwloc_obj_t *roots;
266 
267       roots = malloc(chunks * sizeof(hwloc_obj_t));
268 
269       for (i = 0; i < chunks; i++)
270         roots[i] = hwloc_get_obj_by_depth(topology, from_depth, i);
271 
272       hwloc_distrib(topology, roots, chunks, cpuset, n, to_depth, dflags);
273 
274       for (i = 0; (long) i < n; i++) {
275 	char *str = NULL;
276 	if (singlify) {
277 	  if (dflags & HWLOC_DISTRIB_FLAG_REVERSE) {
278 	    unsigned last = hwloc_bitmap_last(cpuset[i]);
279 	    hwloc_bitmap_only(cpuset[i], last);
280 	  } else {
281 	    hwloc_bitmap_singlify(cpuset[i]);
282 	  }
283 	}
284 	if (taskset)
285 	  hwloc_bitmap_taskset_asprintf(&str, cpuset[i]);
286 	else
287 	  hwloc_bitmap_asprintf(&str, cpuset[i]);
288 	printf("%s\n", str);
289 	free(str);
290 	hwloc_bitmap_free(cpuset[i]);
291       }
292 
293       free(roots);
294     }
295 
296    free(cpuset);
297   }
298 
299   hwloc_topology_destroy(topology);
300 
301   return EXIT_SUCCESS;
302 }
303