diff --git a/shared/source/debug_settings/debug_variables_base.inl b/shared/source/debug_settings/debug_variables_base.inl index 89ac1e37dc..d657109737 100644 --- a/shared/source/debug_settings/debug_variables_base.inl +++ b/shared/source/debug_settings/debug_variables_base.inl @@ -502,6 +502,10 @@ DECLARE_DEBUG_VARIABLE(bool, ForceLargeGrfCompilationMode, false, "Adds build op DECLARE_DEBUG_VARIABLE(bool, EnableConcurrentSharedCrossP2PDeviceAccess, false, "Enables the concurrent use between host and peer devices of shared-allocations ") DECLARE_DEBUG_VARIABLE(bool, AllocateSharedAllocationsInHeapExtendedHost, false, "When enabled driver can allocate shared unified memory allocation in heap extended host. (0 - disable, 1 - enable)") DECLARE_DEBUG_VARIABLE(bool, AllocateHostAllocationsInHeapExtendedHost, true, "When enabled driver can allocate host unified memory allocation in heap extended host. (0 - disable, 1 - enable)") +DECLARE_DEBUG_VARIABLE(bool, PrintBOChunkingLogs, false, "Print some logs on BO chunking") +DECLARE_DEBUG_VARIABLE(bool, EnableBOChunking, false, "Enables use of chunking of BOs in the KMD.") +DECLARE_DEBUG_VARIABLE(bool, EnableBOChunkingPreferredLocationHint, false, "Enables preferred location advise on chunks") +DECLARE_DEBUG_VARIABLE(int32_t, NumberOfBOChunks, 2, "Number of chunks to use. Must be a power of two)") DECLARE_DEBUG_VARIABLE(int32_t, ForceAutoGrfCompilationMode, -1, "Adds build option -*-intel-enable-auto-large-GRF-mode to force kernel compilation") DECLARE_DEBUG_VARIABLE(int32_t, ForceOCLVersion, 0, "Force specific OpenCL API version") DECLARE_DEBUG_VARIABLE(int32_t, ForceOCL21FeaturesSupport, -1, "-1: default, 0: disable, 1:enable. Force support of OpenCL 2.0 and OpenCL 2.1 API features") diff --git a/shared/source/dll/linux/drm_neo_create.cpp b/shared/source/dll/linux/drm_neo_create.cpp index 7c0af612a3..21fef0df73 100644 --- a/shared/source/dll/linux/drm_neo_create.cpp +++ b/shared/source/dll/linux/drm_neo_create.cpp @@ -116,6 +116,7 @@ Drm *Drm::create(std::unique_ptr &&hwDeviceId, RootDeviceEnvironm } drm->isSetPairAvailable(); + drm->isChunkingAvailable(); if (!drm->isPerContextVMRequired()) { if (!drm->createVirtualMemoryAddressSpace(GfxCoreHelper::getSubDevicesCount(rootDeviceEnvironment.getHardwareInfo()))) { diff --git a/shared/source/helpers/constants.h b/shared/source/helpers/constants.h index 0cfc5d2d54..1adcba82f3 100644 --- a/shared/source/helpers/constants.h +++ b/shared/source/helpers/constants.h @@ -54,6 +54,7 @@ inline constexpr uintptr_t page4kEntryMask = std::numeric_limits::max inline constexpr uintptr_t page64kEntryMask = std::numeric_limits::max() & ~MemoryConstants::page64kMask; inline constexpr int GfxAddressBits = is64bit ? 48 : 32; inline constexpr uint64_t maxSvmAddress = is64bit ? maxNBitValue(47) : maxNBitValue(32); +inline constexpr size_t chunkThreshold = MemoryConstants::pageSize64k; } // namespace MemoryConstants diff --git a/shared/source/memory_manager/definitions/storage_info.h b/shared/source/memory_manager/definitions/storage_info.h index d1d2fcc531..51fda1083c 100644 --- a/shared/source/memory_manager/definitions/storage_info.h +++ b/shared/source/memory_manager/definitions/storage_info.h @@ -33,5 +33,7 @@ struct StorageInfo { char resourceTag[AppResourceDefines::maxStrLen + 1] = ""; uint32_t getMemoryBanks() const { return static_cast(memoryBanks.to_ulong()); } uint32_t getTotalBanksCnt() const; + bool isChunked = false; + uint32_t numOfChunks = 0; }; } // namespace NEO diff --git a/shared/source/os_interface/linux/drm_allocation.cpp b/shared/source/os_interface/linux/drm_allocation.cpp index 36f4904f52..08073f557b 100644 --- a/shared/source/os_interface/linux/drm_allocation.cpp +++ b/shared/source/os_interface/linux/drm_allocation.cpp @@ -10,12 +10,15 @@ #include "shared/source/debug_settings/debug_settings_manager.h" #include "shared/source/execution_environment/root_device_environment.h" #include "shared/source/helpers/basic_math.h" +#include "shared/source/helpers/hw_info.h" #include "shared/source/memory_manager/residency.h" #include "shared/source/os_interface/linux/cache_info.h" #include "shared/source/os_interface/linux/drm_buffer_object.h" #include "shared/source/os_interface/linux/drm_memory_manager.h" #include "shared/source/os_interface/linux/drm_neo.h" +#include "shared/source/os_interface/linux/i915_prelim.h" #include "shared/source/os_interface/linux/ioctl_helper.h" +#include "shared/source/os_interface/linux/memory_info.h" #include "shared/source/os_interface/linux/os_context_linux.h" #include "shared/source/os_interface/os_context.h" #include "shared/source/os_interface/product_helper.h" @@ -82,6 +85,44 @@ bool DrmAllocation::setPreferredLocation(Drm *drm, PreferredLocation memoryLocat auto ioctlHelper = drm->getIoctlHelper(); auto remainingMemoryBanks = storageInfo.memoryBanks; bool success = true; + auto pHwInfo = drm->getRootDeviceEnvironment().getHardwareInfo(); + + if (this->storageInfo.isChunked && DebugManager.flags.EnableBOChunkingPreferredLocationHint.get() == 1) { + prelim_drm_i915_gem_memory_class_instance region{}; + region.memory_class = NEO::PrelimI915::PRELIM_I915_MEMORY_CLASS_DEVICE; + auto banks = std::bitset<4>(remainingMemoryBanks); + MemRegionsVec memRegions{}; + size_t currentBank = 0; + size_t i = 0; + while (i < banks.count()) { + if (banks.test(currentBank)) { + auto regionClassAndInstance = drm->getMemoryInfo()->getMemoryRegionClassAndInstance(1u << currentBank, *pHwInfo); + memRegions.push_back(regionClassAndInstance); + i++; + } + currentBank++; + } + + for (uint32_t i = 0; i < this->storageInfo.numOfChunks; i++) { + // Depth-first + region.memory_instance = memRegions[i / (this->storageInfo.numOfChunks / memRegions.size())].memoryInstance; + uint64_t chunkLength = (bufferObjects[0]->peekSize() / this->storageInfo.numOfChunks); + uint64_t chunkStart = i * chunkLength; + printDebugString(DebugManager.flags.PrintBOChunkingLogs.get(), stdout, + "Setting PRELIM_DRM_I915_GEM_VM_ADVISE for BO-%d chunk 0x%lx chunkLength %ld memory_class %d, memory_region %d\n", + bufferObjects[0]->peekHandle(), + chunkStart, + chunkLength, + region.memory_class, + region.memory_instance); + success &= ioctlHelper->setVmBoAdviseForChunking(bufferObjects[0]->peekHandle(), + chunkStart, + chunkLength, + ioctlHelper->getPreferredLocationAdvise(), + ®ion); + } + return success; + } for (uint8_t handleId = 0u; handleId < numHandles; handleId++) { auto memoryInstance = Math::getMinLsbSet(static_cast(remainingMemoryBanks.to_ulong())); diff --git a/shared/source/os_interface/linux/drm_buffer_object.h b/shared/source/os_interface/linux/drm_buffer_object.h index 8ebec5d25a..17ac7ebfb5 100644 --- a/shared/source/os_interface/linux/drm_buffer_object.h +++ b/shared/source/os_interface/linux/drm_buffer_object.h @@ -211,6 +211,8 @@ class BufferObject { uint32_t getOsContextId(OsContext *osContext); std::vector> bindInfo; + bool isChunked = false; + protected: MOCKABLE_VIRTUAL MemoryOperationsStatus evictUnusedAllocations(bool waitForCompletion, bool isLockNeeded); diff --git a/shared/source/os_interface/linux/drm_memory_manager.cpp b/shared/source/os_interface/linux/drm_memory_manager.cpp index e3a48737db..bfc6592222 100644 --- a/shared/source/os_interface/linux/drm_memory_manager.cpp +++ b/shared/source/os_interface/linux/drm_memory_manager.cpp @@ -38,6 +38,7 @@ #include "shared/source/os_interface/linux/drm_memory_operations_handler.h" #include "shared/source/os_interface/linux/drm_neo.h" #include "shared/source/os_interface/linux/drm_wrappers.h" +#include "shared/source/os_interface/linux/i915_prelim.h" #include "shared/source/os_interface/linux/memory_info.h" #include "shared/source/os_interface/linux/os_context_linux.h" #include "shared/source/os_interface/os_interface.h" @@ -1826,6 +1827,34 @@ BufferObject *DrmMemoryManager::createBufferObjectInMemoryRegion(uint32_t rootDe return bo; } +bool DrmMemoryManager::createDrmChunkedAllocation(Drm *drm, DrmAllocation *allocation, uint64_t boAddress, size_t boSize, size_t maxOsContextCount) { + auto &storageInfo = allocation->storageInfo; + auto memoryInfo = drm->getMemoryInfo(); + uint32_t handle = 0; + auto memoryBanks = static_cast(storageInfo.memoryBanks.to_ulong()); + uint32_t numOfChunks = DebugManager.flags.NumberOfBOChunks.get(); + int ret = memoryInfo->createGemExtWithMultipleRegions(memoryBanks, boSize, handle, -1, true, numOfChunks); + if (ret != 0) { + return false; + } + + auto gmm = allocation->getGmm(0u); + auto patIndex = drm->getPatIndex(gmm, allocation->getAllocationType(), CacheRegion::Default, CachePolicy::WriteBack, false); + + auto bo = new (std::nothrow) BufferObject(allocation->getRootDeviceIndex(), drm, patIndex, handle, boSize, maxOsContextCount); + UNRECOVERABLE_IF(bo == nullptr); + bo->setAddress(boAddress); + + allocation->getBufferObjectToModify(0) = bo; + + bo->isChunked = 1; + + storageInfo.isChunked = true; + storageInfo.numOfChunks = numOfChunks; + + return true; +} + bool DrmMemoryManager::createDrmAllocation(Drm *drm, DrmAllocation *allocation, uint64_t gpuAddress, size_t maxOsContextCount) { BufferObjects bos{}; auto &storageInfo = allocation->storageInfo; @@ -1836,7 +1865,25 @@ bool DrmMemoryManager::createDrmAllocation(Drm *drm, DrmAllocation *allocation, auto useKmdMigrationForBuffers = (AllocationType::BUFFER == allocation->getAllocationType() && (DebugManager.flags.UseKmdMigrationForBuffers.get() > 0)); auto handles = storageInfo.getNumBanks(); - if (storageInfo.colouringPolicy == ColouringPolicy::ChunkSizeBased) { + bool useChunking = false; + size_t boTotalChunkSize = 0; + + if (AllocationType::BUFFER == allocation->getAllocationType() && + drm->getChunkingAvailable()) { + boTotalChunkSize = allocation->getUnderlyingBufferSize(); + + uint32_t numOfChunks = DebugManager.flags.NumberOfBOChunks.get(); + size_t chunkingSize = boTotalChunkSize / numOfChunks; + + // Dont chunk for sizes less than chunkThreshold + if (!(chunkingSize & (MemoryConstants::chunkThreshold - 1))) { + + handles = 1; + allocation->resizeBufferObjects(handles); + bos.resize(handles); + useChunking = true; + } + } else if (storageInfo.colouringPolicy == ColouringPolicy::ChunkSizeBased) { handles = allocation->getNumGmms(); allocation->resizeBufferObjects(handles); bos.resize(handles); @@ -1845,6 +1892,10 @@ bool DrmMemoryManager::createDrmAllocation(Drm *drm, DrmAllocation *allocation, int32_t pairHandle = -1; + if (useChunking) { + return createDrmChunkedAllocation(drm, allocation, gpuAddress, boTotalChunkSize, maxOsContextCount); + } + for (auto handleId = 0u; handleId < handles; handleId++, currentBank++) { if (currentBank == banksCnt) { currentBank = 0; @@ -2163,6 +2214,16 @@ GraphicsAllocation *DrmMemoryManager::createSharedUnifiedMemoryAllocation(const auto remainingMemoryBanks = allocationData.storageInfo.memoryBanks; auto numHandles = GraphicsAllocation::getNumHandlesForKmdSharedAllocation(allocationData.storageInfo.getNumBanks()); + bool useChunking = false; + uint32_t numOfChunks = DebugManager.flags.NumberOfBOChunks.get(); + size_t chunkingSize = size / numOfChunks; + + // Dont chunk for sizes less than chunkThreshold + if (drm.getChunkingAvailable() && !(chunkingSize & (MemoryConstants::chunkThreshold - 1))) { + numHandles = 1; + useChunking = true; + } + for (auto handleId = 0u; handleId < numHandles; handleId++) { uint32_t handle = 0; @@ -2172,10 +2233,10 @@ GraphicsAllocation *DrmMemoryManager::createSharedUnifiedMemoryAllocation(const } auto memoryInstance = Math::getMinLsbSet(static_cast(remainingMemoryBanks.to_ulong())); - auto memoryBanks = DebugManager.flags.KMDSupportForCrossTileMigrationPolicy.get() > 0 ? allocationData.storageInfo.memoryBanks : DeviceBitfield(1 << memoryInstance); + auto memoryBanks = (DebugManager.flags.KMDSupportForCrossTileMigrationPolicy.get() > 0 || useChunking) ? allocationData.storageInfo.memoryBanks : DeviceBitfield(1 << memoryInstance); auto memRegions = createMemoryRegionsForSharedAllocation(*pHwInfo, *memoryInfo, allocationData, memoryBanks); - auto ret = memoryInfo->createGemExt(memRegions, currentSize, handle, {}, -1); + int ret = memoryInfo->createGemExt(memRegions, currentSize, handle, {}, -1, useChunking, numOfChunks); if (ret) { this->munmapFunction(cpuPointer, totalSizeToAlloc); @@ -2205,6 +2266,8 @@ GraphicsAllocation *DrmMemoryManager::createSharedUnifiedMemoryAllocation(const bo->setAddress(castToUint64(currentAddress)); + bo->isChunked = useChunking; + bos.push_back(bo.release()); currentAddress = reinterpret_cast(castToUint64(currentAddress) + currentSize); @@ -2220,6 +2283,8 @@ GraphicsAllocation *DrmMemoryManager::createSharedUnifiedMemoryAllocation(const allocation->setReservedAddressRange(reinterpret_cast(preferredAddress), totalSizeToAlloc); allocation->setNumHandles(static_cast(bos.size())); allocation->storageInfo = allocationData.storageInfo; + allocation->storageInfo.isChunked = useChunking; + allocation->storageInfo.numOfChunks = numOfChunks; if (!allocation->setCacheRegion(&drm, static_cast(allocationData.cacheRegion))) { this->munmapFunction(cpuBasePointer, totalSizeToAlloc); for (auto bo : bos) { diff --git a/shared/source/os_interface/linux/drm_memory_manager.h b/shared/source/os_interface/linux/drm_memory_manager.h index ced5055799..d957b38b39 100644 --- a/shared/source/os_interface/linux/drm_memory_manager.h +++ b/shared/source/os_interface/linux/drm_memory_manager.h @@ -137,6 +137,7 @@ class DrmMemoryManager : public MemoryManager { GraphicsAllocation *allocate32BitGraphicsMemoryImpl(const AllocationData &allocationData, bool useLocalMemory) override; void cleanupBeforeReturn(const AllocationData &allocationData, GfxPartition *gfxPartition, DrmAllocation *drmAllocation, GraphicsAllocation *graphicsAllocation, uint64_t &gpuAddress, size_t &sizeAllocated); GraphicsAllocation *allocateGraphicsMemoryInDevicePool(const AllocationData &allocationData, AllocationStatus &status) override; + bool createDrmChunkedAllocation(Drm *drm, DrmAllocation *allocation, uint64_t boAddress, size_t boSize, size_t maxOsContextCount); bool createDrmAllocation(Drm *drm, DrmAllocation *allocation, uint64_t gpuAddress, size_t maxOsContextCount); void registerAllocationInOs(GraphicsAllocation *allocation) override; void waitOnCompletionFence(GraphicsAllocation *allocation); diff --git a/shared/source/os_interface/linux/drm_memory_operations_handler_bind.cpp b/shared/source/os_interface/linux/drm_memory_operations_handler_bind.cpp index f8c52d64ec..562c5a50d5 100644 --- a/shared/source/os_interface/linux/drm_memory_operations_handler_bind.cpp +++ b/shared/source/os_interface/linux/drm_memory_operations_handler_bind.cpp @@ -54,6 +54,10 @@ MemoryOperationsStatus DrmMemoryOperationsHandlerBind::makeResidentWithinOsConte auto drmAllocation = static_cast(*gfxAllocation); auto bo = drmAllocation->storageInfo.getNumBanks() > 1 ? drmAllocation->getBOs()[drmIterator] : drmAllocation->getBO(); + if (drmAllocation->storageInfo.isChunked) { + bo = drmAllocation->getBO(); + } + if (!bo->bindInfo[bo->getOsContextId(osContext)][drmIterator]) { int result = drmAllocation->makeBOsResident(osContext, drmIterator, nullptr, true); if (result) { diff --git a/shared/source/os_interface/linux/drm_neo.cpp b/shared/source/os_interface/linux/drm_neo.cpp index 4724f219fb..7894b015d7 100644 --- a/shared/source/os_interface/linux/drm_neo.cpp +++ b/shared/source/os_interface/linux/drm_neo.cpp @@ -1270,6 +1270,20 @@ bool Drm::isSetPairAvailable() { return setPairAvailable; } +bool Drm::isChunkingAvailable() { + if (DebugManager.flags.EnableBOChunking.get()) { + std::call_once(checkChunkingOnce, [this]() { + int ret = ioctlHelper->isChunkingAvailable(); + if (ret) { + chunkingAvailable = true; + } + printDebugString(DebugManager.flags.PrintBOChunkingLogs.get(), stdout, + "Chunking available: %d\n", chunkingAvailable); + }); + } + return chunkingAvailable; +} + bool Drm::isVmBindAvailable() { std::call_once(checkBindOnce, [this]() { int ret = ioctlHelper->isVmBindAvailable(); @@ -1350,7 +1364,7 @@ int changeBufferObjectBinding(Drm *drm, OsContext *osContext, uint32_t vmHandleI bool bindImmediate = bo->isImmediateBindingRequired(); bool bindMakeResident = false; if (drm->useVMBindImmediate()) { - bindMakeResident = bo->isExplicitResidencyRequired(); + bindMakeResident = bo->isExplicitResidencyRequired() && !bo->isChunked; bindImmediate = true; } flags |= ioctlHelper->getFlagsForVmBind(bindCapture, bindImmediate, bindMakeResident); diff --git a/shared/source/os_interface/linux/drm_neo.h b/shared/source/os_interface/linux/drm_neo.h index 8a3d58d060..a97b794f45 100644 --- a/shared/source/os_interface/linux/drm_neo.h +++ b/shared/source/os_interface/linux/drm_neo.h @@ -161,6 +161,8 @@ class Drm : public DriverModel { MOCKABLE_VIRTUAL bool isSetPairAvailable(); MOCKABLE_VIRTUAL bool getSetPairAvailable() { return setPairAvailable; } + MOCKABLE_VIRTUAL bool isChunkingAvailable(); + MOCKABLE_VIRTUAL bool getChunkingAvailable() { return chunkingAvailable; } MOCKABLE_VIRTUAL bool useVMBindImmediate() const; @@ -334,6 +336,7 @@ class Drm : public DriverModel { std::once_flag checkBindOnce; std::once_flag checkSetPairOnce; + std::once_flag checkChunkingOnce; std::once_flag checkCompletionFenceOnce; RootDeviceEnvironment &rootDeviceEnvironment; @@ -346,6 +349,7 @@ class Drm : public DriverModel { bool bindAvailable = false; bool directSubmissionActive = false; bool setPairAvailable = false; + bool chunkingAvailable = false; bool contextDebugSupported = false; bool pageFaultSupported = false; bool completionFenceSupported = false; diff --git a/shared/source/os_interface/linux/ioctl_helper.h b/shared/source/os_interface/linux/ioctl_helper.h index 115cdfd581..14defdda2e 100644 --- a/shared/source/os_interface/linux/ioctl_helper.h +++ b/shared/source/os_interface/linux/ioctl_helper.h @@ -75,8 +75,9 @@ class IoctlHelper { virtual bool initialize() = 0; virtual bool isSetPairAvailable() = 0; + virtual bool isChunkingAvailable() = 0; virtual bool isVmBindAvailable() = 0; - virtual int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) = 0; + virtual int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) = 0; virtual CacheRegion closAlloc() = 0; virtual uint16_t closAllocWays(CacheRegion closIndex, uint16_t cacheLevel, uint16_t numWays) = 0; virtual CacheRegion closFree(CacheRegion closIndex) = 0; @@ -86,6 +87,7 @@ class IoctlHelper { virtual uint32_t getPreferredLocationAdvise() = 0; virtual std::optional getPreferredLocationRegion(PreferredLocation memoryLocation, uint32_t memoryInstance) = 0; virtual bool setVmBoAdvise(int32_t handle, uint32_t attribute, void *region) = 0; + virtual bool setVmBoAdviseForChunking(int32_t handle, uint64_t start, uint64_t length, uint32_t attribute, void *region) = 0; virtual bool setVmPrefetch(uint64_t start, uint64_t length, uint32_t region, uint32_t vmId) = 0; virtual uint32_t getDirectSubmissionFlag() = 0; virtual std::unique_ptr prepareVmBindExt(const StackVec &bindExtHandles) = 0; @@ -159,8 +161,9 @@ class IoctlHelperUpstream : public IoctlHelper { bool initialize() override; bool isSetPairAvailable() override; + bool isChunkingAvailable() override; bool isVmBindAvailable() override; - int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) override; + int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) override; CacheRegion closAlloc() override; uint16_t closAllocWays(CacheRegion closIndex, uint16_t cacheLevel, uint16_t numWays) override; CacheRegion closFree(CacheRegion closIndex) override; @@ -170,6 +173,7 @@ class IoctlHelperUpstream : public IoctlHelper { uint32_t getPreferredLocationAdvise() override; std::optional getPreferredLocationRegion(PreferredLocation memoryLocation, uint32_t memoryInstance) override; bool setVmBoAdvise(int32_t handle, uint32_t attribute, void *region) override; + bool setVmBoAdviseForChunking(int32_t handle, uint64_t start, uint64_t length, uint32_t attribute, void *region) override; bool setVmPrefetch(uint64_t start, uint64_t length, uint32_t region, uint32_t vmId) override; uint32_t getDirectSubmissionFlag() override; std::unique_ptr prepareVmBindExt(const StackVec &bindExtHandles) override; @@ -215,7 +219,7 @@ class IoctlHelperImpl : public IoctlHelperUpstream { return std::make_unique>(drm); } - int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) override; + int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) override; std::vector translateToMemoryRegions(const std::vector ®ionInfo) override; unsigned int getIoctlRequestValue(DrmIoctl ioctlRequest) const override; std::string getIoctlString(DrmIoctl ioctlRequest) const override; @@ -227,8 +231,9 @@ class IoctlHelperPrelim20 : public IoctlHelper { bool initialize() override; bool isSetPairAvailable() override; + bool isChunkingAvailable() override; bool isVmBindAvailable() override; - int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) override; + int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) override; CacheRegion closAlloc() override; uint16_t closAllocWays(CacheRegion closIndex, uint16_t cacheLevel, uint16_t numWays) override; CacheRegion closFree(CacheRegion closIndex) override; @@ -238,6 +243,7 @@ class IoctlHelperPrelim20 : public IoctlHelper { uint32_t getPreferredLocationAdvise() override; std::optional getPreferredLocationRegion(PreferredLocation memoryLocation, uint32_t memoryInstance) override; bool setVmBoAdvise(int32_t handle, uint32_t attribute, void *region) override; + bool setVmBoAdviseForChunking(int32_t handle, uint64_t start, uint64_t length, uint32_t attribute, void *region) override; bool setVmPrefetch(uint64_t start, uint64_t length, uint32_t region, uint32_t vmId) override; uint32_t getDirectSubmissionFlag() override; std::unique_ptr prepareVmBindExt(const StackVec &bindExtHandles) override; diff --git a/shared/source/os_interface/linux/ioctl_helper_prelim.cpp b/shared/source/os_interface/linux/ioctl_helper_prelim.cpp index f53f30b6fe..d9ac1ed1e7 100644 --- a/shared/source/os_interface/linux/ioctl_helper_prelim.cpp +++ b/shared/source/os_interface/linux/ioctl_helper_prelim.cpp @@ -7,6 +7,7 @@ #include "shared/source/debug_settings/debug_settings_manager.h" #include "shared/source/execution_environment/root_device_environment.h" +#include "shared/source/helpers/aligned_memory.h" #include "shared/source/helpers/common_types.h" #include "shared/source/helpers/constants.h" #include "shared/source/helpers/debug_helpers.h" @@ -56,6 +57,19 @@ bool IoctlHelperPrelim20::isSetPairAvailable() { return setPairSupported; } +bool IoctlHelperPrelim20::isChunkingAvailable() { + int chunkSupported = 0; + GetParam getParam{}; + getParam.param = PRELIM_I915_PARAM_HAS_CHUNK_SIZE; + getParam.value = &chunkSupported; + int retVal = IoctlHelper::ioctl(DrmIoctl::Getparam, &getParam); + if (retVal) { + return false; + } + + return chunkSupported; +} + bool IoctlHelperPrelim20::isVmBindAvailable() { int vmBindSupported = 0; GetParam getParam{}; @@ -68,7 +82,7 @@ bool IoctlHelperPrelim20::isVmBindAvailable() { return vmBindSupported; } -int IoctlHelperPrelim20::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) { +int IoctlHelperPrelim20::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) { uint32_t regionsSize = static_cast(memClassInstances.size()); std::vector regions(regionsSize); for (uint32_t i = 0; i < regionsSize; i++) { @@ -86,6 +100,7 @@ int IoctlHelperPrelim20::createGemExt(const MemRegionsVec &memClassInstances, si prelim_drm_i915_gem_create_ext_vm_private vmPrivate{}; prelim_drm_i915_gem_create_ext_setparam pairSetparamRegion{}; + prelim_drm_i915_gem_create_ext_setparam chunkingParamRegion{}; if (vmId != std::nullopt) { vmPrivate.base.name = PRELIM_I915_GEM_CREATE_EXT_VM_PRIVATE; @@ -98,11 +113,25 @@ int IoctlHelperPrelim20::createGemExt(const MemRegionsVec &memClassInstances, si pairSetparamRegion.param.data = pairHandle; } - if (vmId != std::nullopt) { - vmPrivate.base.next_extension = reinterpret_cast(&pairSetparamRegion); - setparamRegion.base.next_extension = reinterpret_cast(&vmPrivate); - } else if (pairHandle != -1) { - setparamRegion.base.next_extension = reinterpret_cast(&pairSetparamRegion); + if (isChunked) { + size_t chunkingSize = allocSize / numOfChunks; + chunkingParamRegion.base.name = PRELIM_I915_GEM_CREATE_EXT_SETPARAM; + chunkingParamRegion.param.param = PRELIM_I915_OBJECT_PARAM | PRELIM_I915_PARAM_SET_CHUNK_SIZE; + UNRECOVERABLE_IF(chunkingSize & (MemoryConstants::pageSize64k - 1)); + chunkingParamRegion.param.data = chunkingSize; + printDebugString(DebugManager.flags.PrintBOChunkingLogs.get(), stdout, + "GEM_CREATE_EXT with BOChunkingSize %d, chunkingParamRegion.param.data %d, numOfChunks %d\n", + chunkingSize, + chunkingParamRegion.param.data, + numOfChunks); + setparamRegion.base.next_extension = reinterpret_cast(&chunkingParamRegion); + } else { + if (vmId != std::nullopt) { + vmPrivate.base.next_extension = reinterpret_cast(&pairSetparamRegion); + setparamRegion.base.next_extension = reinterpret_cast(&vmPrivate); + } else if (pairHandle != -1) { + setparamRegion.base.next_extension = reinterpret_cast(&pairSetparamRegion); + } } prelim_drm_i915_gem_create_ext createExt{}; @@ -238,6 +267,25 @@ std::optional IoctlHelperPrelim20::getPreferredLocationRegi return region; } +bool IoctlHelperPrelim20::setVmBoAdviseForChunking(int32_t handle, uint64_t start, uint64_t length, uint32_t attribute, void *region) { + prelim_drm_i915_gem_vm_advise vmAdvise{}; + vmAdvise.handle = handle; + vmAdvise.start = start; + vmAdvise.length = length; + vmAdvise.attribute = attribute; + UNRECOVERABLE_IF(region == nullptr); + vmAdvise.region = *reinterpret_cast(region); + + int ret = IoctlHelper::ioctl(DrmIoctl::GemVmAdvise, &vmAdvise); + if (ret != 0) { + int err = errno; + PRINT_DEBUG_STRING(DebugManager.flags.PrintDebugMessages.get(), stderr, "ioctl(PRELIM_DRM_I915_GEM_VM_ADVISE) failed with %d. errno=%d(%s)\n", ret, err, strerror(err)); + DEBUG_BREAK_IF(true); + return false; + } + return true; +} + bool IoctlHelperPrelim20::setVmBoAdvise(int32_t handle, uint32_t attribute, void *region) { prelim_drm_i915_gem_vm_advise vmAdvise{}; diff --git a/shared/source/os_interface/linux/ioctl_helper_upstream.cpp b/shared/source/os_interface/linux/ioctl_helper_upstream.cpp index 23539c022c..94692b0cf3 100644 --- a/shared/source/os_interface/linux/ioctl_helper_upstream.cpp +++ b/shared/source/os_interface/linux/ioctl_helper_upstream.cpp @@ -22,11 +22,15 @@ bool IoctlHelperUpstream::isSetPairAvailable() { return false; } +bool IoctlHelperUpstream::isChunkingAvailable() { + return false; +} + bool IoctlHelperUpstream::isVmBindAvailable() { return false; } -int IoctlHelperUpstream::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) { +int IoctlHelperUpstream::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) { uint32_t regionsSize = static_cast(memClassInstances.size()); std::vector regions(regionsSize); for (uint32_t i = 0; i < regionsSize; i++) { @@ -94,6 +98,10 @@ bool IoctlHelperUpstream::setVmBoAdvise(int32_t handle, uint32_t attribute, void return true; } +bool IoctlHelperUpstream::setVmBoAdviseForChunking(int32_t handle, uint64_t start, uint64_t length, uint32_t attribute, void *region) { + return true; +} + bool IoctlHelperUpstream::setVmPrefetch(uint64_t start, uint64_t length, uint32_t region, uint32_t vmId) { return true; } diff --git a/shared/source/os_interface/linux/local/dg1/ioctl_helper_dg1.cpp b/shared/source/os_interface/linux/local/dg1/ioctl_helper_dg1.cpp index a4ccf525cc..8e680fb71e 100644 --- a/shared/source/os_interface/linux/local/dg1/ioctl_helper_dg1.cpp +++ b/shared/source/os_interface/linux/local/dg1/ioctl_helper_dg1.cpp @@ -21,8 +21,8 @@ constexpr static auto gfxProduct = IGFX_DG1; extern bool isQueryDrmTip(const std::vector &queryInfo); template <> -int IoctlHelperImpl::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) { - auto ret = IoctlHelperUpstream::createGemExt(memClassInstances, allocSize, handle, vmId, pairHandle); +int IoctlHelperImpl::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) { + auto ret = IoctlHelperUpstream::createGemExt(memClassInstances, allocSize, handle, vmId, pairHandle, isChunked, numOfChunks); if (ret == 0) { return ret; } diff --git a/shared/source/os_interface/linux/memory_info.cpp b/shared/source/os_interface/linux/memory_info.cpp index 92c9e79cc2..98cca5d518 100644 --- a/shared/source/os_interface/linux/memory_info.cpp +++ b/shared/source/os_interface/linux/memory_info.cpp @@ -56,8 +56,8 @@ void MemoryInfo::assignRegionsFromDistances(const std::vector &dis } } -int MemoryInfo::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) { - return this->drm.getIoctlHelper()->createGemExt(memClassInstances, allocSize, handle, vmId, pairHandle); +int MemoryInfo::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) { + return this->drm.getIoctlHelper()->createGemExt(memClassInstances, allocSize, handle, vmId, pairHandle, isChunked, numOfChunks); } uint32_t MemoryInfo::getTileIndex(uint32_t memoryBank) { @@ -120,7 +120,8 @@ int MemoryInfo::createGemExtWithSingleRegion(uint32_t memoryBanks, size_t allocS vmId = this->drm.getVirtualMemoryAddressSpace(tileIndex); } } - auto ret = createGemExt(region, allocSize, handle, vmId, pairHandle); + uint32_t numOfChunks = 0; + auto ret = createGemExt(region, allocSize, handle, vmId, pairHandle, false, numOfChunks); return ret; } @@ -138,7 +139,26 @@ int MemoryInfo::createGemExtWithMultipleRegions(uint32_t memoryBanks, size_t all } currentBank++; } - auto ret = createGemExt(memRegions, allocSize, handle, {}, -1); + uint32_t numOfChunks = 0; + auto ret = createGemExt(memRegions, allocSize, handle, {}, -1, false, numOfChunks); + return ret; +} + +int MemoryInfo::createGemExtWithMultipleRegions(uint32_t memoryBanks, size_t allocSize, uint32_t &handle, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) { + auto pHwInfo = this->drm.getRootDeviceEnvironment().getHardwareInfo(); + auto banks = std::bitset<4>(memoryBanks); + MemRegionsVec memRegions{}; + size_t currentBank = 0; + size_t i = 0; + while (i < banks.count()) { + if (banks.test(currentBank)) { + auto regionClassAndInstance = getMemoryRegionClassAndInstance(1u << currentBank, *pHwInfo); + memRegions.push_back(regionClassAndInstance); + i++; + } + currentBank++; + } + auto ret = createGemExt(memRegions, allocSize, handle, {}, pairHandle, isChunked, numOfChunks); return ret; } diff --git a/shared/source/os_interface/linux/memory_info.h b/shared/source/os_interface/linux/memory_info.h index 61a33448f8..3d56e102c0 100644 --- a/shared/source/os_interface/linux/memory_info.h +++ b/shared/source/os_interface/linux/memory_info.h @@ -26,7 +26,7 @@ class MemoryInfo { void assignRegionsFromDistances(const std::vector &distances); - MOCKABLE_VIRTUAL int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle); + MOCKABLE_VIRTUAL int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks); MemoryClassInstance getMemoryRegionClassAndInstance(uint32_t memoryBank, const HardwareInfo &hwInfo); @@ -40,6 +40,7 @@ class MemoryInfo { MOCKABLE_VIRTUAL int createGemExtWithSingleRegion(uint32_t memoryBanks, size_t allocSize, uint32_t &handle, int32_t pairHandle); MOCKABLE_VIRTUAL int createGemExtWithMultipleRegions(uint32_t memoryBanks, size_t allocSize, uint32_t &handle); + MOCKABLE_VIRTUAL int createGemExtWithMultipleRegions(uint32_t memoryBanks, size_t allocSize, uint32_t &handle, int32_t pairHandle, bool isChunked, uint32_t numOfChunks); const RegionContainer &getDrmRegionInfos() const { return drmQueryRegions; } diff --git a/shared/source/os_interface/linux/xe/ioctl_helper_xe.cpp b/shared/source/os_interface/linux/xe/ioctl_helper_xe.cpp index eab64b1202..cc2abb41b5 100644 --- a/shared/source/os_interface/linux/xe/ioctl_helper_xe.cpp +++ b/shared/source/os_interface/linux/xe/ioctl_helper_xe.cpp @@ -252,6 +252,10 @@ bool IoctlHelperXe::isSetPairAvailable() { return false; } +bool IoctlHelperXe::isChunkingAvailable() { + return false; +} + bool IoctlHelperXe::isVmBindAvailable() { return true; } @@ -365,7 +369,7 @@ std::unique_ptr IoctlHelperXe::createMemoryInfo() { return std::make_unique(regionsContainer, drm); } -int IoctlHelperXe::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) { +int IoctlHelperXe::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) { struct drm_xe_gem_create create = {}; uint32_t regionsSize = static_cast(memClassInstances.size()); @@ -483,6 +487,10 @@ bool IoctlHelperXe::setVmBoAdvise(int32_t handle, uint32_t attribute, void *regi return false; } +bool IoctlHelperXe::setVmBoAdviseForChunking(int32_t handle, uint64_t start, uint64_t length, uint32_t attribute, void *region) { + return false; +} + bool IoctlHelperXe::setVmPrefetch(uint64_t start, uint64_t length, uint32_t region, uint32_t vmId) { xeLog(" -> IoctlHelperXe::%s\n", __FUNCTION__); return false; diff --git a/shared/source/os_interface/linux/xe/ioctl_helper_xe.h b/shared/source/os_interface/linux/xe/ioctl_helper_xe.h index 0043c5f824..8ab6bee074 100644 --- a/shared/source/os_interface/linux/xe/ioctl_helper_xe.h +++ b/shared/source/os_interface/linux/xe/ioctl_helper_xe.h @@ -44,8 +44,9 @@ class IoctlHelperXe : public IoctlHelper { bool initialize() override; bool isSetPairAvailable() override; + bool isChunkingAvailable() override; bool isVmBindAvailable() override; - int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) override; + int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) override; CacheRegion closAlloc() override; uint16_t closAllocWays(CacheRegion closIndex, uint16_t cacheLevel, uint16_t numWays) override; CacheRegion closFree(CacheRegion closIndex) override; @@ -55,6 +56,7 @@ class IoctlHelperXe : public IoctlHelper { uint32_t getPreferredLocationAdvise() override; std::optional getPreferredLocationRegion(PreferredLocation memoryLocation, uint32_t memoryInstance) override; bool setVmBoAdvise(int32_t handle, uint32_t attribute, void *region) override; + bool setVmBoAdviseForChunking(int32_t handle, uint64_t start, uint64_t length, uint32_t attribute, void *region) override; bool setVmPrefetch(uint64_t start, uint64_t length, uint32_t region, uint32_t vmId) override; uint32_t getDirectSubmissionFlag() override; std::unique_ptr prepareVmBindExt(const StackVec &bindExtHandles) override; diff --git a/shared/test/common/libult/linux/drm_mock.h b/shared/test/common/libult/linux/drm_mock.h index 8dcc57f1ff..54b7719b3c 100644 --- a/shared/test/common/libult/linux/drm_mock.h +++ b/shared/test/common/libult/linux/drm_mock.h @@ -27,6 +27,7 @@ class DrmMock : public Drm { using Drm::bindAvailable; using Drm::cacheInfo; using Drm::checkQueueSliceSupport; + using Drm::chunkingAvailable; using Drm::classHandles; using Drm::completionFenceSupported; using Drm::contextDebugSupported; @@ -141,6 +142,13 @@ class DrmMock : public Drm { return setPairAvailable; } + bool isChunkingAvailable() override { + if (callBaseIsChunkingAvailable) { + return Drm::isChunkingAvailable(); + } + return chunkingAvailable; + } + bool getSetPairAvailable() override { if (callBaseGetSetPairAvailable) { return Drm::getSetPairAvailable(); @@ -197,6 +205,7 @@ class DrmMock : public Drm { bool callBaseCreateDrmContext = true; bool callBaseIsVmBindAvailable = false; bool callBaseIsSetPairAvailable = false; + bool callBaseIsChunkingAvailable = false; bool callBaseGetSetPairAvailable = false; bool unrecoverableContextSet = false; bool failRetHwIpVersion = false; diff --git a/shared/test/common/libult/linux/drm_mock_prelim_context.cpp b/shared/test/common/libult/linux/drm_mock_prelim_context.cpp index abfdf48b5c..80701bb60e 100644 --- a/shared/test/common/libult/linux/drm_mock_prelim_context.cpp +++ b/shared/test/common/libult/linux/drm_mock_prelim_context.cpp @@ -52,6 +52,10 @@ int DrmMockPrelimContext::handlePrelimRequest(DrmIoctl request, void *arg) { setPairQueryCalled++; *gp->value = setPairQueryValue; return setPairQueryReturn; + } else if (gp->param == PRELIM_I915_PARAM_HAS_CHUNK_SIZE) { + chunkingQueryCalled++; + *gp->value = chunkingQueryValue; + return chunkingQueryReturn; } } break; case DrmIoctl::GemContextGetparam: { diff --git a/shared/test/common/libult/linux/drm_mock_prelim_context.h b/shared/test/common/libult/linux/drm_mock_prelim_context.h index 7c91f0c815..c59ceab91d 100644 --- a/shared/test/common/libult/linux/drm_mock_prelim_context.h +++ b/shared/test/common/libult/linux/drm_mock_prelim_context.h @@ -112,6 +112,10 @@ struct DrmMockPrelimContext { int vmBindQueryValue{0}; int vmBindQueryReturn{0}; + size_t chunkingQueryCalled{0}; + int chunkingQueryValue{0}; + int chunkingQueryReturn{0}; + size_t vmBindCalled{0}; std::optional receivedVmBind{}; std::optional receivedVmBindUserFence{}; diff --git a/shared/test/common/os_interface/linux/device_command_stream_fixture.cpp b/shared/test/common/os_interface/linux/device_command_stream_fixture.cpp index cdbf8ecb4f..91f4bfc4de 100644 --- a/shared/test/common/os_interface/linux/device_command_stream_fixture.cpp +++ b/shared/test/common/os_interface/linux/device_command_stream_fixture.cpp @@ -193,6 +193,9 @@ int DrmMockCustom::ioctl(DrmIoctl request, void *arg) { createExtHandle = createExtParams->handle; createExtExtensions = createExtParams->extensions; ioctlCnt.gemCreateExt++; + if (failOnCreateExt == true) { + return -1; + } } break; case DrmIoctl::GemVmBind: { } break; @@ -258,3 +261,21 @@ bool DrmMockCustom::getSetPairAvailable() { return getSetPairAvailableCall.returnValue; } } + +bool DrmMockCustom::isChunkingAvailable() { + isChunkingAvailableCall.called++; + if (isChunkingAvailableCall.callParent) { + return Drm::isChunkingAvailable(); + } else { + return isChunkingAvailableCall.returnValue; + } +} + +bool DrmMockCustom::getChunkingAvailable() { + getChunkingAvailableCall.called++; + if (getChunkingAvailableCall.callParent) { + return Drm::getChunkingAvailable(); + } else { + return getChunkingAvailableCall.returnValue; + } +} diff --git a/shared/test/common/os_interface/linux/device_command_stream_fixture.h b/shared/test/common/os_interface/linux/device_command_stream_fixture.h index f401a7eb0a..3f5186a302 100644 --- a/shared/test/common/os_interface/linux/device_command_stream_fixture.h +++ b/shared/test/common/os_interface/linux/device_command_stream_fixture.h @@ -121,12 +121,21 @@ class DrmMockCustom : public Drm { uint32_t called = 0u; }; + struct IsChunkingAvailableCall { + bool callParent = true; + bool returnValue = true; + uint32_t called = 0u; + }; + DrmMockCustom(RootDeviceEnvironment &rootDeviceEnvironment); int waitUserFence(uint32_t ctxId, uint64_t address, uint64_t value, ValueWidth dataWidth, int64_t timeout, uint16_t flags) override; bool getSetPairAvailable() override; + bool getChunkingAvailable() override; + bool isChunkingAvailable() override; + bool isVmBindAvailable() override; bool completionFenceSupport() override { @@ -171,6 +180,9 @@ class DrmMockCustom : public Drm { IsVmBindAvailableCall getSetPairAvailableCall{}; IsVmBindAvailableCall isVmBindAvailableCall{}; + IsChunkingAvailableCall getChunkingAvailableCall{}; + IsChunkingAvailableCall isChunkingAvailableCall{}; + std::atomic ioctlRes; std::atomic ioctlResExt; @@ -224,6 +236,7 @@ class DrmMockCustom : public Drm { uint64_t createExtSize = 0; uint32_t createExtHandle = 0; uint64_t createExtExtensions = 0; + bool failOnCreateExt = false; uint32_t vmIdToCreate = 0; diff --git a/shared/test/common/os_interface/linux/drm_memory_manager_fixture.h b/shared/test/common/os_interface/linux/drm_memory_manager_fixture.h index 61b5169f78..2f5d277ec1 100644 --- a/shared/test/common/os_interface/linux/drm_memory_manager_fixture.h +++ b/shared/test/common/os_interface/linux/drm_memory_manager_fixture.h @@ -69,7 +69,7 @@ struct MockedMemoryInfo : public NEO::MemoryInfo { size_t getMemoryRegionSize(uint32_t memoryBank) override { return 1024u; } - int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle) override { + int createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, std::optional vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) override { if (allocSize == 0) { return EINVAL; } @@ -92,8 +92,23 @@ struct MockedMemoryInfo : public NEO::MemoryInfo { banks = memoryBanks; return 0; } + int createGemExtWithMultipleRegions(uint32_t memoryBanks, size_t allocSize, uint32_t &handle, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) override { + if (allocSize == 0) { + return EINVAL; + } + if (failOnCreateGemExtWithMultipleRegions == true) { + return -1; + } + handle = 1u; + banks = memoryBanks; + isChunkedUsed = isChunked; + return 0; + } + uint32_t banks = 0; int32_t pairHandlePassed = -1; + bool isChunkedUsed = false; + bool failOnCreateGemExtWithMultipleRegions = false; }; class DrmMemoryManagerFixtureWithoutQuietIoctlExpectation { diff --git a/shared/test/common/test_files/igdrcl.config b/shared/test/common/test_files/igdrcl.config index f031159716..0118890434 100644 --- a/shared/test/common/test_files/igdrcl.config +++ b/shared/test/common/test_files/igdrcl.config @@ -518,6 +518,10 @@ DetectIndirectAccessInKernel = -1 OptimizeIoqBarriersHandling = -1 AllocateSharedAllocationsInHeapExtendedHost = 0 AllocateHostAllocationsInHeapExtendedHost = 1 +PrintBOChunkingLogs = 0 +EnableBOChunking = 0 +EnableBOChunkingPreferredLocationHint = 0 +NumberOfBOChunks = 2 DirectSubmissionControllerMaxTimeout = -1 ExitOnSubmissionNumber = -1 ExitOnSubmissionMode = 0 diff --git a/shared/test/unit_test/os_interface/linux/drm_bind_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_bind_tests.cpp index fa2714909c..26357de11f 100644 --- a/shared/test/unit_test/os_interface/linux/drm_bind_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_bind_tests.cpp @@ -70,3 +70,11 @@ TEST(DrmBindTest, whenCheckingSetPairAvailabilityThenIoctlHelperSupportIsUsed) { EXPECT_EQ(drm.isSetPairAvailable(), drm.getIoctlHelper()->isSetPairAvailable()); } + +TEST(DrmBindTest, whenCheckingChunkingAvailabilityThenIoctlHelperSupportIsUsed) { + auto executionEnvironment = std::make_unique(); + DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + drm.callBaseIsChunkingAvailable = true; + + EXPECT_EQ(drm.isChunkingAvailable(), drm.getIoctlHelper()->isChunkingAvailable()); +} \ No newline at end of file diff --git a/shared/test/unit_test/os_interface/linux/drm_memory_info_prelim_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_memory_info_prelim_tests.cpp index d28e9e4870..cbc3847138 100644 --- a/shared/test/unit_test/os_interface/linux/drm_memory_info_prelim_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_memory_info_prelim_tests.cpp @@ -372,7 +372,8 @@ TEST(MemoryInfo, givenMemoryInfoWithRegionsWhenCreatingGemWithExtensionsThenRetu auto memoryInfo = std::make_unique(regionInfo, *drm); ASSERT_NE(nullptr, memoryInfo); - auto ret = memoryInfo->createGemExt(memClassInstance, 1024, handle, {}, -1); + uint32_t numOfChunks = 0; + auto ret = memoryInfo->createGemExt(memClassInstance, 1024, handle, {}, -1, false, numOfChunks); EXPECT_EQ(1u, handle); EXPECT_EQ(0, ret); EXPECT_EQ(1u, drm->ioctlCallsCount); @@ -437,6 +438,60 @@ TEST(MemoryInfo, givenMemoryInfoWithRegionsWhenCreatingGemExtWithPairHandleThenR EXPECT_EQ(2u, drm->ioctlCallsCount); } +TEST(MemoryInfo, givenMemoryInfoWithRegionsWhenCreatingGemExtWithChunkingButSizeLessThanAllowedThenExceptionIsThrown) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableLocalMemory.set(1); + + std::vector regionInfo(2); + regionInfo[0].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 0}; + regionInfo[0].probedSize = 8 * GB; + regionInfo[1].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}; + regionInfo[1].probedSize = 16 * GB; + + auto executionEnvironment = std::make_unique(); + executionEnvironment->prepareRootDeviceEnvironments(1); + auto drm = std::make_unique(*executionEnvironment->rootDeviceEnvironments[0]); + drm->context.chunkingQueryValue = 1; + drm->context.chunkingQueryReturn = 1; + + uint32_t numOfChunks = 2; + size_t allocSize = MemoryConstants::chunkThreshold / (numOfChunks * 2); + uint32_t pairHandle = -1; + uint32_t handle = 0; + bool isChunked = true; + auto memoryInfo = std::make_unique(regionInfo, *drm); + ASSERT_NE(nullptr, memoryInfo); + EXPECT_THROW(memoryInfo->createGemExtWithMultipleRegions(1, allocSize, handle, pairHandle, isChunked, numOfChunks), std::runtime_error); +} + +TEST(MemoryInfo, givenMemoryInfoWithRegionsWhenCreatingGemExtWithChunkingWithSizeGreaterThanAllowedThenAllocationIsCreatedWithChunking) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableLocalMemory.set(1); + + std::vector regionInfo(2); + regionInfo[0].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 0}; + regionInfo[0].probedSize = 8 * GB; + regionInfo[1].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}; + regionInfo[1].probedSize = 16 * GB; + + auto executionEnvironment = std::make_unique(); + executionEnvironment->prepareRootDeviceEnvironments(1); + auto drm = std::make_unique(*executionEnvironment->rootDeviceEnvironments[0]); + drm->context.chunkingQueryValue = 1; + drm->context.chunkingQueryReturn = 1; + + uint32_t numOfChunks = 2; + size_t allocSize = MemoryConstants::chunkThreshold * numOfChunks * 2; + uint32_t pairHandle = -1; + uint32_t handle = 0; + bool isChunked = true; + auto memoryInfo = std::make_unique(regionInfo, *drm); + ASSERT_NE(nullptr, memoryInfo); + auto ret = memoryInfo->createGemExtWithMultipleRegions(1, allocSize, handle, pairHandle, isChunked, numOfChunks); + EXPECT_EQ(0, ret); + EXPECT_EQ(1u, drm->ioctlCallsCount); +} + TEST(MemoryInfo, givenMemoryInfoWithRegionsAndPrivateBOSupportWhenCreatingGemExtWithSingleRegionThenValidVmIdIsSet) { DebugManagerStateRestore restorer; DebugManager.flags.EnableLocalMemory.set(1); @@ -564,3 +619,72 @@ TEST(MemoryInfo, givenMemoryInfoWithRegionsWhenCreatingGemExtWithMultipleRegions EXPECT_EQ(3u, createExt->memoryRegions[2].memoryInstance); EXPECT_EQ(1024u, drm->context.receivedCreateGemExt->size); } + +TEST(MemoryInfo, givenMemoryInfoWithRegionsWhenCallingCreatingGemExtWithMultipleRegionsAndNotAllowedSizeThenExceptionIsThrown) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableLocalMemory.set(1); + + std::vector regionInfo(5); + regionInfo[0].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 0}; + regionInfo[0].probedSize = 8 * GB; + regionInfo[1].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}; + regionInfo[1].probedSize = 16 * GB; + regionInfo[2].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 1}; + regionInfo[2].probedSize = 16 * GB; + regionInfo[3].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 2}; + regionInfo[3].probedSize = 16 * GB; + regionInfo[4].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 3}; + regionInfo[4].probedSize = 16 * GB; + + auto executionEnvironment = std::make_unique(); + auto drm = std::make_unique(*executionEnvironment->rootDeviceEnvironments[0]); + + auto memoryInfo = std::make_unique(regionInfo, *drm); + ASSERT_NE(nullptr, memoryInfo); + uint32_t handle = 0; + uint32_t memoryRegions = 0b1011; + uint32_t numOfChunks = 2; + EXPECT_THROW(memoryInfo->createGemExtWithMultipleRegions(memoryRegions, MemoryConstants::chunkThreshold / (numOfChunks * 2), handle, -1, true, numOfChunks), std::runtime_error); +} + +TEST(MemoryInfo, givenMemoryInfoWithRegionsWhenCallingCreatingGemExtWithMultipleRegionsAndChunkingThenReturnCorrectValues) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableLocalMemory.set(1); + + std::vector regionInfo(5); + regionInfo[0].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 0}; + regionInfo[0].probedSize = 8 * GB; + regionInfo[1].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}; + regionInfo[1].probedSize = 16 * GB; + regionInfo[2].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 1}; + regionInfo[2].probedSize = 16 * GB; + regionInfo[3].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 2}; + regionInfo[3].probedSize = 16 * GB; + regionInfo[4].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 3}; + regionInfo[4].probedSize = 16 * GB; + + auto executionEnvironment = std::make_unique(); + auto drm = std::make_unique(*executionEnvironment->rootDeviceEnvironments[0]); + + auto memoryInfo = std::make_unique(regionInfo, *drm); + ASSERT_NE(nullptr, memoryInfo); + uint32_t handle = 0; + uint32_t memoryRegions = 0b1011; + uint32_t numOfChunks = 2; + size_t size = MemoryConstants::chunkThreshold * numOfChunks; + auto ret = memoryInfo->createGemExtWithMultipleRegions(memoryRegions, size, handle, -1, true, numOfChunks); + EXPECT_EQ(1u, handle); + EXPECT_EQ(0, ret); + EXPECT_EQ(1u, drm->ioctlCallsCount); + + const auto &createExt = drm->context.receivedCreateGemExt; + ASSERT_TRUE(createExt); + ASSERT_EQ(3u, createExt->memoryRegions.size()); + EXPECT_EQ(drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, createExt->memoryRegions[0].memoryClass); + EXPECT_EQ(0u, createExt->memoryRegions[0].memoryInstance); + EXPECT_EQ(drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, createExt->memoryRegions[1].memoryClass); + EXPECT_EQ(1u, createExt->memoryRegions[1].memoryInstance); + EXPECT_EQ(drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, createExt->memoryRegions[2].memoryClass); + EXPECT_EQ(3u, createExt->memoryRegions[2].memoryInstance); + EXPECT_EQ(size, drm->context.receivedCreateGemExt->size); +} \ No newline at end of file diff --git a/shared/test/unit_test/os_interface/linux/drm_memory_info_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_memory_info_tests.cpp index 26f963270f..e92a1ced86 100644 --- a/shared/test/unit_test/os_interface/linux/drm_memory_info_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_memory_info_tests.cpp @@ -235,7 +235,8 @@ HWTEST2_F(MemoryInfoTest, givenMemoryInfoWithRegionsWhenCreatingGemWithExtension uint32_t handle = 0; MemRegionsVec memClassInstance = {regionInfo[0].region, regionInfo[1].region}; - auto ret = memoryInfo->createGemExt(memClassInstance, 1024, handle, {}, -1); + uint32_t numOfChunks = 0; + auto ret = memoryInfo->createGemExt(memClassInstance, 1024, handle, {}, -1, false, numOfChunks); EXPECT_EQ(1u, handle); EXPECT_EQ(0, ret); EXPECT_EQ(1u, drm->ioctlCallsCount); diff --git a/shared/test/unit_test/os_interface/linux/drm_memory_manager_localmem_prelim_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_memory_manager_localmem_prelim_tests.cpp index 74379b75d8..66ab917e66 100644 --- a/shared/test/unit_test/os_interface/linux/drm_memory_manager_localmem_prelim_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_memory_manager_localmem_prelim_tests.cpp @@ -324,6 +324,86 @@ TEST_F(DrmMemoryManagerLocalMemoryPrelimTest, whenCreateUnifiedMemoryAllocationT memoryManager->freeGraphicsMemory(allocation); } +TEST_F(DrmMemoryManagerLocalMemoryPrelimTest, + whenCreateUnifiedMemoryAllocationWithChunkingThenGemCreateExtAndPreferredLocationAreUsed) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableBOChunkingPreferredLocationHint.set(1); + std::vector regionInfo(2); + regionInfo[0].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 1}; + regionInfo[1].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, DrmMockHelper::getEngineOrMemoryInstanceValue(0, 0)}; + + mock->memoryInfo.reset(new MemoryInfo(regionInfo, *mock)); + mock->queryEngineInfo(); + mock->ioctlCallsCount = 0; + + mock->chunkingAvailable = true; + mock->callBaseIsChunkingAvailable = true; + + AllocationProperties gpuProperties{0u, + MemoryConstants::chunkThreshold, + AllocationType::UNIFIED_SHARED_MEMORY, + 1u}; + gpuProperties.alignment = 2 * MemoryConstants::megaByte; + gpuProperties.usmInitialPlacement = GraphicsAllocation::UsmInitialPlacement::CPU; + auto allocation = memoryManager->allocateGraphicsMemoryWithProperties(gpuProperties); + + ASSERT_NE(allocation, nullptr); + EXPECT_NE(static_cast(allocation)->getMmapPtr(), nullptr); + EXPECT_NE(static_cast(allocation)->getMmapSize(), 0u); + EXPECT_EQ(allocation->getAllocationOffset(), 0u); + + const auto &createExt = mock->context.receivedCreateGemExt.value(); + EXPECT_EQ(1u, createExt.handle); + + const auto &memRegions = createExt.memoryRegions; + ASSERT_EQ(memRegions.size(), 2u); + EXPECT_EQ(memRegions[0].memoryClass, drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM); + EXPECT_EQ(memRegions[0].memoryInstance, 1u); + EXPECT_EQ(memRegions[1].memoryClass, drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE); + EXPECT_EQ(memRegions[1].memoryInstance, regionInfo[1].region.memoryInstance); + + memoryManager->freeGraphicsMemory(allocation); +} + +TEST_F(DrmMemoryManagerLocalMemoryPrelimTest, + whenCreateUnifiedMemoryAllocationWithChunkingAndNoEnableBOChunkingPreferredLocationHintSetThenGemCreateExtIsUsedWithoutPreferredLocation) { + std::vector regionInfo(2); + regionInfo[0].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 1}; + regionInfo[1].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, DrmMockHelper::getEngineOrMemoryInstanceValue(0, 0)}; + + mock->memoryInfo.reset(new MemoryInfo(regionInfo, *mock)); + mock->queryEngineInfo(); + mock->ioctlCallsCount = 0; + + mock->chunkingAvailable = true; + mock->callBaseIsChunkingAvailable = true; + + AllocationProperties gpuProperties{0u, + MemoryConstants::chunkThreshold, + AllocationType::UNIFIED_SHARED_MEMORY, + 1u}; + gpuProperties.alignment = 2 * MemoryConstants::megaByte; + gpuProperties.usmInitialPlacement = GraphicsAllocation::UsmInitialPlacement::CPU; + auto allocation = memoryManager->allocateGraphicsMemoryWithProperties(gpuProperties); + + ASSERT_NE(allocation, nullptr); + EXPECT_NE(static_cast(allocation)->getMmapPtr(), nullptr); + EXPECT_NE(static_cast(allocation)->getMmapSize(), 0u); + EXPECT_EQ(allocation->getAllocationOffset(), 0u); + + const auto &createExt = mock->context.receivedCreateGemExt.value(); + EXPECT_EQ(1u, createExt.handle); + + const auto &memRegions = createExt.memoryRegions; + ASSERT_EQ(memRegions.size(), 2u); + EXPECT_EQ(memRegions[0].memoryClass, drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM); + EXPECT_EQ(memRegions[0].memoryInstance, 1u); + EXPECT_EQ(memRegions[1].memoryClass, drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE); + EXPECT_EQ(memRegions[1].memoryInstance, regionInfo[1].region.memoryInstance); + + memoryManager->freeGraphicsMemory(allocation); +} + TEST_F(DrmMemoryManagerLocalMemoryPrelimTest, whenCreateUnifiedMemoryAllocationWithMultiMemoryRegionsThenGemCreateExtIsUsedWithSingleLmemRegions) { std::vector regionInfo(3); regionInfo[0].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 1}; diff --git a/shared/test/unit_test/os_interface/linux/drm_memory_manager_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_memory_manager_tests.cpp index 30e33e2210..e99be82fa5 100644 --- a/shared/test/unit_test/os_interface/linux/drm_memory_manager_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_memory_manager_tests.cpp @@ -5259,6 +5259,68 @@ TEST_F(DrmMemoryManagerWithLocalMemoryAndExplicitExpectationsTest, givenMemoryAl memoryManager->freeGraphicsMemory(allocation); } +TEST_F(DrmMemoryManagerWithLocalMemoryAndExplicitExpectationsTest, + givenMemoryAllocationWithLessThanChunkingSizeAllowedThenChunkingIsNotUsed) { + VariableBackup backupChunkingCallParent{&mock->getChunkingAvailableCall.callParent, false}; + VariableBackup backupChunkingReturnValue{&mock->getChunkingAvailableCall.returnValue, true}; + + MemoryManager::AllocationStatus status = MemoryManager::AllocationStatus::Success; + AllocationData allocData; + allocData.allFlags = 0; + allocData.size = MemoryConstants::chunkThreshold / 4; + allocData.type = AllocationType::BUFFER; + allocData.rootDeviceIndex = rootDeviceIndex; + allocData.storageInfo.memoryBanks = 0b11; + + auto allocation = memoryManager->allocateGraphicsMemoryInDevicePool(allocData, status); + EXPECT_NE(nullptr, allocation); + EXPECT_EQ(MemoryManager::AllocationStatus::Success, status); + + EXPECT_EQ(false, static_cast(mock->getMemoryInfo())->isChunkedUsed); + + memoryManager->freeGraphicsMemory(allocation); +} + +TEST_F(DrmMemoryManagerWithLocalMemoryAndExplicitExpectationsTest, + givenMemoryAllocationWithMoreThanChunkingSizeAllowedThenChunkingIsUsed) { + VariableBackup backupChunkingCallParent{&mock->getChunkingAvailableCall.callParent, false}; + VariableBackup backupChunkingReturnValue{&mock->getChunkingAvailableCall.returnValue, true}; + + MemoryManager::AllocationStatus status = MemoryManager::AllocationStatus::Success; + AllocationData allocData; + allocData.allFlags = 0; + allocData.size = MemoryConstants::chunkThreshold * 2; + allocData.type = AllocationType::BUFFER; + allocData.rootDeviceIndex = rootDeviceIndex; + allocData.storageInfo.memoryBanks = 0b11; + + auto allocation = memoryManager->allocateGraphicsMemoryInDevicePool(allocData, status); + EXPECT_NE(nullptr, allocation); + EXPECT_EQ(MemoryManager::AllocationStatus::Success, status); + + EXPECT_EQ(true, static_cast(mock->getMemoryInfo())->isChunkedUsed); + + memoryManager->freeGraphicsMemory(allocation); +} + +TEST_F(DrmMemoryManagerWithLocalMemoryAndExplicitExpectationsTest, + givenMemoryAllocationWithMoreThanChunkingSizeAllowedAndFailGemCreateExtThenNullptrIsReturned) { + VariableBackup backupChunkingCallParent{&mock->getChunkingAvailableCall.callParent, false}; + VariableBackup backupChunkingReturnValue{&mock->getChunkingAvailableCall.returnValue, true}; + + MemoryManager::AllocationStatus status = MemoryManager::AllocationStatus::Success; + AllocationData allocData; + allocData.allFlags = 0; + allocData.size = MemoryConstants::chunkThreshold * 2; + allocData.type = AllocationType::BUFFER; + allocData.rootDeviceIndex = rootDeviceIndex; + allocData.storageInfo.memoryBanks = 0b11; + static_cast(mock->getMemoryInfo())->failOnCreateGemExtWithMultipleRegions = true; + + auto allocation = memoryManager->allocateGraphicsMemoryInDevicePool(allocData, status); + EXPECT_EQ(nullptr, allocation); +} + TEST_F(DrmMemoryManagerWithLocalMemoryAndExplicitExpectationsTest, givenMemoryAllocationWithNoSetPairAndTwoHandlesThenPairHandleIsPassed) { VariableBackup backupSetPairCallParent{&mock->getSetPairAvailableCall.callParent, false}; VariableBackup backupSetPairReturnValue{&mock->getSetPairAvailableCall.returnValue, false}; diff --git a/shared/test/unit_test/os_interface/linux/drm_residency_handler_prelim_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_residency_handler_prelim_tests.cpp index 8250fc20a9..ee8bb88f67 100644 --- a/shared/test/unit_test/os_interface/linux/drm_residency_handler_prelim_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_residency_handler_prelim_tests.cpp @@ -567,6 +567,37 @@ TEST_F(DrmMemoryOperationsHandlerBindTest, givenDrmMemoryOperationBindWhenMakeRe memoryManager->freeGraphicsMemory(allocation); } +TEST_F(DrmMemoryOperationsHandlerBindTest, givenDrmMemoryOperationBindWhenMakeResidentWithChunkingWithinOsContextEvictableAllocationThenAllocationIsNotMarkedAsAlwaysResident) { + auto allocation = memoryManager->allocateGraphicsMemoryWithProperties(MockAllocationProperties{device->getRootDeviceIndex(), MemoryConstants::pageSize}); + allocation->storageInfo.isChunked = true; + + EXPECT_EQ(operationHandler->makeResidentWithinOsContext(device->getDefaultEngine().osContext, ArrayRef(&allocation, 1), false), MemoryOperationsStatus::SUCCESS); + EXPECT_TRUE(allocation->isAlwaysResident(device->getDefaultEngine().osContext->getContextId())); + + EXPECT_EQ(operationHandler->evict(device, *allocation), MemoryOperationsStatus::SUCCESS); + + EXPECT_EQ(operationHandler->makeResidentWithinOsContext(device->getDefaultEngine().osContext, ArrayRef(&allocation, 1), true), MemoryOperationsStatus::SUCCESS); + EXPECT_FALSE(allocation->isAlwaysResident(device->getDefaultEngine().osContext->getContextId())); + + memoryManager->freeGraphicsMemory(allocation); +} + +TEST_F(DrmMemoryOperationsHandlerBindTest, givenDrmMemoryOperationBindWhenMakeResidentWithChunkingAndMultipleBanksWithinOsContextEvictableAllocationThenAllocationIsNotMarkedAsAlwaysResident) { + auto allocation = memoryManager->allocateGraphicsMemoryWithProperties(MockAllocationProperties{device->getRootDeviceIndex(), MemoryConstants::pageSize}); + allocation->storageInfo.isChunked = true; + allocation->storageInfo.memoryBanks = 0x5; + + EXPECT_EQ(operationHandler->makeResidentWithinOsContext(device->getDefaultEngine().osContext, ArrayRef(&allocation, 1), false), MemoryOperationsStatus::SUCCESS); + EXPECT_TRUE(allocation->isAlwaysResident(device->getDefaultEngine().osContext->getContextId())); + + EXPECT_EQ(operationHandler->evict(device, *allocation), MemoryOperationsStatus::SUCCESS); + + EXPECT_EQ(operationHandler->makeResidentWithinOsContext(device->getDefaultEngine().osContext, ArrayRef(&allocation, 1), true), MemoryOperationsStatus::SUCCESS); + EXPECT_FALSE(allocation->isAlwaysResident(device->getDefaultEngine().osContext->getContextId())); + + memoryManager->freeGraphicsMemory(allocation); +} + TEST_F(DrmMemoryOperationsHandlerBindTest, givenDrmMemoryOperationBindWhenChangingResidencyThenOperationIsHandledProperly) { auto allocation = memoryManager->allocateGraphicsMemoryWithProperties(MockAllocationProperties{device->getRootDeviceIndex(), MemoryConstants::pageSize}); @@ -1358,6 +1389,20 @@ TEST(DrmSetPairTests, whenQueryingForSetPairAvailableAndNoDebugKeyThenFalseIsRet EXPECT_EQ(0u, drm.context.setPairQueryCalled); } +TEST(DrmChunkingTests, whenQueryingForChunkingAvailableAndNoDebugKeyThenFalseIsReturned) { + auto executionEnvironment = std::make_unique(); + DrmQueryMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + drm.context.chunkingQueryValue = 0; + drm.context.chunkingQueryReturn = 0; + EXPECT_FALSE(drm.chunkingAvailable); + + EXPECT_EQ(0u, drm.context.chunkingQueryCalled); + drm.callBaseIsChunkingAvailable = true; + EXPECT_FALSE(drm.isChunkingAvailable()); + EXPECT_FALSE(drm.chunkingAvailable); + EXPECT_EQ(0u, drm.context.chunkingQueryCalled); +} + TEST(DrmSetPairTests, whenQueryingForSetPairAvailableAndDebugKeySetAndNoSupportAvailableThenFalseIsReturned) { DebugManagerStateRestore restorer; DebugManager.flags.EnableSetPair.set(1); @@ -1472,3 +1517,54 @@ TEST(DrmResidencyHandlerTests, whenQueryingForSetPairAvailableWithDebugKeySetToZ EXPECT_FALSE(drm.setPairAvailable); EXPECT_EQ(0u, drm.context.setPairQueryCalled); } + +TEST(DrmResidencyHandlerTests, whenQueryingForChunkingAvailableAndSupportAvailableThenExpectedValueIsReturned) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableBOChunking.set(1); + + auto executionEnvironment = std::make_unique(); + DrmQueryMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + drm.context.chunkingQueryValue = 1; + drm.context.chunkingQueryReturn = 0; + EXPECT_FALSE(drm.chunkingAvailable); + + EXPECT_EQ(0u, drm.context.chunkingQueryCalled); + drm.callBaseIsChunkingAvailable = true; + EXPECT_TRUE(drm.isChunkingAvailable()); + EXPECT_TRUE(drm.chunkingAvailable); + EXPECT_EQ(1u, drm.context.chunkingQueryCalled); +} + +TEST(DrmResidencyHandlerTests, whenQueryingForChunkingAvailableAndFailureInQueryThenFalseIsReturned) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableBOChunking.set(1); + + auto executionEnvironment = std::make_unique(); + DrmQueryMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + drm.context.chunkingQueryValue = 1; + drm.context.chunkingQueryReturn = 1; + EXPECT_FALSE(drm.chunkingAvailable); + + EXPECT_EQ(0u, drm.context.chunkingQueryCalled); + drm.callBaseIsChunkingAvailable = true; + EXPECT_FALSE(drm.isChunkingAvailable()); + EXPECT_FALSE(drm.chunkingAvailable); + EXPECT_EQ(1u, drm.context.chunkingQueryCalled); +} + +TEST(DrmResidencyHandlerTests, whenQueryingForChunkingAvailableWithDebugKeySetToZeroThenFalseIsReturned) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableBOChunking.set(0); + + auto executionEnvironment = std::make_unique(); + DrmQueryMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + drm.context.chunkingQueryValue = 1; + drm.context.chunkingQueryReturn = 1; + EXPECT_FALSE(drm.chunkingAvailable); + + EXPECT_EQ(0u, drm.context.chunkingQueryCalled); + drm.callBaseIsChunkingAvailable = true; + EXPECT_FALSE(drm.isChunkingAvailable()); + EXPECT_FALSE(drm.chunkingAvailable); + EXPECT_EQ(0u, drm.context.chunkingQueryCalled); +} diff --git a/shared/test/unit_test/os_interface/linux/drm_vm_bind_prelim_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_vm_bind_prelim_tests.cpp index 4e44044df5..211cdf7faa 100644 --- a/shared/test/unit_test/os_interface/linux/drm_vm_bind_prelim_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_vm_bind_prelim_tests.cpp @@ -61,6 +61,35 @@ TEST(DrmVmBindTest, givenBoRequiringExplicitResidencyWhenBindingThenMakeResident } } +TEST(DrmVmBindTest, + givenBoWithChunkingRequiringExplicitResidencyWhenBindingThenMakeResidentFlagIsNotPassedAndUserFenceIsSetup) { + auto executionEnvironment = std::make_unique(); + executionEnvironment->rootDeviceEnvironments[0]->initGmm(); + executionEnvironment->initializeMemoryManager(); + DrmQueryMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + drm.pageFaultSupported = true; + + for (auto requireResidency : {false, true}) { + MockBufferObject bo(0, &drm, 3, 0, 0, 1); + bo.isChunked = true; + bo.requireExplicitResidency(requireResidency); + + OsContextLinux osContext(drm, 0, 0u, EngineDescriptorHelper::getDefaultDescriptor()); + osContext.ensureContextInitialized(); + uint32_t vmHandleId = 0; + bo.bind(&osContext, vmHandleId); + + if (requireResidency) { + EXPECT_EQ(DrmPrelimHelper::getImmediateVmBindFlag(), drm.context.receivedVmBind->flags); + ASSERT_TRUE(drm.context.receivedVmBindUserFence); + EXPECT_EQ(castToUint64(drm.getFenceAddr(vmHandleId)), drm.context.receivedVmBindUserFence->addr); + EXPECT_EQ(drm.fenceVal[vmHandleId], drm.context.receivedVmBindUserFence->val); + } else { + EXPECT_EQ(DrmPrelimHelper::getImmediateVmBindFlag(), drm.context.receivedVmBind->flags); + } + } +} + TEST(DrmVmBindTest, givenPerContextVmsAndBoRequiringExplicitResidencyWhenBindingThenPagingFenceFromContextIsUsed) { auto executionEnvironment = std::make_unique(); executionEnvironment->rootDeviceEnvironments[0]->initGmm(); diff --git a/shared/test/unit_test/os_interface/linux/drm_with_prelim_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_with_prelim_tests.cpp index a33dd8f9e1..dea5d402a9 100644 --- a/shared/test/unit_test/os_interface/linux/drm_with_prelim_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_with_prelim_tests.cpp @@ -136,13 +136,45 @@ TEST_F(IoctlHelperPrelimFixture, givenPrelimsWhenCreateGemExtThenReturnSuccess) auto ioctlHelper = drm->getIoctlHelper(); uint32_t handle = 0; MemRegionsVec memClassInstance = {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}}; - auto ret = ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1); + uint32_t numOfChunks = 0; + auto ret = ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1, false, numOfChunks); EXPECT_EQ(1u, handle); EXPECT_EQ(0, ret); EXPECT_EQ(1u, drm->ioctlCallsCount); } +TEST_F(IoctlHelperPrelimFixture, givenPrelimsWhenCreateGemExtWithChunkingThenGetNumOfChunks) { + DebugManagerStateRestore stateRestore; + DebugManager.flags.PrintBOChunkingLogs.set(true); + DebugManager.flags.NumberOfBOChunks.set(2); + size_t allocSize = 2 * MemoryConstants::pageSize64k; + + testing::internal::CaptureStdout(); + auto ioctlHelper = drm->getIoctlHelper(); + uint32_t handle = 0; + uint32_t getNumOfChunks = 2; + MemRegionsVec memClassInstance = {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}}; + ioctlHelper->createGemExt(memClassInstance, allocSize, handle, {}, -1, true, getNumOfChunks); + std::string output = testing::internal::GetCapturedStdout(); + std::string expectedOutput("GEM_CREATE_EXT with BOChunkingSize 65536, chunkingParamRegion.param.data 65536, numOfChunks 2\n"); + EXPECT_EQ(expectedOutput, output); + EXPECT_EQ(2u, getNumOfChunks); +} + +TEST_F(IoctlHelperPrelimFixture, givenPrelimsWhenCreateGemExtWithChunkingAndAllocTooSmallThenExceptionThrown) { + DebugManagerStateRestore stateRestore; + DebugManager.flags.PrintBOChunkingLogs.set(false); + DebugManager.flags.NumberOfBOChunks.set(2); + size_t allocSize = MemoryConstants::pageSize64k; + + auto ioctlHelper = drm->getIoctlHelper(); + uint32_t handle = 0; + uint32_t getNumOfChunks = 2; + MemRegionsVec memClassInstance = {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}}; + EXPECT_THROW(ioctlHelper->createGemExt(memClassInstance, allocSize, handle, {}, -1, true, getNumOfChunks), std::runtime_error); +} + TEST_F(IoctlHelperPrelimFixture, givenPrelimsWhenCreateGemExtWithDebugFlagThenPrintDebugInfo) { DebugManagerStateRestore stateRestore; DebugManager.flags.PrintBOCreateDestroyResult.set(true); @@ -151,7 +183,8 @@ TEST_F(IoctlHelperPrelimFixture, givenPrelimsWhenCreateGemExtWithDebugFlagThenPr auto ioctlHelper = drm->getIoctlHelper(); uint32_t handle = 0; MemRegionsVec memClassInstance = {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}}; - ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1); + uint32_t numOfChunks = 0; + ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1, false, numOfChunks); std::string output = testing::internal::GetCapturedStdout(); std::string expectedOutput("Performing GEM_CREATE_EXT with { size: 1024, param: 0x1000000010001, memory class: 1, memory instance: 0 }\nGEM_CREATE_EXT has returned: 0 BO-1 with size: 1024\n"); @@ -252,6 +285,28 @@ TEST_F(IoctlHelperPrelimFixture, givenDrmAllocationWhenSetMemAdviseFailsThenDont EXPECT_NE(memAdviseFlags.allFlags, allocation.enabledMemAdviseFlags.allFlags); } +TEST_F(IoctlHelperPrelimFixture, givenDrmAllocationWhenSetMemAdviseForChunkingFailsThenDontUpdateMemAdviceFlags) { + DebugManagerStateRestore restore; + DebugManager.flags.EnableBOChunking.set(1); + DebugManager.flags.EnableBOChunkingPreferredLocationHint.set(true); + + drm->ioctlCallsCount = 0; + drm->ioctlRetVal = -1; + + MockBufferObject bo(0u, drm.get(), 3, 0, 0, 1); + MockDrmAllocation allocation(0u, AllocationType::BUFFER, MemoryPool::LocalMemory); + allocation.bufferObjects[0] = &bo; + + MemAdviseFlags memAdviseFlags{}; + memAdviseFlags.nonAtomic = 1; + allocation.storageInfo.isChunked = 1; + + allocation.setMemAdvise(drm.get(), memAdviseFlags); + + EXPECT_EQ(1u, drm->ioctlCallsCount); + EXPECT_NE(memAdviseFlags.allFlags, allocation.enabledMemAdviseFlags.allFlags); +} + TEST_F(IoctlHelperPrelimFixture, givenDrmAllocationWhenSetMemAdviseWithNonAtomicIsCalledThenUpdateTheCorrespondingVmAdviceForBufferObject) { MockBufferObject bo(0u, drm.get(), 3, 0, 0, 1); drm->ioctlCallsCount = 0; @@ -288,6 +343,102 @@ TEST_F(IoctlHelperPrelimFixture, givenDrmAllocationWhenSetMemAdviseWithDevicePre EXPECT_EQ(2u, drm->ioctlCallsCount); } +TEST_F(IoctlHelperPrelimFixture, givenDrmAllocationWhenSetMemAdviseWithChunkingPreferredLocationIsCalledThenUpdateTheCorrespondingVmAdviceForBufferChunks) { + DebugManagerStateRestore restore; + DebugManager.flags.EnableBOChunking.set(1); + DebugManager.flags.EnableBOChunkingPreferredLocationHint.set(true); + + std::vector memRegions{ + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 0}, MemoryConstants::chunkThreshold * 4, 0}, + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}, MemoryConstants::chunkThreshold * 4, 0}, + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 1}, MemoryConstants::chunkThreshold * 4, 0}, + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 2}, MemoryConstants::chunkThreshold * 4, 0}}; + drm->memoryInfo.reset(new MemoryInfo(memRegions, *drm)); + + drm->ioctlCallsCount = 0; + MockBufferObject bo(0u, drm.get(), 3, 0, 0, 1); + MockDrmAllocation allocation(0u, AllocationType::BUFFER, MemoryPool::LocalMemory); + allocation.bufferObjects[0] = &bo; + allocation.storageInfo.memoryBanks = 0x1; + allocation.setNumHandles(1); + allocation.storageInfo.isChunked = 1; + allocation.storageInfo.numOfChunks = 4; + + MemAdviseFlags memAdviseFlags{}; + + for (auto devicePreferredLocation : {true, false}) { + memAdviseFlags.devicePreferredLocation = devicePreferredLocation; + + EXPECT_TRUE(allocation.setMemAdvise(drm.get(), memAdviseFlags)); + EXPECT_EQ(memAdviseFlags.allFlags, allocation.enabledMemAdviseFlags.allFlags); + } + EXPECT_EQ(allocation.storageInfo.numOfChunks * 2, drm->ioctlCallsCount); +} + +TEST_F(IoctlHelperPrelimFixture, givenDrmAllocationWhenSetMemAdviseWithChunkingButWithoutEnableBOChunkingPreferredLocationHintCalledThenUpdateTheCorrespondingVmAdviceForBufferObject) { + DebugManagerStateRestore restore; + DebugManager.flags.EnableBOChunking.set(1); + DebugManager.flags.EnableBOChunkingPreferredLocationHint.set(0); + + std::vector memRegions{ + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 0}, MemoryConstants::chunkThreshold * 4, 0}, + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}, MemoryConstants::chunkThreshold * 4, 0}, + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 1}, MemoryConstants::chunkThreshold * 4, 0}, + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 2}, MemoryConstants::chunkThreshold * 4, 0}}; + drm->memoryInfo.reset(new MemoryInfo(memRegions, *drm)); + + drm->ioctlCallsCount = 0; + MockBufferObject bo(0u, drm.get(), 3, 0, 0, 1); + MockDrmAllocation allocation(0u, AllocationType::BUFFER, MemoryPool::LocalMemory); + allocation.bufferObjects[0] = &bo; + allocation.storageInfo.memoryBanks = 0x1; + allocation.setNumHandles(1); + allocation.storageInfo.isChunked = 1; + allocation.storageInfo.numOfChunks = 4; + + MemAdviseFlags memAdviseFlags{}; + + for (auto devicePreferredLocation : {true, false}) { + memAdviseFlags.devicePreferredLocation = devicePreferredLocation; + + EXPECT_TRUE(allocation.setMemAdvise(drm.get(), memAdviseFlags)); + EXPECT_EQ(memAdviseFlags.allFlags, allocation.enabledMemAdviseFlags.allFlags); + } + EXPECT_EQ(2u, drm->ioctlCallsCount); +} + +TEST_F(IoctlHelperPrelimFixture, + givenDrmAllocationWhenSetMemAdviseWithChunkingPreferredLocationIsCalledWithFailureThenReturnFalse) { + drm->ioctlRetVal = -1; + DebugManagerStateRestore restore; + DebugManager.flags.EnableBOChunking.set(1); + DebugManager.flags.EnableBOChunkingPreferredLocationHint.set(true); + + std::vector memRegions{ + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 0}, MemoryConstants::chunkThreshold * 4, 0}, + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}, MemoryConstants::chunkThreshold * 4, 0}, + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 1}, MemoryConstants::chunkThreshold * 4, 0}, + {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 2}, MemoryConstants::chunkThreshold * 4, 0}}; + drm->memoryInfo.reset(new MemoryInfo(memRegions, *drm)); + + drm->ioctlCallsCount = 0; + MockBufferObject bo(0u, drm.get(), 3, 0, 0, 1); + MockDrmAllocation allocation(0u, AllocationType::BUFFER, MemoryPool::LocalMemory); + allocation.bufferObjects[0] = &bo; + allocation.storageInfo.memoryBanks = 0x5; + allocation.setNumHandles(1); + allocation.storageInfo.isChunked = 1; + allocation.storageInfo.numOfChunks = 4; + + MemAdviseFlags memAdviseFlags{}; + + memAdviseFlags.devicePreferredLocation = true; + + EXPECT_FALSE(allocation.setMemAdvise(drm.get(), memAdviseFlags)); + + EXPECT_EQ(allocation.storageInfo.numOfChunks, drm->ioctlCallsCount); +} + TEST_F(IoctlHelperPrelimFixture, givenDrmAllocationWhenSetMemPrefetchSucceedsThenReturnTrue) { SubDeviceIdsVec subDeviceIds{0}; MockBufferObject bo(0u, drm.get(), 3, 0, 0, 1); diff --git a/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_dg1.cpp b/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_dg1.cpp index 4d9440cee4..ca699725a1 100644 --- a/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_dg1.cpp +++ b/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_dg1.cpp @@ -27,7 +27,8 @@ DG1TEST_F(IoctlHelperTestsDg1, givenDg1WhenCreateGemExtThenReturnCorrectValue) { auto ioctlHelper = drm->getIoctlHelper(); uint32_t handle = 0; MemRegionsVec memClassInstance = {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}}; - auto ret = ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1); + uint32_t numOfChunks = 0; + auto ret = ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1, false, numOfChunks); EXPECT_EQ(0, ret); EXPECT_EQ(1u, handle); @@ -48,7 +49,8 @@ DG1TEST_F(IoctlHelperTestsDg1, givenDg1WithDrmTipWhenCreateGemExtWithDebugFlagTh auto ioctlHelper = drm->getIoctlHelper(); uint32_t handle = 0; MemRegionsVec memClassInstance = {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}}; - auto ret = ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1); + uint32_t numOfChunks = 0; + auto ret = ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1, false, numOfChunks); std::string output = testing::internal::GetCapturedStdout(); std::string expectedOutput("Performing GEM_CREATE_EXT with { size: 1024, memory class: 1, memory instance: 0 }\nGEM_CREATE_EXT with EXT_MEMORY_REGIONS has returned: 0 BO-1 with size: 1024\n"); @@ -69,7 +71,8 @@ DG1TEST_F(IoctlHelperTestsDg1, givenDg1WhenCreateGemExtWithDebugFlagThenPrintDeb auto ioctlHelper = drm->getIoctlHelper(); uint32_t handle = 0; MemRegionsVec memClassInstance = {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}}; - auto ret = ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1); + uint32_t numOfChunks = 0; + auto ret = ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1, false, numOfChunks); std::string output = testing::internal::GetCapturedStdout(); std::string expectedOutput("Performing GEM_CREATE_EXT with { size: 1024, memory class: 1, memory instance: 0 }\nGEM_CREATE_EXT with EXT_MEMORY_REGIONS has returned: -1 BO-0 with size: 1024\nGEM_CREATE_EXT with EXT_SETPARAM has returned: 0 BO-1 with size: 1024\n"); diff --git a/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_upstream.cpp b/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_upstream.cpp index 57dc3ccc44..9a6d33bc00 100644 --- a/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_upstream.cpp +++ b/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_upstream.cpp @@ -218,7 +218,8 @@ TEST(IoctlHelperTestsUpstream, givenUpstreamWhenCreateGemExtThenReturnCorrectVal auto ioctlHelper = drm->getIoctlHelper(); uint32_t handle = 0; MemRegionsVec memClassInstance = {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}}; - auto ret = ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1); + uint32_t numOfChunks = 0; + auto ret = ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1, false, numOfChunks); EXPECT_EQ(0, ret); EXPECT_EQ(1u, handle); @@ -238,7 +239,8 @@ TEST(IoctlHelperTestsUpstream, givenUpstreamWhenCreateGemExtWithDebugFlagThenPri auto ioctlHelper = drm->getIoctlHelper(); uint32_t handle = 0; MemRegionsVec memClassInstance = {{drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}}; - ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1); + uint32_t numOfChunks = 0; + ioctlHelper->createGemExt(memClassInstance, 1024, handle, {}, -1, false, numOfChunks); std::string output = testing::internal::GetCapturedStdout(); std::string expectedOutput("Performing GEM_CREATE_EXT with { size: 1024, memory class: 1, memory instance: 0 }\nGEM_CREATE_EXT with EXT_MEMORY_REGIONS has returned: 0 BO-1 with size: 1024\n"); diff --git a/shared/test/unit_test/os_interface/linux/xe/ioctl_helper_xe_tests.cpp b/shared/test/unit_test/os_interface/linux/xe/ioctl_helper_xe_tests.cpp index 4268230e33..9e2754317c 100644 --- a/shared/test/unit_test/os_interface/linux/xe/ioctl_helper_xe_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/xe/ioctl_helper_xe_tests.cpp @@ -62,6 +62,43 @@ TEST(IoctlHelperXeTest, whenChangingBufferBindingThenWaitIsNeededAlways) { EXPECT_TRUE(ioctlHelper.isWaitBeforeBindRequired(false)); } +TEST(IoctlHelperXeTest, givenIoctlHelperXeWhenCallingGemCreateExtWithRegionsThenDummyValueIsReturned) { + auto executionEnvironment = std::make_unique(); + DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + auto xeIoctlHelper = std::make_unique(drm); + ASSERT_NE(nullptr, xeIoctlHelper); + + std::vector regionInfo(2); + regionInfo[0].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 0}; + regionInfo[0].probedSize = 8 * GB; + regionInfo[1].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}; + regionInfo[1].probedSize = 16 * GB; + MemRegionsVec memRegions = {regionInfo[0].region, regionInfo[1].region}; + + uint32_t handle = 0u; + uint32_t numOfChunks = 0; + EXPECT_NE(0, xeIoctlHelper->createGemExt(memRegions, 0u, handle, {}, -1, false, numOfChunks)); +} + +TEST(IoctlHelperXeTest, givenIoctlHelperXeWhenCallingGemCreateExtWithRegionsAndVmIdThenDummyValueIsReturned) { + auto executionEnvironment = std::make_unique(); + DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + auto xeIoctlHelper = std::make_unique(drm); + ASSERT_NE(nullptr, xeIoctlHelper); + + std::vector regionInfo(2); + regionInfo[0].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_SYSTEM, 0}; + regionInfo[0].probedSize = 8 * GB; + regionInfo[1].region = {drm_i915_gem_memory_class::I915_MEMORY_CLASS_DEVICE, 0}; + regionInfo[1].probedSize = 16 * GB; + MemRegionsVec memRegions = {regionInfo[0].region, regionInfo[1].region}; + + uint32_t handle = 0u; + uint32_t numOfChunks = 0; + GemVmControl test = {}; + EXPECT_NE(0, xeIoctlHelper->createGemExt(memRegions, 0u, handle, test.vmId, -1, false, numOfChunks)); +} + TEST(IoctlHelperXeTest, givenIoctlHelperXeWhenCallingAnyMethodThenDummyValueIsReturned) { auto executionEnvironment = std::make_unique(); DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; @@ -82,7 +119,8 @@ TEST(IoctlHelperXeTest, givenIoctlHelperXeWhenCallingAnyMethodThenDummyValueIsRe MemRegionsVec memRegions{}; uint32_t handle = 0u; - EXPECT_NE(0, xeIoctlHelper->createGemExt(memRegions, 0u, handle, {}, -1)); + uint32_t numOfChunks = 0; + EXPECT_NE(0, xeIoctlHelper->createGemExt(memRegions, 0u, handle, {}, -1, false, numOfChunks)); EXPECT_TRUE(xeIoctlHelper->isVmBindAvailable()); @@ -104,6 +142,10 @@ TEST(IoctlHelperXeTest, givenIoctlHelperXeWhenCallingAnyMethodThenDummyValueIsRe EXPECT_FALSE(xeIoctlHelper->setVmBoAdvise(0, 0, nullptr)); + EXPECT_FALSE(xeIoctlHelper->setVmBoAdviseForChunking(0, 0, 0, 0, nullptr)); + + EXPECT_FALSE(xeIoctlHelper->isChunkingAvailable()); + EXPECT_FALSE(xeIoctlHelper->setVmPrefetch(0, 0, 0, 0)); EXPECT_EQ(0u, xeIoctlHelper->getDirectSubmissionFlag()); diff --git a/third_party/uapi/prelim/drm/i915_drm_prelim.h b/third_party/uapi/prelim/drm/i915_drm_prelim.h index e2bf11dd2e..25e5318042 100644 --- a/third_party/uapi/prelim/drm/i915_drm_prelim.h +++ b/third_party/uapi/prelim/drm/i915_drm_prelim.h @@ -265,6 +265,9 @@ struct prelim_i915_user_extension { /* End getparam */ +/* BO chunk granularity support */ +#define PRELIM_I915_PARAM_HAS_CHUNK_SIZE (PRELIM_I915_PARAM | 10) + struct prelim_drm_i915_gem_create_ext { /** @@ -326,6 +329,18 @@ struct prelim_drm_i915_gem_object_param { * use two buffer objects with a single exported dma-buf file descriptor */ #define PRELIM_I915_PARAM_SET_PAIR ((1 << 17) | 0x1) + +/* + * PRELIM_I915_PARAM_SET_CHUNK_SIZE: + * + * Specifies that this buffer object should support 'chunking' and chunk + * granularity. Allows internal KMD paging/migration/eviction handling to + * operate on a single chunk instead of the whole buffer object. + * Size specified in bytes and must be non-zero and a power of 2. + * KMD will return error (-ENOSPC) if CHUNK_SIZE is deemed to be too small + * to be supported. + */ +#define PRELIM_I915_PARAM_SET_CHUNK_SIZE ((1 << 18) | 1) __u64 param; /* Data value or pointer */ @@ -1229,10 +1244,20 @@ struct prelim_drm_i915_gem_vm_bind { /** * struct prelim_drm_i915_gem_vm_advise * - * Set attribute (hint) for an address range or whole buffer object. + * Set attribute (hint) for an address range, whole buffer object, or + * part of buffer object. * * To apply attribute to whole buffer object, specify: handle + * + * To apply attribute to part of buffer object (chunk granularity), specify: + * handle, start, and length. + * Start and length must be exactly aligned to chunk boundaries of object. + * Above requires object to have been created during GEM_CREATE with: + * PRELIM_I915_PARAM_SET_CHUNK_SIZE. + * * To apply attribute to address range, specify: vm_id, start, and length. + * + * On error, any applied hints are reverted before returning. */ struct prelim_drm_i915_gem_vm_advise { /** vm that contains address range (specified with start, length) */