/* * test_util.c - utility functions for test programs * * Copyright 2016 Eric Biggers * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "test_util.h" #include #include #ifdef _WIN32 # include #else # include # include # include #endif #ifndef MAP_ANONYMOUS # define MAP_ANONYMOUS MAP_ANON #endif /* Abort with an error message */ _noreturn void assertion_failed(const char *expr, const char *file, int line) { msg("Assertion failed: %s at %s:%d", expr, file, line); abort(); } void begin_performance_test(void) { /* Skip performance tests by default, since they can be flaky. */ if (getenv("INCLUDE_PERF_TESTS") == NULL) exit(0); } static size_t get_page_size(void) { #ifdef _WIN32 SYSTEM_INFO info; GetSystemInfo(&info); return info.dwPageSize; #else return sysconf(_SC_PAGESIZE); #endif } /* Allocate a buffer with guard pages */ void alloc_guarded_buffer(size_t size, u8 **start_ret, u8 **end_ret) { const size_t pagesize = get_page_size(); const size_t nr_pages = (size + pagesize - 1) / pagesize; u8 *base_addr; u8 *start, *end; #ifdef _WIN32 DWORD oldProtect; #endif *start_ret = NULL; *end_ret = NULL; #ifdef _WIN32 /* Allocate buffer and guard pages with no access. */ base_addr = VirtualAlloc(NULL, (nr_pages + 2) * pagesize, MEM_COMMIT | MEM_RESERVE, PAGE_NOACCESS); if (!base_addr) { msg("Unable to allocate memory (VirtualAlloc): Windows error %u", (unsigned int)GetLastError()); ASSERT(0); } start = base_addr + pagesize; end = start + (nr_pages * pagesize); /* Grant read+write access to just the buffer. */ if (!VirtualProtect(start, end - start, PAGE_READWRITE, &oldProtect)) { msg("Unable to protect memory (VirtualProtect): Windows error %u", (unsigned int)GetLastError()); VirtualFree(base_addr, 0, MEM_RELEASE); ASSERT(0); } #else /* Allocate buffer and guard pages. */ base_addr = mmap(NULL, (nr_pages + 2) * pagesize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (base_addr == (u8 *)MAP_FAILED) { msg_errno("Unable to allocate memory (anonymous mmap)"); ASSERT(0); } start = base_addr + pagesize; end = start + (nr_pages * pagesize); /* Unmap the guard pages. */ munmap(base_addr, pagesize); munmap(end, pagesize); #endif *start_ret = start; *end_ret = end; } /* Free a buffer that was allocated by alloc_guarded_buffer() */ void free_guarded_buffer(u8 *start, u8 *end) { if (!start) return; #ifdef _WIN32 VirtualFree(start - get_page_size(), 0, MEM_RELEASE); #else munmap(start, end - start); #endif } /* * Return the number of timer ticks that have elapsed since some unspecified * point fixed at the start of program execution */ u64 timer_ticks(void) { #ifdef _WIN32 LARGE_INTEGER count; QueryPerformanceCounter(&count); return count.QuadPart; #elif defined(HAVE_CLOCK_GETTIME) || \ /* fallback detection method for direct compilation */ \ (!defined(HAVE_CONFIG_H) && defined(CLOCK_MONOTONIC)) struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (1000000000 * (u64)ts.tv_sec) + ts.tv_nsec; #else struct timeval tv; gettimeofday(&tv, NULL); return (1000000 * (u64)tv.tv_sec) + tv.tv_usec; #endif } /* * Return the number of timer ticks per second */ static u64 timer_frequency(void) { #ifdef _WIN32 LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); return freq.QuadPart; #elif defined(HAVE_CLOCK_GETTIME) return 1000000000; #else return 1000000; #endif } /* * Convert a number of elapsed timer ticks to milliseconds */ u64 timer_ticks_to_ms(u64 ticks) { return ticks * 1000 / timer_frequency(); } /* * Convert a byte count and a number of elapsed timer ticks to MB/s */ u64 timer_MB_per_s(u64 bytes, u64 ticks) { return bytes * timer_frequency() / ticks / 1000000; } /* * Convert a byte count and a number of elapsed timer ticks to KB/s */ u64 timer_KB_per_s(u64 bytes, u64 ticks) { return bytes * timer_frequency() / ticks / 1000; } bool put_bits(struct output_bitstream *os, machine_word_t bits, int num_bits) { os->bitbuf |= bits << os->bitcount; os->bitcount += num_bits; while (os->bitcount >= 8) { if (os->next == os->end) return false; *os->next++ = os->bitbuf; os->bitcount -= 8; os->bitbuf >>= 8; } return true; } bool flush_bits(struct output_bitstream *os) { while (os->bitcount > 0) { if (os->next == os->end) return false; *os->next++ = os->bitbuf; os->bitcount -= 8; os->bitbuf >>= 8; } os->bitcount = 0; return true; }