LCOV - code coverage report
Current view: top level - asmjit - osutils.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 18 22 81.8 %
Date: 2024-10-18 14:00:27 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             : Copyright (c) 2008-2017, Petr Kobalicek
       3             : 
       4             : This software is provided 'as-is', without any express or implied
       5             : warranty. In no event will the authors be held liable for any damages
       6             : arising from the use of this software.
       7             : 
       8             : Permission is granted to anyone to use this software for any purpose,
       9             : including commercial applications, and to alter it and redistribute it
      10             : freely, subject to the following restrictions:
      11             : 
      12             : 1. The origin of this software must not be misrepresented; you must not
      13             :    claim that you wrote the original software. If you use this software
      14             :    in a product, an acknowledgment in the product documentation would be
      15             :    appreciated but is not required.
      16             : 2. Altered source versions must be plainly marked as such, and must not be
      17             :    misrepresented as being the original software.
      18             : 3. This notice may not be removed or altered from any source distribution.
      19             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      20             : #ifdef __PLUMED_HAS_ASMJIT
      21             : #pragma GCC diagnostic push
      22             : #pragma GCC diagnostic ignored "-Wpedantic"
      23             : // [AsmJit]
      24             : // Complete x86/x64 JIT and Remote Assembler for C++.
      25             : //
      26             : // [License]
      27             : // Zlib - See LICENSE.md file in the package.
      28             : 
      29             : // [Export]
      30             : #define ASMJIT_EXPORTS
      31             : 
      32             : // [Dependencies]
      33             : #include "./osutils.h"
      34             : #include "./utils.h"
      35             : 
      36             : #if ASMJIT_OS_POSIX
      37             : # include <sys/types.h>
      38             : # include <sys/mman.h>
      39             : # include <time.h>
      40             : # include <unistd.h>
      41             : #endif // ASMJIT_OS_POSIX
      42             : 
      43             : #if ASMJIT_OS_MAC
      44             : # include <mach/mach_time.h>
      45             : #endif // ASMJIT_OS_MAC
      46             : 
      47             : #if ASMJIT_OS_WINDOWS
      48             : # if defined(_MSC_VER) && _MSC_VER >= 1400
      49             : #  include <intrin.h>
      50             : # else
      51             : #  define _InterlockedCompareExchange InterlockedCompareExchange
      52             : # endif // _MSC_VER
      53             : #endif // ASMJIT_OS_WINDOWS
      54             : 
      55             : // [Api-Begin]
      56             : #include "./asmjit_apibegin.h"
      57             : 
      58             : namespace PLMD {
      59             : namespace asmjit {
      60             : 
      61             : // ============================================================================
      62             : // [asmjit::OSUtils - Virtual Memory]
      63             : // ============================================================================
      64             : 
      65             : // Windows specific implementation using `VirtualAllocEx` and `VirtualFree`.
      66             : #if ASMJIT_OS_WINDOWS
      67             : static ASMJIT_NOINLINE const VMemInfo& OSUtils_GetVMemInfo() noexcept {
      68             :   static VMemInfo vmi;
      69             : 
      70             :   if (ASMJIT_UNLIKELY(!vmi.hCurrentProcess)) {
      71             :     SYSTEM_INFO info;
      72             :     ::GetSystemInfo(&info);
      73             : 
      74             :     vmi.pageSize = Utils::alignToPowerOf2<uint32_t>(info.dwPageSize);
      75             :     vmi.pageGranularity = info.dwAllocationGranularity;
      76             :     vmi.hCurrentProcess = ::GetCurrentProcess();
      77             :   }
      78             : 
      79             :   return vmi;
      80             : };
      81             : 
      82             : VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); }
      83             : 
      84             : void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept {
      85             :   return allocProcessMemory(static_cast<HANDLE>(0), size, allocated, flags);
      86             : }
      87             : 
      88             : Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept {
      89             :   return releaseProcessMemory(static_cast<HANDLE>(0), p, size);
      90             : }
      91             : 
      92             : void* OSUtils::allocProcessMemory(HANDLE hProcess, size_t size, size_t* allocated, uint32_t flags) noexcept {
      93             :   if (size == 0)
      94             :     return nullptr;
      95             : 
      96             :   const VMemInfo& vmi = OSUtils_GetVMemInfo();
      97             :   if (!hProcess) hProcess = vmi.hCurrentProcess;
      98             : 
      99             :   // VirtualAllocEx rounds the allocated size to a page size automatically,
     100             :   // but we need the `alignedSize` so we can store the real allocated size
     101             :   // into `allocated` output.
     102             :   size_t alignedSize = Utils::alignTo(size, vmi.pageSize);
     103             : 
     104             :   // Windows XP SP2 / Vista+ allow data-execution-prevention (DEP).
     105             :   DWORD protectFlags = 0;
     106             : 
     107             :   if (flags & kVMExecutable)
     108             :     protectFlags |= (flags & kVMWritable) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
     109             :   else
     110             :     protectFlags |= (flags & kVMWritable) ? PAGE_READWRITE : PAGE_READONLY;
     111             : 
     112             :   LPVOID mBase = ::VirtualAllocEx(hProcess, nullptr, alignedSize, MEM_COMMIT | MEM_RESERVE, protectFlags);
     113             :   if (ASMJIT_UNLIKELY(!mBase)) return nullptr;
     114             : 
     115             :   ASMJIT_ASSERT(Utils::isAligned<size_t>(reinterpret_cast<size_t>(mBase), vmi.pageSize));
     116             :   if (allocated) *allocated = alignedSize;
     117             :   return mBase;
     118             : }
     119             : 
     120             : Error OSUtils::releaseProcessMemory(HANDLE hProcess, void* p, size_t size) noexcept {
     121             :   const VMemInfo& vmi = OSUtils_GetVMemInfo();
     122             :   if (!hProcess) hProcess = vmi.hCurrentProcess;
     123             : 
     124             :   if (ASMJIT_UNLIKELY(!::VirtualFreeEx(hProcess, p, 0, MEM_RELEASE)))
     125             :     return DebugUtils::errored(kErrorInvalidState);
     126             : 
     127             :   return kErrorOk;
     128             : }
     129             : #endif // ASMJIT_OS_WINDOWS
     130             : 
     131             : // Posix specific implementation using `mmap()` and `munmap()`.
     132             : #if ASMJIT_OS_POSIX
     133             : 
     134             : // Mac uses MAP_ANON instead of MAP_ANONYMOUS.
     135             : #if !defined(MAP_ANONYMOUS)
     136             : # define MAP_ANONYMOUS MAP_ANON
     137             : #endif // MAP_ANONYMOUS
     138             : 
     139       64252 : static const VMemInfo& OSUtils_GetVMemInfo() noexcept {
     140             :   static VMemInfo vmi;
     141       64252 :   if (ASMJIT_UNLIKELY(!vmi.pageSize)) {
     142         260 :     size_t pageSize = ::getpagesize();
     143         260 :     vmi.pageSize = pageSize;
     144         520 :     vmi.pageGranularity = std::max<size_t>(pageSize, 65536);
     145             :   }
     146       64252 :   return vmi;
     147             : };
     148             : 
     149       32141 : VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); }
     150             : 
     151       32111 : void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept {
     152       32111 :   const VMemInfo& vmi = OSUtils_GetVMemInfo();
     153             : 
     154       32111 :   size_t alignedSize = Utils::alignTo<size_t>(size, vmi.pageSize);
     155             :   int protection = PROT_READ;
     156             : 
     157       32111 :   if (flags & kVMWritable  ) protection |= PROT_WRITE;
     158       32111 :   if (flags & kVMExecutable) protection |= PROT_EXEC;
     159             : 
     160       32111 :   void* mbase = ::mmap(nullptr, alignedSize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     161       32111 :   if (ASMJIT_UNLIKELY(mbase == MAP_FAILED)) return nullptr;
     162             : 
     163       32111 :   if (allocated) *allocated = alignedSize;
     164             :   return mbase;
     165             : }
     166             : 
     167       32111 : Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept {
     168       32111 :   if (ASMJIT_UNLIKELY(::munmap(p, size) != 0))
     169             :     return DebugUtils::errored(kErrorInvalidState);
     170             : 
     171       32111 :   return kErrorOk;
     172             : }
     173             : #endif // ASMJIT_OS_POSIX
     174             : 
     175             : // ============================================================================
     176             : // [asmjit::OSUtils - GetTickCount]
     177             : // ============================================================================
     178             : 
     179             : #if ASMJIT_OS_WINDOWS
     180             : static ASMJIT_INLINE uint32_t OSUtils_calcHiRes(const LARGE_INTEGER& now, double freq) noexcept {
     181             :   return static_cast<uint32_t>(
     182             :     (int64_t)(double(now.QuadPart) / freq) & 0xFFFFFFFF);
     183             : }
     184             : 
     185             : uint32_t OSUtils::getTickCount() noexcept {
     186             :   static volatile uint32_t _hiResTicks;
     187             :   static volatile double _hiResFreq;
     188             : 
     189             :   do {
     190             :     uint32_t hiResOk = _hiResTicks;
     191             :     LARGE_INTEGER qpf, now;
     192             : 
     193             :     // If for whatever reason this fails, bail to `GetTickCount()`.
     194             :     if (!::QueryPerformanceCounter(&now)) break;
     195             : 
     196             :     // Expected - if we ran through this at least once `hiResTicks` will be
     197             :     // either 1 or 0xFFFFFFFF. If it's '1' then the Hi-Res counter is available
     198             :     // and `QueryPerformanceCounter()` can be used.
     199             :     if (hiResOk == 1) return OSUtils_calcHiRes(now, _hiResFreq);
     200             : 
     201             :     // Hi-Res counter is not available, bail to `GetTickCount()`.
     202             :     if (hiResOk != 0) break;
     203             : 
     204             :     // Detect availability of Hi-Res counter, if not available, bail to `GetTickCount()`.
     205             :     if (!::QueryPerformanceFrequency(&qpf)) {
     206             :       _InterlockedCompareExchange((LONG*)&_hiResTicks, 0xFFFFFFFF, 0);
     207             :       break;
     208             :     }
     209             : 
     210             :     double freq = double(qpf.QuadPart) / 1000.0;
     211             :     _hiResFreq = freq;
     212             : 
     213             :     _InterlockedCompareExchange((LONG*)&_hiResTicks, 1, 0);
     214             :     return OSUtils_calcHiRes(now, freq);
     215             :   } while (0);
     216             : 
     217             :   return ::GetTickCount();
     218             : }
     219             : #elif ASMJIT_OS_MAC
     220             : uint32_t OSUtils::getTickCount() noexcept {
     221             :   static mach_timebase_info_data_t _machTime;
     222             : 
     223             :   // See Apple's QA1398.
     224             :   if (ASMJIT_UNLIKELY(_machTime.denom == 0) || mach_timebase_info(&_machTime) != KERN_SUCCESS)
     225             :     return 0;
     226             : 
     227             :   // `mach_absolute_time()` returns nanoseconds, we want milliseconds.
     228             :   uint64_t t = mach_absolute_time() / 1000000;
     229             : 
     230             :   t = t * _machTime.numer / _machTime.denom;
     231             :   return static_cast<uint32_t>(t & 0xFFFFFFFFU);
     232             : }
     233             : #elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
     234           0 : uint32_t OSUtils::getTickCount() noexcept {
     235             :   struct timespec ts;
     236             : 
     237           0 :   if (ASMJIT_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0))
     238             :     return 0;
     239             : 
     240           0 :   uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000);
     241           0 :   return static_cast<uint32_t>(t & 0xFFFFFFFFU);
     242             : }
     243             : #else
     244             : #error "[asmjit] OSUtils::getTickCount() is not implemented for your target OS."
     245             : uint32_t OSUtils::getTickCount() noexcept { return 0; }
     246             : #endif
     247             : 
     248             : } // asmjit namespace
     249             : } // namespace PLMD
     250             : 
     251             : // [Api-End]
     252             : #include "./asmjit_apiend.h"
     253             : #pragma GCC diagnostic pop
     254             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16