From 099a6c7b0471ae3dfec7f2eda4971cc15d879226 Mon Sep 17 00:00:00 2001 From: Samy Al Bahra Date: Mon, 30 Apr 2012 13:25:49 -0400 Subject: [PATCH] ck_bitmap: Add bitmap iterator functions. These can do with some optimization. A majority of this work is based off an earlier patch submitted by Shreyas Prasad . --- doc/Makefile.in | 10 +- doc/ck_bitmap_iterator_init | 70 ++++++++++++++ doc/ck_bitmap_next | 90 ++++++++++++++++++ include/ck_bitmap.h | 116 ++++++++++++++++++++---- regressions/ck_bitmap/validate/serial.c | 64 ++++++++++--- 5 files changed, 317 insertions(+), 33 deletions(-) create mode 100644 doc/ck_bitmap_iterator_init create mode 100644 doc/ck_bitmap_next diff --git a/doc/Makefile.in b/doc/Makefile.in index 2ddf41a..ac6216d 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -35,10 +35,18 @@ OBJECTS=ck_ht_allocator_set$(GZIP_SUFFIX) \ ck_bitmap_size$(GZIP_SUFFIX) \ ck_bitmap_clear$(GZIP_SUFFIX) \ ck_bitmap_bits$(GZIP_SUFFIX) \ - ck_bitmap_buffer$(GZIP_SUFFIX) + ck_bitmap_buffer$(GZIP_SUFFIX) \ + ck_bitmap_next$(GZIP_SUFFIX) \ + ck_bitmap_iterator_init$(GZIP_SUFFIX) all: $(OBJECTS) +ck_bitmap_next$(GZIP_SUFFIX): ck_bitmap_next + $(GZIP) ck_bitmap_next > ck_bitmap_next$(GZIP_SUFFIX) + +ck_bitmap_iterator_init$(GZIP_SUFFIX): ck_bitmap_iterator_init + $(GZIP) ck_bitmap_iterator_init > ck_bitmap_iterator_init$(GZIP_SUFFIX) + ck_bitmap_init$(GZIP_SUFFIX): ck_bitmap_init $(GZIP) ck_bitmap_init > ck_bitmap_init$(GZIP_SUFFIX) diff --git a/doc/ck_bitmap_iterator_init b/doc/ck_bitmap_iterator_init new file mode 100644 index 0000000..b4fbe7b --- /dev/null +++ b/doc/ck_bitmap_iterator_init @@ -0,0 +1,70 @@ +.\" +.\" Copyright 2012 Samy Al Bahra. +.\" Copyright 2012 Shreyas Prasad. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" +.Dd April 27, 2012 +.Dt CK_BITMAP_ITERATOR_INIT 3 +.Sh NAME +.Nm ck_bitmap_iterator_init +.Nd initialize bitmap iterator +.Sh LIBRARY +Concurrency Kit (libck, \-lck) +.Sh SYNOPSIS +.In ck_ht.h +.Pp +.Ft void +.Fn ck_bitmap_iterator_init "ck_bitmap_iterator_t *iterator" "ck_bitmap_t *bitmap" +.Sh DESCRIPTION +The +.Fn ck_bitmap_iterator_init +function will initialize the object pointed to by +the +.Fa iterator +argument for use with +.Fa bitmap . +.Pp +An iterator is used to iterate through set bitmap bits +with the +.Xr ck_bitmap_next 3 +function. +.Sh RETURN VALUES +The +.Fn ck_bitmap_iterator_init +function does not return a value. +.Sh ERRORS +This function will not fail. +.Sh SEE ALSO +.Xr ck_bitmap_base 3 , +.Xr ck_bitmap_size 3 , +.Xr ck_bitmap_init 3 , +.Xr ck_bitmap_set_mpmc 3 , +.Xr ck_bitmap_reset_mpmc 3 , +.Xr ck_bitmap_clear 3 , +.Xr ck_bitmap_bits 3 , +.Xr ck_bitmap_buffer 3 , +.Xr ck_bitmap_next 3 +.Pp +Additional information available at http://concurrencykit.org/ diff --git a/doc/ck_bitmap_next b/doc/ck_bitmap_next new file mode 100644 index 0000000..596a444 --- /dev/null +++ b/doc/ck_bitmap_next @@ -0,0 +1,90 @@ +.\" +.\" Copyright 2012 Samy Al Bahra. +.\" Copyright 2012 Shreyas Prasad. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" +.Dd April 27, 2012 +.Dt CK_BITMAP_TEST 3 +.Sh NAME +.Nm ck_bitmap_next +.Nd iterate to the next set bit in bitmap +.Sh LIBRARY +Concurrency Kit (libck, \-lck) +.Sh SYNOPSIS +.In ck_bitmap.h +.Ft bool +.Fn ck_bitmap_next "ck_bitmap_t *bitmap" "ck_bitmap_iterator_t iterator" "unsigned int *bit" +.Sh DESCRIPTION +The +.Fn ck_bitmap_next +function will increment the iterator object pointed to by +.Fa iterator +to point to the next set bit in the bitmap. If +.Fn ck_bitmap_next +returns +.Dv true +then the pointer pointed to by +.Fa bit +is initialized to the number of the current set bit pointed to by the +.Fa iterator +object. +.Pp +It is expected that +.Fa iterator +has been initialized using the +.Xr ck_bitmap_iterator_init 3 +function. +.Sh RETURN VALUES +If +.Fn ck_bitmap_next +returns +.Dv true +then the object pointed to by +.Fa bit +contains a set bit. If +.Fn ck_bitmap_next +returns +.Dv false +then value of the object pointed to by +.Fa bit +is undefined. +.Sh ERRORS +Behavior is undefined if +.Fa iterator +or +.Fa bitmap +are uninitialized. +.Sh SEE ALSO +.Xr ck_bitmap_base 3 , +.Xr ck_bitmap_size 3 , +.Xr ck_bitmap_init 3 , +.Xr ck_bitmap_set_mpmc 3 , +.Xr ck_bitmap_reset_mpmc 3 , +.Xr ck_bitmap_clear 3 , +.Xr ck_bitmap_bits 3 , +.Xr ck_bitmap_buffer 3 , +.Xr ck_bitmap_iterator_init 3 +.Pp +Additional information available at http://concurrencykit.org/ diff --git a/include/ck_bitmap.h b/include/ck_bitmap.h index 0fdafd1..d7b0ace 100644 --- a/include/ck_bitmap.h +++ b/include/ck_bitmap.h @@ -71,9 +71,15 @@ struct ck_bitmap bitmap; \ } +#define CK_BITMAP_ITERATOR_INIT(a, b) \ + ck_bitmap_iterator_init((a), &(b)->bitmap) + #define CK_BITMAP_INIT(a, b, c) \ ck_bitmap_init(&(a)->bitmap, (b), (c)) +#define CK_BITMAP_NEXT(a, b, c) \ + ck_bitmap_next(&(a)->bitmap, (b), (c)) + #define CK_BITMAP_SET_MPMC(a, b) \ ck_bitmap_set_mpmc(&(a)->bitmap, (b)) @@ -101,6 +107,14 @@ struct ck_bitmap { }; typedef struct ck_bitmap ck_bitmap_t; +struct ck_bitmap_iterator { + CK_BITMAP_WORD cache; + unsigned int n_block; + unsigned int n_bit; + unsigned int n_limit; +}; +typedef struct ck_bitmap_iterator ck_bitmap_iterator_t; + CK_CC_INLINE static unsigned int ck_bitmap_base(unsigned int n_bits) { @@ -115,23 +129,6 @@ ck_bitmap_size(unsigned int n_bits) return ck_bitmap_base(n_bits) + sizeof(struct ck_bitmap); } -/* - * Initializes a ck_bitmap pointing to a region of memory with - * ck_bitmap_size(n_bits) bytes. Third argument determines whether - * default bit value is 1 (true) or 0 (false). - */ -CK_CC_INLINE static void -ck_bitmap_init(struct ck_bitmap *bitmap, - unsigned int n_bits, - bool set) -{ - unsigned int base = ck_bitmap_base(n_bits); - - bitmap->n_bits = n_bits; - memset(bitmap->map, -(int)set, base); - return; -} - /* * Sets the bit at the offset specified in the second argument. */ @@ -207,4 +204,89 @@ ck_bitmap_buffer(struct ck_bitmap *bitmap) return bitmap->map; } +/* + * Initializes a ck_bitmap pointing to a region of memory with + * ck_bitmap_size(n_bits) bytes. Third argument determines whether + * default bit value is 1 (true) or 0 (false). + */ +CK_CC_INLINE static void +ck_bitmap_init(struct ck_bitmap *bitmap, + unsigned int n_bits, + bool set) +{ + unsigned int base = ck_bitmap_base(n_bits); + + bitmap->n_bits = n_bits; + memset(bitmap->map, -(int)set, base); + + if (set == true) { + CK_BITMAP_WORD b; + + if (n_bits < CK_BITMAP_BLOCK) + b = n_bits; + else + b = n_bits % CK_BITMAP_BLOCK; + + if (b == 0) + return; + + bitmap->map[base / sizeof(CK_BITMAP_WORD) - 1] &= (1ULL << b) - 1ULL; + } + + return; +} + + +/* + * Initialize iterator for use with provided bitmap. + */ +CK_CC_INLINE static void +ck_bitmap_iterator_init(struct ck_bitmap_iterator *i, struct ck_bitmap *bitmap) +{ + + i->n_block = 0; + i->n_bit = 0; + i->n_limit = CK_BITMAP_BLOCKS(bitmap->n_bits); + i->cache = CK_BITMAP_LOAD(&bitmap->map[i->n_block]); + return; +} + +/* + * Iterate to next bit. + */ +CK_CC_INLINE static bool +ck_bitmap_next(struct ck_bitmap *bitmap, + struct ck_bitmap_iterator *i, + unsigned int *bit) +{ + + /* Load next bitmap block. */ + for (;;) { + while (i->n_bit < CK_BITMAP_BLOCK) { + unsigned int previous = i->n_bit++; + + if (i->cache & 1) { + *bit = previous + (64 * i->n_block); + i->cache >>= 1; + return true; + } + + i->cache >>= 1; + if (i->cache == 0) + break; + } + + i->n_bit = 0; + i->n_block++; + + if (i->n_block >= i->n_limit) + return false; + + i->cache = CK_BITMAP_LOAD(&bitmap->map[i->n_block]); + } + + return false; +} + + #endif /* _CK_BITMAP_H */ diff --git a/regressions/ck_bitmap/validate/serial.c b/regressions/ck_bitmap/validate/serial.c index e217f75..46b7737 100644 --- a/regressions/ck_bitmap/validate/serial.c +++ b/regressions/ck_bitmap/validate/serial.c @@ -1,5 +1,6 @@ /* * Copyright 2012 Samy Al Bahra. + * Copyright 2012 Shreyas Prasad. * Copyright 2012 AppNexus, Inc. * All rights reserved. * @@ -35,15 +36,48 @@ #endif static unsigned int length = 256; +static ck_bitmap_t *g_bits; static void -test(ck_bitmap_t *bits, bool initial) +check_iteration(ck_bitmap_t *bits, unsigned int len, bool initial) { - unsigned int i, n_length = bits->n_bits; + ck_bitmap_iterator_t iter; + unsigned int i = 0, j; + + len += 1; + if (initial == true) { + if (bits == g_bits) + len = length; + else + len = STATIC_LENGTH; + } + + ck_bitmap_iterator_init(&iter, bits); + for (j = 0; ck_bitmap_next(bits, &iter, &i) == true; j++) { + if (i == j) + continue; + + fprintf(stderr, "[4] ERROR: Expected bit %u, got bit %u\n", j, i); + exit(EXIT_FAILURE); + } + + if (j != len) { + fprintf(stderr, "[5] ERROR: Expected length %u, got length %u\n", len, j); + exit(EXIT_FAILURE); + } + + return; +} + +static void +test(ck_bitmap_t *bits, unsigned int n_length, bool initial) +{ + unsigned int i; for (i = 0; i < n_length; i++) { if (ck_bitmap_test(bits, i) == !initial) { - fprintf(stderr, "[0] ERROR: Expected bit to not be set: %u\n", i); + fprintf(stderr, "[0] ERROR [%u]: Expected %u got %u\n", i, + initial, !initial); exit(EXIT_FAILURE); } } @@ -54,7 +88,6 @@ test(ck_bitmap_t *bits, bool initial) fprintf(stderr, "[1] ERROR: Expected bit to be set: %u\n", i); exit(EXIT_FAILURE); } - ck_bitmap_reset_mpmc(bits, i); if (ck_bitmap_test(bits, i) == true) { fprintf(stderr, "[2] ERROR: Expected bit to be cleared: %u\n", i); @@ -66,6 +99,8 @@ test(ck_bitmap_t *bits, bool initial) fprintf(stderr, "[3] ERROR: Expected bit to be set: %u\n", i); exit(EXIT_FAILURE); } + + check_iteration(bits, i, initial); } for (i = 0; i < n_length; i++) { @@ -91,7 +126,6 @@ int main(int argc, char *argv[]) { unsigned int bytes, base; - ck_bitmap_t *bits; if (argc >= 2) { length = atoi(argv[1]); @@ -102,26 +136,26 @@ main(int argc, char *argv[]) fprintf(stderr, "Configuration: %u bytes\n", bytes); - bits = malloc(bytes); - memset(bits->map, 0xFF, base); - ck_bitmap_init(bits, length, false); - test(bits, false); + g_bits = malloc(bytes); + memset(g_bits->map, 0xFF, base); + ck_bitmap_init(g_bits, length, false); + test(g_bits, length, false); - memset(bits->map, 0x00, base); - ck_bitmap_init(bits, length, true); - test(bits, true); + memset(g_bits->map, 0x00, base); + ck_bitmap_init(g_bits, length, true); + test(g_bits, length, true); - ck_bitmap_test(bits, length - 1); + ck_bitmap_test(g_bits, length - 1); CK_BITMAP_INSTANCE(STATIC_LENGTH) sb; fprintf(stderr, "Static configuration: %zu bytes\n", sizeof(sb)); memset(CK_BITMAP_BUFFER(&sb), 0xFF, ck_bitmap_base(STATIC_LENGTH)); CK_BITMAP_INIT(&sb, STATIC_LENGTH, false); - test(CK_BITMAP(&sb), false); + test(CK_BITMAP(&sb), STATIC_LENGTH, false); memset(CK_BITMAP_BUFFER(&sb), 0x00, ck_bitmap_base(STATIC_LENGTH)); CK_BITMAP_INIT(&sb, STATIC_LENGTH, true); - test(CK_BITMAP(&sb), true); + test(CK_BITMAP(&sb), STATIC_LENGTH, true); CK_BITMAP_CLEAR(&sb); if (CK_BITMAP_TEST(&sb, 1) == true) {