Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikwidlund committed Jan 18, 2017
2 parents a75884f + dd48fae commit 3e11527
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 106 deletions.
10 changes: 3 additions & 7 deletions benchmark/map.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ g1 <- ggplot(legend = TRUE) +
theme(plot.title = element_text(size = 10),
axis.title.x = element_text(size = 8), axis.title.y = element_text(size = 8),
axis.text.x = element_text(size = 8), axis.text.y = element_text(size = 8)) +
geom_smooth(method = "loess", span = 0.5, data = data.map, aes(x = size, y = insert, colour = name)) +
geom_smooth(method = "loess", span = 0.1, data = data.map, aes(x = size, y = insert, colour = name)) +
scale_y_continuous(labels = comma) +
expand_limits(y = 0) +
scale_x_continuous(trans = log_trans(), breaks = 10^(0:10), labels = comma)
Expand All @@ -23,7 +23,7 @@ g2 <- ggplot(legend = TRUE) +
theme(plot.title = element_text(size = 10),
axis.title.x = element_text(size = 8), axis.title.y = element_text(size = 8),
axis.text.x = element_text(size = 8), axis.text.y = element_text(size = 8)) +
geom_smooth(method = "loess", span = 0.5, data = data.map, aes(x = size, y = at, colour = name)) +
geom_smooth(method = "loess", span = 0.1, data = data.map, aes(x = size, y = at, colour = name)) +
scale_y_continuous(labels = comma) +
expand_limits(y = 0) +
scale_x_continuous(trans = log_trans(), breaks = 10^(0:10), labels = comma)
Expand All @@ -34,15 +34,11 @@ g3 <- ggplot(legend = TRUE) +
theme(plot.title = element_text(size = 10),
axis.title.x = element_text(size = 8), axis.title.y = element_text(size = 8),
axis.text.x = element_text(size = 8), axis.text.y = element_text(size = 8)) +
geom_smooth(method = "loess", span = 0.5, data = data.map, aes(x = size, y = erase, colour = name)) +
geom_smooth(method = "loess", span = 0.1, data = data.map, aes(x = size, y = erase, colour = name)) +
scale_y_continuous(labels = comma) +
expand_limits(y = 0) +
scale_x_continuous(trans = log_trans(), breaks = 10^(0:10), labels = comma)
g3$labels$colour <- "Implementation"

pdf("map.pdf", width = 10, height = 10)
grid.arrange(g1, g2, g3, ncol=1, top = "libdynamic map benchmark")
#dev.off()

# g4 <- grid.arrangeGrob(g1, g2, g3, ncol=1, top = "libdynamic map benchmark")
#ggsave(g4, file = "map.pdf", width = 10, height = 10)
41 changes: 35 additions & 6 deletions benchmark/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,21 @@
#include "map_dynamic.h"

static map_metric metrics[] = {
{.name = "std::map_unordered", .measure = map_unordered},
{.name = "custom open addressing", .measure = map_custom},
{.name = "libdynamic", .measure = map_dynamic},
{.name = "std::map_unordered", .measure = map_unordered},
{.name = "libdynamic (subclass)", .measure = map_subclass}
};

struct result
{
char *name;
size_t size;
double insert;
double at;
double erase;
};

uint64_t ntime(void)
{
struct timespec ts;
Expand All @@ -29,12 +38,14 @@ uint64_t ntime(void)

int main()
{
size_t i, n, n_min = 10, n_max = 1000000;
size_t i, n, n_min = 10, n_max = 1000000, round, rounds = 5;
double k = 1.1;
uint32_t *a;
map_metric *m;
vector results;
struct result result, *r;

(void) fprintf(stdout, "name,size,insert,at,erase\n");
vector_construct(&results, sizeof result);
for (n = n_min; n < n_max; n = ceil(k * n))
{
a = calloc(n, sizeof *a);
Expand All @@ -43,10 +54,28 @@ int main()

for (m = metrics; m < &metrics[sizeof metrics / sizeof metrics[0]]; m ++)
{
m->measure(m, a, n);
(void) fprintf(stdout, "%s,%lu,%f,%f,%f\n", m->name, n, m->insert, m->at, m->erase);
result = (struct result) {.name = m->name, .size = n};
for (round = 0; round < rounds; round ++)
{
m->measure(m, a, n);
if (!result.insert || m->insert < result.insert)
result.insert = m->insert;
if (!result.at || m->at < result.at)
result.at = m->at;
if (!result.erase || m->erase < result.erase)
result.erase = m->erase;
}
vector_push_back(&results, &result);
}

free(a);
}

(void) fprintf(stdout, "name,size,insert,at,erase\n");
for (i = 0; i < vector_size(&results); i ++)
{
r = vector_at(&results, i);
(void) fprintf(stdout, "%s,%lu,%f,%f,%f\n", r->name, r->size, r->insert, r->at, r->erase);
}

vector_destruct(&results);
}
44 changes: 44 additions & 0 deletions benchmark/map2.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env Rscript

library(ggplot2)
library(scales)
library(sitools)
library(gridExtra)

data.map <- read.csv("map.dat", head=TRUE, sep=",")

g1 <- ggplot(legend = TRUE) +
labs(list(title = "Insert", x = "Map size", y = "Time/Operation (ns)")) +
theme(plot.title = element_text(size = 10),
axis.title.x = element_text(size = 8), axis.title.y = element_text(size = 8),
axis.text.x = element_text(size = 8), axis.text.y = element_text(size = 8)) +
geom_line(data = data.map, aes(x = size, y = insert, colour = name)) +
scale_y_continuous(labels = comma) +
expand_limits(y = 0) +
scale_x_continuous(trans = log_trans(), breaks = 10^(0:10), labels = comma)
g1$labels$colour <- "Implementation"

g2 <- ggplot(legend = TRUE) +
labs(list(title = "Lookup", x = "Map size", y = "Time/Operation (ns)")) +
theme(plot.title = element_text(size = 10),
axis.title.x = element_text(size = 8), axis.title.y = element_text(size = 8),
axis.text.x = element_text(size = 8), axis.text.y = element_text(size = 8)) +
geom_line(data = data.map, aes(x = size, y = at, colour = name)) +
scale_y_continuous(labels = comma) +
expand_limits(y = 0) +
scale_x_continuous(trans = log_trans(), breaks = 10^(0:10), labels = comma)
g2$labels$colour <- "Implementation"

g3 <- ggplot(legend = TRUE) +
labs(list(title = "Delete", x = "Map size", y = "Time/Operation (ns)")) +
theme(plot.title = element_text(size = 10),
axis.title.x = element_text(size = 8), axis.title.y = element_text(size = 8),
axis.text.x = element_text(size = 8), axis.text.y = element_text(size = 8)) +
geom_line(data = data.map, aes(x = size, y = erase, colour = name)) +
scale_y_continuous(labels = comma) +
expand_limits(y = 0) +
scale_x_continuous(trans = log_trans(), breaks = 10^(0:10), labels = comma)
g3$labels$colour <- "Implementation"

pdf("map.pdf", width = 10, height = 10)
grid.arrange(g1, g2, g3, ncol=1, top = "libdynamic map benchmark")
11 changes: 8 additions & 3 deletions benchmark/map_dynamic.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,23 @@ static int equal(void *e1, void *e2)
return *(uint32_t *) e1 == *(uint32_t *) e2;
}

static void set(void *e1, void *e2)
{
*(uint64_t *) e1 = *(uint64_t *) e2;
}

void map_dynamic(map_metric *metric, uint32_t *a, size_t n)
{
map m;
map_element *e;
size_t i;
uint64_t t1, t2;

map_construct(&m, sizeof *e, (map_element[]) {{.key = -1}});
map_construct(&m, sizeof *e, (map_element[]) {{.key = -1}}, set);

t1 = ntime();
for (i = 0; i < n; i ++)
map_insert(&m, (map_element[]) {{.key = a[i], .value = 1}}, hash, equal, NULL);
map_insert(&m, (map_element[]) {{.key = a[i], .value = 1}}, hash, equal, set, NULL);
t2 = ntime();
metric->insert = (double) (t2 - t1) / n;

Expand All @@ -48,7 +53,7 @@ void map_dynamic(map_metric *metric, uint32_t *a, size_t n)

t1 = ntime();
for (i = 0; i < n; i ++)
map_erase(&m, (map_element[]){{.key = a[i]}}, hash, equal, NULL);
map_erase(&m, (map_element[]){{.key = a[i]}}, hash, equal, set, NULL);
t2 = ntime();
if (map_size(&m))
errx(1, "inconsistency");
Expand Down
11 changes: 8 additions & 3 deletions benchmark/map_subclass.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,19 @@ static size_t hash(void *e)
return *(uint32_t *) e;
}

static void set(void *dst, void *src)
{
*(uint64_t *) dst = *(uint64_t *) src;
}

static int equal(void *e1, void *e2)
{
return *(uint32_t *) e1 == *(uint32_t *) e2;
}

static void map_int_pair_construct(map_int_pair *m)
{
map_construct(m, sizeof(map_int_pair_element), &empty);
map_construct(m, sizeof(map_int_pair_element), &empty, set);
}

static void map_int_pair_destruct(map_int_pair *m)
Expand All @@ -46,12 +51,12 @@ static uint32_t map_int_pair_at(map_int_pair *m, uint32_t key)

static void map_int_pair_insert(map_int_pair *m, uint32_t key, uint32_t value)
{
map_insert(m,(map_int_pair_element[]){{.key = key, .value = value}}, hash, equal, NULL);
map_insert(m,(map_int_pair_element[]){{.key = key, .value = value}}, hash, equal, set, NULL);
}

static void map_int_pair_erase(map_int_pair *m, uint32_t key)
{
map_erase(m,(map_int_pair_element[]){{.key = key}}, hash, equal, NULL);
map_erase(m,(map_int_pair_element[]){{.key = key}}, hash, equal, set, NULL);
}

static size_t map_int_pair_size(map_int_pair *m)
Expand Down
74 changes: 40 additions & 34 deletions src/dynamic/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,22 @@ static inline void map_assert(int value)
abort();
}

static void *map_element(map *m, size_t position)
{
return (char *) m->elements + (position * m->element_size);
}

static void map_release_all(map *m, int (*equal)(void *, void *), void (*release)(void *))
{
size_t i;

if (release)
for (i = 0; i < m->elements_capacity; i ++)
if (!equal((char *) m->elements + (i * m->element_size), m->element_empty))
release((char *) m->elements + (i * m->element_size));
if (!equal(map_element(m, i), m->element_empty))
release(map_element(m, i));
}

static void *map_element(map *m, size_t position)
{
return (char *) m->elements + (position * m->element_size);
}

static void map_rehash(map *m, size_t size, size_t (*hash)(void *), int (*equal)(void *, void *))
static void map_rehash(map *m, size_t size, size_t (*hash)(void *), int (*equal)(void *, void *), void (*set)(void *, void *))
{
map new;
size_t i;
Expand All @@ -55,13 +55,13 @@ static void map_rehash(map *m, size_t size, size_t (*hash)(void *), int (*equal)
map_assert(new.elements != NULL);

for (i = 0; i < new.elements_capacity; i ++)
memcpy(map_element(&new, i), new.element_empty, new.element_size);
set(map_element(&new, i), new.element_empty);

if (m->elements)
{
for (i = 0; i < m->elements_capacity; i ++)
if (!equal(map_element(m, i), m->element_empty))
map_insert(&new, map_element(m, i), hash, equal, NULL);
map_insert(&new, map_element(m, i), hash, equal, set, NULL);
free(m->elements);
}

Expand All @@ -70,14 +70,14 @@ static void map_rehash(map *m, size_t size, size_t (*hash)(void *), int (*equal)

/* constructor/destructor */

void map_construct(map *m, size_t element_size, void *element_empty)
void map_construct(map *m, size_t element_size, void *element_empty, void (*set)(void *, void *))
{
m->elements = NULL;
m->elements_count = 0;
m->elements_capacity = 0;
m->element_size = element_size;
m->element_empty = element_empty;
map_rehash(m, MAP_ELEMENTS_CAPACITY_MIN, NULL, NULL);
map_rehash(m, MAP_ELEMENTS_CAPACITY_MIN, NULL, NULL, set);
}

void map_destruct(map *m, int (*equal)(void *, void *), void (*release)(void *))
Expand All @@ -93,11 +93,11 @@ size_t map_size(map *m)
return m->elements_count;
}

void map_reserve(map *m, size_t size, size_t (*hash)(void *), int (*equal)(void *, void *))
void map_reserve(map *m, size_t size, size_t (*hash)(void *), int (*equal)(void *, void *), void (*set)(void *, void *))
{
size *= 2;
if (size > m->elements_capacity)
map_rehash(m, size, hash, equal);
map_rehash(m, size, hash, equal, set);
}

/* element access */
Expand Down Expand Up @@ -125,38 +125,43 @@ void *map_at(map *m, void *element, size_t (*hash)(void *), int (*equal)(void *,

/* modifiers */

void map_insert(map *m, void *element, size_t (*hash)(void *), int (*equal)(void *, void *), void (*release)(void *))
void map_insert(map *m, void *element, size_t (*hash)(void *), int (*equal)(void *, void *), void (*set)(void *, void *), void (*release)(void *))
{
void *test;

map_reserve(m, m->elements_count + 1, hash, equal);
map_reserve(m, m->elements_count + 1, hash, equal, set);
test = map_at(m, element, hash, equal);
if (equal(test, m->element_empty))
{
memcpy(test, element, m->element_size);
set(test, element);
m->elements_count ++;
}
else
{
if (release)
release(element);
}
else if (release)
release(element);
}

void map_erase(map *m, void *element, size_t (*hash)(void *), int (*equal)(void *, void *), void (*release)(void *))
void map_erase(map *m, void *element, size_t (*hash)(void *), int (*equal)(void *, void *), void (*set)(void *, void *), void (*release)(void *))
{
void *test;
size_t i, j, k;

test = map_at(m, element, hash, equal);
if (equal(test, m->element_empty))
return;

if (release)
release(test);
i = hash(element);
while (1)
{
i &= m->elements_capacity - 1;
test = map_element(m, i);
if (equal(test, m->element_empty))
return;
if (equal(test, element))
{
if (release)
release(test);
break;
}
i ++;
}
m->elements_count --;

i = ((char *) test - (char *) m->elements) / m->element_size;
j = i;
while (1)
{
Expand All @@ -168,20 +173,21 @@ void map_erase(map *m, void *element, size_t (*hash)(void *), int (*equal)(void
if ((i < j && (k <= i || k > j)) ||
(i > j && (k <= i && k > j)))
{
memcpy(map_element(m, i), map_element(m, j), m->element_size);
set(map_element(m, i), map_element(m, j));
i = j;
}
}

memcpy(map_element(m, i), m->element_empty, m->element_size);
set(map_element(m, i), m->element_empty);
}

void map_clear(map *m, int (*equal)(void *, void *), void (*release)(void *))
void map_clear(map *m, int (*equal)(void *, void *), void (*set)(void *, void *), void (*release)(void *))
{
map_release_all(m, equal, release);
free(m->elements);
m->elements = NULL;
m->elements_count = 0;
m->elements_capacity = 0;
map_rehash(m, MAP_ELEMENTS_CAPACITY_MIN, NULL, NULL);
map_rehash(m, MAP_ELEMENTS_CAPACITY_MIN, NULL, NULL, set);
}

0 comments on commit 3e11527

Please sign in to comment.