diff --git a/scripts/templates/validation/valddi.cpp.mako b/scripts/templates/validation/valddi.cpp.mako index 623c43e6..13f4f930 100644 --- a/scripts/templates/validation/valddi.cpp.mako +++ b/scripts/templates/validation/valddi.cpp.mako @@ -197,7 +197,7 @@ return ${failure_return}; <% func_name = th.make_func_name(n, tags, obj) - generate_post_call = re.match(r"\w+Create\w*$|\w+Get$|\w+Get\w*Exp$|\w+GetIpcHandle$|\w+GetSubDevices$", func_name) + generate_post_call = re.match(r"\w+Create\w*$|\w+Get$|\w+Get\w*Exp$|\w+GetIpcHandle$|\w+GetSubDevices$|\w+InitDrivers$", func_name) %> if(context.enableHandleLifetime ){ auto result = context.handleLifetime->${n}HandleLifetime.${th.make_func_name(n, tags, obj)}Prologue( \ diff --git a/source/layers/validation/ze_valddi.cpp b/source/layers/validation/ze_valddi.cpp index c078b9a5..fad2b732 100644 --- a/source/layers/validation/ze_valddi.cpp +++ b/source/layers/validation/ze_valddi.cpp @@ -7748,6 +7748,15 @@ namespace validation_layer if(result!=ZE_RESULT_SUCCESS) return logAndPropagateResult_zeInitDrivers(result, pCount, phDrivers, desc); } + + if( driver_result == ZE_RESULT_SUCCESS && context.enableHandleLifetime ){ + for (size_t i = 0; ( nullptr != phDrivers) && (i < *pCount); ++i){ + if (phDrivers[i]){ + context.handleLifetime->addHandle( phDrivers[i] ); + context.handleLifetime->addDependent( pCount, phDrivers[i] ); + } + } + } return logAndPropagateResult_zeInitDrivers(driver_result, pCount, phDrivers, desc); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 364f3032..c4fbd4b0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1130,6 +1130,17 @@ set_property(TEST test_zer_validation_layer_positive_case PROPERTY ENVIRONMENT " add_test(NAME test_zer_parameter_validation_layer_negative_case COMMAND tests --gtest_filter=*GivenLevelZeroLoaderPresentWhenCallingZerApiWithParameterValidationEnabledThenExpectValidationsAreTriggered) set_property(TEST test_zer_parameter_validation_layer_negative_case PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1;ZE_ENABLE_VALIDATION_LAYER=1;ZE_ENABLE_PARAMETER_VALIDATION=1;ZE_ENABLE_HANDLE_LIFETIME=1;ZEL_ENABLE_EVENTS_CHECKER=1;ZEL_ENABLE_BASIC_LEAK_CHECKER=1;ZEL_ENABLE_CERTIFICATION_CHECKER=1") +# Handle Lifetime Validation Tests +# Regression: zeInitDrivers must register driver handles so downstream calls succeed. +add_test(NAME test_handle_lifetime_zeInitDrivers_path COMMAND tests --gtest_filter=*HandleLifetimeValidation*GivenHandleLifetimeEnabledWhenCallingzeDeviceGetWithDriverHandleFromzeInitDriversThenSucceeds*) +set_property(TEST test_handle_lifetime_zeInitDrivers_path PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1;ZEL_TEST_NULL_DRIVER_TYPE=GPU;ZE_ENABLE_VALIDATION_LAYER=1;ZE_ENABLE_HANDLE_LIFETIME=1") + +add_test(NAME test_handle_lifetime_zeDriverGet_path COMMAND tests --gtest_filter=*HandleLifetimeValidation*GivenHandleLifetimeEnabledWhenCallingzeDeviceGetWithDriverHandleFromzeDriverGetThenSucceeds*) +set_property(TEST test_handle_lifetime_zeDriverGet_path PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1;ZEL_TEST_NULL_DRIVER_TYPE=GPU;ZE_ENABLE_VALIDATION_LAYER=1;ZE_ENABLE_HANDLE_LIFETIME=1") + +add_test(NAME test_handle_lifetime_null_handle_rejected COMMAND tests --gtest_filter=*HandleLifetimeValidation*GivenHandleLifetimeEnabledWhenCallingzeDeviceGetWithNullDriverHandleThenReturnsInvalidHandle*) +set_property(TEST test_handle_lifetime_null_handle_rejected PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1;ZEL_TEST_NULL_DRIVER_TYPE=GPU;ZE_ENABLE_VALIDATION_LAYER=1;ZE_ENABLE_HANDLE_LIFETIME=1") + # API Call Tracing Tests - Validation Layer with Trace Logging add_test(NAME test_validation_layer_api_tracing_basic COMMAND tests --gtest_filter=ValidationLayerApiTracing.GivenValidationLayerEnabledWithTraceLevelLoggingWhenCallingBasicApisThenTracingDoesNotCrash) set_property(TEST test_validation_layer_api_tracing_basic PROPERTY ENVIRONMENT "ZE_ENABLE_VALIDATION_LAYER=1;ZEL_ENABLE_LOADER_LOGGING=1;ZEL_LOADER_LOGGING_LEVEL=trace;ZE_ENABLE_NULL_DRIVER=1") diff --git a/test/loader_validation_layer.cpp b/test/loader_validation_layer.cpp index f0735025..62d3538f 100644 --- a/test/loader_validation_layer.cpp +++ b/test/loader_validation_layer.cpp @@ -970,3 +970,89 @@ TEST( EXPECT_EQ(ZE_RESULT_SUCCESS, zeCommandQueueDestroy(commandQueue)); EXPECT_EQ(ZE_RESULT_SUCCESS, zeContextDestroy(context)); } + +/////////////////////////////////////////////////////////////////////////////// +// Handle Lifetime Tests +// +// These tests validate the ZE_ENABLE_HANDLE_LIFETIME feature of the validation +// layer. Handle lifetime tracking registers handles when they are created and +// validates them on every subsequent API call, returning +// ZE_RESULT_ERROR_INVALID_NULL_HANDLE for any unregistered handle. +// +// The tests are run as separate CTest invocations with the environment: +// ZE_ENABLE_VALIDATION_LAYER=1 +// ZE_ENABLE_HANDLE_LIFETIME=1 +// ZE_ENABLE_NULL_DRIVER=1 + +// Regression test: driver handles obtained via zeInitDrivers must be registered +// in the handle lifetime tracker so that subsequent API calls succeed. +// Before the fix, zeInitDrivers had no handle-registration epilogue (unlike +// zeDriverGet), causing zeDeviceGet to return ZE_RESULT_ERROR_INVALID_NULL_HANDLE. +TEST( + HandleLifetimeValidation, + GivenHandleLifetimeEnabledWhenCallingzeDeviceGetWithDriverHandleFromzeInitDriversThenSucceeds) { + + ze_init_driver_type_desc_t driverTypeDesc = {}; + driverTypeDesc.stype = ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC; + driverTypeDesc.pNext = nullptr; + driverTypeDesc.flags = UINT32_MAX; + + uint32_t count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&count, nullptr, &driverTypeDesc)); + EXPECT_GT(count, 0); + + std::vector drivers(count); + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&count, drivers.data(), &driverTypeDesc)); + + // Regression: driver handles from zeInitDrivers must be registered with the + // handle lifetime tracker so that zeDeviceGet does not fail with + // ZE_RESULT_ERROR_INVALID_NULL_HANDLE. + uint32_t deviceCount = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeDeviceGet(drivers[0], &deviceCount, nullptr)); + EXPECT_GT(deviceCount, 0); + + std::vector devices(deviceCount); + EXPECT_EQ(ZE_RESULT_SUCCESS, zeDeviceGet(drivers[0], &deviceCount, devices.data())); +} + +// Verify that driver handles obtained via zeDriverGet are registered correctly +// and can be used with zeDeviceGet when handle lifetime tracking is enabled. +TEST( + HandleLifetimeValidation, + GivenHandleLifetimeEnabledWhenCallingzeDeviceGetWithDriverHandleFromzeDriverGetThenSucceeds) { + + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInit(ZE_INIT_FLAG_GPU_ONLY)); + + uint32_t driverCount = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeDriverGet(&driverCount, nullptr)); + EXPECT_GT(driverCount, 0); + + std::vector drivers(driverCount); + EXPECT_EQ(ZE_RESULT_SUCCESS, zeDriverGet(&driverCount, drivers.data())); + + uint32_t deviceCount = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeDeviceGet(drivers[0], &deviceCount, nullptr)); + EXPECT_GT(deviceCount, 0); + + std::vector devices(deviceCount); + EXPECT_EQ(ZE_RESULT_SUCCESS, zeDeviceGet(drivers[0], &deviceCount, devices.data())); +} + +// Verify that calling an API with a null (unregistered) handle returns +// ZE_RESULT_ERROR_INVALID_NULL_HANDLE when handle lifetime tracking is enabled. +TEST( + HandleLifetimeValidation, + GivenHandleLifetimeEnabledWhenCallingzeDeviceGetWithNullDriverHandleThenReturnsInvalidHandle) { + + ze_init_driver_type_desc_t driverTypeDesc = {}; + driverTypeDesc.stype = ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC; + driverTypeDesc.pNext = nullptr; + driverTypeDesc.flags = UINT32_MAX; + + uint32_t count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&count, nullptr, &driverTypeDesc)); + + // A null handle is never registered; the handle lifetime checker must reject it. + uint32_t deviceCount = 0; + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_NULL_HANDLE, zeDeviceGet(nullptr, &deviceCount, nullptr)); +}