summaryrefslogtreecommitdiff
path: root/test_utils
diff options
context:
space:
mode:
authorTim Kientzle <kientzle@acm.org>2022-02-01 19:12:35 -0800
committerGitHub <noreply@github.com>2022-02-01 19:12:35 -0800
commit3665c7587d6561f0209da1716f86fbebb9a26778 (patch)
tree69acfc0e0ab9faaa856f692a49fc0390d8c835dc /test_utils
parentb9675888c288fb8b293a69783712bbc2a4573773 (diff)
parent10a9214ac65e171f08589ef0ec94ffcbccbfcc49 (diff)
downloadlibarchive-3665c7587d6561f0209da1716f86fbebb9a26778.tar.gz
Merge pull request #1438 from arichardson/faster-tests-avoid-rand
Avoid millions of rand() calls() when running tests
Diffstat (limited to 'test_utils')
-rw-r--r--test_utils/test_utils.c81
-rw-r--r--test_utils/test_utils.h5
2 files changed, 86 insertions, 0 deletions
diff --git a/test_utils/test_utils.c b/test_utils/test_utils.c
index 8ea3d3c4..db6c31b2 100644
--- a/test_utils/test_utils.c
+++ b/test_utils/test_utils.c
@@ -26,8 +26,11 @@
#include "test_utils.h"
+#include <errno.h>
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
+#include <assert.h>
/* Filter tests against a glob pattern. Returns non-zero if test matches
* pattern, zero otherwise. A '^' at the beginning of the pattern negates
@@ -122,3 +125,81 @@ int get_test_set(int *test_set, int limit, const char *test,
}
return ((idx == 0)?-1:idx);
}
+
+static inline uint64_t
+xorshift64(uint64_t *state)
+{
+ uint64_t x = *state;
+ x ^= x << 13;
+ x ^= x >> 7;
+ x ^= x << 17;
+ *state = x;
+ return (x);
+}
+
+/*
+ * Fill a buffer with reproducible pseudo-random data using a simple xorshift
+ * algorithm. Originally, most tests filled buffers with a loop that calls
+ * rand() once for each byte. However, this initialization can be extremely
+ * slow when running on emulated platforms such as QEMU where 16M calls to
+ * rand() take a long time: Before the test_write_format_7zip_large_copy test
+ * took ~22 seconds, whereas using a xorshift random number generator (that can
+ * be inlined) reduces it to ~17 seconds on QEMU RISC-V.
+ */
+void
+fill_with_pseudorandom_data_seed(uint64_t seed, void *buffer, size_t size)
+{
+ uint64_t *aligned_buffer;
+ size_t num_values;
+ size_t i;
+ size_t unaligned_suffix;
+ size_t unaligned_prefix = 0;
+ /*
+ * To avoid unaligned stores we only fill the aligned part of the buffer
+ * with pseudo-random data and fill the unaligned prefix with 0xab and
+ * the suffix with 0xcd.
+ */
+ if ((uintptr_t)buffer % sizeof(uint64_t)) {
+ unaligned_prefix =
+ sizeof(uint64_t) - (uintptr_t)buffer % sizeof(uint64_t);
+ aligned_buffer =
+ (uint64_t *)((char *)buffer + unaligned_prefix);
+ memset(buffer, 0xab, unaligned_prefix);
+ } else {
+ aligned_buffer = (uint64_t *)buffer;
+ }
+ assert((uintptr_t)aligned_buffer % sizeof(uint64_t) == 0);
+ num_values = (size - unaligned_prefix) / sizeof(uint64_t);
+ unaligned_suffix =
+ size - unaligned_prefix - num_values * sizeof(uint64_t);
+ for (i = 0; i < num_values; i++) {
+ aligned_buffer[i] = xorshift64(&seed);
+ }
+ if (unaligned_suffix) {
+ memset((char *)buffer + size - unaligned_suffix, 0xcd,
+ unaligned_suffix);
+ }
+}
+
+void
+fill_with_pseudorandom_data(void *buffer, size_t size)
+{
+ uint64_t seed;
+ const char* seed_str;
+ /*
+ * Check if a seed has been specified in the environment, otherwise fall
+ * back to using rand() as a seed.
+ */
+ if ((seed_str = getenv("TEST_RANDOM_SEED")) != NULL) {
+ errno = 0;
+ seed = strtoull(seed_str, NULL, 10);
+ if (errno != 0) {
+ fprintf(stderr, "strtoull(%s) failed: %s", seed_str,
+ strerror(errno));
+ seed = rand();
+ }
+ } else {
+ seed = rand();
+ }
+ fill_with_pseudorandom_data_seed(seed, buffer, size);
+}
diff --git a/test_utils/test_utils.h b/test_utils/test_utils.h
index 164c528f..3f61f6b2 100644
--- a/test_utils/test_utils.h
+++ b/test_utils/test_utils.h
@@ -27,6 +27,9 @@
#ifndef TEST_UTILS_H
#define TEST_UTILS_H
+#include <stddef.h>
+#include <stdint.h>
+
struct test_list_t
{
void (*func)(void);
@@ -35,5 +38,7 @@ struct test_list_t
};
int get_test_set(int *, int, const char *, struct test_list_t *);
+void fill_with_pseudorandom_data(void* buffer, size_t size);
+void fill_with_pseudorandom_data_seed(uint64_t seed, void* buffer, size_t size);
#endif /* TEST_UTILS_H */