DPDK 22.11.5
rte_member_heap.h
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
3 * Copyright(c) 2020, Alan Liu <zaoxingliu@gmail.com>
4 */
5
6#ifndef RTE_MEMBER_HEAP_H
7#define RTE_MEMBER_HEAP_H
8
9#include <rte_ring_elem.h>
10#include "rte_member.h"
11
12#define LCHILD(x) (2 * x + 1)
13#define RCHILD(x) (2 * x + 2)
14#define PARENT(x) ((x - 1) / 2)
15
16#define HASH_BKT_SIZE 16
17#define HASH_HP_MULTI 4
18#define HASH_RESIZE_MULTI 2
19
20struct hash_bkt {
21 uint16_t sig[HASH_BKT_SIZE];
22 uint16_t idx[HASH_BKT_SIZE];
23};
24
25struct hash {
26 uint16_t bkt_cnt;
27 uint16_t num_item;
28 uint32_t seed;
29 struct hash_bkt buckets[0];
30};
31
32struct node {
33 void *key;
34 uint64_t count;
35};
36
37struct minheap {
38 uint32_t key_len;
39 uint32_t size;
40 uint32_t socket;
41 struct hash *hashtable;
42 struct node *elem;
43};
44
45static int
46hash_table_insert(const void *key, int value, int key_len, struct hash *table)
47{
48 uint32_t hash = MEMBER_HASH_FUNC(key, key_len, table->seed);
49 uint16_t idx = hash % table->bkt_cnt;
50 uint16_t sig = hash >> 16;
51 int i;
52
53 for (i = 0; i < HASH_BKT_SIZE; i++) {
54 if (table->buckets[idx].idx[i] == 0) {
55 table->buckets[idx].idx[i] = value;
56 table->buckets[idx].sig[i] = sig;
57 table->num_item++;
58 return 0;
59 }
60 }
61
62 return -ENOMEM;
63}
64
65static int
66hash_table_update(const void *key, int old_value, int value, int key_len, struct hash *table)
67{
68 uint32_t hash = MEMBER_HASH_FUNC(key, key_len, table->seed);
69 uint16_t idx = hash % table->bkt_cnt;
70 uint16_t sig = hash >> 16;
71 int i;
72
73 for (i = 0; i < HASH_BKT_SIZE; i++) {
74 if (table->buckets[idx].sig[i] == sig && table->buckets[idx].idx[i] == old_value) {
75 table->buckets[idx].idx[i] = value;
76 return 0;
77 }
78 }
79
80 return -1;
81}
82
83static int
84hash_table_del(const void *key, uint16_t value, int key_len, struct hash *table)
85{
86 uint32_t hash = MEMBER_HASH_FUNC(key, key_len, table->seed);
87 uint16_t idx = hash % table->bkt_cnt;
88 uint16_t sig = hash >> 16;
89 int i;
90
91 for (i = 0; i < HASH_BKT_SIZE; i++) {
92 if (table->buckets[idx].sig[i] == sig && table->buckets[idx].idx[i] == value) {
93 table->buckets[idx].idx[i] = 0;
94 table->num_item--;
95 return 0;
96 }
97 }
98
99 return -1;
100}
101
102static int
103hash_table_lookup(const void *key, int key_len, struct minheap *hp)
104{
105 struct hash *table = hp->hashtable;
106 uint32_t hash = MEMBER_HASH_FUNC(key, key_len, table->seed);
107 uint16_t idx = hash % table->bkt_cnt;
108 uint16_t sig = hash >> 16;
109 int i;
110
111 for (i = 0; i < HASH_BKT_SIZE; i++) {
112 if (table->buckets[idx].sig[i] == sig && table->buckets[idx].idx[i] != 0) {
113 uint32_t hp_idx = table->buckets[idx].idx[i] - 1;
114
115 if (memcmp(hp->elem[hp_idx].key, key, hp->key_len) == 0)
116 return hp_idx;
117 }
118 }
119
120 return -ENOENT; /* key doesn't exist */
121}
122
123static int
124resize_hash_table(struct minheap *hp)
125{
126 uint32_t i;
127 uint32_t new_bkt_cnt;
128
129 while (1) {
130 new_bkt_cnt = hp->hashtable->bkt_cnt * HASH_RESIZE_MULTI;
131
132 RTE_MEMBER_LOG(ERR, "Sketch Minheap HT load factor is [%f]\n",
133 hp->hashtable->num_item / ((float)hp->hashtable->bkt_cnt * HASH_BKT_SIZE));
134 RTE_MEMBER_LOG(ERR, "Sketch Minheap HT resize happen!\n");
135 rte_free(hp->hashtable);
136 hp->hashtable = rte_zmalloc_socket(NULL, sizeof(struct hash) +
137 new_bkt_cnt * sizeof(struct hash_bkt),
138 RTE_CACHE_LINE_SIZE, hp->socket);
139
140 if (hp->hashtable == NULL) {
141 RTE_MEMBER_LOG(ERR, "Sketch Minheap HT allocation failed\n");
142 return -ENOMEM;
143 }
144
145 hp->hashtable->bkt_cnt = new_bkt_cnt;
146
147 for (i = 0; i < hp->size; ++i) {
148 if (hash_table_insert(hp->elem[i].key,
149 i + 1, hp->key_len, hp->hashtable) < 0) {
150 RTE_MEMBER_LOG(ERR,
151 "Sketch Minheap HT resize insert fail!\n");
152 break;
153 }
154 }
155 if (i == hp->size)
156 break;
157 }
158
159 return 0;
160}
161
162/* find the item in the given minheap */
163static int
164rte_member_minheap_find(struct minheap *hp, const void *key)
165{
166 int idx = hash_table_lookup(key, hp->key_len, hp);
167 return idx;
168}
169
170static int
171rte_member_minheap_init(struct minheap *heap, int size,
172 uint32_t socket, uint32_t seed)
173{
174 heap->elem = rte_zmalloc_socket(NULL, sizeof(struct node) * size,
175 RTE_CACHE_LINE_SIZE, socket);
176 if (heap->elem == NULL) {
177 RTE_MEMBER_LOG(ERR, "Sketch Minheap elem allocation failed\n");
178 return -ENOMEM;
179 }
180
181 uint32_t hash_bkt_cnt = rte_align32pow2(size * HASH_HP_MULTI) / HASH_BKT_SIZE;
182
183 if (hash_bkt_cnt == 0)
184 hash_bkt_cnt = 1;
185
186 heap->hashtable = rte_zmalloc_socket(NULL, sizeof(struct hash) +
187 hash_bkt_cnt * sizeof(struct hash_bkt),
188 RTE_CACHE_LINE_SIZE, socket);
189
190 if (heap->hashtable == NULL) {
191 RTE_MEMBER_LOG(ERR, "Sketch Minheap HT allocation failed\n");
192 rte_free(heap->elem);
193 return -ENOMEM;
194 }
195
196 heap->hashtable->seed = seed;
197 heap->hashtable->bkt_cnt = hash_bkt_cnt;
198 heap->socket = socket;
199
200 return 0;
201}
202
203/* swap the minheap nodes */
204static __rte_always_inline void
205rte_member_heap_swap(struct node *n1, struct node *n2)
206{
207 struct node temp = *n1;
208 *n1 = *n2;
209 *n2 = temp;
210}
211
212/* heapify function */
213static void
214rte_member_heapify(struct minheap *hp, uint32_t idx, bool update_hash)
215{
216 uint32_t smallest;
217
218 if (LCHILD(idx) < hp->size &&
219 hp->elem[LCHILD(idx)].count < hp->elem[idx].count)
220 smallest = LCHILD(idx);
221 else
222 smallest = idx;
223
224 if (RCHILD(idx) < hp->size &&
225 hp->elem[RCHILD(idx)].count < hp->elem[smallest].count)
226 smallest = RCHILD(idx);
227
228 if (smallest != idx) {
229 rte_member_heap_swap(&(hp->elem[idx]), &(hp->elem[smallest]));
230
231 if (update_hash) {
232 if (hash_table_update(hp->elem[smallest].key, idx + 1, smallest + 1,
233 hp->key_len, hp->hashtable) < 0) {
234 RTE_MEMBER_LOG(ERR, "Minheap Hash Table update failed\n");
235 return;
236 }
237
238 if (hash_table_update(hp->elem[idx].key, smallest + 1, idx + 1,
239 hp->key_len, hp->hashtable) < 0) {
240 RTE_MEMBER_LOG(ERR, "Minheap Hash Table update failed\n");
241 return;
242 }
243 }
244 rte_member_heapify(hp, smallest, update_hash);
245 }
246}
247
248/* insert a node into the minheap */
249static int
250rte_member_minheap_insert_node(struct minheap *hp, const void *key,
251 int counter, void *key_slot,
252 struct rte_ring *free_key_slot)
253{
254 struct node nd;
255 uint32_t slot_id;
256
257 if (rte_ring_sc_dequeue_elem(free_key_slot, &slot_id, sizeof(uint32_t)) != 0) {
258 RTE_MEMBER_LOG(ERR, "Minheap get empty keyslot failed\n");
259 return -1;
260 }
261
262 nd.count = counter;
263 nd.key = RTE_PTR_ADD(key_slot, slot_id * hp->key_len);
264
265 memcpy(nd.key, key, hp->key_len);
266
267 uint32_t i = (hp->size)++;
268
269 while (i && nd.count < hp->elem[PARENT(i)].count) {
270 hp->elem[i] = hp->elem[PARENT(i)];
271 if (hash_table_update(hp->elem[i].key, PARENT(i) + 1, i + 1,
272 hp->key_len, hp->hashtable) < 0) {
273 RTE_MEMBER_LOG(ERR, "Minheap Hash Table update failed\n");
274 return -1;
275 }
276 i = PARENT(i);
277 }
278 hp->elem[i] = nd;
279
280 if (hash_table_insert(key, i + 1, hp->key_len, hp->hashtable) < 0) {
281 if (resize_hash_table(hp) < 0) {
282 RTE_MEMBER_LOG(ERR, "Minheap Hash Table resize failed\n");
283 return -1;
284 }
285 }
286
287 return 0;
288}
289
290/* delete a key from the minheap */
291static int
292rte_member_minheap_delete_node(struct minheap *hp, const void *key,
293 void *key_slot, struct rte_ring *free_key_slot)
294{
295 int idx = rte_member_minheap_find(hp, key);
296 uint32_t offset = RTE_PTR_DIFF(hp->elem[idx].key, key_slot) / hp->key_len;
297
298 if (hash_table_del(key, idx + 1, hp->key_len, hp->hashtable) < 0) {
299 RTE_MEMBER_LOG(ERR, "Minheap Hash Table delete failed\n");
300 return -1;
301 }
302
303 rte_ring_sp_enqueue_elem(free_key_slot, &offset, sizeof(uint32_t));
304
305 if (idx == (int)(hp->size - 1)) {
306 hp->size--;
307 return 0;
308 }
309
310 hp->elem[idx] = hp->elem[hp->size - 1];
311
312 if (hash_table_update(hp->elem[idx].key, hp->size, idx + 1,
313 hp->key_len, hp->hashtable) < 0) {
314 RTE_MEMBER_LOG(ERR, "Minheap Hash Table update failed\n");
315 return -1;
316 }
317 hp->size--;
318 rte_member_heapify(hp, idx, true);
319
320 return 0;
321}
322
323/* replace a min node with a new key. */
324static int
325rte_member_minheap_replace_node(struct minheap *hp,
326 const void *new_key,
327 int new_counter)
328{
329 struct node nd;
330 void *recycle_key = NULL;
331
332 recycle_key = hp->elem[0].key;
333
334 if (hash_table_del(recycle_key, 1, hp->key_len, hp->hashtable) < 0) {
335 RTE_MEMBER_LOG(ERR, "Minheap Hash Table delete failed\n");
336 return -1;
337 }
338
339 hp->elem[0] = hp->elem[hp->size - 1];
340
341 if (hash_table_update(hp->elem[0].key, hp->size, 1,
342 hp->key_len, hp->hashtable) < 0) {
343 RTE_MEMBER_LOG(ERR, "Minheap Hash Table update failed\n");
344 return -1;
345 }
346 hp->size--;
347
348 rte_member_heapify(hp, 0, true);
349
350 nd.count = new_counter;
351 nd.key = recycle_key;
352
353 memcpy(nd.key, new_key, hp->key_len);
354
355 uint32_t i = (hp->size)++;
356
357 while (i && nd.count < hp->elem[PARENT(i)].count) {
358 hp->elem[i] = hp->elem[PARENT(i)];
359 if (hash_table_update(hp->elem[i].key, PARENT(i) + 1, i + 1,
360 hp->key_len, hp->hashtable) < 0) {
361 RTE_MEMBER_LOG(ERR, "Minheap Hash Table update failed\n");
362 return -1;
363 }
364 i = PARENT(i);
365 }
366
367 hp->elem[i] = nd;
368
369 if (hash_table_insert(new_key, i + 1, hp->key_len, hp->hashtable) < 0) {
370 RTE_MEMBER_LOG(ERR, "Minheap Hash Table replace insert failed\n");
371 if (resize_hash_table(hp) < 0) {
372 RTE_MEMBER_LOG(ERR, "Minheap Hash Table replace resize failed\n");
373 return -1;
374 }
375 }
376
377 return 0;
378}
379
380/* sort the heap into a descending array */
381static void
382rte_member_heapsort(struct minheap *hp, struct node *result_array)
383{
384 struct minheap new_hp;
385
386 /* build a new heap for using the given array */
387 new_hp.size = hp->size;
388 new_hp.key_len = hp->key_len;
389 new_hp.elem = result_array;
390 memcpy(result_array, hp->elem, hp->size * sizeof(struct node));
391
392 /* sort the new heap */
393 while (new_hp.size > 1) {
394 rte_member_heap_swap(&(new_hp.elem[0]), &(new_hp.elem[new_hp.size - 1]));
395 new_hp.size--;
396 rte_member_heapify(&new_hp, 0, false);
397 }
398}
399
400static void
401rte_member_minheap_free(struct minheap *hp)
402{
403 if (hp == NULL)
404 return;
405
406 rte_free(hp->elem);
407 rte_free(hp->hashtable);
408}
409
410static void
411rte_member_minheap_reset(struct minheap *hp)
412{
413 if (hp == NULL)
414 return;
415
416 memset(hp->elem, 0, sizeof(struct node) * hp->size);
417 hp->size = 0;
418
419 memset((char *)hp->hashtable + sizeof(struct hash), 0,
420 hp->hashtable->bkt_cnt * sizeof(struct hash_bkt));
421 hp->hashtable->num_item = 0;
422}
423
424#endif /* RTE_MEMBER_HEAP_H */
#define RTE_PTR_DIFF(ptr1, ptr2)
Definition: rte_common.h:302
static uint32_t rte_align32pow2(uint32_t x)
Definition: rte_common.h:548
#define RTE_PTR_ADD(ptr, x)
Definition: rte_common.h:290
#define __rte_always_inline
Definition: rte_common.h:255
void void rte_free(void *ptr)
void * rte_zmalloc_socket(const char *type, size_t size, unsigned align, int socket) __rte_alloc_size(2)
static __rte_always_inline int rte_ring_sp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)
static __rte_always_inline int rte_ring_sc_dequeue_elem(struct rte_ring *r, void *obj_p, unsigned int esize)