Skip to content
Draft
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
1 change: 1 addition & 0 deletions scripts/generate_code.py
Original file line number Diff line number Diff line change
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 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
94 changes: 81 additions & 13 deletions scripts/templates/validation/valddi.cpp.mako
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ from templates import helper as th
*
*/
#include "${x}_validation_layer.h"
#include <sstream>

// Define a macro for marking potentially unused functions
#if defined(_MSC_VER)
// MSVC doesn't support __attribute__((unused)), just omit the marking
#define VALIDATION_MAYBE_UNUSED
#elif defined(__GNUC__) || defined(__clang__)
// GCC and Clang support __attribute__((unused))
#define VALIDATION_MAYBE_UNUSED __attribute__((unused))
#else
#define VALIDATION_MAYBE_UNUSED
#endif

namespace validation_layer
{
Expand All @@ -33,12 +45,68 @@ namespace validation_layer
);

%endif
static ze_result_t logAndPropagateResult(const char* fname, ze_result_t result) {
if (result != ${X}_RESULT_SUCCESS) {
context.logger->log_trace("Error (" + loader::to_string(result) + ") in " + std::string(fname));
}
// Generate specific logAndPropagateResult functions for each API function
%for obj in th.extract_objs(specs, r"function"):
<%
func_name = th.make_func_name(n, tags, obj)
param_lines = [line for line in th.make_param_lines(n, tags, obj, format=['name','delim'])]
param_names = [line for line in th.make_param_lines(n, tags, obj, format=['name'])]
is_void_params = len(param_lines) == 0
%>\
%if 'condition' in obj:
#if ${th.subt(n, tags, obj['condition'])}
%endif
VALIDATION_MAYBE_UNUSED static ze_result_t logAndPropagateResult_${func_name}(
ze_result_t result\
%if not is_void_params:
,
%for line in th.make_param_lines(n, tags, obj):
${line}
%endfor
%endif
) {
std::string status = (result == ${X}_RESULT_SUCCESS) ? "SUCCESS" : "ERROR";
%if is_void_params:
context.logger->log_trace(status + " (" + loader::to_string(result) + ") in ${func_name}()");
%else:
std::ostringstream oss;
oss << status << " (" << loader::to_string(result) << ") in ${func_name}(";
%for i, param in enumerate([p for p in th.make_param_lines(n, tags, obj, format=['name'])]):
%if i > 0:
oss << ", ";
%endif
oss << "${param}=" << loader::to_string(${param});
%endfor
oss << ")";
context.logger->log_trace(oss.str());
%endif
return result;
}
%if 'condition' in obj:
#endif // ${th.subt(n, tags, obj['condition'])}
%endif
%endfor
\
%if n == 'ze':
// Special function for zexCounterBasedEventCreate2
VALIDATION_MAYBE_UNUSED static ze_result_t logAndPropagateResult_zexCounterBasedEventCreate2(
ze_result_t result,
ze_context_handle_t hContext,
ze_device_handle_t hDevice,
const void* desc,
ze_event_handle_t* phEvent
) {
std::string status = (result == ${X}_RESULT_SUCCESS) ? "SUCCESS" : "ERROR";
std::ostringstream oss;
oss << status << " (" << loader::to_string(result) << ") in zexCounterBasedEventCreate2("
<< "hContext=" << static_cast<const void*>(hContext) << ", "
<< "hDevice=" << static_cast<const void*>(hDevice) << ", "
<< "desc=" << desc << ", "
<< "phEvent=" << static_cast<const void*>(phEvent) << ")";
context.logger->log_trace(oss.str());
return result;
}
%endif

%for obj in th.extract_objs(specs, r"function"):
<%
Expand Down Expand Up @@ -66,7 +134,7 @@ namespace validation_layer

if( nullptr == ${th.make_pfn_name(n, tags, obj)} )
%if ret_type == "ze_result_t":
return logAndPropagateResult("${th.make_func_name(n, tags, obj)}", ${X}_RESULT_ERROR_UNSUPPORTED_FEATURE);
return logAndPropagateResult_${th.make_func_name(n, tags, obj)}(${X}_RESULT_ERROR_UNSUPPORTED_FEATURE${', ' if not is_void_params else ''}${', '.join(th.make_param_lines(n, tags, obj, format=["name"]))});
%else:
return ${failure_return};
%endif
Expand All @@ -80,7 +148,7 @@ ${line} \
);
if(result!=${X}_RESULT_SUCCESS) \
%if ret_type == "ze_result_t":
return logAndPropagateResult("${th.make_func_name(n, tags, obj)}", result);
return logAndPropagateResult_${th.make_func_name(n, tags, obj)}(result${', ' if not is_void_params else ''}${', '.join(th.make_param_lines(n, tags, obj, format=["name"]))});
%else:
return ${failure_return};
%endif
Expand All @@ -103,7 +171,7 @@ ${line} \
);
if(result!=${X}_RESULT_SUCCESS) \
%if ret_type == "ze_result_t":
return logAndPropagateResult("${th.make_func_name(n, tags, obj)}", result);
return logAndPropagateResult_${th.make_func_name(n, tags, obj)}(result${', ' if not is_void_params else ''}${', '.join(th.make_param_lines(n, tags, obj, format=["name"]))});
%else:
return ${failure_return};
%endif
Expand Down Expand Up @@ -134,7 +202,7 @@ driver_result );
%endif
if(result!=${X}_RESULT_SUCCESS) \
%if ret_type == "ze_result_t":
return logAndPropagateResult("${th.make_func_name(n, tags, obj)}", result);
return logAndPropagateResult_${th.make_func_name(n, tags, obj)}(result${', ' if not is_void_params else ''}${', '.join(th.make_param_lines(n, tags, obj, format=["name"]))});
%else:
return ${failure_return};
%endif
Expand Down Expand Up @@ -173,7 +241,7 @@ return ${failure_return};
}
%endif
%if ret_type == "ze_result_t":
return logAndPropagateResult("${th.make_func_name(n, tags, obj)}", driver_result);
return logAndPropagateResult_${th.make_func_name(n, tags, obj)}(driver_result${', ' if not is_void_params else ''}${', '.join(th.make_param_lines(n, tags, obj, format=["name"]))});
%else:
return driver_result;
%endif
Expand Down Expand Up @@ -203,7 +271,7 @@ return ${failure_return};
auto numValHandlers = context.validationHandlers.size();
for (size_t i = 0; i < numValHandlers; i++) {
auto result = context.validationHandlers[i]->zeValidation->zexCounterBasedEventCreate2Prologue( hContext, hDevice, desc, phEvent );
if(result!=ZE_RESULT_SUCCESS) return logAndPropagateResult("zexCounterBasedEventCreate2", result);
if(result!=ZE_RESULT_SUCCESS) return logAndPropagateResult_zexCounterBasedEventCreate2(result, hContext, hDevice, desc, phEvent);
}

if(context.enableThreadingValidation){
Expand All @@ -212,7 +280,7 @@ return ${failure_return};

if(context.enableHandleLifetime){
auto result = context.handleLifetime->zeHandleLifetime.zexCounterBasedEventCreate2Prologue( hContext, hDevice, desc, phEvent );
if(result!=ZE_RESULT_SUCCESS) return logAndPropagateResult("zexCounterBasedEventCreate2", result);
if(result!=ZE_RESULT_SUCCESS) return logAndPropagateResult_zexCounterBasedEventCreate2(result, hContext, hDevice, desc, phEvent);
}

// This is an experimental function that must be accessed through the extension mechanism
Expand Down Expand Up @@ -254,7 +322,7 @@ return ${failure_return};

for (size_t i = 0; i < numValHandlers; i++) {
auto result = context.validationHandlers[i]->zeValidation->zexCounterBasedEventCreate2Epilogue( hContext, hDevice, desc, phEvent, driver_result);
if(result!=ZE_RESULT_SUCCESS) return logAndPropagateResult("zexCounterBasedEventCreate2", result);
if(result!=ZE_RESULT_SUCCESS) return logAndPropagateResult_zexCounterBasedEventCreate2(result, hContext, hDevice, desc, phEvent);
}

if(driver_result == ZE_RESULT_SUCCESS && context.enableHandleLifetime){
Expand All @@ -263,7 +331,7 @@ return ${failure_return};
// Note: counter-based events may not have a traditional event pool dependency
}
}
return logAndPropagateResult("zexCounterBasedEventCreate2", driver_result);
return logAndPropagateResult_zexCounterBasedEventCreate2(driver_result, hContext, hDevice, desc, phEvent);
}
%endif
} // namespace validation_layer
Expand Down
Loading
Loading