Files
2023-01-23 10:08:14 +01:00

297 lines
9.6 KiB
C

/**
* 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/cor/hashtable.h"
#include "cmc/cor/heap.h"
#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
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;
}
}
struct
{
CMC_DEF_FTAB_CMP(size_t);
CMC_DEF_FTAB_CPY(size_t);
CMC_DEF_FTAB_STR(size_t);
CMC_DEF_FTAB_FREE(size_t);
CMC_DEF_FTAB_HASH(size_t);
CMC_DEF_FTAB_PRI(size_t);
} int_ftab = { cmc_size_cmp, NULL, cmc_size_str, NULL, cmc_size_hash, cmc_size_cmp };
#define CMC_ARGS_FALLTHROUGH
#define V int
#define K int
#define CMC_EXT_ITER
#define SNAME bitset
#define PFX bs
#include "cmc/bitset.h"
#define SNAME deque
#define PFX d
#include "cmc/deque.h"
#define SNAME hashbidimap
#define PFX hbm
#include "cmc/hashbidimap.h"
#define SNAME hashmap
#define PFX hm
#include "cmc/hashmap.h"
#define SNAME hashmultimap
#define PFX hmm
#include "cmc/hashmultimap.h"
#define SNAME hashmultiset
#define PFX hms
#include "cmc/hashmultiset.h"
#define SNAME hashset
#define PFX hs
#include "cmc/hashset.h"
#define SNAME heap
#define PFX h
#include "cmc/heap.h"
#define SNAME intervalheap
#define PFX ih
#include "cmc/intervalheap.h"
#define SNAME linkedlist
#define PFX ll
#include "cmc/linkedlist.h"
#define SNAME list
#define PFX l
#include "cmc/list.h"
#define SNAME queue
#define PFX q
#include "cmc/queue.h"
#define SNAME sortedlist
#define PFX sl
#include "cmc/sortedlist.h"
#define SNAME stack
#define PFX s
#include "cmc/stack.h"
#define SNAME treemap
#define PFX tm
#include "cmc/treemap.h"
#define SNAME treeset
#define PFX ts
#include "cmc/treeset.h"
#undef CMC_ARGS_FALLTHROUGH
#include "cmc/cor/undef.h"
#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; \
CMC_UNUSED int r; \
\
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 *)&int_ftab), d_push_back(coll, array[i]), d_pop_back(coll),
d_contains(coll, sarray[i]))
BENCHMARK(HASHMAP, hm, hashmap, hm_new(NTOTAL, 0.6, (struct hashmap_fkey *)&int_ftab, (struct hashmap_fval *)&int_ftab),
hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
BENCHMARK(HASHSET, hs, hashset, hs_new(NTOTAL, 0.6, (struct hashset_fval *)&int_ftab), 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, (struct heap_fval *)&int_ftab), h_insert(coll, array[i]),
h_remove(coll), h_contains(coll, sarray[i]))
BENCHMARK(LINKEDLIST, ll, linkedlist, ll_new((struct linkedlist_fval *)&int_ftab), ll_push_back(coll, array[i]),
ll_pop_back(coll), ll_contains(coll, sarray[i]))
BENCHMARK(LIST, l, list, l_new(NTOTAL, (struct list_fval *)&int_ftab), l_push_back(coll, array[i]), l_pop_back(coll),
l_contains(coll, sarray[i]))
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL, (struct queue_fval *)&int_ftab), q_enqueue(coll, array[i]), q_dequeue(coll),
q_contains(coll, sarray[i]))
BENCHMARK(STACK, s, stack, s_new(NTOTAL, (struct stack_fval *)&int_ftab), s_push(coll, array[i]), s_pop(coll),
s_contains(coll, sarray[i]))
BENCHMARK(TREEMAP, tm, treemap, tm_new((struct treemap_fkey *)&int_ftab, (struct treemap_fval *)&int_ftab),
tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
BENCHMARK(TREESET, ts, treeset, ts_new((struct treeset_fval *)&int_ftab), ts_insert(coll, array[i]),
ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
BENCHMARK(INTERVALHEAP, ih, intervalheap, ih_new(NTOTAL, (struct intervalheap_fval *)&int_ftab),
ih_insert(coll, array[i]), ih_remove_max(coll), ih_contains(coll, sarray[i]))
BENCHMARK(MULTIMAP, hmm, hashmultimap,
hmm_new(NTOTAL, 0.8, (struct hashmultimap_fkey *)&int_ftab, (struct hashmultimap_fval *)&int_ftab),
hmm_insert(coll, array[i], array[i]), hmm_remove(coll, array[i], &r), hmm_contains(coll, sarray[i]))
BENCHMARK(MULTISET, hms, hashmultiset, hms_new(NTOTAL, 0.6, (struct hashmultiset_fval *)&int_ftab),
hms_insert(coll, array[i]), hms_remove(coll, array[i]), hms_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;
}