Path: blob/master/thirdparty/embree/common/sys/alloc.cpp
9912 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#include "alloc.h"4#include "intrinsics.h"5#include "sysinfo.h"6#include "mutex.h"78////////////////////////////////////////////////////////////////////////////////9/// All Platforms10////////////////////////////////////////////////////////////////////////////////1112namespace embree13{14void* alignedMalloc(size_t size, size_t align)15{16if (size == 0)17return nullptr;1819assert((align & (align-1)) == 0);20void* ptr = _mm_malloc(size,align);21if (size != 0 && ptr == nullptr)22abort(); //throw std::bad_alloc();23return ptr;24}2526void alignedFree(void* ptr)27{28if (ptr) {29_mm_free(ptr);30}31}3233#if defined(EMBREE_SYCL_SUPPORT)3435void* alignedSYCLMalloc(sycl::context* context, sycl::device* device, size_t size, size_t align, EmbreeUSMMode mode)36{37assert(context);38assert(device);3940if (size == 0)41return nullptr;4243assert((align & (align-1)) == 0);4445void* ptr = nullptr;46if (mode == EmbreeUSMMode::DEVICE_READ_ONLY)47ptr = sycl::aligned_alloc_shared(align,size,*device,*context,sycl::ext::oneapi::property::usm::device_read_only());48else49ptr = sycl::aligned_alloc_shared(align,size,*device,*context);5051if (size != 0 && ptr == nullptr)52abort(); //throw std::bad_alloc();5354return ptr;55}5657void* alignedSYCLMalloc(sycl::context* context, sycl::device* device, size_t size, size_t align, EmbreeUSMMode mode, EmbreeMemoryType type)58{59assert(context);60assert(device);6162if (size == 0)63return nullptr;6465assert((align & (align-1)) == 0);6667void* ptr = nullptr;68if (type == EmbreeMemoryType::USM_SHARED) {69if (mode == EmbreeUSMMode::DEVICE_READ_ONLY)70ptr = sycl::aligned_alloc_shared(align,size,*device,*context,sycl::ext::oneapi::property::usm::device_read_only());71else72ptr = sycl::aligned_alloc_shared(align,size,*device,*context);73}74else if (type == EmbreeMemoryType::USM_HOST) {75ptr = sycl::aligned_alloc_host(align,size,*context);76}77else if (type == EmbreeMemoryType::USM_DEVICE) {78ptr = sycl::aligned_alloc_device(align,size,*device,*context);79}80else {81ptr = alignedMalloc(size,align);82}8384if (size != 0 && ptr == nullptr)85abort(); //throw std::bad_alloc();8687return ptr;88}8990void alignedSYCLFree(sycl::context* context, void* ptr)91{92assert(context);93if (ptr) {94sycl::usm::alloc type = sycl::get_pointer_type(ptr, *context);95if (type == sycl::usm::alloc::host || type == sycl::usm::alloc::device || type == sycl::usm::alloc::shared)96sycl::free(ptr,*context);97else {98alignedFree(ptr);99}100}101}102103#endif104105static bool huge_pages_enabled = false;106static MutexSys os_init_mutex;107108__forceinline bool isHugePageCandidate(const size_t bytes)109{110if (!huge_pages_enabled)111return false;112113/* use huge pages only when memory overhead is low */114const size_t hbytes = (bytes+PAGE_SIZE_2M-1) & ~size_t(PAGE_SIZE_2M-1);115return 66*(hbytes-bytes) < bytes; // at most 1.5% overhead116}117}118119////////////////////////////////////////////////////////////////////////////////120/// Windows Platform121////////////////////////////////////////////////////////////////////////////////122123#ifdef _WIN32124125#define WIN32_LEAN_AND_MEAN126#include <windows.h>127#include <malloc.h>128129namespace embree130{131bool win_enable_selockmemoryprivilege (bool verbose)132{133HANDLE hToken;134if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) {135if (verbose) std::cout << "WARNING: OpenProcessToken failed while trying to enable SeLockMemoryPrivilege: " << GetLastError() << std::endl;136return false;137}138139TOKEN_PRIVILEGES tp;140tp.PrivilegeCount = 1;141tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;142143if (!LookupPrivilegeValueW(nullptr, L"SeLockMemoryPrivilege", &tp.Privileges[0].Luid)) {144if (verbose) std::cout << "WARNING: LookupPrivilegeValue failed while trying to enable SeLockMemoryPrivilege: " << GetLastError() << std::endl;145return false;146}147148SetLastError(ERROR_SUCCESS);149if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), nullptr, 0)) {150if (verbose) std::cout << "WARNING: AdjustTokenPrivileges failed while trying to enable SeLockMemoryPrivilege" << std::endl;151return false;152}153154if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {155if (verbose) std::cout << "WARNING: AdjustTokenPrivileges failed to enable SeLockMemoryPrivilege: Add SeLockMemoryPrivilege for current user and run process in elevated mode (Run as administrator)." << std::endl;156return false;157}158159return true;160}161162bool os_init(bool hugepages, bool verbose)163{164Lock<MutexSys> lock(os_init_mutex);165166if (!hugepages) {167huge_pages_enabled = false;168return true;169}170171if (GetLargePageMinimum() != PAGE_SIZE_2M) {172huge_pages_enabled = false;173return false;174}175176huge_pages_enabled = true;177return true;178}179180void* os_malloc(size_t bytes, bool& hugepages)181{182if (bytes == 0) {183hugepages = false;184return nullptr;185}186187/* try direct huge page allocation first */188if (isHugePageCandidate(bytes))189{190int flags = MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES;191char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE);192if (ptr != nullptr) {193hugepages = true;194return ptr;195}196}197198/* fall back to 4k pages */199int flags = MEM_COMMIT | MEM_RESERVE;200char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE);201if (ptr == nullptr) abort(); //throw std::bad_alloc();202hugepages = false;203return ptr;204}205206size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld, bool hugepages)207{208if (hugepages) // decommitting huge pages seems not to work under Windows209return bytesOld;210211const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;212bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1);213bytesOld = (bytesOld+pageSize-1) & ~(pageSize-1);214if (bytesNew >= bytesOld)215return bytesOld;216217if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT))218abort(); //throw std::bad_alloc();219220return bytesNew;221}222223void os_free(void* ptr, size_t bytes, bool hugepages)224{225if (bytes == 0)226return;227228if (!VirtualFree(ptr,0,MEM_RELEASE))229abort(); //throw std::bad_alloc();230}231232void os_advise(void *ptr, size_t bytes)233{234}235}236237#endif238239////////////////////////////////////////////////////////////////////////////////240/// Unix Platform241////////////////////////////////////////////////////////////////////////////////242243#if defined(__UNIX__)244245#include <sys/mman.h>246#include <errno.h>247#include <stdlib.h>248#include <string.h>249#include <sstream>250251#if defined(__MACOSX__)252#include <mach/vm_statistics.h>253#endif254255namespace embree256{257bool os_init(bool hugepages, bool verbose)258{259Lock<MutexSys> lock(os_init_mutex);260261if (!hugepages) {262huge_pages_enabled = false;263return true;264}265266#if defined(__LINUX__)267268int hugepagesize = 0;269270std::ifstream file;271file.open("/proc/meminfo",std::ios::in);272if (!file.is_open()) {273if (verbose) std::cout << "WARNING: Could not open /proc/meminfo. Huge page support cannot get enabled!" << std::endl;274huge_pages_enabled = false;275return false;276}277278std::string line;279while (getline(file,line))280{281std::stringstream sline(line);282while (!sline.eof() && sline.peek() == ' ') sline.ignore();283std::string tag; getline(sline,tag,' ');284while (!sline.eof() && sline.peek() == ' ') sline.ignore();285std::string val; getline(sline,val,' ');286while (!sline.eof() && sline.peek() == ' ') sline.ignore();287std::string unit; getline(sline,unit,' ');288if (tag == "Hugepagesize:" && unit == "kB") {289hugepagesize = std::stoi(val)*1024;290break;291}292}293294if (hugepagesize != PAGE_SIZE_2M)295{296if (verbose) std::cout << "WARNING: Only 2MB huge pages supported. Huge page support cannot get enabled!" << std::endl;297huge_pages_enabled = false;298return false;299}300#endif301302huge_pages_enabled = true;303return true;304}305306void* os_malloc(size_t bytes, bool& hugepages)307{308if (bytes == 0) {309hugepages = false;310return nullptr;311}312313/* try direct huge page allocation first */314if (isHugePageCandidate(bytes))315{316#if defined(__MACOSX__)317void* ptr = mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);318if (ptr != MAP_FAILED) {319hugepages = true;320return ptr;321}322#elif defined(MAP_HUGETLB)323void* ptr = mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_HUGETLB, -1, 0);324if (ptr != MAP_FAILED) {325hugepages = true;326return ptr;327}328#endif329}330331/* fallback to 4k pages */332void* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);333if (ptr == MAP_FAILED) abort(); //throw std::bad_alloc();334hugepages = false;335336/* advise huge page hint for THP */337os_advise(ptr,bytes);338return ptr;339}340341size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld, bool hugepages)342{343const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;344bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1);345bytesOld = (bytesOld+pageSize-1) & ~(pageSize-1);346if (bytesNew >= bytesOld)347return bytesOld;348349if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1)350abort(); //throw std::bad_alloc();351352return bytesNew;353}354355void os_free(void* ptr, size_t bytes, bool hugepages)356{357if (bytes == 0)358return;359360/* for hugepages we need to also align the size */361const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;362bytes = (bytes+pageSize-1) & ~(pageSize-1);363if (munmap(ptr,bytes) == -1)364abort(); //throw std::bad_alloc();365}366367/* hint for transparent huge pages (THP) */368void os_advise(void* pptr, size_t bytes)369{370#if defined(MADV_HUGEPAGE)371madvise(pptr,bytes,MADV_HUGEPAGE);372#endif373}374}375376#endif377378379