2 // Copyright (c) 2010-2017 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <rte_version.h>
21 #include <rte_prefetch.h>
22 #include <rte_memory.h>
24 #include "prox_malloc.h"
25 #include "prox_assert.h"
36 struct heap_elem *prev;
37 struct heap_elem *next;
38 struct heap_elem *child;
46 int heap_top_is_lower(struct heap *h, uint64_t prio)
48 return !heap_is_empty(h) && h->top->priority < prio;
51 static int heap_elem_check(struct heap_elem *e, int is_top)
62 if (is_top && e->prev != NULL)
64 if (!is_top && e->prev == NULL)
68 if (e->next->prev != e)
71 if (heap_elem_check(e->next, 0))
78 if (e->child->prev != e)
81 if (heap_elem_check(e->child, 0))
90 static int heap_elem_in_heap_elem(struct heap_elem *in, struct heap_elem *find)
96 if (heap_elem_in_heap_elem(in->next, find))
100 if (heap_elem_in_heap_elem(in->child, find))
107 static int heap_elem_in_heap(struct heap *h, struct heap_elem *e)
112 return heap_elem_in_heap_elem(h->top, e);
115 static int heap_elem_is_avail(struct heap *h, struct heap_elem *e)
117 for (uint32_t i = 0; i < h->n_avail; ++i) {
118 if (h->avail[i] == e)
124 static uint32_t heap_elem_calc_size(struct heap_elem *e)
134 ret += heap_elem_calc_size(e->next);
136 ret += heap_elem_calc_size(e->child);
140 static uint32_t heap_calc_size(struct heap *h)
142 return heap_elem_calc_size(h->top);
145 static void cat_indent(struct strl *s, int indent)
152 for (int i = 0; i < indent; ++i) {
153 r = snprintf(s->str, s->len, " ");
159 static void cat_priority(struct strl *s, uint64_t priority)
166 r = snprintf(s->str, s->len, "%"PRIu64"\n", priority);
171 static void heap_print2(struct heap_elem *e, int indent, struct strl *s)
175 cat_indent(s, indent);
176 cat_priority(s, e->priority);
178 struct heap_elem *child = e->child;
181 heap_print2(child, indent + 1, s);
186 static void heap_print3(struct heap_elem *e, char *result, size_t buf_len)
193 heap_print2(e, 0, &s);
196 void heap_print(struct heap *h, char *result, size_t buf_len)
198 if (h->n_elems == 0) {
203 heap_print3(h->top, result, buf_len);
206 struct heap *heap_create(uint32_t max_elems, int socket_id)
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);
219 mem_size += sizeof(*((struct heap *)0)->top) * max_elems;
220 ret = prox_zmalloc(mem_size, socket_id);
224 e = (struct heap_elem *)(((uint8_t *)ret) + elem_mem);
225 PROX_ASSERT((void *)&e[max_elems] <= (void *)ret + mem_size);
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);
234 ret->avail[ret->n_avail++] = e++;
237 PROX_ASSERT(ret->n_elems + ret->n_avail == max_elems);
241 static struct heap_elem *heap_get(struct heap *h)
243 PROX_ASSERT(h->n_avail);
245 return h->avail[--h->n_avail];
248 static void heap_put(struct heap *h, struct heap_elem *e)
250 h->avail[h->n_avail++] = e;
253 void heap_add(struct heap *h, struct heap_ref *ref, uint64_t priority)
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));
261 if (h->n_elems == 0) {
263 h->top = heap_get(h);
265 h->top->priority = priority;
270 h->top->child = NULL;
272 PROX_ASSERT(heap_elem_check(h->top, 1));
273 PROX_ASSERT(h->n_elems == heap_calc_size(h));
278 /* New element becomes new top */
279 if (h->top->priority > priority) {
280 struct heap_elem *n = heap_get(h);
282 n->priority = priority;
292 /* New element is added as first sibling */
294 struct heap_elem *n = heap_get(h);
295 n->priority = priority;
299 n->next = h->top->child;
301 h->top->child->prev = n;
306 PROX_ASSERT(heap_elem_check(h->top, 1));
307 PROX_ASSERT(h->n_elems == heap_calc_size(h));
310 static void heap_merge_tops_left(struct heap_elem *left, struct heap_elem *right)
312 PROX_ASSERT(left->priority <= right->priority);
313 PROX_ASSERT(left != right);
315 /* right moves down and becomes first child of left. */
316 left->next = right->next;
318 right->next->prev = left;
320 right->next = left->child;
322 left->child->prev = right;
324 /* right->prev is now referring to parent since right is the
329 static void heap_merge_tops_right(struct heap_elem *left, struct heap_elem *right)
331 PROX_ASSERT(left->priority >= right->priority);
332 PROX_ASSERT(left != right);
334 /* Left goes down one layer */
335 right->prev = left->prev;
337 left->prev->next = right;
339 left->next = right->child;
341 right->child->prev = left;
347 static struct heap_elem *heap_merge_children(struct heap_elem *e)
349 struct heap_elem *next = e->next;
350 struct heap_elem *tmp;
351 struct heap_elem *prev;
352 struct heap_elem *first;
356 /* TODO: is this really needed? */
360 if (e->priority < next->priority)
370 if (e->priority < next->priority) {
371 heap_merge_tops_left(e, next);
373 PROX_ASSERT(e->child == next);
376 heap_merge_tops_right(e, next);
377 PROX_ASSERT(next->child == e);
384 /* Next could be empty, (uneven # children) */
390 /* Even number of nodes, after breaking set e
391 to the last merged pair top */
392 if (e->priority >= next->priority)
397 /* Backward pass, merge everything with the right until the
402 if (e->priority < prev->priority) {
403 heap_merge_tops_right(prev, e);
410 heap_merge_tops_left(prev, e);
417 static int heap_elem_first_sibling(const struct heap_elem *e)
419 return e->prev->child == e;
422 void heap_del(struct heap *h, struct heap_ref *d)
424 struct heap_elem *del = d->elem;
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);
435 /* Del is at the top */
436 if (del->prev == NULL) {
437 PROX_ASSERT(del == h->top);
439 del->child->prev = NULL;
440 h->top = heap_merge_children(del->child);
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));
454 PROX_ASSERT(del != h->top);
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;
461 del->next->prev = del->prev;
464 del->prev->next = del->next;
466 del->next->prev = del->prev;
469 struct heap_elem *top2 = del->child;
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
477 top2 = heap_merge_children(top2);
479 /* Merge top2 with h->top */
480 if (h->top->priority < top2->priority) {
481 top2->next = h->top->child;
484 h->top->child->prev = top2;
486 h->top->child = top2;
489 h->top->next = top2->child;
492 top2->child->prev = h->top;
494 top2->child = h->top;
502 PROX_ASSERT(heap_elem_check(h->top, 1));
503 PROX_ASSERT(h->n_elems == heap_calc_size(h));
506 struct heap_ref *heap_pop(struct heap *h)
511 struct heap_ref *ret = h->top->ref;
513 heap_del(h, h->top->ref);