Move drm_memory_manager_tests.h and related fixtures to shared

Signed-off-by: Mateusz Jablonski <mateusz.jablonski@intel.com>
This commit is contained in:
Mateusz Jablonski
2021-10-21 14:50:10 +00:00
committed by Compute-Runtime-Automation
parent d2a29ce458
commit 58ebebeec6
64 changed files with 88 additions and 83 deletions

View File

@@ -0,0 +1,182 @@
/*
* Copyright (C) 2018-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/test/common/fixtures/memory_management_fixture.h"
#include "shared/test/common/helpers/memory_leak_listener.h"
#include "shared/test/common/helpers/memory_management.h"
#include <cinttypes>
#if defined(__linux__)
#include <cstdio>
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
#elif defined(_WIN32)
#include <windows.h>
#pragma warning(push) // Saves the current warning state.
#pragma warning(disable : 4091) // Temporarily disables warning 4091.
#include <DbgHelp.h>
#pragma warning(pop) // Restores the warning state.
#pragma comment(lib, "Dbghelp.lib")
#endif
namespace Os {
extern const char *frontEndDllName;
extern const char *igcDllName;
} // namespace Os
void MemoryManagementFixture::SetUp() {
EXPECT_EQ(static_cast<size_t>(-1), MemoryManagement::failingAllocation);
MemoryManagement::indexAllocation = 0;
MemoryManagement::indexDeallocation = 0;
MemoryManagement::failingAllocation = -1;
previousAllocations = MemoryManagement::numAllocations.load();
MemoryManagement::logTraces = MemoryManagement::captureCallStacks;
}
void MemoryManagementFixture::TearDown() {
clearFailingAllocation();
checkForLeaks();
MemoryManagement::logTraces = false;
}
void MemoryManagementFixture::setFailingAllocation(size_t allocation) {
MemoryManagement::indexAllocation = 0;
MemoryManagement::failingAllocation = allocation;
}
void MemoryManagementFixture::clearFailingAllocation() {
MemoryManagement::failingAllocation = -1;
}
::testing::AssertionResult MemoryManagementFixture::assertLeak(
const char *leakExpr,
size_t leakIndex) {
using MemoryManagement::AllocationEvent;
using MemoryManagement::eventsAllocated;
if (leakIndex == MemoryManagement::invalidLeakIndex) {
return ::testing::AssertionSuccess();
}
auto &event = eventsAllocated[leakIndex];
switch (event.event) {
case AllocationEvent::EVENT_DELETE:
return ::testing::AssertionFailure() << "event[" << leakIndex
<< "]: delete doesn't have corresponding new. allocation address="
<< event.address
<< ", allocation size=" << event.size << printCallStack(event);
break;
case AllocationEvent::EVENT_DELETE_ARRAY:
return ::testing::AssertionFailure() << "event[" << leakIndex
<< "]: delete[] doesn't have corresponding new[]. allocation address="
<< event.address
<< ", allocation size=" << event.size << printCallStack(event);
break;
case AllocationEvent::EVENT_NEW:
return ::testing::AssertionFailure() << "event[" << leakIndex
<< "]: new doesn't have corresponding delete. allocation address="
<< event.address
<< ", allocation size=" << event.size << printCallStack(event);
break;
case AllocationEvent::EVENT_NEW_NOTHROW:
return ::testing::AssertionFailure() << "event[" << leakIndex
<< "]: new (std::nothrow) doesn't have corresponding delete. allocation address="
<< event.address
<< ", allocation size=" << event.size << printCallStack(event);
break;
case AllocationEvent::EVENT_NEW_ARRAY:
return ::testing::AssertionFailure() << "event[" << leakIndex
<< "]: new [] doesn't have corresponding delete[]. allocation address="
<< event.address
<< ", allocation size=" << event.size << printCallStack(event);
break;
case AllocationEvent::EVENT_NEW_ARRAY_NOTHROW:
return ::testing::AssertionFailure() << "event[" << leakIndex
<< "] new (std::nothrow) [] doesn't have corresponding delete[]. allocation address="
<< event.address
<< ", allocation size=" << event.size << printCallStack(event);
break;
case AllocationEvent::EVENT_NEW_ARRAY_NOTHROW_FAIL:
case AllocationEvent::EVENT_NEW_ARRAY_FAIL:
case AllocationEvent::EVENT_NEW_NOTHROW_FAIL:
case AllocationEvent::EVENT_NEW_FAIL:
case AllocationEvent::EVENT_UNKNOWN:
default:
return ::testing::AssertionFailure() << "Unknown event[" << leakIndex << "] detected. allocation size=" << event.size;
break;
}
}
void MemoryManagementFixture::checkForLeaks() {
// We have to alias MemoryManagement::numAllocations because
// the following EXPECT_EQ actually allocates more memory :-)
auto currentAllocations = MemoryManagement::numAllocations.load();
auto indexAllocationTop = MemoryManagement::indexAllocation.load();
auto indexDellocationTop = MemoryManagement::indexDeallocation.load();
if (previousAllocations != currentAllocations) {
auto testInfo = ::testing::UnitTest::GetInstance()->current_test_info();
auto testResult = testInfo->result();
if (testResult->Passed()) {
//EXPECT_EQ(previousAllocations, currentAllocations);
size_t leakEventIndex;
do {
leakEventIndex = MemoryManagement::enumerateLeak(indexAllocationTop, indexDellocationTop, false, false);
EXPECT_PRED_FORMAT1(assertLeak, leakEventIndex);
auto invalidLeakIndexValues = MemoryManagement::invalidLeakIndex;
EXPECT_EQ(leakEventIndex, invalidLeakIndexValues);
} while (leakEventIndex != MemoryManagement::invalidLeakIndex);
} else {
printf("*** WARNING: Leaks found but dumping disabled during test failure ***\n");
}
}
}
void MemoryManagementFixture::injectFailures(InjectedFunction &method, uint32_t maxIndex) {
MemoryManagement::indexAllocation = 0;
method(-1);
auto numCurrentAllocations = MemoryManagement::indexAllocation.load();
for (auto i = 0u; i < numCurrentAllocations; i++) {
// Force a failure
MemoryManagement::indexAllocation = numCurrentAllocations;
MemoryManagement::failingAllocation = i + numCurrentAllocations;
if (MemoryManagement::eventsAllocated[i].event == MemoryManagement::AllocationEvent::EVENT_NEW ||
MemoryManagement::eventsAllocated[i].event == MemoryManagement::AllocationEvent::EVENT_NEW_ARRAY) {
continue;
}
if (maxIndex != 0 && i > maxIndex) {
break;
}
// Call the method under test
method(i);
// Restore allocations
MemoryManagement::failingAllocation = -1;
}
MemoryManagement::failingAllocation = -1;
}
void MemoryManagementFixture::injectFailureOnIndex(InjectedFunction &method, uint32_t index) {
MemoryManagement::indexAllocation = 0;
method(-1);
auto numCurrentAllocations = MemoryManagement::indexAllocation.load();
// Force a failure
MemoryManagement::indexAllocation = numCurrentAllocations;
MemoryManagement::failingAllocation = index + numCurrentAllocations;
// Call the method under test
method(index);
// Restore allocations
MemoryManagement::failingAllocation = -1;
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2018-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/test/common/helpers/memory_management.h"
#include "gtest/gtest.h"
#include <functional>
struct MemoryManagementFixture {
MemoryManagementFixture() {
MemoryManagement::detailedAllocationLoggingActive = true;
};
virtual ~MemoryManagementFixture() { MemoryManagement::detailedAllocationLoggingActive = false; };
// Typical Fixture methods
virtual void SetUp(void);
virtual void TearDown(void);
// Helper methods
void setFailingAllocation(size_t allocation);
void clearFailingAllocation(void);
::testing::AssertionResult assertLeak(
const char *leakExpr,
size_t leakIndex);
void checkForLeaks(void);
typedef std::function<void(size_t)> InjectedFunction;
void injectFailures(InjectedFunction &method, uint32_t maxIndex = 0);
void injectFailureOnIndex(InjectedFunction &method, uint32_t index);
// Used to keep track of # of allocations prior at SetUp time
// Gets compared to # at TearDown time
size_t previousAllocations;
};

View File

@@ -67,6 +67,8 @@ set(igdrcl_libult_common_SRCS_LIB_ULT
${NEO_SHARED_TEST_DIRECTORY}/common/helpers/memory_leak_listener.h
${NEO_SHARED_TEST_DIRECTORY}/common/helpers/memory_management.cpp
${NEO_SHARED_TEST_DIRECTORY}/common/helpers/memory_management.h
${NEO_SHARED_TEST_DIRECTORY}/common/fixtures/memory_management_fixture.cpp
${NEO_SHARED_TEST_DIRECTORY}/common/fixtures/memory_management_fixture.h
${NEO_SHARED_TEST_DIRECTORY}/common/helpers/sip_init.cpp
${NEO_SHARED_TEST_DIRECTORY}/common/helpers/test_files.cpp
${NEO_SHARED_TEST_DIRECTORY}/common/helpers/test_files.h
@@ -114,8 +116,16 @@ set(igdrcl_libult_common_SRCS_LIB_ULT_WIN
${NEO_SHARED_TEST_DIRECTORY}/common/os_interface/windows/ult_dxgi_factory.h
)
set(igdrcl_libult_common_SRCS_LIB_ULT_LINUX
${NEO_SHARED_TEST_DIRECTORY}/common/os_interface/linux/device_command_stream_fixture.cpp
${NEO_SHARED_TEST_DIRECTORY}/common/os_interface/linux/device_command_stream_fixture.h
)
set_property(GLOBAL PROPERTY igdrcl_libult_common_SRCS_LIB_ULT_LINUX ${igdrcl_libult_common_SRCS_LIB_ULT_LINUX})
if(WIN32)
target_sources(igdrcl_libult_common PRIVATE ${igdrcl_libult_common_SRCS_LIB_ULT_WIN})
elseif(UNIX)
target_sources(igdrcl_libult_common PRIVATE ${igdrcl_libult_common_SRCS_LIB_ULT_LINUX})
endif()
target_include_directories(igdrcl_libult_common PRIVATE

View File

@@ -90,6 +90,7 @@ if(WIN32)
else()
list(APPEND NEO_CORE_tests_mocks
${CMAKE_CURRENT_SOURCE_DIR}/linux/mock_drm_allocation.h
${CMAKE_CURRENT_SOURCE_DIR}/linux/mock_drm_command_stream_receiver.h
${CMAKE_CURRENT_SOURCE_DIR}/linux/mock_drm_memory_manager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/linux/mock_drm_memory_manager.h
)

View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2018-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/source/os_interface/linux/drm_command_stream.h"
#include "shared/test/common/helpers/ult_hw_config.h"
using namespace NEO;
template <typename GfxFamily>
class TestedDrmCommandStreamReceiver : public DrmCommandStreamReceiver<GfxFamily> {
public:
using CommandStreamReceiver::activePartitions;
using CommandStreamReceiver::clearColorAllocation;
using CommandStreamReceiver::commandStream;
using CommandStreamReceiver::createPreemptionAllocation;
using CommandStreamReceiver::flushStamp;
using CommandStreamReceiver::getTagAddress;
using CommandStreamReceiver::globalFenceAllocation;
using CommandStreamReceiver::latestSentTaskCount;
using CommandStreamReceiver::makeResident;
using CommandStreamReceiver::taskCount;
using CommandStreamReceiver::useGpuIdleImplicitFlush;
using CommandStreamReceiver::useNewResourceImplicitFlush;
using CommandStreamReceiver::useNotifyEnableForPostSync;
using DrmCommandStreamReceiver<GfxFamily>::residency;
using DrmCommandStreamReceiver<GfxFamily>::useContextForUserFenceWait;
using DrmCommandStreamReceiver<GfxFamily>::useUserFenceWait;
using CommandStreamReceiverHw<GfxFamily>::directSubmission;
using CommandStreamReceiverHw<GfxFamily>::blitterDirectSubmission;
using CommandStreamReceiverHw<GfxFamily>::CommandStreamReceiver::lastSentSliceCount;
TestedDrmCommandStreamReceiver(gemCloseWorkerMode mode,
ExecutionEnvironment &executionEnvironment,
const DeviceBitfield deviceBitfield)
: DrmCommandStreamReceiver<GfxFamily>(executionEnvironment, 0, deviceBitfield, mode) {
}
TestedDrmCommandStreamReceiver(ExecutionEnvironment &executionEnvironment,
uint32_t rootDeviceIndex,
const DeviceBitfield deviceBitfield)
: DrmCommandStreamReceiver<GfxFamily>(executionEnvironment, rootDeviceIndex, deviceBitfield, gemCloseWorkerMode::gemCloseWorkerInactive) {
}
void overrideDispatchPolicy(DispatchMode overrideValue) {
this->dispatchMode = overrideValue;
}
void makeNonResident(GraphicsAllocation &gfxAllocation) override {
makeNonResidentResult.called = true;
makeNonResidentResult.allocation = &gfxAllocation;
DrmCommandStreamReceiver<GfxFamily>::makeNonResident(gfxAllocation);
}
struct MakeResidentNonResidentResult {
bool called = false;
GraphicsAllocation *allocation = nullptr;
};
MakeResidentNonResidentResult makeNonResidentResult;
SubmissionAggregator *peekSubmissionAggregator() const {
return this->submissionAggregator.get();
}
void overrideSubmissionAggregator(SubmissionAggregator *newSubmissionsAggregator) {
this->submissionAggregator.reset(newSubmissionsAggregator);
}
std::vector<drm_i915_gem_exec_object2> &getExecStorage() {
return this->execObjectsStorage;
}
bool createPreemptionAllocation() override {
if (ultHwConfig.csrBaseCallCreatePreemption) {
return CommandStreamReceiver::createPreemptionAllocation();
} else {
return ultHwConfig.csrCreatePreemptionReturnValue;
}
}
struct WaitUserFenceResult {
uint32_t called = 0u;
uint32_t waitValue = 0u;
int returnValue = 0;
bool callParent = true;
};
WaitUserFenceResult waitUserFenceResult;
int waitUserFence(uint32_t waitValue) override {
waitUserFenceResult.called++;
waitUserFenceResult.waitValue = waitValue;
if (waitUserFenceResult.callParent) {
return DrmCommandStreamReceiver<GfxFamily>::waitUserFence(waitValue);
} else {
return waitUserFenceResult.returnValue;
}
}
bool callHwFlush = true;
int flushInternal(const BatchBuffer &batchBuffer, const ResidencyContainer &allocationsForResidency) override {
if (callHwFlush) {
return DrmCommandStreamReceiver<GfxFamily>::flushInternal(batchBuffer, allocationsForResidency);
}
return 0;
}
};
template <typename GfxFamily>
class TestedDrmCommandStreamReceiverWithFailingExec : public TestedDrmCommandStreamReceiver<GfxFamily> {
public:
TestedDrmCommandStreamReceiverWithFailingExec(gemCloseWorkerMode mode,
ExecutionEnvironment &executionEnvironment,
const DeviceBitfield deviceBitfield)
: TestedDrmCommandStreamReceiver<GfxFamily>(mode,
executionEnvironment,
deviceBitfield) {
}
TestedDrmCommandStreamReceiverWithFailingExec(ExecutionEnvironment &executionEnvironment,
uint32_t rootDeviceIndex,
const DeviceBitfield deviceBitfield)
: TestedDrmCommandStreamReceiver<GfxFamily>(executionEnvironment,
rootDeviceIndex,
deviceBitfield) {
}
int exec(const BatchBuffer &batchBuffer, uint32_t vmHandleId, uint32_t drmContextId) override {
return -1;
}
};

View File

@@ -10,9 +10,9 @@
#include "shared/source/command_stream/command_stream_receiver.h"
#include "shared/source/command_stream/preemption.h"
#include "shared/source/os_interface/os_context.h"
#include "shared/test//common/mocks/mock_ostime.h"
#include "shared/test/common/mocks/mock_execution_environment.h"
#include "shared/test/common/mocks/mock_memory_manager.h"
#include "shared/test/common/mocks/mock_ostime.h"
#include "shared/test/common/mocks/ult_device_factory.h"
#include "shared/test/unit_test/tests_configuration.h"

View File

@@ -7,7 +7,7 @@
if(UNIX)
target_sources(${TARGET_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
${CMAKE_CURRENT_SOURCE_DIR}/drm_memory_manager_tests.h
)
add_subdirectories()
endif()

View File

@@ -0,0 +1,214 @@
/*
* Copyright (C) 2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/test/common/os_interface/linux/device_command_stream_fixture.h"
const int mockFd = 33;
const char *mockPciPath = "";
void DrmMockCustom::Ioctls::reset() {
total = 0;
execbuffer2 = 0;
gemUserptr = 0;
gemCreate = 0;
gemSetTiling = 0;
gemGetTiling = 0;
primeFdToHandle = 0;
handleToPrimeFd = 0;
gemMmap = 0;
gemSetDomain = 0;
gemWait = 0;
gemClose = 0;
regRead = 0;
getParam = 0;
contextGetParam = 0;
contextCreate = 0;
contextDestroy = 0;
}
void DrmMockCustom::testIoctls() {
if (this->ioctl_expected.total == -1)
return;
#define NEO_IOCTL_EXPECT_EQ(PARAM) \
if (this->ioctl_expected.PARAM >= 0) { \
EXPECT_EQ(this->ioctl_expected.PARAM, this->ioctl_cnt.PARAM); \
}
NEO_IOCTL_EXPECT_EQ(execbuffer2);
NEO_IOCTL_EXPECT_EQ(gemUserptr);
NEO_IOCTL_EXPECT_EQ(gemCreate);
NEO_IOCTL_EXPECT_EQ(gemSetTiling);
NEO_IOCTL_EXPECT_EQ(gemGetTiling);
NEO_IOCTL_EXPECT_EQ(primeFdToHandle);
NEO_IOCTL_EXPECT_EQ(handleToPrimeFd);
NEO_IOCTL_EXPECT_EQ(gemMmap);
NEO_IOCTL_EXPECT_EQ(gemSetDomain);
NEO_IOCTL_EXPECT_EQ(gemWait);
NEO_IOCTL_EXPECT_EQ(gemClose);
NEO_IOCTL_EXPECT_EQ(regRead);
NEO_IOCTL_EXPECT_EQ(getParam);
NEO_IOCTL_EXPECT_EQ(contextGetParam);
NEO_IOCTL_EXPECT_EQ(contextCreate);
NEO_IOCTL_EXPECT_EQ(contextDestroy);
#undef NEO_IOCTL_EXPECT_EQ
}
int DrmMockCustom::ioctl(unsigned long request, void *arg) {
auto ext = ioctl_res_ext.load();
//store flags
switch (request) {
case DRM_IOCTL_I915_GEM_EXECBUFFER2: {
drm_i915_gem_execbuffer2 *execbuf = (drm_i915_gem_execbuffer2 *)arg;
this->execBuffer = *execbuf;
this->execBufferBufferObjects =
*reinterpret_cast<drm_i915_gem_exec_object2 *>(this->execBuffer.buffers_ptr);
ioctl_cnt.execbuffer2++;
} break;
case DRM_IOCTL_I915_GEM_USERPTR: {
auto *userPtrParams = (drm_i915_gem_userptr *)arg;
userPtrParams->handle = returnHandle;
returnHandle++;
ioctl_cnt.gemUserptr++;
} break;
case DRM_IOCTL_I915_GEM_CREATE: {
auto *createParams = (drm_i915_gem_create *)arg;
this->createParamsSize = createParams->size;
this->createParamsHandle = createParams->handle = 1u;
ioctl_cnt.gemCreate++;
} break;
case DRM_IOCTL_I915_GEM_SET_TILING: {
auto *setTilingParams = (drm_i915_gem_set_tiling *)arg;
setTilingMode = setTilingParams->tiling_mode;
setTilingHandle = setTilingParams->handle;
setTilingStride = setTilingParams->stride;
ioctl_cnt.gemSetTiling++;
} break;
case DRM_IOCTL_I915_GEM_GET_TILING: {
auto *getTilingParams = (drm_i915_gem_get_tiling *)arg;
getTilingParams->tiling_mode = getTilingModeOut;
getTilingHandleIn = getTilingParams->handle;
ioctl_cnt.gemGetTiling++;
} break;
case DRM_IOCTL_PRIME_FD_TO_HANDLE: {
auto *primeToHandleParams = (drm_prime_handle *)arg;
//return BO
primeToHandleParams->handle = outputHandle;
inputFd = primeToHandleParams->fd;
ioctl_cnt.primeFdToHandle++;
} break;
case DRM_IOCTL_PRIME_HANDLE_TO_FD: {
auto *handleToPrimeParams = (drm_prime_handle *)arg;
//return FD
inputHandle = handleToPrimeParams->handle;
inputFlags = handleToPrimeParams->flags;
handleToPrimeParams->fd = outputFd;
ioctl_cnt.handleToPrimeFd++;
} break;
case DRM_IOCTL_I915_GEM_MMAP: {
auto mmapParams = (drm_i915_gem_mmap *)arg;
mmapHandle = mmapParams->handle;
mmapPad = mmapParams->pad;
mmapOffset = mmapParams->offset;
mmapSize = mmapParams->size;
mmapFlags = mmapParams->flags;
mmapParams->addr_ptr = mmapAddrPtr;
ioctl_cnt.gemMmap++;
} break;
case DRM_IOCTL_I915_GEM_SET_DOMAIN: {
auto setDomainParams = (drm_i915_gem_set_domain *)arg;
setDomainHandle = setDomainParams->handle;
setDomainReadDomains = setDomainParams->read_domains;
setDomainWriteDomain = setDomainParams->write_domain;
ioctl_cnt.gemSetDomain++;
} break;
case DRM_IOCTL_I915_GEM_WAIT: {
auto gemWaitParams = (drm_i915_gem_wait *)arg;
gemWaitTimeout = gemWaitParams->timeout_ns;
ioctl_cnt.gemWait++;
} break;
case DRM_IOCTL_GEM_CLOSE:
ioctl_cnt.gemClose++;
break;
case DRM_IOCTL_I915_REG_READ:
ioctl_cnt.regRead++;
break;
case DRM_IOCTL_I915_GETPARAM: {
ioctl_cnt.contextGetParam++;
auto getParam = (drm_i915_getparam_t *)arg;
recordedGetParam = *getParam;
*getParam->value = getParamRetValue;
} break;
case DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM: {
} break;
case DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM: {
ioctl_cnt.contextGetParam++;
auto getContextParam = (drm_i915_gem_context_param *)arg;
recordedGetContextParam = *getContextParam;
getContextParam->value = getContextParamRetValue;
} break;
case DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT: {
auto contextCreateParam = reinterpret_cast<drm_i915_gem_context_create_ext *>(arg);
contextCreateParam->ctx_id = ++ioctl_cnt.contextCreate;
} break;
case DRM_IOCTL_I915_GEM_CONTEXT_DESTROY: {
ioctl_cnt.contextDestroy++;
} break;
default:
int res = ioctlExtra(request, arg);
if (returnIoctlExtraErrorValue) {
return res;
}
}
if (!ext->no.empty() && std::find(ext->no.begin(), ext->no.end(), ioctl_cnt.total.load()) != ext->no.end()) {
ioctl_cnt.total.fetch_add(1);
return ext->res;
}
ioctl_cnt.total.fetch_add(1);
return ioctl_res.load();
}
DrmMockCustom::DrmMockCustom(RootDeviceEnvironment &rootDeviceEnvironment)
: Drm(std::make_unique<HwDeviceIdDrm>(mockFd, mockPciPath), rootDeviceEnvironment) {
reset();
ioctl_expected.contextCreate = static_cast<int>(NEO::HwHelper::get(NEO::defaultHwInfo->platform.eRenderCoreFamily).getGpgpuEngineInstances(*NEO::defaultHwInfo).size());
ioctl_expected.contextDestroy = ioctl_expected.contextCreate.load();
createVirtualMemoryAddressSpace(NEO::HwHelper::getSubDevicesCount(rootDeviceEnvironment.getHardwareInfo()));
isVmBindAvailable();
reset();
}
int DrmMockCustom::waitUserFence(uint32_t ctxId, uint64_t address, uint64_t value, ValueWidth dataWidth, int64_t timeout, uint16_t flags) {
waitUserFenceCall.called++;
waitUserFenceCall.ctxId = ctxId;
waitUserFenceCall.address = address;
waitUserFenceCall.dataWidth = dataWidth;
waitUserFenceCall.value = value;
waitUserFenceCall.timeout = timeout;
waitUserFenceCall.flags = flags;
return Drm::waitUserFence(ctxId, address, value, dataWidth, timeout, flags);
}
bool DrmMockCustom::isVmBindAvailable() {
isVmBindAvailableCall.called++;
if (isVmBindAvailableCall.callParent) {
return Drm::isVmBindAvailable();
} else {
return isVmBindAvailableCall.returnValue;
}
}

View File

@@ -0,0 +1,204 @@
/*
* Copyright (C) 2018-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/source/helpers/aligned_memory.h"
#include "shared/source/helpers/hw_helper.h"
#include "shared/source/os_interface/linux/drm_memory_manager.h"
#include "shared/source/os_interface/linux/drm_neo.h"
#include "shared/test/common/helpers/default_hw_info.h"
#include "drm/i915_drm.h"
#include "engine_node.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <atomic>
#include <cstdint>
#include <iostream>
using NEO::Drm;
using NEO::HwDeviceIdDrm;
using NEO::RootDeviceEnvironment;
extern const int mockFd;
extern const char *mockPciPath;
class DrmMockImpl : public Drm {
public:
DrmMockImpl(int fd, RootDeviceEnvironment &rootDeviceEnvironment) : Drm(std::make_unique<HwDeviceIdDrm>(fd, mockPciPath), rootDeviceEnvironment){};
MOCK_METHOD2(ioctl, int(unsigned long request, void *arg));
};
class DrmMockSuccess : public Drm {
public:
DrmMockSuccess(int fd, RootDeviceEnvironment &rootDeviceEnvironment) : Drm(std::make_unique<HwDeviceIdDrm>(fd, mockPciPath), rootDeviceEnvironment) {}
int ioctl(unsigned long request, void *arg) override { return 0; };
};
class DrmMockFail : public Drm {
public:
DrmMockFail(RootDeviceEnvironment &rootDeviceEnvironment) : Drm(std::make_unique<HwDeviceIdDrm>(mockFd, mockPciPath), rootDeviceEnvironment) {}
int ioctl(unsigned long request, void *arg) override { return -1; };
};
class DrmMockTime : public DrmMockSuccess {
public:
using DrmMockSuccess::DrmMockSuccess;
int ioctl(unsigned long request, void *arg) override {
drm_i915_reg_read *reg = reinterpret_cast<drm_i915_reg_read *>(arg);
reg->val = getVal() << 32;
return 0;
};
uint64_t getVal() {
static uint64_t val = 0;
return ++val;
}
};
class DrmMockCustom : public Drm {
public:
using Drm::bindAvailable;
using Drm::cacheInfo;
using Drm::memoryInfo;
struct IoctlResExt {
std::vector<int32_t> no;
int32_t res;
IoctlResExt(int32_t no, int32_t res) : no(1u, no), res(res) {}
};
class Ioctls {
public:
void reset();
std::atomic<int32_t> total;
std::atomic<int32_t> execbuffer2;
std::atomic<int32_t> gemUserptr;
std::atomic<int32_t> gemCreate;
std::atomic<int32_t> gemSetTiling;
std::atomic<int32_t> gemGetTiling;
std::atomic<int32_t> primeFdToHandle;
std::atomic<int32_t> handleToPrimeFd;
std::atomic<int32_t> gemMmap;
std::atomic<int32_t> gemSetDomain;
std::atomic<int32_t> gemWait;
std::atomic<int32_t> gemClose;
std::atomic<int32_t> regRead;
std::atomic<int32_t> getParam;
std::atomic<int32_t> contextGetParam;
std::atomic<int32_t> contextCreate;
std::atomic<int32_t> contextDestroy;
};
struct WaitUserFenceCall {
uint64_t address = 0u;
uint64_t value = 0u;
uint32_t ctxId = 0u;
ValueWidth dataWidth = ValueWidth::U8;
int64_t timeout = 0;
uint16_t flags = 0;
uint32_t called = 0u;
};
struct IsVmBindAvailableCall {
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 isVmBindAvailable() override;
void testIoctls();
int ioctl(unsigned long request, void *arg) override;
virtual int ioctlExtra(unsigned long request, void *arg) {
return -1;
}
int getErrno() override {
return errnoValue;
}
void reset() {
ioctl_res = 0;
ioctl_cnt.reset();
ioctl_expected.reset();
ioctl_res_ext = &NONE;
}
Ioctls ioctl_cnt;
Ioctls ioctl_expected;
IoctlResExt NONE = {-1, 0};
WaitUserFenceCall waitUserFenceCall{};
IsVmBindAvailableCall isVmBindAvailableCall{};
std::atomic<int> ioctl_res;
std::atomic<IoctlResExt *> ioctl_res_ext;
//DRM_IOCTL_I915_GEM_EXECBUFFER2
drm_i915_gem_execbuffer2 execBuffer = {0};
//First exec object
drm_i915_gem_exec_object2 execBufferBufferObjects = {0};
//DRM_IOCTL_I915_GEM_CREATE
__u64 createParamsSize = 0;
__u32 createParamsHandle = 0;
//DRM_IOCTL_I915_GEM_SET_TILING
__u32 setTilingMode = 0;
__u32 setTilingHandle = 0;
__u32 setTilingStride = 0;
//DRM_IOCTL_I915_GEM_GET_TILING
__u32 getTilingModeOut = I915_TILING_NONE;
__u32 getTilingHandleIn = 0;
//DRM_IOCTL_PRIME_FD_TO_HANDLE
__u32 outputHandle = 0;
__s32 inputFd = 0;
//DRM_IOCTL_PRIME_HANDLE_TO_FD
__u32 inputHandle = 0;
__s32 outputFd = 0;
__s32 inputFlags = 0;
//DRM_IOCTL_I915_GEM_USERPTR
__u32 returnHandle = 0;
//DRM_IOCTL_I915_GEM_MMAP
__u32 mmapHandle = 0;
__u32 mmapPad = 0;
__u64 mmapOffset = 0;
__u64 mmapSize = 0;
__u64 mmapAddrPtr = 0x7F4000001000;
__u64 mmapFlags = 0;
//DRM_IOCTL_I915_GEM_SET_DOMAIN
__u32 setDomainHandle = 0;
__u32 setDomainReadDomains = 0;
__u32 setDomainWriteDomain = 0;
//DRM_IOCTL_I915_GETPARAM
drm_i915_getparam_t recordedGetParam = {0};
int getParamRetValue = 0;
//DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM
drm_i915_gem_context_param recordedGetContextParam = {0};
__u64 getContextParamRetValue = 0;
//DRM_IOCTL_I915_GEM_WAIT
int64_t gemWaitTimeout = 0;
int errnoValue = 0;
bool returnIoctlExtraErrorValue = false;
};

View File

@@ -0,0 +1,225 @@
/*
* Copyright (C) 2019-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/source/os_interface/linux/drm_memory_operations_handler.h"
#include "shared/source/os_interface/linux/memory_info.h"
#include "shared/source/os_interface/os_interface.h"
#include "shared/test/common/fixtures/memory_management_fixture.h"
#include "shared/test/common/helpers/debug_manager_state_restore.h"
#include "shared/test/common/helpers/ult_hw_config.h"
#include "shared/test/common/helpers/variable_backup.h"
#include "shared/test/common/mocks/linux/mock_drm_command_stream_receiver.h"
#include "shared/test/common/mocks/linux/mock_drm_memory_manager.h"
#include "shared/test/common/mocks/mock_builtins.h"
#include "shared/test/common/mocks/mock_device.h"
#include "shared/test/common/mocks/mock_execution_environment.h"
#include "shared/test/common/os_interface/linux/device_command_stream_fixture.h"
#include <memory>
namespace NEO {
extern std::vector<void *> mmapVector;
class DrmMemoryManagerBasic : public ::testing::Test {
public:
DrmMemoryManagerBasic() : executionEnvironment(defaultHwInfo.get(), false, numRootDevices){};
void SetUp() override {
for (auto i = 0u; i < numRootDevices; i++) {
executionEnvironment.rootDeviceEnvironments[i]->osInterface = std::make_unique<OSInterface>();
auto drm = Drm::create(nullptr, *executionEnvironment.rootDeviceEnvironments[i]);
executionEnvironment.rootDeviceEnvironments[i]->osInterface->setDriverModel(std::unique_ptr<DriverModel>(drm));
executionEnvironment.rootDeviceEnvironments[i]->memoryOperationsInterface = DrmMemoryOperationsHandler::create(*drm, i);
}
}
const uint32_t rootDeviceIndex = 1u;
const uint32_t numRootDevices = 2u;
MockExecutionEnvironment executionEnvironment;
};
class DrmMemoryManagerFixture : public MemoryManagementFixture {
public:
DrmMockCustom *mock = nullptr;
bool dontTestIoctlInTearDown = false;
const uint32_t rootDeviceIndex = 1u;
const uint32_t numRootDevices = 2u;
TestedDrmMemoryManager *memoryManager = nullptr;
MockDevice *device = nullptr;
void SetUp() override {
MemoryManagementFixture::SetUp();
executionEnvironment = MockDevice::prepareExecutionEnvironment(defaultHwInfo.get(), numRootDevices - 1);
SetUp(new DrmMockCustom(*executionEnvironment->rootDeviceEnvironments[0]), false);
}
void SetUp(DrmMockCustom *mock, bool localMemoryEnabled) {
ASSERT_NE(nullptr, executionEnvironment);
executionEnvironment->incRefInternal();
DebugManager.flags.DeferOsContextInitialization.set(0);
environmentWrapper.setCsrType<TestedDrmCommandStreamReceiver<DEFAULT_TEST_FAMILY_NAME>>();
allocationData.rootDeviceIndex = rootDeviceIndex;
this->mock = mock;
for (auto i = 0u; i < numRootDevices; i++) {
auto rootDeviceEnvironment = executionEnvironment->rootDeviceEnvironments[i].get();
rootDeviceEnvironment->osInterface = std::make_unique<OSInterface>();
rootDeviceEnvironment->osInterface->setDriverModel(std::unique_ptr<DriverModel>(new DrmMockCustom(*rootDeviceEnvironment)));
rootDeviceEnvironment->memoryOperationsInterface = DrmMemoryOperationsHandler::create(*rootDeviceEnvironment->osInterface->getDriverModel()->as<Drm>(), i);
rootDeviceEnvironment->builtins.reset(new MockBuiltins);
}
rootDeviceEnvironment = executionEnvironment->rootDeviceEnvironments[rootDeviceIndex].get();
rootDeviceEnvironment->osInterface->setDriverModel(std::unique_ptr<DriverModel>(mock));
memoryManager = new (std::nothrow) TestedDrmMemoryManager(localMemoryEnabled, false, false, *executionEnvironment);
executionEnvironment->memoryManager.reset(memoryManager);
//assert we have memory manager
ASSERT_NE(nullptr, memoryManager);
if (memoryManager->getgemCloseWorker()) {
memoryManager->getgemCloseWorker()->close(true);
}
device = MockDevice::create<MockDevice>(executionEnvironment, rootDeviceIndex);
mock->reset();
}
void TearDown() override {
mock->testIoctls();
mock->reset();
int enginesCount = static_cast<int>(device->getMemoryManager()->getRegisteredEnginesCount());
mock->ioctl_expected.contextDestroy = enginesCount;
mock->ioctl_expected.gemClose = enginesCount;
mock->ioctl_expected.gemWait = enginesCount;
auto csr = static_cast<TestedDrmCommandStreamReceiver<DEFAULT_TEST_FAMILY_NAME> *>(device->getDefaultEngine().commandStreamReceiver);
if (csr->globalFenceAllocation) {
mock->ioctl_expected.gemClose += enginesCount;
mock->ioctl_expected.gemWait += enginesCount;
}
if (csr->getPreemptionAllocation()) {
mock->ioctl_expected.gemClose += enginesCount;
mock->ioctl_expected.gemWait += enginesCount;
}
mock->ioctl_expected.gemWait += additionalDestroyDeviceIoctls.gemWait.load();
mock->ioctl_expected.gemClose += additionalDestroyDeviceIoctls.gemClose.load();
delete device;
if (dontTestIoctlInTearDown) {
mock->reset();
}
mock->testIoctls();
executionEnvironment->decRefInternal();
MemoryManagementFixture::TearDown();
mmapVector.clear();
}
protected:
ExecutionEnvironment *executionEnvironment = nullptr;
RootDeviceEnvironment *rootDeviceEnvironment = nullptr;
DrmMockCustom::IoctlResExt ioctlResExt = {0, 0};
AllocationData allocationData{};
DrmMockCustom::Ioctls additionalDestroyDeviceIoctls{};
EnvironmentWithCsrWrapper environmentWrapper;
DebugManagerStateRestore restore;
};
class DrmMemoryManagerWithLocalMemoryFixture : public DrmMemoryManagerFixture {
public:
void SetUp() override {
backup = std::make_unique<VariableBackup<UltHwConfig>>(&ultHwConfig);
ultHwConfig.csrBaseCallCreatePreemption = false;
MemoryManagementFixture::SetUp();
executionEnvironment = MockDevice::prepareExecutionEnvironment(defaultHwInfo.get(), numRootDevices - 1);
DrmMemoryManagerFixture::SetUp(new DrmMockCustom(*executionEnvironment->rootDeviceEnvironments[0]), true);
}
void TearDown() override {
DrmMemoryManagerFixture::TearDown();
}
std::unique_ptr<VariableBackup<UltHwConfig>> backup;
};
struct MockMemoryInfoImpl : public NEO::MemoryInfo {
MockMemoryInfoImpl() {}
~MockMemoryInfoImpl() override{};
size_t getMemoryRegionSize(uint32_t memoryBank) override {
return 1024u;
}
uint32_t createGemExt(Drm *drm, void *data, uint32_t dataSize, size_t allocSize, uint32_t &handle) override {
if (allocSize == 0) {
return EINVAL;
}
handle = 1u;
return 0u;
}
uint32_t createGemExtWithSingleRegion(Drm *drm, uint32_t memoryBanks, size_t allocSize, uint32_t &handle) override {
if (allocSize == 0) {
return EINVAL;
}
handle = 1u;
return 0u;
}
};
class DrmMemoryManagerFixtureWithoutQuietIoctlExpectation {
public:
std::unique_ptr<TestedDrmMemoryManager> memoryManager;
DrmMockCustom *mock;
void SetUp() {
SetUp(false);
}
void SetUp(bool enableLocalMem) {
DebugManager.flags.DeferOsContextInitialization.set(0);
executionEnvironment = new ExecutionEnvironment;
executionEnvironment->prepareRootDeviceEnvironments(numRootDevices);
uint32_t i = 0;
for (auto &rootDeviceEnvironment : executionEnvironment->rootDeviceEnvironments) {
rootDeviceEnvironment->setHwInfo(defaultHwInfo.get());
rootDeviceEnvironment->osInterface = std::make_unique<OSInterface>();
rootDeviceEnvironment->osInterface->setDriverModel(std::unique_ptr<DriverModel>(new DrmMockCustom(*rootDeviceEnvironment)));
rootDeviceEnvironment->memoryOperationsInterface = DrmMemoryOperationsHandler::create(*rootDeviceEnvironment->osInterface->getDriverModel()->as<Drm>(), i);
i++;
}
mock = static_cast<DrmMockCustom *>(executionEnvironment->rootDeviceEnvironments[rootDeviceIndex]->osInterface->getDriverModel()->as<Drm>());
mock->memoryInfo.reset(new MockMemoryInfoImpl());
executionEnvironment->rootDeviceEnvironments[0]->memoryOperationsInterface = DrmMemoryOperationsHandler::create(*mock, 0u);
memoryManager.reset(new TestedDrmMemoryManager(enableLocalMem, false, false, *executionEnvironment));
ASSERT_NE(nullptr, memoryManager);
if (memoryManager->getgemCloseWorker()) {
memoryManager->getgemCloseWorker()->close(true);
}
device.reset(MockDevice::createWithExecutionEnvironment<MockDevice>(defaultHwInfo.get(), executionEnvironment, rootDeviceIndex));
}
void TearDown() {
}
protected:
ExecutionEnvironment *executionEnvironment = nullptr;
std::unique_ptr<MockDevice> device;
DrmMockCustom::IoctlResExt ioctlResExt = {0, 0};
DebugManagerStateRestore restore;
const uint32_t rootDeviceIndex = 1u;
const uint32_t numRootDevices = 2u;
};
class DrmMemoryManagerFixtureWithLocalMemoryAndWithoutQuietIoctlExpectation : public DrmMemoryManagerFixtureWithoutQuietIoctlExpectation {
public:
void SetUp() {
DrmMemoryManagerFixtureWithoutQuietIoctlExpectation::SetUp(true);
}
void TearDown() {
DrmMemoryManagerFixtureWithoutQuietIoctlExpectation::TearDown();
}
};
} // namespace NEO

View File

@@ -18,8 +18,8 @@
#include "shared/test/common/libult/linux/drm_mock.h"
#include "shared/test/common/libult/ult_command_stream_receiver.h"
#include "shared/test/common/mocks/mock_device.h"
#include "shared/test/common/os_interface/linux/drm_memory_manager_tests.h"
#include "opencl/test/unit_test/os_interface/linux/drm_memory_manager_tests.h"
#include "test.h"
#include <memory>