diff --git a/include/ck_bitmap.h b/include/ck_bitmap.h new file mode 100644 index 0000000..0c86b69 --- /dev/null +++ b/include/ck_bitmap.h @@ -0,0 +1,145 @@ +/* + * Copyright 2012 Samy Al Bahra + * Copyright 2012 AppNexus, Inc. + * 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 AUTHOR 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 AUTHOR 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. + */ + +#ifndef _CK_BITMAP_H +#define _CK_BITMAP_H + +#include +#include +#include +#include +#include +#include +#include + +#if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_STORE_64) && \ + defined(CK_F_PR_AND_64) && defined(CK_F_PR_OR_64) +#define CK_BITMAP_TYPE uint64_t +#define CK_BITMAP_SHIFT 6 +#define CK_BITMAP_STORE(x, y) ck_pr_store_64(x, y) +#define CK_BITMAP_LOAD(x) ck_pr_load_64(x) +#define CK_BITMAP_OR(x, y) ck_pr_or_64(x, y) +#define CK_BITMAP_AND(x, y) ck_pr_and_64(x, y) +#elif defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_STORE_32) && \ + defined(CK_F_PR_AND_32) && defined(CK_F_PR_OR_32) +#define CK_BITMAP_TYPE uint32_t +#define CK_BITMAP_SHIFT 5 +#define CK_BITMAP_STORE(x, y) ck_pr_store_32(x, y) +#define CK_BITMAP_LOAD(x) ck_pr_load_32(x) +#define CK_BITMAP_OR(x, y) ck_pr_or_32(x, y) +#define CK_BITMAP_AND(x, y) ck_pr_and_32(x, y) +#else +#error "ck_bitmap is not supported on your platform." +#endif + +#define CK_BITMAP_PTR(x, i) ((x) + ((i) >> CK_BITMAP_SHIFT)) +#define CK_BITMAP_MASK (sizeof(CK_BITMAP_TYPE) * CHAR_BIT - 1) + +struct ck_bitmap { + unsigned int length; + unsigned int n_buckets; + CK_BITMAP_TYPE *map; +}; +typedef struct ck_bitmap ck_bitmap_t; + +/* + * Returns the number of bytes that must be allocated for a bitmap + * with the specified number of entries. + */ +CK_CC_INLINE static unsigned int +ck_bitmap_size(unsigned int entries) +{ + size_t s = sizeof(CK_BITMAP_TYPE) * CHAR_BIT; + + return ((entries + (s - 1)) / s) * sizeof(CK_BITMAP_TYPE); +} + +CK_CC_INLINE static void +ck_bitmap_init(struct ck_bitmap *bitmap, + void *buffer, + unsigned int length, + bool set) +{ + + bitmap->map = buffer; + bitmap->length = length; + bitmap->n_buckets = ck_bitmap_size(length) / sizeof(CK_BITMAP_TYPE); + memset(bitmap->map, -(int)set, length); + return; +} + +CK_CC_INLINE static void +ck_bitmap_set_mpmc(struct ck_bitmap *bitmap, unsigned int n) +{ + CK_BITMAP_TYPE mask = 0x1ULL << (n & CK_BITMAP_MASK); + CK_BITMAP_TYPE *map = ck_pr_load_ptr(&bitmap->map); + + CK_BITMAP_OR(CK_BITMAP_PTR(map, n), mask); + return; +} + +CK_CC_INLINE static void +ck_bitmap_reset_mpmc(struct ck_bitmap *bitmap, unsigned int n) +{ + CK_BITMAP_TYPE mask = ~(0x1ULL << (n & CK_BITMAP_MASK)); + CK_BITMAP_TYPE *map = ck_pr_load_ptr(&bitmap->map); + + CK_BITMAP_AND(CK_BITMAP_PTR(map, n), mask); + return; +} + +CK_CC_INLINE static void * +ck_bitmap_clear_mpmc(struct ck_bitmap *bitmap, void *buffer) +{ + CK_BITMAP_TYPE *pointer = ck_pr_load_ptr(&bitmap->map); + unsigned int i; + + if (buffer != NULL) { + if (ck_pr_cas_ptr(&bitmap->map, pointer, buffer) == true) + return pointer; + + return buffer; + } + + for (i = 0; i < bitmap->n_buckets; i++) + CK_BITMAP_STORE(&pointer[i], 0); + + return NULL; +} + +CK_CC_INLINE static bool +ck_bitmap_test(struct ck_bitmap *bitmap, unsigned int n) +{ + CK_BITMAP_TYPE mask = 0x1ULL << (n & CK_BITMAP_MASK); + CK_BITMAP_TYPE *map = ck_pr_load_ptr(&bitmap->map); + CK_BITMAP_TYPE block; + + block = CK_BITMAP_LOAD(CK_BITMAP_PTR(map, n)); + return block & mask; +} + +#endif /* _CK_BITMAP_H */ diff --git a/regressions/Makefile b/regressions/Makefile index d65c5fa..5d1e4de 100644 --- a/regressions/Makefile +++ b/regressions/Makefile @@ -1,6 +1,7 @@ .PHONY: all clean all: + $(MAKE) -C ./ck_bitmap/validate all $(MAKE) -C ./ck_queue/validate all $(MAKE) -C ./ck_brlock/validate all $(MAKE) -C ./ck_ht/validate all @@ -29,6 +30,7 @@ all: $(MAKE) -C ./ck_bag/validate all clean: + $(MAKE) -C ./ck_bitmap/validate clean $(MAKE) -C ./ck_queue/validate clean $(MAKE) -C ./ck_brlock/validate clean $(MAKE) -C ./ck_ht/validate clean diff --git a/regressions/ck_bitmap/validate/Makefile b/regressions/ck_bitmap/validate/Makefile new file mode 100644 index 0000000..6f28020 --- /dev/null +++ b/regressions/ck_bitmap/validate/Makefile @@ -0,0 +1,14 @@ +.PHONY: clean + +OBJECTS=serial + +all: $(OBJECTS) + +serial: serial.c + $(CC) $(CFLAGS) -o serial serial.c + +clean: + rm -rf *~ *.o $(OBJECTS) *.dSYM + +include ../../../build/regressions.build +CFLAGS+=-D_GNU_SOURCE diff --git a/regressions/ck_bitmap/validate/serial.c b/regressions/ck_bitmap/validate/serial.c new file mode 100644 index 0000000..409a853 --- /dev/null +++ b/regressions/ck_bitmap/validate/serial.c @@ -0,0 +1,102 @@ +/* + * Copyright 2012 Samy Al Bahra. + * Copyright 2012 AppNexus, Inc. + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include +#include +#include +#include + +static unsigned int length = 256; + +static void +test(ck_bitmap_t *bits, bool initial) +{ + unsigned int i; + + for (i = 0; i < length; i++) { + if (ck_bitmap_test(bits, i) == !initial) { + fprintf(stderr, "[4] ERROR: Expected bit to not be set: %u\n", i); + exit(EXIT_FAILURE); + } + } + + for (i = 0; i < length; i++) { + ck_bitmap_set_mpmc(bits, i); + if (ck_bitmap_test(bits, i) == false) { + 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); + exit(EXIT_FAILURE); + } + + ck_bitmap_set_mpmc(bits, i); + if (ck_bitmap_test(bits, i) == false) { + fprintf(stderr, "[3] ERROR: Expected bit to be set: %u\n", i); + exit(EXIT_FAILURE); + } + } + + for (i = 0; i < length; i++) { + if (ck_bitmap_test(bits, i) == false) { + fprintf(stderr, "[4] ERROR: Expected bit to be set: %u\n", i); + exit(EXIT_FAILURE); + } + } + + return; +} + +int +main(int argc, char *argv[]) +{ + unsigned int bytes; + ck_bitmap_t bits; + void *buffer; + + if (argc >= 2) { + length = atoi(argv[1]); + } + + bytes = ck_bitmap_size(length); + fprintf(stderr, "Configuration: %u bytes\n\n", + bytes); + + buffer = malloc(bytes); + memset(buffer, 0xFF, bytes); + ck_bitmap_init(&bits, buffer, length, false); + test(&bits, false); + + memset(buffer, 0xFF, bytes); + ck_bitmap_init(&bits, buffer, length, true); + test(&bits, true); + + return 0; +}