DPDK  23.03.0
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 
20 struct hash_bkt {
21  uint16_t sig[HASH_BKT_SIZE];
22  uint16_t idx[HASH_BKT_SIZE];
23 };
24 
25 struct hash {
26  uint16_t bkt_cnt;
27  uint16_t num_item;
28  uint32_t seed;
29  struct hash_bkt buckets[0];
30 };
31 
32 struct node {
33  void *key;
34  uint64_t count;
35 };
36 
37 struct minheap {
38  uint32_t key_len;
39  uint32_t size;
40  uint32_t socket;
41  struct hash *hashtable;
42  struct node *elem;
43 };
44 
45 static int
46 hash_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 
65 static int
66 hash_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 
83 static int
84 hash_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 
102 static int
103 hash_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 
123 static int
124 resize_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 */
163 static int
164 rte_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 
170 static int
171 rte_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 */
204 static __rte_always_inline void
205 rte_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 */
213 static void
214 rte_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 */
249 static int
250 rte_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 */
291 static int
292 rte_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. */
324 static int
325 rte_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 */
381 static void
382 rte_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 
400 static void
401 rte_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 
410 static void
411 rte_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 */
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)
#define __rte_always_inline
Definition: rte_common.h:255
#define RTE_PTR_ADD(ptr, x)
Definition: rte_common.h:290
static uint32_t rte_align32pow2(uint32_t x)
Definition: rte_common.h:548
void * rte_zmalloc_socket(const char *type, size_t size, unsigned align, int socket) __rte_alloc_size(2)
void void rte_free(void *ptr)
#define RTE_PTR_DIFF(ptr1, ptr2)
Definition: rte_common.h:302