Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/lib/libc/cdb Use a more efficient data structure for graph p...
details: https://anonhg.NetBSD.org/src/rev/13a6d66c96a6
branches: trunk
changeset: 357455:13a6d66c96a6
user: alnsn <alnsn%NetBSD.org@localhost>
date: Sat Nov 11 18:05:31 2017 +0000
description:
Use a more efficient data structure for graph peeling.
New code is about 50% faster on amd64 and it consumes less memory.
diffstat:
lib/libc/cdb/cdbw.c | 173 +++++++++++++++++++++------------------------------
1 files changed, 71 insertions(+), 102 deletions(-)
diffs (273 lines):
diff -r b63cd4d351fd -r 13a6d66c96a6 lib/libc/cdb/cdbw.c
--- a/lib/libc/cdb/cdbw.c Sat Nov 11 17:37:03 2017 +0000
+++ b/lib/libc/cdb/cdbw.c Sat Nov 11 18:05:31 2017 +0000
@@ -1,10 +1,10 @@
-/* $NetBSD: cdbw.c,v 1.5 2012/07/21 22:49:37 joerg Exp $ */
+/* $NetBSD: cdbw.c,v 1.6 2017/11/11 18:05:31 alnsn Exp $ */
/*-
- * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
+ * Copyright (c) 2009, 2010, 2015 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Joerg Sonnenberger.
+ * by Joerg Sonnenberger and Alexander Nasonov.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,7 +36,7 @@
#endif
#include <sys/cdefs.h>
-__RCSID("$NetBSD: cdbw.c,v 1.5 2012/07/21 22:49:37 joerg Exp $");
+__RCSID("$NetBSD: cdbw.c,v 1.6 2017/11/11 18:05:31 alnsn Exp $");
#include "namespace.h"
@@ -278,18 +278,31 @@
return 0;
}
-#define unused 0xffffffffU
+/*
+ * The algorithm below is based on paper
+ * Cache-Oblivious Peeling of Random Hypergraphs by Djamal Belazzougui,
+ * Paolo Boldi, Giuseppe Ottaviano, Rossano Venturini, and Sebastiano
+ * Vigna.
+ * http://zola.di.unipi.it/rossano/wp-content/papercite-data/pdf/dcc14.pdf
+ */
-struct vertex {
- uint32_t l_edge, m_edge, r_edge;
+/*
+ * Data type for a valid oriented edge (v0, v1, v2), v1 < v2.
+ * The first vertex v0 is implicit and is determined by an index
+ * of the corresponding element in the state->oedges array.
+ * If the degree of v0 is greater than 1, other members don't
+ * make sense because they're a result of XORing multiple values.
+ */
+struct oedge {
+ uint32_t degree; /* Degree of v0. */
+ uint32_t verts[2]; /* v1 and v2 */
+ uint32_t edge;
};
struct edge {
uint32_t idx;
uint32_t left, middle, right;
- uint32_t l_prev, m_prev, l_next;
- uint32_t r_prev, m_next, r_next;
};
struct state {
@@ -301,69 +314,49 @@
uint32_t *g;
char *visited;
- struct vertex *verts;
+ struct oedge *oedges;
struct edge *edges;
uint32_t output_index;
uint32_t *output_order;
};
-static void
-remove_vertex(struct state *state, struct vertex *v)
+/*
+ * Add (delta == 1) or remove (delta == -1) the edge e from vertex v0.
+ */
+static inline void
+add_remove_edge(struct oedge *o, int delta, uint32_t e,
+ uint32_t v0, uint32_t v1, uint32_t v2)
{
- struct edge *e;
- struct vertex *vl, *vm, *vr;
- if (v->l_edge != unused && v->m_edge != unused)
- return;
- if (v->l_edge != unused && v->r_edge != unused)
- return;
- if (v->m_edge != unused && v->r_edge != unused)
- return;
- if (v->l_edge == unused && v->m_edge == unused && v->r_edge == unused)
- return;
+ o[v0].verts[v1 < v2 ? 0 : 1] ^= v1;
+ o[v0].verts[v1 < v2 ? 1 : 0] ^= v2;
+ o[v0].degree += delta;
+ o[v0].edge ^= e;
+}
+
+static inline void
+add_edge(struct oedge *o, uint32_t e,
+ uint32_t v0, uint32_t v1, uint32_t v2)
+{
- if (v->l_edge != unused) {
- e = &state->edges[v->l_edge];
- if (e->l_next != unused)
- return;
- } else if (v->m_edge != unused) {
- e = &state->edges[v->m_edge];
- if (e->m_next != unused)
- return;
- } else {
- if (v->r_edge == unused)
- abort();
- e = &state->edges[v->r_edge];
- if (e->r_next != unused)
- return;
- }
+ add_remove_edge(o, 1, e, v0, v1, v2);
+}
- state->output_order[--state->output_index] = e - state->edges;
+static inline void
+remove_vertex(struct state *state, uint32_t v0)
+{
+ uint32_t e, v1, v2;
+ struct oedge *o = state->oedges;
- vl = &state->verts[e->left];
- vm = &state->verts[e->middle];
- vr = &state->verts[e->right];
-
- if (e->l_prev == unused)
- vl->l_edge = e->l_next;
- else
- state->edges[e->l_prev].l_next = e->l_next;
- if (e->l_next != unused)
- state->edges[e->l_next].l_prev = e->l_prev;
-
- if (e->m_prev == unused)
- vm->m_edge = e->m_next;
- else
- state->edges[e->m_prev].m_next = e->m_next;
- if (e->m_next != unused)
- state->edges[e->m_next].m_prev = e->m_prev;
-
- if (e->r_prev == unused)
- vr->r_edge = e->r_next;
- else
- state->edges[e->r_prev].r_next = e->r_next;
- if (e->r_next != unused)
- state->edges[e->r_next].r_prev = e->r_prev;
+ if (o[v0].degree == 1) {
+ e = o[v0].edge;
+ v1 = o[v0].verts[0];
+ v2 = o[v0].verts[1];
+ o[v0].degree = 0;
+ add_remove_edge(o, -1, e, v1, v0, v2);
+ add_remove_edge(o, -1, e, v2, v0, v1);
+ state->output_order[--state->output_index] = e;
+ }
}
static int
@@ -371,11 +364,12 @@
{
struct key_hash_head *head;
struct key_hash *key_hash;
- struct vertex *v;
struct edge *e;
uint32_t hashes[3];
size_t i;
+ memset(state->oedges, 0, sizeof(struct oedge) * state->entries);
+
e = state->edges;
for (i = 0; i < cdbw->hash_size; ++i) {
head = &cdbw->hash[i];
@@ -389,57 +383,32 @@
if (e->left == e->middle)
return -1;
+ add_edge(state->oedges, e - state->edges,
+ e->right, e->left, e->middle);
if (e->left == e->right)
return -1;
+ add_edge(state->oedges, e - state->edges,
+ e->middle, e->left, e->right);
if (e->middle == e->right)
return -1;
+ add_edge(state->oedges, e - state->edges,
+ e->left, e->middle, e->right);
++e;
}
}
- for (i = 0; i < state->entries; ++i) {
- v = state->verts + i;
- v->l_edge = unused;
- v->m_edge = unused;
- v->r_edge = unused;
- }
-
- for (i = 0; i < state->keys; ++i) {
- e = state->edges + i;
- v = state->verts + e->left;
- if (v->l_edge != unused)
- state->edges[v->l_edge].l_prev = i;
- e->l_next = v->l_edge;
- e->l_prev = unused;
- v->l_edge = i;
-
- v = &state->verts[e->middle];
- if (v->m_edge != unused)
- state->edges[v->m_edge].m_prev = i;
- e->m_next = v->m_edge;
- e->m_prev = unused;
- v->m_edge = i;
-
- v = &state->verts[e->right];
- if (v->r_edge != unused)
- state->edges[v->r_edge].r_prev = i;
- e->r_next = v->r_edge;
- e->r_prev = unused;
- v->r_edge = i;
- }
-
state->output_index = state->keys;
for (i = 0; i < state->entries; ++i)
- remove_vertex(state, state->verts + i);
+ remove_vertex(state, i);
i = state->keys;
while (i > 0 && i > state->output_index) {
--i;
e = state->edges + state->output_order[i];
- remove_vertex(state, state->verts + e->left);
- remove_vertex(state, state->verts + e->middle);
- remove_vertex(state, state->verts + e->right);
+ remove_vertex(state, e->left);
+ remove_vertex(state, e->middle);
+ remove_vertex(state, e->right);
}
return state->output_index == 0 ? 0 : -1;
@@ -590,12 +559,12 @@
#define NALLOC(var, n) var = calloc(sizeof(*var), n)
NALLOC(state.g, state.entries);
NALLOC(state.visited, state.entries);
- NALLOC(state.verts, state.entries);
- NALLOC(state.edges, state.entries);
+ NALLOC(state.oedges, state.entries);
+ NALLOC(state.edges, state.keys);
NALLOC(state.output_order, state.keys);
#undef NALLOC
- if (state.g == NULL || state.visited == NULL || state.verts == NULL ||
+ if (state.g == NULL || state.visited == NULL || state.oedges == NULL ||
state.edges == NULL || state.output_order == NULL) {
rv = -1;
goto release;
@@ -615,7 +584,7 @@
release:
free(state.g);
free(state.visited);
- free(state.verts);
+ free(state.oedges);
free(state.edges);
free(state.output_order);
Home |
Main Index |
Thread Index |
Old Index