New upstream version 18.11-rc1
[deb_dpdk.git] / lib / librte_eal / common / include / rte_bitmap.h
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #ifndef __INCLUDE_RTE_BITMAP_H__
6 #define __INCLUDE_RTE_BITMAP_H__
7
8 #ifdef __cplusplus
9 extern "C" {
10 #endif
11
12 /**
13  * @file
14  * RTE Bitmap
15  *
16  * The bitmap component provides a mechanism to manage large arrays of bits
17  * through bit get/set/clear and bit array scan operations.
18  *
19  * The bitmap scan operation is optimized for 64-bit CPUs using 64/128 byte cache
20  * lines. The bitmap is hierarchically organized using two arrays (array1 and
21  * array2), with each bit in array1 being associated with a full cache line
22  * (512/1024 bits) of bitmap bits, which are stored in array2: the bit in array1
23  * is set only when there is at least one bit set within its associated array2
24  * bits, otherwise the bit in array1 is cleared. The read and write operations
25  * for array1 and array2 are always done in slabs of 64 bits.
26  *
27  * This bitmap is not thread safe. For lock free operation on a specific bitmap
28  * instance, a single writer thread performing bit set/clear operations is
29  * allowed, only the writer thread can do bitmap scan operations, while there
30  * can be several reader threads performing bit get operations in parallel with
31  * the writer thread. When the use of locking primitives is acceptable, the
32  * serialization of the bit set/clear and bitmap scan operations needs to be
33  * enforced by the caller, while the bit get operation does not require locking
34  * the bitmap.
35  *
36  ***/
37
38 #include <string.h>
39 #include <rte_common.h>
40 #include <rte_config.h>
41 #include <rte_debug.h>
42 #include <rte_memory.h>
43 #include <rte_branch_prediction.h>
44 #include <rte_prefetch.h>
45
46 #ifndef RTE_BITMAP_OPTIMIZATIONS
47 #define RTE_BITMAP_OPTIMIZATIONS                         1
48 #endif
49
50 /* Slab */
51 #define RTE_BITMAP_SLAB_BIT_SIZE                 64
52 #define RTE_BITMAP_SLAB_BIT_SIZE_LOG2            6
53 #define RTE_BITMAP_SLAB_BIT_MASK                 (RTE_BITMAP_SLAB_BIT_SIZE - 1)
54
55 /* Cache line (CL) */
56 #define RTE_BITMAP_CL_BIT_SIZE                   (RTE_CACHE_LINE_SIZE * 8)
57 #define RTE_BITMAP_CL_BIT_SIZE_LOG2              (RTE_CACHE_LINE_SIZE_LOG2 + 3)
58 #define RTE_BITMAP_CL_BIT_MASK                   (RTE_BITMAP_CL_BIT_SIZE - 1)
59
60 #define RTE_BITMAP_CL_SLAB_SIZE                  (RTE_BITMAP_CL_BIT_SIZE / RTE_BITMAP_SLAB_BIT_SIZE)
61 #define RTE_BITMAP_CL_SLAB_SIZE_LOG2             (RTE_BITMAP_CL_BIT_SIZE_LOG2 - RTE_BITMAP_SLAB_BIT_SIZE_LOG2)
62 #define RTE_BITMAP_CL_SLAB_MASK                  (RTE_BITMAP_CL_SLAB_SIZE - 1)
63
64 /** Bitmap data structure */
65 struct rte_bitmap {
66         /* Context for array1 and array2 */
67         uint64_t *array1;                        /**< Bitmap array1 */
68         uint64_t *array2;                        /**< Bitmap array2 */
69         uint32_t array1_size;                    /**< Number of 64-bit slabs in array1 that are actually used */
70         uint32_t array2_size;                    /**< Number of 64-bit slabs in array2 */
71
72         /* Context for the "scan next" operation */
73         uint32_t index1;  /**< Bitmap scan: Index of current array1 slab */
74         uint32_t offset1; /**< Bitmap scan: Offset of current bit within current array1 slab */
75         uint32_t index2;  /**< Bitmap scan: Index of current array2 slab */
76         uint32_t go2;     /**< Bitmap scan: Go/stop condition for current array2 cache line */
77
78         /* Storage space for array1 and array2 */
79         uint8_t memory[];
80 };
81
82 static inline void
83 __rte_bitmap_index1_inc(struct rte_bitmap *bmp)
84 {
85         bmp->index1 = (bmp->index1 + 1) & (bmp->array1_size - 1);
86 }
87
88 static inline uint64_t
89 __rte_bitmap_mask1_get(struct rte_bitmap *bmp)
90 {
91         return (~1llu) << bmp->offset1;
92 }
93
94 static inline void
95 __rte_bitmap_index2_set(struct rte_bitmap *bmp)
96 {
97         bmp->index2 = (((bmp->index1 << RTE_BITMAP_SLAB_BIT_SIZE_LOG2) + bmp->offset1) << RTE_BITMAP_CL_SLAB_SIZE_LOG2);
98 }
99
100 #if RTE_BITMAP_OPTIMIZATIONS
101
102 static inline int
103 rte_bsf64(uint64_t slab, uint32_t *pos)
104 {
105         if (likely(slab == 0)) {
106                 return 0;
107         }
108
109         *pos = __builtin_ctzll(slab);
110         return 1;
111 }
112
113 #else
114
115 static inline int
116 rte_bsf64(uint64_t slab, uint32_t *pos)
117 {
118         uint64_t mask;
119         uint32_t i;
120
121         if (likely(slab == 0)) {
122                 return 0;
123         }
124
125         for (i = 0, mask = 1; i < RTE_BITMAP_SLAB_BIT_SIZE; i ++, mask <<= 1) {
126                 if (unlikely(slab & mask)) {
127                         *pos = i;
128                         return 1;
129                 }
130         }
131
132         return 0;
133 }
134
135 #endif
136
137 static inline uint32_t
138 __rte_bitmap_get_memory_footprint(uint32_t n_bits,
139         uint32_t *array1_byte_offset, uint32_t *array1_slabs,
140         uint32_t *array2_byte_offset, uint32_t *array2_slabs)
141 {
142         uint32_t n_slabs_context, n_slabs_array1, n_cache_lines_context_and_array1;
143         uint32_t n_cache_lines_array2;
144         uint32_t n_bytes_total;
145
146         n_cache_lines_array2 = (n_bits + RTE_BITMAP_CL_BIT_SIZE - 1) / RTE_BITMAP_CL_BIT_SIZE;
147         n_slabs_array1 = (n_cache_lines_array2 + RTE_BITMAP_SLAB_BIT_SIZE - 1) / RTE_BITMAP_SLAB_BIT_SIZE;
148         n_slabs_array1 = rte_align32pow2(n_slabs_array1);
149         n_slabs_context = (sizeof(struct rte_bitmap) + (RTE_BITMAP_SLAB_BIT_SIZE / 8) - 1) / (RTE_BITMAP_SLAB_BIT_SIZE / 8);
150         n_cache_lines_context_and_array1 = (n_slabs_context + n_slabs_array1 + RTE_BITMAP_CL_SLAB_SIZE - 1) / RTE_BITMAP_CL_SLAB_SIZE;
151         n_bytes_total = (n_cache_lines_context_and_array1 + n_cache_lines_array2) * RTE_CACHE_LINE_SIZE;
152
153         if (array1_byte_offset) {
154                 *array1_byte_offset = n_slabs_context * (RTE_BITMAP_SLAB_BIT_SIZE / 8);
155         }
156         if (array1_slabs) {
157                 *array1_slabs = n_slabs_array1;
158         }
159         if (array2_byte_offset) {
160                 *array2_byte_offset = n_cache_lines_context_and_array1 * RTE_CACHE_LINE_SIZE;
161         }
162         if (array2_slabs) {
163                 *array2_slabs = n_cache_lines_array2 * RTE_BITMAP_CL_SLAB_SIZE;
164         }
165
166         return n_bytes_total;
167 }
168
169 static inline void
170 __rte_bitmap_scan_init(struct rte_bitmap *bmp)
171 {
172         bmp->index1 = bmp->array1_size - 1;
173         bmp->offset1 = RTE_BITMAP_SLAB_BIT_SIZE - 1;
174         __rte_bitmap_index2_set(bmp);
175         bmp->index2 += RTE_BITMAP_CL_SLAB_SIZE;
176
177         bmp->go2 = 0;
178 }
179
180 /**
181  * Bitmap memory footprint calculation
182  *
183  * @param n_bits
184  *   Number of bits in the bitmap
185  * @return
186  *   Bitmap memory footprint measured in bytes on success, 0 on error
187  */
188 static inline uint32_t
189 rte_bitmap_get_memory_footprint(uint32_t n_bits) {
190         /* Check input arguments */
191         if (n_bits == 0) {
192                 return 0;
193         }
194
195         return __rte_bitmap_get_memory_footprint(n_bits, NULL, NULL, NULL, NULL);
196 }
197
198 /**
199  * Bitmap initialization
200  *
201  * @param n_bits
202  *   Number of pre-allocated bits in array2.
203  * @param mem
204  *   Base address of array1 and array2.
205  * @param mem_size
206  *   Minimum expected size of bitmap.
207  * @return
208  *   Handle to bitmap instance.
209  */
210 static inline struct rte_bitmap *
211 rte_bitmap_init(uint32_t n_bits, uint8_t *mem, uint32_t mem_size)
212 {
213         struct rte_bitmap *bmp;
214         uint32_t array1_byte_offset, array1_slabs, array2_byte_offset, array2_slabs;
215         uint32_t size;
216
217         /* Check input arguments */
218         if (n_bits == 0) {
219                 return NULL;
220         }
221
222         if ((mem == NULL) || (((uintptr_t) mem) & RTE_CACHE_LINE_MASK)) {
223                 return NULL;
224         }
225
226         size = __rte_bitmap_get_memory_footprint(n_bits,
227                 &array1_byte_offset, &array1_slabs,
228                 &array2_byte_offset, &array2_slabs);
229         if (size < mem_size) {
230                 return NULL;
231         }
232
233         /* Setup bitmap */
234         memset(mem, 0, size);
235         bmp = (struct rte_bitmap *) mem;
236
237         bmp->array1 = (uint64_t *) &mem[array1_byte_offset];
238         bmp->array1_size = array1_slabs;
239         bmp->array2 = (uint64_t *) &mem[array2_byte_offset];
240         bmp->array2_size = array2_slabs;
241
242         __rte_bitmap_scan_init(bmp);
243
244         return bmp;
245 }
246
247 /**
248  * Bitmap free
249  *
250  * @param bmp
251  *   Handle to bitmap instance
252  * @return
253  *   0 upon success, error code otherwise
254  */
255 static inline int
256 rte_bitmap_free(struct rte_bitmap *bmp)
257 {
258         /* Check input arguments */
259         if (bmp == NULL) {
260                 return -1;
261         }
262
263         return 0;
264 }
265
266 /**
267  * Bitmap reset
268  *
269  * @param bmp
270  *   Handle to bitmap instance
271  */
272 static inline void
273 rte_bitmap_reset(struct rte_bitmap *bmp)
274 {
275         memset(bmp->array1, 0, bmp->array1_size * sizeof(uint64_t));
276         memset(bmp->array2, 0, bmp->array2_size * sizeof(uint64_t));
277         __rte_bitmap_scan_init(bmp);
278 }
279
280 /**
281  * Bitmap location prefetch into CPU L1 cache
282  *
283  * @param bmp
284  *   Handle to bitmap instance
285  * @param pos
286  *   Bit position
287  * @return
288  *   0 upon success, error code otherwise
289  */
290 static inline void
291 rte_bitmap_prefetch0(struct rte_bitmap *bmp, uint32_t pos)
292 {
293         uint64_t *slab2;
294         uint32_t index2;
295
296         index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
297         slab2 = bmp->array2 + index2;
298         rte_prefetch0((void *) slab2);
299 }
300
301 /**
302  * Bitmap bit get
303  *
304  * @param bmp
305  *   Handle to bitmap instance
306  * @param pos
307  *   Bit position
308  * @return
309  *   0 when bit is cleared, non-zero when bit is set
310  */
311 static inline uint64_t
312 rte_bitmap_get(struct rte_bitmap *bmp, uint32_t pos)
313 {
314         uint64_t *slab2;
315         uint32_t index2, offset2;
316
317         index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
318         offset2 = pos & RTE_BITMAP_SLAB_BIT_MASK;
319         slab2 = bmp->array2 + index2;
320         return (*slab2) & (1llu << offset2);
321 }
322
323 /**
324  * Bitmap bit set
325  *
326  * @param bmp
327  *   Handle to bitmap instance
328  * @param pos
329  *   Bit position
330  */
331 static inline void
332 rte_bitmap_set(struct rte_bitmap *bmp, uint32_t pos)
333 {
334         uint64_t *slab1, *slab2;
335         uint32_t index1, index2, offset1, offset2;
336
337         /* Set bit in array2 slab and set bit in array1 slab */
338         index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
339         offset2 = pos & RTE_BITMAP_SLAB_BIT_MASK;
340         index1 = pos >> (RTE_BITMAP_SLAB_BIT_SIZE_LOG2 + RTE_BITMAP_CL_BIT_SIZE_LOG2);
341         offset1 = (pos >> RTE_BITMAP_CL_BIT_SIZE_LOG2) & RTE_BITMAP_SLAB_BIT_MASK;
342         slab2 = bmp->array2 + index2;
343         slab1 = bmp->array1 + index1;
344
345         *slab2 |= 1llu << offset2;
346         *slab1 |= 1llu << offset1;
347 }
348
349 /**
350  * Bitmap slab set
351  *
352  * @param bmp
353  *   Handle to bitmap instance
354  * @param pos
355  *   Bit position identifying the array2 slab
356  * @param slab
357  *   Value to be assigned to the 64-bit slab in array2
358  */
359 static inline void
360 rte_bitmap_set_slab(struct rte_bitmap *bmp, uint32_t pos, uint64_t slab)
361 {
362         uint64_t *slab1, *slab2;
363         uint32_t index1, index2, offset1;
364
365         /* Set bits in array2 slab and set bit in array1 slab */
366         index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
367         index1 = pos >> (RTE_BITMAP_SLAB_BIT_SIZE_LOG2 + RTE_BITMAP_CL_BIT_SIZE_LOG2);
368         offset1 = (pos >> RTE_BITMAP_CL_BIT_SIZE_LOG2) & RTE_BITMAP_SLAB_BIT_MASK;
369         slab2 = bmp->array2 + index2;
370         slab1 = bmp->array1 + index1;
371
372         *slab2 |= slab;
373         *slab1 |= 1llu << offset1;
374 }
375
376 static inline uint64_t
377 __rte_bitmap_line_not_empty(uint64_t *slab2)
378 {
379         uint64_t v1, v2, v3, v4;
380
381         v1 = slab2[0] | slab2[1];
382         v2 = slab2[2] | slab2[3];
383         v3 = slab2[4] | slab2[5];
384         v4 = slab2[6] | slab2[7];
385         v1 |= v2;
386         v3 |= v4;
387
388         return v1 | v3;
389 }
390
391 /**
392  * Bitmap bit clear
393  *
394  * @param bmp
395  *   Handle to bitmap instance
396  * @param pos
397  *   Bit position
398  */
399 static inline void
400 rte_bitmap_clear(struct rte_bitmap *bmp, uint32_t pos)
401 {
402         uint64_t *slab1, *slab2;
403         uint32_t index1, index2, offset1, offset2;
404
405         /* Clear bit in array2 slab */
406         index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
407         offset2 = pos & RTE_BITMAP_SLAB_BIT_MASK;
408         slab2 = bmp->array2 + index2;
409
410         /* Return if array2 slab is not all-zeros */
411         *slab2 &= ~(1llu << offset2);
412         if (*slab2){
413                 return;
414         }
415
416         /* Check the entire cache line of array2 for all-zeros */
417         index2 &= ~ RTE_BITMAP_CL_SLAB_MASK;
418         slab2 = bmp->array2 + index2;
419         if (__rte_bitmap_line_not_empty(slab2)) {
420                 return;
421         }
422
423         /* The array2 cache line is all-zeros, so clear bit in array1 slab */
424         index1 = pos >> (RTE_BITMAP_SLAB_BIT_SIZE_LOG2 + RTE_BITMAP_CL_BIT_SIZE_LOG2);
425         offset1 = (pos >> RTE_BITMAP_CL_BIT_SIZE_LOG2) & RTE_BITMAP_SLAB_BIT_MASK;
426         slab1 = bmp->array1 + index1;
427         *slab1 &= ~(1llu << offset1);
428
429         return;
430 }
431
432 static inline int
433 __rte_bitmap_scan_search(struct rte_bitmap *bmp)
434 {
435         uint64_t value1;
436         uint32_t i;
437
438         /* Check current array1 slab */
439         value1 = bmp->array1[bmp->index1];
440         value1 &= __rte_bitmap_mask1_get(bmp);
441
442         if (rte_bsf64(value1, &bmp->offset1)) {
443                 return 1;
444         }
445
446         __rte_bitmap_index1_inc(bmp);
447         bmp->offset1 = 0;
448
449         /* Look for another array1 slab */
450         for (i = 0; i < bmp->array1_size; i ++, __rte_bitmap_index1_inc(bmp)) {
451                 value1 = bmp->array1[bmp->index1];
452
453                 if (rte_bsf64(value1, &bmp->offset1)) {
454                         return 1;
455                 }
456         }
457
458         return 0;
459 }
460
461 static inline void
462 __rte_bitmap_scan_read_init(struct rte_bitmap *bmp)
463 {
464         __rte_bitmap_index2_set(bmp);
465         bmp->go2 = 1;
466         rte_prefetch1((void *)(bmp->array2 + bmp->index2 + 8));
467 }
468
469 static inline int
470 __rte_bitmap_scan_read(struct rte_bitmap *bmp, uint32_t *pos, uint64_t *slab)
471 {
472         uint64_t *slab2;
473
474         slab2 = bmp->array2 + bmp->index2;
475         for ( ; bmp->go2 ; bmp->index2 ++, slab2 ++, bmp->go2 = bmp->index2 & RTE_BITMAP_CL_SLAB_MASK) {
476                 if (*slab2) {
477                         *pos = bmp->index2 << RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
478                         *slab = *slab2;
479
480                         bmp->index2 ++;
481                         slab2 ++;
482                         bmp->go2 = bmp->index2 & RTE_BITMAP_CL_SLAB_MASK;
483                         return 1;
484                 }
485         }
486
487         return 0;
488 }
489
490 /**
491  * Bitmap scan (with automatic wrap-around)
492  *
493  * @param bmp
494  *   Handle to bitmap instance
495  * @param pos
496  *   When function call returns 1, pos contains the position of the next set
497  *   bit, otherwise not modified
498  * @param slab
499  *   When function call returns 1, slab contains the value of the entire 64-bit
500  *   slab where the bit indicated by pos is located. Slabs are always 64-bit
501  *   aligned, so the position of the first bit of the slab (this bit is not
502  *   necessarily set) is pos / 64. Once a slab has been returned by the bitmap
503  *   scan operation, the internal pointers of the bitmap are updated to point
504  *   after this slab, so the same slab will not be returned again if it
505  *   contains more than one bit which is set. When function call returns 0,
506  *   slab is not modified.
507  * @return
508  *   0 if there is no bit set in the bitmap, 1 otherwise
509  */
510 static inline int
511 rte_bitmap_scan(struct rte_bitmap *bmp, uint32_t *pos, uint64_t *slab)
512 {
513         /* Return data from current array2 line if available */
514         if (__rte_bitmap_scan_read(bmp, pos, slab)) {
515                 return 1;
516         }
517
518         /* Look for non-empty array2 line */
519         if (__rte_bitmap_scan_search(bmp)) {
520                 __rte_bitmap_scan_read_init(bmp);
521                 __rte_bitmap_scan_read(bmp, pos, slab);
522                 return 1;
523         }
524
525         /* Empty bitmap */
526         return 0;
527 }
528
529 #ifdef __cplusplus
530 }
531 #endif
532
533 #endif /* __INCLUDE_RTE_BITMAP_H__ */