This commit is contained in:
Gregory Burd 2024-04-16 11:31:55 -04:00
parent 6645665d82
commit 20b81983ae
3 changed files with 65 additions and 76 deletions

View file

@ -114,7 +114,7 @@ typedef struct {
sm_bitvec_t *m_data;
} __sm_chunk_t;
struct sparsemap {
struct __attribute__((aligned(8))) sparsemap {
uint8_t *m_data; /* The serialized bitmap data */
size_t m_capacity; /* The total size of m_data */
size_t m_data_used; /* The used size of m_data */
@ -764,19 +764,13 @@ __sm_append_data(sparsemap_t *map, uint8_t *buffer, size_t buffer_size)
/**
* Inserts data somewhere in the middle of m_data.
*/
static int
void
__sm_insert_data(sparsemap_t *map, size_t offset, uint8_t *buffer, size_t buffer_size)
{
if (map->m_data_used + buffer_size > map->m_capacity) {
__sm_assert(!"buffer overflow");
abort();
}
uint8_t *p = __sm_get_chunk_map_data(map, offset);
memmove(p + buffer_size, p, map->m_data_used - offset);
memcpy(p, buffer, buffer_size);
map->m_data_used += buffer_size;
return 0;
}
/**
@ -944,6 +938,11 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value)
ssize_t offset = __sm_get_chunk_map_offset(map, idx);
bool dont_grow = false;
if (map->m_data_used + sizeof(sm_idx_t) + sizeof(sm_bitvec_t) * 2 > map->m_capacity) {
errno = ENOSPC;
return SPARSEMAP_IDX_MAX;
}
/* If there is no __sm_chunk_t and the bit is set to zero then return
immediately; otherwise create an initial __sm_chunk_t. */
if (offset == -1) {
@ -959,8 +958,8 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value)
__sm_set_chunk_map_count(map, 1);
/* We already inserted an additional sm_bitvec_t; later on there
is no need to grow the vector even further. */
/* We already inserted an additional sm_bitvec_t; given that has happened
there is no need to grow the vector even further. */
dont_grow = true;
offset = 0;
}
@ -1044,8 +1043,10 @@ sparsemap_set(sparsemap_t *map, sparsemap_idx_t idx, bool value)
offset += (ssize_t)(sizeof(sm_idx_t) + position * sizeof(sm_bitvec_t));
__sm_insert_data(map, offset, (uint8_t *)&fill, sizeof(sm_bitvec_t));
}
code = __sm_chunk_map_set(&chunk, idx - start, value, &position, &fill, true);
__sm_assert(code == SM_OK);
__sm_when_diag({
code = __sm_chunk_map_set(&chunk, idx - start, value, &position, &fill, true);
__sm_assert(code == SM_OK);
});
break;
case SM_NEEDS_TO_SHRINK:
/* If the __sm_chunk_t is empty then remove it. */
@ -1259,12 +1260,9 @@ sparsemap_select(sparsemap_t *map, sparsemap_idx_t n, bool value)
p += __sm_chunk_map_get_size(&chunk);
}
#ifdef DEBUG
assert(!"shouldn't be here");
#endif
return SPARSEMAP_IDX_MAX;
return SPARSEMAP_IDX_MAX; // TODO... shouldn't be here?
} else {
return SPARSEMAP_IDX_MIN; // TODO... sparsemap_select(map, -n, value);
return SPARSEMAP_IDX_MIN; // TODO... sparsemap_select(map, -n, value); seek from end, not start
}
}

View file

@ -118,7 +118,7 @@ has_sequential_set(int a[], int l, int r)
int
ensure_sequential_set(int a[], int l, int r)
{
if (!a || l == 0 || r < 1 || r > l) {
if (!a || l == 0 || r < 1 || r > l - 1) {
return 0;
}

View file

@ -314,20 +314,23 @@ test_api_remaining_capacity(const MunitParameter params[], void *data)
do {
sparsemap_set(map, i++, true);
cap = sparsemap_capacity_remaining(map);
} while (cap > 1.0);
// assert_true(i == 169985); when seed is 8675309
assert_true(cap <= 1.0);
} while (cap > 1.0 && errno != ENOSPC);
errno = 0;
assert_true(cap <= 2.0);
sparsemap_clear(map);
cap = sparsemap_capacity_remaining(map);
assert_true(cap > 99);
i = 0;
do {
int p = munit_rand_int_range(0, 150000);
sparsemap_set(map, p, true);
i++;
cap = sparsemap_capacity_remaining(map);
} while (cap > 2.0);
// assert_true(i == 64); when seed is 8675309
assert_true(cap <= 2.0);
} while (cap > 1.0 && errno != ENOSPC);
errno = 0;
assert_true(cap <= 1.0);
return MUNIT_OK;
}
@ -873,33 +876,32 @@ static MunitTest api_test_suite[] = {
static void *
test_scale_lots_o_spans_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(10 * 1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 10 * 1024);
(void)params;
(void)user_data;
sparsemap_t *map = sparsemap(10 * 1024);
assert_ptr_not_null(map);
return (void *)map;
}
static void
test_scale_lots_o_spans_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
assert_ptr_not_null(map);
munit_free(map);
}
static MunitResult
test_scale_lots_o_spans(const MunitParameter params[], void *data)
{
size_t amt = 897915; // 268435456
sparsemap_t *map = (sparsemap_t *)data;
(void)params;
assert_ptr_not_null(map);
for (int i = 0; i < 268435456;) {
for (size_t i = 0; i < amt;) {
int l = i % 31 + 16;
sm_add_span(map, 268435456, l);
// TODO: sm_add_span(map, amt, l);
sm_add_span(map, 10000, l);
if (errno == ENOSPC) {
map = sparsemap_set_data_size(map, sparsemap_get_capacity(map) * 2);
errno = 0;
@ -908,7 +910,6 @@ test_scale_lots_o_spans(const MunitParameter params[], void *data)
/* ANSI esc code to clear line, carrage return, then print on the same line */
// printf("\033[2K\r%d", i);
// printf("%d\t%d\n", l, i);
// fflush(stdout);
}
return MUNIT_OK;
@ -917,21 +918,18 @@ test_scale_lots_o_spans(const MunitParameter params[], void *data)
static void *
test_scale_ondrej_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
(void)params;
(void)user_data;
sparsemap_t *map = sparsemap(10 * 1024);
assert_ptr_not_null(map);
return (void *)map;
}
static void
test_scale_ondrej_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
assert_ptr_not_null(map);
munit_free(map);
}
static MunitResult
test_scale_ondrej(const MunitParameter params[], void *data)
@ -948,59 +946,49 @@ test_scale_ondrej(const MunitParameter params[], void *data)
for (sparsemap_idx_t j = 0; j < stride; j++) {
bool set = (i != needle) ? (j < 10) : (j < 9);
sparsemap_set(map, i, set);
if (errno == ENOSPC) {
map = sparsemap_set_data_size(map, sparsemap_get_capacity(map) * 2);
errno = 0;
}
}
}
#if 0
// sm_add_span(map, 268435456, 9);
size_t b = sparsemap_span(map, 0, 8, true);
if (SPARSEMAP_NOT_FOUND(b)) {
printf("%ld\n", b);
printf("%ld / %ld == %ld %ld\n", b, stride, b / stride, needle);
} else {
printf("not found\n");
}
/*
size_t b = sparsemap_span(map, 0, 9, false); TODO
printf("%ld (%d) / %d == %d", b, (int)b, stride, needle);
fflush(stdout);
assert_true(((int)b / stride) == needle);
*/
#endif
sparsemap_idx_t a = sparsemap_span(map, 0, 9, false);
assert_true((a / stride) == needle);
return MUNIT_OK;
}
static void *
test_scale_spans_come_spans_go_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024, sizeof(uint8_t));
assert_ptr_not_null(buf);
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
(void)params;
(void)user_data;
sparsemap_t *map = sparsemap(10 * 1024);
assert_ptr_not_null(map);
return (void *)map;
}
static void
test_scale_spans_come_spans_go_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
assert_ptr_not_null(map->m_data);
munit_free(map->m_data);
test_api_tear_down(fixture);
assert_ptr_not_null(map);
munit_free(map);
}
static MunitResult
test_scale_spans_come_spans_go(const MunitParameter params[], void *data)
{
size_t amt = 897915; // 268435456, ~5e7 interations due to 2e9 / avg(l)
sparsemap_t *map = (sparsemap_t *)data;
(void)params;
assert_ptr_not_null(map);
/* ~5e7 interations due to 2e9 / avg(l) */
for (int i = 0; i < 268435456;) {
for (size_t i = 0; i < amt;) {
int l = i % 31 + 16;
sm_add_span(map, 268435456, l);
sm_add_span(map, amt, l);
if (errno == ENOSPC) {
map = sparsemap_set_data_size(map, sparsemap_get_capacity(map) * 2);
errno = 0;
}
/* After 10,000 spans are in there we consume a span every iteration. */
if (l > 10000) {
@ -1069,7 +1057,6 @@ test_scale_best_case(const MunitParameter params[], void *data)
for (int i = 0; i < 172032; i++) {
/* ANSI esc code to clear line, carrage return, then print on the same line */
// printf("\033[2K\r%d", i);
// fflush(stdout);
sparsemap_set(map, i, true);
}
@ -1116,7 +1103,6 @@ test_scale_worst_case(const MunitParameter params[], void *data)
for (int i = 0; i < 7744; i += 2) {
/* ANSI esc code to clear line, carrage return, then print on the same line */
// printf("\033[2K\r%d", i);
// fflush(stdout);
sparsemap_set(map, i, true);
}
@ -1260,6 +1246,11 @@ int
main(int argc, char *argv[MUNIT_ARRAY_PARAM(argc + 1)])
{
struct user_data info;
/* Disable buffering on std{out,err} to avoid having to call fflush(). */
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
return munit_suite_main(&main_test_suite, (void *)&info, argc, argv);
}