More refactoring

This commit is contained in:
Leonardo Vencovsky committed 2023-01-17 17:09:48 +01:00
1 parent 0e6c44ac46
commit f6bc58a3d7
59 files changed
+10562 -98

No files matched your search

+266
View File
@@ -0,0 +1,266 @@
/**
* benchmark.c
*
* Creation Date: 13/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Benchmarks:
* - Input
* - Search
* - Iteration
* - Output
*/
#include <assert.h>
#include <inttypes.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include "util/twister.c"
#include "cmc/utl/foreach.h"
#include "cmc/utl/futils.h"
#include "cmc/utl/timer.h"
#define NTOTAL UINT64_C(10000000)
#define NMIN UINT64_C(100)
// Percentage % macro
#define PC(x) x * 100.0
static int intcmp(int a, int b)
{
return a - b;
}
static size_t inthash(int t)
{
size_t a = t;
a += ~(a << 15);
a ^= (a >> 10);
a += (a << 3);
a ^= (a >> 6);
a += ~(a << 11);
a ^= (a >> 16);
return a;
}
size_t randsize(size_t min, size_t max, mt_state_ptr st)
{
return (size_t)floor(twist_real(st) * ((double)max - (double)min + 1.0) + (double)min);
}
void shuffle(int *array, mt_state_ptr st)
{
for (size_t i = 0; i < NTOTAL; i++)
{
size_t j = randsize(0, NTOTAL - 1, st);
int tmp = array[j];
array[j] = array[i];
array[i] = tmp;
}
}
#define K int32_t
#define V int32_t
#define PFX d
#define SNAME deque
#define CMC_EXT_DEQUE_ITER
#include "cmc/deque.h"
// CMC_COLLECTION_GENERATE(DEQUE, d, deque, /* K */, int)
// CMC_COLLECTION_GENERATE(HASHMAP, hm, hmap, int, int)
// CMC_COLLECTION_GENERATE(HASHSET, hs, hset, /* K */, int)
// CMC_COLLECTION_GENERATE(HEAP, h, heap, /* K */, int)
// CMC_COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* K */, int)
// CMC_COLLECTION_GENERATE(LIST, l, list, /* K */, int)
// CMC_COLLECTION_GENERATE(QUEUE, q, queue, /* K */, int)
// CMC_COLLECTION_GENERATE(STACK, s, stack, /* K */, int)
// CMC_COLLECTION_GENERATE(TREEMAP, tm, tmap, int, int)
// CMC_COLLECTION_GENERATE(TREESET, ts, tset, /* K */, int)
// CMC_COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, /* k */, int)
// CMC_COLLECTION_GENERATE(MULTIMAP, mm, mmap, int, int)
// CMC_COLLECTION_GENERATE(MULTISET, ms, mset, /* K */, int)
#define BENCHMARK(NAME, PFX, sname, initfunc, insertbody, removebody, searchbody) \
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
{ \
printf("+------------------------------------------------------------ %10s\n", #NAME); \
printf("+------------------------------------------------------------ \n"); \
struct cmc_timer timer, total; \
int r, k, v; \
size_t j; \
\
struct sname *coll = initfunc; \
\
cmc_timer_start(total); \
cmc_timer_start(timer); \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
insertbody; \
} \
\
cmc_timer_stop(timer); \
\
size_t s1 = PFX##_count(coll); \
\
printf(" INPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
\
double input_time = timer.result; \
\
cmc_timer_start(timer); \
\
for (size_t i = 0; i < s; i++) \
{ \
searchbody; \
} \
\
cmc_timer_stop(timer); \
\
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
\
double search_time = timer.result; \
\
cmc_timer_start(timer); \
\
CMC_FOREACH (PFX, sname, iter, coll) \
{ \
} \
\
cmc_timer_stop(timer); \
\
printf("ITERATION %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
\
double iter_time = timer.result; \
\
cmc_timer_start(timer); \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
removebody; \
} \
\
cmc_timer_stop(timer); \
\
size_t s2 = PFX##_count(coll); \
\
printf(" OUTPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
\
double output_time = timer.result; \
\
cmc_timer_stop(total); \
\
PFX##_free(coll); \
\
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
double no_search = input_time + iter_time + output_time; \
\
printf("+------------------------------------------------------------ \n"); \
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
\
printf("+------------------------------------------------------------ \n"); \
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
printf(" OUTPUT : %5.2lf%% (%5.2f%%)\n", PC(output_time / total.result), PC(output_time / no_search)); \
printf("+------------------------------------------------------------ \n"); \
\
assert(s1 == NTOTAL && s2 == 0); \
\
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
}
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL, &(struct deque_fval){ .cmp = cmc_i32_cmp }), d_push_back(coll, array[i]),
d_pop_back(coll), d_contains(coll, sarray[i]))
// BENCHMARK(HASHMAP, hm, hmap, hm_new(NTOTAL, 0.6, intcmp, inthash), hm_insert(coll, array[i], array[i]),
// hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
// BENCHMARK(HASHSET, hs, hset, hs_new(NTOTAL, 0.6, intcmp, inthash), hs_insert(coll, array[i]), hs_remove(coll,
// array[i]),
// hs_contains(coll, sarray[i]))
// BENCHMARK(HEAP, h, heap, h_new(NTOTAL, cmc_min_heap, intcmp), h_insert(coll, array[i]), h_remove(coll, &r),
// h_contains(coll, sarray[i]))
// BENCHMARK(LINKEDLIST, ll, linked, ll_new(), ll_push_back(coll, array[i]), ll_pop_back(coll),
// ll_contains(coll, sarray[i], intcmp))
// BENCHMARK(LIST, l, list, l_new(NTOTAL), l_push_back(coll, array[i]), l_pop_back(coll),
// l_contains(coll, sarray[i], intcmp))
// BENCHMARK(QUEUE, q, queue, q_new(NTOTAL), q_enqueue(coll, array[i]), q_dequeue(coll),
// q_contains(coll, sarray[i], intcmp))
// BENCHMARK(STACK, s, stack, s_new(NTOTAL), s_push(coll, array[i]), s_pop(coll), s_contains(coll, sarray[i], intcmp))
// BENCHMARK(TREEMAP, tm, tmap, tm_new(intcmp), tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r),
// tm_contains(coll, sarray[i]))
// BENCHMARK(TREESET, ts, tset, ts_new(intcmp), ts_insert(coll, array[i]), ts_remove(coll, array[i]),
// ts_contains(coll, sarray[i]))
// BENCHMARK(INTERVALHEAP, ih, iheap, ih_new(NTOTAL, intcmp), ih_insert(coll, array[i]), ih_remove_max(coll, &r),
// ih_contains(coll, sarray[i]))
// BENCHMARK(MULTIMAP, mm, mmap, mm_new(NTOTAL, 0.8, intcmp, inthash), mm_insert(coll, array[i], array[i]),
// mm_remove(coll, array[i], &r), mm_contains(coll, sarray[i]))
// BENCHMARK(MULTISET, ms, mset, ms_new(NTOTAL, 0.6, intcmp, inthash), ms_insert(coll, array[i]),
// ms_remove(coll, array[i]), ms_contains(coll, sarray[i]))
int main(void)
{
// Using the Mersenne Twister to generate random numbers. This seed
// guarantees that everytime this program runs it will generate the same
// random numbers. The random numbers influence on the shuffling of the
// array.
mt_state st;
twist_init(&st, UINT64_C(12604951237));
int *array = malloc(NTOTAL * sizeof(int));
int *sarray = malloc(NTOTAL * sizeof(int));
if (!array)
{
printf("Allocation failed\n");
return 1;
}
for (int i = -5000000; i < 5000000; i++)
array[i + 5000000] = i;
shuffle(array, &st);
memcpy(sarray, array, NTOTAL * sizeof(int));
shuffle(sarray, &st);
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n",
NTOTAL);
// Linear containers have to search for NMIN elements and non-linear (hash
// and tree) have to search for all elements.
struct cmc_timer timer;
cmc_timer_start(timer);
DEQUE_io_benchmark(array, sarray, NMIN);
// HASHMAP_io_benchmark(array, sarray, NTOTAL);
// HASHSET_io_benchmark(array, sarray, NTOTAL);
// HEAP_io_benchmark(array, sarray, NMIN);
// LINKEDLIST_io_benchmark(array, sarray, NMIN);
// LIST_io_benchmark(array, sarray, NMIN);
// QUEUE_io_benchmark(array, sarray, NMIN);
// STACK_io_benchmark(array, sarray, NMIN);
// TREEMAP_io_benchmark(array, sarray, NTOTAL);
// TREESET_io_benchmark(array, sarray, NTOTAL);
// INTERVALHEAP_io_benchmark(array, array, NMIN);
// MULTIMAP_io_benchmark(array, array, NTOTAL);
// MULTISET_io_benchmark(array, array, NTOTAL);
cmc_timer_stop(timer);
printf("+-----------------------------------------------------------+ \n");
printf("| Total Benchmark Running Time : %12.0lf seconds | \n", timer.result / 1000);
printf("+-----------------------------------------------------------+ \n");
free(array);
free(sarray);
return 0;
}
+18
View File
@@ -0,0 +1,18 @@
INCLUDE=-I ../../../src
CFLAGS=-O3 -Wall -DCOUNT=20000000 -DCMC_NO_CALLBACKS
# Install hyperfine
# https://github.com/sharkdp/hyperfine
run: build
hyperfine --warmup 2 --runs 5 './hashmap.exe'
hyperfine --warmup 2 --runs 5 './hashmultimap.exe'
hyperfine --warmup 2 --runs 5 './unorderedmap.exe'
build:
gcc hashmap.c -o hashmap.exe $(INCLUDE) $(CFLAGS)
gcc hashmultimap.c -o hashmultimap.exe $(INCLUDE) $(CFLAGS)
g++ unorderedmap.cpp $(INCLUDE) -o unorderedmap.exe $(CFLAGS)
clean:
rm *.exe
@@ -0,0 +1,55 @@
#ifndef COUNT
#error "Please define COUNT"
#endif
#include "murmurhash.h"
#include "../../util/twister.c"
#define K uint64_t
#define V uint64_t
#define PFX hm
#define SNAME hashmap
#include "cmc/hashmap.h"
int cmp(uint64_t a, uint64_t b)
{
return (a > b) - (a < b);
}
// size_t hash(uint64_t a)
// {
// size_t x = (size_t)a;
// x = ((x >> 16) ^ x) * 0x45d9f3b;
// x = ((x >> 16) ^ x) * 0x45d9f3b;
// x = (x >> 16) ^ x;
// return x;
// }
size_t hash(uint64_t k)
{
static size_t seed = 211106232532969;
return MurMurHash(&k, sizeof(k), seed);
}
struct hashmap_fkey *fkey = &(struct hashmap_fkey){ .cmp = cmp, .hash = hash, NULL };
struct hashmap_fval *fval = &(struct hashmap_fval){ .cmp = cmp, .hash = hash, NULL };
int main(void)
{
mt_state tw;
twist_init(&tw, 50331653);
struct hashmap *map = hm_new(COUNT, 0.6, fkey, fval);
for (uint64_t i = 0; i < COUNT; i++)
{
uint64_t v = twist_uint64(&tw);
hm_insert(map, v, v);
}
hm_free(map);
return 0;
}
@@ -0,0 +1,55 @@
#ifndef COUNT
#error "Please define COUNT"
#endif
#include "murmurhash.h"
#include "../../util/twister.c"
#define K uint64_t
#define V uint64_t
#define PFX hmm
#define SNAME hashmultimap
#include "cmc/hashmultimap.h"
int cmp(uint64_t a, uint64_t b)
{
return (a > b) - (a < b);
}
// size_t hash(uint64_t a)
// {
// size_t x = (size_t)a;
// x = ((x >> 16) ^ x) * 0x45d9f3b;
// x = ((x >> 16) ^ x) * 0x45d9f3b;
// x = (x >> 16) ^ x;
// return x;
// }
size_t hash(uint64_t k)
{
static size_t seed = 211106232532969;
return MurMurHash(&k, sizeof(k), seed);
}
struct hashmultimap_fkey *fkey = &(struct hashmultimap_fkey){ .cmp = cmp, .hash = hash, NULL };
struct hashmultimap_fval *fval = &(struct hashmultimap_fval){ .cmp = cmp, .hash = hash, NULL };
int main(void)
{
mt_state tw;
twist_init(&tw, 50331653);
struct hashmultimap *map = hmm_new(COUNT, 0.6, fkey, fval);
for (uint64_t i = 0; i < COUNT; i++)
{
uint64_t v = twist_uint64(&tw);
hmm_insert(map, v, v);
}
hmm_free(map);
return 0;
}
@@ -0,0 +1,58 @@
// https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/hash_bytes.cc
#ifndef MURMURHASH
#define MURMURHASH
#include <string.h>
inline size_t unaligned_load(const char *p)
{
size_t result;
memcpy(&result, p, sizeof(result));
return result;
}
inline size_t load_bytes(const char *p, int n)
{
size_t result = 0;
--n;
do
{
result = (result << 8) + (unsigned char)(p[n]);
} while (--n >= 0);
return result;
}
inline size_t shift_mix(size_t v)
{
return v ^ (v >> 47);
}
size_t MurMurHash(const void *ptr, size_t len, size_t seed)
{
static const size_t mul = (((size_t)0xc6a4a793UL) << 32UL) + (size_t)0x5bd1e995UL;
const char *const buf = (const char *)(ptr);
// Remove the bytes not divisible by the sizeof(size_t). This
// allows the main loop to process the data as 64-bit integers.
const size_t len_aligned = len & ~(size_t)0x7;
const char *const end = buf + len_aligned;
size_t hash = seed ^ (len * mul);
for (const char *p = buf; p != end; p += 8)
{
const size_t data = shift_mix(unaligned_load(p) * mul) * mul;
hash ^= data;
hash *= mul;
}
if ((len & 0x7) != 0)
{
const size_t data = load_bytes(end, len & 0x7);
hash ^= data;
hash *= mul;
}
hash = shift_mix(hash) * mul;
hash = shift_mix(hash);
return hash;
}
#endif /* MURMURHASH */
@@ -0,0 +1,34 @@
#ifndef COUNT
#error "Please define COUNT"
#endif
#include "murmurhash.h"
#include <unordered_map>
#include "../../util/twister.c"
struct IntHasher
{
std::size_t operator()(const uint64_t &k) const
{
static size_t seed = 211106232532969;
return MurMurHash(&k, sizeof(k), seed);
}
};
int main(void)
{
mt_state tw;
twist_init(&tw, 50331653);
std::unordered_map<uint64_t, uint64_t, IntHasher> map(COUNT);
for (uint64_t i = 0; i < COUNT; i++)
{
uint64_t v = twist_uint64(&tw);
map.insert({ v, v });
}
return 0;
}
+102
View File
@@ -0,0 +1,102 @@
/**
* twister.c
*
* Creation Date: 09/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Mersenne Twister PRNG utility
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define NN 312
#define MM 156
#define MATRIX_A UINT64_C(0xB5026F5AA96619E9)
#define UM UINT64_C(0xFFFFFFFF80000000) // Most significant 33 bits
#define LM UINT64_C(0x7FFFFFFF) // Least significant 31 bits
// State vector
typedef struct mt_state_s
{
uint64_t mt[NN];
int mti;
} mt_state, *mt_state_ptr;
// Initializes mt[NN] with a seed
void twist_init(mt_state_ptr st, uint64_t seed);
// Generates a random uint64_t in [0, 2^64-1] interval
uint64_t twist_uint64(mt_state_ptr st);
// Generates a double in [0, 1) interval
double twist_real(mt_state_ptr st);
//
// Implementation
//
// Initialize a state mt[NN] with a seed
void twist_init(mt_state_ptr st, uint64_t seed)
{
st->mti = NN + 1;
st->mt[0] = seed;
for (st->mti = 1; st->mti < NN; st->mti++)
{
st->mt[st->mti] = (UINT64_C(6364136223846793005) * (st->mt[st->mti - 1] ^ (st->mt[st->mti - 1] >> 62)) + st->mti);
}
}
// Generates a random uint64_t in [0, 2^64-1] interval
uint64_t twist_uint64(mt_state_ptr st)
{
int i;
uint64_t x;
static uint64_t mag01[2] = {UINT64_C(0), MATRIX_A};
if (st->mti >= NN)
{
// Generate NN words at one time if twist_init() has not been called
// A default initial seed is used
if (st->mti == NN + 1)
twist_init(st, UINT64_C(5489));
for (i = 0; i < NN - MM; i++)
{
x = (st->mt[i] & UM) | (st->mt[i + 1] & LM);
st->mt[i] = st->mt[i + MM] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
}
for (; i < NN - 1; i++)
{
x = (st->mt[i] & UM) | (st->mt[i + 1] & LM);
st->mt[i] = st->mt[i + (MM - NN)] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
}
x = (st->mt[NN - 1] & UM) | (st->mt[0] & LM);
st->mt[NN - 1] = st->mt[MM - 1] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
st->mti = 0;
}
x = st->mt[st->mti++];
x ^= (x >> 29) & UINT64_C(0x5555555555555555);
x ^= (x << 17) & UINT64_C(0x71D67FFFEDA60000);
x ^= (x << 37) & UINT64_C(0xFFF7EEE000000000);
x ^= (x >> 43);
return x;
}
// Generates a double in [0, 1) interval
double twist_real(mt_state_ptr st)
{
return (twist_uint64(st) >> 11) * (1.0 / 9007199254740992.0);
}