diff options
Diffstat (limited to 'regressions/common.h')
-rw-r--r-- | regressions/common.h | 471 |
1 files changed, 471 insertions, 0 deletions
diff --git a/regressions/common.h b/regressions/common.h new file mode 100644 index 0000000..f67c2af --- /dev/null +++ b/regressions/common.h @@ -0,0 +1,471 @@ +/* + * Copyright 2011-2015 Samy Al Bahra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_COMMON_H +#define CK_COMMON_H + +#include <ck_cc.h> +#include <ck_pr.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> + +#ifdef __linux__ +#include <sched.h> +#include <sys/types.h> +#include <sys/syscall.h> +#elif defined(__MACH__) +#include <mach/mach.h> +#include <mach/thread_policy.h> +#elif defined(__FreeBSD__) +#include <sys/param.h> +#include <sys/cpuset.h> +#endif + +#if defined(_WIN32) +#include <assert.h> +#define NOMINMAX +#include <windows.h> +#define DELTA_EPOCH 11644473600000000ULL +#else +#include <signal.h> +#include <unistd.h> +#endif + +#ifndef CORES +#define CORES 8 +#endif + +CK_CC_INLINE static void +common_srand(unsigned int i) +{ +#ifdef _WIN32 + srand(i); +#else + srandom(i); +#endif +} + +CK_CC_INLINE static int +common_rand(void) +{ +#ifdef _WIN32 + return rand(); +#else + return random(); +#endif +} + +CK_CC_INLINE static int +common_rand_r(unsigned int *i) +{ +#ifdef _WIN32 + (void)i; + + /* + * When linked with -mthreads, rand() is thread-safe. + * rand_s is also an option. + */ + return rand(); +#else + return rand_r(i); +#endif +} + +CK_CC_INLINE static void +common_srand48(long int i) +{ +#ifdef _WIN32 + srand(i); +#else + srand48(i); +#endif +} + +CK_CC_INLINE static long int +common_lrand48(void) +{ +#ifdef _WIN32 + return rand(); +#else + return lrand48(); +#endif +} + +CK_CC_INLINE static double +common_drand48(void) +{ +#ifdef _WIN32 + return (double)rand()/RAND_MAX; +#else + return drand48(); +#endif +} + +CK_CC_INLINE static void +common_sleep(unsigned int n) +{ +#ifdef _WIN32 + Sleep(n * 1000); +#else + sleep(n); +#endif +} + +CK_CC_INLINE static int +common_gettimeofday(struct timeval *tv, void *tz) +{ +#ifdef _WIN32 + FILETIME ft; + uint64_t tmp_time = 0; + static bool tzflag = false; + struct timezone *tzp = tz; + + if (tv != NULL) { + GetSystemTimeAsFileTime(&ft); + tmp_time |= ft.dwHighDateTime; + tmp_time <<= 32; + tmp_time |= ft.dwLowDateTime; + + /* GetSystemTimeAsFileTime returns 100 nanosecond intervals. */ + tmp_time /= 10; + + /* Windows' epoch starts on 01/01/1601, while Unix' starts on 01/01/1970. */ + tmp_time -= DELTA_EPOCH; + + tv->tv_sec = (long)(tmp_time / 1000000UL); + tv->tv_usec = (long)(tmp_time % 1000000UL); + } + + + if (tz != NULL) { + if (tzflag == false) { + _tzset(); + tzflag = true; + } + + tzp->tz_minuteswest = _timezone / 60; + tzp->tz_dsttime = _daylight; + } + + return 0; +#else + return gettimeofday(tv, tz); +#endif +} + +CK_CC_UNUSED static unsigned int +common_alarm(void (*sig_handler)(int), void *alarm_event, unsigned int duration) +{ +#ifdef _WIN32 + (void)sig_handler; + (void)duration; + bool success; + HANDLE *alarm_handle = alarm_event; + success = SetEvent(*alarm_handle); + assert(success != false); + return 0; +#else + (void)alarm_event; + signal(SIGALRM, sig_handler); + return alarm(duration); +#endif +} + +#ifdef _WIN32 +#ifndef SECOND_TIMER +#define SECOND_TIMER 10000000 +#endif +#define COMMON_ALARM_DECLARE_GLOBAL(prefix, alarm_event_name, flag_name) \ +static HANDLE prefix##_common_win_alarm_timer; \ +static HANDLE alarm_event_name; \ +static LARGE_INTEGER prefix##_common_alarm_timer_length; \ + \ +static void CALLBACK \ +prefix##_common_win_alarm_handler(LPVOID arg, DWORD timer_low_value, DWORD timer_high_value) \ +{ \ + (void)arg; \ + (void)timer_low_value; \ + (void)timer_high_value; \ + flag_name = true; \ + return; \ +} \ + \ +static void * \ +prefix##_common_win_alarm(void *unused) \ +{ \ + (void)unused; \ + bool timer_success = false; \ + for (;;) { \ + WaitForSingleObjectEx(alarm_event_name, INFINITE, true); \ + timer_success = SetWaitableTimer(prefix##_common_win_alarm_timer, \ + &prefix##_common_alarm_timer_length, \ + 0, \ + prefix##_common_win_alarm_handler, NULL, false); \ + assert(timer_success != false); \ + WaitForSingleObjectEx(prefix##_common_win_alarm_timer, INFINITE, true); \ + } \ + \ + return NULL; \ +} + +#define COMMON_ALARM_DECLARE_LOCAL(prefix, alarm_event_name) \ + int64_t prefix##_common_alarm_tl; \ + pthread_t prefix##_common_win_alarm_thread; + +#define COMMON_ALARM_INIT(prefix, alarm_event_name, duration) \ + prefix##_common_alarm_tl = -1 * (duration) * SECOND_TIMER; \ + prefix##_common_alarm_timer_length.LowPart = \ + (DWORD) (prefix##_common_alarm_tl & 0xFFFFFFFF); \ + prefix##_common_alarm_timer_length.HighPart = \ + (LONG) (prefix##_common_alarm_tl >> 32); \ + alarm_event_name = CreateEvent(NULL, false, false, NULL); \ + assert(alarm_event_name != NULL); \ + prefix##_common_win_alarm_timer = CreateWaitableTimer(NULL, true, NULL); \ + assert(prefix##_common_win_alarm_timer != NULL); \ + if (pthread_create(&prefix##_common_win_alarm_thread, \ + NULL, \ + prefix##_common_win_alarm, \ + NULL) != 0) \ + ck_error("ERROR: Failed to create common_win_alarm thread.\n"); +#else +#define COMMON_ALARM_DECLARE_GLOBAL(prefix, alarm_event_name, flag_name) +#define COMMON_ALARM_DECLARE_LOCAL(prefix, alarm_event_name) \ + int alarm_event_name = 0; +#define COMMON_ALARM_INIT(prefix, alarm_event_name, duration) +#endif + +struct affinity { + unsigned int delta; + unsigned int request; +}; + +#define AFFINITY_INITIALIZER {0, 0} + +#ifdef __linux__ +#ifndef gettid +static pid_t +gettid(void) +{ + return syscall(__NR_gettid); +} +#endif /* gettid */ + +CK_CC_UNUSED static int +aff_iterate(struct affinity *acb) +{ + cpu_set_t s; + unsigned int c; + + c = ck_pr_faa_uint(&acb->request, acb->delta); + CPU_ZERO(&s); + CPU_SET(c % CORES, &s); + + return sched_setaffinity(gettid(), sizeof(s), &s); +} + +CK_CC_UNUSED static int +aff_iterate_core(struct affinity *acb, unsigned int *core) +{ + cpu_set_t s; + + *core = ck_pr_faa_uint(&acb->request, acb->delta); + CPU_ZERO(&s); + CPU_SET((*core) % CORES, &s); + + return sched_setaffinity(gettid(), sizeof(s), &s); +} +#elif defined(__MACH__) +CK_CC_UNUSED static int +aff_iterate(struct affinity *acb) +{ + thread_affinity_policy_data_t policy; + unsigned int c; + + c = ck_pr_faa_uint(&acb->request, acb->delta) % CORES; + policy.affinity_tag = c; + return thread_policy_set(mach_thread_self(), + THREAD_AFFINITY_POLICY, + (thread_policy_t)&policy, + THREAD_AFFINITY_POLICY_COUNT); +} + +CK_CC_UNUSED static int +aff_iterate_core(struct affinity *acb, unsigned int *core) +{ + thread_affinity_policy_data_t policy; + + *core = ck_pr_faa_uint(&acb->request, acb->delta) % CORES; + policy.affinity_tag = *core; + return thread_policy_set(mach_thread_self(), + THREAD_AFFINITY_POLICY, + (thread_policy_t)&policy, + THREAD_AFFINITY_POLICY_COUNT); +} +#elif defined(__FreeBSD__) +CK_CC_UNUSED static int +aff_iterate(struct affinity *acb CK_CC_UNUSED) +{ + unsigned int c; + cpuset_t mask; + + c = ck_pr_faa_uint(&acb->request, acb->delta) % CORES; + CPU_ZERO(&mask); + CPU_SET(c, &mask); + return (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, + sizeof(mask), &mask)); +} + +CK_CC_UNUSED static int +aff_iterate_core(struct affinity *acb CK_CC_UNUSED, unsigned int *core) +{ + cpuset_t mask; + + *core = ck_pr_faa_uint(&acb->request, acb->delta) % CORES; + CPU_ZERO(&mask); + CPU_SET(*core, &mask); + return (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, + sizeof(mask), &mask)); +} +#else +CK_CC_UNUSED static int +aff_iterate(struct affinity *acb CK_CC_UNUSED) +{ + + return (0); +} + +CK_CC_UNUSED static int +aff_iterate_core(struct affinity *acb CK_CC_UNUSED, unsigned int *core) +{ + *core = 0; + return (0); +} +#endif + +CK_CC_INLINE static uint64_t +rdtsc(void) +{ +#if defined(__x86_64__) + uint32_t eax = 0, edx; +#if defined(CK_MD_RDTSCP) + __asm__ __volatile__("rdtscp" + : "+a" (eax), "=d" (edx) + : + : "%ecx", "memory"); + + return (((uint64_t)edx << 32) | eax); +#else + __asm__ __volatile__("cpuid;" + "rdtsc;" + : "+a" (eax), "=d" (edx) + : + : "%ebx", "%ecx", "memory"); + + __asm__ __volatile__("xorl %%eax, %%eax;" + "cpuid;" + : + : + : "%eax", "%ebx", "%ecx", "%edx", "memory"); + + return (((uint64_t)edx << 32) | eax); +#endif /* !CK_MD_RDTSCP */ +#elif defined(__x86__) + uint32_t eax = 0, edx; +#if defined(CK_MD_RDTSCP) + __asm__ __volatile__("rdtscp" + : "+a" (eax), "=d" (edx) + : + : "%ecx", "memory"); + + return (((uint64_t)edx << 32) | eax); +#else + __asm__ __volatile__("pushl %%ebx;" + "cpuid;" + "rdtsc;" + : "+a" (eax), "=d" (edx) + : + : "%ecx", "memory"); + + __asm__ __volatile__("xorl %%eax, %%eax;" + "cpuid;" + "popl %%ebx;" + : + : + : "%eax", "%ecx", "%edx", "memory"); + + return (((uint64_t)edx << 32) | eax); +#endif /* !CK_MD_RDTSCP */ +#elif defined(__sparcv9__) + uint64_t r; + + __asm__ __volatile__("rd %%tick, %0" + : "=r" (r) + : + : "memory"); + return r; +#elif defined(__ppc64__) + uint32_t high, low, snapshot; + + do { + __asm__ __volatile__("isync;" + "mftbu %0;" + "mftb %1;" + "mftbu %2;" + : "=r" (high), "=r" (low), "=r" (snapshot) + : + : "memory"); + } while (snapshot != high); + + return (((uint64_t)high << 32) | low); +#elif defined(__aarch64__) + uint64_t r; + + __asm __volatile__ ("mrs %0, cntvct_el0" : "=r" (r) : : "memory"); + return r; +#else + return 0; +#endif +} + +CK_CC_USED static void +ck_error(const char *message, ...) +{ + va_list ap; + + va_start(ap, message); + vfprintf(stderr, message, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +#define ck_test(A, B, ...) do { \ + if (A) \ + ck_error(B, ##__VA_ARGS__); \ +} while (0) + +#endif /* CK_COMMON_H */ |