From 17e74a58240535a1ab2fd516623af04f5a68ef85 Mon Sep 17 00:00:00 2001 From: Matthew Michel Date: Wed, 24 Jun 2026 08:25:44 -0700 Subject: [PATCH 1/3] [UR][L0v2] Introduce urGraphGetIdExp to provide unique graph identifiers --- .../include/unified-runtime/ur_api.h | 30 +++++++ .../include/unified-runtime/ur_api_funcs.def | 1 + .../include/unified-runtime/ur_ddi.h | 6 ++ .../include/unified-runtime/ur_print.h | 10 +++ .../include/unified-runtime/ur_print.hpp | 26 ++++++ unified-runtime/scripts/core/exp-graph.yml | 12 +++ unified-runtime/scripts/core/registry.yml | 5 +- .../source/adapters/cuda/graph.cpp | 5 ++ .../adapters/cuda/ur_interface_loader.cpp | 1 + unified-runtime/source/adapters/hip/graph.cpp | 5 ++ .../adapters/hip/ur_interface_loader.cpp | 1 + .../source/adapters/level_zero/graph.cpp | 8 ++ .../source/adapters/level_zero/platform.cpp | 2 + .../source/adapters/level_zero/platform.hpp | 2 + .../level_zero/ur_interface_loader.cpp | 1 + .../level_zero/ur_interface_loader.hpp | 1 + .../source/adapters/level_zero/v2/graph.cpp | 12 +++ .../source/adapters/mock/ur_mockddi.cpp | 46 ++++++++++ .../source/adapters/native_cpu/graph.cpp | 6 ++ .../native_cpu/ur_interface_loader.cpp | 1 + .../source/adapters/offload/graph.cpp | 5 ++ .../adapters/offload/ur_interface_loader.cpp | 1 + .../source/adapters/opencl/graph.cpp | 5 ++ .../adapters/opencl/ur_interface_loader.cpp | 1 + .../loader/layers/tracing/ur_trcddi.cpp | 38 ++++++++ .../loader/layers/validation/ur_valddi.cpp | 29 +++++++ unified-runtime/source/loader/loader.def.in | 2 + unified-runtime/source/loader/loader.map.in | 2 + unified-runtime/source/loader/ur_ldrddi.cpp | 19 ++++ unified-runtime/source/loader/ur_libapi.cpp | 27 ++++++ unified-runtime/source/loader/ur_print.cpp | 9 ++ unified-runtime/source/ur_api.cpp | 22 +++++ .../test/conformance/exp_graph/CMakeLists.txt | 1 + .../conformance/exp_graph/urGraphGetIdExp.cpp | 86 +++++++++++++++++++ 34 files changed, 427 insertions(+), 1 deletion(-) create mode 100644 unified-runtime/test/conformance/exp_graph/urGraphGetIdExp.cpp diff --git a/unified-runtime/include/unified-runtime/ur_api.h b/unified-runtime/include/unified-runtime/ur_api.h index e52459cb9b5d3..886d2ca9c4f7f 100644 --- a/unified-runtime/include/unified-runtime/ur_api.h +++ b/unified-runtime/include/unified-runtime/ur_api.h @@ -532,6 +532,8 @@ typedef enum ur_function_t { UR_FUNCTION_IPC_PUT_EVENT_HANDLE_EXP = 324, /// Enumerator for ::urIPCOpenEventHandleExp UR_FUNCTION_IPC_OPEN_EVENT_HANDLE_EXP = 325, + /// Enumerator for ::urGraphGetIdExp + UR_FUNCTION_GRAPH_GET_ID_EXP = 326, /// @cond UR_FUNCTION_FORCE_UINT32 = 0x7fffffff /// @endcond @@ -14252,6 +14254,25 @@ UR_APIEXPORT ur_result_t UR_APICALL urGraphIsEmptyExp( /// [out] Pointer to a boolean where the result will be stored. bool *pResult); +/////////////////////////////////////////////////////////////////////////////// +/// @brief Returns a process-unique identifier that increases monotonically per +/// graph. +/// +/// @returns +/// - ::UR_RESULT_SUCCESS +/// - ::UR_RESULT_ERROR_UNINITIALIZED +/// - ::UR_RESULT_ERROR_DEVICE_LOST +/// - ::UR_RESULT_ERROR_ADAPTER_SPECIFIC +/// - ::UR_RESULT_ERROR_INVALID_NULL_HANDLE +/// + `NULL == hGraph` +/// - ::UR_RESULT_ERROR_INVALID_NULL_POINTER +/// + `NULL == pGraphId` +UR_APIEXPORT ur_result_t UR_APICALL urGraphGetIdExp( + /// [in] Handle of the graph to query. + ur_exp_graph_handle_t hGraph, + /// [out] Pointer to a uint64_t where the unique graph ID will be stored. + uint64_t *pGraphId); + /////////////////////////////////////////////////////////////////////////////// /// @brief Callback function invoked when a graph is destroyed. typedef void (*ur_exp_graph_destruction_callback_t)( @@ -16879,6 +16900,15 @@ typedef struct ur_graph_is_empty_exp_params_t { bool **ppResult; } ur_graph_is_empty_exp_params_t; +/////////////////////////////////////////////////////////////////////////////// +/// @brief Function parameters for urGraphGetIdExp +/// @details Each entry is a pointer to the parameter passed to the function; +/// allowing the callback the ability to modify the parameter's value +typedef struct ur_graph_get_id_exp_params_t { + ur_exp_graph_handle_t *phGraph; + uint64_t **ppGraphId; +} ur_graph_get_id_exp_params_t; + /////////////////////////////////////////////////////////////////////////////// /// @brief Function parameters for urGraphSetDestructionCallbackExp /// @details Each entry is a pointer to the parameter passed to the function; diff --git a/unified-runtime/include/unified-runtime/ur_api_funcs.def b/unified-runtime/include/unified-runtime/ur_api_funcs.def index 48f6ec8435f5a..f293af2583af0 100644 --- a/unified-runtime/include/unified-runtime/ur_api_funcs.def +++ b/unified-runtime/include/unified-runtime/ur_api_funcs.def @@ -218,6 +218,7 @@ _UR_API(urGraphInstantiateGraphExp) _UR_API(urGraphDestroyExp) _UR_API(urGraphExecutableGraphDestroyExp) _UR_API(urGraphIsEmptyExp) +_UR_API(urGraphGetIdExp) _UR_API(urGraphSetDestructionCallbackExp) _UR_API(urGraphDumpContentsExp) _UR_API(urGraphGetNativeHandleExp) diff --git a/unified-runtime/include/unified-runtime/ur_ddi.h b/unified-runtime/include/unified-runtime/ur_ddi.h index 7ba70aca48810..85b8fc33158a6 100644 --- a/unified-runtime/include/unified-runtime/ur_ddi.h +++ b/unified-runtime/include/unified-runtime/ur_ddi.h @@ -1919,6 +1919,11 @@ typedef ur_result_t(UR_APICALL *ur_pfnGraphExecutableGraphDestroyExp_t)( typedef ur_result_t(UR_APICALL *ur_pfnGraphIsEmptyExp_t)(ur_exp_graph_handle_t, bool *); +/////////////////////////////////////////////////////////////////////////////// +/// @brief Function-pointer for urGraphGetIdExp +typedef ur_result_t(UR_APICALL *ur_pfnGraphGetIdExp_t)(ur_exp_graph_handle_t, + uint64_t *); + /////////////////////////////////////////////////////////////////////////////// /// @brief Function-pointer for urGraphSetDestructionCallbackExp typedef ur_result_t(UR_APICALL *ur_pfnGraphSetDestructionCallbackExp_t)( @@ -1947,6 +1952,7 @@ typedef struct ur_graph_exp_dditable_t { ur_pfnGraphDestroyExp_t pfnDestroyExp; ur_pfnGraphExecutableGraphDestroyExp_t pfnExecutableGraphDestroyExp; ur_pfnGraphIsEmptyExp_t pfnIsEmptyExp; + ur_pfnGraphGetIdExp_t pfnGetIdExp; ur_pfnGraphSetDestructionCallbackExp_t pfnSetDestructionCallbackExp; ur_pfnGraphDumpContentsExp_t pfnDumpContentsExp; ur_pfnGraphGetNativeHandleExp_t pfnGetNativeHandleExp; diff --git a/unified-runtime/include/unified-runtime/ur_print.h b/unified-runtime/include/unified-runtime/ur_print.h index fb47190b49119..b78b93d23f090 100644 --- a/unified-runtime/include/unified-runtime/ur_print.h +++ b/unified-runtime/include/unified-runtime/ur_print.h @@ -3765,6 +3765,16 @@ UR_APIEXPORT ur_result_t UR_APICALL urPrintGraphIsEmptyExpParams( const struct ur_graph_is_empty_exp_params_t *params, char *buffer, const size_t buff_size, size_t *out_size); +/////////////////////////////////////////////////////////////////////////////// +/// @brief Print ur_graph_get_id_exp_params_t struct +/// @returns +/// - ::UR_RESULT_SUCCESS +/// - ::UR_RESULT_ERROR_INVALID_SIZE +/// - `buff_size < out_size` +UR_APIEXPORT ur_result_t UR_APICALL urPrintGraphGetIdExpParams( + const struct ur_graph_get_id_exp_params_t *params, char *buffer, + const size_t buff_size, size_t *out_size); + /////////////////////////////////////////////////////////////////////////////// /// @brief Print ur_graph_set_destruction_callback_exp_params_t struct /// @returns diff --git a/unified-runtime/include/unified-runtime/ur_print.hpp b/unified-runtime/include/unified-runtime/ur_print.hpp index 356c722c12305..293a369ac1165 100644 --- a/unified-runtime/include/unified-runtime/ur_print.hpp +++ b/unified-runtime/include/unified-runtime/ur_print.hpp @@ -1422,6 +1422,9 @@ inline std::ostream &operator<<(std::ostream &os, enum ur_function_t value) { case UR_FUNCTION_IPC_OPEN_EVENT_HANDLE_EXP: os << "UR_FUNCTION_IPC_OPEN_EVENT_HANDLE_EXP"; break; + case UR_FUNCTION_GRAPH_GET_ID_EXP: + os << "UR_FUNCTION_GRAPH_GET_ID_EXP"; + break; default: os << "unknown enumerator"; break; @@ -21820,6 +21823,26 @@ inline std::ostream &operator<<( return os; } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Print operator for the ur_graph_get_id_exp_params_t type +/// @returns +/// std::ostream & +inline std::ostream & +operator<<(std::ostream &os, + [[maybe_unused]] const struct ur_graph_get_id_exp_params_t *params) { + + os << ".hGraph = "; + + ur::details::printPtr(os, *(params->phGraph)); + + os << ", "; + os << ".pGraphId = "; + + ur::details::printPtr(os, *(params->ppGraphId)); + + return os; +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Print operator for the ur_graph_set_destruction_callback_exp_params_t /// type @@ -23743,6 +23766,9 @@ inline ur_result_t UR_APICALL printFunctionParams(std::ostream &os, case UR_FUNCTION_GRAPH_IS_EMPTY_EXP: { os << (const struct ur_graph_is_empty_exp_params_t *)params; } break; + case UR_FUNCTION_GRAPH_GET_ID_EXP: { + os << (const struct ur_graph_get_id_exp_params_t *)params; + } break; case UR_FUNCTION_GRAPH_SET_DESTRUCTION_CALLBACK_EXP: { os << (const struct ur_graph_set_destruction_callback_exp_params_t *)params; } break; diff --git a/unified-runtime/scripts/core/exp-graph.yml b/unified-runtime/scripts/core/exp-graph.yml index d693714d0f860..473df9e8772e4 100644 --- a/unified-runtime/scripts/core/exp-graph.yml +++ b/unified-runtime/scripts/core/exp-graph.yml @@ -187,6 +187,18 @@ params: returns: - $X_RESULT_ERROR_INVALID_GRAPH --- #-------------------------------------------------------------------------- +type: function +desc: "Returns a process-unique identifier that increases monotonically per graph." +class: $xGraph +name: GetIdExp +params: + - type: $x_exp_graph_handle_t + name: hGraph + desc: "[in] Handle of the graph to query." + - type: uint64_t* + name: pGraphId + desc: "[out] Pointer to a uint64_t where the unique graph ID will be stored." +--- #-------------------------------------------------------------------------- type: fptr_typedef desc: "Callback function invoked when a graph is destroyed." name: $x_exp_graph_destruction_callback_t diff --git a/unified-runtime/scripts/core/registry.yml b/unified-runtime/scripts/core/registry.yml index d329bdee2a582..bb9e08f583450 100644 --- a/unified-runtime/scripts/core/registry.yml +++ b/unified-runtime/scripts/core/registry.yml @@ -757,7 +757,10 @@ etors: - name: IPC_OPEN_EVENT_HANDLE_EXP desc: Enumerator for $xIPCOpenEventHandleExp value: '325' -max_id: '325' +- name: GRAPH_GET_ID_EXP + desc: Enumerator for $xGraphGetIdExp + value: '326' +max_id: '326' --- type: enum desc: Defines structure types diff --git a/unified-runtime/source/adapters/cuda/graph.cpp b/unified-runtime/source/adapters/cuda/graph.cpp index 58562e0491f1e..c2eb87a364437 100644 --- a/unified-runtime/source/adapters/cuda/graph.cpp +++ b/unified-runtime/source/adapters/cuda/graph.cpp @@ -29,6 +29,11 @@ urGraphIsEmptyExp(ur_exp_graph_handle_t /* hGraph */, bool * /* pIsEmpty */) { return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; } +UR_APIEXPORT ur_result_t UR_APICALL +urGraphGetIdExp(ur_exp_graph_handle_t /* hGraph */, uint64_t * /* pGraphId */) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + UR_APIEXPORT ur_result_t UR_APICALL urGraphSetDestructionCallbackExp( ur_exp_graph_handle_t /* hGraph */, ur_exp_graph_destruction_callback_t /* pfnCallback */, diff --git a/unified-runtime/source/adapters/cuda/ur_interface_loader.cpp b/unified-runtime/source/adapters/cuda/ur_interface_loader.cpp index 7db1f93343a5b..95672aa7d6676 100644 --- a/unified-runtime/source/adapters/cuda/ur_interface_loader.cpp +++ b/unified-runtime/source/adapters/cuda/ur_interface_loader.cpp @@ -99,6 +99,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urGetGraphExpProcAddrTable( pDdiTable->pfnDestroyExp = urGraphDestroyExp; pDdiTable->pfnExecutableGraphDestroyExp = urGraphExecutableGraphDestroyExp; pDdiTable->pfnIsEmptyExp = urGraphIsEmptyExp; + pDdiTable->pfnGetIdExp = urGraphGetIdExp; pDdiTable->pfnSetDestructionCallbackExp = urGraphSetDestructionCallbackExp; pDdiTable->pfnDumpContentsExp = urGraphDumpContentsExp; pDdiTable->pfnGetNativeHandleExp = urGraphGetNativeHandleExp; diff --git a/unified-runtime/source/adapters/hip/graph.cpp b/unified-runtime/source/adapters/hip/graph.cpp index 960ee2243eccd..3cecf9548d281 100644 --- a/unified-runtime/source/adapters/hip/graph.cpp +++ b/unified-runtime/source/adapters/hip/graph.cpp @@ -29,6 +29,11 @@ urGraphIsEmptyExp(ur_exp_graph_handle_t /* hGraph */, bool * /* pIsEmpty */) { return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; } +UR_APIEXPORT ur_result_t UR_APICALL +urGraphGetIdExp(ur_exp_graph_handle_t /* hGraph */, uint64_t * /* pGraphId */) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + UR_APIEXPORT ur_result_t UR_APICALL urGraphSetDestructionCallbackExp( ur_exp_graph_handle_t /* hGraph */, ur_exp_graph_destruction_callback_t /* pfnCallback */, diff --git a/unified-runtime/source/adapters/hip/ur_interface_loader.cpp b/unified-runtime/source/adapters/hip/ur_interface_loader.cpp index 109cd38e6fd81..2b15e2f9f8aa2 100644 --- a/unified-runtime/source/adapters/hip/ur_interface_loader.cpp +++ b/unified-runtime/source/adapters/hip/ur_interface_loader.cpp @@ -99,6 +99,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urGetGraphExpProcAddrTable( pDdiTable->pfnDestroyExp = urGraphDestroyExp; pDdiTable->pfnExecutableGraphDestroyExp = urGraphExecutableGraphDestroyExp; pDdiTable->pfnIsEmptyExp = urGraphIsEmptyExp; + pDdiTable->pfnGetIdExp = urGraphGetIdExp; pDdiTable->pfnSetDestructionCallbackExp = urGraphSetDestructionCallbackExp; pDdiTable->pfnDumpContentsExp = urGraphDumpContentsExp; pDdiTable->pfnGetNativeHandleExp = urGraphGetNativeHandleExp; diff --git a/unified-runtime/source/adapters/level_zero/graph.cpp b/unified-runtime/source/adapters/level_zero/graph.cpp index 8b47e0f1663db..3ab7e25a2cc59 100644 --- a/unified-runtime/source/adapters/level_zero/graph.cpp +++ b/unified-runtime/source/adapters/level_zero/graph.cpp @@ -44,6 +44,14 @@ ur_result_t urGraphIsEmptyExp(ur_exp_graph_handle_t /* hGraph */, return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; } +ur_result_t urGraphGetIdExp(ur_exp_graph_handle_t /* hGraph */, + uint64_t * /* pGraphId */) { + UR_LOG_LEGACY(ERR, + logger::LegacyMessage("[UR][L0] {} function not implemented!"), + "{} function not implemented!", __FUNCTION__); + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + ur_result_t urGraphSetDestructionCallbackExp( ur_exp_graph_handle_t /* hGraph */, ur_exp_graph_destruction_callback_t /* pfnCallback */, diff --git a/unified-runtime/source/adapters/level_zero/platform.cpp b/unified-runtime/source/adapters/level_zero/platform.cpp index 574365c92df97..e8b7b146f3651 100644 --- a/unified-runtime/source/adapters/level_zero/platform.cpp +++ b/unified-runtime/source/adapters/level_zero/platform.cpp @@ -616,6 +616,8 @@ ur_result_t ur_platform_handle_t_::initialize() { {"zeGraphSetDestructionCallbackExp", reinterpret_cast( &ZeGraphExt.zeGraphSetDestructionCallbackExp)}, + {"zeGraphGetIdExt", + reinterpret_cast(&ZeGraphExt.zeGraphGetIdExt)}, }; for (auto &[funcName, funcAddr] : ZeGraphOptionalFuncNameToAddrMap) { diff --git a/unified-runtime/source/adapters/level_zero/platform.hpp b/unified-runtime/source/adapters/level_zero/platform.hpp index e6f582c78eee0..5f5066122e8ec 100644 --- a/unified-runtime/source/adapters/level_zero/platform.hpp +++ b/unified-runtime/source/adapters/level_zero/platform.hpp @@ -201,6 +201,8 @@ struct ur_platform_handle_t_ : ur::handle_base, ze_result_t (*zeCommandListGetGraphExp)( ze_command_list_handle_t hCommandList, ze_graph_handle_t *phGraph); ze_result_t (*zeGraphIsEmptyExp)(ze_graph_handle_t hGraph); + ze_result_t (*zeGraphGetIdExt)(ze_graph_handle_t hGraph, + uint64_t *pGraphId); ze_result_t (*zeGraphDumpContentsExp)(ze_graph_handle_t hGraph, const char *filePath, void *pNext); ze_result_t (*zeGraphSetDestructionCallbackExp)( diff --git a/unified-runtime/source/adapters/level_zero/ur_interface_loader.cpp b/unified-runtime/source/adapters/level_zero/ur_interface_loader.cpp index ce80aeda5b306..35cbb5404b325 100644 --- a/unified-runtime/source/adapters/level_zero/ur_interface_loader.cpp +++ b/unified-runtime/source/adapters/level_zero/ur_interface_loader.cpp @@ -287,6 +287,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urGetGraphExpProcAddrTable( pDdiTable->pfnExecutableGraphDestroyExp = ur::level_zero::urGraphExecutableGraphDestroyExp; pDdiTable->pfnIsEmptyExp = ur::level_zero::urGraphIsEmptyExp; + pDdiTable->pfnGetIdExp = ur::level_zero::urGraphGetIdExp; pDdiTable->pfnSetDestructionCallbackExp = ur::level_zero::urGraphSetDestructionCallbackExp; pDdiTable->pfnDumpContentsExp = ur::level_zero::urGraphDumpContentsExp; diff --git a/unified-runtime/source/adapters/level_zero/ur_interface_loader.hpp b/unified-runtime/source/adapters/level_zero/ur_interface_loader.hpp index fa3def0da0446..72d0d0b2c40e4 100644 --- a/unified-runtime/source/adapters/level_zero/ur_interface_loader.hpp +++ b/unified-runtime/source/adapters/level_zero/ur_interface_loader.hpp @@ -891,6 +891,7 @@ ur_result_t urQueueIsGraphCaptureEnabledExp(ur_queue_handle_t hQueue, ur_result_t urQueueGetGraphExp(ur_queue_handle_t hQueue, ur_exp_graph_handle_t *phGraph); ur_result_t urGraphIsEmptyExp(ur_exp_graph_handle_t hGraph, bool *pResult); +ur_result_t urGraphGetIdExp(ur_exp_graph_handle_t hGraph, uint64_t *pGraphId); ur_result_t urGraphSetDestructionCallbackExp( ur_exp_graph_handle_t hGraph, ur_exp_graph_destruction_callback_t pfnCallback, void *pUserData); diff --git a/unified-runtime/source/adapters/level_zero/v2/graph.cpp b/unified-runtime/source/adapters/level_zero/v2/graph.cpp index 24ea29529c64e..8fca37b6d0470 100644 --- a/unified-runtime/source/adapters/level_zero/v2/graph.cpp +++ b/unified-runtime/source/adapters/level_zero/v2/graph.cpp @@ -148,6 +148,18 @@ ur_result_t urGraphIsEmptyExp(ur_exp_graph_handle_t hGraph, bool *pIsEmpty) { return UR_RESULT_SUCCESS; } +ur_result_t urGraphGetIdExp(ur_exp_graph_handle_t hGraph, uint64_t *pGraphId) { + ur_context_handle_t hContext = hGraph->getContext(); + auto ZeGetId = hContext->getPlatform()->ZeGraphExt.zeGraphGetIdExt; + if (!checkGraphExtensionSupport(hContext) || !ZeGetId) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + ZE2UR_CALL(ZeGetId, (hGraph->getZeHandle(), pGraphId)); + + return UR_RESULT_SUCCESS; +} + ur_result_t urGraphSetDestructionCallbackExp( ur_exp_graph_handle_t hGraph, ur_exp_graph_destruction_callback_t pfnCallback, void *pUserData) { diff --git a/unified-runtime/source/adapters/mock/ur_mockddi.cpp b/unified-runtime/source/adapters/mock/ur_mockddi.cpp index a09e14bdd876e..64069291be595 100644 --- a/unified-runtime/source/adapters/mock/ur_mockddi.cpp +++ b/unified-runtime/source/adapters/mock/ur_mockddi.cpp @@ -13343,6 +13343,50 @@ __urdlllocal ur_result_t UR_APICALL urGraphIsEmptyExp( return exceptionToResult(std::current_exception()); } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urGraphGetIdExp +__urdlllocal ur_result_t UR_APICALL urGraphGetIdExp( + /// [in] Handle of the graph to query. + ur_exp_graph_handle_t hGraph, + /// [out] Pointer to a uint64_t where the unique graph ID will be stored. + uint64_t *pGraphId) try { + ur_result_t result = UR_RESULT_SUCCESS; + + ur_graph_get_id_exp_params_t params = {&hGraph, &pGraphId}; + + auto beforeCallback = reinterpret_cast( + mock::getCallbacks().get_before_callback("urGraphGetIdExp")); + if (beforeCallback) { + result = beforeCallback(¶ms); + if (result != UR_RESULT_SUCCESS) { + return result; + } + } + + auto replaceCallback = reinterpret_cast( + mock::getCallbacks().get_replace_callback("urGraphGetIdExp")); + if (replaceCallback) { + result = replaceCallback(¶ms); + } else { + + result = UR_RESULT_SUCCESS; + } + + if (result != UR_RESULT_SUCCESS) { + return result; + } + + auto afterCallback = reinterpret_cast( + mock::getCallbacks().get_after_callback("urGraphGetIdExp")); + if (afterCallback) { + return afterCallback(¶ms); + } + + return result; +} catch (...) { + return exceptionToResult(std::current_exception()); +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urGraphSetDestructionCallbackExp __urdlllocal ur_result_t UR_APICALL urGraphSetDestructionCallbackExp( @@ -14023,6 +14067,8 @@ UR_DLLEXPORT ur_result_t UR_APICALL urGetGraphExpProcAddrTable( pDdiTable->pfnIsEmptyExp = driver::urGraphIsEmptyExp; + pDdiTable->pfnGetIdExp = driver::urGraphGetIdExp; + pDdiTable->pfnSetDestructionCallbackExp = driver::urGraphSetDestructionCallbackExp; diff --git a/unified-runtime/source/adapters/native_cpu/graph.cpp b/unified-runtime/source/adapters/native_cpu/graph.cpp index 495f77873ce5d..9f42c4e07515f 100644 --- a/unified-runtime/source/adapters/native_cpu/graph.cpp +++ b/unified-runtime/source/adapters/native_cpu/graph.cpp @@ -33,6 +33,12 @@ urGraphIsEmptyExp(ur_exp_graph_handle_t /* hGraph */, bool * /* pIsEmpty */) { DIE_NO_IMPLEMENTATION; } +UR_APIEXPORT ur_result_t UR_APICALL +urGraphGetIdExp(ur_exp_graph_handle_t /* hGraph */, uint64_t * /* pGraphId */) { + + DIE_NO_IMPLEMENTATION; +} + UR_APIEXPORT ur_result_t UR_APICALL urGraphSetDestructionCallbackExp( ur_exp_graph_handle_t /* hGraph */, ur_exp_graph_destruction_callback_t /* pfnCallback */, diff --git a/unified-runtime/source/adapters/native_cpu/ur_interface_loader.cpp b/unified-runtime/source/adapters/native_cpu/ur_interface_loader.cpp index ee9c0dd165c55..affb9bec6c207 100644 --- a/unified-runtime/source/adapters/native_cpu/ur_interface_loader.cpp +++ b/unified-runtime/source/adapters/native_cpu/ur_interface_loader.cpp @@ -99,6 +99,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urGetGraphExpProcAddrTable( pDdiTable->pfnDestroyExp = urGraphDestroyExp; pDdiTable->pfnExecutableGraphDestroyExp = urGraphExecutableGraphDestroyExp; pDdiTable->pfnIsEmptyExp = urGraphIsEmptyExp; + pDdiTable->pfnGetIdExp = urGraphGetIdExp; pDdiTable->pfnSetDestructionCallbackExp = urGraphSetDestructionCallbackExp; pDdiTable->pfnDumpContentsExp = urGraphDumpContentsExp; pDdiTable->pfnGetNativeHandleExp = urGraphGetNativeHandleExp; diff --git a/unified-runtime/source/adapters/offload/graph.cpp b/unified-runtime/source/adapters/offload/graph.cpp index 45671f8a598e8..ef0d2a6e7a0af 100644 --- a/unified-runtime/source/adapters/offload/graph.cpp +++ b/unified-runtime/source/adapters/offload/graph.cpp @@ -29,6 +29,11 @@ urGraphIsEmptyExp(ur_exp_graph_handle_t /* hGraph */, bool * /* pIsEmpty */) { return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; } +UR_APIEXPORT ur_result_t UR_APICALL +urGraphGetIdExp(ur_exp_graph_handle_t /* hGraph */, uint64_t * /* pGraphId */) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + UR_APIEXPORT ur_result_t UR_APICALL urGraphSetDestructionCallbackExp( ur_exp_graph_handle_t /* hGraph */, ur_exp_graph_destruction_callback_t /* pfnCallback */, diff --git a/unified-runtime/source/adapters/offload/ur_interface_loader.cpp b/unified-runtime/source/adapters/offload/ur_interface_loader.cpp index b2e7c10c39145..8ac1d935aa127 100644 --- a/unified-runtime/source/adapters/offload/ur_interface_loader.cpp +++ b/unified-runtime/source/adapters/offload/ur_interface_loader.cpp @@ -99,6 +99,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urGetGraphExpProcAddrTable( pDdiTable->pfnDestroyExp = urGraphDestroyExp; pDdiTable->pfnExecutableGraphDestroyExp = urGraphExecutableGraphDestroyExp; pDdiTable->pfnIsEmptyExp = urGraphIsEmptyExp; + pDdiTable->pfnGetIdExp = urGraphGetIdExp; pDdiTable->pfnSetDestructionCallbackExp = urGraphSetDestructionCallbackExp; pDdiTable->pfnDumpContentsExp = urGraphDumpContentsExp; pDdiTable->pfnGetNativeHandleExp = urGraphGetNativeHandleExp; diff --git a/unified-runtime/source/adapters/opencl/graph.cpp b/unified-runtime/source/adapters/opencl/graph.cpp index 5b5c578bbaa39..5af875b527841 100644 --- a/unified-runtime/source/adapters/opencl/graph.cpp +++ b/unified-runtime/source/adapters/opencl/graph.cpp @@ -29,6 +29,11 @@ urGraphIsEmptyExp(ur_exp_graph_handle_t /* hGraph */, bool * /* pIsEmpty */) { return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; } +UR_APIEXPORT ur_result_t UR_APICALL +urGraphGetIdExp(ur_exp_graph_handle_t /* hGraph */, uint64_t * /* pGraphId */) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + UR_APIEXPORT ur_result_t UR_APICALL urGraphSetDestructionCallbackExp( ur_exp_graph_handle_t /* hGraph */, ur_exp_graph_destruction_callback_t /* pfnCallback */, diff --git a/unified-runtime/source/adapters/opencl/ur_interface_loader.cpp b/unified-runtime/source/adapters/opencl/ur_interface_loader.cpp index 1bfabe9dc2770..3fe8a08ad44a1 100644 --- a/unified-runtime/source/adapters/opencl/ur_interface_loader.cpp +++ b/unified-runtime/source/adapters/opencl/ur_interface_loader.cpp @@ -518,6 +518,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urGetGraphExpProcAddrTable( pDdiTable->pfnDestroyExp = urGraphDestroyExp; pDdiTable->pfnExecutableGraphDestroyExp = urGraphExecutableGraphDestroyExp; pDdiTable->pfnIsEmptyExp = urGraphIsEmptyExp; + pDdiTable->pfnGetIdExp = urGraphGetIdExp; pDdiTable->pfnSetDestructionCallbackExp = urGraphSetDestructionCallbackExp; pDdiTable->pfnDumpContentsExp = urGraphDumpContentsExp; pDdiTable->pfnGetNativeHandleExp = urGraphGetNativeHandleExp; diff --git a/unified-runtime/source/loader/layers/tracing/ur_trcddi.cpp b/unified-runtime/source/loader/layers/tracing/ur_trcddi.cpp index b931542d05728..ca5c58005900c 100644 --- a/unified-runtime/source/loader/layers/tracing/ur_trcddi.cpp +++ b/unified-runtime/source/loader/layers/tracing/ur_trcddi.cpp @@ -11323,6 +11323,41 @@ __urdlllocal ur_result_t UR_APICALL urGraphIsEmptyExp( return result; } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urGraphGetIdExp +__urdlllocal ur_result_t UR_APICALL urGraphGetIdExp( + /// [in] Handle of the graph to query. + ur_exp_graph_handle_t hGraph, + /// [out] Pointer to a uint64_t where the unique graph ID will be stored. + uint64_t *pGraphId) { + auto pfnGetIdExp = getContext()->urDdiTable.GraphExp.pfnGetIdExp; + + if (nullptr == pfnGetIdExp) + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + + ur_graph_get_id_exp_params_t params = {&hGraph, &pGraphId}; + uint64_t instance = getContext()->notify_begin(UR_FUNCTION_GRAPH_GET_ID_EXP, + "urGraphGetIdExp", ¶ms); + + auto &logger = getContext()->logger; + UR_LOG_L(logger, INFO, " ---> urGraphGetIdExp\n"); + + ur_result_t result = pfnGetIdExp(hGraph, pGraphId); + + getContext()->notify_end(UR_FUNCTION_GRAPH_GET_ID_EXP, "urGraphGetIdExp", + ¶ms, &result, instance); + + if (logger.getLevel() <= UR_LOGGER_LEVEL_INFO) { + std::ostringstream args_str; + ur::extras::printFunctionParams(args_str, UR_FUNCTION_GRAPH_GET_ID_EXP, + ¶ms); + UR_LOG_L(logger, INFO, " <--- urGraphGetIdExp({}) -> {};\n", + args_str.str(), result); + } + + return result; +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urGraphSetDestructionCallbackExp __urdlllocal ur_result_t UR_APICALL urGraphSetDestructionCallbackExp( @@ -12135,6 +12170,9 @@ __urdlllocal ur_result_t UR_APICALL urGetGraphExpProcAddrTable( dditable.pfnIsEmptyExp = pDdiTable->pfnIsEmptyExp; pDdiTable->pfnIsEmptyExp = ur_tracing_layer::urGraphIsEmptyExp; + dditable.pfnGetIdExp = pDdiTable->pfnGetIdExp; + pDdiTable->pfnGetIdExp = ur_tracing_layer::urGraphGetIdExp; + dditable.pfnSetDestructionCallbackExp = pDdiTable->pfnSetDestructionCallbackExp; pDdiTable->pfnSetDestructionCallbackExp = diff --git a/unified-runtime/source/loader/layers/validation/ur_valddi.cpp b/unified-runtime/source/loader/layers/validation/ur_valddi.cpp index f49b88e5b28bb..3fc6dfa023bfb 100644 --- a/unified-runtime/source/loader/layers/validation/ur_valddi.cpp +++ b/unified-runtime/source/loader/layers/validation/ur_valddi.cpp @@ -12101,6 +12101,32 @@ __urdlllocal ur_result_t UR_APICALL urGraphIsEmptyExp( return result; } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urGraphGetIdExp +__urdlllocal ur_result_t UR_APICALL urGraphGetIdExp( + /// [in] Handle of the graph to query. + ur_exp_graph_handle_t hGraph, + /// [out] Pointer to a uint64_t where the unique graph ID will be stored. + uint64_t *pGraphId) { + auto pfnGetIdExp = getContext()->urDdiTable.GraphExp.pfnGetIdExp; + + if (nullptr == pfnGetIdExp) { + return UR_RESULT_ERROR_UNINITIALIZED; + } + + if (getContext()->enableParameterValidation) { + if (NULL == pGraphId) + return UR_RESULT_ERROR_INVALID_NULL_POINTER; + + if (NULL == hGraph) + return UR_RESULT_ERROR_INVALID_NULL_HANDLE; + } + + ur_result_t result = pfnGetIdExp(hGraph, pGraphId); + + return result; +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urGraphSetDestructionCallbackExp __urdlllocal ur_result_t UR_APICALL urGraphSetDestructionCallbackExp( @@ -12880,6 +12906,9 @@ UR_DLLEXPORT ur_result_t UR_APICALL urGetGraphExpProcAddrTable( dditable.pfnIsEmptyExp = pDdiTable->pfnIsEmptyExp; pDdiTable->pfnIsEmptyExp = ur_validation_layer::urGraphIsEmptyExp; + dditable.pfnGetIdExp = pDdiTable->pfnGetIdExp; + pDdiTable->pfnGetIdExp = ur_validation_layer::urGraphGetIdExp; + dditable.pfnSetDestructionCallbackExp = pDdiTable->pfnSetDestructionCallbackExp; pDdiTable->pfnSetDestructionCallbackExp = diff --git a/unified-runtime/source/loader/loader.def.in b/unified-runtime/source/loader/loader.def.in index 902bd8a3c651e..57c8fb82b22ed 100644 --- a/unified-runtime/source/loader/loader.def.in +++ b/unified-runtime/source/loader/loader.def.in @@ -146,6 +146,7 @@ EXPORTS urGraphDumpContentsExp urGraphExecutableGraphDestroyExp urGraphExecutableGraphGetNativeHandleExp + urGraphGetIdExp urGraphGetNativeHandleExp urGraphInstantiateGraphExp urGraphIsEmptyExp @@ -404,6 +405,7 @@ EXPORTS urPrintGraphDumpContentsExpParams urPrintGraphExecutableGraphDestroyExpParams urPrintGraphExecutableGraphGetNativeHandleExpParams + urPrintGraphGetIdExpParams urPrintGraphGetNativeHandleExpParams urPrintGraphInstantiateGraphExpParams urPrintGraphIsEmptyExpParams diff --git a/unified-runtime/source/loader/loader.map.in b/unified-runtime/source/loader/loader.map.in index b62d656eb5e6a..5296424a405fe 100644 --- a/unified-runtime/source/loader/loader.map.in +++ b/unified-runtime/source/loader/loader.map.in @@ -146,6 +146,7 @@ urGraphDumpContentsExp; urGraphExecutableGraphDestroyExp; urGraphExecutableGraphGetNativeHandleExp; + urGraphGetIdExp; urGraphGetNativeHandleExp; urGraphInstantiateGraphExp; urGraphIsEmptyExp; @@ -404,6 +405,7 @@ urPrintGraphDumpContentsExpParams; urPrintGraphExecutableGraphDestroyExpParams; urPrintGraphExecutableGraphGetNativeHandleExpParams; + urPrintGraphGetIdExpParams; urPrintGraphGetNativeHandleExpParams; urPrintGraphInstantiateGraphExpParams; urPrintGraphIsEmptyExpParams; diff --git a/unified-runtime/source/loader/ur_ldrddi.cpp b/unified-runtime/source/loader/ur_ldrddi.cpp index f100d55232ce8..e09858787eaaf 100644 --- a/unified-runtime/source/loader/ur_ldrddi.cpp +++ b/unified-runtime/source/loader/ur_ldrddi.cpp @@ -6403,6 +6403,24 @@ __urdlllocal ur_result_t UR_APICALL urGraphIsEmptyExp( return pfnIsEmptyExp(hGraph, pResult); } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Intercept function for urGraphGetIdExp +__urdlllocal ur_result_t UR_APICALL urGraphGetIdExp( + /// [in] Handle of the graph to query. + ur_exp_graph_handle_t hGraph, + /// [out] Pointer to a uint64_t where the unique graph ID will be stored. + uint64_t *pGraphId) { + + auto *dditable = *reinterpret_cast(hGraph); + + auto *pfnGetIdExp = dditable->GraphExp.pfnGetIdExp; + if (nullptr == pfnGetIdExp) + return UR_RESULT_ERROR_UNINITIALIZED; + + // forward to device-platform + return pfnGetIdExp(hGraph, pGraphId); +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Intercept function for urGraphSetDestructionCallbackExp __urdlllocal ur_result_t UR_APICALL urGraphSetDestructionCallbackExp( @@ -7107,6 +7125,7 @@ UR_DLLEXPORT ur_result_t UR_APICALL urGetGraphExpProcAddrTable( pDdiTable->pfnExecutableGraphDestroyExp = ur_loader::urGraphExecutableGraphDestroyExp; pDdiTable->pfnIsEmptyExp = ur_loader::urGraphIsEmptyExp; + pDdiTable->pfnGetIdExp = ur_loader::urGraphGetIdExp; pDdiTable->pfnSetDestructionCallbackExp = ur_loader::urGraphSetDestructionCallbackExp; pDdiTable->pfnDumpContentsExp = ur_loader::urGraphDumpContentsExp; diff --git a/unified-runtime/source/loader/ur_libapi.cpp b/unified-runtime/source/loader/ur_libapi.cpp index 1cca29fb573ed..2ecb305ffbe97 100644 --- a/unified-runtime/source/loader/ur_libapi.cpp +++ b/unified-runtime/source/loader/ur_libapi.cpp @@ -11693,6 +11693,33 @@ ur_result_t UR_APICALL urGraphIsEmptyExp( return exceptionToResult(std::current_exception()); } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Returns a process-unique identifier that increases monotonically per +/// graph. +/// +/// @returns +/// - ::UR_RESULT_SUCCESS +/// - ::UR_RESULT_ERROR_UNINITIALIZED +/// - ::UR_RESULT_ERROR_DEVICE_LOST +/// - ::UR_RESULT_ERROR_ADAPTER_SPECIFIC +/// - ::UR_RESULT_ERROR_INVALID_NULL_HANDLE +/// + `NULL == hGraph` +/// - ::UR_RESULT_ERROR_INVALID_NULL_POINTER +/// + `NULL == pGraphId` +ur_result_t UR_APICALL urGraphGetIdExp( + /// [in] Handle of the graph to query. + ur_exp_graph_handle_t hGraph, + /// [out] Pointer to a uint64_t where the unique graph ID will be stored. + uint64_t *pGraphId) try { + auto pfnGetIdExp = ur_lib::getContext()->urDdiTable.GraphExp.pfnGetIdExp; + if (nullptr == pfnGetIdExp) + return UR_RESULT_ERROR_UNINITIALIZED; + + return pfnGetIdExp(hGraph, pGraphId); +} catch (...) { + return exceptionToResult(std::current_exception()); +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Register a callback to be invoked when the graph is destroyed. /// diff --git a/unified-runtime/source/loader/ur_print.cpp b/unified-runtime/source/loader/ur_print.cpp index c0343a4a3dba4..8004688ec7f57 100644 --- a/unified-runtime/source/loader/ur_print.cpp +++ b/unified-runtime/source/loader/ur_print.cpp @@ -2187,6 +2187,15 @@ ur_result_t urPrintGraphIsEmptyExpParams( return str_copy(&ss, buffer, buff_size, out_size); } +ur_result_t +urPrintGraphGetIdExpParams(const struct ur_graph_get_id_exp_params_t *params, + char *buffer, const size_t buff_size, + size_t *out_size) { + std::stringstream ss; + ss << params; + return str_copy(&ss, buffer, buff_size, out_size); +} + ur_result_t urPrintGraphSetDestructionCallbackExpParams( const struct ur_graph_set_destruction_callback_exp_params_t *params, char *buffer, const size_t buff_size, size_t *out_size) { diff --git a/unified-runtime/source/ur_api.cpp b/unified-runtime/source/ur_api.cpp index 53fa2f5eaf718..4d5ba8f9b17fa 100644 --- a/unified-runtime/source/ur_api.cpp +++ b/unified-runtime/source/ur_api.cpp @@ -10146,6 +10146,28 @@ ur_result_t UR_APICALL urGraphIsEmptyExp( return result; } +/////////////////////////////////////////////////////////////////////////////// +/// @brief Returns a process-unique identifier that increases monotonically per +/// graph. +/// +/// @returns +/// - ::UR_RESULT_SUCCESS +/// - ::UR_RESULT_ERROR_UNINITIALIZED +/// - ::UR_RESULT_ERROR_DEVICE_LOST +/// - ::UR_RESULT_ERROR_ADAPTER_SPECIFIC +/// - ::UR_RESULT_ERROR_INVALID_NULL_HANDLE +/// + `NULL == hGraph` +/// - ::UR_RESULT_ERROR_INVALID_NULL_POINTER +/// + `NULL == pGraphId` +ur_result_t UR_APICALL urGraphGetIdExp( + /// [in] Handle of the graph to query. + ur_exp_graph_handle_t hGraph, + /// [out] Pointer to a uint64_t where the unique graph ID will be stored. + uint64_t *pGraphId) { + ur_result_t result = UR_RESULT_SUCCESS; + return result; +} + /////////////////////////////////////////////////////////////////////////////// /// @brief Register a callback to be invoked when the graph is destroyed. /// diff --git a/unified-runtime/test/conformance/exp_graph/CMakeLists.txt b/unified-runtime/test/conformance/exp_graph/CMakeLists.txt index 8e633b2c0cd4c..11230d04c8882 100644 --- a/unified-runtime/test/conformance/exp_graph/CMakeLists.txt +++ b/unified-runtime/test/conformance/exp_graph/CMakeLists.txt @@ -8,6 +8,7 @@ add_conformance_devices_test(exp_graph urGraphDestroyExp.cpp urGraphDumpContentsExp.cpp urGraphExecutableGraphGetNativeHandleExp.cpp + urGraphGetIdExp.cpp urGraphGetNativeHandleExp.cpp urGraphInstantiateGraphExp.cpp urGraphIsEmptyExp.cpp diff --git a/unified-runtime/test/conformance/exp_graph/urGraphGetIdExp.cpp b/unified-runtime/test/conformance/exp_graph/urGraphGetIdExp.cpp new file mode 100644 index 0000000000000..2ee55cdae9471 --- /dev/null +++ b/unified-runtime/test/conformance/exp_graph/urGraphGetIdExp.cpp @@ -0,0 +1,86 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM +// Exceptions. See https://llvm.org/LICENSE.txt for license information. +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "fixtures.h" + +#include + +struct urGraphGetIdExpTest : uur::urGraphExpTest { + void SetUp() override { + UUR_RETURN_ON_FATAL_FAILURE(urGraphExpTest::SetUp()); + // Unique graph id support was added in this driver version. + std::tuple minL0DriverVersion = {1, 15, 38921}; + SKIP_IF_DRIVER_TOO_OLD("Level-Zero", minL0DriverVersion, platform, device); + } +}; + +UUR_DEVICE_TEST_SUITE_WITH_QUEUE_TYPES( + urGraphGetIdExpTest, + ::testing::Values(0 /* In-Order */, + UR_QUEUE_FLAG_OUT_OF_ORDER_EXEC_MODE_ENABLE)); + +TEST_P(urGraphGetIdExpTest, SuccessMonotonicallyIncreasing) { + uint64_t currentGraphId = 0; + ASSERT_SUCCESS(urGraphGetIdExp(graph, ¤tGraphId)); + + // Ensure the IDs increase monotonically when graphs are kept alive + std::vector graphs; + for (int i = 0; i < 5; i++) { + ur_exp_graph_handle_t nextGraph = nullptr; + ASSERT_SUCCESS(urGraphCreateExp(context, &nextGraph)); + graphs.push_back(nextGraph); + + uint64_t nextGraphId = 0; + ASSERT_SUCCESS(urGraphGetIdExp(nextGraph, &nextGraphId)); + ASSERT_GT(nextGraphId, currentGraphId); + currentGraphId = nextGraphId; + } + + // Ensure the IDs increase monotonically even when graphs are destroyed + for (int i = 0; i < 5; i++) { + ur_exp_graph_handle_t nextGraph = nullptr; + ASSERT_SUCCESS(urGraphCreateExp(context, &nextGraph)); + + uint64_t nextGraphId = 0; + ASSERT_SUCCESS(urGraphGetIdExp(nextGraph, &nextGraphId)); + ASSERT_GT(nextGraphId, currentGraphId); + currentGraphId = nextGraphId; + + ASSERT_SUCCESS(urGraphDestroyExp(nextGraph)); + } + + for (ur_exp_graph_handle_t currentGraph : graphs) { + ASSERT_SUCCESS(urGraphDestroyExp(currentGraph)); + } +} + +TEST_P(urGraphGetIdExpTest, SuccessUniqueAcrossContexts) { + uint64_t firstGraphId = 0; + ASSERT_SUCCESS(urGraphGetIdExp(graph, &firstGraphId)); + + ur_context_handle_t secondContext = nullptr; + ASSERT_SUCCESS(urContextCreate(1, &device, nullptr, &secondContext)); + + ur_exp_graph_handle_t secondGraph = nullptr; + ASSERT_SUCCESS(urGraphCreateExp(secondContext, &secondGraph)); + + uint64_t secondGraphId = 0; + ASSERT_SUCCESS(urGraphGetIdExp(secondGraph, &secondGraphId)); + ASSERT_GT(secondGraphId, firstGraphId); + + ASSERT_SUCCESS(urGraphDestroyExp(secondGraph)); + ASSERT_SUCCESS(urContextRelease(secondContext)); +} + +TEST_P(urGraphGetIdExpTest, InvalidNullHandleGraph) { + uint64_t graphId = 0; + ASSERT_EQ_RESULT(UR_RESULT_ERROR_INVALID_NULL_HANDLE, + urGraphGetIdExp(nullptr, &graphId)); +} + +TEST_P(urGraphGetIdExpTest, InvalidNullPtrGraphId) { + ASSERT_EQ_RESULT(UR_RESULT_ERROR_INVALID_NULL_POINTER, + urGraphGetIdExp(graph, nullptr)); +} From ebcf935ca0c0fea4143d76c67f15ff13e42a4c1e Mon Sep 17 00:00:00 2001 From: Matthew Michel Date: Thu, 25 Jun 2026 17:06:20 -0700 Subject: [PATCH 2/3] Workaround zeDriverGetExtensionFunctionAddress issue that led to memory corruption in SYCL tests --- .../source/adapters/level_zero/platform.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/unified-runtime/source/adapters/level_zero/platform.cpp b/unified-runtime/source/adapters/level_zero/platform.cpp index e8b7b146f3651..4ec36e527de19 100644 --- a/unified-runtime/source/adapters/level_zero/platform.cpp +++ b/unified-runtime/source/adapters/level_zero/platform.cpp @@ -616,14 +616,24 @@ ur_result_t ur_platform_handle_t_::initialize() { {"zeGraphSetDestructionCallbackExp", reinterpret_cast( &ZeGraphExt.zeGraphSetDestructionCallbackExp)}, - {"zeGraphGetIdExt", - reinterpret_cast(&ZeGraphExt.zeGraphGetIdExt)}, }; for (auto &[funcName, funcAddr] : ZeGraphOptionalFuncNameToAddrMap) { ZE_CALL_NOCHECK(zeDriverGetExtensionFunctionAddress, (ZeDriver, funcName.c_str(), funcAddr)); } + + // zeGraphGetIdExt must be special-cased: querying its address on drivers + // that predate its support leads to memory corruption errors in + // sycl/test-e2e/Adapters/level_zero/ tests, so manually check the driver + // version until the issue is resolved. + if (this->isDriverVersionNewerOrSimilar(1, 15, 38921)) { + ZE_CALL_NOCHECK(zeDriverGetExtensionFunctionAddress, + (ZeDriver, "zeGraphGetIdExt", + reinterpret_cast(&ZeGraphExt.zeGraphGetIdExt))); + } else { + ZeGraphExt.zeGraphGetIdExt = nullptr; + } } if (this->isDriverVersionNewerOrSimilar(1, 14, 36035)) { From d36084c299fb81b311b5856bbcb3bf125c67546d Mon Sep 17 00:00:00 2001 From: Matthew Michel Date: Thu, 25 Jun 2026 17:25:52 -0700 Subject: [PATCH 3/3] Add spec revision for urGraphGetIdExp --- unified-runtime/scripts/core/EXP-GRAPH.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/unified-runtime/scripts/core/EXP-GRAPH.rst b/unified-runtime/scripts/core/EXP-GRAPH.rst index 970664f6bc3e1..0282b27757061 100644 --- a/unified-runtime/scripts/core/EXP-GRAPH.rst +++ b/unified-runtime/scripts/core/EXP-GRAPH.rst @@ -44,6 +44,7 @@ Functions * ${x}GraphExecutableGraphDestroyExp * ${x}GraphIsEmptyExp * ${x}GraphDumpContentsExp + * ${x}GraphGetIdExp * Queue * ${x}QueueBeginGraphCaptureExp * ${x}QueueBeginCaptureIntoGraphExp @@ -76,6 +77,9 @@ Changelog | | register user callbacks invoked on graph | | | destruction. | +-----------+---------------------------------------------+ +| 1.5 | Add ${x}GraphGetIdExp to retrieve a | +| | process-unique identifier for a graph. | ++-----------+---------------------------------------------+ Support --------------------------------------------------------------------------------