// returns 0 on error, 1 if ok. int and_or_test() { bitset_container_t* B1 = bitset_container_create(); bitset_container_t* B2 = bitset_container_create(); bitset_container_t* BI = bitset_container_create(); bitset_container_t* BO = bitset_container_create(); int x, c, ci, co; printf("[%s] %s\n", __FILE__, __func__); if ((B1 == NULL) || (B2 == NULL) || (BO == NULL) || (BI == NULL)) { printf("Bug %s, line %d \n", __FILE__, __LINE__); return 0; } for (x = 0; x < (1 << 16); x += 3) { bitset_container_set(B1, (uint16_t)x); bitset_container_set(BI, (uint16_t)x); } for (x = 0; x < (1 << 16); x += 62) { // important: 62 is not divisible by 3 bitset_container_set(B2, (uint16_t)x); bitset_container_set(BI, (uint16_t)x); } for (x = 0; x < (1 << 16); x += 62 * 3) { bitset_container_set(BO, (uint16_t)x); } // we interleave O and I on purpose (to trigger bugs!) ci = bitset_container_compute_cardinality(BO); // expected intersection co = bitset_container_compute_cardinality(BI); // expected union bitset_container_and_nocard(B1, B2, BI); c = bitset_container_compute_cardinality(BI); if (c != ci) { printf("Bug %s, line %d \n", __FILE__, __LINE__); return 0; } c = bitset_container_and(B1, B2, BI); ; if (c != ci) { printf("Bug %s, line %d \n", __FILE__, __LINE__); return 0; } bitset_container_or_nocard(B1, B2, BO); c = bitset_container_compute_cardinality(BO); if (c != co) { printf("Bug %s, line %d \n", __FILE__, __LINE__); return 0; } c = bitset_container_or(B1, B2, BO); if (c != co) { printf("Bug %s, line %d \n", __FILE__, __LINE__); return 0; } bitset_container_free(B1); bitset_container_free(B2); bitset_container_free(BI); bitset_container_free(BO); return 1; }
bool array_array_container_union(const array_container_t *src_1, const array_container_t *src_2, void **dst) { int totalCardinality = src_1->cardinality + src_2->cardinality; if (totalCardinality <= DEFAULT_MAX_SIZE) { *dst = array_container_create_given_capacity(totalCardinality); if (*dst != NULL) array_container_union(src_1, src_2, (array_container_t *)*dst); return false; // not a bitset } *dst = bitset_container_create(); bool returnval = true; // expect a bitset if (*dst != NULL) { bitset_container_t *ourbitset = (bitset_container_t *)*dst; bitset_set_list(ourbitset->array, src_1->array, src_1->cardinality); ourbitset->cardinality = bitset_set_list_withcard(ourbitset->array, src_1->cardinality, src_2->array, src_2->cardinality); if (ourbitset->cardinality <= DEFAULT_MAX_SIZE) { // need to convert! *dst = array_container_from_bitset(ourbitset); bitset_container_free(ourbitset); returnval = false; // not going to be a bitset } } return returnval; }
// returns 0 on error, 1 if ok. int to_uint32_array_test() { printf("[%s] %s\n", __FILE__, __func__); for (int offset = 1; offset < 128; offset *= 2) { bitset_container_t* B = bitset_container_create(); for (int k = 0; k < (1 << 16); k += offset) { bitset_container_set(B, (uint16_t)k); } int card = bitset_container_cardinality(B); uint32_t* out = malloc(sizeof(uint32_t) * (card + sizeof(__m256i))); int nc = bitset_container_to_uint32_array(out, B, 0); if (card != nc) { printf("Bug %s, line %d \n", __FILE__, __LINE__); return 0; } for (int k = 1; k < nc; ++k) { if (out[k] != offset + out[k - 1]) { printf("Bug %s, line %d \n", __FILE__, __LINE__); return 0; } } free(out); bitset_container_free(B); } return 1; }
// returns 0 on error, 1 if ok. int set_get_test() { bitset_container_t* B = bitset_container_create(); int x; printf("[%s] %s\n", __FILE__, __func__); if (B == NULL) { printf("Bug %s, line %d \n", __FILE__, __LINE__); return 0; } for (x = 0; x < 1 << 16; x++) { assert(!bitset_container_get(B, x)); } for (x = 0; x < 1 << 16; x += 3) { assert(bitset_container_cardinality(B) == x / 3); assert(!bitset_container_get(B, x)); bitset_container_set(B, (uint16_t)x); assert(bitset_container_get(B, x)); assert(bitset_container_cardinality(B) == x / 3 + 1); } for (x = 0; x < 1 << 16; x++) { int isset = bitset_container_get(B, (uint16_t)x); int shouldbeset = (x / 3 * 3 == x); if (isset != shouldbeset) { printf("Bug %s, line %d \n", __FILE__, __LINE__); bitset_container_free(B); return 0; } } if (bitset_container_cardinality(B) != (1 << 16) / 3 + 1) { printf("Bug %s, line %d \n", __FILE__, __LINE__); bitset_container_free(B); return 0; } if (bitset_container_compute_cardinality(B) != (1 << 16) / 3 + 1) { printf("Bug %s, line %d \n", __FILE__, __LINE__); bitset_container_free(B); return 0; } for (x = 0; x < 1 << 16; x += 3) { bitset_container_unset(B, (uint16_t)x); } if (bitset_container_cardinality(B) != 0) { printf("Bug %s, line %d \n", __FILE__, __LINE__); bitset_container_free(B); return 0; } if (bitset_container_compute_cardinality(B) != 0) { printf("Bug %s, line %d \n", __FILE__, __LINE__); bitset_container_free(B); return 0; } bitset_container_free(B); return 1; }
// returns 0 on error, 1 if ok. int printf_test() { printf("[%s] %s\n", __FILE__, __func__); bitset_container_t* B = bitset_container_create(); bitset_container_set(B, (uint16_t)1); bitset_container_set(B, (uint16_t)2); bitset_container_set(B, (uint16_t)3); bitset_container_set(B, (uint16_t)10); bitset_container_set(B, (uint16_t)10000); bitset_container_printf(B); // does it crash? printf("\n"); bitset_container_free(B); return 1; }
// returns 0 on error, 1 if ok. int xor_test() { bitset_container_t* B1 = bitset_container_create(); bitset_container_t* B2 = bitset_container_create(); bitset_container_t* BI = bitset_container_create(); int x, c, cx; printf("[%s] %s\n", __FILE__, __func__); for (x = 0; x < (1 << 16); x += 3) { bitset_container_set(B1, (uint16_t)x); bitset_container_set(BI, (uint16_t)x); } for (x = 0; x < (1 << 16); x += 62) { // important: 62 is not divisible by 3 bitset_container_set(B2, (uint16_t)x); bitset_container_set(BI, (uint16_t)x); } for (x = 0; x < (1 << 16); x += 62 * 3) { bitset_container_unset(BI, (uint16_t)x); } cx = bitset_container_compute_cardinality(BI); // expected xor bitset_container_xor_nocard(B1, B2, BI); c = bitset_container_compute_cardinality(BI); if (c != cx) { printf("Bug %s, line %d \n", __FILE__, __LINE__); return 0; } c = bitset_container_xor(B1, B2, BI); if (c != cx) { printf("Bug %s, line %d \n", __FILE__, __LINE__); return 0; } bitset_container_free(B1); bitset_container_free(B2); bitset_container_free(BI); return 1; }
bool bitset_array_container_andnot(const bitset_container_t *src_1, const array_container_t *src_2, void **dst) { // Java did this directly, but we have option of asm or avx bitset_container_t *result = bitset_container_create(); bitset_container_copy(src_1, result); result->cardinality = bitset_clear_list(result->array, result->cardinality, src_2->array, src_2->cardinality); // do required type conversions. if (result->cardinality <= DEFAULT_MAX_SIZE) { *dst = array_container_from_bitset(result); bitset_container_free(result); return false; } *dst = result; return true; }
bool array_array_container_lazy_union(const array_container_t *src_1, const array_container_t *src_2, void **dst) { int totalCardinality = src_1->cardinality + src_2->cardinality; if (totalCardinality <= ARRAY_LAZY_LOWERBOUND) { *dst = array_container_create_given_capacity(totalCardinality); if (*dst != NULL) array_container_union(src_1, src_2, (array_container_t *)*dst); return false; // not a bitset } *dst = bitset_container_create(); bool returnval = true; // expect a bitset if (*dst != NULL) { bitset_container_t *ourbitset = (bitset_container_t *)*dst; bitset_set_list(ourbitset->array, src_1->array, src_1->cardinality); bitset_set_list(ourbitset->array, src_2->array, src_2->cardinality); ourbitset->cardinality = BITSET_UNKNOWN_CARDINALITY; } return returnval; }
bool bitset_run_container_andnot(const bitset_container_t *src_1, const run_container_t *src_2, void **dst) { // follows Java implementation bitset_container_t *result = bitset_container_create(); bitset_container_copy(src_1, result); for (int32_t rlepos = 0; rlepos < src_2->n_runs; ++rlepos) { rle16_t rle = src_2->runs[rlepos]; bitset_reset_range(result->array, rle.value, rle.value + rle.length + UINT32_C(1)); } result->cardinality = bitset_container_compute_cardinality(result); if (result->cardinality <= DEFAULT_MAX_SIZE) { *dst = array_container_from_bitset(result); bitset_container_free(result); return false; // not bitset } *dst = result; return true; // bitset }
/* * Compute the intersection between src_1 and src_2 and write the result * to *dst. If the return function is true, the result is a bitset_container_t * otherwise is a array_container_t. */ bool bitset_bitset_container_intersection(const bitset_container_t *src_1, const bitset_container_t *src_2, void **dst) { const int newCardinality = bitset_container_and_justcard(src_1, src_2); if (newCardinality > DEFAULT_MAX_SIZE) { *dst = bitset_container_create(); if (*dst != NULL) { bitset_container_and_nocard(src_1, src_2, *dst); ((bitset_container_t *)*dst)->cardinality = newCardinality; } return true; // it is a bitset } *dst = array_container_create_given_capacity(newCardinality); if (*dst != NULL) { ((array_container_t *)*dst)->cardinality = newCardinality; bitset_extract_intersection_setbits_uint16( ((bitset_container_t *)src_1)->array, ((bitset_container_t *)src_2)->array, BITSET_CONTAINER_SIZE_IN_WORDS, ((array_container_t *)*dst)->array, 0); } return false; // not a bitset }
int main() { int repeat = 500; int size = (1 << 16) / 3; tellmeall(); printf("bitset container benchmarks\n"); bitset_container_t* B = bitset_container_create(); BEST_TIME(set_test(B), 0, repeat, size); int answer = get_test(B); size = 1 << 16; BEST_TIME(get_test(B), answer, repeat, size); BEST_TIME(bitset_container_cardinality(B), answer, repeat, 1); BEST_TIME(bitset_container_compute_cardinality(B), answer, repeat, BITSET_CONTAINER_SIZE_IN_WORDS); size = (1 << 16) / 3; BEST_TIME(unset_test(B), 0, repeat, size); bitset_container_free(B); for (int howmany = 4096; howmany <= (1 << 16); howmany *= 2) { bitset_container_t* Bt = bitset_container_create(); while (bitset_container_cardinality(Bt) < howmany) { bitset_container_set(Bt, (uint16_t)pcg32_random()); } size_t nbrtestvalues = 1024; uint16_t* testvalues = malloc(nbrtestvalues * sizeof(uint16_t)); printf("\n number of values in container = %d\n", bitset_container_cardinality(Bt)); int card = bitset_container_cardinality(Bt); uint32_t* out = malloc(sizeof(uint32_t) * (unsigned)card + 32); BEST_TIME(bitset_container_to_uint32_array(out, Bt, 1234), card, repeat, card); free(out); BEST_TIME_PRE_ARRAY(Bt, bitset_container_get, bitset_cache_prefetch, testvalues, nbrtestvalues); BEST_TIME_PRE_ARRAY(Bt, bitset_container_get, bitset_cache_flush, testvalues, nbrtestvalues); free(testvalues); bitset_container_free(Bt); } printf("\n"); bitset_container_t* B1 = bitset_container_create(); for (int x = 0; x < 1 << 16; x += 3) { bitset_container_set(B1, (uint16_t)x); } bitset_container_t* B2 = bitset_container_create(); for (int x = 0; x < 1 << 16; x += 5) { bitset_container_set(B2, (uint16_t)x); } bitset_container_t* BO = bitset_container_create(); BEST_TIME(bitset_container_or_nocard(B1, B2, BO), -1, repeat, BITSET_CONTAINER_SIZE_IN_WORDS); answer = bitset_container_compute_cardinality(BO); BEST_TIME(bitset_container_or(B1, B2, BO), answer, repeat, BITSET_CONTAINER_SIZE_IN_WORDS); BEST_TIME(bitset_container_cardinality(BO), answer, repeat, 1); BEST_TIME(bitset_container_compute_cardinality(BO), answer, repeat, BITSET_CONTAINER_SIZE_IN_WORDS); BEST_TIME(bitset_container_and_nocard(B1, B2, BO), -1, repeat, BITSET_CONTAINER_SIZE_IN_WORDS); answer = bitset_container_compute_cardinality(BO); BEST_TIME(bitset_container_and(B1, B2, BO), answer, repeat, BITSET_CONTAINER_SIZE_IN_WORDS); BEST_TIME(bitset_container_cardinality(BO), answer, repeat, 1); BEST_TIME(bitset_container_compute_cardinality(BO), answer, repeat, BITSET_CONTAINER_SIZE_IN_WORDS); // next we are going to benchmark conversion from bitset to array (an // important step) bitset_container_clear(B1); for (int k = 0; k < 4096; ++k) { bitset_container_set(B1, (uint16_t)ranged_random(1 << 16)); } answer = get_cardinality_through_conversion_to_array(B1); BEST_TIME(get_cardinality_through_conversion_to_array(B1), answer, repeat, BITSET_CONTAINER_SIZE_IN_WORDS); bitset_container_free(BO); bitset_container_free(B1); bitset_container_free(B2); return 0; }