Skip to content
Open
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
11 changes: 0 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,6 @@ else()
endif()
add_definitions(-DLOADER_VERSION_SHA="${VERSION_SHA}")

if(SYSTEM_SPDLOG)
find_package(spdlog CONFIG)
if(spdlog_FOUND)
message(STATUS "System spdlog found.")
else()
message(FATAL_ERROR "SYSTEM_SPDLOG specified but spdlog wasn't found.")
endif()
else()
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/third_party/spdlog_headers")
endif()

include(FetchContent)

if(BUILD_L0_LOADER_TESTS)
Expand Down
2 changes: 1 addition & 1 deletion PRODUCT_GUID.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
1.28.4
cfa0eed1-ba15-4a52-8efe-5d532373fded
cfa0eed1-ba15-4a52-8efe-5d532373fded
62 changes: 41 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,32 +53,50 @@ To enable this debug tracing feature, set the environment variable `ZE_ENABLE_LO
This will enforce the Loader to print all errors whether fatal or non-fatal to stderr with the PREFIX `ZE_LOADER_DEBUG_TRACE:`.


# Logging to File - PREVIEW
The Level Zero Loader uses spdlog logging and can be controlled via environment variables:
# Logging to File
The Level Zero Loader provides built-in logging controlled via environment variables:

`ZEL_ENABLE_LOADER_LOGGING=1`
| Environment Variable | Default | Description |
|---|---|---|
| `ZEL_ENABLE_LOADER_LOGGING` | `0` | Set to `1` to enable file logging |
| `ZEL_LOADER_LOG_CONSOLE` | `0` | Set to `1` to enable console (stderr) logging, overrides file logging |
| `ZEL_LOADER_LOGGING_LEVEL` | `warn` | Log level: `trace`, `debug`, `info`, `warn`, `error`, `critical`, `off` |
| `ZEL_LOADER_LOG_DIR` | `~/.oneapi_logs` | Directory to write the log file into |
| `ZEL_LOADER_LOG_FILE` | `ze_loader.log` | Log filename |
| `ZEL_LOADER_LOG_PATTERN` | see below | Custom log format pattern |

## Output destination

The two flags control output as follows:

`ZEL_LOADER_LOG_DIR='/directory/path'`
| `ZEL_ENABLE_LOADER_LOGGING` | `ZEL_LOADER_LOG_CONSOLE` | Output |
|---|---|---|
| `0` (default) | `0` (default) | Logging disabled — no file or console output |
| `0` | `1` | Console output to **stderr** at the configured level |
| `1` | `0` | File output to `ZEL_LOADER_LOG_DIR/ZEL_LOADER_LOG_FILE` |
| `1` | `1` | Console output to **stderr** — file path is ignored |

`ZEL_LOADER_LOGGING_LEVEL=debug`
> **Note:** When both `ZEL_ENABLE_LOADER_LOGGING=1` and `ZEL_LOADER_LOG_CONSOLE=1` are set,
> output goes to the console only. The file path configuration is not used. If persistent file
> capture is required, set `ZEL_LOADER_LOG_CONSOLE=0`.

Default Log Pattern (Does not need to be set, please see below):
`ZEL_LOADER_LOG_PATTERN='[%Y-%m-%d %H:%M:%S.%e] [thread-id: %t] [%^%l%$] %v'`
The log directory (`ZEL_LOADER_LOG_DIR`) is created automatically on first use if it does not exist.

Valid logging levels are trace, debug, info, warn, error, critical, off.
Logging is disabled by default but when enabled the default level is 'warn'.
The default log file is 'ze_loader.log' in '.oneapi_logs' in the current
user's home directory.
## Log pattern

The default log pattern includes timestamps, thread IDs, log levels, and messages.
You can customize the pattern using `ZEL_LOADER_LOG_PATTERN`. Common pattern flags:
- `%t` - thread id
- `%Y-%m-%d %H:%M:%S.%e` - timestamp with milliseconds
- `%l` - log level
- `%v` - the actual log message
See spdlog documentation for more pattern options.
Default pattern (used when `ZEL_LOADER_LOG_PATTERN` is not set):
```
[%Y-%m-%d %H:%M:%S.%e] [thread-id: %t] [%^%l%$] %v
```

This feature is in early development and is preview only.
Supported pattern tokens:
- `%Y-%m-%d %H:%M:%S.%e` — timestamp with milliseconds (must appear as this exact sequence)
- `%t` — thread id
- `%P` — process id
- `%l` — log level label
- `%^` — begin color range (no-op when output is not a TTY)
- `%$` — end color range
- `%v` — log message

# Logging API calls
The Level Zero Loader will log all API calls whenever logging level is set to `trace` and
Expand All @@ -95,8 +113,10 @@ To print successful API call results, set
Otherwise, only error results will be printed in the API trace output.
NOTE: This will become the default behavior in future releases. for now, please set the env var to enable this logging feature.

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.
By default logs will be written to the log file as described above. To print logs
to stderr instead of a file, set `ZEL_LOADER_LOG_CONSOLE=1`. Note that when
`ZEL_LOADER_LOG_CONSOLE=1`, the file path configuration is ignored — output goes
to the console only.

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 thread-id, logger name, log level. Example output:

Expand Down
5 changes: 2 additions & 3 deletions scripts/templates/ze_loader_internal.h.mako
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ from templates import helper as th
#include "zer_ldrddi.h"

#include "loader/ze_loader.h"
#include "../utils/logging.h"
#include "spdlog/spdlog.h"
#include "../utils/ze_logger.h"
#include "source/lib/error_state.h"
namespace loader
{
Expand Down Expand Up @@ -139,7 +138,7 @@ namespace loader
bool instrumentationEnabled = false;
bool pciOrderingRequested = false;
dditable_t tracing_dditable = {};
std::shared_ptr<Logger> zel_logger;
std::shared_ptr<ZeLogger> zel_logger;
ze_driver_handle_t defaultZerDriverHandle = nullptr;
};

Expand Down
17 changes: 16 additions & 1 deletion source/layers/validation/ze_validation_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ namespace validation_layer
enableThreadingValidation = getenv_tobool( "ZE_ENABLE_THREADING_VALIDATION" );
verboseLogging = getenv_tobool( "ZEL_LOADER_LOGGING_ENABLE_SUCCESS_PRINT" );

logger = loader::createLogger();
// Point at the process-lifetime no-op logger until the loader calls
// zelLoaderSetLogger(). This is never null, so call sites need no null check.
// Thread-safety: zelLoaderSetLogger() writes this field exactly once on the
// init thread before zeDdiTable.exchange() makes the layer reachable.
logger = loader::noopLogger();
}

///////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -54,6 +58,17 @@ zelLoaderGetVersion(zel_component_version_t *version)
return ZE_RESULT_SUCCESS;
}

/// @brief Called by the loader immediately after dlopen to share its logger.
/// Replaces the no-op default so that validation-layer messages flow
/// through the same sink as the loader.
ZE_DLLEXPORT void ZE_APICALL
zelLoaderSetLogger(loader::ZeLogger *loaderLogger)
{
if (loaderLogger) {
validation_layer::context_t::getInstance().logger = loaderLogger;
}
}

#if defined(__cplusplus)
};
#endif
9 changes: 7 additions & 2 deletions source/layers/validation/ze_validation_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include "zet_entry_points.h"
#include "zes_entry_points.h"
#include "zer_entry_points.h"
#include "logging.h"
#include "ze_logger.h"
#include "ze_to_string.h"
#include "zes_to_string.h"
#include "zet_to_string.h"
Expand Down Expand Up @@ -57,7 +57,12 @@ namespace validation_layer
std::vector<validationChecker *> validationHandlers;
std::unique_ptr<HandleLifetimeValidation> handleLifetime;

std::shared_ptr<loader::Logger> logger;
// Raw pointer — the loader owns the ZeLogger and guarantees it outlives
// the validation layer during normal operation (dlclose happens before
// zel_logger is destroyed in context_t::~context_t()). Using a raw pointer
// (rather than shared_ptr) avoids _Sp_counted_base::_M_release() being
// called during _dl_call_fini after the control block has been freed.
loader::ZeLogger *logger;

static context_t& getInstance() {
static context_t instance;
Expand Down
8 changes: 6 additions & 2 deletions source/lib/ze_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,12 @@ namespace ze_lib
loaderLibraryPath = readLevelZeroLoaderLibraryPath();
}
#endif
if (debugTraceEnabled)
debug_trace_message("Static Loader Using Loader Library Path: ", loaderLibraryPath);
if (debugTraceEnabled) {
if (loaderLibraryPath.empty())
debug_trace_message("Static Loader Using Loader Library Path: ", "Not set");
else
debug_trace_message("Static Loader Using Loader Library Path: ", loaderLibraryPath);
}
std::string loaderFullLibraryPath = create_library_path(MAKE_LIBRARY_NAME( "ze_loader", L0_LOADER_VERSION), loaderLibraryPath.c_str());
loader = LOAD_DRIVER_LIBRARY(loaderFullLibraryPath.c_str());

Expand Down
3 changes: 2 additions & 1 deletion source/lib/ze_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
#include "zer_ddi.h"
#include "layers/zel_tracing_api.h"
#include "layers/zel_tracing_ddi.h"
#include "../utils/logging.h"
#include "../utils/ze_logger.h"
#include "loader/ze_loader.h"
#include "ze_util.h"
#include <vector>
#include <map>
#include <mutex>
#include <atomic>
#include <typeinfo>
Expand Down
100 changes: 88 additions & 12 deletions source/loader/ze_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,19 @@ namespace loader
auto handle = LOAD_DRIVER_LIBRARY( driver.name.c_str() );
if( NULL != handle )
{
if (debugTraceEnabled) {
#if !defined(_WIN32) && !defined(ANDROID)
struct link_map *dlinfo_map;
if (dlinfo(handle, RTLD_DI_LINKMAP, &dlinfo_map) == 0) {
debug_trace_message("init driver " + driver.name + " resolved path: ", std::string(dlinfo_map->l_name));
}
#elif defined(_WIN32)
char resolved[MAX_PATH];
if (GetModuleFileNameA(static_cast<HMODULE>(handle), resolved, MAX_PATH)) {
debug_trace_message("init driver " + driver.name + " resolved path: ", std::string(resolved));
}
#endif
}
driver.handle = handle;
} else {
std::string loadLibraryErrorValue;
Expand Down Expand Up @@ -616,15 +629,25 @@ namespace loader
auto discoveredDrivers = discoverEnabledDrivers();
std::string loadLibraryErrorValue;

zel_logger = createLogger();
#ifdef L0_STATIC_LOADER_BUILD
zel_logger = createLogger("Static Loader");
#else
zel_logger = createLogger("Dynamic Loader");
#endif

if ((getenv_string("ZEL_LOADER_LOGGING_LEVEL") == "trace") && !debugTraceEnabled) {
debugTraceEnabled = true;
zel_logger->log_to_console = false;
}

if (zel_logger->logging_enabled)
zel_logger->get_base_logger()->info("Loader Version {}.{}.{} {}", LOADER_VERSION_MAJOR, LOADER_VERSION_MINOR, LOADER_VERSION_PATCH, LOADER_VERSION_SHA);
if (zel_logger->getLevel() != loader::LogLevel::off) {
std::string ver_msg = "Loader Version " +
std::to_string(LOADER_VERSION_MAJOR) + "." +
std::to_string(LOADER_VERSION_MINOR) + "." +
std::to_string(LOADER_VERSION_PATCH) + " " +
LOADER_VERSION_SHA;
zel_logger->log_info(ver_msg);
}

add_loader_version();
std::string loaderLibraryPath;
Expand All @@ -637,8 +660,12 @@ namespace loader
loaderLibraryPath = readLevelZeroLoaderLibraryPath();
}
#endif
if (debugTraceEnabled)
debug_trace_message("Using Loader Library Path: ", loaderLibraryPath);
if (debugTraceEnabled) {
if (loaderLibraryPath.empty())
debug_trace_message("Using Loader Library Path: ", "Not set");
else
debug_trace_message("Using Loader Library Path: ", loaderLibraryPath);
}

if (debugTraceEnabled && driverDDIPathDefault) {
debug_trace_message("DDI Driver Extension Path is Enabled", "");
Expand All @@ -652,19 +679,31 @@ namespace loader
if( getenv_tobool( "ZE_ENABLE_NULL_DRIVER" ) )
{
zel_logger->log_info("Enabling Null Driver");
auto handle = LOAD_DRIVER_LIBRARY( create_library_path( MAKE_LIBRARY_NAME( "ze_null", L0_LOADER_VERSION ), loaderLibraryPath.c_str()).c_str());
if (debugTraceEnabled) {
std::string message = "ze_null Driver Init";
debug_trace_message(message, "");
}
std::string nullDriverPath = create_library_path( MAKE_LIBRARY_NAME( "ze_null", L0_LOADER_VERSION ), loaderLibraryPath.c_str());
if (debugTraceEnabled)
debug_trace_message("Null Driver Library Path (requested): ", nullDriverPath);
auto handle = LOAD_DRIVER_LIBRARY( nullDriverPath.c_str() );
if( NULL != handle )
{
if (debugTraceEnabled) {
#if !defined(_WIN32) && !defined(ANDROID)
struct link_map *dlinfo_map;
if (dlinfo(handle, RTLD_DI_LINKMAP, &dlinfo_map) == 0) {
debug_trace_message("Null Driver Library Path (resolved): ", std::string(dlinfo_map->l_name));
}
#elif defined(_WIN32)
char resolved[MAX_PATH];
if (GetModuleFileNameA(static_cast<HMODULE>(handle), resolved, MAX_PATH)) {
debug_trace_message("Null Driver Library Path (resolved): ", std::string(resolved));
}
#endif
}
allDrivers.emplace_back();
allDrivers.rbegin()->handle = handle;
allDrivers.rbegin()->name = "ze_null";
} else if (debugTraceEnabled) {
GET_LIBRARY_ERROR(loadLibraryErrorValue);
std::string errorMessage = "Load Library of " + create_library_path( MAKE_LIBRARY_NAME( "ze_null", L0_LOADER_VERSION ), loaderLibraryPath.c_str()) + " failed with ";
std::string errorMessage = "Load Library of " + nullDriverPath + " failed with ";
debug_trace_message(errorMessage, loadLibraryErrorValue);
loadLibraryErrorValue.clear();
}
Expand Down Expand Up @@ -721,9 +760,33 @@ namespace loader
{
zel_logger->log_info("Validation Layer Enabled");
std::string validationLayerLibraryPath = create_library_path(MAKE_LAYER_NAME( "ze_validation_layer" ), loaderLibraryPath.c_str());
if (debugTraceEnabled)
debug_trace_message("Validation Layer Library Path (requested): ", validationLayerLibraryPath);
validationLayer = LOAD_DRIVER_LIBRARY( validationLayerLibraryPath.c_str() );
if(validationLayer)
{
if (debugTraceEnabled) {
#if !defined(_WIN32) && !defined(ANDROID)
struct link_map *dlinfo_map;
if (dlinfo(validationLayer, RTLD_DI_LINKMAP, &dlinfo_map) == 0) {
debug_trace_message("Validation Layer Library Path (resolved): ", std::string(dlinfo_map->l_name));
}
#elif defined(_WIN32)
char resolved[MAX_PATH];
if (GetModuleFileNameA(static_cast<HMODULE>(validationLayer), resolved, MAX_PATH)) {
debug_trace_message("Validation Layer Library Path (resolved): ", std::string(resolved));
}
#endif
}
// Inject this loader instance's logger into the validation layer
// so both share a single file handle and mutex.
using SetLoggerFn = void (*)(loader::ZeLogger *);
auto setLogger = reinterpret_cast<SetLoggerFn>(
GET_FUNCTION_PTR(validationLayer, "zelLoaderSetLogger"));
if (setLogger) {
setLogger(zel_logger.get());
}

auto getVersion = reinterpret_cast<getVersion_t>(
GET_FUNCTION_PTR(validationLayer, "zelLoaderGetVersion"));
zel_component_version_t compVersion;
Expand All @@ -745,10 +808,23 @@ namespace loader
}
std::string tracingLayerLibraryPath = create_library_path(MAKE_LAYER_NAME( "ze_tracing_layer" ), loaderLibraryPath.c_str());
if (debugTraceEnabled)
debug_trace_message("Tracing Layer Library Path: ", tracingLayerLibraryPath);
debug_trace_message("Tracing Layer Library Path (requested): ", tracingLayerLibraryPath);
tracingLayer = LOAD_DRIVER_LIBRARY( tracingLayerLibraryPath.c_str() );
if(tracingLayer)
{
if (debugTraceEnabled) {
#if !defined(_WIN32) && !defined(ANDROID)
struct link_map *dlinfo_map;
if (dlinfo(tracingLayer, RTLD_DI_LINKMAP, &dlinfo_map) == 0) {
debug_trace_message("Tracing Layer Library Path (resolved): ", std::string(dlinfo_map->l_name));
}
#elif defined(_WIN32)
char resolved[MAX_PATH];
if (GetModuleFileNameA(static_cast<HMODULE>(tracingLayer), resolved, MAX_PATH)) {
debug_trace_message("Tracing Layer Library Path (resolved): ", std::string(resolved));
}
#endif
}
auto getVersion = reinterpret_cast<getVersion_t>(
GET_FUNCTION_PTR(tracingLayer, "zelLoaderGetVersion"));
zel_component_version_t compVersion;
Expand Down
3 changes: 1 addition & 2 deletions source/loader/ze_loader_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,10 @@ zeLoaderGetTracingHandle();
/// @brief Get pointer to Loader Context
///
/// @returns
/// - ::handle to tracing library
/// - ::Pointer to the Loader's Context
ZE_DLLEXPORT loader::context_t *ZE_APICALL
zelLoaderGetContext();


///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for getting version
///
Expand Down
5 changes: 2 additions & 3 deletions source/loader/ze_loader_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
#include "zer_ldrddi.h"

#include "loader/ze_loader.h"
#include "../utils/logging.h"
#include "spdlog/spdlog.h"
#include "../utils/ze_logger.h"
#include "source/lib/error_state.h"
namespace loader
{
Expand Down Expand Up @@ -175,7 +174,7 @@ namespace loader
bool instrumentationEnabled = false;
bool pciOrderingRequested = false;
dditable_t tracing_dditable = {};
std::shared_ptr<Logger> zel_logger;
std::shared_ptr<ZeLogger> zel_logger;
ze_driver_handle_t defaultZerDriverHandle = nullptr;
};

Expand Down
Loading
Loading