Skip to content

Commit 7c64d8c

Browse files
committed
feature: Add zelGetLoaderVersion, allowing for query of Loader Version without init
- New API zelGetLoaderVersion, allows for loader version check without init for dynamic loader usecases. - zelGetLoaderVersion called from static loader applications will require zeInitDrivers due to requring the loader init to be completed. Signed-off-by: Neil R. Spruit <neil.r.spruit@intel.com>
1 parent 5e35e03 commit 7c64d8c

File tree

5 files changed

+272
-0
lines changed

5 files changed

+272
-0
lines changed

include/loader/ze_loader.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,75 @@ extern "C" {
3434
} zel_component_version_t;
3535

3636

37+
/**
38+
* @brief Retrieves version information for all components of the Level Zero loader.
39+
*
40+
* This function returns the versions of all loader components. It requires that
41+
* the driver initialization routine has been called prior to use.
42+
*
43+
* Preconditions:
44+
* - `zeInitDrivers()` must be successfully invoked before calling this function.
45+
*
46+
* Usage:
47+
* - If `versions` is `NULL`, the function writes the number of available component
48+
* versions to `*num_elems` and returns.
49+
* - If `versions` is non-NULL, provide an array large enough to hold `*num_elems`
50+
* entries; the function fills the array with the versions of all loader components.
51+
*
52+
* @param[out] num_elems
53+
* Pointer to a size_t that receives the number of available component version entries.
54+
* When `versions` is non-NULL, on success it may be updated to reflect the number
55+
* of entries written.
56+
*
57+
* @param[out] versions
58+
* Pointer to an array of `zel_component_version_t` to be filled with version data.
59+
* If set to `NULL`, no version data is returned and only `*num_elems` is populated.
60+
*
61+
* @return ze_result_t
62+
* - `ZE_RESULT_SUCCESS` on successful retrieval.
63+
* - `ZE_RESULT_ERROR_UNINITIALIZED` if `zeInitDrivers()` was not called.
64+
* - `ZE_RESULT_ERROR_INVALID_NULL_POINTER` if required pointers are `NULL`.
65+
* - `ZE_RESULT_ERROR_INVALID_SIZE` if the provided array is too small.
66+
* - Other `ze_result_t` error codes as appropriate.
67+
*/
3768
ZE_APIEXPORT ze_result_t ZE_APICALL
3869
zelLoaderGetVersions(
3970
size_t *num_elems, //Pointer to num versions to get.
4071
zel_component_version_t *versions); //Pointer to array of versions. If set to NULL, num_elems is returned
4172

73+
74+
/**
75+
* @brief Retrieves the Level Zero loader's version information.
76+
*
77+
* Populates the provided zel_component_version_t structure with the loader's
78+
* version details (e.g., major, minor, patch), allowing applications to
79+
* query and validate the loader's compatibility at runtime.
80+
*
81+
* Does not require zeInitDrivers to be called prior to invocation unless the
82+
* application is using a static build of the loader.
83+
*
84+
* Thread-safety: This function is typically safe to call from multiple threads.
85+
* The implementation does not modify global state other than filling the
86+
* supplied version structure.
87+
*
88+
* @param[out] version
89+
* Pointer to a zel_component_version_t structure that will be filled with
90+
* the loader's version information. Must be a valid, non-null pointer.
91+
*
92+
* @return
93+
* - ZE_RESULT_SUCCESS on successful retrieval of the loader version.
94+
* - ZE_RESULT_ERROR_INVALID_NULL_POINTER if version is nullptr.
95+
* - ZE_RESULT_ERROR_UNINITIALIZED if the loader is not properly initialized.
96+
* NOTE: this error only occurs with a static loader build.
97+
* - Other ze_result_t error codes on failure conditions as defined by the API.
98+
*
99+
* @note The caller owns the memory for the version structure and must ensure
100+
* it remains valid for the duration of the call.
101+
*/
102+
ZE_DLLEXPORT ze_result_t ZE_APICALL
103+
zelGetLoaderVersion(zel_component_version_t *version
104+
);
105+
42106
typedef enum _zel_handle_type_t {
43107
ZEL_HANDLE_DRIVER,
44108
ZEL_HANDLE_DEVICE,

source/lib/ze_lib.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,22 @@ zelLoaderGetVersions(
389389
#endif
390390
}
391391

392+
ze_result_t ZE_APICALL
393+
zelGetLoaderVersion(
394+
zel_component_version_t *version) //Pointer to version structure to be filled with loader version information
395+
{
396+
#ifdef L0_STATIC_LOADER_BUILD
397+
if(!ze_lib::context || nullptr == ze_lib::context->loader)
398+
return ZE_RESULT_ERROR_UNINITIALIZED;
399+
typedef ze_result_t (ZE_APICALL *zelLoaderGetVersion_t)(zel_component_version_t *version);
400+
auto getVersion = reinterpret_cast<zelLoaderGetVersion_t>(
401+
GET_FUNCTION_PTR(ze_lib::context->loader, "zelLoaderGetVersion") );
402+
return getVersion(version);
403+
#else
404+
return zelLoaderGetVersion(version);
405+
#endif
406+
}
407+
392408

393409
ze_result_t ZE_APICALL
394410
zelLoaderTranslateHandle(

source/loader/ze_loader_api.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,19 @@ zelLoaderGetVersionsInternal(
9292
return ZE_RESULT_SUCCESS;
9393
}
9494

95+
ZE_DLLEXPORT ze_result_t ZE_APICALL
96+
zelLoaderGetVersion(zel_component_version_t *version)
97+
{
98+
if(version == nullptr)
99+
return ZE_RESULT_ERROR_INVALID_NULL_POINTER;
100+
string_copy_s(version->component_name, "loader", ZEL_COMPONENT_STRING_SIZE);
101+
version->spec_version = ZE_API_VERSION_CURRENT;
102+
version->component_lib_version.major = LOADER_VERSION_MAJOR;
103+
version->component_lib_version.minor = LOADER_VERSION_MINOR;
104+
version->component_lib_version.patch = LOADER_VERSION_PATCH;
105+
106+
return ZE_RESULT_SUCCESS;
107+
}
95108

96109
ZE_DLLEXPORT ze_result_t ZE_APICALL
97110
zelLoaderTranslateHandleInternal(

test/CMakeLists.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,26 @@ endif()
115115

116116
add_test(NAME tests_api COMMAND tests --gtest_filter=*GivenLevelZeroLoaderPresentWhenCallingzeGetLoaderVersionsAPIThenValidVersionIsReturned*)
117117
set_property(TEST tests_api PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1")
118+
119+
# LoaderVersionAPI Tests
120+
add_test(NAME tests_loader_version_after_init COMMAND tests --gtest_filter=*LoaderVersionAPI*GivenLoaderWhenCallingzelGetLoaderVersionAfterInitThenValidVersionIsReturned*)
121+
set_property(TEST tests_loader_version_after_init PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1")
122+
123+
add_test(NAME tests_loader_version_null_pointer COMMAND tests --gtest_filter=*LoaderVersionAPI*GivenLoaderWhenCallingzelGetLoaderVersionWithNullPointerThenErrorIsReturned*)
124+
set_property(TEST tests_loader_version_null_pointer PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1")
125+
126+
add_test(NAME tests_loader_version_without_init COMMAND tests --gtest_filter=*LoaderVersionAPI*GivenLoaderWhenCallingzelGetLoaderVersionWithoutInitThenCorrectResultIsReturned*)
127+
set_property(TEST tests_loader_version_without_init PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1")
128+
129+
add_test(NAME tests_loader_version_before_and_after_init COMMAND tests --gtest_filter=*LoaderVersionAPI*GivenLoaderWhenCallingzelGetLoaderVersionBeforeAndAfterInitThenCorrectResultIsReturned*)
130+
set_property(TEST tests_loader_version_before_and_after_init PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1")
131+
132+
add_test(NAME tests_loader_version_multiple_times COMMAND tests --gtest_filter=*LoaderVersionAPI*GivenLoaderWhenCallingzelGetLoaderVersionMultipleTimesThenConsistentVersionIsReturned*)
133+
set_property(TEST tests_loader_version_multiple_times PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1")
134+
135+
add_test(NAME tests_loader_version_compare_apis COMMAND tests --gtest_filter=*LoaderVersionAPI*GivenLoaderWhenComparingzelGetLoaderVersionWithzelLoaderGetVersionsThenVersionsMatch*)
136+
set_property(TEST tests_loader_version_compare_apis PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1")
137+
118138
add_test(NAME tests_init_gpu_all COMMAND tests --gtest_filter=*GivenLevelZeroLoaderPresentWhenCallingZeInitDriversWithGPUTypeThenExpectPassWithGPUorAllOnly*)
119139
set_property(TEST tests_init_gpu_all PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1")
120140
add_test(NAME tests_init_npu_all COMMAND tests --gtest_filter=*GivenLevelZeroLoaderPresentWhenCallingZeInitDriversWithNPUTypeThenExpectPassWithNPUorAllOnly*)
@@ -755,6 +775,8 @@ set_property(TEST test_ze_and_zer_tracing_dynamic PROPERTY ENVIRONMENT "ZE_ENABL
755775
add_test(NAME test_zer_unsupported_and_ze_tracing_dynamic COMMAND tests --gtest_filter=*TracingParameterizedTest*GivenLoaderWithDynamicTracingEnabledAndZerApisUnsupportedAndBothZeAndZerCallbacksRegisteredWhenCallingBothApisThenTracingWorksForZeAndZerCallbacksAreStillInvoked*)
756776
set_property(TEST test_zer_unsupported_and_ze_tracing_dynamic PROPERTY ENVIRONMENT "ZE_ENABLE_NULL_DRIVER=1")
757777

778+
779+
758780
# ZER API Validation Layer Tests
759781
add_test(NAME test_zer_validation_layer_positive_case COMMAND tests --gtest_filter=*GivenLevelZeroLoaderPresentWithLoaderInterceptEnabledAndDdiExtSupportedWhenCallingRuntimeApisAfterZeInitDriversThenExpectNullDriverIsReachedSuccessfully)
760782
set_property(TEST test_zer_validation_layer_positive_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=0;ZEL_ENABLE_EVENTS_CHECKER=1;ZEL_ENABLE_BASIC_LEAK_CHECKER=1;ZEL_ENABLE_CERTIFICATION_CHECKER=1")

test/loader_api.cpp

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,163 @@ TEST(
9292
}
9393
}
9494

95+
TEST(
96+
LoaderVersionAPI,
97+
GivenLoaderWhenCallingzelGetLoaderVersionAfterInitThenValidVersionIsReturned) {
98+
99+
uint32_t pCount = 0;
100+
ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC};
101+
desc.flags = UINT32_MAX;
102+
desc.pNext = nullptr;
103+
EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc));
104+
105+
zel_component_version_t version = {};
106+
EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetLoaderVersion(&version));
107+
108+
// Verify component name is "loader"
109+
EXPECT_STREQ(version.component_name, "loader");
110+
111+
// Verify spec version is valid (current API version)
112+
EXPECT_GT(version.spec_version, 0);
113+
114+
// Verify library version components are valid
115+
EXPECT_GE(version.component_lib_version.major, 0);
116+
EXPECT_GE(version.component_lib_version.minor, 0);
117+
EXPECT_GE(version.component_lib_version.patch, 0);
118+
}
119+
120+
TEST(
121+
LoaderVersionAPI,
122+
GivenLoaderWhenCallingzelGetLoaderVersionWithNullPointerThenErrorIsReturned) {
123+
124+
uint32_t pCount = 0;
125+
ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC};
126+
desc.flags = UINT32_MAX;
127+
desc.pNext = nullptr;
128+
EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc));
129+
130+
EXPECT_EQ(ZE_RESULT_ERROR_INVALID_NULL_POINTER, zelGetLoaderVersion(nullptr));
131+
}
132+
133+
TEST(
134+
LoaderVersionAPI,
135+
GivenLoaderWhenCallingzelGetLoaderVersionWithoutInitThenCorrectResultIsReturned) {
136+
137+
zel_component_version_t version = {};
138+
139+
#ifdef L0_STATIC_LOADER_BUILD
140+
// Static build: requires initialization
141+
EXPECT_EQ(ZE_RESULT_ERROR_UNINITIALIZED, zelGetLoaderVersion(&version));
142+
#else
143+
// Dynamic build: works without initialization
144+
EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetLoaderVersion(&version));
145+
146+
EXPECT_STREQ(version.component_name, "loader");
147+
EXPECT_GT(version.spec_version, 0);
148+
EXPECT_GE(version.component_lib_version.major, 0);
149+
EXPECT_GE(version.component_lib_version.minor, 0);
150+
EXPECT_GE(version.component_lib_version.patch, 0);
151+
#endif
152+
}
153+
154+
TEST(
155+
LoaderVersionAPI,
156+
GivenLoaderWhenCallingzelGetLoaderVersionBeforeAndAfterInitThenCorrectResultIsReturned) {
157+
158+
// Get version before initialization
159+
zel_component_version_t version_before = {};
160+
161+
#ifdef L0_STATIC_LOADER_BUILD
162+
// Static build: should fail before init
163+
EXPECT_EQ(ZE_RESULT_ERROR_UNINITIALIZED, zelGetLoaderVersion(&version_before));
164+
#else
165+
// Dynamic build: should work before init
166+
EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetLoaderVersion(&version_before));
167+
#endif
168+
169+
// Initialize drivers
170+
uint32_t pCount = 0;
171+
ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC};
172+
desc.flags = UINT32_MAX;
173+
desc.pNext = nullptr;
174+
EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc));
175+
176+
// Get version after initialization
177+
zel_component_version_t version_after = {};
178+
EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetLoaderVersion(&version_after));
179+
180+
#ifndef L0_STATIC_LOADER_BUILD
181+
// Dynamic build: verify both versions match
182+
EXPECT_STREQ(version_before.component_name, version_after.component_name);
183+
EXPECT_EQ(version_before.spec_version, version_after.spec_version);
184+
EXPECT_EQ(version_before.component_lib_version.major, version_after.component_lib_version.major);
185+
EXPECT_EQ(version_before.component_lib_version.minor, version_after.component_lib_version.minor);
186+
EXPECT_EQ(version_before.component_lib_version.patch, version_after.component_lib_version.patch);
187+
#endif
188+
}
189+
190+
TEST(
191+
LoaderVersionAPI,
192+
GivenLoaderWhenCallingzelGetLoaderVersionMultipleTimesThenConsistentVersionIsReturned) {
193+
194+
uint32_t pCount = 0;
195+
ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC};
196+
desc.flags = UINT32_MAX;
197+
desc.pNext = nullptr;
198+
EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc));
199+
200+
zel_component_version_t version1 = {};
201+
zel_component_version_t version2 = {};
202+
203+
EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetLoaderVersion(&version1));
204+
EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetLoaderVersion(&version2));
205+
206+
// Verify both calls return the same version
207+
EXPECT_STREQ(version1.component_name, version2.component_name);
208+
EXPECT_EQ(version1.spec_version, version2.spec_version);
209+
EXPECT_EQ(version1.component_lib_version.major, version2.component_lib_version.major);
210+
EXPECT_EQ(version1.component_lib_version.minor, version2.component_lib_version.minor);
211+
EXPECT_EQ(version1.component_lib_version.patch, version2.component_lib_version.patch);
212+
}
213+
214+
TEST(
215+
LoaderVersionAPI,
216+
GivenLoaderWhenComparingzelGetLoaderVersionWithzelLoaderGetVersionsThenVersionsMatch) {
217+
218+
uint32_t pCount = 0;
219+
ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC};
220+
desc.flags = UINT32_MAX;
221+
desc.pNext = nullptr;
222+
EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc));
223+
224+
// Get version via zelGetLoaderVersion
225+
zel_component_version_t single_version = {};
226+
EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetLoaderVersion(&single_version));
227+
228+
// Get versions via zelLoaderGetVersions
229+
size_t size = 0;
230+
EXPECT_EQ(ZE_RESULT_SUCCESS, zelLoaderGetVersions(&size, nullptr));
231+
EXPECT_GT(size, 0);
232+
233+
std::vector<zel_component_version_t> versions(size);
234+
EXPECT_EQ(ZE_RESULT_SUCCESS, zelLoaderGetVersions(&size, versions.data()));
235+
236+
// Find the loader component in the versions array
237+
bool found_loader = false;
238+
for (const auto &component : versions) {
239+
if (strcmp(component.component_name, "loader") == 0) {
240+
found_loader = true;
241+
// Verify both APIs return the same version info
242+
EXPECT_EQ(single_version.spec_version, component.spec_version);
243+
EXPECT_EQ(single_version.component_lib_version.major, component.component_lib_version.major);
244+
EXPECT_EQ(single_version.component_lib_version.minor, component.component_lib_version.minor);
245+
EXPECT_EQ(single_version.component_lib_version.patch, component.component_lib_version.patch);
246+
break;
247+
}
248+
}
249+
EXPECT_TRUE(found_loader) << "Loader component not found in zelLoaderGetVersions output";
250+
}
251+
95252
TEST(
96253
LoaderInit,
97254
GivenLevelZeroLoaderPresentWhenCallingZeInitDriversWithTypesUnsupportedWithFailureThenSupportedTypesThenSuccessReturned) {

0 commit comments

Comments
 (0)