Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace intel_npu {
class ZeroEngineBackend final : public IEngineBackend {
public:
ZeroEngineBackend();
virtual ~ZeroEngineBackend();
~ZeroEngineBackend() override = default;
const std::shared_ptr<IDevice> getDevice() const override;
const std::shared_ptr<IDevice> getDevice(const std::string&) const override;
const std::string getName() const override {
Expand Down
2 changes: 0 additions & 2 deletions src/plugins/intel_npu/src/backend/src/zero_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ bool ZeroEngineBackend::isLUIDExtSupported() const {
return _initStruct->isExtensionSupported(std::string(ZE_DEVICE_LUID_EXT_NAME), ZE_MAKE_VERSION(1, 0));
}

ZeroEngineBackend::~ZeroEngineBackend() = default;

const std::shared_ptr<IDevice> ZeroEngineBackend::getDevice() const {
if (_devices.empty()) {
_logger.debug("ZeroEngineBackend - getDevice() returning empty list");
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/intel_npu/src/plugin/include/remote_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class RemoteContextImpl : public ov::IRemoteContext {
public:
RemoteContextImpl(const ov::SoPtr<IEngineBackend>& engineBackend, const ov::AnyMap& remote_properties = {});

~RemoteContextImpl() override = default;

/**
* @brief Returns name of a device on which underlying object is allocated.
* @return A device name string in fully specified format `<device_name>[.<device_id>[.<tile_id>]]` (e.g. GPU.0.1).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class ZeroApi {

~ZeroApi() = default;

static const std::shared_ptr<ZeroApi>& getInstance();
static const std::shared_ptr<ZeroApi> getInstance();

#define symbol_statement(symbol) decltype(&::symbol) symbol;
symbols_list();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class ZeroInitStructsHolder final {
return _external_memory_fd_win32_supported;
}

static const std::shared_ptr<ZeroInitStructsHolder>& getInstance();
static const std::shared_ptr<ZeroInitStructsHolder> getInstance();

private:
void initNpuDriver();
Expand All @@ -91,13 +91,15 @@ class ZeroInitStructsHolder final {
Logger log;

ze_context_handle_t context = nullptr;
uint32_t context_options = 0;
ze_driver_handle_t driver_handle = nullptr;
ze_device_handle_t device_handle = nullptr;

std::map<std::string, uint32_t> driver_extension_properties;
std::unique_ptr<ze_graph_dditable_ext_decorator> graph_dditable_ext_decorator;
std::unique_ptr<ze_command_queue_npu_dditable_ext_decorator> command_queue_npu_dditable_ext_decorator;
std::unique_ptr<ze_graph_profiling_ddi_table_ext_decorator> graph_profiling_npu_dditable_ext_decorator;
std::unique_ptr<ze_context_npu_dditable_ext_decorator> context_npu_dditable_ext_decorator;

ze_driver_properties_t driver_properties = {};
uint32_t mutable_command_list_ext_version = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <ze_api.h>
#include <ze_command_queue_npu_ext.h>
#include <ze_context_npu_ext.h>
#include <ze_graph_ext.h>
#include <ze_graph_profiling_ext.h>

Expand All @@ -19,6 +20,10 @@ using ze_command_queue_npu_dditable_ext_last_t = ze_command_queue_npu_dditable_e
* @brief Last version of the Graph Profiling functions used within plugin
*/
using ze_graph_profiling_dditable_ext_last_t = ze_graph_profiling_dditable_ext_t;
/**
* @brief Last version of the Context functions used within plugin
*/
using ze_context_npu_dditable_ext_last_t = ze_context_npu_dditable_ext_t;

/**
* @brief Table of Graph Extension functions pointers and function wrappers
Expand Down Expand Up @@ -301,6 +306,58 @@ struct ze_graph_profiling_ddi_table_ext_decorator final {
ze_pfnGraphProfilingLogGetString_ext_t pfnProfilingLogGetString;
};

/**
* @brief Context function wrappers
* @details Use function wrappers for function from within higher driver versions in order to throw when loaded driver
* is older than required
*/
struct ze_context_npu_dditable_ext_decorator final {
private:
ze_context_npu_dditable_ext_last_t* const _impl;
const uint32_t _contextExtVersion;

ze_context_npu_dditable_ext_decorator(const ze_context_npu_dditable_ext_decorator&) = delete;
ze_context_npu_dditable_ext_decorator(ze_context_npu_dditable_ext_decorator&&) = delete;

ze_context_npu_dditable_ext_decorator& operator=(const ze_context_npu_dditable_ext_decorator&) = delete;
ze_context_npu_dditable_ext_decorator& operator=(ze_context_npu_dditable_ext_decorator&&) = delete;

void throwWhenUnsupported(std::string_view func, uint32_t since) {
if (_contextExtVersion < since) {
OPENVINO_THROW("Driver Context extension function ",
func,
" is only available with version ",
ZE_MAJOR_VERSION(since),
".",
ZE_MINOR_VERSION(since),
" or later");
}
}

public:
ze_context_npu_dditable_ext_decorator(ze_context_npu_dditable_ext_last_t* impl, uint32_t contextExtVersion)
: _impl(impl),
_contextExtVersion(contextExtVersion) {}
~ze_context_npu_dditable_ext_decorator() = default;

inline uint32_t version() const {
return _contextExtVersion;
}

// version 1.0
ze_result_t ZE_APICALL pfnSetProperties(ze_context_handle_t hContext,
ze_context_properties_npu_ext_t* contextProperties) {
throwWhenUnsupported("pfnSetProperties", ZE_CONTEXT_NPU_EXT_VERSION_1_0);
return _impl->pfnSetProperties(hContext, contextProperties);
}

ze_result_t ZE_APICALL pfnReleaseMemory(ze_context_handle_t hContext) {
throwWhenUnsupported("pfnReleaseMemory", ZE_CONTEXT_NPU_EXT_VERSION_1_0);
return _impl->pfnReleaseMemory(hContext);
}
};

using ze_graph_dditable_ext_curr_t = ze_graph_dditable_ext_decorator;
using ze_command_queue_npu_dditable_ext_curr_t = ze_command_queue_npu_dditable_ext_decorator;
using ze_graph_profiling_dditable_ext_curr_t = ze_graph_profiling_ddi_table_ext_decorator;
using ze_context_npu_dditable_ext_curr_t = ze_context_npu_dditable_ext_decorator;
14 changes: 12 additions & 2 deletions src/plugins/intel_npu/src/utils/src/zero/zero_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "intel_npu/utils/zero/zero_api.hpp"

#include <mutex>

#include "openvino/util/file_util.hpp"
#include "openvino/util/shared_object.hpp"

Expand Down Expand Up @@ -49,8 +51,16 @@ ZeroApi::ZeroApi() {
#undef symbol_statement
}

const std::shared_ptr<ZeroApi>& ZeroApi::getInstance() {
static std::shared_ptr<ZeroApi> instance = std::make_shared<ZeroApi>();
const std::shared_ptr<ZeroApi> ZeroApi::getInstance() {
static std::mutex mutex;
static std::weak_ptr<ZeroApi> weak_instance;

std::lock_guard<std::mutex> lock(mutex);
auto instance = weak_instance.lock();
if (!instance) {
instance = std::make_shared<ZeroApi>();
weak_instance = instance;
}
return instance;
}

Expand Down
77 changes: 64 additions & 13 deletions src/plugins/intel_npu/src/utils/src/zero/zero_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <ze_command_queue_npu_ext.h>
#include <ze_mem_import_system_memory_ext.h>

#include <mutex>
#include <regex>

#include "intel_npu/utils/zero/zero_utils.hpp"
Expand Down Expand Up @@ -181,7 +182,7 @@ ZeroInitStructsHolder::ZeroInitStructsHolder()
// Query our graph extension version
std::string graph_ext_name;
uint32_t graph_ext_version = 0;
uint32_t target_graph_ext_version = ZE_GRAPH_EXT_VERSION_CURRENT;
uint32_t target_graph_ext_version = ZE_GRAPH_EXT_VERSION_1_14;

#if defined(NPU_PLUGIN_DEVELOPER_BUILD)
const char* extVersion = std::getenv("NPU_ZE_GRAPH_EXT_VERSION");
Expand Down Expand Up @@ -222,6 +223,15 @@ ZeroInitStructsHolder::ZeroInitStructsHolder()
driver_ext_major_version);
}

// Load our graph extension
ze_graph_dditable_ext_t* graph_ddi_table_ext = nullptr;
THROW_ON_FAIL_FOR_LEVELZERO("zeDriverGetExtensionFunctionAddress",
zeDriverGetExtensionFunctionAddress(driver_handle,
graph_ext_name.c_str(),
reinterpret_cast<void**>(&graph_ddi_table_ext)));
graph_dditable_ext_decorator =
std::make_unique<ze_graph_dditable_ext_decorator>(graph_ddi_table_ext, graph_ext_version);

log.info("Found Driver Version %d.%d, Graph Extension Version %d.%d (%s)",
ZE_MAJOR_VERSION(ze_drv_api_version),
ZE_MINOR_VERSION(ze_drv_api_version),
Expand Down Expand Up @@ -256,15 +266,6 @@ ZeroInitStructsHolder::ZeroInitStructsHolder()
std::make_unique<ze_command_queue_npu_dditable_ext_decorator>(_command_queue_npu_dditable_ext,
command_queue_ext_version);

// Load our graph extension
ze_graph_dditable_ext_t* graph_ddi_table_ext = nullptr;
THROW_ON_FAIL_FOR_LEVELZERO("zeDriverGetExtensionFunctionAddress",
zeDriverGetExtensionFunctionAddress(driver_handle,
graph_ext_name.c_str(),
reinterpret_cast<void**>(&graph_ddi_table_ext)));
graph_dditable_ext_decorator =
std::make_unique<ze_graph_dditable_ext_decorator>(graph_ddi_table_ext, graph_ext_version);

// Query the mutable command list version
#ifdef _WIN32
// The 2688 Windows driver version doesn't support as expected the MutableCommandList feature
Expand Down Expand Up @@ -295,12 +296,45 @@ ZeroInitStructsHolder::ZeroInitStructsHolder()
graph_profiling_npu_dditable_ext_decorator =
std::make_unique<ze_graph_profiling_ddi_table_ext_decorator>(_graph_profiling_ddi_table_ext);

// Query our context extension version
std::string context_ext_name;
uint32_t context_ext_version = 0;
std::tie(context_ext_version, context_ext_name) =
queryDriverExtensionVersion(ZE_CONTEXT_NPU_EXT_NAME, ZE_CONTEXT_NPU_EXT_VERSION_CURRENT, extProps, count);

log.debug("NPU context extension version %d.%d",
ZE_MAJOR_VERSION(context_ext_version),
ZE_MINOR_VERSION(context_ext_version));

// Load our context extension
ze_context_npu_dditable_ext_last_t* _context_npu_dditable_ext = nullptr;
if (context_ext_version) {
THROW_ON_FAIL_FOR_LEVELZERO(
"zeDriverGetExtensionFunctionAddress " + context_ext_name,
zeDriverGetExtensionFunctionAddress(driver_handle,
context_ext_name.c_str(),
reinterpret_cast<void**>(&_context_npu_dditable_ext)));
}

context_npu_dditable_ext_decorator =
std::make_unique<ze_context_npu_dditable_ext_decorator>(_context_npu_dditable_ext, context_ext_version);

uint32_t device_count = 1;
// Get our target device
THROW_ON_FAIL_FOR_LEVELZERO("zeDeviceGet", zeDeviceGet(driver_handle, &device_count, &device_handle));

// Create context - share between the compiler and the backend
ze_context_desc_t context_desc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC, 0, 0};
ze_context_desc_t context_desc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC, nullptr, 0};

ze_context_properties_npu_ext_t context_properties = {};
if (context_ext_version >= ZE_MAKE_VERSION(1, 0)) {
context_options |= ZE_NPU_CONTEXT_OPTION_ENABLE_IDLE_OPTIMIZATIONS;

context_properties.stype = ZE_STRUCTURE_TYPE_CONTEXT_PROPERTIES_NPU_EXT;
context_properties.options = context_options;
context_desc.pNext = static_cast<const void*>(&context_properties);
}

THROW_ON_FAIL_FOR_LEVELZERO("zeContextCreate", zeContextCreate(driver_handle, &context_desc, &context));
log.debug("ZeroInitStructsHolder initialize complete");

Expand Down Expand Up @@ -331,15 +365,32 @@ ZeroInitStructsHolder::ZeroInitStructsHolder()
}
}

const std::shared_ptr<ZeroInitStructsHolder>& ZeroInitStructsHolder::getInstance() {
static std::shared_ptr<ZeroInitStructsHolder> instance = std::make_shared<ZeroInitStructsHolder>();
const std::shared_ptr<ZeroInitStructsHolder> ZeroInitStructsHolder::getInstance() {
static std::mutex mutex;
static std::weak_ptr<ZeroInitStructsHolder> weak_instance;

std::lock_guard<std::mutex> lock(mutex);
auto instance = weak_instance.lock();
if (!instance) {
instance = std::make_shared<ZeroInitStructsHolder>();
weak_instance = instance;
}
return instance;
}

ZeroInitStructsHolder::~ZeroInitStructsHolder() {
if (context) {
if (context_npu_dditable_ext_decorator->version() >= ZE_MAKE_VERSION(1, 0)) {
context_options &= ~(ZE_NPU_CONTEXT_OPTION_ENABLE_IDLE_OPTIMIZATIONS);
ze_context_properties_npu_ext_t context_properties = {ZE_STRUCTURE_TYPE_CONTEXT_PROPERTIES_NPU_EXT,
nullptr,
context_options};
context_npu_dditable_ext_decorator->pfnSetProperties(context, &context_properties);
}

log.debug("ZeroInitStructsHolder - performing zeContextDestroy");
auto result = zeContextDestroy(context);
context = nullptr;
if (result != ZE_RESULT_SUCCESS) {
if (result == ZE_RESULT_ERROR_UNINITIALIZED) {
log.warning("zeContextDestroy failed to destroy the context; Level zero context was already destroyed");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ ZeroInitStructsMock::ZeroInitStructsMock(int extVersion)
driver_ext_major_version);
}

// Load our graph extension
ze_graph_dditable_ext_t* graph_ddi_table_ext = nullptr;
THROW_ON_FAIL_FOR_LEVELZERO("zeDriverGetExtensionFunctionAddress",
zeDriverGetExtensionFunctionAddress(driver_handle,
graph_ext_name.c_str(),
reinterpret_cast<void**>(&graph_ddi_table_ext)));
graph_dditable_ext_decorator =
std::make_unique<ze_graph_dditable_ext_decorator>(graph_ddi_table_ext, graph_ext_version);

log.info("Found Driver Version %d.%d, Graph Extension Version %d.%d (%s)",
ZE_MAJOR_VERSION(ze_drv_api_version),
ZE_MINOR_VERSION(ze_drv_api_version),
Expand Down Expand Up @@ -228,15 +237,6 @@ ZeroInitStructsMock::ZeroInitStructsMock(int extVersion)
std::make_unique<ze_command_queue_npu_dditable_ext_decorator>(_command_queue_npu_dditable_ext,
command_queue_ext_version);

// Load our graph extension
ze_graph_dditable_ext_t* graph_ddi_table_ext = nullptr;
THROW_ON_FAIL_FOR_LEVELZERO("zeDriverGetExtensionFunctionAddress",
zeDriverGetExtensionFunctionAddress(driver_handle,
graph_ext_name.c_str(),
reinterpret_cast<void**>(&graph_ddi_table_ext)));
graph_dditable_ext_decorator =
std::make_unique<ze_graph_dditable_ext_decorator>(graph_ddi_table_ext, graph_ext_version);

// Query the mutable command list version
[[maybe_unused]] std::string mutuable_command_list_ext_name;
std::tie(mutable_command_list_ext_version, mutuable_command_list_ext_name) =
Expand All @@ -260,12 +260,45 @@ ZeroInitStructsMock::ZeroInitStructsMock(int extVersion)
graph_profiling_npu_dditable_ext_decorator =
std::make_unique<ze_graph_profiling_ddi_table_ext_decorator>(_graph_profiling_ddi_table_ext);

// Query our context extension version
std::string context_ext_name;
uint32_t context_ext_version = 0;
std::tie(context_ext_version, context_ext_name) =
queryDriverExtensionVersion(ZE_CONTEXT_NPU_EXT_NAME, ZE_CONTEXT_NPU_EXT_VERSION_CURRENT, extProps, count);

log.debug("NPU context extension version %d.%d",
ZE_MAJOR_VERSION(context_ext_version),
ZE_MINOR_VERSION(context_ext_version));

// Load our context extension
ze_context_npu_dditable_ext_last_t* _context_npu_dditable_ext = nullptr;
if (context_ext_version) {
THROW_ON_FAIL_FOR_LEVELZERO(
"zeDriverGetExtensionFunctionAddress " + context_ext_name,
zeDriverGetExtensionFunctionAddress(driver_handle,
context_ext_name.c_str(),
reinterpret_cast<void**>(&_context_npu_dditable_ext)));
}

context_npu_dditable_ext_decorator =
std::make_unique<ze_context_npu_dditable_ext_decorator>(_context_npu_dditable_ext, context_ext_version);

uint32_t device_count = 1;
// Get our target device
THROW_ON_FAIL_FOR_LEVELZERO("zeDeviceGet", zeDeviceGet(driver_handle, &device_count, &device_handle));

// Create context - share between the compiler and the backend
ze_context_desc_t context_desc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC, 0, 0};
ze_context_desc_t context_desc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC, nullptr, 0};

ze_context_properties_npu_ext_t context_properties = {};
if (context_ext_version >= ZE_MAKE_VERSION(1, 0)) {
context_options |= ZE_NPU_CONTEXT_OPTION_ENABLE_IDLE_OPTIMIZATIONS;

context_properties.stype = ZE_STRUCTURE_TYPE_CONTEXT_PROPERTIES_NPU_EXT;
context_properties.options = context_options;
context_desc.pNext = static_cast<const void*>(&context_properties);
}

THROW_ON_FAIL_FOR_LEVELZERO("zeContextCreate", zeContextCreate(driver_handle, &context_desc, &context));
log.debug("ZeroInitStructsMock initialize complete");

Expand Down Expand Up @@ -298,8 +331,17 @@ ZeroInitStructsMock::ZeroInitStructsMock(int extVersion)

ZeroInitStructsMock::~ZeroInitStructsMock() {
if (context) {
log.debug("ZeroInitStructsMock - performing zeContextDestroy");
if (context_npu_dditable_ext_decorator->version() >= ZE_MAKE_VERSION(1, 0)) {
context_options &= ~(ZE_NPU_CONTEXT_OPTION_ENABLE_IDLE_OPTIMIZATIONS);
ze_context_properties_npu_ext_t context_properties = {ZE_STRUCTURE_TYPE_CONTEXT_PROPERTIES_NPU_EXT,
nullptr,
context_options};
context_npu_dditable_ext_decorator->pfnSetProperties(context, &context_properties);
}

log.debug("ZeroInitStructsHolder - performing zeContextDestroy");
auto result = zeContextDestroy(context);
context = nullptr;
if (result != ZE_RESULT_SUCCESS) {
if (result == ZE_RESULT_ERROR_UNINITIALIZED) {
log.warning("zeContextDestroy failed to destroy the context; Level zero context was already destroyed");
Expand Down
Loading
Loading