Skip to content

Commit b8d1a56

Browse files
authored
Add Unit Test for multi driver init (#436)
Signed-off-by: Neil R. Spruit <neil.r.spruit@intel.com>
1 parent b62852e commit b8d1a56

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

test/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@ set_property(TEST tests_multi_call_failure PROPERTY ENVIRONMENT "ZE_ENABLE_LOADE
163163
add_test(NAME tests_no_initialization COMMAND tests --gtest_filter=*LoaderInit.GivenNoInitializationWhenCallingZeInitDriversThenErrorUninitializedIsReturned*)
164164
set_property(TEST tests_no_initialization PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1")
165165

166+
# Regression test: NPU driver must not be lost after an intermediate GPU-only call
167+
# Uses ze_intel_gpu (ZEL_NULL_DRIVER_TYPE_GPU) and ze_intel_npu (ZEL_NULL_DRIVER_TYPE_NPU)
168+
# from lib_fake so each driver has a distinct compile-time type, making the 4-step
169+
# sequence (NPU|GPU → GPU → NPU → NPU|GPU) a meaningful regression check.
170+
if(NOT BUILD_STATIC AND NOT WIN32)
171+
add_test(NAME tests_init_gpu_npu_regression_combined
172+
COMMAND tests --gtest_filter=*InitDriverGPUNPURegressionTest*)
173+
set_property(TEST tests_init_gpu_npu_regression_combined PROPERTY ENVIRONMENT
174+
"ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_ALT_DRIVERS=${CMAKE_BINARY_DIR}/lib_fake/libze_intel_gpu.so,${CMAKE_BINARY_DIR}/lib_fake/libze_intel_npu.so")
175+
endif()
176+
177+
166178
# Run with multiple drivers
167179
add_test(NAME tests_multi_driver_missing_initDrivers COMMAND tests --gtest_filter=*GivenLevelZeroLoaderPresentWithMultipleDriversMissingInitDriversWhenCallingZeInitDriversThenExpectSuccessForZeInit)
168180
if (MSVC)

test/init_driver_dynamic_unit_tests.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,75 @@ TEST_F(InitDriverUnitTest, zeInitDriversWithAllTypes_VerifyRoutingToCorrectDrive
252252
// At least one type of driver should be found if we have drivers
253253
EXPECT_TRUE(foundGPUDriver || foundNPUDriver);
254254
}
255+
}
256+
257+
// Derived fixture for the NPU-loss regression test so it runs as its own
258+
// named test suite and can be targeted independently via --gtest_filter.
259+
class InitDriverGPUNPURegressionTest : public InitDriverUnitTest {};
260+
261+
// Regression test for the bug where calling zeInitDrivers with GPU-only flags
262+
// causes the NPU driver to be absent in a subsequent NPU|GPU call.
263+
//
264+
// Reproduction sequence:
265+
// Step 1: NPU|GPU → count=N (GPU + NPU) [expected: success]
266+
// Step 2: GPU → count=1 (GPU only) [expected: success]
267+
// Step 3: NPU → count=1 (NPU only) [expected: success]
268+
// Step 4: NPU|GPU → count should still equal N [BUG: count was < N]
269+
TEST_F(InitDriverGPUNPURegressionTest, zeInitDriversGPUAndNPU_AfterGPUOnlyThenNPUOnly_BothStillReturnedOnCombined) {
270+
ze_init_driver_type_desc_t descBoth = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC};
271+
descBoth.flags = ZE_INIT_DRIVER_TYPE_FLAG_GPU | ZE_INIT_DRIVER_TYPE_FLAG_NPU;
272+
descBoth.pNext = nullptr;
273+
274+
ze_init_driver_type_desc_t descGPU = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC};
275+
descGPU.flags = ZE_INIT_DRIVER_TYPE_FLAG_GPU;
276+
descGPU.pNext = nullptr;
277+
278+
ze_init_driver_type_desc_t descNPU = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC};
279+
descNPU.flags = ZE_INIT_DRIVER_TYPE_FLAG_NPU;
280+
descNPU.pNext = nullptr;
281+
282+
// Step 1: NPU|GPU — establish the baseline combined count
283+
uint32_t countBothFirst = 0;
284+
ASSERT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&countBothFirst, nullptr, &descBoth));
285+
286+
// Only meaningful if at least one driver is present
287+
if (countBothFirst == 0) {
288+
GTEST_SKIP() << "No GPU or NPU drivers available; skipping regression test";
289+
}
290+
291+
EXPECT_EQ(countBothFirst, 2);
292+
293+
// Step 2: GPU-only call
294+
uint32_t countGPU = 0;
295+
EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&countGPU, nullptr, &descGPU));
296+
297+
EXPECT_EQ(countGPU, 1);
298+
299+
// Step 3: NPU-only call
300+
uint32_t countNPU = 0;
301+
EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&countNPU, nullptr, &descNPU));
302+
303+
EXPECT_EQ(countNPU, 1);
304+
305+
// Step 4: NPU|GPU again — must return the same count as Step 1
306+
// This is the regression check: the NPU driver must not have been lost
307+
// as a side-effect of the intermediate GPU-only or NPU-only calls.
308+
uint32_t countBothSecond = 0;
309+
EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&countBothSecond, nullptr, &descBoth));
310+
EXPECT_EQ(countBothFirst, countBothSecond)
311+
<< "Regression: zeInitDrivers(NPU|GPU) returned fewer drivers after "
312+
"intermediate GPU-only and NPU-only calls. "
313+
"First combined count=" << countBothFirst
314+
<< ", second combined count=" << countBothSecond;
315+
316+
// Verify the returned handles are valid
317+
if (countBothSecond > 0) {
318+
std::vector<ze_driver_handle_t> drivers(countBothSecond);
319+
EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&countBothSecond, drivers.data(), &descBoth));
320+
for (uint32_t i = 0; i < countBothSecond; i++) {
321+
EXPECT_NE(drivers[i], nullptr);
322+
uint32_t deviceCount = 0;
323+
EXPECT_EQ(ZE_RESULT_SUCCESS, zeDeviceGet(drivers[i], &deviceCount, nullptr));
324+
}
325+
}
255326
}

0 commit comments

Comments
 (0)