Support DPDK 19.11 rc0
[samplevnf.git] / VNFs / DPPD-PROX / heap.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <string.h>
18 #include <stdio.h>
19 #include <stddef.h>
20 #include <rte_version.h>
21 #include <rte_prefetch.h>
22 #include <rte_memory.h>
23
24 #include "prox_malloc.h"
25 #include "prox_assert.h"
26 #include "heap.h"
27 #include "log.h"
28
29 #include <string.h>
30 #include <stddef.h>
31 #include <stdlib.h>
32
33 struct heap_elem {
34         uint64_t priority;
35         struct heap_ref *ref;
36         struct heap_elem *prev;
37         struct heap_elem *next;
38         struct heap_elem *child;
39 };
40
41 struct strl {
42         char *str;
43         size_t len;
44 };
45
46 int heap_top_is_lower(struct heap *h, uint64_t prio)
47 {
48         return !heap_is_empty(h) && h->top->priority < prio;
49 }
50
51 static int heap_elem_check(struct heap_elem *e, int is_top)
52 {
53         if (!e)
54                 return 1;
55         if (e != e->prev &&
56             e != e->next &&
57             e != e->child)
58                 return 1;
59         else
60                 return 0;
61
62         if (is_top && e->prev != NULL)
63                 return 0;
64         if (!is_top && e->prev == NULL)
65                 return 0;
66
67         if (e->next) {
68                 if (e->next->prev != e)
69                         return 0;
70
71                 if (heap_elem_check(e->next, 0))
72                         return 1;
73                 else
74                         return 0;
75         }
76
77         if (e->child) {
78                 if (e->child->prev != e)
79                         return 0;
80
81                 if (heap_elem_check(e->child, 0))
82                         return 1;
83                 else
84                         return 0;
85         }
86
87         return 1;
88 }
89
90 static int heap_elem_in_heap_elem(struct heap_elem *in, struct heap_elem *find)
91 {
92         if (in == find)
93                 return 1;
94
95         if (in->next) {
96                 if (heap_elem_in_heap_elem(in->next, find))
97                         return 1;
98         }
99         if (in->child) {
100                 if (heap_elem_in_heap_elem(in->child, find))
101                         return 1;
102         }
103
104         return 0;
105 }
106
107 static int heap_elem_in_heap(struct heap *h, struct heap_elem *e)
108 {
109         if (h->top == NULL)
110                 return 0;
111
112         return heap_elem_in_heap_elem(h->top, e);
113 }
114
115 static int heap_elem_is_avail(struct heap *h, struct heap_elem *e)
116 {
117         for (uint32_t i = 0; i < h->n_avail; ++i) {
118                 if (h->avail[i] == e)
119                         return 1;
120         }
121         return 0;
122 }
123
124 static uint32_t heap_elem_calc_size(struct heap_elem *e)
125 {
126         int ret = 0;
127
128         if (e)
129                 ret++;
130         else
131                 return ret;
132
133         if (e->next)
134                 ret += heap_elem_calc_size(e->next);
135         if (e->child)
136                 ret += heap_elem_calc_size(e->child);
137         return ret;
138 }
139
140 static uint32_t heap_calc_size(struct heap *h)
141 {
142         return heap_elem_calc_size(h->top);
143 }
144
145 static void cat_indent(struct strl *s, int indent)
146 {
147         size_t r;
148
149         if (s->len < 50)
150                 return ;
151
152         for (int i = 0; i < indent; ++i) {
153                 r = snprintf(s->str, s->len, " ");
154                 s->str += r;
155                 s->len -= r;
156         }
157 }
158
159 static void cat_priority(struct strl *s, uint64_t priority)
160 {
161         size_t r;
162
163         if (s->len < 50)
164                 return ;
165
166         r = snprintf(s->str, s->len, "%"PRIu64"\n", priority);
167         s->str += r;
168         s->len -= r;
169 }
170
171 static void heap_print2(struct heap_elem *e, int indent, struct strl *s)
172 {
173         size_t r;
174
175         cat_indent(s, indent);
176         cat_priority(s, e->priority);
177
178         struct heap_elem *child = e->child;
179
180         while (child) {
181                 heap_print2(child, indent + 1, s);
182                 child = child->next;
183         }
184 }
185
186 static void heap_print3(struct heap_elem *e, char *result, size_t buf_len)
187 {
188         struct strl s;
189
190         s.str = result;
191         s.len = buf_len;
192
193         heap_print2(e, 0, &s);
194 }
195
196 void heap_print(struct heap *h, char *result, size_t buf_len)
197 {
198         if (h->n_elems == 0) {
199                 *result = 0;
200                 return ;
201         }
202
203         heap_print3(h->top, result, buf_len);
204 }
205
206 struct heap *heap_create(uint32_t max_elems, int socket_id)
207 {
208         struct heap *ret;
209         size_t mem_size = 0;
210         size_t elem_mem = 0;
211         struct heap_elem *e;
212
213         /* max_elems + 1 since index start at 1. Store total number of
214            elements in the first entry (which is unused otherwise). */
215         mem_size += sizeof(struct heap);
216         mem_size += sizeof(((struct heap *)0)->top) * max_elems;
217         mem_size = RTE_CACHE_LINE_ROUNDUP(mem_size);
218         elem_mem = mem_size;
219         mem_size += sizeof(*((struct heap *)0)->top) * max_elems;
220         ret = prox_zmalloc(mem_size, socket_id);
221         if (!ret)
222                 return NULL;
223
224         e = (struct heap_elem *)(((uint8_t *)ret) + elem_mem);
225         PROX_ASSERT((void *)&e[max_elems] <= (void *)ret + mem_size);
226
227         for (uint32_t i = 0; i < max_elems; ++i) {
228                 PROX_ASSERT(e->priority == 0);
229                 PROX_ASSERT(e->ref == 0);
230                 PROX_ASSERT(e->prev == 0);
231                 PROX_ASSERT(e->next == 0);
232                 PROX_ASSERT(e->child == 0);
233
234                 ret->avail[ret->n_avail++] = e++;
235         }
236
237         PROX_ASSERT(ret->n_elems + ret->n_avail == max_elems);
238         return ret;
239 }
240
241 static struct heap_elem *heap_get(struct heap *h)
242 {
243         PROX_ASSERT(h->n_avail);
244
245         return h->avail[--h->n_avail];
246 }
247
248 static void heap_put(struct heap *h, struct heap_elem *e)
249 {
250         h->avail[h->n_avail++] = e;
251 }
252
253 void heap_add(struct heap *h, struct heap_ref *ref, uint64_t priority)
254 {
255         PROX_ASSERT(h);
256         PROX_ASSERT(ref);
257         PROX_ASSERT(ref->elem == NULL);
258         PROX_ASSERT(heap_elem_check(h->top, 1));
259         PROX_ASSERT(h->n_elems == heap_calc_size(h));
260
261         if (h->n_elems == 0) {
262                 h->n_elems++;
263                 h->top = heap_get(h);
264
265                 h->top->priority = priority;
266                 h->top->ref = ref;
267                 ref->elem = h->top;
268                 h->top->prev = NULL;
269                 h->top->next = NULL;
270                 h->top->child = NULL;
271
272                 PROX_ASSERT(heap_elem_check(h->top, 1));
273                 PROX_ASSERT(h->n_elems == heap_calc_size(h));
274                 return ;
275         }
276
277         h->n_elems++;
278         /* New element becomes new top */
279         if (h->top->priority > priority) {
280                 struct heap_elem *n = heap_get(h);
281
282                 n->priority = priority;
283                 n->ref = ref;
284                 ref->elem = n;
285                 n->prev = NULL;
286                 n->next = NULL;
287                 n->child = h->top;
288
289                 h->top->prev = n;
290                 h->top = n;
291         }
292         /* New element is added as first sibling */
293         else {
294                 struct heap_elem *n = heap_get(h);
295                 n->priority = priority;
296                 n->ref = ref;
297                 ref->elem = n;
298                 n->prev = h->top;
299                 n->next = h->top->child;
300                 if (h->top->child)
301                         h->top->child->prev = n;
302                 n->child = NULL;
303                 h->top->child = n;
304         }
305
306         PROX_ASSERT(heap_elem_check(h->top, 1));
307         PROX_ASSERT(h->n_elems == heap_calc_size(h));
308 }
309
310 static void heap_merge_tops_left(struct heap_elem *left, struct heap_elem *right)
311 {
312         PROX_ASSERT(left->priority <= right->priority);
313         PROX_ASSERT(left != right);
314
315         /* right moves down and becomes first child of left. */
316         left->next = right->next;
317         if (right->next)
318                 right->next->prev = left;
319
320         right->next = left->child;
321         if (left->child)
322                 left->child->prev = right;
323
324         /* right->prev is now referring to parent since right is the
325            new first child. */
326         left->child = right;
327 }
328
329 static void heap_merge_tops_right(struct heap_elem *left, struct heap_elem *right)
330 {
331         PROX_ASSERT(left->priority >= right->priority);
332         PROX_ASSERT(left != right);
333
334         /* Left goes down one layer */
335         right->prev = left->prev;
336         if (left->prev)
337                 left->prev->next = right;
338
339         left->next = right->child;
340         if (right->child)
341                 right->child->prev = left;
342
343         left->prev = right;
344         right->child = left;
345 }
346
347 static struct heap_elem *heap_merge_children(struct heap_elem *e)
348 {
349         struct heap_elem *next = e->next;
350         struct heap_elem *tmp;
351         struct heap_elem *prev;
352         struct heap_elem *first;
353
354         PROX_ASSERT(e);
355         int cnt = 0;
356         /* TODO: is this really needed? */
357         if (!next)
358                 return e;
359
360         if (e->priority < next->priority)
361                 first = e;
362         else
363                 first = next;
364
365         /* Forward pass */
366         do {
367                 cnt++;
368                 tmp = next->next;
369                 rte_prefetch0(tmp);
370                 if (e->priority < next->priority) {
371                         heap_merge_tops_left(e, next);
372                         prev = e;
373                         PROX_ASSERT(e->child == next);
374                 }
375                 else {
376                         heap_merge_tops_right(e, next);
377                         PROX_ASSERT(next->child == e);
378                         prev = next;
379                 }
380
381                 if (tmp) {
382                         tmp->prev = prev;
383                         e = tmp;
384                         /* Next could be empty, (uneven # children) */
385                         if (!tmp->next)
386                                 break;
387                         next = tmp->next;
388                 }
389                 else {
390                         /* Even number of nodes, after breaking set e
391                            to the last merged pair top */
392                         if (e->priority >= next->priority)
393                                 e = next;
394                         break;
395                 }
396         } while (1);
397         /* Backward pass, merge everything with the right until the
398            first child */
399         while (first != e) {
400                 prev = e->prev;
401
402                 if (e->priority < prev->priority) {
403                         heap_merge_tops_right(prev, e);
404                         if (prev == first) {
405                                 first = e;
406                                 break;
407                         }
408                 }
409                 else {
410                         heap_merge_tops_left(prev, e);
411                         e = prev;
412                 }
413         }
414         return first;
415 }
416
417 static int heap_elem_first_sibling(const struct heap_elem *e)
418 {
419         return e->prev->child == e;
420 }
421
422 void heap_del(struct heap *h, struct heap_ref *d)
423 {
424         struct heap_elem *del = d->elem;
425
426         PROX_ASSERT(del);
427         PROX_ASSERT(heap_elem_in_heap(h, del));
428         PROX_ASSERT(!heap_elem_is_avail(h, del));
429         PROX_ASSERT(h->n_elems == heap_calc_size(h));
430         PROX_ASSERT(heap_elem_check(h->top, 1));
431         PROX_ASSERT(h->top->next == NULL);
432         PROX_ASSERT(h->top->prev == NULL);
433
434         d->elem = NULL;
435         /* Del is at the top */
436         if (del->prev == NULL) {
437                 PROX_ASSERT(del == h->top);
438                 if (del->child) {
439                         del->child->prev = NULL;
440                         h->top = heap_merge_children(del->child);
441                         PROX_ASSERT(h->top);
442                 }
443                 else {
444                         h->top = NULL;
445                 }
446
447                 h->n_elems--;
448                 heap_put(h, del);
449                 PROX_ASSERT(heap_elem_check(h->top, 1));
450                 PROX_ASSERT(h->n_elems == 0 || h->top != NULL);
451                 PROX_ASSERT(h->n_elems == heap_calc_size(h));
452                 return ;
453         }
454         PROX_ASSERT(del != h->top);
455
456         /* Del is somewhere in a lower layer. If it the first child,
457            need to fix the parent differently. */
458         if (heap_elem_first_sibling(del)) {
459                 del->prev->child = del->next;
460                 if (del->next)
461                         del->next->prev = del->prev;
462         }
463         else {
464                 del->prev->next = del->next;
465                 if (del->next)
466                         del->next->prev = del->prev;
467         }
468
469         struct heap_elem *top2 = del->child;
470
471         /* If the node to be deleted has children, there is more work:
472            merge the children into a single heap and merge with
473            top. If there are no children, then the disconnection above
474            is enough. */
475         if (top2) {
476                 top2->prev = NULL;
477                 top2 = heap_merge_children(top2);
478
479                 /* Merge top2 with h->top */
480                 if (h->top->priority < top2->priority) {
481                         top2->next = h->top->child;
482                         top2->prev = h->top;
483                         if (h->top->child)
484                                 h->top->child->prev = top2;
485
486                         h->top->child = top2;
487                 }
488                 else {
489                         h->top->next = top2->child;
490                         h->top->prev = top2;
491                         if (top2->child)
492                                 top2->child->prev = h->top;
493
494                         top2->child = h->top;
495                         h->top = top2;
496                 }
497
498         }
499         h->n_elems--;
500         heap_put(h, del);
501
502         PROX_ASSERT(heap_elem_check(h->top, 1));
503         PROX_ASSERT(h->n_elems == heap_calc_size(h));
504 }
505
506 struct heap_ref *heap_pop(struct heap *h)
507 {
508         if (h->n_elems == 0)
509                 return NULL;
510
511         struct heap_ref *ret = h->top->ref;
512
513         heap_del(h, h->top->ref);
514         return ret;
515 }