1 /*
2  * Copyright © 2012-2019 Inria.  All rights reserved.
3  * See COPYING in top-level directory.
4  */
5 
6 #include <private/private.h>
7 #include <hwloc-calc.h>
8 #include <hwloc.h>
9 
10 #include "misc.h"
11 
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 
usage(const char * callname __hwloc_attribute_unused,FILE * where)16 void usage(const char *callname __hwloc_attribute_unused, FILE *where)
17 {
18 	fprintf(where, "Usage: hwloc-annotate [options] <input.xml> <output.xml> <location> <annotation>\n");
19 	fprintf(where, "  <location> may be:\n");
20 	fprintf(where, "    all, root, <type>:<logicalindex>, <type>:all\n");
21 	fprintf(where, "  <annotation> may be:\n");
22 	fprintf(where, "    info <name> <value>\n");
23 	fprintf(where, "    misc <name>\n");
24 	fprintf(where, "    none\n");
25         fprintf(where, "Options:\n");
26 	fprintf(where, "  --ci\tClear existing infos\n");
27 	fprintf(where, "  --ri\tReplace or remove existing infos with same name (annotation must be info)\n");
28 	fprintf(where, "  --cu\tClear existing userdata\n");
29 }
30 
31 static char *infoname = NULL, *infovalue = NULL;
32 
33 static char *miscname = NULL;
34 
35 static int clearinfos = 0;
36 static int replaceinfos = 0;
37 static int clearuserdata = 0;
38 
apply(hwloc_topology_t topology,hwloc_obj_t obj)39 static void apply(hwloc_topology_t topology, hwloc_obj_t obj)
40 {
41 	unsigned i,j;
42 	if (clearinfos) {
43 		/* this may be considered dangerous, applications should not modify objects directly */
44 		for(i=0; i<obj->infos_count; i++) {
45 			free(obj->infos[i].name);
46 			free(obj->infos[i].value);
47 		}
48 		free(obj->infos);
49 		obj->infos = NULL;
50 		obj->infos_count = 0;
51 	}
52 	if (clearuserdata) {
53 		hwloc_utils_userdata_free(obj);
54 	}
55 	if (infoname) {
56 		if (replaceinfos) {
57 			/* this may be considered dangerous, applications should not modify objects directly */
58 			for(i=0, j=0; i<obj->infos_count; i++) {
59 				if (!strcmp(infoname, obj->infos[i].name)) {
60 					/* remove info */
61 					free(obj->infos[i].name);
62 					free(obj->infos[i].value);
63 					obj->infos[i].name = NULL;
64 				} else {
65 					if (i != j) {
66 						/* shift info to where it belongs */
67 						obj->infos[j].name = obj->infos[i].name;
68 						obj->infos[j].value = obj->infos[i].value;
69 					}
70 					j++;
71 				}
72 			}
73 			obj->infos_count = j;
74 			if (!j) {
75 				free(obj->infos);
76 				obj->infos = NULL;
77 			}
78 		}
79 		if (infovalue)
80 			hwloc_obj_add_info(obj, infoname, infovalue);
81 	}
82 	if (miscname)
83 		hwloc_topology_insert_misc_object_by_parent(topology, obj, miscname);
84 }
85 
apply_recursive(hwloc_topology_t topology,hwloc_obj_t obj)86 static void apply_recursive(hwloc_topology_t topology, hwloc_obj_t obj)
87 {
88 	unsigned i;
89 	for(i=0; i<obj->arity; i++)
90 		apply_recursive(topology, obj->children[i]);
91 	apply(topology, obj);
92 }
93 
94 static void
hwloc_calc_process_location_annotate_cb(struct hwloc_calc_location_context_s * lcontext,void * _data __hwloc_attribute_unused,hwloc_obj_t obj)95 hwloc_calc_process_location_annotate_cb(struct hwloc_calc_location_context_s *lcontext,
96 					void *_data __hwloc_attribute_unused,
97 					hwloc_obj_t obj)
98 {
99 	apply(lcontext->topology, obj);
100 }
101 
main(int argc,char * argv[])102 int main(int argc, char *argv[])
103 {
104 	hwloc_topology_t topology;
105 	char *callname, *input, *output, *location;
106 	unsigned topodepth;
107 	int err;
108 
109 	putenv((char *) "HWLOC_XML_VERBOSE=1");
110 
111 	callname = argv[0];
112 	/* skip argv[0], handle options */
113 	argc--;
114 	argv++;
115 
116 	while (argc && *argv[0] == '-') {
117 		if (!strcmp(argv[0], "--ci"))
118 			clearinfos = 1;
119 		else if (!strcmp(argv[0], "--ri"))
120 			replaceinfos = 1;
121 		else if (!strcmp(argv[0], "--cu"))
122 			clearuserdata = 1;
123 		else {
124 			fprintf(stderr, "Unrecognized options: %s\n", argv[0]);
125 			usage(callname, stderr);
126 			exit(EXIT_FAILURE);
127 		}
128 		argc--;
129 		argv++;
130 	}
131 
132 	if (argc < 3) {
133 		usage(callname, stderr);
134 		exit(EXIT_FAILURE);
135 	}
136 	input = argv[0];
137 	output = argv[1];
138 	location = argv[2];
139 	argc -= 3;
140 	argv += 3;
141 
142 	if (argc < 1) {
143 		usage(callname, stderr);
144 		exit(EXIT_FAILURE);
145 	}
146 	if (!strcmp(argv[0], "info")) {
147 		if (argc < 2 || (!replaceinfos && argc < 3)) {
148 			usage(callname, stderr);
149 			exit(EXIT_FAILURE);
150 		}
151 		infoname = argv[1];
152 		infovalue = argc >= 3 ? argv[2] : NULL;
153 
154 	} else if (!strcmp(argv[0], "misc")) {
155 		if (argc < 2) {
156 			usage(callname, stderr);
157 			exit(EXIT_FAILURE);
158 		}
159 		miscname = argv[1];
160 
161 	} else if (!strcmp(argv[0], "none")) {
162 		/* do nothing (maybe clear) */
163 	} else {
164 		fprintf(stderr, "Unrecognized annotation type: %s\n", argv[0]);
165 		usage(callname, stderr);
166 		exit(EXIT_FAILURE);
167 	}
168 
169 	if (replaceinfos && !infoname) {
170 		fprintf(stderr, "--ri missing a info name\n");
171 		usage(callname, stderr);
172 		exit(EXIT_FAILURE);
173 	}
174 
175 	hwloc_topology_init(&topology);
176 	hwloc_topology_set_flags(topology, HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM | HWLOC_TOPOLOGY_FLAG_WHOLE_IO | HWLOC_TOPOLOGY_FLAG_ICACHES);
177 	err = hwloc_topology_set_xml(topology, input);
178 	if (err < 0)
179 		goto out_with_topology;
180 
181 	putenv((char *) "HWLOC_XML_USERDATA_NOT_DECODED=1");
182 	hwloc_topology_set_userdata_import_callback(topology, hwloc_utils_userdata_import_cb);
183 	hwloc_topology_set_userdata_export_callback(topology, hwloc_utils_userdata_export_cb);
184 
185 	err = hwloc_topology_load(topology);
186 	if (err < 0)
187 		goto out_with_topology;
188 
189 	topodepth = hwloc_topology_get_depth(topology);
190 
191 	if (!strcmp(location, "all")) {
192 		apply_recursive(topology, hwloc_get_root_obj(topology));
193 	} else if (!strcmp(location, "root")) {
194 		apply(topology, hwloc_get_root_obj(topology));
195 	} else {
196 		size_t typelen;
197 		typelen = strspn(location, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
198 		if (typelen && (location[typelen] == ':' || location[typelen] == '=' || location[typelen] == '[')) {
199 			struct hwloc_calc_location_context_s lcontext;
200 			lcontext.topology = topology;
201 			lcontext.topodepth = topodepth;
202 			lcontext.only_hbm = -1;
203 			lcontext.logical = 1;
204 			lcontext.verbose = 0;
205 			err = hwloc_calc_process_location(&lcontext, location, typelen,
206 							  hwloc_calc_process_location_annotate_cb, topology);
207 		}
208 	}
209 
210 	err = hwloc_topology_export_xml(topology, output);
211 	if (err < 0)
212 		goto out;
213 
214 	hwloc_utils_userdata_free_recursive(hwloc_get_root_obj(topology));
215 	hwloc_topology_destroy(topology);
216 	exit(EXIT_SUCCESS);
217 
218 out_with_topology:
219 	hwloc_utils_userdata_free_recursive(hwloc_get_root_obj(topology));
220 	hwloc_topology_destroy(topology);
221 out:
222 	exit(EXIT_FAILURE);
223 }
224