1 /* 2 * Copyright (c) 2003-2012 Tim Kientzle 3 * Copyright (c) 2012 Andres Mejia 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "test_utils.h" 28 29 #include <errno.h> 30 #include <stdlib.h> 31 #include <stdio.h> 32 #include <string.h> 33 #include <assert.h> 34 35 static inline uint64_t 36 xorshift64(uint64_t *state) 37 { 38 uint64_t x = *state; 39 x ^= x << 13; 40 x ^= x >> 7; 41 x ^= x << 17; 42 *state = x; 43 return (x); 44 } 45 46 /* 47 * Fill a buffer with reproducible pseudo-random data using a simple xorshift 48 * algorithm. Originally, most tests filled buffers with a loop that calls 49 * rand() once for each byte. However, this initialization can be extremely 50 * slow when running on emulated platforms such as QEMU where 16M calls to 51 * rand() take a long time: Before the test_write_format_7zip_large_copy test 52 * took ~22 seconds, whereas using a xorshift random number generator (that can 53 * be inlined) reduces it to ~17 seconds on QEMU RISC-V. 54 */ 55 static void 56 fill_with_pseudorandom_data_seed(uint64_t seed, void *buffer, size_t size) 57 { 58 uint64_t *aligned_buffer; 59 size_t num_values; 60 size_t i; 61 size_t unaligned_suffix; 62 size_t unaligned_prefix = 0; 63 /* 64 * To avoid unaligned stores we only fill the aligned part of the buffer 65 * with pseudo-random data and fill the unaligned prefix with 0xab and 66 * the suffix with 0xcd. 67 */ 68 if ((uintptr_t)buffer % sizeof(uint64_t)) { 69 unaligned_prefix = 70 sizeof(uint64_t) - (uintptr_t)buffer % sizeof(uint64_t); 71 aligned_buffer = 72 (uint64_t *)((char *)buffer + unaligned_prefix); 73 memset(buffer, 0xab, unaligned_prefix); 74 } else { 75 aligned_buffer = (uint64_t *)buffer; 76 } 77 assert((uintptr_t)aligned_buffer % sizeof(uint64_t) == 0); 78 num_values = (size - unaligned_prefix) / sizeof(uint64_t); 79 unaligned_suffix = 80 size - unaligned_prefix - num_values * sizeof(uint64_t); 81 for (i = 0; i < num_values; i++) { 82 aligned_buffer[i] = xorshift64(&seed); 83 } 84 if (unaligned_suffix) { 85 memset((char *)buffer + size - unaligned_suffix, 0xcd, 86 unaligned_suffix); 87 } 88 } 89 90 void 91 fill_with_pseudorandom_data(void *buffer, size_t size) 92 { 93 uint64_t seed; 94 const char* seed_str; 95 /* 96 * Check if a seed has been specified in the environment, otherwise fall 97 * back to using rand() as a seed. 98 */ 99 if ((seed_str = getenv("TEST_RANDOM_SEED")) != NULL) { 100 errno = 0; 101 seed = strtoull(seed_str, NULL, 10); 102 if (errno != 0) { 103 fprintf(stderr, "strtoull(%s) failed: %s", seed_str, 104 strerror(errno)); 105 seed = rand(); 106 } 107 } else { 108 seed = rand(); 109 } 110 fill_with_pseudorandom_data_seed(seed, buffer, size); 111 } 112