1 1.6 joerg /* $NetBSD: graph2.c,v 1.6 2021/01/28 18:52:43 joerg Exp $ */ 2 1.1 joerg /*- 3 1.1 joerg * Copyright (c) 2009 The NetBSD Foundation, Inc. 4 1.1 joerg * All rights reserved. 5 1.1 joerg * 6 1.1 joerg * This code is derived from software contributed to The NetBSD Foundation 7 1.1 joerg * by Joerg Sonnenberger. 8 1.1 joerg * 9 1.1 joerg * Redistribution and use in source and binary forms, with or without 10 1.1 joerg * modification, are permitted provided that the following conditions 11 1.1 joerg * are met: 12 1.1 joerg * 13 1.1 joerg * 1. Redistributions of source code must retain the above copyright 14 1.1 joerg * notice, this list of conditions and the following disclaimer. 15 1.1 joerg * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 joerg * notice, this list of conditions and the following disclaimer in 17 1.1 joerg * the documentation and/or other materials provided with the 18 1.1 joerg * distribution. 19 1.1 joerg * 20 1.1 joerg * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 1.1 joerg * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 1.1 joerg * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 1.1 joerg * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 1.1 joerg * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 1.1 joerg * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 1.1 joerg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 1.1 joerg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 1.1 joerg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 1.1 joerg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30 1.1 joerg * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 joerg * SUCH DAMAGE. 32 1.1 joerg */ 33 1.1 joerg 34 1.4 joerg #if HAVE_NBTOOL_CONFIG_H 35 1.4 joerg #include "nbtool_config.h" 36 1.4 joerg #endif 37 1.4 joerg 38 1.1 joerg #include <sys/cdefs.h> 39 1.6 joerg __RCSID("$NetBSD: graph2.c,v 1.6 2021/01/28 18:52:43 joerg Exp $"); 40 1.1 joerg 41 1.1 joerg #include <err.h> 42 1.1 joerg #include <inttypes.h> 43 1.1 joerg #include <stdio.h> 44 1.1 joerg #include <stdlib.h> 45 1.3 joerg #include <string.h> 46 1.1 joerg 47 1.1 joerg #include "nbperf.h" 48 1.1 joerg #include "graph2.h" 49 1.1 joerg 50 1.1 joerg void 51 1.5 joerg SIZED2(_setup)(struct SIZED(graph) *graph, uint32_t v, uint32_t e) 52 1.1 joerg { 53 1.1 joerg graph->v = v; 54 1.1 joerg graph->e = e; 55 1.1 joerg 56 1.5 joerg graph->verts = calloc(sizeof(*graph->verts), v); 57 1.5 joerg graph->edges = calloc(sizeof(*graph->edges), e); 58 1.1 joerg graph->output_order = calloc(sizeof(uint32_t), e); 59 1.1 joerg 60 1.1 joerg if (graph->verts == NULL || graph->edges == NULL || 61 1.1 joerg graph->output_order == NULL) 62 1.1 joerg err(1, "malloc failed"); 63 1.1 joerg } 64 1.1 joerg 65 1.1 joerg void 66 1.5 joerg SIZED2(_free)(struct SIZED(graph) *graph) 67 1.1 joerg { 68 1.1 joerg free(graph->verts); 69 1.1 joerg free(graph->edges); 70 1.1 joerg free(graph->output_order); 71 1.1 joerg 72 1.1 joerg graph->verts = NULL; 73 1.1 joerg graph->edges = NULL; 74 1.1 joerg graph->output_order = NULL; 75 1.1 joerg } 76 1.1 joerg 77 1.5 joerg static struct nbperf *sorting_nbperf; 78 1.5 joerg static struct SIZED(graph) *sorting_graph; 79 1.5 joerg static int sorting_found; 80 1.5 joerg 81 1.5 joerg static int sorting_cmp(const void *a_, const void *b_) 82 1.5 joerg { 83 1.5 joerg const uint32_t *a = a_, *b = b_; 84 1.5 joerg int i; 85 1.5 joerg const struct SIZED(edge) *ea = &sorting_graph->edges[*a], 86 1.5 joerg *eb = &sorting_graph->edges[*b]; 87 1.5 joerg for (i = 0; i < GRAPH_SIZE; ++i) { 88 1.5 joerg if (ea->vertices[i] < eb->vertices[i]) 89 1.5 joerg return -1; 90 1.5 joerg if (ea->vertices[i] > eb->vertices[i]) 91 1.5 joerg return 1; 92 1.5 joerg } 93 1.5 joerg if (sorting_nbperf->keylens[*a] < sorting_nbperf->keylens[*b]) 94 1.5 joerg return -1; 95 1.5 joerg if (sorting_nbperf->keylens[*a] > sorting_nbperf->keylens[*b]) 96 1.5 joerg return 1; 97 1.5 joerg i = memcmp(sorting_nbperf->keys[*a], sorting_nbperf->keys[*b], 98 1.5 joerg sorting_nbperf->keylens[*a]); 99 1.5 joerg if (i == 0) 100 1.5 joerg sorting_found = 1; 101 1.5 joerg return i; 102 1.5 joerg } 103 1.5 joerg 104 1.3 joerg static int 105 1.5 joerg SIZED2(_check_duplicates)(struct nbperf *nbperf, struct SIZED(graph) *graph) 106 1.3 joerg { 107 1.5 joerg size_t i; 108 1.5 joerg uint32_t *key_index = calloc(sizeof(*key_index), graph->e); 109 1.3 joerg 110 1.5 joerg if (key_index == NULL) 111 1.5 joerg err(1, "malloc failed"); 112 1.5 joerg for (i = 0; i < graph->e; ++i) 113 1.5 joerg key_index[i] = i; 114 1.5 joerg 115 1.5 joerg sorting_nbperf = nbperf; 116 1.5 joerg sorting_graph = graph; 117 1.5 joerg sorting_found = 0; 118 1.5 joerg qsort(key_index, graph->e, sizeof(*key_index), sorting_cmp); 119 1.5 joerg if (sorting_found) 120 1.5 joerg goto found_dups; 121 1.5 joerg /* 122 1.5 joerg * Any duplicate must have been found as part of the qsort, 123 1.5 joerg * as it can't sort consecutive elements in the output without 124 1.5 joerg * comparing them at least once. 125 1.5 joerg */ 126 1.5 joerg 127 1.5 joerg free(key_index); 128 1.3 joerg return 0; 129 1.5 joerg found_dups: 130 1.5 joerg nbperf->has_duplicates = 1; 131 1.5 joerg return -1; 132 1.3 joerg } 133 1.3 joerg 134 1.5 joerg static inline void 135 1.5 joerg SIZED2(_add_edge)(struct SIZED(graph) *graph, uint32_t edge) 136 1.1 joerg { 137 1.5 joerg struct SIZED(edge) *e = graph->edges + edge; 138 1.5 joerg struct SIZED(vertex) *v; 139 1.1 joerg size_t i; 140 1.1 joerg 141 1.5 joerg for (i = 0; i < GRAPH_SIZE; ++i) { 142 1.5 joerg v = graph->verts + e->vertices[i]; 143 1.5 joerg v->edges ^= edge; 144 1.5 joerg ++v->degree; 145 1.1 joerg } 146 1.5 joerg } 147 1.5 joerg 148 1.5 joerg static inline void 149 1.5 joerg SIZED2(_remove_edge)(struct SIZED(graph) *graph, uint32_t edge) 150 1.5 joerg { 151 1.5 joerg struct SIZED(edge) *e = graph->edges + edge; 152 1.5 joerg struct SIZED(vertex) *v; 153 1.5 joerg size_t i; 154 1.1 joerg 155 1.5 joerg for (i = 0; i < GRAPH_SIZE; ++i) { 156 1.5 joerg v = graph->verts + e->vertices[i]; 157 1.5 joerg v->edges ^= edge; 158 1.5 joerg --v->degree; 159 1.1 joerg } 160 1.5 joerg } 161 1.1 joerg 162 1.5 joerg static inline void 163 1.5 joerg SIZED2(_remove_vertex)(struct SIZED(graph) *graph, uint32_t vertex) 164 1.5 joerg { 165 1.5 joerg struct SIZED(vertex) *v = graph->verts + vertex; 166 1.5 joerg uint32_t e; 167 1.5 joerg 168 1.5 joerg if (v->degree == 1) { 169 1.5 joerg e = v->edges; 170 1.5 joerg graph->output_order[--graph->output_index] = e; 171 1.5 joerg SIZED2(_remove_edge)(graph, e); 172 1.3 joerg } 173 1.1 joerg } 174 1.1 joerg 175 1.5 joerg int 176 1.5 joerg SIZED2(_hash)(struct nbperf *nbperf, struct SIZED(graph) *graph) 177 1.1 joerg { 178 1.5 joerg struct SIZED(edge) *e; 179 1.5 joerg uint32_t hashes[NBPERF_MAX_HASH_SIZE]; 180 1.5 joerg size_t i, j; 181 1.1 joerg 182 1.5 joerg #if GRAPH_SIZE == 2 183 1.6 joerg if (nbperf->allow_hash_fudging && (graph->v & 1) != 0) 184 1.6 joerg errx(1, "vertex count must have lowest bit clear"); 185 1.5 joerg #else 186 1.6 joerg if (nbperf->allow_hash_fudging && (graph->v & 3) != 0) 187 1.6 joerg errx(1, "vertex count must have lowest 2 bits clear"); 188 1.5 joerg #endif 189 1.5 joerg 190 1.5 joerg 191 1.5 joerg memset(graph->verts, 0, sizeof(*graph->verts) * graph->v); 192 1.5 joerg graph->hash_fudge = 0; 193 1.5 joerg 194 1.5 joerg for (i = 0; i < graph->e; ++i) { 195 1.5 joerg (*nbperf->compute_hash)(nbperf, 196 1.5 joerg nbperf->keys[i], nbperf->keylens[i], hashes); 197 1.5 joerg e = graph->edges + i; 198 1.5 joerg for (j = 0; j < GRAPH_SIZE; ++j) { 199 1.5 joerg e->vertices[j] = hashes[j] % graph->v; 200 1.5 joerg if (j == 1 && e->vertices[0] == e->vertices[1]) { 201 1.5 joerg if (!nbperf->allow_hash_fudging) 202 1.5 joerg return -1; 203 1.5 joerg e->vertices[1] ^= 1; /* toogle bit to differ */ 204 1.5 joerg graph->hash_fudge |= 1; 205 1.5 joerg } 206 1.5 joerg #if GRAPH_SIZE == 3 207 1.5 joerg if (j == 2 && (e->vertices[0] == e->vertices[2] || 208 1.5 joerg e->vertices[1] == e->vertices[2])) { 209 1.5 joerg if (!nbperf->allow_hash_fudging) 210 1.5 joerg return -1; 211 1.5 joerg graph->hash_fudge |= 2; 212 1.5 joerg e->vertices[2] ^= 1; 213 1.5 joerg e->vertices[2] ^= 2 * (e->vertices[0] == e->vertices[2] || 214 1.5 joerg e->vertices[1] == e->vertices[2]); 215 1.5 joerg } 216 1.5 joerg #endif 217 1.1 joerg } 218 1.5 joerg } 219 1.5 joerg 220 1.5 joerg for (i = 0; i < graph->e; ++i) 221 1.5 joerg SIZED2(_add_edge)(graph, i); 222 1.1 joerg 223 1.5 joerg if (nbperf->check_duplicates) { 224 1.5 joerg nbperf->check_duplicates = 0; 225 1.5 joerg return SIZED2(_check_duplicates)(nbperf, graph); 226 1.1 joerg } 227 1.5 joerg 228 1.5 joerg return 0; 229 1.1 joerg } 230 1.1 joerg 231 1.1 joerg int 232 1.5 joerg SIZED2(_output_order)(struct SIZED(graph) *graph) 233 1.1 joerg { 234 1.5 joerg size_t i, j; 235 1.5 joerg struct SIZED(edge) *e2; 236 1.1 joerg 237 1.1 joerg graph->output_index = graph->e; 238 1.1 joerg 239 1.1 joerg for (i = 0; i < graph->v; ++i) 240 1.5 joerg SIZED2(_remove_vertex)(graph, i); 241 1.1 joerg 242 1.5 joerg for (i = graph->e; graph->output_index > 0 && i > graph->output_index;) { 243 1.5 joerg e2 = graph->edges + graph->output_order[--i]; 244 1.5 joerg for (j = 0; j < GRAPH_SIZE; ++j) 245 1.5 joerg SIZED2(_remove_vertex)(graph, e2->vertices[j]); 246 1.5 joerg } 247 1.5 joerg 248 1.5 joerg if (graph->output_index != 0) { 249 1.1 joerg return -1; 250 1.5 joerg } 251 1.1 joerg 252 1.1 joerg return 0; 253 1.1 joerg } 254