1db354bd2SLeyi Rong /* SPDX-License-Identifier: BSD-3-Clause
2db354bd2SLeyi Rong * Copyright(c) 2020 Intel Corporation
3db354bd2SLeyi Rong * Copyright(c) 2020, Alan Liu <zaoxingliu@gmail.com>
4db354bd2SLeyi Rong */
5db354bd2SLeyi Rong
6db354bd2SLeyi Rong #include <math.h>
7db354bd2SLeyi Rong #include <string.h>
8db354bd2SLeyi Rong
9db354bd2SLeyi Rong #include <rte_malloc.h>
10db354bd2SLeyi Rong #include <rte_memory.h>
11db354bd2SLeyi Rong #include <rte_errno.h>
12db354bd2SLeyi Rong #include <rte_log.h>
13db354bd2SLeyi Rong #include <rte_random.h>
14db354bd2SLeyi Rong #include <rte_prefetch.h>
15db354bd2SLeyi Rong #include <rte_ring_elem.h>
16db354bd2SLeyi Rong
170e21c7c0SDavid Marchand #include "member.h"
18db354bd2SLeyi Rong #include "rte_member.h"
19db354bd2SLeyi Rong #include "rte_member_sketch.h"
20db354bd2SLeyi Rong #include "rte_member_heap.h"
21db354bd2SLeyi Rong
22db354bd2SLeyi Rong #ifdef CC_AVX512_SUPPORT
23db354bd2SLeyi Rong #include "rte_member_sketch_avx512.h"
24db354bd2SLeyi Rong #endif /* CC_AVX512_SUPPORT */
25db354bd2SLeyi Rong
26*c6552d9aSTyler Retzlaff struct __rte_cache_aligned sketch_runtime {
27db354bd2SLeyi Rong uint64_t pkt_cnt;
28db354bd2SLeyi Rong uint32_t until_next;
29db354bd2SLeyi Rong int converged;
30db354bd2SLeyi Rong struct minheap heap;
31db354bd2SLeyi Rong struct node *report_array;
32db354bd2SLeyi Rong void *key_slots;
33db354bd2SLeyi Rong struct rte_ring *free_key_slots;
34*c6552d9aSTyler Retzlaff };
35db354bd2SLeyi Rong
36db354bd2SLeyi Rong /*
37db354bd2SLeyi Rong * Geometric sampling to calculate how many packets needs to be
38db354bd2SLeyi Rong * skipped until next update. This method can mitigate the CPU
39db354bd2SLeyi Rong * overheads compared with coin-toss sampling.
40db354bd2SLeyi Rong */
41db354bd2SLeyi Rong static uint32_t
draw_geometric(const struct rte_member_setsum * ss)42db354bd2SLeyi Rong draw_geometric(const struct rte_member_setsum *ss)
43db354bd2SLeyi Rong {
44db354bd2SLeyi Rong double rand = 1;
45db354bd2SLeyi Rong
46db354bd2SLeyi Rong if (ss->sample_rate == 1)
47db354bd2SLeyi Rong return 1;
48db354bd2SLeyi Rong
49db354bd2SLeyi Rong while (rand == 1 || rand == 0)
50db354bd2SLeyi Rong rand = (double) rte_rand() / (double)(RTE_RAND_MAX);
51db354bd2SLeyi Rong
52db354bd2SLeyi Rong return (uint32_t)ceil(log(1 - rand) / log(1 - ss->sample_rate));
53db354bd2SLeyi Rong }
54db354bd2SLeyi Rong
55db354bd2SLeyi Rong static void
isort(uint64_t * array,int n)56db354bd2SLeyi Rong isort(uint64_t *array, int n)
57db354bd2SLeyi Rong {
58db354bd2SLeyi Rong int i;
59db354bd2SLeyi Rong
60db354bd2SLeyi Rong for (i = 1; i < n; i++) {
61db354bd2SLeyi Rong uint64_t t = array[i];
62db354bd2SLeyi Rong int j;
63db354bd2SLeyi Rong
64db354bd2SLeyi Rong for (j = i - 1; j >= 0; j--) {
65db354bd2SLeyi Rong if (t < array[j])
66db354bd2SLeyi Rong array[j + 1] = array[j];
67db354bd2SLeyi Rong else
68db354bd2SLeyi Rong break;
69db354bd2SLeyi Rong }
70db354bd2SLeyi Rong array[j + 1] = t;
71db354bd2SLeyi Rong }
72db354bd2SLeyi Rong }
73db354bd2SLeyi Rong
74db354bd2SLeyi Rong static __rte_always_inline void
swap(uint64_t * a,uint64_t * b)75db354bd2SLeyi Rong swap(uint64_t *a, uint64_t *b)
76db354bd2SLeyi Rong {
77db354bd2SLeyi Rong uint64_t tmp = *a;
78db354bd2SLeyi Rong *a = *b;
79db354bd2SLeyi Rong *b = tmp;
80db354bd2SLeyi Rong }
81db354bd2SLeyi Rong
82db354bd2SLeyi Rong static uint64_t
medianof5(uint64_t a,uint64_t b,uint64_t c,uint64_t d,uint64_t e)83db354bd2SLeyi Rong medianof5(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e)
84db354bd2SLeyi Rong {
85db354bd2SLeyi Rong if (a > b)
86db354bd2SLeyi Rong swap(&a, &b);
87db354bd2SLeyi Rong if (c > d)
88db354bd2SLeyi Rong swap(&c, &d);
89db354bd2SLeyi Rong if (a > c) {
90db354bd2SLeyi Rong if (d > e)
91db354bd2SLeyi Rong swap(&c, &e);
92db354bd2SLeyi Rong else {
93db354bd2SLeyi Rong swap(&c, &d);
94db354bd2SLeyi Rong swap(&d, &e);
95db354bd2SLeyi Rong }
96db354bd2SLeyi Rong } else {
97db354bd2SLeyi Rong if (b > e)
98db354bd2SLeyi Rong swap(&a, &e);
99db354bd2SLeyi Rong else {
100db354bd2SLeyi Rong swap(&a, &b);
101db354bd2SLeyi Rong swap(&b, &e);
102db354bd2SLeyi Rong }
103db354bd2SLeyi Rong }
104db354bd2SLeyi Rong
105db354bd2SLeyi Rong if (a > c)
106db354bd2SLeyi Rong return a > d ? d : a;
107db354bd2SLeyi Rong else
108db354bd2SLeyi Rong return b > c ? c : b;
109db354bd2SLeyi Rong }
110db354bd2SLeyi Rong
111db354bd2SLeyi Rong int
rte_member_create_sketch(struct rte_member_setsum * ss,const struct rte_member_parameters * params,struct rte_ring * ring)112db354bd2SLeyi Rong rte_member_create_sketch(struct rte_member_setsum *ss,
113db354bd2SLeyi Rong const struct rte_member_parameters *params,
114db354bd2SLeyi Rong struct rte_ring *ring)
115db354bd2SLeyi Rong {
116db354bd2SLeyi Rong struct sketch_runtime *runtime;
117db354bd2SLeyi Rong uint32_t num_col;
118db354bd2SLeyi Rong uint32_t i;
119db354bd2SLeyi Rong
120db354bd2SLeyi Rong if (params->sample_rate == 0 || params->sample_rate > 1) {
121db354bd2SLeyi Rong rte_errno = EINVAL;
1220e21c7c0SDavid Marchand MEMBER_LOG(ERR,
1230e21c7c0SDavid Marchand "Membership Sketch created with invalid parameters");
124db354bd2SLeyi Rong return -EINVAL;
125db354bd2SLeyi Rong }
126db354bd2SLeyi Rong
127db354bd2SLeyi Rong if (params->extra_flag & RTE_MEMBER_SKETCH_COUNT_BYTE)
128db354bd2SLeyi Rong ss->count_byte = 1;
129db354bd2SLeyi Rong
130db354bd2SLeyi Rong #ifdef RTE_ARCH_X86
131db354bd2SLeyi Rong if (ss->count_byte == 1 &&
132db354bd2SLeyi Rong rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_512 &&
133db354bd2SLeyi Rong rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) == 1 &&
134db354bd2SLeyi Rong rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512IFMA) == 1) {
135db354bd2SLeyi Rong #ifdef CC_AVX512_SUPPORT
136db354bd2SLeyi Rong ss->use_avx512 = true;
137db354bd2SLeyi Rong #else
138db354bd2SLeyi Rong ss->use_avx512 = false;
139db354bd2SLeyi Rong #endif
140db354bd2SLeyi Rong }
141db354bd2SLeyi Rong
142db354bd2SLeyi Rong if (ss->use_avx512 == true) {
143db354bd2SLeyi Rong #ifdef CC_AVX512_SUPPORT
144db354bd2SLeyi Rong ss->num_row = NUM_ROW_VEC;
1450e21c7c0SDavid Marchand MEMBER_LOG(NOTICE,
1460e21c7c0SDavid Marchand "Membership Sketch AVX512 update/lookup/delete ops is selected");
147db354bd2SLeyi Rong ss->sketch_update = sketch_update_avx512;
148db354bd2SLeyi Rong ss->sketch_lookup = sketch_lookup_avx512;
149db354bd2SLeyi Rong ss->sketch_delete = sketch_delete_avx512;
150db354bd2SLeyi Rong #endif
151db354bd2SLeyi Rong } else
152db354bd2SLeyi Rong #endif
153db354bd2SLeyi Rong {
154db354bd2SLeyi Rong ss->num_row = NUM_ROW_SCALAR;
1550e21c7c0SDavid Marchand MEMBER_LOG(NOTICE,
1560e21c7c0SDavid Marchand "Membership Sketch SCALAR update/lookup/delete ops is selected");
157db354bd2SLeyi Rong ss->sketch_update = sketch_update_scalar;
158db354bd2SLeyi Rong ss->sketch_lookup = sketch_lookup_scalar;
159db354bd2SLeyi Rong ss->sketch_delete = sketch_delete_scalar;
160db354bd2SLeyi Rong }
161db354bd2SLeyi Rong
162db354bd2SLeyi Rong ss->socket_id = params->socket_id;
163db354bd2SLeyi Rong
164db354bd2SLeyi Rong if (ss->count_byte == 0)
165db354bd2SLeyi Rong num_col = 4.0 / params->error_rate / params->sample_rate;
166db354bd2SLeyi Rong #ifdef RTE_ARCH_X86
167db354bd2SLeyi Rong else if (ss->use_avx512 == true)
168db354bd2SLeyi Rong num_col = rte_align32pow2(4.0 / params->error_rate);
169db354bd2SLeyi Rong #endif
170db354bd2SLeyi Rong else
171db354bd2SLeyi Rong num_col = 4.0 / params->error_rate;
172db354bd2SLeyi Rong
173db354bd2SLeyi Rong ss->table = rte_zmalloc_socket(NULL,
174db354bd2SLeyi Rong sizeof(uint64_t) * num_col * ss->num_row,
175db354bd2SLeyi Rong RTE_CACHE_LINE_SIZE, ss->socket_id);
176db354bd2SLeyi Rong if (ss->table == NULL) {
1770e21c7c0SDavid Marchand MEMBER_LOG(ERR, "Sketch Table memory allocation failed");
178db354bd2SLeyi Rong return -ENOMEM;
179db354bd2SLeyi Rong }
180db354bd2SLeyi Rong
181db354bd2SLeyi Rong ss->hash_seeds = rte_zmalloc_socket(NULL, sizeof(uint64_t) * ss->num_row,
182db354bd2SLeyi Rong RTE_CACHE_LINE_SIZE, ss->socket_id);
183db354bd2SLeyi Rong if (ss->hash_seeds == NULL) {
1840e21c7c0SDavid Marchand MEMBER_LOG(ERR, "Sketch Hashseeds memory allocation failed");
185db354bd2SLeyi Rong return -ENOMEM;
186db354bd2SLeyi Rong }
187db354bd2SLeyi Rong
188db354bd2SLeyi Rong ss->runtime_var = rte_zmalloc_socket(NULL, sizeof(struct sketch_runtime),
189db354bd2SLeyi Rong RTE_CACHE_LINE_SIZE, ss->socket_id);
190db354bd2SLeyi Rong if (ss->runtime_var == NULL) {
1910e21c7c0SDavid Marchand MEMBER_LOG(ERR, "Sketch Runtime memory allocation failed");
192db354bd2SLeyi Rong rte_free(ss);
193db354bd2SLeyi Rong return -ENOMEM;
194db354bd2SLeyi Rong }
195db354bd2SLeyi Rong runtime = ss->runtime_var;
196db354bd2SLeyi Rong
197db354bd2SLeyi Rong ss->num_col = num_col;
198db354bd2SLeyi Rong ss->sample_rate = params->sample_rate;
199db354bd2SLeyi Rong ss->prim_hash_seed = params->prim_hash_seed;
200db354bd2SLeyi Rong ss->sec_hash_seed = params->sec_hash_seed;
201db354bd2SLeyi Rong ss->error_rate = params->error_rate;
202db354bd2SLeyi Rong ss->topk = params->top_k;
203db354bd2SLeyi Rong ss->key_len = params->key_len;
204db354bd2SLeyi Rong runtime->heap.key_len = ss->key_len;
205db354bd2SLeyi Rong
206db354bd2SLeyi Rong runtime->key_slots = rte_zmalloc_socket(NULL, ss->key_len * ss->topk,
207db354bd2SLeyi Rong RTE_CACHE_LINE_SIZE, ss->socket_id);
208db354bd2SLeyi Rong if (runtime->key_slots == NULL) {
2090e21c7c0SDavid Marchand MEMBER_LOG(ERR, "Sketch Key Slots allocation failed");
210db354bd2SLeyi Rong goto error;
211db354bd2SLeyi Rong }
212db354bd2SLeyi Rong
213db354bd2SLeyi Rong runtime->free_key_slots = ring;
214db354bd2SLeyi Rong for (i = 0; i < ss->topk; i++)
215db354bd2SLeyi Rong rte_ring_sp_enqueue_elem(runtime->free_key_slots,
216db354bd2SLeyi Rong &i, sizeof(uint32_t));
217db354bd2SLeyi Rong
218db354bd2SLeyi Rong if (rte_member_minheap_init(&(runtime->heap), params->top_k,
219db354bd2SLeyi Rong ss->socket_id, params->prim_hash_seed) < 0) {
2200e21c7c0SDavid Marchand MEMBER_LOG(ERR, "Sketch Minheap allocation failed");
221db354bd2SLeyi Rong goto error_runtime;
222db354bd2SLeyi Rong }
223db354bd2SLeyi Rong
224db354bd2SLeyi Rong runtime->report_array = rte_zmalloc_socket(NULL, sizeof(struct node) * ss->topk,
225db354bd2SLeyi Rong RTE_CACHE_LINE_SIZE, ss->socket_id);
226db354bd2SLeyi Rong if (runtime->report_array == NULL) {
2270e21c7c0SDavid Marchand MEMBER_LOG(ERR, "Sketch Runtime Report Array allocation failed");
228db354bd2SLeyi Rong goto error_runtime;
229db354bd2SLeyi Rong }
230db354bd2SLeyi Rong
231db354bd2SLeyi Rong for (i = 0; i < ss->num_row; i++)
232db354bd2SLeyi Rong ss->hash_seeds[i] = rte_rand();
233db354bd2SLeyi Rong
234db354bd2SLeyi Rong if (params->extra_flag & RTE_MEMBER_SKETCH_ALWAYS_BOUNDED)
235db354bd2SLeyi Rong ss->always_bounded = 1;
236db354bd2SLeyi Rong
237db354bd2SLeyi Rong if (ss->always_bounded) {
238db354bd2SLeyi Rong double delta = 1.0 / (pow(2, ss->num_row));
239db354bd2SLeyi Rong
240db354bd2SLeyi Rong ss->converge_thresh = 10 * pow(ss->error_rate, -2.0) * sqrt(log(1 / delta));
241db354bd2SLeyi Rong }
242db354bd2SLeyi Rong
2430e21c7c0SDavid Marchand MEMBER_LOG(DEBUG, "Sketch created, "
2440e21c7c0SDavid Marchand "the total memory required is %u Bytes", ss->num_col * ss->num_row * 8);
245db354bd2SLeyi Rong
246db354bd2SLeyi Rong return 0;
247db354bd2SLeyi Rong
248db354bd2SLeyi Rong error_runtime:
249db354bd2SLeyi Rong rte_member_minheap_free(&runtime->heap);
250db354bd2SLeyi Rong rte_ring_free(runtime->free_key_slots);
251db354bd2SLeyi Rong rte_free(runtime->key_slots);
252db354bd2SLeyi Rong error:
253db354bd2SLeyi Rong rte_free(runtime);
254db354bd2SLeyi Rong rte_free(ss);
255db354bd2SLeyi Rong
256db354bd2SLeyi Rong return -ENOMEM;
257db354bd2SLeyi Rong }
258db354bd2SLeyi Rong
259db354bd2SLeyi Rong uint64_t
sketch_lookup_scalar(const struct rte_member_setsum * ss,const void * key)260db354bd2SLeyi Rong sketch_lookup_scalar(const struct rte_member_setsum *ss, const void *key)
261db354bd2SLeyi Rong {
262db354bd2SLeyi Rong uint64_t *count_array = ss->table;
263db354bd2SLeyi Rong uint32_t col[ss->num_row];
264db354bd2SLeyi Rong uint64_t count_row[ss->num_row];
265db354bd2SLeyi Rong uint32_t cur_row;
266db354bd2SLeyi Rong uint64_t count;
267db354bd2SLeyi Rong
268db354bd2SLeyi Rong for (cur_row = 0; cur_row < ss->num_row; cur_row++) {
269db354bd2SLeyi Rong col[cur_row] = MEMBER_HASH_FUNC(key, ss->key_len,
270db354bd2SLeyi Rong ss->hash_seeds[cur_row]) % ss->num_col;
271db354bd2SLeyi Rong
272db354bd2SLeyi Rong rte_prefetch0(&count_array[cur_row * ss->num_col + col[cur_row]]);
273db354bd2SLeyi Rong }
274db354bd2SLeyi Rong
275db354bd2SLeyi Rong /* if sample rate is 1, it is a regular count-min, we report the min */
276db354bd2SLeyi Rong if (ss->sample_rate == 1 || ss->count_byte == 1)
277db354bd2SLeyi Rong return count_min(ss, col);
278db354bd2SLeyi Rong
279db354bd2SLeyi Rong memset(count_row, 0, sizeof(uint64_t) * ss->num_row);
280db354bd2SLeyi Rong
281db354bd2SLeyi Rong /* otherwise we report the median number */
282db354bd2SLeyi Rong for (cur_row = 0; cur_row < ss->num_row; cur_row++)
283db354bd2SLeyi Rong count_row[cur_row] = count_array[cur_row * ss->num_col + col[cur_row]];
284db354bd2SLeyi Rong
285db354bd2SLeyi Rong if (ss->num_row == 5)
286db354bd2SLeyi Rong return medianof5(count_row[0], count_row[1],
287db354bd2SLeyi Rong count_row[2], count_row[3], count_row[4]);
288db354bd2SLeyi Rong
289db354bd2SLeyi Rong isort(count_row, ss->num_row);
290db354bd2SLeyi Rong
291db354bd2SLeyi Rong if (ss->num_row % 2 == 0) {
292db354bd2SLeyi Rong count = (count_row[ss->num_row / 2] + count_row[ss->num_row / 2 - 1]) / 2;
293db354bd2SLeyi Rong return count;
294db354bd2SLeyi Rong }
295db354bd2SLeyi Rong /* ss->num_row % 2 != 0 */
296db354bd2SLeyi Rong count = count_row[ss->num_row / 2];
297db354bd2SLeyi Rong
298db354bd2SLeyi Rong return count;
299db354bd2SLeyi Rong }
300db354bd2SLeyi Rong
301db354bd2SLeyi Rong void
sketch_delete_scalar(const struct rte_member_setsum * ss,const void * key)302db354bd2SLeyi Rong sketch_delete_scalar(const struct rte_member_setsum *ss, const void *key)
303db354bd2SLeyi Rong {
304db354bd2SLeyi Rong uint32_t col[ss->num_row];
305db354bd2SLeyi Rong uint64_t *count_array = ss->table;
306db354bd2SLeyi Rong uint32_t cur_row;
307db354bd2SLeyi Rong
308db354bd2SLeyi Rong for (cur_row = 0; cur_row < ss->num_row; cur_row++) {
309db354bd2SLeyi Rong col[cur_row] = MEMBER_HASH_FUNC(key, ss->key_len,
310db354bd2SLeyi Rong ss->hash_seeds[cur_row]) % ss->num_col;
311db354bd2SLeyi Rong
312db354bd2SLeyi Rong /* set corresponding counter to 0 */
313db354bd2SLeyi Rong count_array[cur_row * ss->num_col + col[cur_row]] = 0;
314db354bd2SLeyi Rong }
315db354bd2SLeyi Rong }
316db354bd2SLeyi Rong
317db354bd2SLeyi Rong int
rte_member_query_sketch(const struct rte_member_setsum * ss,const void * key,uint64_t * output)318db354bd2SLeyi Rong rte_member_query_sketch(const struct rte_member_setsum *ss,
319db354bd2SLeyi Rong const void *key,
320db354bd2SLeyi Rong uint64_t *output)
321db354bd2SLeyi Rong {
322db354bd2SLeyi Rong uint64_t count = ss->sketch_lookup(ss, key);
323db354bd2SLeyi Rong *output = count;
324db354bd2SLeyi Rong
325db354bd2SLeyi Rong return 0;
326db354bd2SLeyi Rong }
327db354bd2SLeyi Rong
328db354bd2SLeyi Rong void
rte_member_update_heap(const struct rte_member_setsum * ss)329db354bd2SLeyi Rong rte_member_update_heap(const struct rte_member_setsum *ss)
330db354bd2SLeyi Rong {
331db354bd2SLeyi Rong uint32_t i;
332db354bd2SLeyi Rong struct sketch_runtime *runtime_var = ss->runtime_var;
333db354bd2SLeyi Rong
334db354bd2SLeyi Rong for (i = 0; i < runtime_var->heap.size; i++) {
335db354bd2SLeyi Rong uint64_t count = ss->sketch_lookup(ss, runtime_var->heap.elem[i].key);
336db354bd2SLeyi Rong
337db354bd2SLeyi Rong runtime_var->heap.elem[i].count = count;
338db354bd2SLeyi Rong }
339db354bd2SLeyi Rong }
340db354bd2SLeyi Rong
341db354bd2SLeyi Rong int
rte_member_report_heavyhitter_sketch(const struct rte_member_setsum * setsum,void ** key,uint64_t * count)342db354bd2SLeyi Rong rte_member_report_heavyhitter_sketch(const struct rte_member_setsum *setsum,
343db354bd2SLeyi Rong void **key,
344db354bd2SLeyi Rong uint64_t *count)
345db354bd2SLeyi Rong {
346db354bd2SLeyi Rong uint32_t i;
347db354bd2SLeyi Rong struct sketch_runtime *runtime_var = setsum->runtime_var;
348db354bd2SLeyi Rong
349db354bd2SLeyi Rong rte_member_update_heap(setsum);
350db354bd2SLeyi Rong rte_member_heapsort(&(runtime_var->heap), runtime_var->report_array);
351db354bd2SLeyi Rong
352db354bd2SLeyi Rong for (i = 0; i < runtime_var->heap.size; i++) {
353db354bd2SLeyi Rong key[i] = runtime_var->report_array[i].key;
354db354bd2SLeyi Rong count[i] = runtime_var->report_array[i].count;
355db354bd2SLeyi Rong }
356db354bd2SLeyi Rong
357db354bd2SLeyi Rong return runtime_var->heap.size;
358db354bd2SLeyi Rong }
359db354bd2SLeyi Rong
360db354bd2SLeyi Rong int
rte_member_lookup_sketch(const struct rte_member_setsum * ss,const void * key,member_set_t * set_id)361db354bd2SLeyi Rong rte_member_lookup_sketch(const struct rte_member_setsum *ss,
362db354bd2SLeyi Rong const void *key, member_set_t *set_id)
363db354bd2SLeyi Rong {
364db354bd2SLeyi Rong uint64_t count = ss->sketch_lookup(ss, key);
365db354bd2SLeyi Rong struct sketch_runtime *runtime_var = ss->runtime_var;
366db354bd2SLeyi Rong
367db354bd2SLeyi Rong if (runtime_var->heap.size > 0 && count >= runtime_var->heap.elem[0].count)
368db354bd2SLeyi Rong *set_id = 1;
369db354bd2SLeyi Rong else
370db354bd2SLeyi Rong *set_id = 0;
371db354bd2SLeyi Rong
372db354bd2SLeyi Rong if (count == 0)
373db354bd2SLeyi Rong return 0;
374db354bd2SLeyi Rong else
375db354bd2SLeyi Rong return 1;
376db354bd2SLeyi Rong }
377db354bd2SLeyi Rong
378db354bd2SLeyi Rong static void
should_converge(const struct rte_member_setsum * ss)379db354bd2SLeyi Rong should_converge(const struct rte_member_setsum *ss)
380db354bd2SLeyi Rong {
381db354bd2SLeyi Rong struct sketch_runtime *runtime_var = ss->runtime_var;
382db354bd2SLeyi Rong
383db354bd2SLeyi Rong /* For count min sketch - L1 norm */
384db354bd2SLeyi Rong if (runtime_var->pkt_cnt > ss->converge_thresh) {
385db354bd2SLeyi Rong runtime_var->converged = 1;
3860e21c7c0SDavid Marchand MEMBER_LOG(DEBUG, "Sketch converged, begin sampling "
3870e21c7c0SDavid Marchand "from key count %"PRIu64,
388db354bd2SLeyi Rong runtime_var->pkt_cnt);
389db354bd2SLeyi Rong }
390db354bd2SLeyi Rong }
391db354bd2SLeyi Rong
392db354bd2SLeyi Rong static void
sketch_update_row(const struct rte_member_setsum * ss,const void * key,uint32_t count,uint32_t cur_row)393db354bd2SLeyi Rong sketch_update_row(const struct rte_member_setsum *ss, const void *key,
394db354bd2SLeyi Rong uint32_t count, uint32_t cur_row)
395db354bd2SLeyi Rong {
396db354bd2SLeyi Rong uint64_t *count_array = ss->table;
397db354bd2SLeyi Rong uint32_t col = MEMBER_HASH_FUNC(key, ss->key_len,
398db354bd2SLeyi Rong ss->hash_seeds[cur_row]) % ss->num_col;
399db354bd2SLeyi Rong
400db354bd2SLeyi Rong /* sketch counter update */
401db354bd2SLeyi Rong count_array[cur_row * ss->num_col + col] +=
402db354bd2SLeyi Rong ceil(count / (ss->sample_rate));
403db354bd2SLeyi Rong }
404db354bd2SLeyi Rong
405db354bd2SLeyi Rong void
sketch_update_scalar(const struct rte_member_setsum * ss,const void * key,uint32_t count)406db354bd2SLeyi Rong sketch_update_scalar(const struct rte_member_setsum *ss,
407db354bd2SLeyi Rong const void *key,
408db354bd2SLeyi Rong uint32_t count)
409db354bd2SLeyi Rong {
410db354bd2SLeyi Rong uint64_t *count_array = ss->table;
411db354bd2SLeyi Rong uint32_t col;
412db354bd2SLeyi Rong uint32_t cur_row;
413db354bd2SLeyi Rong
414db354bd2SLeyi Rong for (cur_row = 0; cur_row < ss->num_row; cur_row++) {
415db354bd2SLeyi Rong col = MEMBER_HASH_FUNC(key, ss->key_len,
416db354bd2SLeyi Rong ss->hash_seeds[cur_row]) % ss->num_col;
417db354bd2SLeyi Rong count_array[cur_row * ss->num_col + col] += count;
418db354bd2SLeyi Rong }
419db354bd2SLeyi Rong }
420db354bd2SLeyi Rong
421db354bd2SLeyi Rong static void
heap_update(const struct rte_member_setsum * ss,const void * key)422db354bd2SLeyi Rong heap_update(const struct rte_member_setsum *ss, const void *key)
423db354bd2SLeyi Rong {
424db354bd2SLeyi Rong struct sketch_runtime *runtime_var = ss->runtime_var;
425db354bd2SLeyi Rong uint64_t key_cnt = 0;
426db354bd2SLeyi Rong int found;
427db354bd2SLeyi Rong
428db354bd2SLeyi Rong /* We also update the heap for this key */
429db354bd2SLeyi Rong key_cnt = ss->sketch_lookup(ss, key);
430db354bd2SLeyi Rong if (key_cnt > runtime_var->heap.elem[0].count) {
431db354bd2SLeyi Rong found = rte_member_minheap_find(&runtime_var->heap, key);
432db354bd2SLeyi Rong /* the key is found in the top-k heap */
433db354bd2SLeyi Rong if (found >= 0) {
434db354bd2SLeyi Rong if (runtime_var->heap.elem[found].count < key_cnt)
435db354bd2SLeyi Rong rte_member_heapify(&runtime_var->heap, found, true);
436db354bd2SLeyi Rong
437db354bd2SLeyi Rong runtime_var->heap.elem[found].count = key_cnt;
438db354bd2SLeyi Rong } else if (runtime_var->heap.size < ss->topk) {
439db354bd2SLeyi Rong rte_member_minheap_insert_node(&runtime_var->heap, key,
440db354bd2SLeyi Rong key_cnt, runtime_var->key_slots, runtime_var->free_key_slots);
441db354bd2SLeyi Rong } else {
442db354bd2SLeyi Rong rte_member_minheap_replace_node(&runtime_var->heap, key, key_cnt);
443db354bd2SLeyi Rong }
444db354bd2SLeyi Rong } else if (runtime_var->heap.size < ss->topk) {
445db354bd2SLeyi Rong found = rte_member_minheap_find(&runtime_var->heap, key);
446db354bd2SLeyi Rong if (found >= 0) {
447db354bd2SLeyi Rong if (runtime_var->heap.elem[found].count < key_cnt)
448db354bd2SLeyi Rong rte_member_heapify(&runtime_var->heap, found, true);
449db354bd2SLeyi Rong
450db354bd2SLeyi Rong runtime_var->heap.elem[found].count = key_cnt;
451db354bd2SLeyi Rong } else
452db354bd2SLeyi Rong rte_member_minheap_insert_node(&runtime_var->heap, key,
453db354bd2SLeyi Rong key_cnt, runtime_var->key_slots, runtime_var->free_key_slots);
454db354bd2SLeyi Rong }
455db354bd2SLeyi Rong }
456db354bd2SLeyi Rong
457db354bd2SLeyi Rong /*
458db354bd2SLeyi Rong * Add a single packet into the sketch.
459db354bd2SLeyi Rong * Sketch value is meatured by packet numbers in this mode.
460db354bd2SLeyi Rong */
461db354bd2SLeyi Rong int
rte_member_add_sketch(const struct rte_member_setsum * ss,const void * key,__rte_unused member_set_t set_id)462db354bd2SLeyi Rong rte_member_add_sketch(const struct rte_member_setsum *ss,
463db354bd2SLeyi Rong const void *key,
464db354bd2SLeyi Rong __rte_unused member_set_t set_id)
465db354bd2SLeyi Rong {
466db354bd2SLeyi Rong uint32_t cur_row;
467db354bd2SLeyi Rong struct sketch_runtime *runtime_var = ss->runtime_var;
468db354bd2SLeyi Rong uint32_t *until_next = &(runtime_var->until_next);
469db354bd2SLeyi Rong
470db354bd2SLeyi Rong /*
471db354bd2SLeyi Rong * If sketch is measured by byte count,
472db354bd2SLeyi Rong * the rte_member_add_sketch_byte_count routine should be used.
473db354bd2SLeyi Rong */
474db354bd2SLeyi Rong if (ss->count_byte == 1) {
4750e21c7c0SDavid Marchand MEMBER_LOG(ERR, "Sketch is Byte Mode, "
4760e21c7c0SDavid Marchand "should use rte_member_add_byte_count()!");
477db354bd2SLeyi Rong return -EINVAL;
478db354bd2SLeyi Rong }
479db354bd2SLeyi Rong
480db354bd2SLeyi Rong if (ss->sample_rate == 1) {
481db354bd2SLeyi Rong ss->sketch_update(ss, key, 1);
482db354bd2SLeyi Rong heap_update(ss, key);
483db354bd2SLeyi Rong return 0;
484db354bd2SLeyi Rong }
485db354bd2SLeyi Rong
486db354bd2SLeyi Rong /* convergence stage if it's needed */
487db354bd2SLeyi Rong if (ss->always_bounded && !runtime_var->converged) {
488db354bd2SLeyi Rong ss->sketch_update(ss, key, 1);
489db354bd2SLeyi Rong
490db354bd2SLeyi Rong if (!((++runtime_var->pkt_cnt) & (INTERVAL - 1)))
491db354bd2SLeyi Rong should_converge(ss);
492db354bd2SLeyi Rong
493db354bd2SLeyi Rong heap_update(ss, key);
494db354bd2SLeyi Rong return 0;
495db354bd2SLeyi Rong }
496db354bd2SLeyi Rong
497db354bd2SLeyi Rong /* should we skip this packet */
498db354bd2SLeyi Rong if (*until_next >= ss->num_row) {
499db354bd2SLeyi Rong *until_next -= ss->num_row;
500db354bd2SLeyi Rong return 0;
501db354bd2SLeyi Rong }
502db354bd2SLeyi Rong cur_row = *until_next;
503db354bd2SLeyi Rong do {
504db354bd2SLeyi Rong sketch_update_row(ss, key, 1, cur_row);
505db354bd2SLeyi Rong *until_next = draw_geometric(ss);
506db354bd2SLeyi Rong if (cur_row + *until_next >= ss->num_row)
507db354bd2SLeyi Rong break;
508db354bd2SLeyi Rong cur_row += *until_next;
509db354bd2SLeyi Rong } while (1);
510db354bd2SLeyi Rong
511db354bd2SLeyi Rong *until_next -= (ss->num_row - cur_row);
512db354bd2SLeyi Rong
513db354bd2SLeyi Rong heap_update(ss, key);
514db354bd2SLeyi Rong
515db354bd2SLeyi Rong return 0;
516db354bd2SLeyi Rong }
517db354bd2SLeyi Rong
518db354bd2SLeyi Rong /*
519db354bd2SLeyi Rong * Add the byte count of the packet into the sketch.
520db354bd2SLeyi Rong * Sketch value is meatured by byte count numbers in this mode.
521db354bd2SLeyi Rong */
522db354bd2SLeyi Rong int
rte_member_add_sketch_byte_count(const struct rte_member_setsum * ss,const void * key,uint32_t byte_count)523db354bd2SLeyi Rong rte_member_add_sketch_byte_count(const struct rte_member_setsum *ss,
524db354bd2SLeyi Rong const void *key,
525db354bd2SLeyi Rong uint32_t byte_count)
526db354bd2SLeyi Rong {
527db354bd2SLeyi Rong struct sketch_runtime *runtime_var = ss->runtime_var;
528db354bd2SLeyi Rong uint32_t *until_next = &(runtime_var->until_next);
529db354bd2SLeyi Rong
530db354bd2SLeyi Rong /* should not call this API if not in count byte mode */
531db354bd2SLeyi Rong if (ss->count_byte == 0) {
5320e21c7c0SDavid Marchand MEMBER_LOG(ERR, "Sketch is Pkt Mode, "
5330e21c7c0SDavid Marchand "should use rte_member_add()!");
534db354bd2SLeyi Rong return -EINVAL;
535db354bd2SLeyi Rong }
536db354bd2SLeyi Rong
537db354bd2SLeyi Rong /* there's specific optimization for the sketch update */
538db354bd2SLeyi Rong ss->sketch_update(ss, key, byte_count);
539db354bd2SLeyi Rong
540db354bd2SLeyi Rong if (*until_next != 0) {
541db354bd2SLeyi Rong *until_next = *until_next - 1;
542db354bd2SLeyi Rong return 0;
543db354bd2SLeyi Rong }
544db354bd2SLeyi Rong
545db354bd2SLeyi Rong *until_next = draw_geometric(ss) - 1;
546db354bd2SLeyi Rong
547db354bd2SLeyi Rong heap_update(ss, key);
548db354bd2SLeyi Rong
549db354bd2SLeyi Rong return 0;
550db354bd2SLeyi Rong }
551db354bd2SLeyi Rong
552db354bd2SLeyi Rong int
rte_member_delete_sketch(const struct rte_member_setsum * ss,const void * key)553db354bd2SLeyi Rong rte_member_delete_sketch(const struct rte_member_setsum *ss,
554db354bd2SLeyi Rong const void *key)
555db354bd2SLeyi Rong {
556db354bd2SLeyi Rong struct sketch_runtime *runtime_var = ss->runtime_var;
557db354bd2SLeyi Rong int found;
558db354bd2SLeyi Rong
559db354bd2SLeyi Rong found = rte_member_minheap_find(&runtime_var->heap, key);
560db354bd2SLeyi Rong if (found < 0)
561db354bd2SLeyi Rong return -1;
562db354bd2SLeyi Rong
563db354bd2SLeyi Rong ss->sketch_delete(ss, key);
564db354bd2SLeyi Rong
565db354bd2SLeyi Rong return rte_member_minheap_delete_node
566db354bd2SLeyi Rong (&runtime_var->heap, key, runtime_var->key_slots, runtime_var->free_key_slots);
567db354bd2SLeyi Rong }
568db354bd2SLeyi Rong
569db354bd2SLeyi Rong void
rte_member_free_sketch(struct rte_member_setsum * ss)570db354bd2SLeyi Rong rte_member_free_sketch(struct rte_member_setsum *ss)
571db354bd2SLeyi Rong {
572db354bd2SLeyi Rong struct sketch_runtime *runtime_var = ss->runtime_var;
573db354bd2SLeyi Rong
574db354bd2SLeyi Rong rte_free(ss->table);
575db354bd2SLeyi Rong rte_member_minheap_free(&runtime_var->heap);
576db354bd2SLeyi Rong rte_free(runtime_var->key_slots);
577db354bd2SLeyi Rong rte_ring_free(runtime_var->free_key_slots);
578db354bd2SLeyi Rong rte_free(runtime_var);
579db354bd2SLeyi Rong }
580db354bd2SLeyi Rong
581db354bd2SLeyi Rong void
rte_member_reset_sketch(const struct rte_member_setsum * ss)582db354bd2SLeyi Rong rte_member_reset_sketch(const struct rte_member_setsum *ss)
583db354bd2SLeyi Rong {
584db354bd2SLeyi Rong struct sketch_runtime *runtime_var = ss->runtime_var;
585db354bd2SLeyi Rong uint64_t *sketch = ss->table;
586db354bd2SLeyi Rong uint32_t i;
587db354bd2SLeyi Rong
588db354bd2SLeyi Rong memset(sketch, 0, sizeof(uint64_t) * ss->num_col * ss->num_row);
589db354bd2SLeyi Rong rte_member_minheap_reset(&runtime_var->heap);
590db354bd2SLeyi Rong rte_ring_reset(runtime_var->free_key_slots);
591db354bd2SLeyi Rong
592db354bd2SLeyi Rong for (i = 0; i < ss->topk; i++)
593db354bd2SLeyi Rong rte_ring_sp_enqueue_elem(runtime_var->free_key_slots, &i, sizeof(uint32_t));
594db354bd2SLeyi Rong }
595