1*366fc9ceSchristos /* $NetBSD: nbperf.c,v 1.9 2024/09/22 20:34:26 christos Exp $ */ 203c8ba1cSjoerg /*- 303c8ba1cSjoerg * Copyright (c) 2009 The NetBSD Foundation, Inc. 403c8ba1cSjoerg * All rights reserved. 503c8ba1cSjoerg * 603c8ba1cSjoerg * This code is derived from software contributed to The NetBSD Foundation 703c8ba1cSjoerg * by Joerg Sonnenberger. 803c8ba1cSjoerg * 903c8ba1cSjoerg * Redistribution and use in source and binary forms, with or without 1003c8ba1cSjoerg * modification, are permitted provided that the following conditions 1103c8ba1cSjoerg * are met: 1203c8ba1cSjoerg * 1303c8ba1cSjoerg * 1. Redistributions of source code must retain the above copyright 1403c8ba1cSjoerg * notice, this list of conditions and the following disclaimer. 1503c8ba1cSjoerg * 2. Redistributions in binary form must reproduce the above copyright 1603c8ba1cSjoerg * notice, this list of conditions and the following disclaimer in 1703c8ba1cSjoerg * the documentation and/or other materials provided with the 1803c8ba1cSjoerg * distribution. 1903c8ba1cSjoerg * 2003c8ba1cSjoerg * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2103c8ba1cSjoerg * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2203c8ba1cSjoerg * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2303c8ba1cSjoerg * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 2403c8ba1cSjoerg * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2503c8ba1cSjoerg * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 2603c8ba1cSjoerg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2703c8ba1cSjoerg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2803c8ba1cSjoerg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2903c8ba1cSjoerg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 3003c8ba1cSjoerg * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3103c8ba1cSjoerg * SUCH DAMAGE. 3203c8ba1cSjoerg */ 3303c8ba1cSjoerg 3410769988Sjoerg #if HAVE_NBTOOL_CONFIG_H 3510769988Sjoerg #include "nbtool_config.h" 3610769988Sjoerg #endif 3710769988Sjoerg 3803c8ba1cSjoerg #include <sys/cdefs.h> 39*366fc9ceSchristos __RCSID("$NetBSD: nbperf.c,v 1.9 2024/09/22 20:34:26 christos Exp $"); 4003c8ba1cSjoerg 4103c8ba1cSjoerg #include <sys/endian.h> 4203c8ba1cSjoerg #include <err.h> 4303c8ba1cSjoerg #include <errno.h> 4403c8ba1cSjoerg #include <inttypes.h> 4503c8ba1cSjoerg #include <stdlib.h> 4603c8ba1cSjoerg #include <stdio.h> 4703c8ba1cSjoerg #include <string.h> 487c219dd6Sjoerg #include <time.h> 4903c8ba1cSjoerg #include <unistd.h> 5003c8ba1cSjoerg 5103c8ba1cSjoerg #include "nbperf.h" 5203c8ba1cSjoerg 5310769988Sjoerg static int predictable; 5410769988Sjoerg 5503c8ba1cSjoerg static __dead 5603c8ba1cSjoerg void usage(void) 5703c8ba1cSjoerg { 5803c8ba1cSjoerg fprintf(stderr, 5910769988Sjoerg "%s [-ps] [-c utilisation] [-i iterations] [-n name] " 6003c8ba1cSjoerg "[-o output] input\n", 6103c8ba1cSjoerg getprogname()); 6203c8ba1cSjoerg exit(1); 6303c8ba1cSjoerg } 6403c8ba1cSjoerg 6548b62e13Sjoerg #if HAVE_NBTOOL_CONFIG_H 6610769988Sjoerg #define arc4random() rand() 6710769988Sjoerg #endif 6810769988Sjoerg 6903c8ba1cSjoerg static void 7003c8ba1cSjoerg mi_vector_hash_seed_hash(struct nbperf *nbperf) 7103c8ba1cSjoerg { 7210769988Sjoerg static uint32_t predictable_counter; 7310769988Sjoerg if (predictable) 7410769988Sjoerg nbperf->seed[0] = predictable_counter++; 7510769988Sjoerg else 7603c8ba1cSjoerg nbperf->seed[0] = arc4random(); 7703c8ba1cSjoerg } 7803c8ba1cSjoerg 7903c8ba1cSjoerg static void 8003c8ba1cSjoerg mi_vector_hash_compute(struct nbperf *nbperf, const void *key, size_t keylen, 8103c8ba1cSjoerg uint32_t *hashes) 8203c8ba1cSjoerg { 8303c8ba1cSjoerg mi_vector_hash(key, keylen, nbperf->seed[0], hashes); 8403c8ba1cSjoerg } 8503c8ba1cSjoerg 8603c8ba1cSjoerg static void 8703c8ba1cSjoerg mi_vector_hash_print_hash(struct nbperf *nbperf, const char *indent, 8803c8ba1cSjoerg const char *key, const char *keylen, const char *hash) 8903c8ba1cSjoerg { 9003c8ba1cSjoerg fprintf(nbperf->output, 9103c8ba1cSjoerg "%smi_vector_hash(%s, %s, 0x%08" PRIx32 "U, %s);\n", 9203c8ba1cSjoerg indent, key, keylen, nbperf->seed[0], hash); 9303c8ba1cSjoerg } 9403c8ba1cSjoerg 9503c8ba1cSjoerg static void 9603c8ba1cSjoerg set_hash(struct nbperf *nbperf, const char *arg) 9703c8ba1cSjoerg { 9803c8ba1cSjoerg if (strcmp(arg, "mi_vector_hash") == 0) { 9903c8ba1cSjoerg nbperf->hash_size = 3; 10003c8ba1cSjoerg nbperf->seed_hash = mi_vector_hash_seed_hash; 10103c8ba1cSjoerg nbperf->compute_hash = mi_vector_hash_compute; 10203c8ba1cSjoerg nbperf->print_hash = mi_vector_hash_print_hash; 10303c8ba1cSjoerg return; 10403c8ba1cSjoerg } 105976b948dSjoerg if (nbperf->hash_size > NBPERF_MAX_HASH_SIZE) 106976b948dSjoerg errx(1, "Hash function creates too many output values"); 10703c8ba1cSjoerg errx(1, "Unknown hash function: %s", arg); 10803c8ba1cSjoerg } 10903c8ba1cSjoerg 11003c8ba1cSjoerg int 11103c8ba1cSjoerg main(int argc, char **argv) 11203c8ba1cSjoerg { 11303c8ba1cSjoerg struct nbperf nbperf = { 11403c8ba1cSjoerg .c = 0, 11503c8ba1cSjoerg .hash_name = "hash", 11603c8ba1cSjoerg .map_output = NULL, 11703c8ba1cSjoerg .output = NULL, 11803c8ba1cSjoerg .static_hash = 0, 1197c219dd6Sjoerg .check_duplicates = 0, 120f9c779deSjoerg .has_duplicates = 0, 1217c219dd6Sjoerg .allow_hash_fudging = 0, 12203c8ba1cSjoerg }; 12303c8ba1cSjoerg FILE *input; 12403c8ba1cSjoerg size_t curlen = 0, curalloc = 0; 12503c8ba1cSjoerg char *line, *eos; 12610769988Sjoerg ssize_t line_len; 12710769988Sjoerg size_t line_allocated; 12803c8ba1cSjoerg const void **keys = NULL; 12903c8ba1cSjoerg size_t *keylens = NULL; 130*366fc9ceSchristos uint32_t max_iterations = ~0U; 13103c8ba1cSjoerg long long tmp; 13203c8ba1cSjoerg int looped, ch; 13303c8ba1cSjoerg int (*build_hash)(struct nbperf *) = chm_compute; 13403c8ba1cSjoerg 13503c8ba1cSjoerg set_hash(&nbperf, "mi_vector_hash"); 13603c8ba1cSjoerg 1377c219dd6Sjoerg while ((ch = getopt(argc, argv, "a:c:fh:i:m:n:o:ps")) != -1) { 13803c8ba1cSjoerg switch (ch) { 13903c8ba1cSjoerg case 'a': 140a81d4ca3Sjoerg /* Accept bdz as alias for netbsd-6 compat. */ 14103c8ba1cSjoerg if (strcmp(optarg, "chm") == 0) 14203c8ba1cSjoerg build_hash = chm_compute; 14303c8ba1cSjoerg else if (strcmp(optarg, "chm3") == 0) 14403c8ba1cSjoerg build_hash = chm3_compute; 145a81d4ca3Sjoerg else if (strcmp(optarg, "bpz") == 0 || 146a81d4ca3Sjoerg strcmp(optarg, "bdz") == 0) 147a81d4ca3Sjoerg build_hash = bpz_compute; 14803c8ba1cSjoerg else 149947fbafbSandvar errx(1, "Unsupported algorithm: %s", optarg); 15003c8ba1cSjoerg break; 15103c8ba1cSjoerg case 'c': 15203c8ba1cSjoerg errno = 0; 15303c8ba1cSjoerg nbperf.c = strtod(optarg, &eos); 15403c8ba1cSjoerg if (errno || eos[0] || !nbperf.c) 15503c8ba1cSjoerg errx(2, "Invalid argument for -c"); 15603c8ba1cSjoerg break; 1577c219dd6Sjoerg case 'f': 1587c219dd6Sjoerg nbperf.allow_hash_fudging = 1; 1597c219dd6Sjoerg break; 16003c8ba1cSjoerg case 'h': 16103c8ba1cSjoerg set_hash(&nbperf, optarg); 16203c8ba1cSjoerg break; 16303c8ba1cSjoerg case 'i': 16403c8ba1cSjoerg errno = 0; 16503c8ba1cSjoerg tmp = strtoll(optarg, &eos, 0); 16603c8ba1cSjoerg if (errno || eos == optarg || eos[0] || 16703c8ba1cSjoerg tmp < 0 || tmp > 0xffffffffU) 16803c8ba1cSjoerg errx(2, "Iteration count must be " 16903c8ba1cSjoerg "a 32bit integer"); 17003c8ba1cSjoerg max_iterations = (uint32_t)tmp; 17103c8ba1cSjoerg break; 17203c8ba1cSjoerg case 'm': 17303c8ba1cSjoerg if (nbperf.map_output) 17403c8ba1cSjoerg fclose(nbperf.map_output); 17503c8ba1cSjoerg nbperf.map_output = fopen(optarg, "w"); 17603c8ba1cSjoerg if (nbperf.map_output == NULL) 17703c8ba1cSjoerg err(2, "cannot open map file"); 17803c8ba1cSjoerg break; 17903c8ba1cSjoerg case 'n': 18003c8ba1cSjoerg nbperf.hash_name = optarg; 18103c8ba1cSjoerg break; 18203c8ba1cSjoerg case 'o': 18303c8ba1cSjoerg if (nbperf.output) 18403c8ba1cSjoerg fclose(nbperf.output); 18503c8ba1cSjoerg nbperf.output = fopen(optarg, "w"); 18603c8ba1cSjoerg if (nbperf.output == NULL) 18703c8ba1cSjoerg err(2, "cannot open output file"); 18803c8ba1cSjoerg break; 18910769988Sjoerg case 'p': 19010769988Sjoerg predictable = 1; 19110769988Sjoerg break; 19203c8ba1cSjoerg case 's': 19303c8ba1cSjoerg nbperf.static_hash = 1; 19403c8ba1cSjoerg break; 19503c8ba1cSjoerg default: 19603c8ba1cSjoerg usage(); 19703c8ba1cSjoerg } 19803c8ba1cSjoerg } 19903c8ba1cSjoerg 20003c8ba1cSjoerg argc -= optind; 20103c8ba1cSjoerg argv += optind; 20203c8ba1cSjoerg 20303c8ba1cSjoerg if (argc > 1) 20403c8ba1cSjoerg usage(); 20503c8ba1cSjoerg 20603c8ba1cSjoerg if (argc == 1) { 20703c8ba1cSjoerg input = fopen(argv[0], "r"); 20803c8ba1cSjoerg if (input == NULL) 20903c8ba1cSjoerg err(1, "can't open input file"); 21003c8ba1cSjoerg } else 21103c8ba1cSjoerg input = stdin; 21203c8ba1cSjoerg 21303c8ba1cSjoerg if (nbperf.output == NULL) 21403c8ba1cSjoerg nbperf.output = stdout; 21503c8ba1cSjoerg 21610769988Sjoerg line = NULL; 21710769988Sjoerg line_allocated = 0; 21810769988Sjoerg while ((line_len = getline(&line, &line_allocated, input)) != -1) { 21903c8ba1cSjoerg if (line_len && line[line_len - 1] == '\n') 22003c8ba1cSjoerg --line_len; 22103c8ba1cSjoerg if (curlen == curalloc) { 22203c8ba1cSjoerg if (curalloc < 256) 22303c8ba1cSjoerg curalloc = 256; 22403c8ba1cSjoerg else 22503c8ba1cSjoerg curalloc += curalloc; 22603c8ba1cSjoerg keys = realloc(keys, curalloc * sizeof(*keys)); 22703c8ba1cSjoerg if (keys == NULL) 22803c8ba1cSjoerg err(1, "realloc failed"); 22903c8ba1cSjoerg keylens = realloc(keylens, 23003c8ba1cSjoerg curalloc * sizeof(*keylens)); 23103c8ba1cSjoerg if (keylens == NULL) 23203c8ba1cSjoerg err(1, "realloc failed"); 23303c8ba1cSjoerg } 23403c8ba1cSjoerg if ((keys[curlen] = strndup(line, line_len)) == NULL) 23503c8ba1cSjoerg err(1, "malloc failed"); 23603c8ba1cSjoerg keylens[curlen] = line_len; 23703c8ba1cSjoerg ++curlen; 23803c8ba1cSjoerg } 23910769988Sjoerg free(line); 24003c8ba1cSjoerg 24103c8ba1cSjoerg if (input != stdin) 24203c8ba1cSjoerg fclose(input); 24303c8ba1cSjoerg 24403c8ba1cSjoerg nbperf.n = curlen; 24503c8ba1cSjoerg nbperf.keys = keys; 24603c8ba1cSjoerg nbperf.keylens = keylens; 24703c8ba1cSjoerg 24803c8ba1cSjoerg looped = 0; 2497c219dd6Sjoerg int rv; 2507c219dd6Sjoerg for (;;) { 2517c219dd6Sjoerg rv = (*build_hash)(&nbperf); 2527c219dd6Sjoerg if (!rv) 2537c219dd6Sjoerg break; 2547c219dd6Sjoerg if (nbperf.has_duplicates) { 2557c219dd6Sjoerg fputc('\n', stderr); 256f9c779deSjoerg errx(1, "Duplicate keys detected"); 2577c219dd6Sjoerg } 25803c8ba1cSjoerg fputc('.', stderr); 2597c219dd6Sjoerg if (!looped) 2607c219dd6Sjoerg nbperf.check_duplicates = 1; 26103c8ba1cSjoerg looped = 1; 262*366fc9ceSchristos if (max_iterations == ~0U) 26303c8ba1cSjoerg continue; 26403c8ba1cSjoerg if (--max_iterations == 0) { 26503c8ba1cSjoerg fputc('\n', stderr); 26603c8ba1cSjoerg errx(1, "Iteration count reached"); 26703c8ba1cSjoerg } 26803c8ba1cSjoerg } 26903c8ba1cSjoerg if (looped) 27003c8ba1cSjoerg fputc('\n', stderr); 27103c8ba1cSjoerg 27203c8ba1cSjoerg return 0; 27303c8ba1cSjoerg } 274