xref: /netbsd-src/usr.bin/nbperf/graph2.c (revision 1ca06f9c9235889e2ff6dc77279d01d151d70a9a)
1 /*	$NetBSD: graph2.c,v 1.2 2009/08/22 17:52:17 joerg Exp $	*/
2 /*-
3  * Copyright (c) 2009 The NetBSD Foundation, Inc.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to The NetBSD Foundation
7  * by Joerg Sonnenberger.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: graph2.c,v 1.2 2009/08/22 17:52:17 joerg Exp $");
36 
37 #include <err.h>
38 #include <inttypes.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 
42 #include "nbperf.h"
43 #include "graph2.h"
44 
45 static const uint32_t unused = 0xffffffffU;
46 
47 void
48 graph2_setup(struct graph2 *graph, uint32_t v, uint32_t e)
49 {
50 	graph->v = v;
51 	graph->e = e;
52 
53 	graph->verts = calloc(sizeof(struct vertex2), v);
54 	graph->edges = calloc(sizeof(struct edge2), e);
55 	graph->output_order = calloc(sizeof(uint32_t), e);
56 
57 	if (graph->verts == NULL || graph->edges == NULL ||
58 	    graph->output_order == NULL)
59 		err(1, "malloc failed");
60 }
61 
62 void
63 graph2_free(struct graph2 *graph)
64 {
65 	free(graph->verts);
66 	free(graph->edges);
67 	free(graph->output_order);
68 
69 	graph->verts = NULL;
70 	graph->edges = NULL;
71 	graph->output_order = NULL;
72 }
73 
74 int
75 graph2_hash(struct nbperf *nbperf, struct graph2 *graph)
76 {
77 	struct vertex2 *v;
78 	uint32_t hashes[NBPERF_MAX_HASH_SIZE];
79 	size_t i;
80 
81 	for (i = 0; i < graph->e; ++i) {
82 		(*nbperf->compute_hash)(nbperf,
83 		    nbperf->keys[i], nbperf->keylens[i], hashes);
84 		graph->edges[i].left = hashes[0] % graph->v;
85 		graph->edges[i].right = hashes[1] % graph->v;
86 		if (graph->edges[i].left == graph->edges[i].right)
87 			return -1;
88 	}
89 
90 	for (i = 0; i < graph->v; ++i) {
91 		graph->verts[i].l_edge = unused;
92 		graph->verts[i].r_edge = unused;
93 	}
94 
95 	for (i = 0; i < graph->e; ++i) {
96 		v = &graph->verts[graph->edges[i].left];
97 		if (v->l_edge != unused)
98 			graph->edges[v->l_edge].l_prev = i;
99 		graph->edges[i].l_next = v->l_edge;
100 		graph->edges[i].l_prev = unused;
101 		v->l_edge = i;
102 
103 		v = &graph->verts[graph->edges[i].right];
104 		if (v->r_edge != unused)
105 			graph->edges[v->r_edge].r_prev = i;
106 		graph->edges[i].r_next = v->r_edge;
107 		graph->edges[i].r_prev = unused;
108 		v->r_edge = i;
109 	}
110 
111 	return 0;
112 }
113 
114 static void
115 graph2_remove_vertex(struct graph2 *graph, struct vertex2 *v)
116 {
117 	struct edge2 *e;
118 	struct vertex2 *v2;
119 
120 	for (;;) {
121 		if (v->l_edge != unused && v->r_edge != unused)
122 			break;
123 		if (v->l_edge == unused && v->r_edge == unused)
124 			break;
125 
126 		if (v->l_edge != unused) {
127 			e = &graph->edges[v->l_edge];
128 			if (e->l_next != unused)
129 				break;
130 			v->l_edge = unused; /* No other elements possible! */
131 			v2 = &graph->verts[e->right];
132 			if (e->r_prev == unused)
133 				v2->r_edge = e->r_next;
134 			else
135 				graph->edges[e->r_prev].r_next = e->r_next;
136 			if (e->r_next != unused)
137 				graph->edges[e->r_next].r_prev = e->r_prev;
138 			v = v2;
139 		} else {
140 			e = &graph->edges[v->r_edge];
141 			if (e->r_next != unused)
142 				break;
143 			v->r_edge = unused; /* No other elements possible! */
144 			v2 = &graph->verts[e->left];
145 			if (e->l_prev == unused)
146 				v2->l_edge = e->l_next;
147 			else
148 				graph->edges[e->l_prev].l_next = e->l_next;
149 			if (e->l_next != unused)
150 				graph->edges[e->l_next].l_prev = e->l_prev;
151 			v = v2;
152 		}
153 
154 		graph->output_order[--graph->output_index] = e - graph->edges;
155 	}
156 }
157 
158 int
159 graph2_output_order(struct graph2 *graph)
160 {
161 	size_t i;
162 
163 	graph->output_index = graph->e;
164 
165 	for (i = 0; i < graph->v; ++i)
166 		graph2_remove_vertex(graph, &graph->verts[i]);
167 
168 	if (graph->output_index != 0)
169 		return -1;
170 
171 	return 0;
172 }
173