xref: /minix3/usr.bin/nbperf/nbperf-bdz.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: nbperf-bdz.c,v 1.9 2014/04/30 21:04:58 joerg Exp $	*/
2c75851fcSLionel Sambuc /*-
3c75851fcSLionel Sambuc  * Copyright (c) 2009, 2012 The NetBSD Foundation, Inc.
4c75851fcSLionel Sambuc  * All rights reserved.
5c75851fcSLionel Sambuc  *
6c75851fcSLionel Sambuc  * This code is derived from software contributed to The NetBSD Foundation
7c75851fcSLionel Sambuc  * by Joerg Sonnenberger.
8c75851fcSLionel Sambuc  *
9c75851fcSLionel Sambuc  * Redistribution and use in source and binary forms, with or without
10c75851fcSLionel Sambuc  * modification, are permitted provided that the following conditions
11c75851fcSLionel Sambuc  * are met:
12c75851fcSLionel Sambuc  *
13c75851fcSLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
14c75851fcSLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
15c75851fcSLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16c75851fcSLionel Sambuc  *    notice, this list of conditions and the following disclaimer in
17c75851fcSLionel Sambuc  *    the documentation and/or other materials provided with the
18c75851fcSLionel Sambuc  *    distribution.
19c75851fcSLionel Sambuc  *
20c75851fcSLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21c75851fcSLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22c75851fcSLionel Sambuc  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23c75851fcSLionel Sambuc  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
24c75851fcSLionel Sambuc  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25c75851fcSLionel Sambuc  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26c75851fcSLionel Sambuc  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27c75851fcSLionel Sambuc  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28c75851fcSLionel Sambuc  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29c75851fcSLionel Sambuc  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30c75851fcSLionel Sambuc  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c75851fcSLionel Sambuc  * SUCH DAMAGE.
32c75851fcSLionel Sambuc  */
33c75851fcSLionel Sambuc 
34c75851fcSLionel Sambuc #if HAVE_NBTOOL_CONFIG_H
35c75851fcSLionel Sambuc #include "nbtool_config.h"
36c75851fcSLionel Sambuc #endif
37c75851fcSLionel Sambuc 
38c75851fcSLionel Sambuc #include <sys/cdefs.h>
39*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: nbperf-bdz.c,v 1.9 2014/04/30 21:04:58 joerg Exp $");
40c75851fcSLionel Sambuc 
41c75851fcSLionel Sambuc #include <err.h>
42c75851fcSLionel Sambuc #include <inttypes.h>
43c75851fcSLionel Sambuc #include <stdlib.h>
44c75851fcSLionel Sambuc #include <stdio.h>
45c75851fcSLionel Sambuc #include <string.h>
46c75851fcSLionel Sambuc 
47c75851fcSLionel Sambuc #include "nbperf.h"
48c75851fcSLionel Sambuc 
49c75851fcSLionel Sambuc /*
50c75851fcSLionel Sambuc  * A full description of the algorithm can be found in:
51c75851fcSLionel Sambuc  * "Simple and Space-Efficient Minimal Perfect Hash Functions"
52c75851fcSLionel Sambuc  * by Botelho, Pagh and Ziviani, proceeedings of WADS 2007.
53c75851fcSLionel Sambuc  */
54c75851fcSLionel Sambuc 
55c75851fcSLionel Sambuc /*
56c75851fcSLionel Sambuc  * The algorithm is based on random, acyclic 3-graphs.
57c75851fcSLionel Sambuc  *
58c75851fcSLionel Sambuc  * Each edge in the represents a key.  The vertices are the reminder of
59c75851fcSLionel Sambuc  * the hash function mod n.  n = cm with c > 1.23.  This ensures that
60c75851fcSLionel Sambuc  * an acyclic graph can be found with a very high probality.
61c75851fcSLionel Sambuc  *
62c75851fcSLionel Sambuc  * An acyclic graph has an edge order, where at least one vertex of
63c75851fcSLionel Sambuc  * each edge hasn't been seen before.   It is declares the first unvisited
64c75851fcSLionel Sambuc  * vertex as authoritive for the edge and assigns a 2bit value to unvisited
65c75851fcSLionel Sambuc  * vertices, so that the sum of all vertices of the edge modulo 4 is
66c75851fcSLionel Sambuc  * the index of the authoritive vertex.
67c75851fcSLionel Sambuc  */
68c75851fcSLionel Sambuc 
69c75851fcSLionel Sambuc #include "graph3.h"
70c75851fcSLionel Sambuc 
71c75851fcSLionel Sambuc struct state {
72c75851fcSLionel Sambuc 	struct graph3 graph;
73c75851fcSLionel Sambuc 	uint32_t *visited;
74c75851fcSLionel Sambuc 	uint32_t *holes64k;
75c75851fcSLionel Sambuc 	uint16_t *holes64;
76c75851fcSLionel Sambuc 	uint8_t *g;
77c75851fcSLionel Sambuc 	uint32_t *result_map;
78c75851fcSLionel Sambuc };
79c75851fcSLionel Sambuc 
80c75851fcSLionel Sambuc static void
assign_nodes(struct state * state)81c75851fcSLionel Sambuc assign_nodes(struct state *state)
82c75851fcSLionel Sambuc {
83c75851fcSLionel Sambuc 	struct edge3 *e;
84c75851fcSLionel Sambuc 	size_t i, j;
85c75851fcSLionel Sambuc 	uint32_t t, r, holes;
86c75851fcSLionel Sambuc 
87c75851fcSLionel Sambuc 	for (i = 0; i < state->graph.v; ++i)
88c75851fcSLionel Sambuc 		state->g[i] = 3;
89c75851fcSLionel Sambuc 
90c75851fcSLionel Sambuc 	for (i = 0; i < state->graph.e; ++i) {
91c75851fcSLionel Sambuc 		j = state->graph.output_order[i];
92c75851fcSLionel Sambuc 		e = &state->graph.edges[j];
93c75851fcSLionel Sambuc 		if (!state->visited[e->left]) {
94c75851fcSLionel Sambuc 			r = 0;
95c75851fcSLionel Sambuc 			t = e->left;
96c75851fcSLionel Sambuc 		} else if (!state->visited[e->middle]) {
97c75851fcSLionel Sambuc 			r = 1;
98c75851fcSLionel Sambuc 			t = e->middle;
99c75851fcSLionel Sambuc 		} else {
100c75851fcSLionel Sambuc 			if (state->visited[e->right])
101c75851fcSLionel Sambuc 				abort();
102c75851fcSLionel Sambuc 			r = 2;
103c75851fcSLionel Sambuc 			t = e->right;
104c75851fcSLionel Sambuc 		}
105c75851fcSLionel Sambuc 
106c75851fcSLionel Sambuc 		state->visited[t] = 2 + j;
107c75851fcSLionel Sambuc 		if (state->visited[e->left] == 0)
108c75851fcSLionel Sambuc 			state->visited[e->left] = 1;
109c75851fcSLionel Sambuc 		if (state->visited[e->middle] == 0)
110c75851fcSLionel Sambuc 			state->visited[e->middle] = 1;
111c75851fcSLionel Sambuc 		if (state->visited[e->right] == 0)
112c75851fcSLionel Sambuc 			state->visited[e->right] = 1;
113c75851fcSLionel Sambuc 
114c75851fcSLionel Sambuc 		state->g[t] = (9 + r - state->g[e->left] - state->g[e->middle]
115c75851fcSLionel Sambuc 		    - state->g[e->right]) % 3;
116c75851fcSLionel Sambuc 	}
117c75851fcSLionel Sambuc 
118c75851fcSLionel Sambuc 	holes = 0;
119c75851fcSLionel Sambuc 	for (i = 0; i < state->graph.v; ++i) {
120c75851fcSLionel Sambuc 		if (i % 65536 == 0)
121c75851fcSLionel Sambuc 			state->holes64k[i >> 16] = holes;
122c75851fcSLionel Sambuc 
123c75851fcSLionel Sambuc 		if (i % 64 == 0)
124c75851fcSLionel Sambuc 			state->holes64[i >> 6] = holes - state->holes64k[i >> 16];
125c75851fcSLionel Sambuc 
126c75851fcSLionel Sambuc 		if (state->visited[i] > 1) {
127c75851fcSLionel Sambuc 			j = state->visited[i] - 2;
128c75851fcSLionel Sambuc 			state->result_map[j] = i - holes;
129c75851fcSLionel Sambuc 		}
130c75851fcSLionel Sambuc 
131c75851fcSLionel Sambuc 		if (state->g[i] == 3)
132c75851fcSLionel Sambuc 			++holes;
133c75851fcSLionel Sambuc 	}
134c75851fcSLionel Sambuc }
135c75851fcSLionel Sambuc 
136c75851fcSLionel Sambuc static void
print_hash(struct nbperf * nbperf,struct state * state)137c75851fcSLionel Sambuc print_hash(struct nbperf *nbperf, struct state *state)
138c75851fcSLionel Sambuc {
139c75851fcSLionel Sambuc 	uint64_t sum;
140c75851fcSLionel Sambuc 	size_t i;
141c75851fcSLionel Sambuc 
142c75851fcSLionel Sambuc 	fprintf(nbperf->output, "#include <stdlib.h>\n");
143c75851fcSLionel Sambuc 	fprintf(nbperf->output, "#include <strings.h>\n\n");
144c75851fcSLionel Sambuc 
145c75851fcSLionel Sambuc 	fprintf(nbperf->output, "%suint32_t\n",
146c75851fcSLionel Sambuc 	    nbperf->static_hash ? "static " : "");
147c75851fcSLionel Sambuc 	fprintf(nbperf->output,
148c75851fcSLionel Sambuc 	    "%s(const void * __restrict key, size_t keylen)\n",
149c75851fcSLionel Sambuc 	    nbperf->hash_name);
150c75851fcSLionel Sambuc 	fprintf(nbperf->output, "{\n");
151c75851fcSLionel Sambuc 
152c75851fcSLionel Sambuc 	fprintf(nbperf->output,
153c75851fcSLionel Sambuc 	    "\tstatic const uint64_t g1[%" PRId32 "] = {\n",
154c75851fcSLionel Sambuc 	    (state->graph.v + 63) / 64);
155c75851fcSLionel Sambuc 	sum = 0;
156c75851fcSLionel Sambuc 	for (i = 0; i < state->graph.v; ++i) {
157c75851fcSLionel Sambuc 		sum |= ((uint64_t)state->g[i] & 1) << (i & 63);
158c75851fcSLionel Sambuc 		if (i % 64 == 63) {
159c75851fcSLionel Sambuc 			fprintf(nbperf->output, "%s0x%016" PRIx64 "ULL,%s",
160c75851fcSLionel Sambuc 			    (i / 64 % 2 == 0 ? "\t    " : " "),
161c75851fcSLionel Sambuc 			    sum,
162c75851fcSLionel Sambuc 			    (i / 64 % 2 == 1 ? "\n" : ""));
163c75851fcSLionel Sambuc 			sum = 0;
164c75851fcSLionel Sambuc 		}
165c75851fcSLionel Sambuc 	}
166c75851fcSLionel Sambuc 	if (i % 64 != 0) {
167c75851fcSLionel Sambuc 		fprintf(nbperf->output, "%s0x%016" PRIx64 "ULL,%s",
168c75851fcSLionel Sambuc 		    (i / 64 % 2 == 0 ? "\t    " : " "),
169c75851fcSLionel Sambuc 		    sum,
170c75851fcSLionel Sambuc 		    (i / 64 % 2 == 1 ? "\n" : ""));
171c75851fcSLionel Sambuc 	}
172c75851fcSLionel Sambuc 	fprintf(nbperf->output, "%s\t};\n", (i % 2 ? "\n" : ""));
173c75851fcSLionel Sambuc 
174c75851fcSLionel Sambuc 	fprintf(nbperf->output,
175c75851fcSLionel Sambuc 	    "\tstatic const uint64_t g2[%" PRId32 "] = {\n",
176c75851fcSLionel Sambuc 	    (state->graph.v + 63) / 64);
177c75851fcSLionel Sambuc 	sum = 0;
178c75851fcSLionel Sambuc 	for (i = 0; i < state->graph.v; ++i) {
179c75851fcSLionel Sambuc 		sum |= (((uint64_t)state->g[i] & 2) >> 1) << (i & 63);
180c75851fcSLionel Sambuc 		if (i % 64 == 63) {
181c75851fcSLionel Sambuc 			fprintf(nbperf->output, "%s0x%016" PRIx64 "ULL,%s",
182c75851fcSLionel Sambuc 			    (i / 64 % 2 == 0 ? "\t    " : " "),
183c75851fcSLionel Sambuc 			    sum,
184c75851fcSLionel Sambuc 			    (i / 64 % 2 == 1 ? "\n" : ""));
185c75851fcSLionel Sambuc 			sum = 0;
186c75851fcSLionel Sambuc 		}
187c75851fcSLionel Sambuc 	}
188c75851fcSLionel Sambuc 	if (i % 64 != 0) {
189c75851fcSLionel Sambuc 		fprintf(nbperf->output, "%s0x%016" PRIx64 "ULL,%s",
190c75851fcSLionel Sambuc 		    (i / 64 % 2 == 0 ? "\t    " : " "),
191c75851fcSLionel Sambuc 		    sum,
192c75851fcSLionel Sambuc 		    (i / 64 % 2 == 1 ? "\n" : ""));
193c75851fcSLionel Sambuc 	}
194c75851fcSLionel Sambuc 	fprintf(nbperf->output, "%s\t};\n", (i % 2 ? "\n" : ""));
195c75851fcSLionel Sambuc 
196c75851fcSLionel Sambuc 	fprintf(nbperf->output,
197c75851fcSLionel Sambuc 	    "\tstatic const uint32_t holes64k[%" PRId32 "] = {\n",
198c75851fcSLionel Sambuc 	    (state->graph.v + 65535) / 65536);
199c75851fcSLionel Sambuc 	for (i = 0; i < state->graph.v; i += 65536)
200c75851fcSLionel Sambuc 		fprintf(nbperf->output, "%s0x%08" PRIx32 ",%s",
201c75851fcSLionel Sambuc 		    (i / 65536 % 4 == 0 ? "\t    " : " "),
202c75851fcSLionel Sambuc 		    state->holes64k[i >> 16],
203c75851fcSLionel Sambuc 		    (i / 65536 % 4 == 3 ? "\n" : ""));
204c75851fcSLionel Sambuc 	fprintf(nbperf->output, "%s\t};\n", (i / 65536 % 4 ? "\n" : ""));
205c75851fcSLionel Sambuc 
206c75851fcSLionel Sambuc 	fprintf(nbperf->output,
207c75851fcSLionel Sambuc 	    "\tstatic const uint16_t holes64[%" PRId32 "] = {\n",
208c75851fcSLionel Sambuc 	    (state->graph.v + 63) / 64);
209c75851fcSLionel Sambuc 	for (i = 0; i < state->graph.v; i += 64)
210c75851fcSLionel Sambuc 		fprintf(nbperf->output, "%s0x%04" PRIx32 ",%s",
211c75851fcSLionel Sambuc 		    (i / 64 % 4 == 0 ? "\t    " : " "),
212c75851fcSLionel Sambuc 		    state->holes64[i >> 6],
213c75851fcSLionel Sambuc 		    (i / 64 % 4 == 3 ? "\n" : ""));
214c75851fcSLionel Sambuc 	fprintf(nbperf->output, "%s\t};\n", (i / 64 % 4 ? "\n" : ""));
215c75851fcSLionel Sambuc 
216c75851fcSLionel Sambuc 	fprintf(nbperf->output, "\tuint64_t m;\n");
217c75851fcSLionel Sambuc 	fprintf(nbperf->output, "\tuint32_t idx, i, idx2;\n");
218c75851fcSLionel Sambuc 	fprintf(nbperf->output, "\tuint32_t h[%zu];\n\n", nbperf->hash_size);
219c75851fcSLionel Sambuc 
220c75851fcSLionel Sambuc 	(*nbperf->print_hash)(nbperf, "\t", "key", "keylen", "h");
221c75851fcSLionel Sambuc 
222c75851fcSLionel Sambuc 	fprintf(nbperf->output, "\n\th[0] = h[0] %% %" PRIu32 ";\n",
223c75851fcSLionel Sambuc 	    state->graph.v);
224c75851fcSLionel Sambuc 	fprintf(nbperf->output, "\th[1] = h[1] %% %" PRIu32 ";\n",
225c75851fcSLionel Sambuc 	    state->graph.v);
226c75851fcSLionel Sambuc 	fprintf(nbperf->output, "\th[2] = h[2] %% %" PRIu32 ";\n",
227c75851fcSLionel Sambuc 	    state->graph.v);
228c75851fcSLionel Sambuc 
229c75851fcSLionel Sambuc 	fprintf(nbperf->output,
23084d9c625SLionel Sambuc 	    "\tidx = 9 + ((g1[h[0] >> 6] >> (h[0] & 63)) &1)\n"
23184d9c625SLionel Sambuc 	    "\t      + ((g1[h[1] >> 6] >> (h[1] & 63)) & 1)\n"
23284d9c625SLionel Sambuc 	    "\t      + ((g1[h[2] >> 6] >> (h[2] & 63)) & 1)\n"
23384d9c625SLionel Sambuc 	    "\t      - ((g2[h[0] >> 6] >> (h[0] & 63)) & 1)\n"
23484d9c625SLionel Sambuc 	    "\t      - ((g2[h[1] >> 6] >> (h[1] & 63)) & 1)\n"
23584d9c625SLionel Sambuc 	    "\t      - ((g2[h[2] >> 6] >> (h[2] & 63)) & 1);\n"
236c75851fcSLionel Sambuc 	    );
237c75851fcSLionel Sambuc 
238c75851fcSLionel Sambuc 	fprintf(nbperf->output,
239c75851fcSLionel Sambuc 	    "\tidx = h[idx %% 3];\n");
240c75851fcSLionel Sambuc 	fprintf(nbperf->output,
241c75851fcSLionel Sambuc 	    "\tidx2 = idx - holes64[idx >> 6] - holes64k[idx >> 16];\n"
242c75851fcSLionel Sambuc 	    "\tidx2 -= popcount64(g1[idx >> 6] & g2[idx >> 6]\n"
243*0a6a1f1dSLionel Sambuc 	    "\t                   & (((uint64_t)1 << (idx & 63)) - 1));\n"
24484d9c625SLionel Sambuc 	    "\treturn idx2;\n");
245c75851fcSLionel Sambuc 
246c75851fcSLionel Sambuc 	fprintf(nbperf->output, "}\n");
247c75851fcSLionel Sambuc 
248c75851fcSLionel Sambuc 	if (nbperf->map_output != NULL) {
249c75851fcSLionel Sambuc 		for (i = 0; i < state->graph.e; ++i)
250c75851fcSLionel Sambuc 			fprintf(nbperf->map_output, "%" PRIu32 "\n",
251c75851fcSLionel Sambuc 			    state->result_map[i]);
252c75851fcSLionel Sambuc 	}
253c75851fcSLionel Sambuc }
254c75851fcSLionel Sambuc 
255c75851fcSLionel Sambuc int
bpz_compute(struct nbperf * nbperf)25684d9c625SLionel Sambuc bpz_compute(struct nbperf *nbperf)
257c75851fcSLionel Sambuc {
258c75851fcSLionel Sambuc 	struct state state;
259c75851fcSLionel Sambuc 	int retval = -1;
260c75851fcSLionel Sambuc 	uint32_t v, e;
261c75851fcSLionel Sambuc 
262c75851fcSLionel Sambuc 	if (nbperf->c == 0)
263c75851fcSLionel Sambuc 		nbperf->c = 1.24;
264c75851fcSLionel Sambuc 	if (nbperf->c < 1.24)
265c75851fcSLionel Sambuc 		errx(1, "The argument for option -c must be at least 1.24");
266c75851fcSLionel Sambuc 	if (nbperf->hash_size < 3)
267c75851fcSLionel Sambuc 		errx(1, "The hash function must generate at least 3 values");
268c75851fcSLionel Sambuc 
269c75851fcSLionel Sambuc 	(*nbperf->seed_hash)(nbperf);
270c75851fcSLionel Sambuc 	e = nbperf->n;
271c75851fcSLionel Sambuc 	v = nbperf->c * nbperf->n;
272c75851fcSLionel Sambuc 	if (1.24 * nbperf->n > v)
273c75851fcSLionel Sambuc 		++v;
274c75851fcSLionel Sambuc 	if (v < 10)
275c75851fcSLionel Sambuc 		v = 10;
276c75851fcSLionel Sambuc 
277c75851fcSLionel Sambuc 	graph3_setup(&state.graph, v, e);
278c75851fcSLionel Sambuc 
279c75851fcSLionel Sambuc 	state.holes64k = calloc(sizeof(uint32_t), (v + 65535) / 65536);
280c75851fcSLionel Sambuc 	state.holes64 = calloc(sizeof(uint16_t), (v + 63) / 64 );
281c75851fcSLionel Sambuc 	state.g = calloc(sizeof(uint32_t), v | 63);
282c75851fcSLionel Sambuc 	state.visited = calloc(sizeof(uint32_t), v);
283c75851fcSLionel Sambuc 	state.result_map = calloc(sizeof(uint32_t), e);
284c75851fcSLionel Sambuc 
285c75851fcSLionel Sambuc 	if (state.holes64k == NULL || state.holes64 == NULL ||
286c75851fcSLionel Sambuc 	    state.g == NULL || state.visited == NULL ||
287c75851fcSLionel Sambuc 	    state.result_map == NULL)
288c75851fcSLionel Sambuc 		err(1, "malloc failed");
289c75851fcSLionel Sambuc 
290c75851fcSLionel Sambuc 	if (graph3_hash(nbperf, &state.graph))
291c75851fcSLionel Sambuc 		goto failed;
292c75851fcSLionel Sambuc 	if (graph3_output_order(&state.graph))
293c75851fcSLionel Sambuc 		goto failed;
294c75851fcSLionel Sambuc 	assign_nodes(&state);
295c75851fcSLionel Sambuc 	print_hash(nbperf, &state);
296c75851fcSLionel Sambuc 
297c75851fcSLionel Sambuc 	retval = 0;
298c75851fcSLionel Sambuc 
299c75851fcSLionel Sambuc failed:
300c75851fcSLionel Sambuc 	graph3_free(&state.graph);
301c75851fcSLionel Sambuc 	free(state.visited);
302c75851fcSLionel Sambuc 	free(state.g);
303c75851fcSLionel Sambuc 	free(state.holes64k);
304c75851fcSLionel Sambuc 	free(state.holes64);
305c75851fcSLionel Sambuc 	free(state.result_map);
306c75851fcSLionel Sambuc 	return retval;
307c75851fcSLionel Sambuc }
308