summaryrefslogtreecommitdiff
path: root/plugins/Dbx_mdbx/src/libmdbx/test/utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/Dbx_mdbx/src/libmdbx/test/utils.cc')
-rw-r--r--plugins/Dbx_mdbx/src/libmdbx/test/utils.cc316
1 files changed, 316 insertions, 0 deletions
diff --git a/plugins/Dbx_mdbx/src/libmdbx/test/utils.cc b/plugins/Dbx_mdbx/src/libmdbx/test/utils.cc
new file mode 100644
index 0000000000..9a6338cc31
--- /dev/null
+++ b/plugins/Dbx_mdbx/src/libmdbx/test/utils.cc
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2017 Leonid Yuriev <leo@yuriev.ru>
+ * and other libmdbx authors: please see AUTHORS file.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include "test.h"
+#include <float.h>
+#ifdef HAVE_IEEE754_H
+#include <ieee754.h>
+#endif
+
+std::string format(const char *fmt, ...) {
+ va_list ap, ones;
+ va_start(ap, fmt);
+ va_copy(ones, ap);
+#ifdef _MSC_VER
+ int needed = _vscprintf(fmt, ap);
+#else
+ int needed = vsnprintf(nullptr, 0, fmt, ap);
+#endif
+ assert(needed >= 0);
+ va_end(ap);
+ std::string result;
+ result.reserve((size_t)needed + 1);
+ result.resize((size_t)needed, '\0');
+ int actual = vsnprintf((char *)result.data(), result.capacity(), fmt, ones);
+ assert(actual == needed);
+ (void)actual;
+ va_end(ones);
+ return result;
+}
+
+std::string data2hex(const void *ptr, size_t bytes, simple_checksum &checksum) {
+ std::string result;
+ if (bytes > 0) {
+ const uint8_t *data = (const uint8_t *)ptr;
+ checksum.push(data, bytes);
+ result.reserve(bytes * 2);
+ const uint8_t *const end = data + bytes;
+ do {
+ char h = *data >> 4;
+ char l = *data & 15;
+ result.push_back((l < 10) ? l + '0' : l - 10 + 'a');
+ result.push_back((h < 10) ? h + '0' : h - 10 + 'a');
+ } while (++data < end);
+ }
+ assert(result.size() == bytes * 2);
+ return result;
+}
+
+bool hex2data(const char *hex_begin, const char *hex_end, void *ptr,
+ size_t bytes, simple_checksum &checksum) {
+ if (bytes * 2 != (size_t)(hex_end - hex_begin))
+ return false;
+
+ uint8_t *data = (uint8_t *)ptr;
+ for (const char *hex = hex_begin; hex != hex_end; hex += 2, ++data) {
+ unsigned l = hex[0], h = hex[1];
+
+ if (l >= '0' && l <= '9')
+ l = l - '0';
+ else if (l >= 'A' && l <= 'F')
+ l = l - 'A' + 10;
+ else if (l >= 'a' && l <= 'f')
+ l = l - 'a' + 10;
+ else
+ return false;
+
+ if (h >= '0' && h <= '9')
+ h = h - '0';
+ else if (h >= 'A' && h <= 'F')
+ h = h - 'A' + 10;
+ else if (h >= 'a' && h <= 'f')
+ h = h - 'a' + 10;
+ else
+ return false;
+
+ uint32_t c = l + (h << 4);
+ checksum.push(c);
+ *data = (uint8_t)c;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+
+#ifdef __mips__
+static uint64_t *mips_tsc_addr;
+
+__cold static void mips_rdtsc_init() {
+ int mem_fd = open("/dev/mem", O_RDONLY | O_SYNC, 0);
+ HIPPEUS_ENSURE(mem_fd >= 0);
+
+ mips_tsc_addr = mmap(nullptr, pagesize, PROT_READ, MAP_SHARED, mem_fd,
+ 0x10030000 /* MIPS_ZBUS_TIMER */);
+ close(mem_fd);
+}
+#endif /* __mips__ */
+
+uint64_t entropy_ticks(void) {
+#if defined(__GNUC__) || defined(__clang__)
+#if defined(__ia64__)
+ uint64_t ticks;
+ __asm __volatile("mov %0=ar.itc" : "=r"(ticks));
+ return ticks;
+#elif defined(__hppa__)
+ uint64_t ticks;
+ __asm __volatile("mfctl 16, %0" : "=r"(ticks));
+ return ticks;
+#elif defined(__s390__)
+ uint64_t ticks;
+ __asm __volatile("stck 0(%0)" : : "a"(&(ticks)) : "memory", "cc");
+ return ticks;
+#elif defined(__alpha__)
+ uint64_t ticks;
+ __asm __volatile("rpcc %0" : "=r"(ticks));
+ return ticks;
+#elif defined(__sparc_v9__)
+ uint64_t ticks;
+ __asm __volatile("rd %%tick, %0" : "=r"(ticks));
+ return ticks;
+#elif defined(__powerpc64__) || defined(__ppc64__)
+ uint64_t ticks;
+ __asm __volatile("mfspr %0, 268" : "=r"(ticks));
+ return ticks;
+#elif defined(__ppc__) || defined(__powerpc__)
+ unsigned tbl, tbu;
+
+ /* LY: Here not a problem if a high-part (tbu)
+ * would been updated during reading. */
+ __asm __volatile("mftb %0" : "=r"(tbl));
+ __asm __volatile("mftbu %0" : "=r"(tbu));
+
+ return (((uin64_t)tbu0) << 32) | tbl;
+#elif defined(__mips__)
+ if (mips_tsc_addr != MAP_FAILED) {
+ if (unlikely(!mips_tsc_addr)) {
+ static pthread_once_t is_initialized = PTHREAD_ONCE_INIT;
+ int rc = pthread_once(&is_initialized, mips_rdtsc_init);
+ if (unlikely(rc))
+ failure_perror("pthread_once()", rc);
+ }
+ if (mips_tsc_addr != MAP_FAILED)
+ return *mips_tsc_addr;
+ }
+#elif defined(__x86_64__) || defined(__i386__)
+#if __GNUC_PREREQ(4, 7) || __has_builtin(__builtin_ia32_rdtsc)
+ return __builtin_ia32_rdtsc();
+#else
+ unsigned lo, hi;
+
+ /* LY: Using the "a" and "d" constraints is important for correct code. */
+ __asm __volatile("rdtsc" : "=a"(lo), "=d"(hi));
+
+ return (((uint64_t)hi) << 32) + lo;
+#endif
+#endif /* arch selector */
+
+#elif defined(_M_IX86) || defined(_M_X64)
+ return __rdtsc();
+#elif defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
+ LARGE_INTEGER PerformanceCount;
+ if (QueryPerformanceCounter(&PerformanceCount))
+ return PerformanceCount.QuadPart;
+ return GetTickCount64();
+#else
+ struct timespec ts;
+#if defined(CLOCK_MONOTONIC_COARSE)
+ clockid_t clock = CLOCK_MONOTONIC_COARSE;
+#elif defined(CLOCK_MONOTONIC_RAW)
+ clockid_t clock = CLOCK_MONOTONIC_RAW;
+#else
+ clockid_t clock = CLOCK_MONOTONIC;
+#endif
+ int rc = clock_gettime(clock, &ts);
+ if (unlikely(rc))
+ failure_perror("clock_gettime()", rc);
+
+ return (((uint64_t)ts.tv_sec) << 32) + ts.tv_nsec;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+
+static __inline uint64_t bleach64(uint64_t dirty) {
+ return mul_64x64_high(bswap64(dirty), UINT64_C(17048867929148541611));
+}
+
+static __inline uint32_t bleach32(uint32_t dirty) {
+ return (uint32_t)((bswap32(dirty) * UINT64_C(2175734609)) >> 32);
+}
+
+uint64_t prng64_careless(uint64_t &state) {
+ state = state * UINT64_C(6364136223846793005) + 1;
+ return state;
+}
+
+uint64_t prng64_white(uint64_t &state) {
+ state = state * UINT64_C(6364136223846793005) + UINT64_C(1442695040888963407);
+ return bleach64(state);
+}
+
+uint32_t prng32(uint64_t &state) {
+ return (uint32_t)(prng64_careless(state) >> 32);
+}
+
+void prng_fill(uint64_t &state, void *ptr, size_t bytes) {
+ while (bytes >= 4) {
+ *((uint32_t *)ptr) = prng32(state);
+ ptr = (uint32_t *)ptr + 1;
+ bytes -= 4;
+ }
+
+ switch (bytes & 3) {
+ case 3: {
+ uint32_t u32 = prng32(state);
+ memcpy(ptr, &u32, 3);
+ } break;
+ case 2:
+ *((uint16_t *)ptr) = (uint16_t)prng32(state);
+ break;
+ case 1:
+ *((uint8_t *)ptr) = (uint8_t)prng32(state);
+ break;
+ case 0:
+ break;
+ }
+}
+
+static __thread uint64_t prng_state;
+
+void prng_seed(uint64_t seed) { prng_state = bleach64(seed); }
+
+uint32_t prng32(void) { return prng32(prng_state); }
+
+uint64_t prng64(void) { return prng64_white(prng_state); }
+
+void prng_fill(void *ptr, size_t bytes) { prng_fill(prng_state, ptr, bytes); }
+
+uint64_t entropy_white() { return bleach64(entropy_ticks()); }
+
+double double_from_lower(uint64_t salt) {
+#ifdef IEEE754_DOUBLE_BIAS
+ ieee754_double r;
+ r.ieee.negative = 0;
+ r.ieee.exponent = IEEE754_DOUBLE_BIAS;
+ r.ieee.mantissa0 = (unsigned)(salt >> 32);
+ r.ieee.mantissa1 = (unsigned)salt;
+ return r.d;
+#else
+ const uint64_t top = (UINT64_C(1) << DBL_MANT_DIG) - 1;
+ const double scale = 1.0 / (double)top;
+ return (salt & top) * scale;
+#endif
+}
+
+double double_from_upper(uint64_t salt) {
+#ifdef IEEE754_DOUBLE_BIAS
+ ieee754_double r;
+ r.ieee.negative = 0;
+ r.ieee.exponent = IEEE754_DOUBLE_BIAS;
+ salt >>= 64 - DBL_MANT_DIG;
+ r.ieee.mantissa0 = (unsigned)(salt >> 32);
+ r.ieee.mantissa1 = (unsigned)salt;
+ return r.d;
+#else
+ const uint64_t top = (UINT64_C(1) << DBL_MANT_DIG) - 1;
+ const double scale = 1.0 / (double)top;
+ return (salt >> (64 - DBL_MANT_DIG)) * scale;
+#endif
+}
+
+bool flipcoin() { return bleach32((uint32_t)entropy_ticks()) & 1; }
+
+bool jitter(unsigned probability_percent) {
+ const uint32_t top = UINT32_MAX - UINT32_MAX % 100;
+ uint32_t dice, edge = (top) / 100 * probability_percent;
+ do
+ dice = bleach32((uint32_t)entropy_ticks());
+ while (dice >= top);
+ return dice < edge;
+}
+
+void jitter_delay(bool extra) {
+ unsigned dice = entropy_white() & 3;
+ if (dice == 0) {
+ log_trace("== jitter.no-delay");
+ } else {
+ log_trace(">> jitter.delay: dice %u", dice);
+ do {
+ cpu_relax();
+ memory_barrier();
+ cpu_relax();
+ if (dice > 1) {
+ osal_yield();
+ cpu_relax();
+ if (dice > 2) {
+ unsigned us = entropy_white() &
+ (extra ? 0xfffff /* 1.05 s */ : 0x3ff /* 1 ms */);
+ log_trace("== jitter.delay: %0.6f", us / 1000000.0);
+ osal_udelay(us);
+ }
+ }
+ } while (flipcoin());
+ log_trace("<< jitter.delay: dice %u", dice);
+ }
+}