1 /*
2  * Copyright © 2013-2020 Inria.  All rights reserved.
3  * See COPYING in top-level directory.
4  */
5 
6 #include "hwloc.h"
7 
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <assert.h>
12 
main(void)13 int main(void)
14 {
15   hwloc_topology_t topo1, topo2, topo3;
16   hwloc_topology_diff_t diff, diff2, tmpdiff;
17   hwloc_obj_t obj;
18   char *xmlbuffer;
19   int xmlbuflen;
20   char *refname;
21   int err;
22 
23   putenv((char *) "HWLOC_LIBXML_CLEANUP=1");
24 
25   hwloc_topology_init(&topo1);
26   hwloc_topology_load(topo1);
27   printf("duplicate topo1 into topo2\n");
28   hwloc_topology_dup(&topo2, topo1);
29 
30   printf("check that topo2 is identical\n");
31   err = hwloc_topology_diff_build(topo1, topo2, 0, &diff);
32   assert(err == 0);
33   assert(!diff);
34 
35   printf("add a new info to topo2 root\n");
36   obj = hwloc_get_root_obj(topo1);
37   hwloc_obj_add_info(obj, "Foo", "Bar");
38   printf("check that topo2 cannot be diff'ed from topo1\n");
39   err = hwloc_topology_diff_build(topo1, topo2, 0, &diff);
40   assert(err == 1);
41   assert(diff->generic.type == HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX);
42   assert(diff->generic.next == NULL);
43   assert(diff->too_complex.obj_depth == 0);
44   assert(diff->too_complex.obj_index == 0);
45   hwloc_topology_diff_destroy(diff);
46 
47   printf("add a similar info to topo1, and change memory size of first NUMA\n");
48   obj = hwloc_get_root_obj(topo2);
49   hwloc_obj_add_info(obj, "Foo", "Bar2");
50 
51   obj = hwloc_get_obj_by_type(topo2, HWLOC_OBJ_NUMANODE, 0);
52   obj->attr->numanode.local_memory += 32*4096;
53 
54   printf("check that topo2 is now properly diff'ed\n");
55   err = hwloc_topology_diff_build(topo1, topo2, 0, &diff);
56   assert(err == 0);
57   tmpdiff = diff;
58   assert(tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR);
59   assert(tmpdiff->obj_attr.obj_depth == 0);
60   assert(tmpdiff->obj_attr.obj_index == 0);
61   assert(tmpdiff->obj_attr.diff.generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO);
62   err = strcmp(tmpdiff->obj_attr.diff.string.name, "Foo");
63   assert(!err);
64   err = strcmp(tmpdiff->obj_attr.diff.string.oldvalue, "Bar");
65   assert(!err);
66   err = strcmp(tmpdiff->obj_attr.diff.string.newvalue, "Bar2");
67   assert(!err);
68   tmpdiff = tmpdiff->generic.next;
69   assert(tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR);
70   assert(tmpdiff->obj_attr.obj_depth == hwloc_get_type_depth(topo1, HWLOC_OBJ_NUMANODE));
71   assert(tmpdiff->obj_attr.obj_index == 0);
72   assert(tmpdiff->obj_attr.diff.generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE);
73   assert(tmpdiff->obj_attr.diff.uint64.newvalue - tmpdiff->obj_attr.diff.uint64.oldvalue == 32*4096);
74   assert(tmpdiff->generic.next == NULL);
75 
76   printf("apply the diff to new duplicate topo3 of topo1\n");
77   hwloc_topology_dup(&topo3, topo1);
78   err = hwloc_topology_diff_apply(topo3, diff, 0);
79   assert(!err);
80   printf("check that topo2 and topo3 are identical\n");
81   err = hwloc_topology_diff_build(topo2, topo3, 0, &diff2);
82   assert(err == 0);
83   assert(!diff2);
84 
85   printf("apply the reverse diff to topo2\n");
86   err = hwloc_topology_diff_apply(topo2, diff, HWLOC_TOPOLOGY_DIFF_APPLY_REVERSE);
87   assert(!err);
88   printf("check that topo2 and topo1 are identical\n");
89   err = hwloc_topology_diff_build(topo1, topo2, 0, &diff2);
90   assert(err == 0);
91   assert(!diff2);
92 
93   printf("exporting and reloading diff from XML buffer without refname\n");
94   err = hwloc_topology_diff_export_xmlbuffer(diff, NULL, &xmlbuffer, &xmlbuflen);
95   assert(!err);
96   hwloc_topology_diff_destroy(diff);
97   err = hwloc_topology_diff_load_xmlbuffer(xmlbuffer, xmlbuflen, &diff2, &refname);
98   assert(!err);
99   assert(diff2);
100   assert(!refname);
101   assert(!err);
102   hwloc_free_xmlbuffer(topo1, xmlbuffer);
103 
104   printf("exporting and reloading diff from XML buffer with refname\n");
105   err = hwloc_topology_diff_export_xmlbuffer(diff2, "foobar", &xmlbuffer, &xmlbuflen);
106   assert(!err);
107   hwloc_topology_diff_destroy(diff2);
108   err = hwloc_topology_diff_load_xmlbuffer(xmlbuffer, xmlbuflen, &diff, &refname);
109   assert(!err);
110   assert(diff);
111   err = strcmp(refname, "foobar");
112   assert(!err);
113   free(refname);
114   hwloc_free_xmlbuffer(topo1, xmlbuffer);
115 
116   tmpdiff = diff;
117   assert(tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR);
118   assert(tmpdiff->obj_attr.obj_depth == 0);
119   assert(tmpdiff->obj_attr.obj_index == 0);
120   assert(tmpdiff->obj_attr.diff.generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO);
121   err = strcmp(tmpdiff->obj_attr.diff.string.name, "Foo");
122   assert(!err);
123   err = strcmp(tmpdiff->obj_attr.diff.string.oldvalue, "Bar");
124   assert(!err);
125   err = strcmp(tmpdiff->obj_attr.diff.string.newvalue, "Bar2");
126   assert(!err);
127   tmpdiff = tmpdiff->generic.next;
128   assert(tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR);
129   assert(tmpdiff->obj_attr.obj_depth == hwloc_get_type_depth(topo1, HWLOC_OBJ_NUMANODE));
130   assert(tmpdiff->obj_attr.obj_index == 0);
131   assert(tmpdiff->obj_attr.diff.generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE);
132   assert(tmpdiff->obj_attr.diff.uint64.newvalue - tmpdiff->obj_attr.diff.uint64.oldvalue == 32*4096);
133   assert(tmpdiff->generic.next == NULL);
134 
135   printf("reapplying to topo2\n");
136   err = hwloc_topology_diff_apply(topo2, diff, 0);
137   assert(!err);
138   printf("check that topo2 and topo3 are again identical\n");
139   err = hwloc_topology_diff_build(topo2, topo3, 0, &diff2);
140   assert(err == 0);
141   assert(!diff2);
142 
143   hwloc_topology_diff_destroy(diff);
144 
145   printf("adding new key to the bottom of topo3 on first PU\n");
146   obj = hwloc_get_obj_by_type(topo3, HWLOC_OBJ_PU, 0);
147   assert(obj);
148   hwloc_obj_add_info(obj, "Bar", "Baz3");
149 
150   printf("check that diff fails at the 2nd or 3rd entry\n");
151   err = hwloc_topology_diff_build(topo1, topo3, 0, &diff);
152   assert(err == 1);
153   assert(diff);
154   tmpdiff = diff;
155   assert(tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR);
156   tmpdiff = tmpdiff->generic.next;
157   if (tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX) {
158     /* normal case, PU appears before NUMA, we get ATTR(root)+TOO_COMPLEX(pu)+ATTR(numa) */
159     tmpdiff = tmpdiff->generic.next;
160     assert(tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR);
161     assert(tmpdiff->generic.next == NULL);
162   } else if (tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR) {
163     /* unusual case, PU appears after NUMA (first NUMA is CPUless), we get ATTR(root)+ATTR(numa)+TOO_COMPLEX(pu) */
164     tmpdiff = tmpdiff->generic.next;
165     assert(tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX);
166     assert(tmpdiff->generic.next == NULL);
167   } else {
168     assert(0);
169   }
170   hwloc_topology_diff_destroy(diff);
171 
172   printf("adding similar key to topo1\n");
173   obj = hwloc_get_obj_by_type(topo1, HWLOC_OBJ_PU, 0);
174   assert(obj);
175   hwloc_obj_add_info(obj, "Bar", "Baz1");
176   printf("checking that topo3 diff fails to reverse apply to topo2\n");
177   err = hwloc_topology_diff_build(topo1, topo3, 0, &diff);
178   assert(err == 0);
179   assert(diff);
180   err = hwloc_topology_diff_apply(topo2, diff, HWLOC_TOPOLOGY_DIFF_APPLY_REVERSE);
181   assert(err == -2 || err == -3);
182   hwloc_topology_diff_destroy(diff);
183 
184   hwloc_topology_destroy(topo3);
185   hwloc_topology_destroy(topo2);
186   hwloc_topology_destroy(topo1);
187 
188   return 0;
189 }
190