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