Home | History | Annotate | Line # | Download | only in nbperf
      1 /*	$NetBSD: graph2.c,v 1.6 2021/01/28 18:52:43 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 #if HAVE_NBTOOL_CONFIG_H
     35 #include "nbtool_config.h"
     36 #endif
     37 
     38 #include <sys/cdefs.h>
     39 __RCSID("$NetBSD: graph2.c,v 1.6 2021/01/28 18:52:43 joerg Exp $");
     40 
     41 #include <err.h>
     42 #include <inttypes.h>
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <string.h>
     46 
     47 #include "nbperf.h"
     48 #include "graph2.h"
     49 
     50 void
     51 SIZED2(_setup)(struct SIZED(graph) *graph, uint32_t v, uint32_t e)
     52 {
     53 	graph->v = v;
     54 	graph->e = e;
     55 
     56 	graph->verts = calloc(sizeof(*graph->verts), v);
     57 	graph->edges = calloc(sizeof(*graph->edges), e);
     58 	graph->output_order = calloc(sizeof(uint32_t), e);
     59 
     60 	if (graph->verts == NULL || graph->edges == NULL ||
     61 	    graph->output_order == NULL)
     62 		err(1, "malloc failed");
     63 }
     64 
     65 void
     66 SIZED2(_free)(struct SIZED(graph) *graph)
     67 {
     68 	free(graph->verts);
     69 	free(graph->edges);
     70 	free(graph->output_order);
     71 
     72 	graph->verts = NULL;
     73 	graph->edges = NULL;
     74 	graph->output_order = NULL;
     75 }
     76 
     77 static struct nbperf *sorting_nbperf;
     78 static struct SIZED(graph) *sorting_graph;
     79 static int sorting_found;
     80 
     81 static int sorting_cmp(const void *a_, const void *b_)
     82 {
     83 	const uint32_t *a = a_, *b = b_;
     84 	int i;
     85 	const struct SIZED(edge) *ea = &sorting_graph->edges[*a],
     86 	    *eb = &sorting_graph->edges[*b];
     87 	for (i = 0; i < GRAPH_SIZE; ++i) {
     88 		if (ea->vertices[i] < eb->vertices[i])
     89 			return -1;
     90 		if (ea->vertices[i] > eb->vertices[i])
     91 			return 1;
     92 	}
     93 	if (sorting_nbperf->keylens[*a] < sorting_nbperf->keylens[*b])
     94 		return -1;
     95 	if (sorting_nbperf->keylens[*a] > sorting_nbperf->keylens[*b])
     96 		return 1;
     97 	i = memcmp(sorting_nbperf->keys[*a], sorting_nbperf->keys[*b],
     98 	    sorting_nbperf->keylens[*a]);
     99 	if (i == 0)
    100 		sorting_found = 1;
    101 	return i;
    102 }
    103 
    104 static int
    105 SIZED2(_check_duplicates)(struct nbperf *nbperf, struct SIZED(graph) *graph)
    106 {
    107 	size_t i;
    108 	uint32_t *key_index = calloc(sizeof(*key_index), graph->e);
    109 
    110 	if (key_index == NULL)
    111 		err(1, "malloc failed");
    112 	for (i = 0; i < graph->e; ++i)
    113 		key_index[i] = i;
    114 
    115 	sorting_nbperf = nbperf;
    116 	sorting_graph = graph;
    117 	sorting_found = 0;
    118 	qsort(key_index, graph->e, sizeof(*key_index), sorting_cmp);
    119 	if (sorting_found)
    120 		goto found_dups;
    121 	/*
    122 	 * Any duplicate must have been found as part of the qsort,
    123 	 * as it can't sort consecutive elements in the output without
    124 	 * comparing them at least once.
    125 	 */
    126 
    127 	free(key_index);
    128 	return 0;
    129  found_dups:
    130 	nbperf->has_duplicates = 1;
    131 	return -1;
    132 }
    133 
    134 static inline void
    135 SIZED2(_add_edge)(struct SIZED(graph) *graph, uint32_t edge)
    136 {
    137 	struct SIZED(edge) *e = graph->edges + edge;
    138 	struct SIZED(vertex) *v;
    139 	size_t i;
    140 
    141 	for (i = 0; i < GRAPH_SIZE; ++i) {
    142 		v = graph->verts + e->vertices[i];
    143 		v->edges ^= edge;
    144 		++v->degree;
    145 	}
    146 }
    147 
    148 static inline void
    149 SIZED2(_remove_edge)(struct SIZED(graph) *graph, uint32_t edge)
    150 {
    151 	struct SIZED(edge) *e = graph->edges + edge;
    152 	struct SIZED(vertex) *v;
    153 	size_t i;
    154 
    155 	for (i = 0; i < GRAPH_SIZE; ++i) {
    156 		v = graph->verts + e->vertices[i];
    157 		v->edges ^= edge;
    158 		--v->degree;
    159 	}
    160 }
    161 
    162 static inline void
    163 SIZED2(_remove_vertex)(struct SIZED(graph) *graph, uint32_t vertex)
    164 {
    165 	struct SIZED(vertex) *v = graph->verts + vertex;
    166 	uint32_t e;
    167 
    168 	if (v->degree == 1) {
    169 		e = v->edges;
    170 		graph->output_order[--graph->output_index] = e;
    171 		SIZED2(_remove_edge)(graph, e);
    172 	}
    173 }
    174 
    175 int
    176 SIZED2(_hash)(struct nbperf *nbperf, struct SIZED(graph) *graph)
    177 {
    178 	struct SIZED(edge) *e;
    179 	uint32_t hashes[NBPERF_MAX_HASH_SIZE];
    180 	size_t i, j;
    181 
    182 #if GRAPH_SIZE == 2
    183 	if (nbperf->allow_hash_fudging && (graph->v & 1) != 0)
    184 		errx(1, "vertex count must have lowest bit clear");
    185 #else
    186 	if (nbperf->allow_hash_fudging && (graph->v & 3) != 0)
    187 		errx(1, "vertex count must have lowest 2 bits clear");
    188 #endif
    189 
    190 
    191 	memset(graph->verts, 0, sizeof(*graph->verts) * graph->v);
    192 	graph->hash_fudge = 0;
    193 
    194 	for (i = 0; i < graph->e; ++i) {
    195 		(*nbperf->compute_hash)(nbperf,
    196 		    nbperf->keys[i], nbperf->keylens[i], hashes);
    197 		e = graph->edges + i;
    198 		for (j = 0; j < GRAPH_SIZE; ++j) {
    199 			e->vertices[j] = hashes[j] % graph->v;
    200 			if (j == 1 && e->vertices[0] == e->vertices[1]) {
    201 				if (!nbperf->allow_hash_fudging)
    202 					return -1;
    203 				e->vertices[1] ^= 1; /* toogle bit to differ */
    204 				graph->hash_fudge |= 1;
    205 			}
    206 #if GRAPH_SIZE == 3
    207 			if (j == 2 && (e->vertices[0] == e->vertices[2] ||
    208 			    e->vertices[1] == e->vertices[2])) {
    209 				if (!nbperf->allow_hash_fudging)
    210 					return -1;
    211 				graph->hash_fudge |= 2;
    212 				e->vertices[2] ^= 1;
    213 				e->vertices[2] ^= 2 * (e->vertices[0] == e->vertices[2] ||
    214 				    e->vertices[1] == e->vertices[2]);
    215 			}
    216 #endif
    217 		}
    218 	}
    219 
    220 	for (i = 0; i < graph->e; ++i)
    221 		SIZED2(_add_edge)(graph, i);
    222 
    223 	if (nbperf->check_duplicates) {
    224 		nbperf->check_duplicates = 0;
    225 		return SIZED2(_check_duplicates)(nbperf, graph);
    226 	}
    227 
    228 	return 0;
    229 }
    230 
    231 int
    232 SIZED2(_output_order)(struct SIZED(graph) *graph)
    233 {
    234 	size_t i, j;
    235 	struct SIZED(edge) *e2;
    236 
    237 	graph->output_index = graph->e;
    238 
    239 	for (i = 0; i < graph->v; ++i)
    240 		SIZED2(_remove_vertex)(graph, i);
    241 
    242 	for (i = graph->e; graph->output_index > 0 && i > graph->output_index;) {
    243 		e2 = graph->edges + graph->output_order[--i];
    244 		for (j = 0; j < GRAPH_SIZE; ++j)
    245 			SIZED2(_remove_vertex)(graph, e2->vertices[j]);
    246 	}
    247 
    248 	if (graph->output_index != 0) {
    249 		return -1;
    250 	}
    251 
    252 	return 0;
    253 }
    254