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