1 /*
2  * Copyright © 2013-2020 Inria.  All rights reserved.
3  * See COPYING in top-level directory.
4  */
5 
6 /** \file
7  * \brief Topology differences.
8  */
9 
10 #ifndef HWLOC_DIFF_H
11 #define HWLOC_DIFF_H
12 
13 #ifndef HWLOC_H
14 #error Please include the main hwloc.h instead
15 #endif
16 
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #elif 0
21 }
22 #endif
23 
24 
25 /** \defgroup hwlocality_diff Topology differences
26  *
27  * Applications that manipulate many similar topologies, for instance
28  * one for each node of a homogeneous cluster, may want to compress
29  * topologies to reduce the memory footprint.
30  *
31  * This file offers a way to manipulate the difference between topologies
32  * and export/import it to/from XML.
33  * Compression may therefore be achieved by storing one topology
34  * entirely while the others are only described by their differences
35  * with the former.
36  * The actual topology can be reconstructed when actually needed by
37  * applying the precomputed difference to the reference topology.
38  *
39  * This interface targets very similar nodes.
40  * Only very simple differences between topologies are actually
41  * supported, for instance a change in the memory size, the name
42  * of the object, or some info attribute.
43  * More complex differences such as adding or removing objects cannot
44  * be represented in the difference structures and therefore return
45  * errors.
46  * Differences between object sets or topology-wide allowed sets,
47  * cannot be represented either.
48  *
49  * It means that there is no need to apply the difference when
50  * looking at the tree organization (how many levels, how many
51  * objects per level, what kind of objects, CPU and node sets, etc)
52  * and when binding to objects.
53  * However the difference must be applied when looking at object
54  * attributes such as the name, the memory size or info attributes.
55  *
56  * @{
57  */
58 
59 
60 /** \brief Type of one object attribute difference.
61  */
62 typedef enum hwloc_topology_diff_obj_attr_type_e {
63   /** \brief The object local memory is modified.
64    * The union is a hwloc_topology_diff_obj_attr_u::hwloc_topology_diff_obj_attr_uint64_s
65    * (and the index field is ignored).
66    */
67   HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE,
68 
69   /** \brief The object name is modified.
70    * The union is a hwloc_topology_diff_obj_attr_u::hwloc_topology_diff_obj_attr_string_s
71    * (and the name field is ignored).
72    */
73 
74   HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME,
75   /** \brief the value of an info attribute is modified.
76    * The union is a hwloc_topology_diff_obj_attr_u::hwloc_topology_diff_obj_attr_string_s.
77    */
78   HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO
79 } hwloc_topology_diff_obj_attr_type_t;
80 
81 /** \brief One object attribute difference.
82  */
83 union hwloc_topology_diff_obj_attr_u {
84   struct hwloc_topology_diff_obj_attr_generic_s {
85     /* each part of the union must start with these */
86     hwloc_topology_diff_obj_attr_type_t type;
87   } generic;
88 
89   /** \brief Integer attribute modification with an optional index. */
90   struct hwloc_topology_diff_obj_attr_uint64_s {
91     /* used for storing integer attributes */
92     hwloc_topology_diff_obj_attr_type_t type;
93     hwloc_uint64_t index; /* not used for SIZE */
94     hwloc_uint64_t oldvalue;
95     hwloc_uint64_t newvalue;
96   } uint64;
97 
98   /** \brief String attribute modification with an optional name */
99   struct hwloc_topology_diff_obj_attr_string_s {
100     /* used for storing name and info pairs */
101     hwloc_topology_diff_obj_attr_type_t type;
102     char *name; /* not used for NAME */
103     char *oldvalue;
104     char *newvalue;
105   } string;
106 };
107 
108 
109 /** \brief Type of one element of a difference list.
110  */
111 typedef enum hwloc_topology_diff_type_e {
112   /** \brief An object attribute was changed.
113    * The union is a hwloc_topology_diff_u::hwloc_topology_diff_obj_attr_s.
114    */
115   HWLOC_TOPOLOGY_DIFF_OBJ_ATTR,
116 
117   /** \brief The difference is too complex,
118    * it cannot be represented. The difference below
119    * this object has not been checked.
120    * hwloc_topology_diff_build() will return 1.
121    *
122    * The union is a hwloc_topology_diff_u::hwloc_topology_diff_too_complex_s.
123    */
124   HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX
125 } hwloc_topology_diff_type_t;
126 
127 /** \brief One element of a difference list between two topologies.
128  */
129 typedef union hwloc_topology_diff_u {
130   struct hwloc_topology_diff_generic_s {
131     /* each part of the union must start with these */
132     hwloc_topology_diff_type_t type;
133     union hwloc_topology_diff_u * next; /* pointer to the next element of the list, or NULL */
134   } generic;
135 
136   /* A difference in an object attribute. */
137   struct hwloc_topology_diff_obj_attr_s {
138     hwloc_topology_diff_type_t type; /* must be ::HWLOC_TOPOLOGY_DIFF_OBJ_ATTR */
139     union hwloc_topology_diff_u * next;
140     /* List of attribute differences for a single object */
141     int obj_depth;
142     unsigned obj_index;
143     union hwloc_topology_diff_obj_attr_u diff;
144   } obj_attr;
145 
146   /* A difference that is too complex. */
147   struct hwloc_topology_diff_too_complex_s {
148     hwloc_topology_diff_type_t type; /* must be ::HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX */
149     union hwloc_topology_diff_u * next;
150     /* Where we had to stop computing the diff in the first topology */
151     int obj_depth;
152     unsigned obj_index;
153   } too_complex;
154 } * hwloc_topology_diff_t;
155 
156 
157 /** \brief Compute the difference between 2 topologies.
158  *
159  * The difference is stored as a list of ::hwloc_topology_diff_t entries
160  * starting at \p diff.
161  * It is computed by doing a depth-first traversal of both topology trees
162  * simultaneously.
163  *
164  * If the difference between 2 objects is too complex to be represented
165  * (for instance if some objects have different types, or different numbers
166  * of children), a special diff entry of type ::HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX
167  * is queued.
168  * The computation of the diff does not continue below these objects.
169  * So each such diff entry means that the difference between two subtrees
170  * could not be computed.
171  *
172  * \return 0 if the difference can be represented properly.
173  *
174  * \return 0 with \p diff pointing to NULL if there is no difference
175  * between the topologies.
176  *
177  * \return 1 if the difference is too complex (see above). Some entries in
178  * the list will be of type ::HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX.
179  *
180  * \return -1 on any other error.
181  *
182  * \note \p flags is currently not used. It should be 0.
183  *
184  * \note The output diff has to be freed with hwloc_topology_diff_destroy().
185  *
186  * \note The output diff can only be exported to XML or passed to
187  * hwloc_topology_diff_apply() if 0 was returned, i.e. if no entry of type
188  * ::HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX is listed.
189  *
190  * \note The output diff may be modified by removing some entries from
191  * the list. The removed entries should be freed by passing them to
192  * to hwloc_topology_diff_destroy() (possible as another list).
193 */
194 HWLOC_DECLSPEC int hwloc_topology_diff_build(hwloc_topology_t topology, hwloc_topology_t newtopology, unsigned long flags, hwloc_topology_diff_t *diff);
195 
196 /** \brief Flags to be given to hwloc_topology_diff_apply().
197  */
198 enum hwloc_topology_diff_apply_flags_e {
199   /** \brief Apply topology diff in reverse direction.
200    * \hideinitializer
201    */
202   HWLOC_TOPOLOGY_DIFF_APPLY_REVERSE = (1UL<<0)
203 };
204 
205 /** \brief Apply a topology diff to an existing topology.
206  *
207  * \p flags is an OR'ed set of ::hwloc_topology_diff_apply_flags_e.
208  *
209  * The new topology is modified in place. hwloc_topology_dup()
210  * may be used to duplicate it before patching.
211  *
212  * If the difference cannot be applied entirely, all previous applied
213  * elements are unapplied before returning.
214  *
215  * \return 0 on success.
216  *
217  * \return -N if applying the difference failed while trying
218  * to apply the N-th part of the difference. For instance -1
219  * is returned if the very first difference element could not
220  * be applied.
221  */
222 HWLOC_DECLSPEC int hwloc_topology_diff_apply(hwloc_topology_t topology, hwloc_topology_diff_t diff, unsigned long flags);
223 
224 /** \brief Destroy a list of topology differences.
225  */
226 HWLOC_DECLSPEC int hwloc_topology_diff_destroy(hwloc_topology_diff_t diff);
227 
228 /** \brief Load a list of topology differences from a XML file.
229  *
230  * If not \c NULL, \p refname will be filled with the identifier
231  * string of the reference topology for the difference file,
232  * if any was specified in the XML file.
233  * This identifier is usually the name of the other XML file
234  * that contains the reference topology.
235  *
236  * \note the pointer returned in refname should later be freed
237  * by the caller.
238  */
239 HWLOC_DECLSPEC int hwloc_topology_diff_load_xml(const char *xmlpath, hwloc_topology_diff_t *diff, char **refname);
240 
241 /** \brief Export a list of topology differences to a XML file.
242  *
243  * If not \c NULL, \p refname defines an identifier string
244  * for the reference topology which was used as a base when
245  * computing this difference.
246  * This identifier is usually the name of the other XML file
247  * that contains the reference topology.
248  * This attribute is given back when reading the diff from XML.
249  */
250 HWLOC_DECLSPEC int hwloc_topology_diff_export_xml(hwloc_topology_diff_t diff, const char *refname, const char *xmlpath);
251 
252 /** \brief Load a list of topology differences from a XML buffer.
253  *
254  * If not \c NULL, \p refname will be filled with the identifier
255  * string of the reference topology for the difference file,
256  * if any was specified in the XML file.
257  * This identifier is usually the name of the other XML file
258  * that contains the reference topology.
259  *
260  * \note the pointer returned in refname should later be freed
261  * by the caller.
262   */
263 HWLOC_DECLSPEC int hwloc_topology_diff_load_xmlbuffer(const char *xmlbuffer, int buflen, hwloc_topology_diff_t *diff, char **refname);
264 
265 /** \brief Export a list of topology differences to a XML buffer.
266  *
267  * If not \c NULL, \p refname defines an identifier string
268  * for the reference topology which was used as a base when
269  * computing this difference.
270  * This identifier is usually the name of the other XML file
271  * that contains the reference topology.
272  * This attribute is given back when reading the diff from XML.
273  *
274  * The returned buffer ends with a \0 that is included in the returned
275  * length.
276  *
277  * \note The XML buffer should later be freed with hwloc_free_xmlbuffer().
278  */
279 HWLOC_DECLSPEC int hwloc_topology_diff_export_xmlbuffer(hwloc_topology_diff_t diff, const char *refname, char **xmlbuffer, int *buflen);
280 
281 /** @} */
282 
283 
284 #ifdef __cplusplus
285 } /* extern "C" */
286 #endif
287 
288 
289 #endif /* HWLOC_DIFF_H */
290