feature: exit with warning if small bar detected on Linux

Return early and provide justification, otherwise SIGBUS error is
returned.

Related-To: NEO-14506
Signed-off-by: Maciej Bielski <maciej.bielski@intel.com>
This commit is contained in:
Maciej Bielski
2025-04-09 21:32:48 +00:00
committed by Compute-Runtime-Automation
parent e82be94368
commit 6ecf5b373e
12 changed files with 148 additions and 35 deletions

View File

@@ -510,6 +510,9 @@ int Drm::setupHardwareInfo(const DeviceDescriptor *device, bool setupFeatureTabl
if (!queryMemoryInfo()) {
setPerContextVMRequired(true);
printDebugString(debugManager.flags.PrintDebugMessages.get(), stderr, "%s", "WARNING: Failed to query memory info\n");
} else if (getMemoryInfo()->isSmallBarDetected()) {
IoFunctions::fprintf(stderr, "WARNING: Small BAR detected for device %s\n", getPciPath().c_str());
return -1;
}
if (!queryEngineInfo()) {

View File

@@ -46,6 +46,7 @@ struct MemoryRegion {
MemoryClassInstance region;
uint64_t probedSize;
uint64_t unallocatedSize;
uint64_t cpuVisibleSize;
std::bitset<4> tilesMask;
};

View File

@@ -26,6 +26,7 @@
#include "shared/source/utilities/directory.h"
#include <fcntl.h>
#include <span>
#include <sstream>
namespace NEO {
@@ -183,11 +184,13 @@ std::vector<EngineCapabilities> IoctlHelperI915::translateToEngineCaps(const std
}
std::vector<MemoryRegion> IoctlHelperI915::translateToMemoryRegions(const std::vector<uint64_t> &regionInfo) {
auto *data = reinterpret_cast<const drm_i915_query_memory_regions *>(regionInfo.data());
auto memRegions = std::vector<MemoryRegion>(data->num_regions);
for (uint32_t i = 0; i < data->num_regions; i++) {
memRegions[i].probedSize = data->regions[i].probed_size;
memRegions[i].unallocatedSize = data->regions[i].unallocated_size;
memRegions[i].cpuVisibleSize = data->regions[i].probed_cpu_visible_size;
memRegions[i].region.memoryClass = data->regions[i].region.memory_class;
memRegions[i].region.memoryInstance = data->regions[i].region.memory_instance;
}

View File

@@ -17,6 +17,7 @@
#include "shared/source/os_interface/linux/numa_library.h"
#include "shared/source/os_interface/product_helper.h"
#include <algorithm>
#include <iostream>
namespace NEO {
@@ -27,10 +28,16 @@ MemoryInfo::MemoryInfo(const RegionContainer &regionInfo, const Drm &inputDrm)
const auto memoryClassSystem = ioctlHelper->getDrmParamValue(DrmParam::memoryClassSystem);
const auto memoryClassDevice = ioctlHelper->getDrmParamValue(DrmParam::memoryClassDevice);
UNRECOVERABLE_IF(this->systemMemoryRegion.region.memoryClass != memoryClassSystem);
std::copy_if(drmQueryRegions.begin(), drmQueryRegions.end(), std::back_inserter(localMemoryRegions),
[&](const MemoryRegion &memoryRegionInfo) {
return (memoryRegionInfo.region.memoryClass == memoryClassDevice);
});
std::ranges::copy_if(drmQueryRegions, std::back_inserter(localMemoryRegions),
[memoryClassDevice](const MemoryRegion &memoryRegionInfo) {
return (memoryRegionInfo.region.memoryClass == memoryClassDevice);
});
smallBarDetected = std::ranges::any_of(localMemoryRegions,
[](const MemoryRegion &region) {
return (region.cpuVisibleSize && region.cpuVisibleSize < region.probedSize);
});
populateTileToLocalMemoryRegionIndexMap();

View File

@@ -47,6 +47,7 @@ class MemoryInfo {
const RegionContainer &getLocalMemoryRegions() const { return localMemoryRegions; }
const RegionContainer &getDrmRegionInfos() const { return drmQueryRegions; }
bool isMemPolicySupported() const { return memPolicySupported; }
bool isSmallBarDetected() const { return smallBarDetected; }
protected:
const Drm &drm;
@@ -57,6 +58,7 @@ class MemoryInfo {
int memPolicyMode;
RegionContainer localMemoryRegions;
std::array<uint32_t, 4> tileToLocalMemoryRegionIndexMap{};
bool smallBarDetected;
};
} // namespace NEO

View File

@@ -373,13 +373,15 @@ std::unique_ptr<EngineInfo> IoctlHelperXe::createEngineInfo(bool isSysmanEnabled
}
inline MemoryRegion createMemoryRegionFromXeMemRegion(const drm_xe_mem_region &xeMemRegion, std::bitset<4> tilesMask) {
MemoryRegion memoryRegion{};
memoryRegion.region.memoryInstance = xeMemRegion.instance;
memoryRegion.region.memoryClass = xeMemRegion.mem_class;
memoryRegion.probedSize = xeMemRegion.total_size;
memoryRegion.unallocatedSize = xeMemRegion.total_size - xeMemRegion.used;
memoryRegion.tilesMask = tilesMask;
return memoryRegion;
return {
.region{
.memoryClass = xeMemRegion.mem_class,
.memoryInstance = xeMemRegion.instance},
.probedSize = xeMemRegion.total_size,
.unallocatedSize = xeMemRegion.total_size - xeMemRegion.used,
.cpuVisibleSize = xeMemRegion.cpu_visible_size,
.tilesMask = tilesMask,
};
}
std::unique_ptr<MemoryInfo> IoctlHelperXe::createMemoryInfo() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2024 Intel Corporation
* Copyright (C) 2020-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -19,6 +19,7 @@ const std::vector<NEO::MemoryRegion> memoryRegions = {
struct MockMemoryInfo : public NEO::MemoryInfo {
using NEO::MemoryInfo::localMemoryRegions;
using NEO::MemoryInfo::smallBarDetected;
MockMemoryInfo(const NEO::Drm &drm) : MemoryInfo(memoryRegions, drm) {}
};

View File

@@ -285,25 +285,28 @@ void DrmMockXe::initInstance() {
auto xeQueryMemUsage = reinterpret_cast<drm_xe_query_mem_regions *>(this->queryMemUsage);
xeQueryMemUsage->num_mem_regions = 3;
xeQueryMemUsage->mem_regions[0] = {
DRM_XE_MEM_REGION_CLASS_VRAM, // class
1, // instance
MemoryConstants::pageSize, // min page size
2 * MemoryConstants::gigaByte, // total size
MemoryConstants::megaByte // used size
.mem_class = DRM_XE_MEM_REGION_CLASS_VRAM,
.instance = 1,
.min_page_size = MemoryConstants::pageSize,
.total_size = 2 * MemoryConstants::gigaByte,
.used = MemoryConstants::megaByte,
.cpu_visible_size = 2 * MemoryConstants::gigaByte,
};
xeQueryMemUsage->mem_regions[1] = {
DRM_XE_MEM_REGION_CLASS_SYSMEM, // class
0, // instance
MemoryConstants::pageSize, // min page size
MemoryConstants::gigaByte, // total size
MemoryConstants::kiloByte // used size
.mem_class = DRM_XE_MEM_REGION_CLASS_SYSMEM,
.instance = 0,
.min_page_size = MemoryConstants::pageSize,
.total_size = MemoryConstants::gigaByte,
.used = MemoryConstants::kiloByte,
.cpu_visible_size = MemoryConstants::gigaByte,
};
xeQueryMemUsage->mem_regions[2] = {
DRM_XE_MEM_REGION_CLASS_VRAM, // class
2, // instance
MemoryConstants::pageSize, // min page size
4 * MemoryConstants::gigaByte, // total size
MemoryConstants::gigaByte // used size
.mem_class = DRM_XE_MEM_REGION_CLASS_VRAM,
.instance = 2,
.min_page_size = MemoryConstants::pageSize,
.total_size = 4 * MemoryConstants::gigaByte,
.used = MemoryConstants::gigaByte,
.cpu_visible_size = 4 * MemoryConstants::gigaByte,
};
this->queryGtList.resize(1 + (6 * 12)); // 1 qword for num gts and 12 qwords per gt

View File

@@ -27,6 +27,7 @@
#include "shared/test/common/mocks/linux/mock_ioctl_helper.h"
#include "shared/test/common/mocks/linux/mock_os_context_linux.h"
#include "shared/test/common/mocks/mock_execution_environment.h"
#include "shared/test/common/os_interface/linux/drm_mock_memory_info.h"
#include "shared/test/common/os_interface/linux/sys_calls_linux_ult.h"
#include "shared/test/common/test_macros/hw_test.h"
@@ -141,6 +142,33 @@ TEST(DrmTest, GivenValidSysfsNodeWhenGetDeviceMemoryMaxClockRateInMhzIsCalledThe
EXPECT_EQ(clkRate, 800u);
}
struct MockIoctlHelperForSmallBar : public IoctlHelperUpstream {
using IoctlHelperUpstream::IoctlHelperUpstream;
std::unique_ptr<MemoryInfo> createMemoryInfo() {
auto memoryInfo{new MockMemoryInfo{drm}};
memoryInfo->smallBarDetected = true;
return std::unique_ptr<MemoryInfo>{memoryInfo};
}
};
TEST(DrmTest, givenSmallBarDetectedInMemoryInfoWhenSetupHardwareInfoCalledThenErrorMessagePrinted) {
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]};
drm.setPciPath("0000:ab:cd.e");
auto setupHardwareInfo = [](HardwareInfo *hwInfo, bool, const ReleaseHelper *) {};
DeviceDescriptor device = {0, defaultHwInfo.get(), setupHardwareInfo};
auto mockIoctlHelper = std::make_unique<MockIoctlHelperForSmallBar>(drm);
drm.ioctlHelper.reset(mockIoctlHelper.release());
::testing::internal::CaptureStderr();
EXPECT_EQ(-1, drm.setupHardwareInfo(&device, false));
std::string output = testing::internal::GetCapturedStderr();
EXPECT_STREQ("WARNING: Small BAR detected for device 0000:ab:cd.e\n", output.c_str());
}
TEST(DrmTest, GivenMemoryInfoWithLocalMemoryRegionsWhenGetDeviceMemoryPhysicalSizeInBytesIsCalledThenCorrectSizeReturned) {
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]};

View File

@@ -194,9 +194,11 @@ TEST_F(IoctlPrelimHelperTests, givenPrelimsWhenTranslateToMemoryRegionsThenRetur
expectedMemRegions[0].region.memoryClass = prelim_drm_i915_gem_memory_class::PRELIM_I915_MEMORY_CLASS_SYSTEM;
expectedMemRegions[0].region.memoryInstance = 0;
expectedMemRegions[0].probedSize = 1024;
expectedMemRegions[0].cpuVisibleSize = 1024;
expectedMemRegions[1].region.memoryClass = prelim_drm_i915_gem_memory_class::PRELIM_I915_MEMORY_CLASS_DEVICE;
expectedMemRegions[1].region.memoryInstance = 0;
expectedMemRegions[1].probedSize = 1024;
expectedMemRegions[1].cpuVisibleSize = 256;
auto regionInfo = getRegionInfo(expectedMemRegions);
@@ -207,6 +209,7 @@ TEST_F(IoctlPrelimHelperTests, givenPrelimsWhenTranslateToMemoryRegionsThenRetur
EXPECT_EQ(expectedMemRegions[i].region.memoryInstance, memRegions[i].region.memoryInstance);
EXPECT_EQ(expectedMemRegions[i].probedSize, memRegions[i].probedSize);
EXPECT_EQ(expectedMemRegions[i].unallocatedSize, memRegions[i].unallocatedSize);
EXPECT_EQ(expectedMemRegions[i].cpuVisibleSize, memRegions[i].cpuVisibleSize);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2024 Intel Corporation
* Copyright (C) 2021-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -109,6 +109,7 @@ std::vector<uint64_t> getRegionInfo(const std::vector<MemoryRegion> &inputRegion
memoryRegions->regions[i].region.memory_instance = inputRegions[i].region.memoryInstance;
memoryRegions->regions[i].probed_size = inputRegions[i].probedSize;
memoryRegions->regions[i].unallocated_size = inputRegions[i].unallocatedSize;
memoryRegions->regions[i].rsvd1[0] = inputRegions[i].cpuVisibleSize;
}
return data;
}

View File

@@ -135,10 +135,10 @@ TEST_F(IoctlHelperXeTest, givenIoctlHelperXeWhenCallGemCreateAndNoLocalMemoryThe
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
ASSERT_NE(nullptr, xeIoctlHelper);
uint64_t size = 1234;
uint32_t memoryBanks = 3u;
@@ -166,10 +166,10 @@ TEST_F(IoctlHelperXeTest, givenIoctlHelperXeWhenCallGemCreateWhenMemoryBanksZero
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
ASSERT_NE(nullptr, xeIoctlHelper);
uint64_t size = 1234;
uint32_t memoryBanks = 0u;
@@ -197,10 +197,10 @@ TEST_F(IoctlHelperXeTest, givenIoctlHelperXeWhenCallGemCreateAndLocalMemoryThenP
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
ASSERT_NE(nullptr, xeIoctlHelper);
uint64_t size = 1234;
uint32_t memoryBanks = 3u;
@@ -227,10 +227,10 @@ TEST_F(IoctlHelperXeTest, givenIoctlHelperXeWhenCallingGemCreateWithRegionsAndCo
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
ASSERT_NE(nullptr, xeIoctlHelper);
bool isCoherent = true;
uint64_t size = 1234;
@@ -246,10 +246,10 @@ TEST_F(IoctlHelperXeTest, givenIoctlHelperXeWhenCallingGemCreateWithOnlySystemRe
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
ASSERT_NE(nullptr, xeIoctlHelper);
bool isCoherent = true;
uint64_t size = 1234;
@@ -259,6 +259,65 @@ TEST_F(IoctlHelperXeTest, givenIoctlHelperXeWhenCallingGemCreateWithOnlySystemRe
EXPECT_EQ(DRM_XE_GEM_CPU_CACHING_WB, drm->createParamsCpuCaching);
}
TEST_F(IoctlHelperXeTest, givenLmemRegionsCpuVisibleSizeEqualToProbedSizeWhenMemoryInfoCreatedThenSmallBarIsNotDetected) {
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
EXPECT_FALSE(drm->memoryInfo->isSmallBarDetected());
}
TEST_F(IoctlHelperXeTest, givenLmemRegionCpuVisibleSizeSmallerThanProbedSizeWhenMemoryInfoCreatedThenSmallBarIsDetected) {
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
auto xeQueryMemUsage = reinterpret_cast<drm_xe_query_mem_regions *>(drm->queryMemUsage);
auto &smallBarRegion = xeQueryMemUsage->mem_regions[0];
EXPECT_EQ(smallBarRegion.mem_class, DRM_XE_MEM_REGION_CLASS_VRAM);
smallBarRegion.cpu_visible_size = smallBarRegion.total_size - 1U;
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
EXPECT_TRUE(drm->memoryInfo->isSmallBarDetected());
}
TEST_F(IoctlHelperXeTest, givenLmemRegionCpuVisibleSizeBeingZeroWhenMemoryInfoCreatedThenSmallBarIsNotDetected) {
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
auto xeQueryMemUsage = reinterpret_cast<drm_xe_query_mem_regions *>(drm->queryMemUsage);
auto &smallBarRegion = xeQueryMemUsage->mem_regions[2];
EXPECT_EQ(smallBarRegion.mem_class, DRM_XE_MEM_REGION_CLASS_VRAM);
smallBarRegion.cpu_visible_size = 0U;
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
EXPECT_FALSE(drm->memoryInfo->isSmallBarDetected());
}
TEST_F(IoctlHelperXeTest, givenSysmemRegionCpuVisibleSizeSmallerThanProbedWhenMemoryInfoCreatedThenSmallBarIsDetected) {
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
auto xeQueryMemUsage = reinterpret_cast<drm_xe_query_mem_regions *>(drm->queryMemUsage);
auto &sysmemRegion = xeQueryMemUsage->mem_regions[1];
EXPECT_EQ(sysmemRegion.mem_class, DRM_XE_MEM_REGION_CLASS_SYSMEM);
sysmemRegion.cpu_visible_size = sysmemRegion.total_size - 1U;
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
EXPECT_FALSE(drm->memoryInfo->isSmallBarDetected());
}
TEST_F(IoctlHelperXeTest, givenIoctlHelperXeWhenCallSetGemTilingThenAlwaysTrue) {
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
@@ -1844,10 +1903,10 @@ TEST_F(IoctlHelperXeTest, givenIoctlHelperXeWhenGetCpuCachingModeCalledThenCorre
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
ASSERT_NE(nullptr, xeIoctlHelper);
EXPECT_EQ(xeIoctlHelper->getCpuCachingMode(false, false), DRM_XE_GEM_CPU_CACHING_WC);
EXPECT_EQ(xeIoctlHelper->getCpuCachingMode(false, true), DRM_XE_GEM_CPU_CACHING_WC);
@@ -1951,10 +2010,10 @@ TEST_F(IoctlHelperXeTest, whenCallingGetResetStatsThenSuccessIsReturned) {
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);
auto xeIoctlHelper = static_cast<MockIoctlHelperXe *>(drm->getIoctlHelper());
ASSERT_NE(nullptr, xeIoctlHelper);
xeIoctlHelper->initialize();
drm->memoryInfo.reset(xeIoctlHelper->createMemoryInfo().release());
ASSERT_NE(nullptr, xeIoctlHelper);
ResetStats resetStats{};
resetStats.contextId = 0;