DPDK  2.1.0
rte_bitmap.h
Go to the documentation of this file.
1 /*-
2  * BSD LICENSE
3  *
4  * Copyright(c) 2010-2014 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 #ifndef __INCLUDE_RTE_BITMAP_H__
35 #define __INCLUDE_RTE_BITMAP_H__
36 
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40 
67 #include <rte_common.h>
68 #include <rte_debug.h>
69 #include <rte_memory.h>
70 #include <rte_branch_prediction.h>
71 #include <rte_prefetch.h>
72 
73 #ifndef RTE_BITMAP_OPTIMIZATIONS
74 #define RTE_BITMAP_OPTIMIZATIONS 1
75 #endif
76 #if RTE_BITMAP_OPTIMIZATIONS
77 #include <tmmintrin.h>
78 #endif
79 
80 /* Slab */
81 #define RTE_BITMAP_SLAB_BIT_SIZE 64
82 #define RTE_BITMAP_SLAB_BIT_SIZE_LOG2 6
83 #define RTE_BITMAP_SLAB_BIT_MASK (RTE_BITMAP_SLAB_BIT_SIZE - 1)
84 
85 /* Cache line (CL) */
86 #define RTE_BITMAP_CL_BIT_SIZE (RTE_CACHE_LINE_SIZE * 8)
87 #define RTE_BITMAP_CL_BIT_SIZE_LOG2 9
88 #define RTE_BITMAP_CL_BIT_MASK (RTE_BITMAP_CL_BIT_SIZE - 1)
89 
90 #define RTE_BITMAP_CL_SLAB_SIZE (RTE_BITMAP_CL_BIT_SIZE / RTE_BITMAP_SLAB_BIT_SIZE)
91 #define RTE_BITMAP_CL_SLAB_SIZE_LOG2 3
92 #define RTE_BITMAP_CL_SLAB_MASK (RTE_BITMAP_CL_SLAB_SIZE - 1)
93 
95 struct rte_bitmap {
96  /* Context for array1 and array2 */
97  uint64_t *array1;
98  uint64_t *array2;
99  uint32_t array1_size;
100  uint32_t array2_size;
102  /* Context for the "scan next" operation */
103  uint32_t index1;
104  uint32_t offset1;
105  uint32_t index2;
106  uint32_t go2;
108  /* Storage space for array1 and array2 */
109  uint8_t memory[0];
110 };
111 
112 static inline void
113 __rte_bitmap_index1_inc(struct rte_bitmap *bmp)
114 {
115  bmp->index1 = (bmp->index1 + 1) & (bmp->array1_size - 1);
116 }
117 
118 static inline uint64_t
119 __rte_bitmap_mask1_get(struct rte_bitmap *bmp)
120 {
121  return ((~1lu) << bmp->offset1);
122 }
123 
124 static inline void
125 __rte_bitmap_index2_set(struct rte_bitmap *bmp)
126 {
127  bmp->index2 = (((bmp->index1 << RTE_BITMAP_SLAB_BIT_SIZE_LOG2) + bmp->offset1) << RTE_BITMAP_CL_SLAB_SIZE_LOG2);
128 }
129 
130 #if RTE_BITMAP_OPTIMIZATIONS
131 
132 static inline int
133 rte_bsf64(uint64_t slab, uint32_t *pos)
134 {
135  if (likely(slab == 0)) {
136  return 0;
137  }
138 
139  *pos = __builtin_ctzll(slab);
140  return 1;
141 }
142 
143 #else
144 
145 static inline int
146 rte_bsf64(uint64_t slab, uint32_t *pos)
147 {
148  uint64_t mask;
149  uint32_t i;
150 
151  if (likely(slab == 0)) {
152  return 0;
153  }
154 
155  for (i = 0, mask = 1; i < RTE_BITMAP_SLAB_BIT_SIZE; i ++, mask <<= 1) {
156  if (unlikely(slab & mask)) {
157  *pos = i;
158  return 1;
159  }
160  }
161 
162  return 0;
163 }
164 
165 #endif
166 
167 static inline uint32_t
168 __rte_bitmap_get_memory_footprint(uint32_t n_bits,
169  uint32_t *array1_byte_offset, uint32_t *array1_slabs,
170  uint32_t *array2_byte_offset, uint32_t *array2_slabs)
171 {
172  uint32_t n_slabs_context, n_slabs_array1, n_cache_lines_context_and_array1;
173  uint32_t n_cache_lines_array2;
174  uint32_t n_bytes_total;
175 
176  n_cache_lines_array2 = (n_bits + RTE_BITMAP_CL_BIT_SIZE - 1) / RTE_BITMAP_CL_BIT_SIZE;
177  n_slabs_array1 = (n_cache_lines_array2 + RTE_BITMAP_SLAB_BIT_SIZE - 1) / RTE_BITMAP_SLAB_BIT_SIZE;
178  n_slabs_array1 = rte_align32pow2(n_slabs_array1);
179  n_slabs_context = (sizeof(struct rte_bitmap) + (RTE_BITMAP_SLAB_BIT_SIZE / 8) - 1) / (RTE_BITMAP_SLAB_BIT_SIZE / 8);
180  n_cache_lines_context_and_array1 = (n_slabs_context + n_slabs_array1 + RTE_BITMAP_CL_SLAB_SIZE - 1) / RTE_BITMAP_CL_SLAB_SIZE;
181  n_bytes_total = (n_cache_lines_context_and_array1 + n_cache_lines_array2) * RTE_CACHE_LINE_SIZE;
182 
183  if (array1_byte_offset) {
184  *array1_byte_offset = n_slabs_context * (RTE_BITMAP_SLAB_BIT_SIZE / 8);
185  }
186  if (array1_slabs) {
187  *array1_slabs = n_slabs_array1;
188  }
189  if (array2_byte_offset) {
190  *array2_byte_offset = n_cache_lines_context_and_array1 * RTE_CACHE_LINE_SIZE;
191  }
192  if (array2_slabs) {
193  *array2_slabs = n_cache_lines_array2 * RTE_BITMAP_CL_SLAB_SIZE;
194  }
195 
196  return n_bytes_total;
197 }
198 
199 static inline void
200 __rte_bitmap_scan_init(struct rte_bitmap *bmp)
201 {
202  bmp->index1 = bmp->array1_size - 1;
203  bmp->offset1 = RTE_BITMAP_SLAB_BIT_SIZE - 1;
204  __rte_bitmap_index2_set(bmp);
205  bmp->index2 += RTE_BITMAP_CL_SLAB_SIZE;
206 
207  bmp->go2 = 0;
208 }
209 
218 static inline uint32_t
220  /* Check input arguments */
221  if (n_bits == 0) {
222  return 0;
223  }
224 
225  return __rte_bitmap_get_memory_footprint(n_bits, NULL, NULL, NULL, NULL);
226 }
227 
240 static inline struct rte_bitmap *
241 rte_bitmap_init(uint32_t n_bits, uint8_t *mem, uint32_t mem_size)
242 {
243  struct rte_bitmap *bmp;
244  uint32_t array1_byte_offset, array1_slabs, array2_byte_offset, array2_slabs;
245  uint32_t size;
246 
247  /* Check input arguments */
248  if (n_bits == 0) {
249  return NULL;
250  }
251 
252  if ((mem == NULL) || (((uintptr_t) mem) & RTE_CACHE_LINE_MASK)) {
253  return NULL;
254  }
255 
256  size = __rte_bitmap_get_memory_footprint(n_bits,
257  &array1_byte_offset, &array1_slabs,
258  &array2_byte_offset, &array2_slabs);
259  if (size < mem_size) {
260  return NULL;
261  }
262 
263  /* Setup bitmap */
264  memset(mem, 0, size);
265  bmp = (struct rte_bitmap *) mem;
266 
267  bmp->array1 = (uint64_t *) &mem[array1_byte_offset];
268  bmp->array1_size = array1_slabs;
269  bmp->array2 = (uint64_t *) &mem[array2_byte_offset];
270  bmp->array2_size = array2_slabs;
271 
272  __rte_bitmap_scan_init(bmp);
273 
274  return bmp;
275 }
276 
285 static inline int
287 {
288  /* Check input arguments */
289  if (bmp == NULL) {
290  return -1;
291  }
292 
293  return 0;
294 }
295 
302 static inline void
304 {
305  memset(bmp->array1, 0, bmp->array1_size * sizeof(uint64_t));
306  memset(bmp->array2, 0, bmp->array2_size * sizeof(uint64_t));
307  __rte_bitmap_scan_init(bmp);
308 }
309 
320 static inline void
321 rte_bitmap_prefetch0(struct rte_bitmap *bmp, uint32_t pos)
322 {
323  uint64_t *slab2;
324  uint32_t index2;
325 
326  index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
327  slab2 = bmp->array2 + index2;
328  rte_prefetch0((void *) slab2);
329 }
330 
341 static inline uint64_t
342 rte_bitmap_get(struct rte_bitmap *bmp, uint32_t pos)
343 {
344  uint64_t *slab2;
345  uint32_t index2, offset2;
346 
347  index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
348  offset2 = pos & RTE_BITMAP_SLAB_BIT_MASK;
349  slab2 = bmp->array2 + index2;
350  return ((*slab2) & (1lu << offset2));
351 }
352 
361 static inline void
362 rte_bitmap_set(struct rte_bitmap *bmp, uint32_t pos)
363 {
364  uint64_t *slab1, *slab2;
365  uint32_t index1, index2, offset1, offset2;
366 
367  /* Set bit in array2 slab and set bit in array1 slab */
368  index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
369  offset2 = pos & RTE_BITMAP_SLAB_BIT_MASK;
370  index1 = pos >> (RTE_BITMAP_SLAB_BIT_SIZE_LOG2 + RTE_BITMAP_CL_BIT_SIZE_LOG2);
371  offset1 = (pos >> RTE_BITMAP_CL_BIT_SIZE_LOG2) & RTE_BITMAP_SLAB_BIT_MASK;
372  slab2 = bmp->array2 + index2;
373  slab1 = bmp->array1 + index1;
374 
375  *slab2 |= 1lu << offset2;
376  *slab1 |= 1lu << offset1;
377 }
378 
389 static inline void
390 rte_bitmap_set_slab(struct rte_bitmap *bmp, uint32_t pos, uint64_t slab)
391 {
392  uint64_t *slab1, *slab2;
393  uint32_t index1, index2, offset1;
394 
395  /* Set bits in array2 slab and set bit in array1 slab */
396  index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
397  index1 = pos >> (RTE_BITMAP_SLAB_BIT_SIZE_LOG2 + RTE_BITMAP_CL_BIT_SIZE_LOG2);
398  offset1 = (pos >> RTE_BITMAP_CL_BIT_SIZE_LOG2) & RTE_BITMAP_SLAB_BIT_MASK;
399  slab2 = bmp->array2 + index2;
400  slab1 = bmp->array1 + index1;
401 
402  *slab2 |= slab;
403  *slab1 |= 1lu << offset1;
404 }
405 
406 static inline uint64_t
407 __rte_bitmap_line_not_empty(uint64_t *slab2)
408 {
409  uint64_t v1, v2, v3, v4;
410 
411  v1 = slab2[0] | slab2[1];
412  v2 = slab2[2] | slab2[3];
413  v3 = slab2[4] | slab2[5];
414  v4 = slab2[6] | slab2[7];
415  v1 |= v2;
416  v3 |= v4;
417 
418  return (v1 | v3);
419 }
420 
429 static inline void
430 rte_bitmap_clear(struct rte_bitmap *bmp, uint32_t pos)
431 {
432  uint64_t *slab1, *slab2;
433  uint32_t index1, index2, offset1, offset2;
434 
435  /* Clear bit in array2 slab */
436  index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
437  offset2 = pos & RTE_BITMAP_SLAB_BIT_MASK;
438  slab2 = bmp->array2 + index2;
439 
440  /* Return if array2 slab is not all-zeros */
441  *slab2 &= ~(1lu << offset2);
442  if (*slab2){
443  return;
444  }
445 
446  /* Check the entire cache line of array2 for all-zeros */
447  index2 &= ~ RTE_BITMAP_CL_SLAB_MASK;
448  slab2 = bmp->array2 + index2;
449  if (__rte_bitmap_line_not_empty(slab2)) {
450  return;
451  }
452 
453  /* The array2 cache line is all-zeros, so clear bit in array1 slab */
454  index1 = pos >> (RTE_BITMAP_SLAB_BIT_SIZE_LOG2 + RTE_BITMAP_CL_BIT_SIZE_LOG2);
455  offset1 = (pos >> RTE_BITMAP_CL_BIT_SIZE_LOG2) & RTE_BITMAP_SLAB_BIT_MASK;
456  slab1 = bmp->array1 + index1;
457  *slab1 &= ~(1lu << offset1);
458 
459  return;
460 }
461 
462 static inline int
463 __rte_bitmap_scan_search(struct rte_bitmap *bmp)
464 {
465  uint64_t value1;
466  uint32_t i;
467 
468  /* Check current array1 slab */
469  value1 = bmp->array1[bmp->index1];
470  value1 &= __rte_bitmap_mask1_get(bmp);
471 
472  if (rte_bsf64(value1, &bmp->offset1)) {
473  return 1;
474  }
475 
476  __rte_bitmap_index1_inc(bmp);
477  bmp->offset1 = 0;
478 
479  /* Look for another array1 slab */
480  for (i = 0; i < bmp->array1_size; i ++, __rte_bitmap_index1_inc(bmp)) {
481  value1 = bmp->array1[bmp->index1];
482 
483  if (rte_bsf64(value1, &bmp->offset1)) {
484  return 1;
485  }
486  }
487 
488  return 0;
489 }
490 
491 static inline void
492 __rte_bitmap_scan_read_init(struct rte_bitmap *bmp)
493 {
494  __rte_bitmap_index2_set(bmp);
495  bmp->go2 = 1;
496  rte_prefetch1((void *)(bmp->array2 + bmp->index2 + 8));
497 }
498 
499 static inline int
500 __rte_bitmap_scan_read(struct rte_bitmap *bmp, uint32_t *pos, uint64_t *slab)
501 {
502  uint64_t *slab2;
503 
504  slab2 = bmp->array2 + bmp->index2;
505  for ( ; bmp->go2 ; bmp->index2 ++, slab2 ++, bmp->go2 = bmp->index2 & RTE_BITMAP_CL_SLAB_MASK) {
506  if (*slab2) {
507  *pos = bmp->index2 << RTE_BITMAP_SLAB_BIT_SIZE_LOG2;
508  *slab = *slab2;
509 
510  bmp->index2 ++;
511  slab2 ++;
512  bmp->go2 = bmp->index2 & RTE_BITMAP_CL_SLAB_MASK;
513  return 1;
514  }
515  }
516 
517  return 0;
518 }
519 
540 static inline int
541 rte_bitmap_scan(struct rte_bitmap *bmp, uint32_t *pos, uint64_t *slab)
542 {
543  /* Return data from current array2 line if available */
544  if (__rte_bitmap_scan_read(bmp, pos, slab)) {
545  return 1;
546  }
547 
548  /* Look for non-empty array2 line */
549  if (__rte_bitmap_scan_search(bmp)) {
550  __rte_bitmap_scan_read_init(bmp);
551  __rte_bitmap_scan_read(bmp, pos, slab);
552  return 1;
553  }
554 
555  /* Empty bitmap */
556  return 0;
557 }
558 
559 #ifdef __cplusplus
560 }
561 #endif
562 
563 #endif /* __INCLUDE_RTE_BITMAP_H__ */