From a1a20a3b34129a810e410d487c3e2c5b74fdc2d4 Mon Sep 17 00:00:00 2001 From: "Hoppe, Mateusz" Date: Wed, 28 Feb 2018 12:09:48 +0100 Subject: [PATCH] Service read only memory passed as host_ptr - read only memory cannot be used for allocation, Oses cannot create graphics alocation for such memory - if memory allocation fails for host_ptr passed to enqueueWrite calls, then try doing new allocation and copy host_ptr on cpu Change-Id: I415a4673ae1319ea8f77e53bd8fba7489fe85218 --- runtime/command_queue/enqueue_common.h | 9 + runtime/command_queue/enqueue_write_buffer.h | 2 +- .../command_queue/enqueue_write_buffer_rect.h | 2 +- runtime/command_queue/enqueue_write_image.h | 2 +- runtime/memory_manager/memory_manager.cpp | 8 +- runtime/memory_manager/memory_manager.h | 8 +- .../os_agnostic_memory_manager.cpp | 6 +- .../os_agnostic_memory_manager.h | 4 +- runtime/memory_manager/surface.h | 9 + .../os_interface/linux/drm_buffer_object.cpp | 25 +- .../os_interface/linux/drm_buffer_object.h | 7 +- .../os_interface/linux/drm_command_stream.inl | 2 +- .../os_interface/linux/drm_memory_manager.cpp | 69 +++- .../os_interface/linux/drm_memory_manager.h | 10 +- runtime/os_interface/linux/drm_neo.cpp | 6 +- runtime/os_interface/linux/drm_neo.h | 3 +- .../windows/wddm_memory_manager.cpp | 4 +- .../windows/wddm_memory_manager.h | 2 +- .../command_queue/command_queue_hw_tests.cpp | 66 ++- .../fixtures/memory_manager_fixture.cpp | 3 +- unit_tests/memory_manager/CMakeLists.txt | 3 +- ...memory_manager_allocate_with_ptr_tests.cpp | 45 ++ unit_tests/memory_manager/surface_tests.cpp | 21 + unit_tests/mocks/mock_command_queue.h | 4 +- unit_tests/mocks/mock_device.h | 4 +- unit_tests/mocks/mock_memory_manager.h | 5 +- .../linux/device_command_stream_fixture.h | 5 + .../linux/drm_buffer_object_tests.cpp | 77 +++- .../linux/drm_command_stream_mm_tests.cpp | 6 +- .../linux/drm_command_stream_tests.cpp | 117 ++++-- .../linux/drm_gem_close_worker_tests.cpp | 2 +- .../linux/drm_memory_manager_tests.cpp | 388 +++++++++++++++--- unit_tests/os_interface/linux/drm_tests.cpp | 13 +- 33 files changed, 774 insertions(+), 163 deletions(-) create mode 100644 unit_tests/memory_manager/memory_manager_allocate_with_ptr_tests.cpp diff --git a/runtime/command_queue/enqueue_common.h b/runtime/command_queue/enqueue_common.h index 544a65bc45..5568637922 100644 --- a/runtime/command_queue/enqueue_common.h +++ b/runtime/command_queue/enqueue_common.h @@ -692,6 +692,15 @@ template bool CommandQueueHw::createAllocationForHostSurface(HostPtrSurface &surface) { auto memoryManager = device->getCommandStreamReceiver().getMemoryManager(); GraphicsAllocation *allocation = memoryManager->allocateGraphicsMemory(surface.getSurfaceSize(), surface.getMemoryPointer()); + + if (allocation == nullptr && surface.peekIsPtrCopyAllowed()) { + // Try with no host pointer allocation and copy + allocation = memoryManager->allocateGraphicsMemory(surface.getSurfaceSize(), MemoryConstants::pageSize, false, false); + + if (allocation) { + memcpy_s(allocation->getUnderlyingBuffer(), allocation->getUnderlyingBufferSize(), surface.getMemoryPointer(), surface.getSurfaceSize()); + } + } if (allocation == nullptr) { return false; } diff --git a/runtime/command_queue/enqueue_write_buffer.h b/runtime/command_queue/enqueue_write_buffer.h index 1c3dce7a81..f8ed271e64 100644 --- a/runtime/command_queue/enqueue_write_buffer.h +++ b/runtime/command_queue/enqueue_write_buffer.h @@ -99,8 +99,8 @@ cl_int CommandQueueHw::enqueueWriteBuffer( void *srcPtr = const_cast(ptr); + HostPtrSurface hostPtrSurf(srcPtr, size, true); MemObjSurface bufferSurf(buffer); - HostPtrSurface hostPtrSurf(srcPtr, size); Surface *surfaces[] = {&bufferSurf, &hostPtrSurf}; if (size != 0) { diff --git a/runtime/command_queue/enqueue_write_buffer_rect.h b/runtime/command_queue/enqueue_write_buffer_rect.h index 170f79342f..00dd8c9a77 100644 --- a/runtime/command_queue/enqueue_write_buffer_rect.h +++ b/runtime/command_queue/enqueue_write_buffer_rect.h @@ -84,7 +84,7 @@ cl_int CommandQueueHw::enqueueWriteBufferRect( void *srcPtr = const_cast(ptr); MemObjSurface dstBufferSurf(buffer); - HostPtrSurface hostPtrSurf(srcPtr, hostPtrSize); + HostPtrSurface hostPtrSurf(srcPtr, hostPtrSize, true); Surface *surfaces[] = {&dstBufferSurf, &hostPtrSurf}; if (region[0] != 0 && diff --git a/runtime/command_queue/enqueue_write_image.h b/runtime/command_queue/enqueue_write_image.h index 9e79727d27..9b8e0c5fbb 100644 --- a/runtime/command_queue/enqueue_write_image.h +++ b/runtime/command_queue/enqueue_write_image.h @@ -84,7 +84,7 @@ cl_int CommandQueueHw::enqueueWriteImage( void *srcPtr = const_cast(ptr); MemObjSurface dstImgSurf(dstImage); - HostPtrSurface hostPtrSurf(srcPtr, hostPtrSize); + HostPtrSurface hostPtrSurf(srcPtr, hostPtrSize, true); Surface *surfaces[] = {&dstImgSurf, &hostPtrSurf}; if (region[0] != 0 && diff --git a/runtime/memory_manager/memory_manager.cpp b/runtime/memory_manager/memory_manager.cpp index f8f5f9d93d..7917b97cc7 100644 --- a/runtime/memory_manager/memory_manager.cpp +++ b/runtime/memory_manager/memory_manager.cpp @@ -125,6 +125,7 @@ void MemoryManager::freeGmm(GraphicsAllocation *gfxAllocation) { GraphicsAllocation *MemoryManager::allocateGraphicsMemory(size_t size, const void *ptr, bool forcePin) { std::lock_guard lock(mtx); auto requirements = HostPtrManager::getAllocationRequirements(ptr, size); + GraphicsAllocation *graphicsAllocation = nullptr; if (deferredDeleter) { deferredDeleter->drain(true); @@ -141,14 +142,13 @@ GraphicsAllocation *MemoryManager::allocateGraphicsMemory(size_t size, const voi if (osStorage.fragmentCount == 0) { return nullptr; } - auto success = populateOsHandles(osStorage); - if (!success) { + auto result = populateOsHandles(osStorage); + if (result != AllocationStatus::Success) { cleanOsHandles(osStorage); return nullptr; } - auto graphicsAllocation = createGraphicsAllocation(osStorage, size, ptr); - + graphicsAllocation = createGraphicsAllocation(osStorage, size, ptr); return graphicsAllocation; } diff --git a/runtime/memory_manager/memory_manager.h b/runtime/memory_manager/memory_manager.h index b1dfbb9bb0..b8db28bd98 100644 --- a/runtime/memory_manager/memory_manager.h +++ b/runtime/memory_manager/memory_manager.h @@ -80,6 +80,12 @@ struct ImageInfo; class MemoryManager { public: + enum AllocationStatus { + Success = 0, + Error, + InvalidHostPointer, + }; + MemoryManager(bool enable64kbpages); virtual ~MemoryManager(); @@ -127,7 +133,7 @@ class MemoryManager { GraphicsAllocation *createGraphicsAllocationWithPadding(GraphicsAllocation *inputGraphicsAllocation, size_t sizeWithPadding); virtual GraphicsAllocation *createPaddedAllocation(GraphicsAllocation *inputGraphicsAllocation, size_t sizeWithPadding); - virtual bool populateOsHandles(OsHandleStorage &handleStorage) = 0; + virtual AllocationStatus populateOsHandles(OsHandleStorage &handleStorage) = 0; virtual void cleanOsHandles(OsHandleStorage &handleStorage) = 0; void freeSystemMemory(void *ptr); diff --git a/runtime/memory_manager/os_agnostic_memory_manager.cpp b/runtime/memory_manager/os_agnostic_memory_manager.cpp index 80a7a6f466..acf9158cb3 100644 --- a/runtime/memory_manager/os_agnostic_memory_manager.cpp +++ b/runtime/memory_manager/os_agnostic_memory_manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Intel Corporation + * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -181,7 +181,7 @@ void OsAgnosticMemoryManager::turnOnFakingBigAllocations() { this->fakeBigAllocations = true; } -bool OsAgnosticMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) { +MemoryManager::AllocationStatus OsAgnosticMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) { for (unsigned int i = 0; i < max_fragments_count; i++) { if (!handleStorage.fragmentStorageData[i].osHandleStorage && handleStorage.fragmentStorageData[i].cpuPtr) { handleStorage.fragmentStorageData[i].osHandleStorage = new OsHandle(); @@ -195,7 +195,7 @@ bool OsAgnosticMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) hostPtrManager.storeFragment(newFragment); } } - return true; + return AllocationStatus::Success; } void OsAgnosticMemoryManager::cleanOsHandles(OsHandleStorage &handleStorage) { for (unsigned int i = 0; i < max_fragments_count; i++) { diff --git a/runtime/memory_manager/os_agnostic_memory_manager.h b/runtime/memory_manager/os_agnostic_memory_manager.h index 2e75c0946d..6fdcded892 100644 --- a/runtime/memory_manager/os_agnostic_memory_manager.h +++ b/runtime/memory_manager/os_agnostic_memory_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Intel Corporation + * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -71,7 +71,7 @@ class OsAgnosticMemoryManager : public MemoryManager { void *lockResource(GraphicsAllocation *graphicsAllocation) override { return nullptr; }; void unlockResource(GraphicsAllocation *graphicsAllocation) override{}; - bool populateOsHandles(OsHandleStorage &handleStorage) override; + AllocationStatus populateOsHandles(OsHandleStorage &handleStorage) override; void cleanOsHandles(OsHandleStorage &handleStorage) override; uint64_t getSystemSharedMemory() override; diff --git a/runtime/memory_manager/surface.h b/runtime/memory_manager/surface.h index 6fd43119de..d53fe2220a 100644 --- a/runtime/memory_manager/surface.h +++ b/runtime/memory_manager/surface.h @@ -54,6 +54,10 @@ class HostPtrSurface : public Surface { gfxAllocation = nullptr; } + HostPtrSurface(void *ptr, size_t size, bool copyAllowed) : HostPtrSurface(ptr, size) { + isPtrCopyAllowed = copyAllowed; + } + HostPtrSurface(void *ptr, size_t size, GraphicsAllocation *allocation) : memoryPointer(ptr), surfaceSize(size), gfxAllocation(allocation) { DEBUG_BREAK_IF(!ptr); } @@ -86,10 +90,15 @@ class HostPtrSurface : public Surface { return gfxAllocation; } + bool peekIsPtrCopyAllowed() { + return isPtrCopyAllowed; + } + protected: void *memoryPointer; size_t surfaceSize; GraphicsAllocation *gfxAllocation; + bool isPtrCopyAllowed = false; }; class MemObjSurface : public Surface { diff --git a/runtime/os_interface/linux/drm_buffer_object.cpp b/runtime/os_interface/linux/drm_buffer_object.cpp index 4f0aa03eee..f23fa3d8d0 100644 --- a/runtime/os_interface/linux/drm_buffer_object.cpp +++ b/runtime/os_interface/linux/drm_buffer_object.cpp @@ -26,6 +26,7 @@ #include "runtime/os_interface/linux/drm_memory_manager.h" #include "runtime/os_interface/linux/drm_neo.h" #include "runtime/os_interface/linux/os_time.h" +#include "runtime/utilities/stackvec.h" #include #include @@ -182,31 +183,39 @@ int BufferObject::exec(uint32_t used, size_t startOffset, unsigned int flags, bo return ret; } -int BufferObject::pin(BufferObject *boToPin) { +int BufferObject::pin(BufferObject *boToPin[], size_t numberOfBos) { drm_i915_gem_execbuffer2 execbuf; - drm_i915_gem_exec_object2 execObject[2]; + StackVec execObject; reinterpret_cast(this->address)[0] = 0x05000000; reinterpret_cast(this->address)[1] = 0x00000000; - boToPin->fillExecObject(execObject[0]); - this->fillExecObject(execObject[1]); + execObject.resize(numberOfBos + 1); + + uint32_t boIndex = 0; + for (boIndex = 0; boIndex < (uint32_t)numberOfBos; boIndex++) { + boToPin[boIndex]->fillExecObject(execObject[boIndex]); + } + + this->fillExecObject(execObject[boIndex]); memset(&execbuf, 0, sizeof(execbuf)); - execbuf.buffers_ptr = reinterpret_cast(execObject); - execbuf.buffer_count = 2; + execbuf.buffers_ptr = reinterpret_cast(&execObject[0]); + execbuf.buffer_count = boIndex + 1; execbuf.batch_len = alignUp(static_cast(sizeof(uint32_t)), 8); if (drm->peekCoherencyDisablePatchActive()) { execbuf.flags = execbuf.flags | I915_PRIVATE_EXEC_FORCE_NON_COHERENT; } + int err = 0; int ret = this->drm->ioctl(DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); if (ret != 0) { - int err = errno; + err = this->drm->getErrno(); printDebugString(DebugManager.flags.PrintDebugMessages.get(), stderr, "ioctl(I915_GEM_EXECBUFFER2) failed with %d. errno=%d(%s)\n", ret, err, strerror(err)); } - return ret; + return err; } + } // namespace OCLRT diff --git a/runtime/os_interface/linux/drm_buffer_object.h b/runtime/os_interface/linux/drm_buffer_object.h index e0c1645ef5..0594d83274 100644 --- a/runtime/os_interface/linux/drm_buffer_object.h +++ b/runtime/os_interface/linux/drm_buffer_object.h @@ -52,13 +52,14 @@ class BufferObject { using ResidencyVector = std::vector; public: - ~BufferObject(){}; + MOCKABLE_VIRTUAL ~BufferObject(){}; bool softPin(uint64_t offset); bool setTiling(uint32_t mode, uint32_t stride); - int pin(BufferObject *boToPin); + int pin(BufferObject *boToPin[], size_t numberOfBos); + int exec(uint32_t used, size_t startOffset, unsigned int flags, bool requiresCoherency = false, bool lowPriority = false); int wait(int64_t timeoutNs); @@ -106,7 +107,7 @@ class BufferObject { uint32_t tiling_mode; uint32_t stride; - void fillExecObject(drm_i915_gem_exec_object2 &execObject); + MOCKABLE_VIRTUAL void fillExecObject(drm_i915_gem_exec_object2 &execObject); void processRelocs(int &idx); uint64_t offset64; // last-seen GPU offset diff --git a/runtime/os_interface/linux/drm_command_stream.inl b/runtime/os_interface/linux/drm_command_stream.inl index ff09ba2597..c72cb3c98f 100644 --- a/runtime/os_interface/linux/drm_command_stream.inl +++ b/runtime/os_interface/linux/drm_command_stream.inl @@ -161,7 +161,7 @@ DrmMemoryManager *DrmCommandStreamReceiver::getMemoryManager() { template MemoryManager *DrmCommandStreamReceiver::createMemoryManager(bool enable64kbPages) { - memoryManager = new DrmMemoryManager(this->drm, this->gemCloseWorkerOperationMode, DebugManager.flags.EnableForcePin.get()); + memoryManager = new DrmMemoryManager(this->drm, this->gemCloseWorkerOperationMode, DebugManager.flags.EnableForcePin.get(), true); return memoryManager; } diff --git a/runtime/os_interface/linux/drm_memory_manager.cpp b/runtime/os_interface/linux/drm_memory_manager.cpp index 19315d812b..943b8dac87 100644 --- a/runtime/os_interface/linux/drm_memory_manager.cpp +++ b/runtime/os_interface/linux/drm_memory_manager.cpp @@ -41,23 +41,29 @@ extern "C" { namespace OCLRT { -DrmMemoryManager::DrmMemoryManager(Drm *drm, gemCloseWorkerMode mode, bool forcePinAllowed) : MemoryManager(false), drm(drm), pinBB(nullptr) { +DrmMemoryManager::DrmMemoryManager(Drm *drm, gemCloseWorkerMode mode, bool forcePinAllowed, bool validateHostPtrMemory) : MemoryManager(false), + drm(drm), + pinBB(nullptr), + forcePinEnabled(forcePinAllowed), + validateHostPtrMemory(validateHostPtrMemory) { MemoryManager::virtualPaddingAvailable = true; if (mode != gemCloseWorkerMode::gemCloseWorkerInactive) { gemCloseWorker.reset(new DrmGemCloseWorker(*this)); } - if (forcePinAllowed) { - auto mem = alignedMalloc(MemoryConstants::pageSize, MemoryConstants::pageSize); - DEBUG_BREAK_IF(mem == nullptr); + auto mem = alignedMalloc(MemoryConstants::pageSize, MemoryConstants::pageSize); + DEBUG_BREAK_IF(mem == nullptr); + if (forcePinEnabled || validateHostPtrMemory) { pinBB = allocUserptr(reinterpret_cast(mem), MemoryConstants::pageSize, 0, true); + } - if (!pinBB) { - alignedFree(mem); - } else { - pinBB->isAllocated = true; - } + if (!pinBB) { + alignedFree(mem); + DEBUG_BREAK_IF(true); + UNRECOVERABLE_IF(validateHostPtrMemory); + } else { + pinBB->isAllocated = true; } internal32bitAllocator.reset(new Allocator32bit); } @@ -191,20 +197,21 @@ DrmAllocation *DrmMemoryManager::allocateGraphicsMemory(size_t size, size_t alig } bo->isAllocated = true; - if (pinBB != nullptr && forcePin && size >= this->pinThreshold) { - pinBB->pin(bo); + if (forcePinEnabled && pinBB != nullptr && forcePin && size >= this->pinThreshold) { + pinBB->pin(&bo, 1); } return new DrmAllocation(bo, res, cSize); } DrmAllocation *DrmMemoryManager::allocateGraphicsMemory(size_t size, const void *ptr, bool forcePin) { - auto res = (DrmAllocation *)MemoryManager::allocateGraphicsMemory(size, const_cast(ptr)); + auto res = (DrmAllocation *)MemoryManager::allocateGraphicsMemory(size, const_cast(ptr), forcePin); - if (res != nullptr && pinBB != nullptr && forcePin && size >= this->pinThreshold) { - pinBB->pin(res->getBO()); + bool forcePinAllowed = res != nullptr && pinBB != nullptr && forcePinEnabled && forcePin && size >= this->pinThreshold; + if (!validateHostPtrMemory && forcePinAllowed) { + BufferObject *boArray[] = {res->getBO()}; + pinBB->pin(boArray, 1); } - return res; } @@ -466,7 +473,10 @@ uint64_t DrmMemoryManager::getInternalHeapBaseAddress() { return this->internal32bitAllocator->getBase(); } -bool DrmMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) { +MemoryManager::AllocationStatus DrmMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) { + BufferObject *allocatedBos[max_fragments_count]; + size_t numberOfBosAllocated = 0; + for (unsigned int i = 0; i < max_fragments_count; i++) { // If there is no fragment it means it already exists. if (!handleStorage.fragmentStorageData[i].osHandleStorage && handleStorage.fragmentStorageData[i].fragmentSize) { @@ -479,12 +489,27 @@ bool DrmMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) { true); if (!handleStorage.fragmentStorageData[i].osHandleStorage->bo) { handleStorage.fragmentStorageData[i].freeTheFragment = true; - return false; + return AllocationStatus::Error; } + + allocatedBos[i] = handleStorage.fragmentStorageData[i].osHandleStorage->bo; + numberOfBosAllocated++; + hostPtrManager.storeFragment(handleStorage.fragmentStorageData[i]); } } - return true; + + if (validateHostPtrMemory) { + int result = pinBB->pin(allocatedBos, numberOfBosAllocated); + + if (result == EFAULT) { + return AllocationStatus::InvalidHostPointer; + } else if (result != 0) { + return AllocationStatus::Error; + } + } + + return AllocationStatus::Success; } void DrmMemoryManager::cleanOsHandles(OsHandleStorage &handleStorage) { for (unsigned int i = 0; i < max_fragments_count; i++) { @@ -506,6 +531,14 @@ BufferObject *DrmMemoryManager::getPinBB() const { return pinBB; } +void DrmMemoryManager::waitForDeletions() { + if (gemCloseWorker.get()) { + while (!gemCloseWorker->isEmpty()) + ; + } + MemoryManager::waitForDeletions(); +} + bool DrmMemoryManager::setDomainCpu(GraphicsAllocation &graphicsAllocation, bool writeEnable) { DEBUG_BREAK_IF(writeEnable); //unsupported path (for CPU writes call SW_FINISH ioctl in unlockResource) diff --git a/runtime/os_interface/linux/drm_memory_manager.h b/runtime/os_interface/linux/drm_memory_manager.h index c545fef9d3..dc97269a29 100644 --- a/runtime/os_interface/linux/drm_memory_manager.h +++ b/runtime/os_interface/linux/drm_memory_manager.h @@ -36,7 +36,7 @@ class DrmMemoryManager : public MemoryManager { public: using MemoryManager::createGraphicsAllocationFromSharedHandle; - DrmMemoryManager(Drm *drm, gemCloseWorkerMode mode, bool forcePinAllowed); + DrmMemoryManager(Drm *drm, gemCloseWorkerMode mode, bool forcePinAllowed, bool validateHostPtrMemory); ~DrmMemoryManager() override; BufferObject *getPinBB() const; @@ -64,7 +64,7 @@ class DrmMemoryManager : public MemoryManager { uint64_t getMaxApplicationAddress() override; uint64_t getInternalHeapBaseAddress() override; - bool populateOsHandles(OsHandleStorage &handleStorage) override; + AllocationStatus populateOsHandles(OsHandleStorage &handleStorage) override; void cleanOsHandles(OsHandleStorage &handleStorage) override; // drm/i915 ioctl wrappers @@ -74,6 +74,10 @@ class DrmMemoryManager : public MemoryManager { void push(DrmAllocation *alloc); DrmAllocation *createGraphicsAllocation(OsHandleStorage &handleStorage, size_t hostPtrSize, const void *hostPtr) override; + void waitForDeletions() override; + bool isValidateHostMemoryEnabled() const { + return validateHostPtrMemory; + } protected: BufferObject *findAndReferenceSharedBufferObject(int boHandle); @@ -86,6 +90,8 @@ class DrmMemoryManager : public MemoryManager { Drm *drm; BufferObject *pinBB; size_t pinThreshold = 8 * 1024 * 1024; + bool forcePinEnabled = false; + const bool validateHostPtrMemory; std::unique_ptr gemCloseWorker; decltype(&lseek) lseekFunction = lseek; decltype(&mmap) mmapFunction = mmap; diff --git a/runtime/os_interface/linux/drm_neo.cpp b/runtime/os_interface/linux/drm_neo.cpp index 04cef88b3a..f8da25153b 100644 --- a/runtime/os_interface/linux/drm_neo.cpp +++ b/runtime/os_interface/linux/drm_neo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Intel Corporation + * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -231,4 +231,8 @@ int Drm::getMinEuInPool(int &minEUinPool) { #endif } +int Drm::getErrno() { + return errno; +} + } // namespace OCLRT diff --git a/runtime/os_interface/linux/drm_neo.h b/runtime/os_interface/linux/drm_neo.h index a3ec1cbd30..5e175c64ca 100644 --- a/runtime/os_interface/linux/drm_neo.h +++ b/runtime/os_interface/linux/drm_neo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Intel Corporation + * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -82,6 +82,7 @@ class Drm { void setGtType(GTTYPE eGtType) { this->eGtType = eGtType; } GTTYPE getGtType() const { return this->eGtType; } + MOCKABLE_VIRTUAL int getErrno(); protected: int fd; diff --git a/runtime/os_interface/windows/wddm_memory_manager.cpp b/runtime/os_interface/windows/wddm_memory_manager.cpp index 75b3a3f915..af5536f951 100644 --- a/runtime/os_interface/windows/wddm_memory_manager.cpp +++ b/runtime/os_interface/windows/wddm_memory_manager.cpp @@ -336,7 +336,7 @@ bool WddmMemoryManager::validateAllocation(WddmAllocation *alloc) { return true; } -bool WddmMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) { +MemoryManager::AllocationStatus WddmMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) { for (unsigned int i = 0; i < max_fragments_count; i++) { // If no fragment is present it means it already exists. if (!handleStorage.fragmentStorageData[i].osHandleStorage && handleStorage.fragmentStorageData[i].cpuPtr) { @@ -348,7 +348,7 @@ bool WddmMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) { } } wddm->createAllocationsAndMapGpuVa(handleStorage); - return true; + return AllocationStatus::Success; } void WddmMemoryManager::cleanOsHandles(OsHandleStorage &handleStorage) { diff --git a/runtime/os_interface/windows/wddm_memory_manager.h b/runtime/os_interface/windows/wddm_memory_manager.h index 57e43bec7b..3b4e10674a 100644 --- a/runtime/os_interface/windows/wddm_memory_manager.h +++ b/runtime/os_interface/windows/wddm_memory_manager.h @@ -57,7 +57,7 @@ class WddmMemoryManager : public MemoryManager { bool makeResidentResidencyAllocations(ResidencyContainer *allocationsForResidency); void makeNonResidentEvictionAllocations(); - bool populateOsHandles(OsHandleStorage &handleStorage) override; + AllocationStatus populateOsHandles(OsHandleStorage &handleStorage) override; void cleanOsHandles(OsHandleStorage &handleStorage) override; GraphicsAllocation *createGraphicsAllocation(OsHandleStorage &handleStorage, size_t hostPtrSize, const void *hostPtr) override; diff --git a/unit_tests/command_queue/command_queue_hw_tests.cpp b/unit_tests/command_queue/command_queue_hw_tests.cpp index 311bc98b22..21ff3eb697 100644 --- a/unit_tests/command_queue/command_queue_hw_tests.cpp +++ b/unit_tests/command_queue/command_queue_hw_tests.cpp @@ -34,6 +34,7 @@ #include "unit_tests/fixtures/context_fixture.h" #include "unit_tests/fixtures/device_fixture.h" #include "unit_tests/fixtures/memory_management_fixture.h" +#include "unit_tests/gen_common/matchers.h" #include "unit_tests/helpers/debug_manager_state_restore.h" #include "unit_tests/mocks/mock_buffer.h" #include "unit_tests/mocks/mock_command_queue.h" @@ -44,8 +45,8 @@ #include "unit_tests/mocks/mock_program.h" #include "unit_tests/helpers/debug_manager_state_restore.h" #include "test.h" - #include "gmock/gmock-matchers.h" +#include using namespace OCLRT; @@ -1085,3 +1086,66 @@ HWTEST_F(CommandQueueHwTest, givenKernelSplitEnqueueReadBufferWhenBlockedThenEnq EXPECT_EQ(expected, it->second); } } + +HWTEST_F(CommandQueueHwTest, givenReadOnlyHostPointerWhenAllocationForHostSurfaceWithPtrCopyAllowedIsCreatedThenCopyAllocationIsCreatedAndMemoryCopied) { + ::testing::NiceMock *gmockMemoryManager = new ::testing::NiceMock; + ASSERT_NE(nullptr, gmockMemoryManager); + + std::unique_ptr device(DeviceHelper<>::create(nullptr)); + ASSERT_NE(nullptr, device.get()); + device->injectMemoryManager(gmockMemoryManager); + MockContext *mockContext = new MockContext(device.get()); + ASSERT_NE(nullptr, mockContext); + + auto mockCmdQ = new MockCommandQueueHw(mockContext, device.get(), 0); + ASSERT_NE(nullptr, mockCmdQ); + + const char memory[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + size_t size = sizeof(memory); + HostPtrSurface surface(const_cast(memory), size, true); + + EXPECT_CALL(*gmockMemoryManager, populateOsHandles(::testing::_)).Times(1).WillOnce(::testing::Return(MemoryManager::AllocationStatus::InvalidHostPointer)); + + bool result = mockCmdQ->createAllocationForHostSurface(surface); + EXPECT_TRUE(result); + + auto allocation = surface.getAllocation(); + ASSERT_NE(nullptr, allocation); + + EXPECT_NE(memory, allocation->getUnderlyingBuffer()); + EXPECT_THAT(allocation->getUnderlyingBuffer(), MemCompare(memory, size)); + + gmockMemoryManager->cleanAllocationList(-1, TEMPORARY_ALLOCATION); + mockCmdQ->release(); + mockContext->release(); +} + +HWTEST_F(CommandQueueHwTest, givenReadOnlyHostPointerWhenAllocationForHostSurfaceWithPtrCopyNotAllowedIsCreatedThenCopyAllocationIsNotCreated) { + ::testing::NiceMock *gmockMemoryManager = new ::testing::NiceMock; + ASSERT_NE(nullptr, gmockMemoryManager); + + std::unique_ptr device(DeviceHelper<>::create(nullptr)); + ASSERT_NE(nullptr, device.get()); + device->injectMemoryManager(gmockMemoryManager); + MockContext *mockContext = new MockContext(device.get()); + ASSERT_NE(nullptr, mockContext); + + auto mockCmdQ = new MockCommandQueueHw(mockContext, device.get(), 0); + ASSERT_NE(nullptr, mockCmdQ); + + const char memory[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + size_t size = sizeof(memory); + HostPtrSurface surface(const_cast(memory), size, false); + + EXPECT_CALL(*gmockMemoryManager, populateOsHandles(::testing::_)).Times(1).WillOnce(::testing::Return(MemoryManager::AllocationStatus::InvalidHostPointer)); + + bool result = mockCmdQ->createAllocationForHostSurface(surface); + EXPECT_FALSE(result); + + auto allocation = surface.getAllocation(); + EXPECT_EQ(nullptr, allocation); + + gmockMemoryManager->cleanAllocationList(-1, TEMPORARY_ALLOCATION); + mockCmdQ->release(); + mockContext->release(); +} diff --git a/unit_tests/fixtures/memory_manager_fixture.cpp b/unit_tests/fixtures/memory_manager_fixture.cpp index 955d4a51a5..50fb1e30b9 100644 --- a/unit_tests/fixtures/memory_manager_fixture.cpp +++ b/unit_tests/fixtures/memory_manager_fixture.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Intel Corporation + * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -32,6 +32,7 @@ void MemoryManagerWithCsrFixture::SetUp() { memoryManager = gmockMemoryManager; ON_CALL(*gmockMemoryManager, cleanAllocationList(::testing::_, ::testing::_)).WillByDefault(::testing::Invoke(gmockMemoryManager, &GMockMemoryManager::MemoryManagerCleanAllocationList)); + ON_CALL(*gmockMemoryManager, populateOsHandles(::testing::_)).WillByDefault(::testing::Invoke(gmockMemoryManager, &GMockMemoryManager::MemoryManagerPopulateOsHandles)); csr.tagAddress = ¤tGpuTag; memoryManager->csr = &csr; diff --git a/unit_tests/memory_manager/CMakeLists.txt b/unit_tests/memory_manager/CMakeLists.txt index 21bee043ce..4f6db3414e 100644 --- a/unit_tests/memory_manager/CMakeLists.txt +++ b/unit_tests/memory_manager/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017, Intel Corporation +# Copyright (c) 2017 - 2018, Intel Corporation # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -24,6 +24,7 @@ set(IGDRCL_SRCS_tests_memory_manager ${CMAKE_CURRENT_SOURCE_DIR}/deferred_deleter_mt_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/host_ptr_manager_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/memory_manager_tests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/memory_manager_allocate_with_ptr_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/page_table_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/surface_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/svm_memory_manager.cpp diff --git a/unit_tests/memory_manager/memory_manager_allocate_with_ptr_tests.cpp b/unit_tests/memory_manager/memory_manager_allocate_with_ptr_tests.cpp new file mode 100644 index 0000000000..dca27ade56 --- /dev/null +++ b/unit_tests/memory_manager/memory_manager_allocate_with_ptr_tests.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * 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 "gtest/gtest.h" +#include "test.h" +#include "unit_tests/gen_common/matchers.h" +#include "unit_tests/mocks/mock_memory_manager.h" +#include + +using namespace OCLRT; +using namespace std; +using namespace ::testing; + +TEST(MemoryManagerTest, givenInvalidHostPointerWhenPopulateOsHandlesFailsThenNullAllocationIsReturned) { + unique_ptr> gmockMemoryManager(new NiceMock); + + EXPECT_CALL(*gmockMemoryManager, populateOsHandles(::testing::_)).Times(1).WillOnce(::testing::Return(MemoryManager::AllocationStatus::InvalidHostPointer)); + + const char memory[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + size_t size = sizeof(memory); + + auto allocation = gmockMemoryManager->allocateGraphicsMemory(size, memory); + + ASSERT_EQ(nullptr, allocation); + gmockMemoryManager->freeGraphicsMemory(allocation); +} diff --git a/unit_tests/memory_manager/surface_tests.cpp b/unit_tests/memory_manager/surface_tests.cpp index 1e97898d8e..878a8e55cf 100644 --- a/unit_tests/memory_manager/surface_tests.cpp +++ b/unit_tests/memory_manager/surface_tests.cpp @@ -113,3 +113,24 @@ TEST_F(CoherentMemObjSurface, BufferFromCoherentSvm) { delete surface; } + +TEST(HostPtrSurfaceTest, givenHostPtrSurfaceWhenCreatedWithoutSpecifyingPtrCopyAllowanceThenPtrCopyIsNotAllowed) { + char memory[2]; + HostPtrSurface surface(memory, sizeof(memory)); + + EXPECT_FALSE(surface.peekIsPtrCopyAllowed()); +} + +TEST(HostPtrSurfaceTest, givenHostPtrSurfaceWhenCreatedWithPtrCopyAllowedThenQueryReturnsTrue) { + char memory[2]; + HostPtrSurface surface(memory, sizeof(memory), true); + + EXPECT_TRUE(surface.peekIsPtrCopyAllowed()); +} + +TEST(HostPtrSurfaceTest, givenHostPtrSurfaceWhenCreatedWithPtrCopyNotAllowedThenQueryReturnsFalse) { + char memory[2]; + HostPtrSurface surface(memory, sizeof(memory), false); + + EXPECT_FALSE(surface.peekIsPtrCopyAllowed()); +} diff --git a/unit_tests/mocks/mock_command_queue.h b/unit_tests/mocks/mock_command_queue.h index 592ac23f4f..7a6abc9748 100644 --- a/unit_tests/mocks/mock_command_queue.h +++ b/unit_tests/mocks/mock_command_queue.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Intel Corporation + * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -53,6 +53,8 @@ class MockCommandQueueHw : public CommandQueueHw { typedef CommandQueueHw BaseClass; public: + using BaseClass::createAllocationForHostSurface; + MockCommandQueueHw(Context *context, Device *device, cl_queue_properties *properties) : BaseClass(context, device, properties) { diff --git a/unit_tests/mocks/mock_device.h b/unit_tests/mocks/mock_device.h index ecade49884..10624c14f1 100644 --- a/unit_tests/mocks/mock_device.h +++ b/unit_tests/mocks/mock_device.h @@ -138,8 +138,8 @@ class FailMemoryManager : public MockMemoryManager { void *lockResource(GraphicsAllocation *gfxAllocation) override { return nullptr; }; void unlockResource(GraphicsAllocation *gfxAllocation) override{}; - bool populateOsHandles(OsHandleStorage &handleStorage) override { - return false; + MemoryManager::AllocationStatus populateOsHandles(OsHandleStorage &handleStorage) override { + return AllocationStatus::Error; }; void cleanOsHandles(OsHandleStorage &handleStorage) override{}; diff --git a/unit_tests/mocks/mock_memory_manager.h b/unit_tests/mocks/mock_memory_manager.h index 0bda87a53e..7f80c575eb 100644 --- a/unit_tests/mocks/mock_memory_manager.h +++ b/unit_tests/mocks/mock_memory_manager.h @@ -39,11 +39,14 @@ class MockMemoryManager : public OsAgnosticMemoryManager { GraphicsAllocation *peekAllocationListHead(); }; -class GMockMemoryManager : public OsAgnosticMemoryManager { +class GMockMemoryManager : public MockMemoryManager { public: MOCK_METHOD2(cleanAllocationList, bool(uint32_t waitTaskCount, uint32_t allocationType)); // cleanAllocationList call defined in MemoryManager. + + MOCK_METHOD1(populateOsHandles, MemoryManager::AllocationStatus(OsHandleStorage &handleStorage)); bool MemoryManagerCleanAllocationList(uint32_t waitTaskCount, uint32_t allocationType) { return MemoryManager::cleanAllocationList(waitTaskCount, allocationType); } + MemoryManager::AllocationStatus MemoryManagerPopulateOsHandles(OsHandleStorage &handleStorage) { return OsAgnosticMemoryManager::populateOsHandles(handleStorage); } }; class MockAllocSysMemAgnosticMemoryManager : public OsAgnosticMemoryManager { diff --git a/unit_tests/os_interface/linux/device_command_stream_fixture.h b/unit_tests/os_interface/linux/device_command_stream_fixture.h index a8a6ac81fd..149baa1a83 100644 --- a/unit_tests/os_interface/linux/device_command_stream_fixture.h +++ b/unit_tests/os_interface/linux/device_command_stream_fixture.h @@ -168,6 +168,8 @@ class DrmMockCustom : public Drm { __u32 setDomainReadDomains = 0; __u32 setDomainWriteDomain = 0; + int errnoValue = 0; + int ioctl(unsigned long request, void *arg) override { auto ext = ioctl_res_ext.load(); @@ -267,4 +269,7 @@ class DrmMockCustom : public Drm { DrmMockCustom() : Drm(mockFd) { reset(); } + int getErrno() override { + return errnoValue; + } }; diff --git a/unit_tests/os_interface/linux/drm_buffer_object_tests.cpp b/unit_tests/os_interface/linux/drm_buffer_object_tests.cpp index c6d258d072..48d3f876a9 100644 --- a/unit_tests/os_interface/linux/drm_buffer_object_tests.cpp +++ b/unit_tests/os_interface/linux/drm_buffer_object_tests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Intel Corporation + * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -40,9 +40,12 @@ class TestedBufferObject : public BufferObject { this->tiling_mode = mode; } - void fillExecObject(drm_i915_gem_exec_object2 &execObject) { + void fillExecObject(drm_i915_gem_exec_object2 &execObject) override { BufferObject::fillExecObject(execObject); + execObjectPointerFilled = &execObject; } + + drm_i915_gem_exec_object2 *execObjectPointerFilled = nullptr; }; class DrmBufferObjectFixture : public MemoryManagementFixture { @@ -159,7 +162,8 @@ TEST_F(DrmBufferObjectTest, onPinBBhasOnlyBbEndAndForceNonCoherent) { ASSERT_NE(nullptr, boToPin.get()); bo->setAddress(buff.get()); - auto ret = bo->pin(boToPin.get()); + BufferObject *boArray[1] = {boToPin.get()}; + auto ret = bo->pin(boArray, 1); EXPECT_EQ(mock->ioctl_res, ret); uint32_t bb_end = 0x05000000; EXPECT_EQ(buff[0], bb_end); @@ -179,7 +183,8 @@ TEST_F(DrmBufferObjectTest, onPinBBhasOnlyBbEndAndNoForceNonCoherent) { ASSERT_NE(nullptr, boToPin.get()); bo->setAddress(buff.get()); - auto ret = bo->pin(boToPin.get()); + BufferObject *boArray[1] = {boToPin.get()}; + auto ret = bo->pin(boArray, 1); EXPECT_EQ(mock->ioctl_res, ret); uint32_t bb_end = 0x05000000; EXPECT_EQ(buff[0], bb_end); @@ -194,11 +199,71 @@ TEST_F(DrmBufferObjectTest, onPinIoctlFailed) { mock->ioctl_expected.total = 1; mock->ioctl_res = -1; + this->mock->errnoValue = EINVAL; std::unique_ptr boToPin(new TestedBufferObject(this->mock)); ASSERT_NE(nullptr, boToPin.get()); bo->setAddress(buff.get()); - auto ret = bo->pin(boToPin.get()); - EXPECT_EQ(mock->ioctl_res, ret); + BufferObject *boArray[1] = {boToPin.get()}; + auto ret = bo->pin(boArray, 1); + EXPECT_EQ(EINVAL, ret); +} + +TEST(DrmBufferObjectSimpleTest, givenInvalidBoWhenPinIsCalledThenErrorIsReturned) { + std::unique_ptr buff(new uint32_t[256]); + std::unique_ptr mock(new DrmMockCustom); + ASSERT_NE(nullptr, mock.get()); + std::unique_ptr bo(new TestedBufferObject(mock.get())); + ASSERT_NE(nullptr, bo.get()); + drm_i915_gem_exec_object2 execObjectsStorage[3]; + bo->setExecObjectsStorage(execObjectsStorage); + + // fail DRM_IOCTL_I915_GEM_EXECBUFFER2 in pin + mock->ioctl_res = -1; + + std::unique_ptr boToPin(new TestedBufferObject(mock.get())); + ASSERT_NE(nullptr, boToPin.get()); + + bo->setAddress(buff.get()); + mock->errnoValue = EFAULT; + + BufferObject *boArray[1] = {boToPin.get()}; + auto ret = bo->pin(boArray, 1); + EXPECT_EQ(EFAULT, ret); +} + +TEST(DrmBufferObjectSimpleTest, givenArrayOfBosWhenPinnedThenAllBosArePinned) { + std::unique_ptr buff(new uint32_t[256]); + std::unique_ptr mock(new DrmMockCustom); + ASSERT_NE(nullptr, mock.get()); + std::unique_ptr bo(new TestedBufferObject(mock.get())); + ASSERT_NE(nullptr, bo.get()); + drm_i915_gem_exec_object2 execObjectsStorage[4]; + bo->setExecObjectsStorage(execObjectsStorage); + mock->ioctl_res = 0; + + std::unique_ptr boToPin(new TestedBufferObject(mock.get())); + std::unique_ptr boToPin2(new TestedBufferObject(mock.get())); + std::unique_ptr boToPin3(new TestedBufferObject(mock.get())); + + ASSERT_NE(nullptr, boToPin.get()); + ASSERT_NE(nullptr, boToPin2.get()); + ASSERT_NE(nullptr, boToPin3.get()); + + BufferObject *array[3] = {boToPin.get(), boToPin2.get(), boToPin3.get()}; + + bo->setAddress(buff.get()); + auto ret = bo->pin(array, 3); + EXPECT_EQ(mock->ioctl_res, ret); + uint32_t bb_end = 0x05000000; + EXPECT_EQ(buff[0], bb_end); + + EXPECT_LT(0u, mock->execBuffer.batch_len); + EXPECT_EQ(4u, mock->execBuffer.buffer_count); // 3 bos to pin plus 1 exec bo + EXPECT_EQ(reinterpret_cast(boToPin->execObjectPointerFilled), mock->execBuffer.buffers_ptr); + EXPECT_NE(nullptr, boToPin2->execObjectPointerFilled); + EXPECT_NE(nullptr, boToPin3->execObjectPointerFilled); + + bo->setAddress(nullptr); } diff --git a/unit_tests/os_interface/linux/drm_command_stream_mm_tests.cpp b/unit_tests/os_interface/linux/drm_command_stream_mm_tests.cpp index f146e8a029..48d5c4fa73 100644 --- a/unit_tests/os_interface/linux/drm_command_stream_mm_tests.cpp +++ b/unit_tests/os_interface/linux/drm_command_stream_mm_tests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Intel Corporation + * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -61,7 +61,7 @@ HWTEST_F(DrmCommandStreamMMTest, MMwithPinBB) { } } -HWTEST_F(DrmCommandStreamMMTest, MMwithoutPinBB) { +HWTEST_F(DrmCommandStreamMMTest, givenForcePinDisabledWhenMemoryManagerIsCreatedThenPinBBIsCreated) { DebugManagerStateRestore dbgRestorer; { DebugManager.flags.EnableForcePin.set(false); @@ -75,7 +75,7 @@ HWTEST_F(DrmCommandStreamMMTest, MMwithoutPinBB) { csr.setMemoryManager(nullptr); ASSERT_NE(nullptr, mm); - EXPECT_EQ(nullptr, mm->getPinBB()); + EXPECT_NE(nullptr, mm->getPinBB()); delete mm; } diff --git a/unit_tests/os_interface/linux/drm_command_stream_tests.cpp b/unit_tests/os_interface/linux/drm_command_stream_tests.cpp index be256bbefa..87ef313a64 100644 --- a/unit_tests/os_interface/linux/drm_command_stream_tests.cpp +++ b/unit_tests/os_interface/linux/drm_command_stream_tests.cpp @@ -66,13 +66,22 @@ class DrmCommandStreamFixture { csr = new DrmCommandStreamReceiver(*platformDevices[0], mock, gemCloseWorkerMode::gemCloseWorkerConsumingCommandBuffers); ASSERT_NE(nullptr, csr); + + // Memory manager creates pinBB with ioctl, expect one call + EXPECT_CALL(*mock, ioctl(::testing::_, ::testing::_)).Times(1); mm = csr->createMemoryManager(false); + ::testing::Mock::VerifyAndClearExpectations(mock); + //assert we have memory manager ASSERT_NE(nullptr, mm); } void TearDown() { + mm->waitForDeletions(); + ::testing::Mock::VerifyAndClearExpectations(mock); delete csr; + // Memory manager closes pinBB with ioctl, expect one call + EXPECT_CALL(*mock, ioctl(::testing::_, ::testing::_)).Times(::testing::AtLeast(1)); delete mm; delete this->mock; this->mock = 0; @@ -178,16 +187,21 @@ TEST_F(DrmCommandStreamTest, Flush) { return 0; }; + ::testing::InSequence inSequence; EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_USERPTR, ::testing::_)) .Times(1) - .WillRepeatedly(::testing::Invoke(setBoHandle)); + .WillRepeatedly(::testing::Invoke(setBoHandle)) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_EXECBUFFER2, BoExecFlushEq(0u, expectedSize))) .Times(1) - .WillRepeatedly(::testing::Return(0)); - EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) - .Times(1); + .WillRepeatedly(::testing::Return(0)) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_WAIT, ::testing::_)) - .Times(1); + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) + .Times(1) + .RetiresOnSaturation(); DrmAllocation *commandBuffer = static_cast(mm->allocateGraphicsMemory(1024, 4096)); ASSERT_NE(nullptr, commandBuffer); @@ -207,16 +221,22 @@ TEST_F(DrmCommandStreamTest, Flush) { TEST_F(DrmCommandStreamTest, FlushWithLowPriorityContext) { auto expectedSize = alignUp(8u, MemoryConstants::cacheLineSize); // bbEnd + ::testing::InSequence inSequence; + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_USERPTR, ::testing::_)) .Times(1) - .WillRepeatedly(::testing::Return(0)); + .WillRepeatedly(::testing::Return(0)) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_EXECBUFFER2, BoExecFlushEq(0u, expectedSize))) .Times(1) - .WillRepeatedly(::testing::Return(0)); - EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) - .Times(1); + .WillRepeatedly(::testing::Return(0)) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_WAIT, ::testing::_)) - .Times(1); + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) + .Times(1) + .RetiresOnSaturation(); auto *commandBuffer = mm->allocateGraphicsMemory(1024, 4096); ASSERT_NE(nullptr, commandBuffer); @@ -232,14 +252,20 @@ TEST_F(DrmCommandStreamTest, FlushWithLowPriorityContext) { } TEST_F(DrmCommandStreamTest, FlushInvalidAddress) { + ::testing::InSequence inSequence; + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_USERPTR, ::testing::_)) - .Times(0); + .Times(0) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_EXECBUFFER2, BoExecFlushEq(0u, 8u))) - .Times(0); - EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) - .Times(0); + .Times(0) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_WAIT, ::testing::_)) - .Times(0); + .Times(0) + .RetiresOnSaturation(); + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) + .Times(0) + .RetiresOnSaturation(); //allocate command buffer manually char *commandBuffer = new (std::nothrow) char[1024]; @@ -257,16 +283,22 @@ TEST_F(DrmCommandStreamTest, FlushInvalidAddress) { TEST_F(DrmCommandStreamTest, FlushMultipleTimes) { auto expectedSize = alignUp(8u, MemoryConstants::cacheLineSize); // bbEnd + ::testing::InSequence inSequence; + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_USERPTR, ::testing::_)) .Times(1) - .WillRepeatedly(::testing::Return(0)); + .WillRepeatedly(::testing::Return(0)) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_EXECBUFFER2, BoExecFlushEq(0u, expectedSize))) .Times(1) - .WillRepeatedly(::testing::Return(0)); - EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) - .Times(1); + .WillRepeatedly(::testing::Return(0)) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_WAIT, ::testing::_)) - .Times(1); + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) + .Times(1) + .RetiresOnSaturation(); auto *commandBuffer = mm->allocateGraphicsMemory(1024, 4096); ASSERT_NE(nullptr, commandBuffer); @@ -283,16 +315,22 @@ TEST_F(DrmCommandStreamTest, FlushNotEmptyBB) { uint32_t bbUsed = 16 * sizeof(uint32_t); auto expectedSize = alignUp(bbUsed + 8, MemoryConstants::cacheLineSize); // bbUsed + bbEnd + ::testing::InSequence inSequence; + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_USERPTR, ::testing::_)) .Times(1) - .WillRepeatedly(::testing::Return(0)); + .WillRepeatedly(::testing::Return(0)) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_EXECBUFFER2, BoExecFlushEq(0u, expectedSize))) .Times(1) - .WillRepeatedly(::testing::Return(0)); - EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) - .Times(1); + .WillRepeatedly(::testing::Return(0)) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_WAIT, ::testing::_)) - .Times(1); + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) + .Times(1) + .RetiresOnSaturation(); auto *commandBuffer = mm->allocateGraphicsMemory(1024, 4096); ASSERT_NE(nullptr, commandBuffer); @@ -308,16 +346,23 @@ TEST_F(DrmCommandStreamTest, FlushNotEmptyBB) { TEST_F(DrmCommandStreamTest, FlushNotEmptyNotPaddedBB) { uint32_t bbUsed = 15 * sizeof(uint32_t); + + ::testing::InSequence inSequence; + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_USERPTR, ::testing::_)) .Times(1) - .WillRepeatedly(::testing::Return(0)); + .WillRepeatedly(::testing::Return(0)) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_EXECBUFFER2, BoExecFlushEq(0u, bbUsed + 4))) .Times(1) - .WillRepeatedly(::testing::Return(0)); - EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) - .Times(1); + .WillRepeatedly(::testing::Return(0)) + .RetiresOnSaturation(); EXPECT_CALL(*mock, ioctl(DRM_IOCTL_I915_GEM_WAIT, ::testing::_)) - .Times(1); + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*mock, ioctl(DRM_IOCTL_GEM_CLOSE, ::testing::_)) + .Times(1) + .RetiresOnSaturation(); auto *commandBuffer = mm->allocateGraphicsMemory(1024, 4096); ASSERT_NE(nullptr, commandBuffer); @@ -912,7 +957,7 @@ TEST_F(DrmCommandStreamBatchingTests, givenCSRWhenFlushIsCalledThenProperFlagsAr BatchBuffer batchBuffer{cs.getGraphicsAllocation(), 0, 0, nullptr, false, false, QueueThrottle::MEDIUM, cs.getUsed(), &cs}; csr->flush(batchBuffer, EngineType::ENGINE_RCS, nullptr); - EXPECT_EQ(3, this->mock->ioctl_cnt.total); + EXPECT_EQ(4, this->mock->ioctl_cnt.total); uint64_t flags = I915_EXEC_RENDER | I915_EXEC_NO_RELOC; EXPECT_EQ(flags, this->mock->execBuffer.flags); @@ -965,7 +1010,7 @@ TEST_F(DrmCommandStreamBatchingTests, givenCsrWhenDispatchPolicyIsSetToBatchingT EXPECT_EQ(tCsr->commandStream.getGraphicsAllocation(), recordedCmdBuffer->batchBuffer.commandBufferAllocation); - EXPECT_EQ(4, this->mock->ioctl_cnt.total); + EXPECT_EQ(5, this->mock->ioctl_cnt.total); EXPECT_EQ(0u, this->mock->execBuffer.flags); @@ -1031,7 +1076,7 @@ TEST_F(DrmCommandStreamBatchingTests, givenRecordedCommandBufferWhenItIsSubmitte EXPECT_TRUE(handleFound); } - EXPECT_EQ(5, this->mock->ioctl_cnt.total); + EXPECT_EQ(6, this->mock->ioctl_cnt.total); mm->freeGraphicsMemory(dummyAllocation); mm->freeGraphicsMemory(commandBuffer); @@ -1660,3 +1705,9 @@ TEST_F(DrmCommandStreamLeaksTest, BufferResidency) { EXPECT_FALSE(buffer->getGraphicsAllocation()->isResident()); EXPECT_EQ(ObjectNotResident, buffer->getGraphicsAllocation()->residencyTaskCount); } + +typedef Test DrmCommandStreamMemoryManagerTest; + +TEST_F(DrmCommandStreamMemoryManagerTest, givenDrmCommandStreamReceiverWhenMemoryManagerIsCreatedThenItHasHostMemoryValidationEnabledByDefault) { + EXPECT_TRUE(mm->isValidateHostMemoryEnabled()); +} diff --git a/unit_tests/os_interface/linux/drm_gem_close_worker_tests.cpp b/unit_tests/os_interface/linux/drm_gem_close_worker_tests.cpp index 99a21d56de..7194833b4d 100644 --- a/unit_tests/os_interface/linux/drm_gem_close_worker_tests.cpp +++ b/unit_tests/os_interface/linux/drm_gem_close_worker_tests.cpp @@ -82,7 +82,7 @@ class DrmGemCloseWorkerFixture : public MemoryManagementFixture { this->drmMock->gem_close_cnt = 0; this->drmMock->gem_close_expected = 0; - this->mm = new DrmMemoryManager(this->drmMock, gemCloseWorkerMode::gemCloseWorkerConsumingCommandBuffers, false); + this->mm = new DrmMemoryManager(this->drmMock, gemCloseWorkerMode::gemCloseWorkerConsumingCommandBuffers, false, false); } void TearDown() override { diff --git a/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp b/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp index dfd0d88840..cdca003c1f 100644 --- a/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp +++ b/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp @@ -81,7 +81,7 @@ class TestedDrmMemoryManager : public DrmMemoryManager { using DrmMemoryManager::allocUserptr; using DrmMemoryManager::setDomainCpu; - TestedDrmMemoryManager(Drm *drm) : DrmMemoryManager(drm, gemCloseWorkerMode::gemCloseWorkerConsumingCommandBuffers, false) { + TestedDrmMemoryManager(Drm *drm) : DrmMemoryManager(drm, gemCloseWorkerMode::gemCloseWorkerConsumingCommandBuffers, false, false) { this->lseekFunction = &lseekMock; this->mmapFunction = &mmapMock; this->munmapFunction = &munmapMock; @@ -91,7 +91,7 @@ class TestedDrmMemoryManager : public DrmMemoryManager { mmapMockCallCount = 0; munmapMockCallCount = 0; }; - TestedDrmMemoryManager(Drm *drm, bool allowForcePin) : DrmMemoryManager(drm, gemCloseWorkerMode::gemCloseWorkerConsumingCommandBuffers, allowForcePin) { + TestedDrmMemoryManager(Drm *drm, bool allowForcePin, bool validateHostPtrMemory) : DrmMemoryManager(drm, gemCloseWorkerMode::gemCloseWorkerConsumingCommandBuffers, allowForcePin, validateHostPtrMemory) { this->lseekFunction = &lseekMock; this->mmapFunction = &mmapMock; this->munmapFunction = &munmapMock; @@ -140,31 +140,61 @@ class DrmMemoryManagerFixture : public MemoryManagementFixture { DrmMockCustom::IoctlResExt ioctlResExt = {0, 0}; }; -typedef Test DrmMemoryManagerTest; +class DrmMemoryManagerFixtureWithoutQuietIoctlExpectation : public MemoryManagementFixture { + public: + TestedDrmMemoryManager *memoryManager = nullptr; + DrmMockCustom *mock; -TEST_F(DrmMemoryManagerTest, givenDefaultDrmMemoryMangerWhenItIsCreatedThenItContainsInternal32BitAllocator) { - mock->ioctl_expected.reset(); + void SetUp() override { + MemoryManagementFixture::SetUp(); + this->mock = new DrmMockCustom; + memoryManager = new (std::nothrow) TestedDrmMemoryManager(this->mock); + ASSERT_NE(nullptr, memoryManager); + memoryManager->getgemCloseWorker()->close(true); + } + + void TearDown() override { + delete memoryManager; + delete this->mock; + this->mock = nullptr; + MemoryManagementFixture::TearDown(); + } + + protected: + DrmMockCustom::IoctlResExt ioctlResExt = {0, 0}; +}; + +typedef Test DrmMemoryManagerTest; +typedef Test DrmMemoryManagerWithExplicitExpectationsTest; + +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenDefaultDrmMemoryMangerWhenItIsCreatedThenItContainsInternal32BitAllocator) { EXPECT_NE(nullptr, memoryManager->getDrmInternal32BitAllocator()); } -TEST_F(DrmMemoryManagerTest, pinBBnotCreated) { - mock->ioctl_expected.reset(); - EXPECT_EQ(nullptr, memoryManager->getPinBB()); +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenforcePinAllowedWhenMemoryManagerIsCreatedThenPinBbIsCreated) { + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true, false); + EXPECT_NE(nullptr, mm->getPinBB()); + delete mm; } TEST_F(DrmMemoryManagerTest, pinBBisCreated) { mock->ioctl_expected.gemUserptr = 1; mock->ioctl_expected.gemClose = 1; - auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true); + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true, false); EXPECT_NE(nullptr, mm->getPinBB()); delete mm; } +TEST_F(DrmMemoryManagerTest, givenNotAllowedForcePinWhenMemoryManagerIsCreatedThenPinBBIsNotCreated) { + std::unique_ptr mm(new (std::nothrow) TestedDrmMemoryManager(this->mock, false, false)); + EXPECT_EQ(nullptr, mm->getPinBB()); +} + TEST_F(DrmMemoryManagerTest, pinBBnotCreatedWhenIoctlFailed) { mock->ioctl_expected.gemUserptr = 1; mock->ioctl_res = -1; - auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true); + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true, false); EXPECT_EQ(nullptr, mm->getPinBB()); delete mm; } @@ -175,7 +205,7 @@ TEST_F(DrmMemoryManagerTest, pinAfterAllocateWhenAskedAndAllowedAndBigAllocation mock->ioctl_expected.gemWait = 1; mock->ioctl_expected.gemClose = 2; - auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true); + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true, false); ASSERT_NE(nullptr, mm->getPinBB()); auto alloc = mm->allocateGraphicsMemory(10 * 1014 * 1024, 1024, true, false); @@ -192,7 +222,7 @@ TEST_F(DrmMemoryManagerTest, doNotPinAfterAllocateWhenAskedAndAllowedButSmallAll mock->ioctl_expected.gemWait = 1; mock->ioctl_expected.gemClose = 2; - auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true); + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true, false); ASSERT_NE(nullptr, mm->getPinBB()); // one page is too small for early pinning @@ -210,7 +240,7 @@ TEST_F(DrmMemoryManagerTest, doNotPinAfterAllocateWhenNotAskedButAllowed) { mock->ioctl_expected.gemClose = 2; mock->ioctl_expected.gemWait = 1; - auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true); + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true, false); ASSERT_NE(nullptr, mm->getPinBB()); auto alloc = mm->allocateGraphicsMemory(1024, 1024, false, false); @@ -227,8 +257,7 @@ TEST_F(DrmMemoryManagerTest, doNotPinAfterAllocateWhenAskedButNotAllowed) { mock->ioctl_expected.gemWait = 1; mock->ioctl_expected.gemClose = 1; - auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, false); - ASSERT_EQ(nullptr, mm->getPinBB()); + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, false, false); auto alloc = mm->allocateGraphicsMemory(1024, 1024, true, false); ASSERT_NE(nullptr, alloc); @@ -246,7 +275,7 @@ TEST_F(DrmMemoryManagerTest, pinAfterAllocateWhenAskedAndAllowedAndBigAllocation mock->ioctl_expected.execbuffer2 = 1; mock->ioctl_expected.gemWait = 1; - auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true); + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true, false); ASSERT_NE(nullptr, mm->getPinBB()); size_t size = 10 * 1024 * 1024; @@ -261,12 +290,12 @@ TEST_F(DrmMemoryManagerTest, pinAfterAllocateWhenAskedAndAllowedAndBigAllocation ::alignedFree(ptr); } -TEST_F(DrmMemoryManagerTest, doNotPinAfterAllocateWhenAskedAndAllowedButSmallAllocationHostPtr) { +TEST_F(DrmMemoryManagerTest, givenSmallAllocationHostPtrAllocationWhenForcePinIsTrueThenBufferObjectIsNotPinned) { mock->ioctl_expected.gemUserptr = 2; mock->ioctl_expected.gemWait = 1; mock->ioctl_expected.gemClose = 2; - auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true); + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true, false); ASSERT_NE(nullptr, mm->getPinBB()); // one page is too small for early pinning @@ -287,7 +316,7 @@ TEST_F(DrmMemoryManagerTest, doNotPinAfterAllocateWhenNotAskedButAllowedHostPtr) mock->ioctl_expected.gemWait = 1; mock->ioctl_expected.gemClose = 2; - auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true); + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, true, false); ASSERT_NE(nullptr, mm->getPinBB()); size_t size = 4 * 1024; @@ -307,8 +336,7 @@ TEST_F(DrmMemoryManagerTest, doNotPinAfterAllocateWhenAskedButNotAllowedHostPtr) mock->ioctl_expected.gemWait = 1; mock->ioctl_expected.gemClose = 1; - auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, false); - ASSERT_EQ(nullptr, mm->getPinBB()); + auto mm = new (std::nothrow) TestedDrmMemoryManager(this->mock, false, false); size_t size = 4 * 1024; void *ptr = ::alignedMalloc(size, 4096); @@ -334,10 +362,10 @@ TEST_F(DrmMemoryManagerTest, UnreferenceNullPtr) { memoryManager->unreference(nullptr); } -TEST_F(DrmMemoryManagerTest, givenDrmMemoryManagerCreatedWithGemCloseWorkerModeInactiveThenGemCloseWorkerIsNotCreated) { +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenDrmMemoryManagerCreatedWithGemCloseWorkerModeInactiveThenGemCloseWorkerIsNotCreated) { class MyTestedDrmMemoryManager : public DrmMemoryManager { public: - MyTestedDrmMemoryManager(Drm *drm, gemCloseWorkerMode mode) : DrmMemoryManager(drm, mode, false) {} + MyTestedDrmMemoryManager(Drm *drm, gemCloseWorkerMode mode) : DrmMemoryManager(drm, mode, false, false) {} DrmGemCloseWorker *getgemCloseWorker() { return this->gemCloseWorker.get(); } }; @@ -506,7 +534,6 @@ TEST_F(DrmMemoryManagerTest, getMaxApplicationAddress) { TEST_F(DrmMemoryManagerTest, getMinimumSystemSharedMemory) { auto hostMemorySize = MemoryConstants::pageSize * (uint64_t)(sysconf(_SC_PHYS_PAGES)); - // gpuMemSize < hostMemSize auto gpuMemorySize = hostMemorySize - 1u; mock->gpuMemSize = gpuMemorySize; @@ -554,6 +581,64 @@ TEST_F(DrmMemoryManagerTest, NullOsHandleStorageAskedForPopulationReturnsFilledP memoryManager->cleanOsHandles(storage); } +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenEnabledHostMemoryValidationWhenReadOnlyPointerCausesPinningFailWithEfaultThenPopulateOsHandlesReturnsInvalidHostPointerError) { + std::unique_ptr testedMemoryManager(new (std::nothrow) TestedDrmMemoryManager(this->mock, false, true)); + + OsHandleStorage storage; + storage.fragmentStorageData[0].cpuPtr = (void *)0x1000; + storage.fragmentStorageData[0].fragmentSize = 1; + + mock->reset(); + + DrmMockCustom::IoctlResExt ioctlResExt = {1, -1}; + mock->ioctl_res_ext = &ioctlResExt; + mock->errnoValue = EFAULT; + mock->ioctl_expected.gemUserptr = 1; + mock->ioctl_expected.execbuffer2 = 1; + + MemoryManager::AllocationStatus result = testedMemoryManager->populateOsHandles(storage); + + EXPECT_EQ(MemoryManager::AllocationStatus::InvalidHostPointer, result); + mock->testIoctls(); + + EXPECT_NE(nullptr, storage.fragmentStorageData[0].osHandleStorage); + EXPECT_EQ(nullptr, storage.fragmentStorageData[1].osHandleStorage); + EXPECT_EQ(nullptr, storage.fragmentStorageData[2].osHandleStorage); + + storage.fragmentStorageData[0].freeTheFragment = true; + testedMemoryManager->cleanOsHandles(storage); + mock->ioctl_res_ext = &mock->NONE; +} + +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenEnabledHostMemoryValidationWhenPinningFailWithErrorDifferentThanEfaultThenPopulateOsHandlesReturnsError) { + std::unique_ptr testedMemoryManager(new (std::nothrow) TestedDrmMemoryManager(this->mock, false, true)); + + OsHandleStorage storage; + storage.fragmentStorageData[0].cpuPtr = (void *)0x1000; + storage.fragmentStorageData[0].fragmentSize = 1; + + mock->reset(); + + DrmMockCustom::IoctlResExt ioctlResExt = {1, -1}; + mock->ioctl_res_ext = &ioctlResExt; + mock->errnoValue = ENOMEM; + mock->ioctl_expected.gemUserptr = 1; + mock->ioctl_expected.execbuffer2 = 1; + + MemoryManager::AllocationStatus result = testedMemoryManager->populateOsHandles(storage); + + EXPECT_EQ(MemoryManager::AllocationStatus::Error, result); + mock->testIoctls(); + + EXPECT_NE(nullptr, storage.fragmentStorageData[0].osHandleStorage); + EXPECT_EQ(nullptr, storage.fragmentStorageData[1].osHandleStorage); + EXPECT_EQ(nullptr, storage.fragmentStorageData[2].osHandleStorage); + + storage.fragmentStorageData[0].freeTheFragment = true; + testedMemoryManager->cleanOsHandles(storage); + mock->ioctl_res_ext = &mock->NONE; +} + TEST_F(DrmMemoryManagerTest, GivenNoInputsWhenOsHandleIsCreatedThenAllBoHandlesAreInitializedAsNullPtrs) { OsHandle boHandle; EXPECT_EQ(nullptr, boHandle.bo); @@ -563,7 +648,6 @@ TEST_F(DrmMemoryManagerTest, GivenNoInputsWhenOsHandleIsCreatedThenAllBoHandlesA } TEST_F(DrmMemoryManagerTest, GivenPointerAndSizeWhenAskedToCreateGrahicsAllocationThenGraphicsAllocationIsCreated) { - OsHandleStorage handleStorage; auto ptr = (void *)0x1000; auto ptr2 = (void *)0x1001; @@ -625,8 +709,7 @@ TEST_F(DrmMemoryManagerTest, GivenMisalignedHostPtrAndMultiplePagesSizeWhenAsked EXPECT_EQ(0u, hostPtrManager.getFragmentCount()); } -TEST_F(DrmMemoryManagerTest, testProfilingAllocatorCleanup) { - mock->ioctl_expected.total = -1; //don't care +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, testProfilingAllocatorCleanup) { MemoryManager *memMngr = memoryManager; TagAllocator *allocator = memMngr->getEventTsAllocator(); EXPECT_NE(nullptr, allocator); @@ -710,9 +793,9 @@ TEST_F(DrmMemoryManagerTest, Given32bitAllocatorWhenAskedForBufferAllocationThen if (is32BitOsAllocatorAvailable) { EXPECT_LT(address64bit - baseAddress, max32BitAddress); - } + } - delete buffer; + delete buffer; } TEST_F(DrmMemoryManagerTest, Given32bitAllocatorWhenAskedForBufferCreatedFromHostPtrThen32BitBufferIsReturned) { @@ -755,37 +838,37 @@ TEST_F(DrmMemoryManagerTest, Given32bitAllocatorWhenAskedForBufferCreatedFromHos if (is32BitOsAllocatorAvailable) { auto baseAddress = buffer->getGraphicsAllocation()->gpuBaseAddress; EXPECT_LT(address64bitOnGpu - baseAddress, max32BitAddress); - } + } - EXPECT_TRUE(drmAllocation->is32BitAllocation); + EXPECT_TRUE(drmAllocation->is32BitAllocation); - auto allocationCpuPtr = (uintptr_t)drmAllocation->getUnderlyingBuffer(); - auto allocationPageOffset = allocationCpuPtr - alignDown(allocationCpuPtr, MemoryConstants::pageSize); + auto allocationCpuPtr = (uintptr_t)drmAllocation->getUnderlyingBuffer(); + auto allocationPageOffset = allocationCpuPtr - alignDown(allocationCpuPtr, MemoryConstants::pageSize); - auto allocationGpuPtr = (uintptr_t)drmAllocation->getGpuAddress(); - auto allocationGpuOffset = allocationGpuPtr - alignDown(allocationGpuPtr, MemoryConstants::pageSize); + auto allocationGpuPtr = (uintptr_t)drmAllocation->getGpuAddress(); + auto allocationGpuOffset = allocationGpuPtr - alignDown(allocationGpuPtr, MemoryConstants::pageSize); - auto bufferObject = drmAllocation->getBO(); + auto bufferObject = drmAllocation->getBO(); - if (DebugManager.flags.UseNewHeapAllocator.get()) { - EXPECT_NE(0u, bufferObject->peekUnmapSize()); - } else { - EXPECT_EQ(0u, bufferObject->peekUnmapSize()); - } - EXPECT_EQ(drmAllocation->getUnderlyingBuffer(), (void *)offsetedPtr); + if (DebugManager.flags.UseNewHeapAllocator.get()) { + EXPECT_NE(0u, bufferObject->peekUnmapSize()); + } else { + EXPECT_EQ(0u, bufferObject->peekUnmapSize()); + } + EXPECT_EQ(drmAllocation->getUnderlyingBuffer(), (void *)offsetedPtr); - // Gpu address should be different - EXPECT_NE(offsetedPtr, drmAllocation->getGpuAddress()); - // Gpu address offset iqual to cpu offset - EXPECT_EQ(allocationGpuOffset, ptrOffset); + // Gpu address should be different + EXPECT_NE(offsetedPtr, drmAllocation->getGpuAddress()); + // Gpu address offset iqual to cpu offset + EXPECT_EQ(allocationGpuOffset, ptrOffset); - EXPECT_EQ(allocationPageOffset, ptrOffset); - EXPECT_FALSE(bufferObject->peekIsAllocated()); + EXPECT_EQ(allocationPageOffset, ptrOffset); + EXPECT_FALSE(bufferObject->peekIsAllocated()); - auto boAddress = bufferObject->peekAddress(); - EXPECT_EQ(alignDown(boAddress, MemoryConstants::pageSize), boAddress); + auto boAddress = bufferObject->peekAddress(); + EXPECT_EQ(alignDown(boAddress, MemoryConstants::pageSize), boAddress); - delete buffer; + delete buffer; } TEST_F(DrmMemoryManagerTest, Given32bitAllocatorWhenAskedForBufferCreatedFrom64BitHostPtrThen32BitBufferIsReturned) { @@ -868,6 +951,7 @@ TEST_F(DrmMemoryManagerTest, givenMemoryManagerWhenAskedFor32BitAllocationWithHo auto allocation = memoryManager->allocate32BitGraphicsMemory(size, host_ptr, MemoryType::EXTERNAL_ALLOCATION); EXPECT_EQ(nullptr, allocation); + mock->ioctl_res_ext = &mock->NONE; } TEST_F(DrmMemoryManagerTest, givenMemoryManagerWhenAskedFor32BitAllocationAndAllocUserptrFailsThenFails) { @@ -881,6 +965,7 @@ TEST_F(DrmMemoryManagerTest, givenMemoryManagerWhenAskedFor32BitAllocationAndAll auto allocation = memoryManager->allocate32BitGraphicsMemory(size, nullptr, MemoryType::EXTERNAL_ALLOCATION); EXPECT_EQ(nullptr, allocation); + mock->ioctl_res_ext = &mock->NONE; } TEST_F(DrmMemoryManagerTest, GivenSizeAbove2GBWhenUseHostPtrAndAllocHostPtrAreCreatedThenFirstSucceedsAndSecondFails) { @@ -925,9 +1010,9 @@ TEST_F(DrmMemoryManagerTest, GivenSizeAbove2GBWhenUseHostPtrAndAllocHostPtrAreCr EXPECT_TRUE(buffer->getGraphicsAllocation()->is32BitAllocation); auto baseAddress = buffer->getGraphicsAllocation()->gpuBaseAddress; EXPECT_LT((uintptr_t)(bufferPtr - baseAddress), max32BitAddress); - } + } - delete buffer; + delete buffer; } TEST_F(DrmMemoryManagerTest, GivenSizeAbove2GBWhenAllocHostPtrAndUseHostPtrAreCreatedThenFirstSucceedsAndSecondFails) { @@ -1540,7 +1625,7 @@ TEST_F(DrmMemoryManagerTest, givenNon32BitAddressingWhenBufferFromSharedHandleIs EXPECT_EQ(1, munmapMockCallCount); } -TEST_F(DrmMemoryManagerTest, givenDrmMemoryManagerWhenCreateAllocationFromNtHandleIsCalledThenReturnNullptr) { +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenDrmMemoryManagerWhenCreateAllocationFromNtHandleIsCalledThenReturnNullptr) { auto graphicsAllocation = memoryManager->createGraphicsAllocationFromNTHandle((void *)1); EXPECT_EQ(nullptr, graphicsAllocation); } @@ -1667,6 +1752,7 @@ TEST_F(DrmMemoryManagerTest, givenDrmMemoryManagerWhenLockUnlockIsCalledButFails EXPECT_EQ(nullptr, ptr); memoryManager->unlockResource(&drmAllocation); + mock->ioctl_res_ext = &mock->NONE; } TEST_F(DrmMemoryManagerTest, givenDrmMemoryManagerWhenSetDomainCpuIsCalledOnAllocationWithoutBufferObjectThenReturnFalse) { @@ -1692,6 +1778,7 @@ TEST_F(DrmMemoryManagerTest, givenDrmMemoryManagerWhenSetDomainCpuIsCalledButFai auto success = memoryManager->setDomainCpu(drmAllocation, false); EXPECT_FALSE(success); + mock->ioctl_res_ext = &mock->NONE; } TEST_F(DrmMemoryManagerTest, givenDrmMemoryManagerWhenSetDomainCpuIsCalledOnAllocationThenReturnSetWriteDomain) { @@ -1903,7 +1990,6 @@ TEST_F(DrmMemoryManagerTest, givenMemoryManagerSupportingVirutalPaddingWhenAlloc mock->ioctl_expected.gemUserptr = 3; mock->ioctl_expected.gemWait = 2; mock->ioctl_expected.gemClose = 2; - this->ioctlResExt = {2, -1}; mock->ioctl_res_ext = &ioctlResExt; @@ -1921,13 +2007,14 @@ TEST_F(DrmMemoryManagerTest, givenMemoryManagerSupportingVirutalPaddingWhenAlloc EXPECT_EQ(nullptr, paddedAllocation); memoryManager->freeGraphicsMemory(buffer); + mock->ioctl_res_ext = &mock->NONE; } -TEST_F(DrmMemoryManagerTest, givenDefaultDrmMemoryManagerWhenAskedForVirtualPaddingSupportThenTrueIsReturned) { +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenDefaultDrmMemoryManagerWhenAskedForVirtualPaddingSupportThenTrueIsReturned) { EXPECT_TRUE(memoryManager->peekVirtualPaddingSupport()); } -TEST_F(DrmMemoryManagerTest, givenDefaultDrmMemoryManagerWhenAskedForAlignedMallocRestrictionsThenNullPtrIsReturned) { +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenDefaultDrmMemoryManagerWhenAskedForAlignedMallocRestrictionsThenNullPtrIsReturned) { EXPECT_EQ(nullptr, memoryManager->getAlignedMallocRestrictions()); } @@ -2205,7 +2292,7 @@ TEST(MmapFlags, givenVariousMmapParametersGetTimeDeltaForTheOperation) { } TEST(DrmMemoryManager, givenDefaultMemoryManagerWhenItIsCreatedThenAsyncDeleterEnabledIsTrue) { - DrmMemoryManager memoryManager(Drm::get(0), gemCloseWorkerMode::gemCloseWorkerInactive, false); + DrmMemoryManager memoryManager(Drm::get(0), gemCloseWorkerMode::gemCloseWorkerInactive, false, true); EXPECT_FALSE(memoryManager.isAsyncDeleterEnabled()); EXPECT_EQ(nullptr, memoryManager.getDeferredDeleter()); } @@ -2213,7 +2300,7 @@ TEST(DrmMemoryManager, givenDefaultMemoryManagerWhenItIsCreatedThenAsyncDeleterE TEST(DrmMemoryManager, givenEnabledAsyncDeleterFlagWhenMemoryManagerIsCreatedThenAsyncDeleterEnabledIsFalseAndDeleterIsNullptr) { DebugManagerStateRestore dbgStateRestore; DebugManager.flags.EnableDeferredDeleter.set(true); - DrmMemoryManager memoryManager(Drm::get(0), gemCloseWorkerMode::gemCloseWorkerInactive, false); + DrmMemoryManager memoryManager(Drm::get(0), gemCloseWorkerMode::gemCloseWorkerInactive, false, true); EXPECT_FALSE(memoryManager.isAsyncDeleterEnabled()); EXPECT_EQ(nullptr, memoryManager.getDeferredDeleter()); } @@ -2221,14 +2308,193 @@ TEST(DrmMemoryManager, givenEnabledAsyncDeleterFlagWhenMemoryManagerIsCreatedThe TEST(DrmMemoryManager, givenDisabledAsyncDeleterFlagWhenMemoryManagerIsCreatedThenAsyncDeleterEnabledIsFalseAndDeleterIsNullptr) { DebugManagerStateRestore dbgStateRestore; DebugManager.flags.EnableDeferredDeleter.set(false); - DrmMemoryManager memoryManager(Drm::get(0), gemCloseWorkerMode::gemCloseWorkerInactive, false); + DrmMemoryManager memoryManager(Drm::get(0), gemCloseWorkerMode::gemCloseWorkerInactive, false, true); EXPECT_FALSE(memoryManager.isAsyncDeleterEnabled()); EXPECT_EQ(nullptr, memoryManager.getDeferredDeleter()); } TEST(DrmMemoryManager, givenDefaultDrmMemoryManagerWhenItIsQueriedForInternalHeapBaseThenInternalHeapBaseIsReturned) { - std::unique_ptr memoryManager(new (std::nothrow) TestedDrmMemoryManager(Drm::get(0), true)); + std::unique_ptr memoryManager(new (std::nothrow) TestedDrmMemoryManager(Drm::get(0), true, true)); auto internalAllocator = memoryManager->getDrmInternal32BitAllocator(); auto heapBase = internalAllocator->getBase(); EXPECT_EQ(heapBase, memoryManager->getInternalHeapBaseAddress()); } + +TEST(DrmMemoryManager, givenEnabledGemCloseWorkerWhenWaitForDeletionsIsCalledThenGemCloseWorkerIsEmpty) { + TestedDrmMemoryManager memoryManager(Drm::get(0)); + auto gemCloseWorker = memoryManager.getgemCloseWorker(); + + EXPECT_TRUE(gemCloseWorker->isEmpty()); + auto allocation = memoryManager.allocateGraphicsMemory(1024, 4096, false, false); + + memoryManager.push(allocation); + memoryManager.waitForDeletions(); + + EXPECT_TRUE(gemCloseWorker->isEmpty()); +} + +TEST(DrmMemoryManager, givenMemoryManagerWithEnabledHostMemoryValidationWhenFeatureIsQueriedThenTrueIsReturned) { + std::unique_ptr memoryManager(new (std::nothrow) TestedDrmMemoryManager(Drm::get(0), false, true)); + ASSERT_NE(nullptr, memoryManager.get()); + EXPECT_TRUE(memoryManager->isValidateHostMemoryEnabled()); +} + +TEST(DrmMemoryManager, givenMemoryManagerWithDisabledHostMemoryValidationWhenFeatureIsQueriedThenFalseIsReturned) { + std::unique_ptr memoryManager(new (std::nothrow) TestedDrmMemoryManager(Drm::get(0), false, false)); + ASSERT_NE(nullptr, memoryManager.get()); + EXPECT_FALSE(memoryManager->isValidateHostMemoryEnabled()); +} + +TEST(DrmMemoryManager, givenEnabledHostMemoryValidationWhenMemoryManagerIsCreatedThenPinBBIsCreated) { + std::unique_ptr memoryManager(new (std::nothrow) TestedDrmMemoryManager(Drm::get(0), false, true)); + ASSERT_NE(nullptr, memoryManager.get()); + ASSERT_NE(nullptr, memoryManager->getPinBB()); +} + +TEST(DrmMemoryManager, givenEnabledHostMemoryValidationAndForcePinWhenMemoryManagerIsCreatedThenPinBBIsCreated) { + std::unique_ptr memoryManager(new (std::nothrow) TestedDrmMemoryManager(Drm::get(0), true, true)); + ASSERT_NE(nullptr, memoryManager.get()); + ASSERT_NE(nullptr, memoryManager->getPinBB()); +} + +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenDisabledForcePinAndEnabledValidateHostMemoryWhenPinBBAllocationFailsThenUnrecoverableIsCalled) { + this->mock->ioctl_res = -1; + this->mock->ioctl_expected.gemUserptr = 1; + EXPECT_THROW( + { + std::unique_ptr testedMemoryManager(new TestedDrmMemoryManager(this->mock, false, true)); + EXPECT_NE(nullptr, testedMemoryManager.get()); + }, + std::exception); + this->mock->ioctl_res = 0; + this->mock->testIoctls(); +} + +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenDisabledForcePinAndEnabledValidateHostMemoryWhenPopulateOsHandlesIsCalledThenHostMemoryIsValidated) { + + std::unique_ptr testedMemoryManager(new TestedDrmMemoryManager(this->mock, false, true)); + ASSERT_NE(nullptr, testedMemoryManager.get()); + ASSERT_NE(nullptr, testedMemoryManager->getPinBB()); + + mock->reset(); + mock->ioctl_expected.gemUserptr = 1; + mock->ioctl_expected.execbuffer2 = 1; // for pinning - host memory validation + + OsHandleStorage handleStorage; + handleStorage.fragmentStorageData[0].cpuPtr = (void *)0x1000; + handleStorage.fragmentStorageData[0].fragmentSize = 4096; + auto result = testedMemoryManager->populateOsHandles(handleStorage); + EXPECT_EQ(MemoryManager::AllocationStatus::Success, result); + + mock->testIoctls(); + + EXPECT_NE(nullptr, handleStorage.fragmentStorageData[0].osHandleStorage); + handleStorage.fragmentStorageData[0].freeTheFragment = true; + + testedMemoryManager->cleanOsHandles(handleStorage); +} + +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenValidateHostPtrMemoryEnabledWhenHostPtrAllocationIsCreatedWithoutForcingPinThenBufferObjectIsPinned) { + mock->ioctl_expected.gemUserptr = 2; + mock->ioctl_expected.gemWait = 1; + mock->ioctl_expected.gemClose = 2; + + std::unique_ptr mm(new (std::nothrow) TestedDrmMemoryManager(this->mock, true, true)); + ASSERT_NE(nullptr, mm->getPinBB()); + + size_t size = 10 * 1024 * 1024; + void *ptr = ::alignedMalloc(size, 4096); + auto alloc = mm->allocateGraphicsMemory(size, ptr, false); + ASSERT_NE(nullptr, alloc); + EXPECT_NE(nullptr, alloc->getBO()); + + mm->freeGraphicsMemory(alloc); + ::alignedFree(ptr); +} + +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenEnabledHostMemoryValidationWhenValidHostPointerIsPassedToPopulateThenSuccessIsReturned) { + std::unique_ptr testedMemoryManager(new (std::nothrow) TestedDrmMemoryManager(this->mock, false, true)); + + OsHandleStorage storage; + storage.fragmentStorageData[0].cpuPtr = (void *)0x1000; + storage.fragmentStorageData[0].fragmentSize = 1; + auto result = testedMemoryManager->populateOsHandles(storage); + EXPECT_EQ(MemoryManager::AllocationStatus::Success, result); + + EXPECT_NE(nullptr, storage.fragmentStorageData[0].osHandleStorage); + storage.fragmentStorageData[0].freeTheFragment = true; + testedMemoryManager->cleanOsHandles(storage); +} + +TEST_F(DrmMemoryManagerTest, givenForcePinAndHostMemoryValidationEnabledWhenSmallAllocationIsCreatedThenBufferObjectIsPinned) { + mock->ioctl_expected.gemUserptr = 2; // 1 pinBB, 1 small allocation + mock->ioctl_expected.execbuffer2 = 1; // pinning + mock->ioctl_expected.gemWait = 1; // in freeGraphicsAllocation + mock->ioctl_expected.gemClose = 2; // 1 pinBB, 1 small allocation + + std::unique_ptr mm(new (std::nothrow) TestedDrmMemoryManager(this->mock, true, true)); + ASSERT_NE(nullptr, mm->getPinBB()); + + // one page is too small for early pinning but pinning is used for host memory validation + size_t size = 4 * 1024; + void *ptr = ::alignedMalloc(size, 4096); + auto alloc = mm->allocateGraphicsMemory(size, ptr, false); + ASSERT_NE(nullptr, alloc); + EXPECT_NE(nullptr, alloc->getBO()); + + mm->freeGraphicsMemory(alloc); + ::alignedFree(ptr); +} + +TEST_F(DrmMemoryManagerTest, givenForcePinAllowedAndNoPinBBInMemoryManagerWhenAllocationWithForcePinFlagTrueIsCreatedThenAllocationIsNotPinned) { + mock->ioctl_expected.gemUserptr = 2; + mock->ioctl_expected.gemWait = 1; + mock->ioctl_expected.gemClose = 1; + mock->ioctl_res = -1; + std::unique_ptr mm(new (std::nothrow) TestedDrmMemoryManager(this->mock, true, false)); + EXPECT_EQ(nullptr, mm->getPinBB()); + mock->ioctl_res = 0; + + auto allocation = mm->allocateGraphicsMemory(4096, 4096, true, false); + EXPECT_NE(nullptr, allocation); + mm->freeGraphicsMemory(allocation); +} + +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenForcePinNotAllowedAndHostMemoryValidationEnabledWhenAllocationIsCreatedThenBufferObjectIsPinnedOnlyOnce) { + std::unique_ptr mm(new TestedDrmMemoryManager(this->mock, false, true)); + mock->reset(); + mock->ioctl_expected.gemUserptr = 1; + mock->ioctl_expected.execbuffer2 = 1; + mock->ioctl_expected.gemClose = 1; + mock->ioctl_expected.gemWait = 1; + + size_t size = 1024; + void *ptr = ::alignedMalloc(size, 4096); + auto alloc = mm->allocateGraphicsMemory(size, ptr, true); + ASSERT_NE(nullptr, alloc); + EXPECT_NE(nullptr, alloc->getBO()); + + mm->freeGraphicsMemory(alloc); + mock->testIoctls(); + + ::alignedFree(ptr); +} + +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenForcePinNotAllowedAndHostMemoryValidationDisabledWhenAllocationIsCreatedThenBufferObjectIsNotPinned) { + std::unique_ptr mm(new TestedDrmMemoryManager(this->mock, false, false)); + mock->reset(); + mock->ioctl_expected.gemUserptr = 1; + mock->ioctl_expected.gemClose = 1; + mock->ioctl_expected.gemWait = 1; + + size_t size = 10 * 1024 * 1024; // bigger than threshold + void *ptr = ::alignedMalloc(size, 4096); + auto alloc = mm->allocateGraphicsMemory(size, ptr, true); + ASSERT_NE(nullptr, alloc); + EXPECT_NE(nullptr, alloc->getBO()); + + mm->freeGraphicsMemory(alloc); + mock->testIoctls(); + + ::alignedFree(ptr); +} diff --git a/unit_tests/os_interface/linux/drm_tests.cpp b/unit_tests/os_interface/linux/drm_tests.cpp index 486a73ffc8..e23e36184f 100644 --- a/unit_tests/os_interface/linux/drm_tests.cpp +++ b/unit_tests/os_interface/linux/drm_tests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Intel Corporation + * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -309,4 +309,13 @@ TEST(DrmTest, getMinEuInPool) { EXPECT_EQ(0, minEUinPool); #endif delete pDrm; -} \ No newline at end of file +} + +TEST(DrmTest, givenDrmWhenGetErrnoIsCalledThenErrnoValueIsReturned) { + Drm2 *pDrm = new Drm2; + EXPECT_NE(nullptr, pDrm); + + auto errnoFromDrm = pDrm->getErrno(); + EXPECT_EQ(errno, errnoFromDrm); + delete pDrm; +}