Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,33 @@ validation layer is enabled. Following variables need to be set to enable API lo
By default logs will be written to the log file, as described above. To print the logs
to stderr instead, `ZEL_LOADER_LOG_CONSOLE=1` needs to be set.

The API logging output format includes both function entry and exit information, showing parameter names on entry and parameter values with the result code on exit. Each log entry is timestamped and includes the logger name and log level. Example output:

```
[2026-01-14 09:01:38.951] [ze_loader] [trace] zeContextCreate(hDriver, desc, phContext)
[2026-01-14 09:01:38.951] [ze_loader] [trace] SUCCESS (ZE_RESULT_SUCCESS) in zeContextCreate(hDriver=0x5b261fa70588, desc={stype=0x7ffdd20fe1e0, flags=0}, phContext=0x7ffdd20fe148)
[2026-01-14 09:01:38.951] [ze_loader] [trace] zeCommandListCreateImmediate(hContext, hDevice, altdesc, phCommandList)
[2026-01-14 09:01:38.951] [ze_loader] [trace] SUCCESS (ZE_RESULT_SUCCESS) in zeCommandListCreateImmediate(hContext=0x5b261fa74228, hDevice=0x5b261fa708b8, altdesc={stype=0x7ffdd20fe240, ordinal=0, index=0, flags=0, mode=0x7ffdd20fe25c, priority=0x7ffdd20fe260}, phCommandList=0x7ffdd20fe150)
[2026-01-14 09:01:38.951] [ze_loader] [trace] zeEventPoolCreate(hContext, desc, numDevices, phDevicesLocal, phEventPool)
[2026-01-14 09:01:38.951] [ze_loader] [trace] SUCCESS (ZE_RESULT_SUCCESS) in zeEventPoolCreate(hContext=0x5b261fa74228, desc={stype=0x7ffdd20fe200, flags=1, count=1}, numDevices=1, phDevices=0x7ffdd20fe138, phEventPool=0x7ffdd20fe160)
[2026-01-14 09:01:38.951] [ze_loader] [trace] zeEventCreate(hEventPool, desc, phEvent)
[2026-01-14 09:01:38.951] [ze_loader] [trace] SUCCESS (ZE_RESULT_SUCCESS) in zeEventCreate(hEventPool=0x5b261fa19c18, desc={stype=0x7ffdd20fe220, index=0, signal=4, wait=4}, phEvent=0x7ffdd20fe158)
[2026-01-14 09:01:38.951] [ze_loader] [trace] zeCommandListAppendSignalEvent(hCommandList, hEvent)
[2026-01-14 09:01:38.952] [ze_loader] [trace] SUCCESS (ZE_RESULT_SUCCESS) in zeCommandListAppendSignalEvent(hCommandList=0x5b261fa743c8, hEvent=0x5b261c69e5d8)
[2026-01-14 09:01:38.952] [ze_loader] [trace] zeEventHostSynchronize(hEvent, timeout)
[2026-01-14 09:01:38.954] [ze_loader] [trace] SUCCESS (ZE_RESULT_SUCCESS) in zeEventHostSynchronize(hEvent=0x5b261c69e5d8, timeout=18446744073709551615)
[2026-01-14 09:01:38.954] [ze_loader] [trace] zeContextDestroy(hContext)
[2026-01-14 09:01:38.954] [ze_loader] [trace] SUCCESS (ZE_RESULT_SUCCESS) in zeContextDestroy(hContext=0x5b261fa74228)
[2026-01-14 09:01:38.954] [ze_loader] [trace] zeCommandListDestroy(hCommandList)
[2026-01-14 09:01:38.955] [ze_loader] [trace] SUCCESS (ZE_RESULT_SUCCESS) in zeCommandListDestroy(hCommandList=0x5b261fa743c8)
[2026-01-14 09:01:38.955] [ze_loader] [trace] zeEventDestroy(hEvent)
[2026-01-14 09:01:38.955] [ze_loader] [trace] SUCCESS (ZE_RESULT_SUCCESS) in zeEventDestroy(hEvent=0x5b261c69e5d8)
[2026-01-14 09:01:38.955] [ze_loader] [trace] zeEventPoolDestroy(hEventPool)
[2026-01-14 09:01:38.955] [ze_loader] [trace] SUCCESS (ZE_RESULT_SUCCESS) in zeEventPoolDestroy(hEventPool=0x5b261fa19c18)
```



# Driver/Device Sorting

As of v1.20.3 of the Loader, Drivers and Devices reported to the user are sorted to enable the first device to be the best available device.
Expand Down
3 changes: 2 additions & 1 deletion scripts/generate_code.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Copyright (C) 2019-2025 Intel Corporation
Copyright (C) 2019-2026 Intel Corporation

SPDX-License-Identifier: MIT

Expand Down Expand Up @@ -182,6 +182,7 @@ def _mako_loader_cpp(path, namespace, tags, version, specs, meta):
'handle_lifetime.h.mako' : ('handle_lifetime_tracking', 'handle_lifetime.h'),
'handle_lifetime.cpp.mako' : ('handle_lifetime_tracking', 'handle_lifetime.cpp'),
'certification.h.mako' : ('checkers/certification/generated', 'certification.h'),
'to_string.h.mako' : ('../../utils', 'to_string.h'),
}

def _mako_validation_layer_cpp(path, namespace, tags, version, specs, meta):
Expand Down
171 changes: 171 additions & 0 deletions scripts/templates/validation/to_string.h.mako
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<%!
import re
from templates import helper as th
%><%
n=namespace
N=n.upper()

x=tags['$x']
X=x.upper()
%>/*
* ***THIS FILE IS GENERATED. ***
* See to_string.h.mako for modifications
*
* Copyright (C) 2025-2026 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
* @file ${name}
*
* to_string functions for Level Zero types
*/

#ifndef _${N}_TO_STRING_H
#define _${N}_TO_STRING_H

#include "${x}_api.h"
#include <string>
#include <sstream>
#include <iomanip>

%if n == 'ze':
namespace loader {

// Forward declarations
std::string to_string(const ${x}_result_t result);

// Pointer to_string
template<typename T>
inline std::string to_string(const T* ptr) {
if (ptr == nullptr) {
return "nullptr";
}
std::ostringstream oss;
oss << "0x" << std::hex << reinterpret_cast<uintptr_t>(ptr);
return oss.str();
}

%else:
// Include ze_to_string.h for common definitions
#include "ze_to_string.h"

namespace loader {
%endif
%if n == 'ze':
// Handle to_string functions
%for obj in th.extract_objs(specs, r"handle"):
inline std::string to_string(${th.make_type_name(n, tags, obj)} handle) {
return to_string(reinterpret_cast<const void*>(handle));
}

%endfor
%endif
%if n == 'ze':
// For primitive types and Level Zero typedef'd types
// Since most Level Zero types are typedef'd to uint32_t, we can't distinguish them by type
inline std::string to_string(uint32_t value) { return std::to_string(value); }
inline std::string to_string(uint64_t value) { return std::to_string(value); }
inline std::string to_string(uint8_t value) { return std::to_string(static_cast<unsigned>(value)); }
inline std::string to_string(uint16_t value) { return std::to_string(value); }
inline std::string to_string(int32_t value) { return std::to_string(value); }
inline std::string to_string(int64_t value) { return std::to_string(value); }
#if SIZE_MAX != UINT64_MAX
inline std::string to_string(size_t value) { return std::to_string(value); }
#endif
inline std::string to_string(double value) { return std::to_string(value); }
inline std::string to_string(const char* str) {
if (!str) return "nullptr";
return std::string("\"") + str + "\"";
}

// Pointer to primitive types - dereference and print value
inline std::string to_string(const uint32_t* ptr) {
if (!ptr) return "nullptr";
return to_string(*ptr);
}
inline std::string to_string(const uint64_t* ptr) {
if (!ptr) return "nullptr";
return to_string(*ptr);
}
inline std::string to_string(const uint8_t* ptr) {
if (!ptr) return "nullptr";
return to_string(*ptr);
}
inline std::string to_string(const uint16_t* ptr) {
if (!ptr) return "nullptr";
return to_string(*ptr);
}
inline std::string to_string(const int32_t* ptr) {
if (!ptr) return "nullptr";
return to_string(*ptr);
}
inline std::string to_string(const int64_t* ptr) {
if (!ptr) return "nullptr";
return to_string(*ptr);
}
#if SIZE_MAX != UINT64_MAX
inline std::string to_string(const size_t* ptr) {
if (!ptr) return "nullptr";
return to_string(*ptr);
}
#endif
inline std::string to_string(const double* ptr) {
if (!ptr) return "nullptr";
return to_string(*ptr);
}

%endif
// Struct to_string functions
%for obj in th.extract_objs(specs, r"struct"):
<%
struct_name = th.make_type_name(n, tags, obj)
%>\
inline std::string to_string(const ${struct_name}* desc) {
if (!desc) return "nullptr";
std::ostringstream oss;
oss << "{";
%for idx, member in enumerate(obj['members']):
%if member['name'] != 'pNext':
<%
# Extract the actual member name without array brackets
member_name_full = member['name']
member_name = member_name_full.split('[')[0] if '[' in member_name_full else member_name_full
is_array = '[' in member_name_full

# Check if member is a pointer or regular value
member_type = member.get('type', '')
if is_array:
# For arrays, just pass the array name (decays to pointer)
member_access = f"desc->{member_name}"
elif '*' in member_type:
# It's already a pointer - pass directly
member_access = f"desc->{member_name}"
else:
# Check if it's a struct type by looking at the type name
# If it contains a struct typename pattern, take its address
if '_t' in member_type and 'uint' not in member_type and 'int' not in member_type and 'size_t' not in member_type:
member_access = f"&desc->{member_name}"
else:
member_access = f"desc->{member_name}"
%>\
%if idx == 0 and member['name'] == 'stype':
oss << "stype=" << to_string(${member_access});
%elif idx == 0:
oss << "${member_name}=" << to_string(${member_access});
%else:
oss << ", ${member_name}=" << to_string(${member_access});
%endif
%endif
%endfor
oss << "}";
return oss.str();
}

inline std::string to_string(const ${struct_name}& desc) {
return to_string(&desc);
}

%endfor
} // namespace loader

#endif // _${N}_TO_STRING_H
Loading
Loading