Optimize nbperf
- add fudge mode which gives a slightly slower hash function, but works almost always in the first iteration by avoiding degenerate edges - avoid keeping incidence lists around reducing the memory foot print by 30% - split edge processing from hashing as in the non-fudge case it is a reasonable costly part that often gets thrown away - merge graph2 and graph3 routines now that they are mostly the same
This commit is contained in:
parent
bb682c3920
commit
7c219dd6db
@ -1,4 +1,4 @@
|
||||
# $NetBSD: t_nbperf.sh,v 1.3 2014/04/30 21:04:21 joerg Exp $
|
||||
# $NetBSD: t_nbperf.sh,v 1.4 2021/01/07 16:03:08 joerg Exp $
|
||||
#
|
||||
# Copyright (c) 2012 The NetBSD Foundation, Inc.
|
||||
# All rights reserved.
|
||||
@ -27,7 +27,7 @@
|
||||
|
||||
cleanup()
|
||||
{
|
||||
rm -f reference.txt hash.c hash.map testprog
|
||||
rm -f reference.txt input.txt hash.c hash.map testprog
|
||||
}
|
||||
|
||||
atf_test_case chm
|
||||
@ -38,7 +38,7 @@ chm_head()
|
||||
atf_set "require.progs" "cc"
|
||||
}
|
||||
chm_body()
|
||||
{
|
||||
{
|
||||
for n in 4 32 128 1024 65536; do
|
||||
seq 0 $(($n - 1)) > reference.txt
|
||||
atf_check -o file:reference.txt \
|
||||
@ -54,6 +54,32 @@ chm_clean()
|
||||
cleanup
|
||||
}
|
||||
|
||||
atf_test_case chm_fudged
|
||||
chm_fudged_head()
|
||||
{
|
||||
atf_set "descr" "Checks chm algorithm with fudged hash"
|
||||
atf_set "require.progs" "cc"
|
||||
}
|
||||
chm_fudged_body()
|
||||
{
|
||||
seq 0 9 > reference.txt
|
||||
seq 1 10 > input.txt
|
||||
|
||||
atf_check -o file:reference.txt \
|
||||
$(atf_get_srcdir)/h_nbperf input.txt "chm -p" cat \
|
||||
10 $(atf_get_srcdir)/hash_driver.c
|
||||
atf_check -s exit:1 fgrep -q '^=' hash.c
|
||||
|
||||
atf_check -o file:reference.txt \
|
||||
$(atf_get_srcdir)/h_nbperf input.txt "chm -f -p" cat \
|
||||
10 $(atf_get_srcdir)/hash_driver.c
|
||||
atf_check -s exit:0 fgrep -q '^=' hash.c
|
||||
}
|
||||
chm_fudged_clean()
|
||||
{
|
||||
cleanup
|
||||
}
|
||||
|
||||
atf_test_case chm3
|
||||
chm3_head()
|
||||
{
|
||||
@ -78,26 +104,102 @@ chm3_clean()
|
||||
cleanup
|
||||
}
|
||||
|
||||
atf_test_case bdz
|
||||
bdz_head()
|
||||
atf_test_case chm3_fudged
|
||||
chm3_fudged_head()
|
||||
{
|
||||
atf_set "descr" "Checks bdz algorithm"
|
||||
atf_set "descr" "Checks chm3 algorithm with fudged hash"
|
||||
atf_set "require.progs" "cc"
|
||||
}
|
||||
chm3_fudged_body()
|
||||
{
|
||||
seq 0 9 > reference.txt
|
||||
seq 1 10 > input.txt
|
||||
|
||||
atf_check -o file:reference.txt \
|
||||
$(atf_get_srcdir)/h_nbperf input.txt "chm3 -p" cat \
|
||||
10 $(atf_get_srcdir)/hash_driver.c
|
||||
atf_check -s exit:1 fgrep -q '^=' hash.c
|
||||
|
||||
atf_check -o file:reference.txt \
|
||||
$(atf_get_srcdir)/h_nbperf input.txt "chm3 -f -p" cat \
|
||||
10 $(atf_get_srcdir)/hash_driver.c
|
||||
atf_check -s exit:0 fgrep -q '^= (' hash.c
|
||||
atf_check -s exit:0 fgrep -q '^= 2' hash.c
|
||||
}
|
||||
chm3_fudged_clean()
|
||||
{
|
||||
cleanup
|
||||
}
|
||||
|
||||
atf_test_case bpz
|
||||
bpz_head()
|
||||
{
|
||||
atf_set "descr" "Checks bpz algorithm"
|
||||
atf_set "require.files" "/usr/share/dict/web2"
|
||||
atf_set "require.progs" "cc"
|
||||
}
|
||||
bdz_body()
|
||||
{
|
||||
bpz_body()
|
||||
{
|
||||
for n in 4 32 128 1024 65536 131072; do
|
||||
seq 0 $(($n - 1)) > reference.txt
|
||||
atf_check -o file:reference.txt \
|
||||
$(atf_get_srcdir)/h_nbperf /usr/share/dict/web2 bdz "sort -n" \
|
||||
$(atf_get_srcdir)/h_nbperf /usr/share/dict/web2 bpz "sort -n" \
|
||||
$n $(atf_get_srcdir)/hash_driver.c
|
||||
atf_check -o file:hash.map \
|
||||
$(atf_get_srcdir)/h_nbperf /usr/share/dict/web2 bdz cat \
|
||||
$(atf_get_srcdir)/h_nbperf /usr/share/dict/web2 bpz cat \
|
||||
$n $(atf_get_srcdir)/hash_driver.c
|
||||
done
|
||||
}
|
||||
bdz_clean()
|
||||
bpz_clean()
|
||||
{
|
||||
cleanup
|
||||
}
|
||||
|
||||
atf_test_case bpz_fudged
|
||||
bpz_fudged_head()
|
||||
{
|
||||
atf_set "descr" "Checks bpz algorithm with fudged hash"
|
||||
atf_set "require.progs" "cc"
|
||||
}
|
||||
bpz_fudged_body()
|
||||
{
|
||||
seq 0 9 > reference.txt
|
||||
seq 1 10 > input.txt
|
||||
|
||||
atf_check -o file:reference.txt \
|
||||
$(atf_get_srcdir)/h_nbperf input.txt "bpz -p" "sort -n" \
|
||||
10 $(atf_get_srcdir)/hash_driver.c
|
||||
atf_check -s exit:1 fgrep -q '^=' hash.c
|
||||
|
||||
atf_check -o file:reference.txt \
|
||||
$(atf_get_srcdir)/h_nbperf input.txt "bpz -f -p" "sort -n" \
|
||||
10 $(atf_get_srcdir)/hash_driver.c
|
||||
atf_check -s exit:0 fgrep -q '^= (' hash.c
|
||||
atf_check -s exit:0 fgrep -q '^= 2' hash.c
|
||||
}
|
||||
bpz_fudged_clean()
|
||||
{
|
||||
cleanup
|
||||
}
|
||||
|
||||
atf_test_case handle_dup
|
||||
handle_dup_head()
|
||||
{
|
||||
atf_set "descr" "Checks different algorithms deal with duplicates"
|
||||
atf_set "require.progs" "cc"
|
||||
}
|
||||
handle_dup_body()
|
||||
{
|
||||
seq 0 9 > reference.txt
|
||||
echo 0 >> reference.txt
|
||||
atf_check -s exit:1 -e match:"nbperf: Duplicate keys detected" \
|
||||
nbperf -a chm < reference.txt
|
||||
atf_check -s exit:1 -e match:"nbperf: Duplicate keys detected" \
|
||||
nbperf -a chm3 < reference.txt
|
||||
atf_check -s exit:1 -e match:"nbperf: Duplicate keys detected" \
|
||||
nbperf -a bpz < reference.txt
|
||||
}
|
||||
handle_dup_clean()
|
||||
{
|
||||
cleanup
|
||||
}
|
||||
@ -105,6 +207,10 @@ bdz_clean()
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case chm
|
||||
atf_add_test_case chm_fudged
|
||||
atf_add_test_case chm3
|
||||
atf_add_test_case bdz
|
||||
atf_add_test_case chm3_fudged
|
||||
atf_add_test_case bpz
|
||||
atf_add_test_case bpz_fudged
|
||||
atf_add_test_case handle_dup
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: graph2.c,v 1.4 2011/10/21 23:47:11 joerg Exp $ */
|
||||
/* $NetBSD: graph2.c,v 1.5 2021/01/07 16:03:08 joerg Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
@ -36,7 +36,7 @@
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: graph2.c,v 1.4 2011/10/21 23:47:11 joerg Exp $");
|
||||
__RCSID("$NetBSD: graph2.c,v 1.5 2021/01/07 16:03:08 joerg Exp $");
|
||||
|
||||
#include <err.h>
|
||||
#include <inttypes.h>
|
||||
@ -47,16 +47,14 @@ __RCSID("$NetBSD: graph2.c,v 1.4 2011/10/21 23:47:11 joerg Exp $");
|
||||
#include "nbperf.h"
|
||||
#include "graph2.h"
|
||||
|
||||
static const uint32_t unused = 0xffffffffU;
|
||||
|
||||
void
|
||||
graph2_setup(struct graph2 *graph, uint32_t v, uint32_t e)
|
||||
SIZED2(_setup)(struct SIZED(graph) *graph, uint32_t v, uint32_t e)
|
||||
{
|
||||
graph->v = v;
|
||||
graph->e = e;
|
||||
|
||||
graph->verts = calloc(sizeof(struct vertex2), v);
|
||||
graph->edges = calloc(sizeof(struct edge2), e);
|
||||
graph->verts = calloc(sizeof(*graph->verts), v);
|
||||
graph->edges = calloc(sizeof(*graph->edges), e);
|
||||
graph->output_order = calloc(sizeof(uint32_t), e);
|
||||
|
||||
if (graph->verts == NULL || graph->edges == NULL ||
|
||||
@ -65,7 +63,7 @@ graph2_setup(struct graph2 *graph, uint32_t v, uint32_t e)
|
||||
}
|
||||
|
||||
void
|
||||
graph2_free(struct graph2 *graph)
|
||||
SIZED2(_free)(struct SIZED(graph) *graph)
|
||||
{
|
||||
free(graph->verts);
|
||||
free(graph->edges);
|
||||
@ -76,136 +74,180 @@ graph2_free(struct graph2 *graph)
|
||||
graph->output_order = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
graph2_check_duplicates(struct nbperf *nbperf, struct graph2 *graph)
|
||||
{
|
||||
struct vertex2 *v;
|
||||
struct edge2 *e, *e2;
|
||||
uint32_t i, j;
|
||||
static struct nbperf *sorting_nbperf;
|
||||
static struct SIZED(graph) *sorting_graph;
|
||||
static int sorting_found;
|
||||
|
||||
for (i = 0; i < graph->e; ++i) {
|
||||
e = &graph->edges[i];
|
||||
v = &graph->verts[e->left];
|
||||
j = v->l_edge;
|
||||
e2 = &graph->edges[j];
|
||||
for (;;) {
|
||||
if (i < j && e->right == e2->right &&
|
||||
nbperf->keylens[i] == nbperf->keylens[j] &&
|
||||
memcmp(nbperf->keys[i], nbperf->keys[j],
|
||||
nbperf->keylens[i]) == 0) {
|
||||
nbperf->has_duplicates = 1;
|
||||
return -1;
|
||||
}
|
||||
if (e2->l_next == unused)
|
||||
break;
|
||||
j = e2->l_next;
|
||||
e2 = &graph->edges[j];
|
||||
}
|
||||
static int sorting_cmp(const void *a_, const void *b_)
|
||||
{
|
||||
const uint32_t *a = a_, *b = b_;
|
||||
int i;
|
||||
const struct SIZED(edge) *ea = &sorting_graph->edges[*a],
|
||||
*eb = &sorting_graph->edges[*b];
|
||||
for (i = 0; i < GRAPH_SIZE; ++i) {
|
||||
if (ea->vertices[i] < eb->vertices[i])
|
||||
return -1;
|
||||
if (ea->vertices[i] > eb->vertices[i])
|
||||
return 1;
|
||||
}
|
||||
if (sorting_nbperf->keylens[*a] < sorting_nbperf->keylens[*b])
|
||||
return -1;
|
||||
if (sorting_nbperf->keylens[*a] > sorting_nbperf->keylens[*b])
|
||||
return 1;
|
||||
i = memcmp(sorting_nbperf->keys[*a], sorting_nbperf->keys[*b],
|
||||
sorting_nbperf->keylens[*a]);
|
||||
if (i == 0)
|
||||
sorting_found = 1;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int
|
||||
SIZED2(_check_duplicates)(struct nbperf *nbperf, struct SIZED(graph) *graph)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t *key_index = calloc(sizeof(*key_index), graph->e);
|
||||
|
||||
if (key_index == NULL)
|
||||
err(1, "malloc failed");
|
||||
for (i = 0; i < graph->e; ++i)
|
||||
key_index[i] = i;
|
||||
|
||||
sorting_nbperf = nbperf;
|
||||
sorting_graph = graph;
|
||||
sorting_found = 0;
|
||||
qsort(key_index, graph->e, sizeof(*key_index), sorting_cmp);
|
||||
if (sorting_found)
|
||||
goto found_dups;
|
||||
/*
|
||||
* Any duplicate must have been found as part of the qsort,
|
||||
* as it can't sort consecutive elements in the output without
|
||||
* comparing them at least once.
|
||||
*/
|
||||
|
||||
free(key_index);
|
||||
return 0;
|
||||
found_dups:
|
||||
nbperf->has_duplicates = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIZED2(_add_edge)(struct SIZED(graph) *graph, uint32_t edge)
|
||||
{
|
||||
struct SIZED(edge) *e = graph->edges + edge;
|
||||
struct SIZED(vertex) *v;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < GRAPH_SIZE; ++i) {
|
||||
v = graph->verts + e->vertices[i];
|
||||
v->edges ^= edge;
|
||||
++v->degree;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIZED2(_remove_edge)(struct SIZED(graph) *graph, uint32_t edge)
|
||||
{
|
||||
struct SIZED(edge) *e = graph->edges + edge;
|
||||
struct SIZED(vertex) *v;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < GRAPH_SIZE; ++i) {
|
||||
v = graph->verts + e->vertices[i];
|
||||
v->edges ^= edge;
|
||||
--v->degree;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIZED2(_remove_vertex)(struct SIZED(graph) *graph, uint32_t vertex)
|
||||
{
|
||||
struct SIZED(vertex) *v = graph->verts + vertex;
|
||||
uint32_t e;
|
||||
|
||||
if (v->degree == 1) {
|
||||
e = v->edges;
|
||||
graph->output_order[--graph->output_index] = e;
|
||||
SIZED2(_remove_edge)(graph, e);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
graph2_hash(struct nbperf *nbperf, struct graph2 *graph)
|
||||
SIZED2(_hash)(struct nbperf *nbperf, struct SIZED(graph) *graph)
|
||||
{
|
||||
struct vertex2 *v;
|
||||
struct SIZED(edge) *e;
|
||||
uint32_t hashes[NBPERF_MAX_HASH_SIZE];
|
||||
size_t i;
|
||||
size_t i, j;
|
||||
|
||||
#if GRAPH_SIZE == 2
|
||||
if (nbperf->allow_hash_fudging && (graph->v & 1) != 1)
|
||||
errx(1, "vertex count must have lowest bit set");
|
||||
#else
|
||||
if (nbperf->allow_hash_fudging && (graph->v & 3) != 3)
|
||||
errx(1, "vertex count must have lowest 2 bits set");
|
||||
#endif
|
||||
|
||||
|
||||
memset(graph->verts, 0, sizeof(*graph->verts) * graph->v);
|
||||
graph->hash_fudge = 0;
|
||||
|
||||
for (i = 0; i < graph->e; ++i) {
|
||||
(*nbperf->compute_hash)(nbperf,
|
||||
nbperf->keys[i], nbperf->keylens[i], hashes);
|
||||
graph->edges[i].left = hashes[0] % graph->v;
|
||||
graph->edges[i].right = hashes[1] % graph->v;
|
||||
if (graph->edges[i].left == graph->edges[i].right)
|
||||
return -1;
|
||||
e = graph->edges + i;
|
||||
for (j = 0; j < GRAPH_SIZE; ++j) {
|
||||
e->vertices[j] = hashes[j] % graph->v;
|
||||
if (j == 1 && e->vertices[0] == e->vertices[1]) {
|
||||
if (!nbperf->allow_hash_fudging)
|
||||
return -1;
|
||||
e->vertices[1] ^= 1; /* toogle bit to differ */
|
||||
graph->hash_fudge |= 1;
|
||||
}
|
||||
#if GRAPH_SIZE == 3
|
||||
if (j == 2 && (e->vertices[0] == e->vertices[2] ||
|
||||
e->vertices[1] == e->vertices[2])) {
|
||||
if (!nbperf->allow_hash_fudging)
|
||||
return -1;
|
||||
graph->hash_fudge |= 2;
|
||||
e->vertices[2] ^= 1;
|
||||
e->vertices[2] ^= 2 * (e->vertices[0] == e->vertices[2] ||
|
||||
e->vertices[1] == e->vertices[2]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < graph->v; ++i) {
|
||||
graph->verts[i].l_edge = unused;
|
||||
graph->verts[i].r_edge = unused;
|
||||
}
|
||||
for (i = 0; i < graph->e; ++i)
|
||||
SIZED2(_add_edge)(graph, i);
|
||||
|
||||
for (i = 0; i < graph->e; ++i) {
|
||||
v = &graph->verts[graph->edges[i].left];
|
||||
if (v->l_edge != unused)
|
||||
graph->edges[v->l_edge].l_prev = i;
|
||||
graph->edges[i].l_next = v->l_edge;
|
||||
graph->edges[i].l_prev = unused;
|
||||
v->l_edge = i;
|
||||
|
||||
v = &graph->verts[graph->edges[i].right];
|
||||
if (v->r_edge != unused)
|
||||
graph->edges[v->r_edge].r_prev = i;
|
||||
graph->edges[i].r_next = v->r_edge;
|
||||
graph->edges[i].r_prev = unused;
|
||||
v->r_edge = i;
|
||||
}
|
||||
|
||||
if (nbperf->first_round) {
|
||||
nbperf->first_round = 0;
|
||||
return graph2_check_duplicates(nbperf, graph);
|
||||
if (nbperf->check_duplicates) {
|
||||
nbperf->check_duplicates = 0;
|
||||
return SIZED2(_check_duplicates)(nbperf, graph);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
graph2_remove_vertex(struct graph2 *graph, struct vertex2 *v)
|
||||
{
|
||||
struct edge2 *e;
|
||||
struct vertex2 *v2;
|
||||
|
||||
for (;;) {
|
||||
if (v->l_edge != unused && v->r_edge != unused)
|
||||
break;
|
||||
if (v->l_edge == unused && v->r_edge == unused)
|
||||
break;
|
||||
|
||||
if (v->l_edge != unused) {
|
||||
e = &graph->edges[v->l_edge];
|
||||
if (e->l_next != unused)
|
||||
break;
|
||||
v->l_edge = unused; /* No other elements possible! */
|
||||
v2 = &graph->verts[e->right];
|
||||
if (e->r_prev == unused)
|
||||
v2->r_edge = e->r_next;
|
||||
else
|
||||
graph->edges[e->r_prev].r_next = e->r_next;
|
||||
if (e->r_next != unused)
|
||||
graph->edges[e->r_next].r_prev = e->r_prev;
|
||||
v = v2;
|
||||
} else {
|
||||
e = &graph->edges[v->r_edge];
|
||||
if (e->r_next != unused)
|
||||
break;
|
||||
v->r_edge = unused; /* No other elements possible! */
|
||||
v2 = &graph->verts[e->left];
|
||||
if (e->l_prev == unused)
|
||||
v2->l_edge = e->l_next;
|
||||
else
|
||||
graph->edges[e->l_prev].l_next = e->l_next;
|
||||
if (e->l_next != unused)
|
||||
graph->edges[e->l_next].l_prev = e->l_prev;
|
||||
v = v2;
|
||||
}
|
||||
|
||||
graph->output_order[--graph->output_index] = e - graph->edges;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
graph2_output_order(struct graph2 *graph)
|
||||
SIZED2(_output_order)(struct SIZED(graph) *graph)
|
||||
{
|
||||
size_t i;
|
||||
size_t i, j;
|
||||
struct SIZED(edge) *e2;
|
||||
|
||||
graph->output_index = graph->e;
|
||||
|
||||
for (i = 0; i < graph->v; ++i)
|
||||
graph2_remove_vertex(graph, &graph->verts[i]);
|
||||
SIZED2(_remove_vertex)(graph, i);
|
||||
|
||||
if (graph->output_index != 0)
|
||||
for (i = graph->e; graph->output_index > 0 && i > graph->output_index;) {
|
||||
e2 = graph->edges + graph->output_order[--i];
|
||||
for (j = 0; j < GRAPH_SIZE; ++j)
|
||||
SIZED2(_remove_vertex)(graph, e2->vertices[j]);
|
||||
}
|
||||
|
||||
if (graph->output_index != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: graph2.h,v 1.1 2009/08/15 16:21:05 joerg Exp $ */
|
||||
/* $NetBSD: graph2.h,v 1.2 2021/01/07 16:03:08 joerg Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
@ -32,32 +32,57 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation of common 2-graph routines:
|
||||
* - build a 2-graph with hash-pairs as edges
|
||||
* - check a 2-graph for acyclicness and compute an output order
|
||||
* Implementation of common 2/3-graph routines:
|
||||
* - build a 2/3-graph with hash-pairs as edges
|
||||
* - check a 2/3-graph for acyclicness and compute an output order
|
||||
*
|
||||
* For each vertex in the 2/3-graph, the incidence lists need to kept.
|
||||
* Avoid storing the full list by just XORing the indices of the still
|
||||
* incident edges and the number of such edges as that's all the peeling
|
||||
* computation needs. This is inspired by:
|
||||
* Cache-Oblivious Peeling of Random Hypergraphs by Djamal Belazzougui,
|
||||
* Paolo Boldi, Giuseppe Ottaviano, Rossano Venturini, and Sebastiano
|
||||
* Vigna. https://arxiv.org/abs/1312.0526
|
||||
*
|
||||
* Unlike in the paper, we don't care about external storage and have
|
||||
* the edge list at hand all the time. As such, no ordering is necessary
|
||||
* and the vertices of the edge don't have to be copied.
|
||||
*
|
||||
* The core observation of the paper above is that for a degree of one,
|
||||
* the incident edge can be obtained directly.
|
||||
*/
|
||||
|
||||
struct vertex2 {
|
||||
uint32_t l_edge, r_edge;
|
||||
#ifndef GRAPH_SIZE
|
||||
#define GRAPH_SIZE 2
|
||||
#endif
|
||||
|
||||
#define SIZED__(n, i) n ## i
|
||||
#define SIZED_(n, i) SIZED__(n, i)
|
||||
#define SIZED(n) SIZED_(n, GRAPH_SIZE)
|
||||
#define SIZED2__(n, i, m) n ## i ## m
|
||||
#define SIZED2_(n, i, m) SIZED2__(n, i, m)
|
||||
#define SIZED2(n) SIZED2_(graph, GRAPH_SIZE, n)
|
||||
|
||||
struct SIZED(vertex) {
|
||||
uint32_t degree, edges;
|
||||
};
|
||||
|
||||
struct edge2 {
|
||||
uint32_t left, right;
|
||||
uint32_t l_prev, l_next;
|
||||
uint32_t r_prev, r_next;
|
||||
struct SIZED(edge) {
|
||||
uint32_t vertices[GRAPH_SIZE];
|
||||
};
|
||||
|
||||
struct graph2 {
|
||||
struct vertex2 *verts;
|
||||
struct edge2 *edges;
|
||||
struct SIZED(graph) {
|
||||
struct SIZED(vertex) *verts;
|
||||
struct SIZED(edge) *edges;
|
||||
uint32_t output_index;
|
||||
uint32_t *output_order;
|
||||
uint8_t *visited;
|
||||
uint32_t e, v;
|
||||
int hash_fudge;
|
||||
};
|
||||
|
||||
void graph2_setup(struct graph2 *, uint32_t, uint32_t);
|
||||
void graph2_free(struct graph2 *);
|
||||
void SIZED2(_setup)(struct SIZED(graph) *, uint32_t, uint32_t);
|
||||
void SIZED2(_free)(struct SIZED(graph) *);
|
||||
|
||||
int graph2_hash(struct nbperf *, struct graph2 *);
|
||||
int graph2_output_order(struct graph2 *graph);
|
||||
int SIZED2(_hash)(struct nbperf *, struct SIZED(graph) *);
|
||||
int SIZED2(_output_order)(struct SIZED(graph) *graph);
|
||||
|
@ -1,250 +1,4 @@
|
||||
/* $NetBSD: graph3.c,v 1.4 2011/10/21 23:47:11 joerg Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Joerg Sonnenberger.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/* $NetBSD*/
|
||||
|
||||
#if HAVE_NBTOOL_CONFIG_H
|
||||
#include "nbtool_config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: graph3.c,v 1.4 2011/10/21 23:47:11 joerg Exp $");
|
||||
|
||||
#include <err.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nbperf.h"
|
||||
#include "graph3.h"
|
||||
|
||||
static const uint32_t unused = 0xffffffffU;
|
||||
|
||||
void
|
||||
graph3_setup(struct graph3 *graph, uint32_t v, uint32_t e)
|
||||
{
|
||||
graph->v = v;
|
||||
graph->e = e;
|
||||
|
||||
graph->verts = calloc(sizeof(struct vertex3), v);
|
||||
graph->edges = calloc(sizeof(struct edge3), e);
|
||||
graph->output_order = calloc(sizeof(uint32_t), e);
|
||||
|
||||
if (graph->verts == NULL || graph->edges == NULL ||
|
||||
graph->output_order == NULL)
|
||||
err(1, "malloc failed");
|
||||
}
|
||||
|
||||
void
|
||||
graph3_free(struct graph3 *graph)
|
||||
{
|
||||
free(graph->verts);
|
||||
free(graph->edges);
|
||||
free(graph->output_order);
|
||||
|
||||
graph->verts = NULL;
|
||||
graph->edges = NULL;
|
||||
graph->output_order = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
graph3_check_duplicates(struct nbperf *nbperf, struct graph3 *graph)
|
||||
{
|
||||
struct vertex3 *v;
|
||||
struct edge3 *e, *e2;
|
||||
uint32_t i, j;
|
||||
|
||||
for (i = 0; i < graph->e; ++i) {
|
||||
e = &graph->edges[i];
|
||||
v = &graph->verts[e->left];
|
||||
j = v->l_edge;
|
||||
e2 = &graph->edges[j];
|
||||
for (;;) {
|
||||
if (i < j && e->middle == e2->middle &&
|
||||
e->right == e2->right &&
|
||||
nbperf->keylens[i] == nbperf->keylens[j] &&
|
||||
memcmp(nbperf->keys[i], nbperf->keys[j],
|
||||
nbperf->keylens[i]) == 0) {
|
||||
nbperf->has_duplicates = 1;
|
||||
return -1;
|
||||
}
|
||||
if (e2->l_next == unused)
|
||||
break;
|
||||
j = e2->l_next;
|
||||
e2 = &graph->edges[j];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
graph3_hash(struct nbperf *nbperf, struct graph3 *graph)
|
||||
{
|
||||
struct vertex3 *v;
|
||||
uint32_t hashes[NBPERF_MAX_HASH_SIZE];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < graph->e; ++i) {
|
||||
(*nbperf->compute_hash)(nbperf,
|
||||
nbperf->keys[i], nbperf->keylens[i], hashes);
|
||||
graph->edges[i].left = hashes[0] % graph->v;
|
||||
graph->edges[i].middle = hashes[1] % graph->v;
|
||||
graph->edges[i].right = hashes[2] % graph->v;
|
||||
if (graph->edges[i].left == graph->edges[i].middle)
|
||||
return -1;
|
||||
if (graph->edges[i].left == graph->edges[i].right)
|
||||
return -1;
|
||||
if (graph->edges[i].middle == graph->edges[i].right)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < graph->v; ++i) {
|
||||
graph->verts[i].l_edge = unused;
|
||||
graph->verts[i].m_edge = unused;
|
||||
graph->verts[i].r_edge = unused;
|
||||
}
|
||||
|
||||
for (i = 0; i < graph->e; ++i) {
|
||||
v = &graph->verts[graph->edges[i].left];
|
||||
if (v->l_edge != unused)
|
||||
graph->edges[v->l_edge].l_prev = i;
|
||||
graph->edges[i].l_next = v->l_edge;
|
||||
graph->edges[i].l_prev = unused;
|
||||
v->l_edge = i;
|
||||
|
||||
v = &graph->verts[graph->edges[i].middle];
|
||||
if (v->m_edge != unused)
|
||||
graph->edges[v->m_edge].m_prev = i;
|
||||
graph->edges[i].m_next = v->m_edge;
|
||||
graph->edges[i].m_prev = unused;
|
||||
v->m_edge = i;
|
||||
|
||||
v = &graph->verts[graph->edges[i].right];
|
||||
if (v->r_edge != unused)
|
||||
graph->edges[v->r_edge].r_prev = i;
|
||||
graph->edges[i].r_next = v->r_edge;
|
||||
graph->edges[i].r_prev = unused;
|
||||
v->r_edge = i;
|
||||
}
|
||||
|
||||
if (nbperf->first_round) {
|
||||
nbperf->first_round = 0;
|
||||
return graph3_check_duplicates(nbperf, graph);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
graph3_remove_vertex(struct graph3 *graph, struct vertex3 *v)
|
||||
{
|
||||
struct edge3 *e;
|
||||
struct vertex3 *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;
|
||||
|
||||
if (v->l_edge != unused) {
|
||||
e = &graph->edges[v->l_edge];
|
||||
if (e->l_next != unused)
|
||||
return;
|
||||
} else if (v->m_edge != unused) {
|
||||
e = &graph->edges[v->m_edge];
|
||||
if (e->m_next != unused)
|
||||
return;
|
||||
} else {
|
||||
if (v->r_edge == unused)
|
||||
abort();
|
||||
e = &graph->edges[v->r_edge];
|
||||
if (e->r_next != unused)
|
||||
return;
|
||||
}
|
||||
|
||||
graph->output_order[--graph->output_index] = e - graph->edges;
|
||||
|
||||
vl = &graph->verts[e->left];
|
||||
vm = &graph->verts[e->middle];
|
||||
vr = &graph->verts[e->right];
|
||||
|
||||
if (e->l_prev == unused)
|
||||
vl->l_edge = e->l_next;
|
||||
else
|
||||
graph->edges[e->l_prev].l_next = e->l_next;
|
||||
if (e->l_next != unused)
|
||||
graph->edges[e->l_next].l_prev = e->l_prev;
|
||||
|
||||
if (e->m_prev == unused)
|
||||
vm->m_edge = e->m_next;
|
||||
else
|
||||
graph->edges[e->m_prev].m_next = e->m_next;
|
||||
if (e->m_next != unused)
|
||||
graph->edges[e->m_next].m_prev = e->m_prev;
|
||||
|
||||
if (e->r_prev == unused)
|
||||
vr->r_edge = e->r_next;
|
||||
else
|
||||
graph->edges[e->r_prev].r_next = e->r_next;
|
||||
if (e->r_next != unused)
|
||||
graph->edges[e->r_next].r_prev = e->r_prev;
|
||||
}
|
||||
|
||||
int
|
||||
graph3_output_order(struct graph3 *graph)
|
||||
{
|
||||
struct edge3 *e;
|
||||
size_t i;
|
||||
|
||||
graph->output_index = graph->e;
|
||||
|
||||
for (i = 0; i < graph->v; ++i)
|
||||
graph3_remove_vertex(graph, &graph->verts[i]);
|
||||
|
||||
for (i = graph->e; i > 0 && i > graph->output_index;) {
|
||||
--i;
|
||||
e = &graph->edges[graph->output_order[i]];
|
||||
|
||||
graph3_remove_vertex(graph, &graph->verts[e->left]);
|
||||
graph3_remove_vertex(graph, &graph->verts[e->middle]);
|
||||
graph3_remove_vertex(graph, &graph->verts[e->right]);
|
||||
}
|
||||
|
||||
if (graph->output_index != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define GRAPH_SIZE 3
|
||||
#include "graph2.c"
|
||||
|
@ -1,62 +0,0 @@
|
||||
/* $NetBSD: graph3.h,v 1.1 2009/08/15 16:21:05 joerg Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Joerg Sonnenberger.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation of common 3-graph routines:
|
||||
* - build a 3-graph with hash-triple as edges
|
||||
* - check a 3-graph for acyclicness and compute an output order
|
||||
*/
|
||||
|
||||
struct vertex3 {
|
||||
uint32_t l_edge, m_edge, r_edge;
|
||||
};
|
||||
|
||||
struct edge3 {
|
||||
uint32_t left, middle, right;
|
||||
uint32_t l_prev, m_prev, l_next;
|
||||
uint32_t r_prev, m_next, r_next;
|
||||
};
|
||||
|
||||
struct graph3 {
|
||||
struct vertex3 *verts;
|
||||
struct edge3 *edges;
|
||||
uint32_t output_index;
|
||||
uint32_t *output_order;
|
||||
uint32_t e, v;
|
||||
};
|
||||
|
||||
void graph3_setup(struct graph3 *, uint32_t, uint32_t);
|
||||
void graph3_free(struct graph3 *);
|
||||
|
||||
int graph3_hash(struct nbperf *, struct graph3 *);
|
||||
int graph3_output_order(struct graph3 *);
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: nbperf-bdz.c,v 1.9 2014/04/30 21:04:58 joerg Exp $ */
|
||||
/* $NetBSD: nbperf-bdz.c,v 1.10 2021/01/07 16:03:08 joerg Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2009, 2012 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
@ -36,7 +36,7 @@
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: nbperf-bdz.c,v 1.9 2014/04/30 21:04:58 joerg Exp $");
|
||||
__RCSID("$NetBSD: nbperf-bdz.c,v 1.10 2021/01/07 16:03:08 joerg Exp $");
|
||||
|
||||
#include <err.h>
|
||||
#include <inttypes.h>
|
||||
@ -66,10 +66,11 @@ __RCSID("$NetBSD: nbperf-bdz.c,v 1.9 2014/04/30 21:04:58 joerg Exp $");
|
||||
* the index of the authoritive vertex.
|
||||
*/
|
||||
|
||||
#include "graph3.h"
|
||||
#define GRAPH_SIZE 3
|
||||
#include "graph2.h"
|
||||
|
||||
struct state {
|
||||
struct graph3 graph;
|
||||
struct SIZED(graph) graph;
|
||||
uint32_t *visited;
|
||||
uint32_t *holes64k;
|
||||
uint16_t *holes64;
|
||||
@ -80,7 +81,7 @@ struct state {
|
||||
static void
|
||||
assign_nodes(struct state *state)
|
||||
{
|
||||
struct edge3 *e;
|
||||
struct SIZED(edge) *e;
|
||||
size_t i, j;
|
||||
uint32_t t, r, holes;
|
||||
|
||||
@ -90,29 +91,29 @@ assign_nodes(struct state *state)
|
||||
for (i = 0; i < state->graph.e; ++i) {
|
||||
j = state->graph.output_order[i];
|
||||
e = &state->graph.edges[j];
|
||||
if (!state->visited[e->left]) {
|
||||
if (!state->visited[e->vertices[0]]) {
|
||||
r = 0;
|
||||
t = e->left;
|
||||
} else if (!state->visited[e->middle]) {
|
||||
t = e->vertices[0];
|
||||
} else if (!state->visited[e->vertices[1]]) {
|
||||
r = 1;
|
||||
t = e->middle;
|
||||
t = e->vertices[1];
|
||||
} else {
|
||||
if (state->visited[e->right])
|
||||
if (state->visited[e->vertices[2]])
|
||||
abort();
|
||||
r = 2;
|
||||
t = e->right;
|
||||
t = e->vertices[2];
|
||||
}
|
||||
|
||||
state->visited[t] = 2 + j;
|
||||
if (state->visited[e->left] == 0)
|
||||
state->visited[e->left] = 1;
|
||||
if (state->visited[e->middle] == 0)
|
||||
state->visited[e->middle] = 1;
|
||||
if (state->visited[e->right] == 0)
|
||||
state->visited[e->right] = 1;
|
||||
if (state->visited[e->vertices[0]] == 0)
|
||||
state->visited[e->vertices[0]] = 1;
|
||||
if (state->visited[e->vertices[1]] == 0)
|
||||
state->visited[e->vertices[1]] = 1;
|
||||
if (state->visited[e->vertices[2]] == 0)
|
||||
state->visited[e->vertices[2]] = 1;
|
||||
|
||||
state->g[t] = (9 + r - state->g[e->left] - state->g[e->middle]
|
||||
- state->g[e->right]) % 3;
|
||||
state->g[t] = (9 + r - state->g[e->vertices[0]] - state->g[e->vertices[1]]
|
||||
- state->g[e->vertices[2]]) % 3;
|
||||
}
|
||||
|
||||
holes = 0;
|
||||
@ -226,6 +227,16 @@ print_hash(struct nbperf *nbperf, struct state *state)
|
||||
fprintf(nbperf->output, "\th[2] = h[2] %% %" PRIu32 ";\n",
|
||||
state->graph.v);
|
||||
|
||||
if (state->graph.hash_fudge & 1)
|
||||
fprintf(nbperf->output, "\th[1] ^= (h[0] == h[1]);\n");
|
||||
|
||||
if (state->graph.hash_fudge & 2) {
|
||||
fprintf(nbperf->output,
|
||||
"\th[2] ^= (h[0] == h[2] || h[1] == h[2]);\n");
|
||||
fprintf(nbperf->output,
|
||||
"\th[2] ^= 2 * (h[0] == h[2] || h[1] == h[2]);\n");
|
||||
}
|
||||
|
||||
fprintf(nbperf->output,
|
||||
"\tidx = 9 + ((g1[h[0] >> 6] >> (h[0] & 63)) &1)\n"
|
||||
"\t + ((g1[h[1] >> 6] >> (h[1] & 63)) & 1)\n"
|
||||
@ -273,6 +284,8 @@ bpz_compute(struct nbperf *nbperf)
|
||||
++v;
|
||||
if (v < 10)
|
||||
v = 10;
|
||||
if (nbperf->allow_hash_fudging)
|
||||
v |= 3;
|
||||
|
||||
graph3_setup(&state.graph, v, e);
|
||||
|
||||
@ -287,9 +300,9 @@ bpz_compute(struct nbperf *nbperf)
|
||||
state.result_map == NULL)
|
||||
err(1, "malloc failed");
|
||||
|
||||
if (graph3_hash(nbperf, &state.graph))
|
||||
if (SIZED2(_hash)(nbperf, &state.graph))
|
||||
goto failed;
|
||||
if (graph3_output_order(&state.graph))
|
||||
if (SIZED2(_output_order)(&state.graph))
|
||||
goto failed;
|
||||
assign_nodes(&state);
|
||||
print_hash(nbperf, &state);
|
||||
@ -297,7 +310,7 @@ bpz_compute(struct nbperf *nbperf)
|
||||
retval = 0;
|
||||
|
||||
failed:
|
||||
graph3_free(&state.graph);
|
||||
SIZED2(_free)(&state.graph);
|
||||
free(state.visited);
|
||||
free(state.g);
|
||||
free(state.holes64k);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: nbperf-chm.c,v 1.3 2011/10/21 23:47:11 joerg Exp $ */
|
||||
/* $NetBSD: nbperf-chm.c,v 1.4 2021/01/07 16:03:08 joerg Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
@ -35,7 +35,7 @@
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: nbperf-chm.c,v 1.3 2011/10/21 23:47:11 joerg Exp $");
|
||||
__RCSID("$NetBSD: nbperf-chm.c,v 1.4 2021/01/07 16:03:08 joerg Exp $");
|
||||
|
||||
#include <err.h>
|
||||
#include <inttypes.h>
|
||||
@ -45,11 +45,7 @@ __RCSID("$NetBSD: nbperf-chm.c,v 1.3 2011/10/21 23:47:11 joerg Exp $");
|
||||
|
||||
#include "nbperf.h"
|
||||
|
||||
#ifdef BUILD_CHM3
|
||||
#include "graph3.h"
|
||||
#else
|
||||
#include "graph2.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A full description of the algorithm can be found in:
|
||||
@ -78,60 +74,74 @@ __RCSID("$NetBSD: nbperf-chm.c,v 1.3 2011/10/21 23:47:11 joerg Exp $");
|
||||
*/
|
||||
|
||||
struct state {
|
||||
#ifdef BUILD_CHM3
|
||||
struct graph3 graph;
|
||||
#else
|
||||
struct graph2 graph;
|
||||
#endif
|
||||
struct SIZED(graph) graph;
|
||||
uint32_t *g;
|
||||
uint8_t *visited;
|
||||
};
|
||||
|
||||
#if GRAPH_SIZE == 3
|
||||
static void
|
||||
assign_nodes(struct state *state)
|
||||
{
|
||||
#ifdef BUILD_CHM3
|
||||
struct edge3 *e;
|
||||
#else
|
||||
struct edge2 *e;
|
||||
#endif
|
||||
struct SIZED(edge) *e;
|
||||
size_t i;
|
||||
uint32_t e_idx;
|
||||
uint32_t e_idx, v0, v1, v2, g;
|
||||
|
||||
for (i = 0; i < state->graph.e; ++i) {
|
||||
e_idx = state->graph.output_order[i];
|
||||
e = &state->graph.edges[e_idx];
|
||||
|
||||
#ifdef BUILD_CHM3
|
||||
if (!state->visited[e->left]) {
|
||||
state->g[e->left] = (2 * state->graph.e + e_idx
|
||||
- state->g[e->middle] - state->g[e->right])
|
||||
% state->graph.e;
|
||||
} else if (!state->visited[e->middle]) {
|
||||
state->g[e->middle] = (2 * state->graph.e + e_idx
|
||||
- state->g[e->left] - state->g[e->right])
|
||||
% state->graph.e;
|
||||
if (!state->visited[e->vertices[0]]) {
|
||||
v0 = e->vertices[0];
|
||||
v1 = e->vertices[1];
|
||||
v2 = e->vertices[2];
|
||||
} else if (!state->visited[e->vertices[1]]) {
|
||||
v0 = e->vertices[1];
|
||||
v1 = e->vertices[0];
|
||||
v2 = e->vertices[2];
|
||||
} else {
|
||||
state->g[e->right] = (2 * state->graph.e + e_idx
|
||||
- state->g[e->left] - state->g[e->middle])
|
||||
% state->graph.e;
|
||||
v0 = e->vertices[2];
|
||||
v1 = e->vertices[0];
|
||||
v2 = e->vertices[1];
|
||||
}
|
||||
state->visited[e->left] = 1;
|
||||
state->visited[e->middle] = 1;
|
||||
state->visited[e->right] = 1;
|
||||
#else
|
||||
if (!state->visited[e->left]) {
|
||||
state->g[e->left] = (state->graph.e + e_idx
|
||||
- state->g[e->right]) % state->graph.e;
|
||||
} else {
|
||||
state->g[e->right] = (state->graph.e + e_idx
|
||||
- state->g[e->left]) % state->graph.e;
|
||||
g = e_idx - state->g[v1] - state->g[v2];
|
||||
if (g >= state->graph.e) {
|
||||
g += state->graph.e;
|
||||
if (g >= state->graph.e)
|
||||
g += state->graph.e;
|
||||
}
|
||||
state->visited[e->left] = 1;
|
||||
state->visited[e->right] = 1;
|
||||
#endif
|
||||
state->g[v0] = g;
|
||||
state->visited[v0] = 1;
|
||||
state->visited[v1] = 1;
|
||||
state->visited[v2] = 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void
|
||||
assign_nodes(struct state *state)
|
||||
{
|
||||
struct SIZED(edge) *e;
|
||||
size_t i;
|
||||
uint32_t e_idx, v0, v1, g;
|
||||
|
||||
for (i = 0; i < state->graph.e; ++i) {
|
||||
e_idx = state->graph.output_order[i];
|
||||
e = &state->graph.edges[e_idx];
|
||||
if (!state->visited[e->vertices[0]]) {
|
||||
v0 = e->vertices[0];
|
||||
v1 = e->vertices[1];
|
||||
} else {
|
||||
v0 = e->vertices[1];
|
||||
v1 = e->vertices[0];
|
||||
}
|
||||
g = e_idx - state->g[v1];
|
||||
if (g >= state->graph.e)
|
||||
g += state->graph.e;
|
||||
state->g[v0] = g;
|
||||
state->visited[v0] = 1;
|
||||
state->visited[v1] = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
print_hash(struct nbperf *nbperf, struct state *state)
|
||||
@ -175,15 +185,34 @@ print_hash(struct nbperf *nbperf, struct state *state)
|
||||
fprintf(nbperf->output, "\t};\n");
|
||||
fprintf(nbperf->output, "\tuint32_t h[%zu];\n\n", nbperf->hash_size);
|
||||
(*nbperf->print_hash)(nbperf, "\t", "key", "keylen", "h");
|
||||
#ifdef BUILD_CHM3
|
||||
fprintf(nbperf->output, "\treturn (g[h[0] %% %" PRIu32 "] + "
|
||||
"g[h[1] %% %" PRIu32 "] + "
|
||||
"g[h[2] %% %" PRIu32"]) %% %" PRIu32 ";\n",
|
||||
state->graph.v, state->graph.v, state->graph.v, state->graph.e);
|
||||
|
||||
fprintf(nbperf->output, "\n\th[0] = h[0] %% %" PRIu32 ";\n",
|
||||
state->graph.v);
|
||||
fprintf(nbperf->output, "\th[1] = h[1] %% %" PRIu32 ";\n",
|
||||
state->graph.v);
|
||||
#if GRAPH_SIZE == 3
|
||||
fprintf(nbperf->output, "\th[2] = h[2] %% %" PRIu32 ";\n",
|
||||
state->graph.v);
|
||||
#endif
|
||||
|
||||
if (state->graph.hash_fudge & 1)
|
||||
fprintf(nbperf->output, "\th[1] ^= (h[0] == h[1]);\n");
|
||||
|
||||
#if GRAPH_SIZE == 3
|
||||
if (state->graph.hash_fudge & 2) {
|
||||
fprintf(nbperf->output,
|
||||
"\th[2] ^= (h[0] == h[2] || h[1] == h[2]);\n");
|
||||
fprintf(nbperf->output,
|
||||
"\th[2] ^= 2 * (h[0] == h[2] || h[1] == h[2]);\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if GRAPH_SIZE == 3
|
||||
fprintf(nbperf->output, "\treturn (g[h[0]] + g[h[1]] + g[h[2]]) %% "
|
||||
"%" PRIu32 ";\n", state->graph.e);
|
||||
#else
|
||||
fprintf(nbperf->output, "\treturn (g[h[0] %% %" PRIu32 "] + "
|
||||
"g[h[1] %% %" PRIu32"]) %% %" PRIu32 ";\n",
|
||||
state->graph.v, state->graph.v, state->graph.e);
|
||||
fprintf(nbperf->output, "\treturn (g[h[0]] + g[h[1]]) %% "
|
||||
"%" PRIu32 ";\n", state->graph.e);
|
||||
#endif
|
||||
fprintf(nbperf->output, "}\n");
|
||||
|
||||
@ -194,7 +223,7 @@ print_hash(struct nbperf *nbperf, struct state *state)
|
||||
}
|
||||
|
||||
int
|
||||
#ifdef BUILD_CHM3
|
||||
#if GRAPH_SIZE == 3
|
||||
chm3_compute(struct nbperf *nbperf)
|
||||
#else
|
||||
chm_compute(struct nbperf *nbperf)
|
||||
@ -204,7 +233,7 @@ chm_compute(struct nbperf *nbperf)
|
||||
int retval = -1;
|
||||
uint32_t v, e;
|
||||
|
||||
#ifdef BUILD_CHM3
|
||||
#if GRAPH_SIZE == 3
|
||||
if (nbperf->c == 0)
|
||||
nbperf-> c = 1.24;
|
||||
|
||||
@ -227,14 +256,18 @@ chm_compute(struct nbperf *nbperf)
|
||||
(*nbperf->seed_hash)(nbperf);
|
||||
e = nbperf->n;
|
||||
v = nbperf->c * nbperf->n;
|
||||
#ifdef BUILD_CHM3
|
||||
#if GRAPH_SIZE == 3
|
||||
if (v == 1.24 * nbperf->n)
|
||||
++v;
|
||||
if (v < 10)
|
||||
v = 10;
|
||||
if (nbperf->allow_hash_fudging)
|
||||
v |= 3;
|
||||
#else
|
||||
if (v == 2 * nbperf->n)
|
||||
++v;
|
||||
if (nbperf->allow_hash_fudging)
|
||||
v |= 1;
|
||||
#endif
|
||||
|
||||
state.g = calloc(sizeof(uint32_t), v);
|
||||
@ -242,30 +275,18 @@ chm_compute(struct nbperf *nbperf)
|
||||
if (state.g == NULL || state.visited == NULL)
|
||||
err(1, "malloc failed");
|
||||
|
||||
#ifdef BUILD_CHM3
|
||||
graph3_setup(&state.graph, v, e);
|
||||
if (graph3_hash(nbperf, &state.graph))
|
||||
SIZED2(_setup)(&state.graph, v, e);
|
||||
if (SIZED2(_hash)(nbperf, &state.graph))
|
||||
goto failed;
|
||||
if (graph3_output_order(&state.graph))
|
||||
if (SIZED2(_output_order)(&state.graph))
|
||||
goto failed;
|
||||
#else
|
||||
graph2_setup(&state.graph, v, e);
|
||||
if (graph2_hash(nbperf, &state.graph))
|
||||
goto failed;
|
||||
if (graph2_output_order(&state.graph))
|
||||
goto failed;
|
||||
#endif
|
||||
assign_nodes(&state);
|
||||
print_hash(nbperf, &state);
|
||||
|
||||
retval = 0;
|
||||
|
||||
failed:
|
||||
#ifdef BUILD_CHM3
|
||||
graph3_free(&state.graph);
|
||||
#else
|
||||
graph2_free(&state.graph);
|
||||
#endif
|
||||
SIZED2(_free)(&state.graph);
|
||||
free(state.g);
|
||||
free(state.visited);
|
||||
return retval;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: nbperf-chm3.c,v 1.1 2009/08/15 16:21:05 joerg Exp $ */
|
||||
/* $NetBSD: nbperf-chm3.c,v 1.2 2021/01/07 16:03:08 joerg Exp $ */
|
||||
|
||||
#define BUILD_CHM3
|
||||
#define GRAPH_SIZE 3
|
||||
#include "nbperf-chm.c"
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: nbperf.1,v 1.7 2017/06/20 15:50:04 abhinav Exp $
|
||||
.\" $NetBSD: nbperf.1,v 1.8 2021/01/07 16:03:08 joerg Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
@ -27,7 +27,7 @@
|
||||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd September 25, 2012
|
||||
.Dd January 5, 2021
|
||||
.Dt NBPERF 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -35,7 +35,7 @@
|
||||
.Nd compute a perfect hash function
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl ps
|
||||
.Op Fl fps
|
||||
.Op Fl a Ar algorithm
|
||||
.Op Fl c Ar utilisation
|
||||
.Op Fl h Ar hash
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: nbperf.c,v 1.5 2013/01/31 16:32:02 joerg Exp $ */
|
||||
/* $NetBSD: nbperf.c,v 1.6 2021/01/07 16:03:08 joerg Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
@ -36,7 +36,7 @@
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: nbperf.c,v 1.5 2013/01/31 16:32:02 joerg Exp $");
|
||||
__RCSID("$NetBSD: nbperf.c,v 1.6 2021/01/07 16:03:08 joerg Exp $");
|
||||
|
||||
#include <sys/endian.h>
|
||||
#include <err.h>
|
||||
@ -45,6 +45,7 @@ __RCSID("$NetBSD: nbperf.c,v 1.5 2013/01/31 16:32:02 joerg Exp $");
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nbperf.h"
|
||||
@ -115,8 +116,9 @@ main(int argc, char **argv)
|
||||
.map_output = NULL,
|
||||
.output = NULL,
|
||||
.static_hash = 0,
|
||||
.first_round = 1,
|
||||
.check_duplicates = 0,
|
||||
.has_duplicates = 0,
|
||||
.allow_hash_fudging = 0,
|
||||
};
|
||||
FILE *input;
|
||||
size_t curlen = 0, curalloc = 0;
|
||||
@ -132,7 +134,7 @@ main(int argc, char **argv)
|
||||
|
||||
set_hash(&nbperf, "mi_vector_hash");
|
||||
|
||||
while ((ch = getopt(argc, argv, "a:c:h:i:m:n:o:ps")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "a:c:fh:i:m:n:o:ps")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
/* Accept bdz as alias for netbsd-6 compat. */
|
||||
@ -152,6 +154,9 @@ main(int argc, char **argv)
|
||||
if (errno || eos[0] || !nbperf.c)
|
||||
errx(2, "Invalid argument for -c");
|
||||
break;
|
||||
case 'f':
|
||||
nbperf.allow_hash_fudging = 1;
|
||||
break;
|
||||
case 'h':
|
||||
set_hash(&nbperf, optarg);
|
||||
break;
|
||||
@ -241,10 +246,18 @@ main(int argc, char **argv)
|
||||
nbperf.keylens = keylens;
|
||||
|
||||
looped = 0;
|
||||
while ((*build_hash)(&nbperf)) {
|
||||
if (nbperf.has_duplicates)
|
||||
int rv;
|
||||
for (;;) {
|
||||
rv = (*build_hash)(&nbperf);
|
||||
if (!rv)
|
||||
break;
|
||||
if (nbperf.has_duplicates) {
|
||||
fputc('\n', stderr);
|
||||
errx(1, "Duplicate keys detected");
|
||||
}
|
||||
fputc('.', stderr);
|
||||
if (!looped)
|
||||
nbperf.check_duplicates = 1;
|
||||
looped = 1;
|
||||
if (max_iterations == 0xffffffffU)
|
||||
continue;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: nbperf.h,v 1.4 2013/01/31 16:32:02 joerg Exp $ */
|
||||
/* $NetBSD: nbperf.h,v 1.5 2021/01/07 16:03:08 joerg Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
@ -38,10 +38,11 @@ struct nbperf {
|
||||
FILE *map_output;
|
||||
const char *hash_name;
|
||||
int static_hash;
|
||||
int allow_hash_fudging;
|
||||
size_t n;
|
||||
const void * __restrict * keys;
|
||||
const size_t *keylens;
|
||||
int first_round, has_duplicates;
|
||||
int check_duplicates, has_duplicates;
|
||||
|
||||
double c;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user