performance of span

This commit is contained in:
Gregory Burd 2024-04-10 23:16:06 -04:00
parent feb3e12581
commit 5460ef87b7
7 changed files with 322 additions and 110 deletions

View file

@ -6,10 +6,10 @@ SHARED_LIB = libsparsemap.so
#CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c11 -Iinclude/ -fPIC
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DSPARSEMAP_ASSERT -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c99 -Iinclude/ -fPIC
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=all -fhardened -std=c99 -Iinclude/ -fPIC
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=all -fhardened -std=c11 -Iinclude/ -fPIC
TEST_FLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c99 -Iinclude/ -Itests/ -fPIC
TEST_FLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -Itests/ -fPIC
TESTS = tests/test
TEST_OBJS = tests/test.o tests/munit.o tests/common.o
@ -49,7 +49,7 @@ clean:
rm -f $(EXAMPLES) examples/*.o
format:
clang-format -i src/sparsemap.c include/sparsemap.h examples/ex_*.c tests/test.c tests/common.c
clang-format -i src/sparsemap.c include/sparsemap.h examples/ex_*.c tests/test.c tests/common.c tests/common.h
# clang-format -i include/*.h src/*.c tests/*.c tests/*.h examples/*.c
%.o: src/%.c
@ -76,4 +76,4 @@ examples/ex_3: examples/common.o examples/ex_3.o $(STATIC_LIB)
examples/ex_4: examples/common.o examples/ex_4.o $(STATIC_LIB)
$(CC) $^ -o $@ $(CFLAGS) $(TEST_FLAGS)
# cp src/sparsemap.c /tmp && clang-tidy src/sparsemap.c -fix -fix-errors -checks="readability-braces-around-statements" -- -DDEBUG -DSPARSEMAP_DIAGNOSTIC -DSPARSEMAP_ASSERT -Wall -Wextra -Wpedantic -Og -g -std=c99 -Iinclude/ -fPIC
# cp src/sparsemap.c /tmp && clang-tidy src/sparsemap.c -fix -fix-errors -checks="readability-braces-around-statements" -- -DDEBUG -DSPARSEMAP_DIAGNOSTIC -DSPARSEMAP_ASSERT -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC

View file

@ -12,7 +12,6 @@
} while (0)
#pragma GCC diagnostic pop
/* !!! Duplicated here for testing purposes. Keep in sync, or suffer. !!! */
struct sparsemap {
uint8_t *m_data;
@ -20,7 +19,6 @@ struct sparsemap {
size_t m_data_used;
};
int
main()
{

View file

@ -87,12 +87,10 @@
* Usually this is an uint64_t.
*/
typedef struct sparsemap sparsemap_t;
typedef uint32_t sm_idx_t;
typedef uint64_t sm_bitvec_t;
/* Allocate on a sparsemap_t on the heap and initialize it. */
sparsemap_t *sparsemap(uint8_t *data, size_t size);

View file

@ -20,13 +20,12 @@
* SOFTWARE.
*/
#include <assert.h>
#include <popcount.h>
#include <sparsemap.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <popcount.h>
#include <sparsemap.h>
#ifdef SPARSEMAP_DIAGNOSTIC
#pragma GCC diagnostic push
@ -99,18 +98,16 @@ enum __SM_CHUNK_INFO {
#define SM_CHUNK_GET_FLAGS(from, at) (((from)) & ((sm_bitvec_t)SM_FLAG_MASK << ((at) * 2))) >> ((at) * 2)
typedef struct {
sm_bitvec_t *m_data;
} __sm_chunk_t;
struct 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 */
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 */
};
/**
* Calculates the number of sm_bitvec_ts required by a single byte with flags
* (in m_data[0]).
@ -799,7 +796,8 @@ sparsemap_set_data_size(sparsemap_t *map, size_t data_size)
* indicate full.
*/
double
sparsemap_capacity_remaining(sparsemap_t *map) {
sparsemap_capacity_remaining(sparsemap_t *map)
{
if (map->m_data_used > map->m_capacity) {
return 0;
}

View file

@ -2,12 +2,12 @@
#include <assert.h>
#include <pthread.h>
#include <sparsemap.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "../include/sparsemap.h"
#include "common.h"
#pragma GCC diagnostic push
@ -19,6 +19,87 @@
} while (0)
#pragma GCC diagnostic pop
uint64_t
tsc(void)
{
uint32_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return ((uint64_t)high << 32) | low;
}
static
uint64_t get_tsc_frequency() {
uint32_t high, low;
__asm__ volatile("rdtsc" : "=a" (low), "=d" (high));
__asm__ volatile("rdtsc");
return ((uint64_t)high << 32) | low;
}
double
tsc_ticks_to_ns(uint64_t tsc_ticks) {
static uint64_t tsc_freq = 0;
if (tsc_freq == 0) {
tsc_freq = get_tsc_frequency();
}
return (double)tsc_ticks / (double)tsc_freq * 1e9;
}
void
est_sift_up(uint64_t *heap, int child_index)
{
while (child_index > 0) {
int parent_index = (child_index - 1) / 2;
if (heap[parent_index] > heap[child_index]) {
// Swap parent and child
uint64_t temp = heap[parent_index];
heap[parent_index] = heap[child_index];
heap[child_index] = temp;
child_index = parent_index;
} else {
break; // Heap property satisfied
}
}
}
void
est_sift_down(uint64_t *heap, int heap_size, int parent_index)
{
int child_index = 2 * parent_index + 1; // Left child
while (child_index < heap_size) {
// Right child exists and is smaller than left child
if (child_index + 1 < heap_size && heap[child_index + 1] < heap[child_index]) {
child_index++;
}
// If the smallest child is smaller than the parent, swap them
if (heap[child_index] < heap[parent_index]) {
uint64_t temp = heap[child_index];
heap[child_index] = heap[parent_index];
heap[parent_index] = temp;
parent_index = child_index;
child_index = 2 * parent_index + 1;
} else {
break; // Heap property satisfied
}
}
}
void
est_insert_value(uint64_t *heap, int heap_max_size, int *heap_size, uint64_t value)
{
if (*heap_size < heap_max_size) { // Heap not full, insert value
heap[*heap_size] = value;
est_sift_up(heap, *heap_size);
(*heap_size)++;
} else {
// Heap is full, replace root with new value with a certain probability
// This is a very naive approach to maintain a sample of the input
if (rand() % 2) {
heap[0] = value;
est_sift_down(heap, heap_max_size, 0);
}
}
}
int __xorshift32_state = 0;
// Xorshift algorithm for PRNG
@ -120,7 +201,11 @@ int
create_sequential_set_in_empty_map(sparsemap_t *map, int s, int r)
{
int placed_at;
placed_at = random_uint32() % (s - r - 1);
if (s >= r + 1) {
placed_at = 0;
} else {
placed_at = random_uint32() % (s - r - 1);
}
for (int i = placed_at; i < placed_at + r; i++) {
sparsemap_set(map, i, true);
}
@ -269,60 +354,62 @@ setup_test_array(int a[], int l, int max_value)
}
void
bitmap_from_uint32(sparsemap_t *map, uint32_t number) {
for (int i = 0; i < 32; i++) {
bool bit = number & (1 << i);
sparsemap_set(map, i, bit);
}
bitmap_from_uint32(sparsemap_t *map, uint32_t number)
{
for (int i = 0; i < 32; i++) {
bool bit = number & (1 << i);
sparsemap_set(map, i, bit);
}
}
void
bitmap_from_uint64(sparsemap_t *map, uint64_t number) {
for (int i = 0; i < 64; i++) {
bool bit = number & (1 << i);
sparsemap_set(map, i, bit);
}
bitmap_from_uint64(sparsemap_t *map, uint64_t number)
{
for (int i = 0; i < 64; i++) {
bool bit = number & (1 << i);
sparsemap_set(map, i, bit);
}
}
uint32_t
rank_uint64(uint64_t number, int n, int p)
{
if (p < n || p > 63) {
return 0;
}
if (p < n || p > 63) {
return 0;
}
/* Create a mask for the range between n and p.
This works by shifting 1 to the left (p+1) times, subtracting 1 to have
a sequence of p 1's, then shifting n times to the left to position it
starting at n. Finally, subtracting (1 << n) - 1 removes the bits below
n from the mask. */
uint64_t mask = ((uint64_t)1 << (p + 1)) - 1 - (((uint64_t)1 << n) - 1);
/* Create a mask for the range between n and p.
This works by shifting 1 to the left (p+1) times, subtracting 1 to have
a sequence of p 1's, then shifting n times to the left to position it
starting at n. Finally, subtracting (1 << n) - 1 removes the bits below
n from the mask. */
uint64_t mask = ((uint64_t)1 << (p + 1)) - 1 - (((uint64_t)1 << n) - 1);
/* Apply the mask and count the set bits in the result. */
uint64_t maskedNumber = number & mask;
/* Apply the mask and count the set bits in the result. */
uint64_t maskedNumber = number & mask;
/* Count the bits set in maskedNumber. */
uint32_t count = 0;
while (maskedNumber) {
count += maskedNumber & 1;
maskedNumber >>= 1;
}
/* Count the bits set in maskedNumber. */
uint32_t count = 0;
while (maskedNumber) {
count += maskedNumber & 1;
maskedNumber >>= 1;
}
return count;
return count;
}
int
whats_set_uint64(uint64_t number, int pos[64])
{
int length = 0;
int length = 0;
for (int i = 0; i < 64; i++) {
if (number & ((uint64_t)1 << i)) {
pos[length++] = i;
}
for (int i = 0; i < 64; i++) {
if (number & ((uint64_t)1 << i)) {
pos[length++] = i;
}
}
return length;
return length;
}
void

View file

@ -23,6 +23,21 @@
#define XORSHIFT_SEED_VALUE ((unsigned int)time(NULL) ^ getpid())
#endif
#define EST_MEDIAN_DECL(decl, size) \
uint64_t heap_##decl[size] = { 0 }; \
int heap_##decl##_max_size = size; \
int heap_##decl##_size = 0;
#define EST_MEDIAN_ADD(decl, value) est_insert_value(heap_##decl, heap_##decl##_max_size, &heap_##decl##_size, (value));
#define EST_MEDIAN_GET(decl) heap_##decl[0]
uint64_t tsc(void);
double tsc_ticks_to_ns(uint64_t tsc_ticks);
void est_sift_up(uint64_t *heap, int child_index);
void est_sift_down(uint64_t *heap, int heap_size, int parent_index);
void est_insert_value(uint64_t *heap, int heap_max_size, int *heap_size, uint64_t value);
void xorshift32_seed();
uint32_t xorshift32();

View file

@ -21,7 +21,6 @@
#pragma warning(disable : 4127)
#endif
/* !!! Duplicated here for testing purposes. Keep in sync, or suffer. !!! */
struct sparsemap {
uint8_t *m_data;
@ -39,7 +38,7 @@ populate_map(sparsemap_t *map, int size, int max_value)
int array[size];
setup_test_array(array, size, max_value);
//TODO ensure_sequential_set(array, size, 10);
// TODO ensure_sequential_set(array, size, 10);
shuffle(array, size);
for (int i = 0; i < size; i++) {
sparsemap_set(map, array[i], true);
@ -70,7 +69,7 @@ static MunitResult
test_api_static_init(const MunitParameter params[], void *data)
{
sparsemap_t a_map, *map = &a_map;
uint8_t buf[1024] = {0};
uint8_t buf[1024] = { 0 };
(void)params;
(void)data;
@ -215,7 +214,7 @@ test_api_remaining_capacity(const MunitParameter params[], void *data)
sparsemap_set(map, i++, true);
cap = sparsemap_capacity_remaining(map);
} while (cap > 1.0);
//assert_true(i == 169985); when seed is 8675309
// assert_true(i == 169985); when seed is 8675309
assert_true(cap <= 1.0);
sparsemap_clear(map);
@ -226,7 +225,7 @@ test_api_remaining_capacity(const MunitParameter params[], void *data)
i++;
cap = sparsemap_capacity_remaining(map);
} while (cap > 2.0);
//assert_true(i == 64); when seed is 8675309
// assert_true(i == 64); when seed is 8675309
assert_true(cap <= 2.0);
return MUNIT_OK;
@ -422,7 +421,8 @@ test_api_scan_tear_down(void *fixture)
test_api_tear_down(fixture);
}
void
scan_for_0xfeedfacebadcoffee(sm_idx_t v[], size_t n) {
scan_for_0xfeedfacebadcoffee(sm_idx_t v[], size_t n)
{
/* Called multiple times */
((void)v);
((void)n);
@ -449,7 +449,7 @@ test_api_split_setup(const MunitParameter params[], void *user_data)
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 1024);
for(int i = 0; i < 1024; i ++) {
for (int i = 0; i < 1024; i++) {
sparsemap_set(map, i, true);
}
return (void *)map;
@ -465,7 +465,7 @@ static MunitResult
test_api_split(const MunitParameter params[], void *data)
{
sparsemap_t *map = (sparsemap_t *)data;
uint8_t buf[1024] = {0};
uint8_t buf[1024] = { 0 };
sparsemap_t portion;
(void)params;
@ -600,58 +600,174 @@ test_api_span(const MunitParameter params[], void *data)
assert_ptr_not_null(map);
int located_at, placed_at, amt = 5000;
for (int i = 1; i < amt; i++) {
for (int j = 1; j < amt / 10; j++) {
sparsemap_clear(map);
placed_at = create_sequential_set_in_empty_map(map, amt, j);
//logf("i = %d, j = %d\tplaced_at %d\n", i, j, placed_at);
//whats_set(map, 5000);
located_at = sparsemap_span(map, 0, j);
if (placed_at != located_at)
logf("a: i = %d, j = %d\tplaced_at %d located_at %d\n", i, j, placed_at, located_at);
assert_true(located_at == placed_at);
}
}
/*
for (int i = 1; i < amt; i++) {
for (int j = 1; j < amt / 10; j++) {
sparsemap_clear(map);
populate_map(map, 1024, 3 * 1024);
placed_at = create_sequential_set_in_empty_map(map, amt, j);
located_at = sparsemap_span(map, 0, j);
if (located_at >= placed_at)
logf("b: i = %d, j = %d\tplaced_at %d located_at %d\n", i, j, placed_at, located_at);
//assert_true(located_at >= placed_at);
located_at = sparsemap_span(map, (placed_at < j ? 0 : placed_at / 2), i);
assert_true(placed_at == located_at);
}
}
*/
int located_at, placed_at, amt = 10000;
return MUNIT_OK;
placed_at = create_sequential_set_in_empty_map(map, amt, 1);
located_at = sparsemap_span(map, 0, 1);
assert_true(located_at == placed_at);
sparsemap_clear(map);
placed_at = create_sequential_set_in_empty_map(map, amt, 50);
located_at = sparsemap_span(map, 0, 50);
assert_true(located_at == placed_at);
sparsemap_clear(map);
placed_at = create_sequential_set_in_empty_map(map, amt, 50);
located_at = sparsemap_span(map, placed_at / 2, 50);
assert_true(located_at == placed_at);
/* TODO
sparsemap_clear(map);
placed_at = create_sequential_set_in_empty_map(map, amt, amt - 1);
located_at = sparsemap_span(map, 0, amt - 1);
assert_true(located_at == placed_at);
*/
return MUNIT_OK;
}
static MunitTest api_test_suite[] = { { (char *)"/api/static_init", test_api_static_init, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/clear", test_api_clear, test_api_clear_setup, test_api_clear_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/open", test_api_open, test_api_open_setup, test_api_open_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/set_data_size", test_api_set_data_size, test_api_set_data_size_setup, test_api_set_data_size_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/remaining_capacity", test_api_remaining_capacity, test_api_remaining_capacity_setup, test_api_remaining_capacity_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/get_range_size", test_api_get_range_size, test_api_get_range_size_setup, test_api_get_range_size_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/is_set", test_api_is_set, test_api_is_set_setup, test_api_is_set_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/set", test_api_set, test_api_set_setup, test_api_set_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/get_start_offset", test_api_get_start_offset, test_api_get_start_offset_setup, test_api_get_start_offset_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/get_size", test_api_get_size, test_api_get_size_setup, test_api_get_size_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/scan", test_api_scan, test_api_scan_setup, test_api_scan_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/split", test_api_split, test_api_split_setup, test_api_split_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/select", test_api_select, test_api_select_setup, test_api_select_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/rank", test_api_rank, test_api_rank_setup, test_api_rank_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/api/span", test_api_span, test_api_span_setup, test_api_span_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
// clang-format off
static MunitTest api_test_suite[] = {
{ (char *)"/static_init", test_api_static_init, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/clear", test_api_clear, test_api_clear_setup, test_api_clear_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/open", test_api_open, test_api_open_setup, test_api_open_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/set_data_size", test_api_set_data_size, test_api_set_data_size_setup, test_api_set_data_size_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/remaining_capacity", test_api_remaining_capacity, test_api_remaining_capacity_setup, test_api_remaining_capacity_tear_down,
MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/get_range_size", test_api_get_range_size, test_api_get_range_size_setup, test_api_get_range_size_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/is_set", test_api_is_set, test_api_is_set_setup, test_api_is_set_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/set", test_api_set, test_api_set_setup, test_api_set_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/get_start_offset", test_api_get_start_offset, test_api_get_start_offset_setup, test_api_get_start_offset_tear_down, MUNIT_TEST_OPTION_NONE,
NULL },
{ (char *)"/get_size", test_api_get_size, test_api_get_size_setup, test_api_get_size_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/scan", test_api_scan, test_api_scan_setup, test_api_scan_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/split", test_api_split, test_api_split_setup, test_api_split_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/select", test_api_select, test_api_select_setup, test_api_select_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/rank", test_api_rank, test_api_rank_setup, test_api_rank_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/span", test_api_span, test_api_span_setup, test_api_span_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
// clang-format on
static void *
test_perf_span_solo_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024 * 3, sizeof(uint8_t));
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 3 * 1024);
return (void *)map;
}
static void
test_perf_span_solo_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
test_api_tear_down(fixture);
}
EST_MEDIAN_DECL(solo, 10000)
static MunitResult
test_perf_span_solo(const MunitParameter params[], void *data)
{
sparsemap_t *map = (sparsemap_t *)data;
uint64_t stop, start;
(void)params;
int located_at, placed_at, amt = 1000;
assert_ptr_not_null(map);
for (int i = 1; i < amt; i++) {
for (int j = 1; j < amt / 10; j++) {
sparsemap_clear(map);
placed_at = create_sequential_set_in_empty_map(map, amt, j);
// logf("i = %d, j = %d\tplaced_at %d\n", i, j, placed_at);
// whats_set(map, 5000);
start = tsc();
located_at = sparsemap_span(map, 0, j);
stop = tsc();
// fprintf(stdout, "%ll - %ll = %ll\n", stop, start, stop - start);
EST_MEDIAN_ADD(solo, stop - start);
if (placed_at != located_at)
logf("a: i = %d, j = %d\tplaced_at %d located_at %d\n", i, j, placed_at, located_at);
}
}
uint64_t est = EST_MEDIAN_GET(solo);
fprintf(stdout, "median time %zu or %f ns\n", est, tsc_ticks_to_ns(est)); // measured 228
assert_true(EST_MEDIAN_GET(solo) < 500);
fflush(stdout);
return MUNIT_OK;
}
static void *
test_perf_span_tainted_setup(const MunitParameter params[], void *user_data)
{
uint8_t *buf = munit_calloc(1024 * 3, sizeof(uint8_t));
sparsemap_t *map = (sparsemap_t *)test_api_setup(params, user_data);
sparsemap_init(map, buf, 3 * 1024);
return (void *)map;
}
static void
test_perf_span_tainted_tear_down(void *fixture)
{
sparsemap_t *map = (sparsemap_t *)fixture;
free(map->m_data);
test_api_tear_down(fixture);
}
EST_MEDIAN_DECL(tainted, 10000)
static MunitResult
test_perf_span_tainted(const MunitParameter params[], void *data)
{
sparsemap_t *map = (sparsemap_t *)data;
uint64_t stop, start;
(void)params;
assert_ptr_not_null(map);
int located_at, placed_at, amt = 1000;
for (int i = 1; i < amt; i++) {
for (int j = 1; j < amt / 10; j++) {
sparsemap_clear(map);
populate_map(map, 1024, 1 * 1024);
placed_at = create_sequential_set_in_empty_map(map, amt, j);
start = tsc();
located_at = sparsemap_span(map, 0, j);
stop = tsc();
EST_MEDIAN_ADD(tainted, stop - start);
if (located_at >= placed_at)
logf("b: i = %d, j = %d\tplaced_at %d located_at %d\n", i, j, placed_at, located_at);
// assert_true(located_at >= placed_at);
//start = tsc();
//located_at = sparsemap_span(map, (placed_at < j ? 0 : placed_at / 2), i);
//stop = tsc();
//EST_MEDIAN_ADD(solo, stop - start);
// assert_true(placed_at == located_at);
}
}
uint64_t est = EST_MEDIAN_GET(tainted);
fprintf(stdout, "median time %zu or %f ns\n", est, tsc_ticks_to_ns(est)); // measured 228
return MUNIT_OK;
}
// clang-format off
static MunitTest performance_test_suite[] = {
{ (char *)"/span/solo", test_perf_span_solo, test_perf_span_solo_setup, test_perf_span_solo_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ (char *)"/span/tainted", test_perf_span_tainted, test_perf_span_tainted_setup, test_perf_span_tainted_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } };
// clang-format on
static MunitTest scale_tests[] = { { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } };
static MunitSuite other_test_suite[] = { { "/scale", scale_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE }, { NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } };
// clang-format off
static MunitSuite other_test_suite[] = {
{ "/performance", performance_test_suite, NULL, 1, MUNIT_SUITE_OPTION_NONE },
{ NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } };
// clang-format on
static const MunitSuite main_test_suite = { (char *)"/api", api_test_suite, other_test_suite, 1, MUNIT_SUITE_OPTION_NONE };