From 9a95f3c62de1d813fcbf4ac46c18f57d995e1d46 Mon Sep 17 00:00:00 2001 From: Mateusz Jablonski Date: Thu, 25 Aug 2022 15:49:58 +0000 Subject: [PATCH] Propagate exec buffer error to L0 API level This change makes that drm file is opened in nonblocking mode for prelim kernels. In such case when calling exec buffer ioctl and get EAGAIN (aka EWOULDBLOCK) we may return error to API level Related-To: NEO-7144 Signed-off-by: Mateusz Jablonski --- .../core/source/cmdqueue/cmdqueue_hw.inl | 3 + .../test/unit_tests/mocks/mock_cmdqueue.h | 6 +- .../os_interface/linux/CMakeLists.txt | 12 +++ .../linux/cmdqueue_linux_tests.cpp | 74 +++++++++++++++++++ .../sources/cmdqueue/test_cmdqueue_1.cpp | 24 ++++++ .../source/command_stream/submission_status.h | 1 + .../drm_command_stream_bdw_and_later.inl | 3 + .../drm_command_stream_xehp_and_later.inl | 3 + shared/source/os_interface/linux/drm_neo.cpp | 8 ++ .../os_interface/linux/ioctl_helper.cpp | 1 + .../source/os_interface/linux/ioctl_helper.h | 5 +- .../linux/ioctl_helper_prelim.cpp | 9 +++ shared/source/os_interface/linux/sys_calls.h | 2 + .../os_interface/linux/sys_calls_linux.cpp | 7 ++ shared/test/common/libult/linux/drm_mock.cpp | 2 +- shared/test/common/libult/linux/drm_mock.h | 1 + .../linux/drm_buffer_object_fixture.h | 3 + .../linux/drm_command_stream_fixture.h | 10 ++- .../linux/sys_calls_linux_ult.cpp | 23 +++++- .../os_interface/linux/sys_calls_linux_ult.h | 4 + .../linux/drm_command_stream_tests.cpp | 26 +++++-- .../linux/drm_command_stream_tests_1.cpp | 6 -- .../linux/ioctl_helper_tests_prelim.cpp | 21 ++++++ .../linux/ioctl_helper_tests_upstream.cpp | 8 ++ 24 files changed, 244 insertions(+), 18 deletions(-) create mode 100644 level_zero/core/test/unit_tests/os_interface/linux/CMakeLists.txt create mode 100644 level_zero/core/test/unit_tests/os_interface/linux/cmdqueue_linux_tests.cpp diff --git a/level_zero/core/source/cmdqueue/cmdqueue_hw.inl b/level_zero/core/source/cmdqueue/cmdqueue_hw.inl index e391ab4314..c1010bb8a4 100644 --- a/level_zero/core/source/cmdqueue/cmdqueue_hw.inl +++ b/level_zero/core/source/cmdqueue/cmdqueue_hw.inl @@ -1116,6 +1116,9 @@ ze_result_t CommandQueueHw::handleSubmissionAndCompletionResults( if (submitRet == NEO::SubmissionStatus::OUT_OF_MEMORY) { completionRet = ZE_RESULT_ERROR_OUT_OF_DEVICE_MEMORY; } + if (submitRet == NEO::SubmissionStatus::OUT_OF_HOST_MEMORY) { + completionRet = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } } return completionRet; diff --git a/level_zero/core/test/unit_tests/mocks/mock_cmdqueue.h b/level_zero/core/test/unit_tests/mocks/mock_cmdqueue.h index 221a40af79..5d7bd1b3b5 100644 --- a/level_zero/core/test/unit_tests/mocks/mock_cmdqueue.h +++ b/level_zero/core/test/unit_tests/mocks/mock_cmdqueue.h @@ -92,6 +92,9 @@ struct MockCommandQueueHw : public L0::CommandQueueHw { NEO::SubmissionStatus submitBatchBuffer(size_t offset, NEO::ResidencyContainer &residencyContainer, void *endingCmdPtr, bool isCooperative) override { residencyContainerSnapshot = residencyContainer; + if (submitBatchBufferReturnValue.has_value()) { + return *submitBatchBufferReturnValue; + } return BaseClass::submitBatchBuffer(offset, residencyContainer, endingCmdPtr, isCooperative); } @@ -99,6 +102,7 @@ struct MockCommandQueueHw : public L0::CommandQueueHw { NEO::ResidencyContainer residencyContainerSnapshot; ze_result_t synchronizeReturnValue{ZE_RESULT_SUCCESS}; std::optional reserveLinearStreamSizeReturnValue{}; + std::optional submitBatchBufferReturnValue{}; }; struct Deleter { @@ -108,4 +112,4 @@ struct Deleter { }; } // namespace ult -} // namespace L0 \ No newline at end of file +} // namespace L0 diff --git a/level_zero/core/test/unit_tests/os_interface/linux/CMakeLists.txt b/level_zero/core/test/unit_tests/os_interface/linux/CMakeLists.txt new file mode 100644 index 0000000000..cf9bea6cd6 --- /dev/null +++ b/level_zero/core/test/unit_tests/os_interface/linux/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (C) 2022 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +if(UNIX) + target_sources(${TARGET_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/cmdqueue_linux_tests.cpp + ) +endif() diff --git a/level_zero/core/test/unit_tests/os_interface/linux/cmdqueue_linux_tests.cpp b/level_zero/core/test/unit_tests/os_interface/linux/cmdqueue_linux_tests.cpp new file mode 100644 index 0000000000..05de580a79 --- /dev/null +++ b/level_zero/core/test/unit_tests/os_interface/linux/cmdqueue_linux_tests.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/test/common/helpers/ult_hw_config.h" +#include "shared/test/common/helpers/variable_backup.h" +#include "shared/test/common/libult/create_command_stream.h" +#include "shared/test/common/libult/linux/drm_mock.h" +#include "shared/test/common/test_macros/hw_test.h" + +#include "level_zero/core/test/unit_tests/fixtures/device_fixture.h" +#include "level_zero/core/test/unit_tests/mocks/mock_cmdlist.h" +#include "level_zero/core/test/unit_tests/mocks/mock_cmdqueue.h" +#include "level_zero/core/test/unit_tests/mocks/mock_kernel.h" + +namespace L0 { +namespace ult { + +struct CommandQueueLinuxTests : public Test { + + void SetUp() override { + VariableBackup backup(&ultHwConfig); + ultHwConfig.useMockedPrepareDeviceEnvironmentsFunc = false; + ultHwConfig.useHwCsr = true; + ultHwConfig.forceOsAgnosticMemoryManager = false; + auto *executionEnvironment = new NEO::ExecutionEnvironment(); + prepareDeviceEnvironments(*executionEnvironment); + executionEnvironment->initializeMemoryManager(); + setupWithExecutionEnvironment(*executionEnvironment); + } +}; + +HWCMDTEST_F(IGFX_XE_HP_CORE, CommandQueueLinuxTests, givenExecBufferErrorWhenExecutingCommandListsThenOutOfHostMemoryIsReturned) { + auto drm = neoDevice->getRootDeviceEnvironment().osInterface->getDriverModel()->as(); + + drm->execBufferResult = -1; + drm->baseErrno = false; + drm->errnoRetVal = EWOULDBLOCK; + const ze_command_queue_desc_t desc = {}; + ze_result_t returnValue; + auto commandQueue = whiteboxCast(CommandQueue::create(productFamily, + device, + neoDevice->getDefaultEngine().commandStreamReceiver, + &desc, + false, + false, + returnValue)); + + EXPECT_EQ(ZE_RESULT_SUCCESS, returnValue); + Mock kernel; + kernel.immutableData.isaGraphicsAllocation.reset(neoDevice->getMemoryManager()->allocateGraphicsMemoryWithProperties( + {device->getRootDeviceIndex(), MemoryConstants::pageSize, NEO::AllocationType::KERNEL_ISA, neoDevice->getDeviceBitfield()})); + kernel.immutableData.device = device; + + auto commandList = std::unique_ptr(whiteboxCast(CommandList::create(productFamily, device, NEO::EngineGroupType::RenderCompute, 0u, returnValue))); + EXPECT_EQ(ZE_RESULT_SUCCESS, returnValue); + ASSERT_NE(nullptr, commandList); + + ze_group_count_t dispatchFunctionArguments{1, 1, 1}; + CmdListKernelLaunchParams launchParams = {}; + commandList->appendLaunchKernel(kernel.toHandle(), &dispatchFunctionArguments, nullptr, 0, nullptr, launchParams); + + ze_command_list_handle_t cmdListHandles[1] = {commandList->toHandle()}; + + returnValue = commandQueue->executeCommandLists(1, cmdListHandles, nullptr, false); + EXPECT_EQ(ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY, returnValue); + commandQueue->destroy(); + neoDevice->getMemoryManager()->freeGraphicsMemory(kernel.immutableData.isaGraphicsAllocation.release()); +} +} // namespace ult +} // namespace L0 diff --git a/level_zero/core/test/unit_tests/sources/cmdqueue/test_cmdqueue_1.cpp b/level_zero/core/test/unit_tests/sources/cmdqueue/test_cmdqueue_1.cpp index 76c70dc0bf..46fea3fe63 100644 --- a/level_zero/core/test/unit_tests/sources/cmdqueue/test_cmdqueue_1.cpp +++ b/level_zero/core/test/unit_tests/sources/cmdqueue/test_cmdqueue_1.cpp @@ -357,6 +357,30 @@ HWTEST2_F(CommandQueueCreate, givenLogicalStateHelperAndImmediateCmdListWhenExec commandQueue->destroy(); } +HWTEST2_F(CommandQueueCreate, givenOutOfHostMemoryErrorFromSubmitBatchBufferWhenExecutingCommandListsThenOutOfHostMemoryIsReturned, IsAtLeastSkl) { + const ze_command_queue_desc_t desc = {}; + auto commandQueue = new MockCommandQueueHw(device, neoDevice->getDefaultEngine().commandStreamReceiver, &desc); + commandQueue->initialize(false, false); + commandQueue->submitBatchBufferReturnValue = NEO::SubmissionStatus::OUT_OF_HOST_MEMORY; + + Mock kernel; + kernel.immutableData.device = device; + + ze_result_t returnValue; + auto commandList = std::unique_ptr(whiteboxCast(CommandList::create(productFamily, device, NEO::EngineGroupType::RenderCompute, 0u, returnValue))); + ASSERT_NE(nullptr, commandList); + + ze_group_count_t dispatchFunctionArguments{1, 1, 1}; + CmdListKernelLaunchParams launchParams = {}; + commandList->appendLaunchKernel(kernel.toHandle(), &dispatchFunctionArguments, nullptr, 0, nullptr, launchParams); + + ze_command_list_handle_t cmdListHandles[1] = {commandList->toHandle()}; + + const auto result = commandQueue->executeCommandLists(1, cmdListHandles, nullptr, false); + EXPECT_EQ(ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY, result); + commandQueue->destroy(); +} + HWTEST2_F(CommandQueueCreate, givenGpuHangInReservingLinearStreamWhenExecutingCommandListsThenDeviceLostIsReturned, IsSKL) { const ze_command_queue_desc_t desc = {}; MockCommandQueueHw commandQueue(device, neoDevice->getDefaultEngine().commandStreamReceiver, &desc); diff --git a/shared/source/command_stream/submission_status.h b/shared/source/command_stream/submission_status.h index 40dc2dd2fa..1a5bf38ec3 100644 --- a/shared/source/command_stream/submission_status.h +++ b/shared/source/command_stream/submission_status.h @@ -14,6 +14,7 @@ enum class SubmissionStatus : uint32_t { SUCCESS = 0, FAILED, OUT_OF_MEMORY, + OUT_OF_HOST_MEMORY, UNSUPPORTED, DEVICE_UNINITIALIZED, }; diff --git a/shared/source/os_interface/linux/drm_command_stream_bdw_and_later.inl b/shared/source/os_interface/linux/drm_command_stream_bdw_and_later.inl index d34e4d3aaa..a229c7b686 100644 --- a/shared/source/os_interface/linux/drm_command_stream_bdw_and_later.inl +++ b/shared/source/os_interface/linux/drm_command_stream_bdw_and_later.inl @@ -20,6 +20,9 @@ SubmissionStatus DrmCommandStreamReceiver::flushInternal(const BatchB int ret = this->exec(batchBuffer, 0u, static_cast(osContext)->getDrmContextIds()[0], 0); if (ret) { + if (ret == EWOULDBLOCK) { + return SubmissionStatus::OUT_OF_HOST_MEMORY; + } return SubmissionStatus::FAILED; } return SubmissionStatus::SUCCESS; diff --git a/shared/source/os_interface/linux/drm_command_stream_xehp_and_later.inl b/shared/source/os_interface/linux/drm_command_stream_xehp_and_later.inl index 0d7a30b286..2a84a42c54 100644 --- a/shared/source/os_interface/linux/drm_command_stream_xehp_and_later.inl +++ b/shared/source/os_interface/linux/drm_command_stream_xehp_and_later.inl @@ -39,6 +39,9 @@ SubmissionStatus DrmCommandStreamReceiver::flushInternal(const BatchB int ret = this->exec(batchBuffer, tileIterator, drmContextIds[contextIndex], contextIndex); if (ret) { + if (ret == EWOULDBLOCK) { + return SubmissionStatus::OUT_OF_HOST_MEMORY; + } return SubmissionStatus::FAILED; } diff --git a/shared/source/os_interface/linux/drm_neo.cpp b/shared/source/os_interface/linux/drm_neo.cpp index 4ce2df9aac..9397493e96 100644 --- a/shared/source/os_interface/linux/drm_neo.cpp +++ b/shared/source/os_interface/linux/drm_neo.cpp @@ -58,6 +58,10 @@ void Drm::queryAndSetVmBindPatIndexProgrammingSupport() { } int Drm::ioctl(DrmIoctl request, void *arg) { + auto shouldBreakIoctlLoopOnWouldBlock = false; + if (ioctlHelper) { + shouldBreakIoctlLoopOnWouldBlock = ioctlHelper->shouldBreakIoctlLoopOnWouldBlock(request); + } auto requestValue = getIoctlRequestValue(request, ioctlHelper.get()); int ret; int returnedErrno; @@ -108,6 +112,10 @@ int Drm::ioctl(DrmIoctl request, void *arg) { } } + if (ret == -1 && returnedErrno == EWOULDBLOCK && shouldBreakIoctlLoopOnWouldBlock) { + break; + } + } while (ret == -1 && (returnedErrno == EINTR || returnedErrno == EAGAIN || returnedErrno == EBUSY || returnedErrno == -EBUSY)); SYSTEM_LEAVE(request); return ret; diff --git a/shared/source/os_interface/linux/ioctl_helper.cpp b/shared/source/os_interface/linux/ioctl_helper.cpp index 3f02558806..eaa8d8e29d 100644 --- a/shared/source/os_interface/linux/ioctl_helper.cpp +++ b/shared/source/os_interface/linux/ioctl_helper.cpp @@ -369,4 +369,5 @@ std::string IoctlHelper::getFileForMaxMemoryFrequencyOfSubDevice(int subDeviceId return "/gt/gt" + std::to_string(subDeviceId) + "/mem_RP0_freq_mhz"; } +bool IoctlHelper::shouldBreakIoctlLoopOnWouldBlock(DrmIoctl ioctlRequest) const { return false; } } // namespace NEO diff --git a/shared/source/os_interface/linux/ioctl_helper.h b/shared/source/os_interface/linux/ioctl_helper.h index 8f61d5fd03..adca548518 100644 --- a/shared/source/os_interface/linux/ioctl_helper.h +++ b/shared/source/os_interface/linux/ioctl_helper.h @@ -136,6 +136,8 @@ class IoctlHelper { uint32_t getFlagsForPrimeHandleToFd() const; + virtual bool shouldBreakIoctlLoopOnWouldBlock(DrmIoctl ioctlRequest) const; + protected: Drm &drm; }; @@ -207,7 +209,7 @@ class IoctlHelperImpl : public IoctlHelperUpstream { class IoctlHelperPrelim20 : public IoctlHelper { public: - using IoctlHelper::IoctlHelper; + IoctlHelperPrelim20(Drm &drmArg); bool initialize() override; bool isSetPairAvailable() override; @@ -254,6 +256,7 @@ class IoctlHelperPrelim20 : public IoctlHelper { int getDrmParamValue(DrmParam drmParam) const override; std::string getDrmParamString(DrmParam param) const override; std::string getIoctlString(DrmIoctl ioctlRequest) const override; + bool shouldBreakIoctlLoopOnWouldBlock(DrmIoctl ioctlRequest) const override; }; } // namespace NEO diff --git a/shared/source/os_interface/linux/ioctl_helper_prelim.cpp b/shared/source/os_interface/linux/ioctl_helper_prelim.cpp index c4587e613d..0b41ba6f5d 100644 --- a/shared/source/os_interface/linux/ioctl_helper_prelim.cpp +++ b/shared/source/os_interface/linux/ioctl_helper_prelim.cpp @@ -12,9 +12,11 @@ #include "shared/source/helpers/ptr_math.h" #include "shared/source/helpers/string.h" #include "shared/source/os_interface/linux/cache_info.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/ioctl_helper.h" +#include "shared/source/os_interface/linux/sys_calls.h" #include #include @@ -25,6 +27,11 @@ namespace NEO { +IoctlHelperPrelim20::IoctlHelperPrelim20(Drm &drmArg) : IoctlHelper(drmArg) { + auto fileDescriptor = this->drm.getFileDescriptor(); + SysCalls::fcntl(fileDescriptor, F_SETFL, SysCalls::fcntl(fileDescriptor, F_GETFL) | O_NONBLOCK); +}; + bool IoctlHelperPrelim20::isSetPairAvailable() { int setPairSupported = 0; GetParam getParam{}; @@ -645,6 +652,8 @@ std::string IoctlHelperPrelim20::getIoctlString(DrmIoctl ioctlRequest) const { } } +bool IoctlHelperPrelim20::shouldBreakIoctlLoopOnWouldBlock(DrmIoctl ioctlRequest) const { return ioctlRequest == DrmIoctl::GemExecbuffer2; } + static_assert(sizeof(MemoryClassInstance) == sizeof(prelim_drm_i915_gem_memory_class_instance)); static_assert(offsetof(MemoryClassInstance, memoryClass) == offsetof(prelim_drm_i915_gem_memory_class_instance, memory_class)); static_assert(offsetof(MemoryClassInstance, memoryInstance) == offsetof(prelim_drm_i915_gem_memory_class_instance, memory_instance)); diff --git a/shared/source/os_interface/linux/sys_calls.h b/shared/source/os_interface/linux/sys_calls.h index 07f0026437..9c9f97eca3 100644 --- a/shared/source/os_interface/linux/sys_calls.h +++ b/shared/source/os_interface/linux/sys_calls.h @@ -29,5 +29,7 @@ ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); void *mmap(void *addr, size_t size, int prot, int flags, int fd, off_t off); int munmap(void *addr, size_t size); ssize_t read(int fd, void *buf, size_t count); +int fcntl(int fd, int cmd); +int fcntl(int fd, int cmd, int arg); } // namespace SysCalls } // namespace NEO diff --git a/shared/source/os_interface/linux/sys_calls_linux.cpp b/shared/source/os_interface/linux/sys_calls_linux.cpp index 92e3e1568d..0376929e45 100644 --- a/shared/source/os_interface/linux/sys_calls_linux.cpp +++ b/shared/source/os_interface/linux/sys_calls_linux.cpp @@ -93,5 +93,12 @@ ssize_t read(int fd, void *buf, size_t count) { return ::read(fd, buf, count); } +int fcntl(int fd, int cmd) { + return ::fcntl(fd, cmd); +} +int fcntl(int fd, int cmd, int arg) { + return ::fcntl(fd, cmd, arg); +} + } // namespace SysCalls } // namespace NEO diff --git a/shared/test/common/libult/linux/drm_mock.cpp b/shared/test/common/libult/linux/drm_mock.cpp index 6b60b81735..1f642795fb 100644 --- a/shared/test/common/libult/linux/drm_mock.cpp +++ b/shared/test/common/libult/linux/drm_mock.cpp @@ -193,7 +193,7 @@ int DrmMock::ioctl(DrmIoctl request, void *arg) { for (uint32_t i = 0; i < execbuf->getBufferCount(); i++) { this->receivedBos.push_back(execObjects[i]); } - return 0; + return execBufferResult; } if (request == DrmIoctl::GemUserptr) { ioctlCount.gemUserptr++; diff --git a/shared/test/common/libult/linux/drm_mock.h b/shared/test/common/libult/linux/drm_mock.h index 011126c39c..74ed24e1e0 100644 --- a/shared/test/common/libult/linux/drm_mock.h +++ b/shared/test/common/libult/linux/drm_mock.h @@ -212,6 +212,7 @@ class DrmMock : public Drm { //DRM_IOCTL_I915_GEM_EXECBUFFER2 std::vector execBuffers{}; std::vector receivedBos{}; + int execBufferResult = 0; //DRM_IOCTL_I915_GEM_CREATE uint64_t createParamsSize = 0; uint32_t createParamsHandle = 0; diff --git a/shared/test/common/os_interface/linux/drm_buffer_object_fixture.h b/shared/test/common/os_interface/linux/drm_buffer_object_fixture.h index 8b7b1db0a6..904699a96a 100644 --- a/shared/test/common/os_interface/linux/drm_buffer_object_fixture.h +++ b/shared/test/common/os_interface/linux/drm_buffer_object_fixture.h @@ -8,12 +8,15 @@ #pragma once #include "shared/source/os_interface/linux/drm_buffer_object.h" #include "shared/source/os_interface/linux/drm_memory_operations_handler_default.h" +#include "shared/source/os_interface/linux/drm_wrappers.h" #include "shared/source/os_interface/linux/os_context_linux.h" #include "shared/test/common/helpers/engine_descriptor_helper.h" #include "shared/test/common/mocks/mock_execution_environment.h" #include +using namespace NEO; + class TestedBufferObject : public BufferObject { public: using BufferObject::handle; diff --git a/shared/test/common/os_interface/linux/drm_command_stream_fixture.h b/shared/test/common/os_interface/linux/drm_command_stream_fixture.h index 60414aaac4..2156fa568d 100644 --- a/shared/test/common/os_interface/linux/drm_command_stream_fixture.h +++ b/shared/test/common/os_interface/linux/drm_command_stream_fixture.h @@ -20,6 +20,14 @@ #include +template +struct MockDrmCsr : public DrmCommandStreamReceiver { + using DrmCommandStreamReceiver::DrmCommandStreamReceiver; + using DrmCommandStreamReceiver::dispatchMode; + using DrmCommandStreamReceiver::completionFenceValuePointer; + using DrmCommandStreamReceiver::flushInternal; +}; + class DrmCommandStreamTest : public ::testing::Test { public: template @@ -43,7 +51,7 @@ class DrmCommandStreamTest : public ::testing::Test { PreemptionHelper::getDefaultPreemptionMode(*hwInfo))); osContext->ensureContextInitialized(); - csr = new DrmCommandStreamReceiver(executionEnvironment, 0, 1, gemCloseWorkerMode::gemCloseWorkerActive); + csr = new MockDrmCsr(executionEnvironment, 0, 1, gemCloseWorkerMode::gemCloseWorkerActive); ASSERT_NE(nullptr, csr); csr->setupContext(*osContext); diff --git a/shared/test/common/os_interface/linux/sys_calls_linux_ult.cpp b/shared/test/common/os_interface/linux/sys_calls_linux_ult.cpp index 636016ef93..802a2fe282 100644 --- a/shared/test/common/os_interface/linux/sys_calls_linux_ult.cpp +++ b/shared/test/common/os_interface/linux/sys_calls_linux_ult.cpp @@ -5,6 +5,8 @@ * */ +#include "shared/test/common/os_interface/linux/sys_calls_linux_ult.h" + #include "shared/source/helpers/string.h" #include "shared/source/os_interface/linux/drm_wrappers.h" #include "shared/source/os_interface/linux/i915.h" @@ -17,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +34,6 @@ int closeFuncArgPassed = 0; int closeFuncRetVal = 0; int dlOpenFlags = 0; bool dlOpenCalled = 0; -constexpr int fakeFileDescriptor = 123; bool makeFakeDevicePath = false; bool allowFakeDevicePath = false; constexpr unsigned long int invalidIoctl = static_cast(-1); @@ -43,6 +45,9 @@ uint32_t mmapFuncCalled = 0u; uint32_t munmapFuncCalled = 0u; bool isInvalidAILTest = false; const char *drmVersion = "i915"; +int passedFileDescriptorFlagsToSet = 0; +int getFileDescriptorFlagsCalled = 0; +int setFileDescriptorFlagsCalled = 0; int (*sysCallsOpen)(const char *pathname, int flags) = nullptr; ssize_t (*sysCallsPread)(int fd, void *buf, size_t count, off_t offset) = nullptr; @@ -195,5 +200,21 @@ ssize_t read(int fd, void *buf, size_t count) { return 0; } +int fcntl(int fd, int cmd) { + if (cmd == F_GETFL) { + getFileDescriptorFlagsCalled++; + return O_RDWR; + } + return 0; +} +int fcntl(int fd, int cmd, int arg) { + if (cmd == F_SETFL) { + setFileDescriptorFlagsCalled++; + passedFileDescriptorFlagsToSet = arg; + } + + return 0; +} + } // namespace SysCalls } // namespace NEO diff --git a/shared/test/common/os_interface/linux/sys_calls_linux_ult.h b/shared/test/common/os_interface/linux/sys_calls_linux_ult.h index fd36b5bbab..b216146ba0 100644 --- a/shared/test/common/os_interface/linux/sys_calls_linux_ult.h +++ b/shared/test/common/os_interface/linux/sys_calls_linux_ult.h @@ -21,5 +21,9 @@ extern int (*sysCallsPoll)(struct pollfd *pollFd, unsigned long int numberOfFds, extern ssize_t (*sysCallsRead)(int fd, void *buf, size_t count); extern const char *drmVersion; +constexpr int fakeFileDescriptor = 123; +extern int passedFileDescriptorFlagsToSet; +extern int getFileDescriptorFlagsCalled; +extern int setFileDescriptorFlagsCalled; } // namespace SysCalls } // namespace NEO diff --git a/shared/test/unit_test/os_interface/linux/drm_command_stream_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_command_stream_tests.cpp index f6bffdfec6..522991b20b 100644 --- a/shared/test/unit_test/os_interface/linux/drm_command_stream_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_command_stream_tests.cpp @@ -6,7 +6,9 @@ */ #include "shared/source/helpers/api_specific_config.h" +#include "shared/test/common/mocks/linux/mock_drm_allocation.h" #include "shared/test/common/mocks/mock_graphics_allocation.h" +#include "shared/test/common/os_interface/linux/drm_buffer_object_fixture.h" #include "shared/test/common/os_interface/linux/drm_command_stream_fixture.h" #include "shared/test/common/test_macros/hw_test.h" @@ -15,13 +17,6 @@ extern ApiSpecificConfig::ApiType apiTypeForUlts; } //namespace NEO using namespace NEO; -template -struct MockDrmCsr : public DrmCommandStreamReceiver { - using DrmCommandStreamReceiver::DrmCommandStreamReceiver; - using DrmCommandStreamReceiver::dispatchMode; - using DrmCommandStreamReceiver::completionFenceValuePointer; -}; - HWTEST_TEMPLATED_F(DrmCommandStreamTest, givenL0ApiConfigWhenCreatingDrmCsrThenEnableImmediateDispatch) { VariableBackup backup(&apiTypeForUlts, ApiSpecificConfig::L0); MockDrmCsr csr(executionEnvironment, 0, 1, gemCloseWorkerMode::gemCloseWorkerInactive); @@ -75,3 +70,20 @@ HWTEST_TEMPLATED_F(DrmCommandStreamTest, givenNoTagAddressWhenGettingCompletionA EXPECT_EQ(nullptr, csr->getTagAddress()); EXPECT_EQ(0u, csr->getCompletionAddress()); } + +HWTEST_TEMPLATED_F(DrmCommandStreamTest, GivenExecBufferErrorWhenFlushInternalThenProperErrorIsReturned) { + mock->execBufferResult = -1; + mock->baseErrno = false; + mock->errnoRetVal = EWOULDBLOCK; + TestedBufferObject bo(mock, 128); + MockDrmAllocation cmdBuffer(AllocationType::COMMAND_BUFFER, MemoryPool::System4KBPages); + cmdBuffer.bufferObjects[0] = &bo; + uint8_t buff[128]{}; + + LinearStream cs(&cmdBuffer, buff, 128); + + BatchBuffer batchBuffer{cs.getGraphicsAllocation(), 0, 0, nullptr, false, false, QueueThrottle::MEDIUM, QueueSliceCount::defaultSliceCount, cs.getUsed(), &cs, nullptr, false}; + + auto ret = static_cast *>(csr)->flushInternal(batchBuffer, csr->getResidencyAllocations()); + EXPECT_EQ(SubmissionStatus::OUT_OF_HOST_MEMORY, ret); +} diff --git a/shared/test/unit_test/os_interface/linux/drm_command_stream_tests_1.cpp b/shared/test/unit_test/os_interface/linux/drm_command_stream_tests_1.cpp index 3dee8a3b34..d5ab68867d 100644 --- a/shared/test/unit_test/os_interface/linux/drm_command_stream_tests_1.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_command_stream_tests_1.cpp @@ -884,12 +884,6 @@ HWTEST_TEMPLATED_F(DrmCommandStreamBlitterDirectSubmissionTest, givenEnabledDire EXPECT_EQ(nullptr, static_cast *>(csr)->directSubmission.get()); } -template -struct MockDrmCsr : public DrmCommandStreamReceiver { - using DrmCommandStreamReceiver::DrmCommandStreamReceiver; - using DrmCommandStreamReceiver::dispatchMode; -}; - HWTEST_TEMPLATED_F(DrmCommandStreamTest, givenDrmCommandStreamReceiverWhenCreatePageTableManagerIsCalledThenCreatePageTableManager) { executionEnvironment.prepareRootDeviceEnvironments(2); executionEnvironment.rootDeviceEnvironments[1]->setHwInfo(defaultHwInfo.get()); diff --git a/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_prelim.cpp b/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_prelim.cpp index b95b37145a..e872c18e7c 100644 --- a/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_prelim.cpp +++ b/shared/test/unit_test/os_interface/linux/ioctl_helper_tests_prelim.cpp @@ -10,7 +10,9 @@ #include "shared/source/os_interface/linux/i915_prelim.h" #include "shared/source/os_interface/linux/ioctl_helper.h" #include "shared/test/common/helpers/debug_manager_state_restore.h" +#include "shared/test/common/helpers/variable_backup.h" #include "shared/test/common/mocks/mock_execution_environment.h" +#include "shared/test/common/os_interface/linux/sys_calls_linux_ult.h" #include "shared/test/common/test_macros/test.h" using namespace NEO; @@ -348,3 +350,22 @@ TEST_F(IoctlPrelimHelperTests, givenPrelimWhenGettingEuStallPropertiesThenCorrec TEST_F(IoctlPrelimHelperTests, givenPrelimWhenGettingEuStallFdParameterThenCorrectIoctlValueIsReturned) { EXPECT_EQ(static_cast(PRELIM_I915_PERF_FLAG_FD_EU_STALL), ioctlHelper.getEuStallFdParameter()); } +TEST_F(IoctlPrelimHelperTests, whenCallingIoctlWithGemExecbufferThenShouldBreakOnWouldBlock) { + EXPECT_TRUE(ioctlHelper.shouldBreakIoctlLoopOnWouldBlock(DrmIoctl::GemExecbuffer2)); + EXPECT_FALSE(ioctlHelper.shouldBreakIoctlLoopOnWouldBlock(DrmIoctl::GemVmBind)); +} + +TEST(IoctlPrelimHelperTest, whenCreatingIoctlHelperThenProperFlagsAreSetToFileDescriptor) { + MockExecutionEnvironment executionEnvironment{}; + std::unique_ptr drm{Drm::create(std::make_unique(0, ""), *executionEnvironment.rootDeviceEnvironments[0])}; + + VariableBackup backupGetFlags(&SysCalls::getFileDescriptorFlagsCalled, 0); + VariableBackup backupSetFlags(&SysCalls::setFileDescriptorFlagsCalled, 0); + VariableBackup backupPassedFlags(&SysCalls::passedFileDescriptorFlagsToSet, 0); + + IoctlHelperPrelim20 ioctlHelper{*drm}; + + EXPECT_EQ(1, SysCalls::getFileDescriptorFlagsCalled); + EXPECT_EQ(1, SysCalls::setFileDescriptorFlagsCalled); + EXPECT_EQ((O_RDWR | O_NONBLOCK), SysCalls::passedFileDescriptorFlagsToSet); +} 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 03c81d55b7..7a1e7001dd 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 @@ -477,3 +477,11 @@ TEST(IoctlHelperTestsUpstream, givenUpstreamWhenInitializingThenTrueIsReturned) IoctlHelperUpstream ioctlHelper{*drm}; EXPECT_EQ(true, ioctlHelper.initialize()); } + +TEST(IoctlHelperUpstreamTest, whenCallingIoctlWithGemExecbufferThenShouldNotBreakOnWouldBlock) { + auto executionEnvironment = std::make_unique(); + auto drm = std::make_unique(*executionEnvironment->rootDeviceEnvironments[0]); + IoctlHelperUpstream ioctlHelper{*drm}; + EXPECT_FALSE(ioctlHelper.shouldBreakIoctlLoopOnWouldBlock(DrmIoctl::GemExecbuffer2)); + EXPECT_FALSE(ioctlHelper.shouldBreakIoctlLoopOnWouldBlock(DrmIoctl::GemVmBind)); +}