1 /*
2  * Copyright © 2011-2021 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 <stdint.h>
12 #include <assert.h>
13 
main(void)14 int main(void)
15 {
16   hwloc_topology_t topology;
17   hwloc_obj_t obj, group, saved, res, root;
18   hwloc_obj_t objs[32];
19   hwloc_uint64_t values[32*32];
20   int depth;
21   hwloc_obj_type_t type;
22   unsigned width;
23   unsigned i, j;
24   int err;
25 
26   /* testing of adding specific groups */
27 
28   hwloc_topology_init(&topology);
29   hwloc_topology_set_synthetic(topology, "pack:4 [numa] pu:4");
30   hwloc_topology_load(topology);
31   root = hwloc_get_root_obj(topology);
32   assert(hwloc_topology_get_depth(topology) == 3);
33   /* insert a group identical to root, will be merged */
34   group = hwloc_topology_alloc_group_object(topology);
35   assert(group);
36   group->cpuset = hwloc_bitmap_dup(root->cpuset);
37   res = hwloc_topology_insert_group_object(topology, group);
38   assert(res);
39   assert(res == root);
40   assert(hwloc_topology_get_depth(topology) == 3);
41   /* insert a group identical to a package, will be merged */
42   group = hwloc_topology_alloc_group_object(topology);
43   assert(group);
44   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 1);
45   assert(obj);
46   group->cpuset = hwloc_bitmap_dup(obj->cpuset);
47   res = hwloc_topology_insert_group_object(topology, group);
48   assert(res);
49   assert(res == obj);
50   assert(hwloc_topology_get_depth(topology) == 3);
51   /* insert a invalid group of two PUs in different packages, will fail */
52   group = hwloc_topology_alloc_group_object(topology);
53   assert(group);
54   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PU, 1);
55   assert(obj);
56   group->cpuset = hwloc_bitmap_dup(obj->cpuset);
57   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PU, 12);
58   assert(obj);
59   hwloc_bitmap_or(group->cpuset, group->cpuset, obj->cpuset);
60   res = hwloc_topology_insert_group_object(topology, group);
61   assert(!res);
62   assert(hwloc_topology_get_depth(topology) == 3);
63   /* insert a group of two packages with high kind (so that it gets merged later) */
64   group = hwloc_topology_alloc_group_object(topology);
65   assert(group);
66   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 1);
67   assert(obj);
68   group->cpuset = hwloc_bitmap_dup(obj->cpuset);
69   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 2);
70   assert(obj);
71   hwloc_bitmap_or(group->cpuset, group->cpuset, obj->cpuset);
72   group->attr->group.kind = (unsigned)-1;
73   res = hwloc_topology_insert_group_object(topology, group);
74   assert(res == group);
75   saved = group;
76   assert(hwloc_topology_get_depth(topology) == 4);
77   /* insert same group with lower kind to replace the previous one */
78   group = hwloc_topology_alloc_group_object(topology);
79   assert(group);
80   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 1);
81   assert(obj);
82   group->cpuset = hwloc_bitmap_dup(obj->cpuset);
83   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 2);
84   assert(obj);
85   hwloc_bitmap_or(group->cpuset, group->cpuset, obj->cpuset);
86   group->attr->group.kind = 0;
87   res = hwloc_topology_insert_group_object(topology, group);
88   assert(res == saved); /* the core should move the contents of this new group into a previous one */
89   assert(res != group);
90   assert(hwloc_topology_get_depth(topology) == 4);
91   /* insert yet another same group with higher kind, it will be dropped in favor of the previous-previous one */
92   group = hwloc_topology_alloc_group_object(topology);
93   assert(group);
94   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 1);
95   assert(obj);
96   group->cpuset = hwloc_bitmap_dup(obj->cpuset);
97   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 2);
98   assert(obj);
99   hwloc_bitmap_or(group->cpuset, group->cpuset, obj->cpuset);
100   group->attr->group.kind = (unsigned)-1;
101   res = hwloc_topology_insert_group_object(topology, group);
102   assert(res == saved);
103   assert(res != group);
104   assert(hwloc_topology_get_depth(topology) == 4);
105   /* insert a conflict group of two packages by nodeset, will fail */
106   group = hwloc_topology_alloc_group_object(topology);
107   assert(group);
108   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 0);
109   assert(obj);
110   group->nodeset = hwloc_bitmap_dup(obj->nodeset);
111   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 2);
112   assert(obj);
113   hwloc_bitmap_or(group->nodeset, group->nodeset, obj->nodeset);
114   res = hwloc_topology_insert_group_object(topology, group);
115   assert(!res);
116   /* insert a group of three packages by nodeset */
117   group = hwloc_topology_alloc_group_object(topology);
118   assert(group);
119   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 0);
120   assert(obj);
121   group->nodeset = hwloc_bitmap_dup(obj->nodeset);
122   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 1);
123   assert(obj);
124   hwloc_bitmap_or(group->nodeset, group->nodeset, obj->nodeset);
125   obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, 2);
126   assert(obj);
127   hwloc_bitmap_or(group->nodeset, group->nodeset, obj->nodeset);
128   res = hwloc_topology_insert_group_object(topology, group);
129   assert(res == group);
130   assert(hwloc_topology_get_depth(topology) == 5);
131 
132   hwloc_topology_destroy(topology);
133 
134   /* intensive testing of two grouping cases (2+1 and 2+2+1) */
135 
136   /* group 3 numa nodes as 1 group of 2 and 1 on the side */
137   hwloc_topology_init(&topology);
138   hwloc_topology_set_synthetic(topology, "node:3 pu:1");
139   hwloc_topology_load(topology);
140   /* 3 group at depth 1 */
141   depth = hwloc_get_type_depth(topology, HWLOC_OBJ_GROUP);
142   assert(depth == 1);
143   width = hwloc_get_nbobjs_by_depth(topology, 1);
144   assert(width == 3);
145   /* insert distances and groups */
146   for(i=0; i<3; i++)
147     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PU, i);
148   values[0] = 1; values[1] = 4; values[2] = 4;
149   values[3] = 4; values[4] = 1; values[5] = 2;
150   values[6] = 4; values[7] = 2; values[8] = 1;
151   err = hwloc_distances_add(topology, 3, objs, values,
152 			    HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
153 			    HWLOC_DISTANCES_ADD_FLAG_GROUP);
154   assert(!err);
155   /* 1 groups at depth 1 and 2 */
156   depth = hwloc_get_type_depth(topology, HWLOC_OBJ_GROUP);
157   assert(depth == -2);
158   type = hwloc_get_depth_type(topology, 1);
159   assert(type == HWLOC_OBJ_GROUP);
160   width = hwloc_get_nbobjs_by_depth(topology, 1);
161   assert(width == 1);
162   type = hwloc_get_depth_type(topology, 2);
163   assert(type == HWLOC_OBJ_GROUP);
164   width = hwloc_get_nbobjs_by_depth(topology, 2);
165   assert(width == 3);
166   /* 3 nodes */
167   depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
168   assert(depth == HWLOC_TYPE_DEPTH_NUMANODE);
169   width = hwloc_get_nbobjs_by_depth(topology, depth);
170   assert(width == 3);
171   /* find the root obj */
172   obj = hwloc_get_root_obj(topology);
173   assert(obj->arity == 2);
174   /* check its children */
175   /* first child is a group with PU+NUMA children */
176   assert(obj->children[0]->type == HWLOC_OBJ_GROUP);
177   assert(obj->children[0]->depth == 2);
178   assert(obj->children[0]->arity == 1);
179   assert(obj->children[0]->first_child->type == HWLOC_OBJ_PU);
180   assert(obj->children[0]->memory_arity == 1);
181   assert(obj->children[0]->memory_first_child->type == HWLOC_OBJ_NUMANODE);
182   /* second child is a group with two group children */
183   assert(obj->children[1]->type == HWLOC_OBJ_GROUP);
184   assert(obj->children[1]->depth == 1);
185   assert(obj->children[1]->arity == 2);
186   assert(obj->children[1]->children[0]->type == HWLOC_OBJ_GROUP);
187   assert(obj->children[1]->children[1]->type == HWLOC_OBJ_GROUP);
188   assert(obj->children[1]->memory_arity == 0);
189   hwloc_topology_destroy(topology);
190 
191   /* group 5 packages as 2 group of 2 and 1 on the side, all of them below a common node object */
192   hwloc_topology_init(&topology);
193   hwloc_topology_set_synthetic(topology, "node:1 pack:5 pu:1");
194   hwloc_topology_load(topology);
195   for(i=0; i<5; i++)
196     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PACKAGE, i);
197   values[ 0] = 1; values[ 1] = 2; values[ 2] = 4; values[ 3] = 4; values[ 4] = 4;
198   values[ 5] = 2; values[ 6] = 1; values[ 7] = 4; values[ 8] = 4; values[ 9] = 4;
199   values[10] = 4; values[11] = 4; values[12] = 1; values[13] = 4; values[14] = 4;
200   values[15] = 4; values[16] = 4; values[17] = 4; values[18] = 1; values[19] = 2;
201   values[20] = 4; values[21] = 4; values[22] = 4; values[23] = 2; values[24] = 1;
202   err = hwloc_distances_add(topology, 5, objs, values,
203 			    HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
204 			    HWLOC_DISTANCES_ADD_FLAG_GROUP);
205   assert(!err);
206   /* 1 node */
207   depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
208   assert(depth == HWLOC_TYPE_DEPTH_NUMANODE);
209   width = hwloc_get_nbobjs_by_depth(topology, depth);
210   assert(width == 1);
211   /* 2 groups at depth 1 */
212   depth = hwloc_get_type_depth(topology, HWLOC_OBJ_GROUP);
213   assert(depth == 1);
214   width = hwloc_get_nbobjs_by_depth(topology, depth);
215   assert(width == 2);
216   /* 5 packages at depth 2 */
217   depth = hwloc_get_type_depth(topology, HWLOC_OBJ_PACKAGE);
218   assert(depth == 2);
219   width = hwloc_get_nbobjs_by_depth(topology, depth);
220   assert(width == 5);
221   /* check root */
222   obj = hwloc_get_root_obj(topology);
223   assert(obj->arity == 3);
224   assert(obj->memory_arity == 1);
225   /* check root children */
226   assert(obj->children[0]->type == HWLOC_OBJ_GROUP);
227   assert(obj->children[0]->depth == 1);
228   assert(obj->children[0]->arity == 2);
229   assert(obj->children[1]->type == HWLOC_OBJ_PACKAGE);
230   assert(obj->children[1]->depth == 2);
231   assert(obj->children[1]->arity == 1);
232   assert(obj->children[2]->type == HWLOC_OBJ_GROUP);
233   assert(obj->children[2]->depth == 1);
234   assert(obj->children[2]->arity == 2);
235   obj = obj->memory_first_child;
236   assert(obj->type == HWLOC_OBJ_NUMANODE);
237   assert(obj->arity == 0);
238   assert(obj->memory_arity == 0);
239   hwloc_topology_destroy(topology);
240 
241 /* testing of adding/replacing/removing distance matrices
242    and grouping with/without accuracy
243  */
244 
245   /* grouping matrix 4*2*2 */
246   for(i=0; i<16; i++) {
247     for(j=0; j<16; j++)
248       if (i==j)
249         values[i+16*j] = values[j+16*i] = 30;
250       else if (i/2==j/2)
251         values[i+16*j] = values[j+16*i] = 50;
252       else if (i/4==j/4)
253         values[i+16*j] = values[j+16*i] = 70;
254       else
255         values[i+16*j] = values[j+16*i] = 90;
256   }
257 
258   /* default 2*8*1 */
259   hwloc_topology_init(&topology);
260   hwloc_topology_set_synthetic(topology, "node:2 core:8 pu:1");
261   hwloc_topology_load(topology);
262   depth = hwloc_topology_get_depth(topology);
263   assert(depth == 4);
264   width = hwloc_get_nbobjs_by_depth(topology, 0);
265   assert(width == 1);
266   width = hwloc_get_nbobjs_by_depth(topology, 1);
267   assert(width == 2);
268   width = hwloc_get_nbobjs_by_depth(topology, 2);
269   assert(width == 16);
270   width = hwloc_get_nbobjs_by_depth(topology, 3);
271   assert(width == 16);
272   width = hwloc_get_nbobjs_by_depth(topology, HWLOC_TYPE_DEPTH_NUMANODE);
273   assert(width == 2);
274   /* group 8cores as 2*2*2 */
275   for(i=0; i<16; i++)
276     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_CORE, i);
277   assert(!hwloc_distances_add(topology, 16, objs, values,
278 			      HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
279 			      HWLOC_DISTANCES_ADD_FLAG_GROUP));
280   depth = hwloc_topology_get_depth(topology);
281   assert(depth == 6);
282   width = hwloc_get_nbobjs_by_depth(topology, 0);
283   assert(width == 1);
284   width = hwloc_get_nbobjs_by_depth(topology, 1);
285   assert(width == 2);
286   width = hwloc_get_nbobjs_by_depth(topology, 2);
287   assert(width == 4);
288   width = hwloc_get_nbobjs_by_depth(topology, 3);
289   assert(width == 8);
290   width = hwloc_get_nbobjs_by_depth(topology, 4);
291   assert(width == 16);
292   width = hwloc_get_nbobjs_by_depth(topology, HWLOC_TYPE_DEPTH_NUMANODE);
293   assert(width == 2);
294   hwloc_topology_destroy(topology);
295 
296   /* play with accuracy */
297   values[0] = 29; /* diagonal, instead of 3 (0.0333% error) */
298   values[1] = 51; values[16] = 52; /* smallest group, instead of 5 (0.02% error) */
299   putenv((char *) "HWLOC_GROUPING_ACCURACY=0.1"); /* ok */
300   hwloc_topology_init(&topology);
301   hwloc_topology_set_synthetic(topology, "node:2 core:8 pu:1");
302   hwloc_topology_load(topology);
303   for(i=0; i<16; i++)
304     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_CORE, i);
305   assert(!hwloc_distances_add(topology, 16, objs, values,
306 			      HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
307 			      HWLOC_DISTANCES_ADD_FLAG_GROUP|HWLOC_DISTANCES_ADD_FLAG_GROUP_INACCURATE));
308   depth = hwloc_topology_get_depth(topology);
309   assert(depth == 6);
310   hwloc_topology_destroy(topology);
311 
312   putenv((char *) "HWLOC_GROUPING_ACCURACY=try"); /* ok */
313   hwloc_topology_init(&topology);
314   hwloc_topology_set_synthetic(topology, "node:2 core:8 pu:1");
315   hwloc_topology_load(topology);
316   for(i=0; i<16; i++)
317     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_CORE, i);
318   assert(!hwloc_distances_add(topology, 16, objs, values,
319 			      HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
320 			      HWLOC_DISTANCES_ADD_FLAG_GROUP|HWLOC_DISTANCES_ADD_FLAG_GROUP_INACCURATE));
321   depth = hwloc_topology_get_depth(topology);
322   assert(depth == 6);
323   hwloc_topology_destroy(topology);
324 
325   hwloc_topology_init(&topology);
326   hwloc_topology_set_synthetic(topology, "node:2 core:8 pu:1");
327   hwloc_topology_load(topology);
328   for(i=0; i<16; i++)
329     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_CORE, i);
330   assert(!hwloc_distances_add(topology, 16, objs, values,
331 			      HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
332 			      HWLOC_DISTANCES_ADD_FLAG_GROUP /* no inaccurate flag, cannot group */));
333   depth = hwloc_topology_get_depth(topology);
334   assert(depth == 4);
335   hwloc_topology_destroy(topology);
336 
337   putenv((char *) "HWLOC_GROUPING_ACCURACY=0.01"); /* too small, cannot group */
338   hwloc_topology_init(&topology);
339   hwloc_topology_set_synthetic(topology, "node:2 core:8 pu:1");
340   hwloc_topology_load(topology);
341   for(i=0; i<16; i++)
342     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_CORE, i);
343   assert(!hwloc_distances_add(topology, 16, objs, values,
344 			      HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
345 			      HWLOC_DISTANCES_ADD_FLAG_GROUP|HWLOC_DISTANCES_ADD_FLAG_GROUP_INACCURATE));
346   depth = hwloc_topology_get_depth(topology);
347   assert(depth == 4);
348   hwloc_topology_destroy(topology);
349 
350   putenv((char *) "HWLOC_GROUPING_ACCURACY=0"); /* full accuracy, cannot group */
351   hwloc_topology_init(&topology);
352   hwloc_topology_set_synthetic(topology, "node:2 core:8 pu:1");
353   hwloc_topology_load(topology);
354   for(i=0; i<16; i++)
355     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_CORE, i);
356   assert(!hwloc_distances_add(topology, 16, objs, values,
357 			      HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
358 			      HWLOC_DISTANCES_ADD_FLAG_GROUP|HWLOC_DISTANCES_ADD_FLAG_GROUP_INACCURATE));
359   depth = hwloc_topology_get_depth(topology);
360   assert(depth == 4);
361   hwloc_topology_destroy(topology);
362 
363   /* default 2*4*4 */
364   hwloc_topology_init(&topology);
365   hwloc_topology_set_synthetic(topology, "node:2 core:4 pu:4");
366   hwloc_topology_load(topology);
367   depth = hwloc_topology_get_depth(topology);
368   assert(depth == 4);
369   width = hwloc_get_nbobjs_by_depth(topology, 0);
370   assert(width == 1);
371   width = hwloc_get_nbobjs_by_depth(topology, 1);
372   assert(width == 2);
373   width = hwloc_get_nbobjs_by_depth(topology, 2);
374   assert(width == 8);
375   width = hwloc_get_nbobjs_by_depth(topology, 3);
376   assert(width == 32);
377   width = hwloc_get_nbobjs_by_depth(topology, HWLOC_TYPE_DEPTH_NUMANODE);
378   assert(width == 2);
379   /* apply useless core distances */
380   for(i=0; i<8; i++) {
381     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_CORE, i);
382     for(j=0; j<8; j++)
383       if (i==j)
384         values[i+8*j] = values[j+8*i] = 1;
385       else if (i/4==j/4)
386         values[i+8*j] = values[j+8*i] = 4;
387       else
388         values[i+8*j] = values[j+8*i] = 8;
389   }
390   assert(!hwloc_distances_add(topology, 8, objs, values,
391 			      HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
392 			      HWLOC_DISTANCES_ADD_FLAG_GROUP));
393   depth = hwloc_topology_get_depth(topology);
394   assert(depth == 4);
395   /* group 4cores as 2*2 */
396   for(i=0; i<8; i++) {
397     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_CORE, i);
398     for(j=0; j<8; j++)
399       if (i==j)
400         values[i+8*j] = values[j+8*i] = 1;
401       else if (i/2==j/2)
402         values[i+8*j] = values[j+8*i] = 4;
403       else
404         values[i+8*j] = values[j+8*i] = 8;
405   }
406   assert(!hwloc_distances_add(topology, 8, objs, values,
407 			      HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
408 			      HWLOC_DISTANCES_ADD_FLAG_GROUP));
409   depth = hwloc_topology_get_depth(topology);
410   assert(depth == 5);
411   width = hwloc_get_nbobjs_by_depth(topology, 0);
412   assert(width == 1);
413   width = hwloc_get_nbobjs_by_depth(topology, 1);
414   assert(width == 2);
415   width = hwloc_get_nbobjs_by_depth(topology, 2);
416   assert(width == 4);
417   width = hwloc_get_nbobjs_by_depth(topology, 3);
418   assert(width == 8);
419   width = hwloc_get_nbobjs_by_depth(topology, 4);
420   assert(width == 32);
421   width = hwloc_get_nbobjs_by_depth(topology, HWLOC_TYPE_DEPTH_NUMANODE);
422   assert(width == 2);
423   /* group 4PUs as 2*2 */
424   for(i=0; i<32; i++) {
425     objs[i] = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PU, i);
426     for(j=0; j<32; j++)
427       if (i==j)
428         values[i+32*j] = values[j+32*i] = 1;
429       else if (i/2==j/2)
430         values[i+32*j] = values[j+32*i] = 4;
431       else
432         values[i+32*j] = values[j+32*i] = 8;
433   }
434   assert(!hwloc_distances_add(topology, 32, objs, values,
435 			      HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_FROM_USER,
436 			      HWLOC_DISTANCES_ADD_FLAG_GROUP));
437   depth = hwloc_topology_get_depth(topology);
438   assert(depth == 6);
439   width = hwloc_get_nbobjs_by_depth(topology, 0);
440   assert(width == 1);
441   width = hwloc_get_nbobjs_by_depth(topology, 1);
442   assert(width == 2);
443   width = hwloc_get_nbobjs_by_depth(topology, 2);
444   assert(width == 4);
445   width = hwloc_get_nbobjs_by_depth(topology, 3);
446   assert(width == 8);
447   width = hwloc_get_nbobjs_by_depth(topology, 4);
448   assert(width == 16);
449   width = hwloc_get_nbobjs_by_depth(topology, 5);
450   assert(width == 32);
451   width = hwloc_get_nbobjs_by_depth(topology, HWLOC_TYPE_DEPTH_NUMANODE);
452   assert(width == 2);
453   hwloc_topology_destroy(topology);
454 
455   return 0;
456 }
457