diff --git a/level_zero/api/core/ze_core_loader.cpp b/level_zero/api/core/ze_core_loader.cpp index 553ffd5b14..e8cebba9dd 100644 --- a/level_zero/api/core/ze_core_loader.cpp +++ b/level_zero/api/core/ze_core_loader.cpp @@ -247,6 +247,22 @@ zeGetDeviceProcAddrTable( return result; } +ZE_APIEXPORT ze_result_t ZE_APICALL +zeGetDeviceExpProcAddrTable( + ze_api_version_t version, + ze_device_exp_dditable_t *pDdiTable) { + if (nullptr == pDdiTable) + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + if (ZE_MAJOR_VERSION(driver_ddiTable.version) != ZE_MAJOR_VERSION(version) || + ZE_MINOR_VERSION(driver_ddiTable.version) > ZE_MINOR_VERSION(version)) + return ZE_RESULT_ERROR_UNSUPPORTED_VERSION; + + ze_result_t result = ZE_RESULT_SUCCESS; + pDdiTable->pfnGetFabricVertexExp = L0::zeDeviceGetFabricVertexExp; + driver_ddiTable.core_ddiTable.DeviceExp = *pDdiTable; + return result; +} + ZE_APIEXPORT ze_result_t ZE_APICALL zeGetCommandQueueProcAddrTable( ze_api_version_t version, @@ -646,3 +662,22 @@ zeGetFabricVertexExpProcAddrTable( driver_ddiTable.core_ddiTable.FabricVertexExp = *pDdiTable; return result; } + +ZE_APIEXPORT ze_result_t ZE_APICALL +zeGetFabricEdgeExpProcAddrTable( + ze_api_version_t version, + ze_fabric_edge_exp_dditable_t *pDdiTable) { + + if (nullptr == pDdiTable) + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + if (ZE_MAJOR_VERSION(driver_ddiTable.version) != ZE_MAJOR_VERSION(version) || + ZE_MINOR_VERSION(driver_ddiTable.version) > ZE_MINOR_VERSION(version)) + return ZE_RESULT_ERROR_UNSUPPORTED_VERSION; + + ze_result_t result = ZE_RESULT_SUCCESS; + pDdiTable->pfnGetExp = L0::zeFabricEdgeGetExp; + pDdiTable->pfnGetVerticesExp = L0::zeFabricEdgeGetVerticesExp; + pDdiTable->pfnGetPropertiesExp = L0::zeFabricEdgeGetPropertiesExp; + driver_ddiTable.core_ddiTable.FabricEdgeExp = *pDdiTable; + return result; +} \ No newline at end of file diff --git a/level_zero/api/extensions/public/ze_exp_ext.cpp b/level_zero/api/extensions/public/ze_exp_ext.cpp index 4537318c23..78e200b9ff 100644 --- a/level_zero/api/extensions/public/ze_exp_ext.cpp +++ b/level_zero/api/extensions/public/ze_exp_ext.cpp @@ -84,6 +84,27 @@ ze_result_t zeFabricVertexGetDeviceExp( return L0::FabricVertex::fromHandle(hVertex)->getDevice(phDevice); } +ze_result_t zeDeviceGetFabricVertexExp(ze_device_handle_t hDevice, ze_fabric_vertex_handle_t *phVertex) { + + return L0::Device::fromHandle(hDevice)->getFabricVertex(phVertex); +} + +ze_result_t zeFabricEdgeGetExp(ze_fabric_vertex_handle_t hVertexA, ze_fabric_vertex_handle_t hVertexB, + uint32_t *pCount, ze_fabric_edge_handle_t *phEdges) { + + return L0::FabricVertex::fromHandle(hVertexA)->edgeGet(hVertexB, pCount, phEdges); +} + +ze_result_t zeFabricEdgeGetVerticesExp(ze_fabric_edge_handle_t hEdge, ze_fabric_vertex_handle_t *phVertexA, + ze_fabric_vertex_handle_t *phVertexB) { + return L0::FabricEdge::fromHandle(hEdge)->getVertices(phVertexA, phVertexB); +} + +ze_result_t zeFabricEdgeGetPropertiesExp(ze_fabric_edge_handle_t hEdge, + ze_fabric_edge_exp_properties_t *pEdgeProperties) { + return L0::FabricEdge::fromHandle(hEdge)->getProperties(pEdgeProperties); +} + } // namespace L0 extern "C" { @@ -161,4 +182,35 @@ zeFabricVertexGetDeviceExp( return L0::zeFabricVertexGetDeviceExp(hVertex, phDevice); } +ZE_APIEXPORT ze_result_t ZE_APICALL +zeDeviceGetFabricVertexExp( + ze_device_handle_t hDevice, + ze_fabric_vertex_handle_t *phVertex) { + return L0::zeDeviceGetFabricVertexExp(hDevice, phVertex); +} + +ZE_APIEXPORT ze_result_t ZE_APICALL +zeFabricEdgeGetExp( + ze_fabric_vertex_handle_t hVertexA, + ze_fabric_vertex_handle_t hVertexB, + uint32_t *pCount, + ze_fabric_edge_handle_t *phEdges) { + return L0::zeFabricEdgeGetExp(hVertexA, hVertexB, pCount, phEdges); +} + +ZE_APIEXPORT ze_result_t ZE_APICALL +zeFabricEdgeGetVerticesExp( + ze_fabric_edge_handle_t hEdge, + ze_fabric_vertex_handle_t *phVertexA, + ze_fabric_vertex_handle_t *phVertexB) { + return L0::zeFabricEdgeGetVerticesExp(hEdge, phVertexA, phVertexB); +} + +ZE_APIEXPORT ze_result_t ZE_APICALL +zeFabricEdgeGetPropertiesExp( + ze_fabric_edge_handle_t hEdge, + ze_fabric_edge_exp_properties_t *pEdgeProperties) { + return L0::zeFabricEdgeGetPropertiesExp(hEdge, pEdgeProperties); +} + } // extern "C" diff --git a/level_zero/api/extensions/public/ze_exp_ext.h b/level_zero/api/extensions/public/ze_exp_ext.h index 643dafe330..e9cb60a26f 100644 --- a/level_zero/api/extensions/public/ze_exp_ext.h +++ b/level_zero/api/extensions/public/ze_exp_ext.h @@ -67,4 +67,23 @@ ze_result_t zeFabricVertexGetDeviceExp( ze_fabric_vertex_handle_t hVertex, ze_device_handle_t *phDevice); +ze_result_t zeDeviceGetFabricVertexExp( + ze_device_handle_t hDevice, + ze_fabric_vertex_handle_t *phVertex); + +ze_result_t zeFabricEdgeGetExp( + ze_fabric_vertex_handle_t hVertexA, + ze_fabric_vertex_handle_t hVertexB, + uint32_t *pCount, + ze_fabric_edge_handle_t *phEdges); + +ze_result_t zeFabricEdgeGetVerticesExp( + ze_fabric_edge_handle_t hEdge, + ze_fabric_vertex_handle_t *phVertexA, + ze_fabric_vertex_handle_t *phVertexB); + +ze_result_t zeFabricEdgeGetPropertiesExp( + ze_fabric_edge_handle_t hEdge, + ze_fabric_edge_exp_properties_t *pEdgeProperties); + } // namespace L0 diff --git a/level_zero/core/source/device/device.h b/level_zero/core/source/device/device.h index 04ce58d193..094f140a0f 100644 --- a/level_zero/core/source/device/device.h +++ b/level_zero/core/source/device/device.h @@ -135,6 +135,7 @@ struct Device : _ze_device_handle_t { virtual ze_result_t getCsrForLowPriority(NEO::CommandStreamReceiver **csr) = 0; virtual NEO::GraphicsAllocation *obtainReusableAllocation(size_t requiredSize, NEO::AllocationType type) = 0; virtual void storeReusableAllocation(NEO::GraphicsAllocation &alloc) = 0; + virtual ze_result_t getFabricVertex(ze_fabric_vertex_handle_t *phVertex) const = 0; protected: NEO::Device *neoDevice = nullptr; diff --git a/level_zero/core/source/device/device_imp.cpp b/level_zero/core/source/device/device_imp.cpp index 18a112d879..73c74bf9df 100644 --- a/level_zero/core/source/device/device_imp.cpp +++ b/level_zero/core/source/device/device_imp.cpp @@ -1480,4 +1480,13 @@ NEO::EngineGroupType DeviceImp::getEngineGroupTypeForOrdinal(uint32_t ordinal) c return engineGroupType; } +ze_result_t DeviceImp::getFabricVertex(ze_fabric_vertex_handle_t *phVertex) const { + if (fabricVertex == nullptr) { + return ZE_RESULT_EXP_ERROR_DEVICE_IS_NOT_VERTEX; + } + + *phVertex = fabricVertex->toHandle(); + return ZE_RESULT_SUCCESS; +} + } // namespace L0 diff --git a/level_zero/core/source/device/device_imp.h b/level_zero/core/source/device/device_imp.h index 26725c54a8..a0ee5d6e5e 100644 --- a/level_zero/core/source/device/device_imp.h +++ b/level_zero/core/source/device/device_imp.h @@ -116,6 +116,7 @@ struct DeviceImp : public Device { std::vector subDevices; std::unordered_map crossAccessEnabledDevices; DriverHandle *driverHandle = nullptr; + FabricVertex *fabricVertex = nullptr; CommandList *pageFaultCommandList = nullptr; ze_pci_speed_ext_t pciMaxSpeed = {-1, -1, -1}; @@ -136,7 +137,7 @@ struct DeviceImp : public Device { using CmdListCreateFunPtrT = L0::CommandList *(*)(uint32_t, Device *, NEO::EngineGroupType, ze_command_list_flags_t, ze_result_t &); CmdListCreateFunPtrT getCmdListCreateFunc(const ze_command_list_desc_t *desc); - FabricVertex *fabricVertex = nullptr; + ze_result_t getFabricVertex(ze_fabric_vertex_handle_t *phVertex) const override; ze_result_t queryDeviceLuid(ze_device_luid_ext_properties_t *deviceLuidProperties); ze_result_t setDeviceLuid(ze_device_luid_ext_properties_t *deviceLuidProperties); diff --git a/level_zero/core/source/driver/driver_handle_imp.cpp b/level_zero/core/source/driver/driver_handle_imp.cpp index d8d2c86fa8..1f93ded5ff 100644 --- a/level_zero/core/source/driver/driver_handle_imp.cpp +++ b/level_zero/core/source/driver/driver_handle_imp.cpp @@ -165,6 +165,11 @@ DriverHandleImp::~DriverHandleImp() { } this->fabricVertices.clear(); + for (auto &edge : this->fabricEdges) { + delete edge; + } + this->fabricEdges.clear(); + if (this->svmAllocsManager) { delete this->svmAllocsManager; this->svmAllocsManager = nullptr; @@ -242,10 +247,15 @@ ze_result_t DriverHandleImp::initialize(std::vector auto deviceImpl = static_cast(device); auto fabricVertex = FabricVertex::createFromDevice(device); + if (fabricVertex == nullptr) { + continue; + } deviceImpl->setFabricVertex(fabricVertex); this->fabricVertices.push_back(fabricVertex); } + FabricEdge::createEdgesFromVertices(this->fabricVertices, this->fabricEdges); + return ZE_RESULT_SUCCESS; } @@ -650,4 +660,43 @@ ze_result_t DriverHandleImp::fabricVertexGetExp(uint32_t *pCount, ze_fabric_vert return ZE_RESULT_SUCCESS; } +ze_result_t DriverHandleImp::fabricEdgeGetExp(ze_fabric_vertex_handle_t hVertexA, ze_fabric_vertex_handle_t hVertexB, + uint32_t *pCount, ze_fabric_edge_handle_t *phEdges) { + + FabricVertex *queryVertexA = FabricVertex::fromHandle(hVertexA); + FabricVertex *queryVertexB = FabricVertex::fromHandle(hVertexB); + uint32_t maxEdges = 0, edgeUpdateIndex = 0; + bool updateEdges = false; + + if (*pCount == 0) { + maxEdges = static_cast(fabricEdges.size()); + } else { + maxEdges = std::min(*pCount, static_cast(fabricEdges.size())); + } + + if (phEdges != nullptr) { + updateEdges = true; + } + + for (const auto &edge : fabricEdges) { + // Fabric Connections are bi-directional + if ((edge->vertexA == queryVertexA && edge->vertexB == queryVertexB) || + (edge->vertexA == queryVertexB && edge->vertexB == queryVertexA)) { + + if (updateEdges == true) { + phEdges[edgeUpdateIndex] = edge->toHandle(); + } + ++edgeUpdateIndex; + } + + // Stop if the edges overflow the count + if (edgeUpdateIndex >= maxEdges) { + break; + } + } + + *pCount = edgeUpdateIndex; + return ZE_RESULT_SUCCESS; +} + } // namespace L0 diff --git a/level_zero/core/source/driver/driver_handle_imp.h b/level_zero/core/source/driver/driver_handle_imp.h index ec6e7ccca2..269c2f8bd8 100644 --- a/level_zero/core/source/driver/driver_handle_imp.h +++ b/level_zero/core/source/driver/driver_handle_imp.h @@ -19,6 +19,7 @@ namespace L0 { class HostPointerManager; struct FabricVertex; +struct FabricEdge; struct DriverHandleImp : public DriverHandle { ~DriverHandleImp() override; @@ -78,6 +79,8 @@ struct DriverHandleImp : public DriverHandle { NEO::GraphicsAllocation *alloc, NEO::SvmAllocationData *allocData, Device *device); + ze_result_t fabricEdgeGetExp(ze_fabric_vertex_handle_t hVertexA, ze_fabric_vertex_handle_t hVertexB, + uint32_t *pCount, ze_fabric_edge_handle_t *phEdges); std::unique_ptr hostPointerManager; // Experimental functions @@ -88,6 +91,7 @@ struct DriverHandleImp : public DriverHandle { std::vector devices; std::vector fabricVertices; + std::vector fabricEdges; // Spec extensions const std::vector> extensionsSupported = { {ZE_FLOAT_ATOMICS_EXT_NAME, ZE_FLOAT_ATOMICS_EXT_VERSION_CURRENT}, diff --git a/level_zero/core/source/fabric/CMakeLists.txt b/level_zero/core/source/fabric/CMakeLists.txt index 598ee6e512..fe6c0e54df 100644 --- a/level_zero/core/source/fabric/CMakeLists.txt +++ b/level_zero/core/source/fabric/CMakeLists.txt @@ -8,6 +8,7 @@ set(L0_SRCS_FABRIC ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt ${CMAKE_CURRENT_SOURCE_DIR}/fabric.h ${CMAKE_CURRENT_SOURCE_DIR}/fabric_device_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/fabric_device_mdfi.cpp ${CMAKE_CURRENT_SOURCE_DIR}/fabric.cpp ) diff --git a/level_zero/core/source/fabric/fabric.cpp b/level_zero/core/source/fabric/fabric.cpp index 47a6202eb5..8d165eecc0 100644 --- a/level_zero/core/source/fabric/fabric.cpp +++ b/level_zero/core/source/fabric/fabric.cpp @@ -10,6 +10,7 @@ #include "shared/source/helpers/string.h" #include "level_zero/core/source/device/device_imp.h" +#include "level_zero/core/source/driver/driver_handle_imp.h" #include "level_zero/core/source/fabric/fabric_device_interface.h" namespace L0 { @@ -68,10 +69,12 @@ FabricVertex *FabricVertex::createFromDevice(Device *device) { fabricVertex->properties.address.function = pciProperties.address.function; } - fabricVertex->pFabricDeviceInterface = FabricDeviceInterface::createFabricDeviceInterface(*fabricVertex); - UNRECOVERABLE_IF(fabricVertex->pFabricDeviceInterface == nullptr); + fabricVertex->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Iaf] = FabricDeviceInterface::createFabricDeviceInterfaceIaf(fabricVertex); + fabricVertex->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Mdfi] = FabricDeviceInterface::createFabricDeviceInterfaceMdfi(fabricVertex); - fabricVertex->pFabricDeviceInterface->enumerate(); + for (auto const &fabricDeviceInterface : fabricVertex->pFabricDeviceInterfaces) { + fabricDeviceInterface.second->enumerate(); + } return fabricVertex; } @@ -103,4 +106,46 @@ ze_result_t FabricVertex::getDevice(ze_device_handle_t *phDevice) const { return ZE_RESULT_SUCCESS; } +ze_result_t FabricVertex::edgeGet(ze_fabric_vertex_handle_t hVertexB, + uint32_t *pCount, ze_fabric_edge_handle_t *phEdges) { + DriverHandleImp *driverHandleImp = static_cast(device->getDriverHandle()); + return driverHandleImp->fabricEdgeGetExp(this->toHandle(), hVertexB, pCount, phEdges); +} + +FabricEdge *FabricEdge::create(FabricVertex *vertexA, FabricVertex *vertexB, ze_fabric_edge_exp_properties_t &properties) { + + FabricEdge *edge = new FabricEdge(); + edge->vertexA = vertexA; + edge->vertexB = vertexB; + edge->properties = properties; + return edge; +} + +void FabricEdge::createEdgesFromVertices(const std::vector &vertices, std::vector &edges) { + + // Get all vertices and sub-vertices + std::vector allVertices = {}; + for (auto &fabricVertex : vertices) { + allVertices.push_back(fabricVertex); + for (auto &fabricSubVertex : fabricVertex->subVertices) { + allVertices.push_back(fabricSubVertex); + } + } + + // Get edges between all vertices + for (uint32_t vertexAIndex = 0; vertexAIndex < allVertices.size(); vertexAIndex++) { + for (uint32_t vertexBIndex = vertexAIndex + 1; vertexBIndex < allVertices.size(); vertexBIndex++) { + ze_fabric_edge_exp_properties_t edgeProperty = {}; + + for (auto const &fabricDeviceInterface : allVertices[vertexAIndex]->pFabricDeviceInterfaces) { + bool isConnected = + fabricDeviceInterface.second->getEdgeProperty(allVertices[vertexBIndex], edgeProperty); + if (isConnected) { + edges.push_back(create(allVertices[vertexAIndex], allVertices[vertexBIndex], edgeProperty)); + } + } + } + } +} + } // namespace L0 diff --git a/level_zero/core/source/fabric/fabric.h b/level_zero/core/source/fabric/fabric.h index 6931500d04..4f910169f2 100644 --- a/level_zero/core/source/fabric/fabric.h +++ b/level_zero/core/source/fabric/fabric.h @@ -7,16 +7,19 @@ #pragma once +#include "level_zero/core/source/fabric/fabric_device_interface.h" #include +#include #include #include struct _ze_fabric_vertex_handle_t {}; +struct _ze_fabric_edge_handle_t {}; namespace L0 { struct Device; -class FabricDeviceInterface; +struct DriverHandle; struct FabricVertex : _ze_fabric_vertex_handle_t { @@ -28,14 +31,40 @@ struct FabricVertex : _ze_fabric_vertex_handle_t { ze_result_t getDevice(ze_device_handle_t *phDevice) const; static FabricVertex *fromHandle(ze_fabric_vertex_handle_t handle) { return static_cast(handle); } inline ze_fabric_vertex_handle_t toHandle() { return this; } - - std::unique_ptr pFabricDeviceInterface; + ze_result_t edgeGet(ze_fabric_vertex_handle_t hVertexB, + uint32_t *pCount, ze_fabric_edge_handle_t *phEdges); + std::map> pFabricDeviceInterfaces; + std::vector subVertices = {}; + struct Device *device = nullptr; private: - struct Device *device = nullptr; ze_fabric_vertex_exp_properties_t properties = {}; +}; - std::vector subVertices = {}; +struct FabricEdge : _ze_fabric_edge_handle_t { + + public: + virtual ~FabricEdge() = default; + + static void createEdgesFromVertices(const std::vector &vertices, std::vector &edges); + static FabricEdge *create(FabricVertex *vertexA, FabricVertex *vertexB, ze_fabric_edge_exp_properties_t &properties); + ze_result_t getProperties(ze_fabric_edge_exp_properties_t *pEdgeProperties) const { + *pEdgeProperties = properties; + return ZE_RESULT_SUCCESS; + } + ze_result_t getVertices(ze_fabric_vertex_handle_t *phVertexA, + ze_fabric_vertex_handle_t *phVertexB) { + *phVertexA = vertexA->toHandle(); + *phVertexB = vertexB->toHandle(); + return ZE_RESULT_SUCCESS; + } + + static FabricEdge *fromHandle(ze_fabric_edge_handle_t handle) { return static_cast(handle); } + inline ze_fabric_edge_handle_t toHandle() { return this; } + + ze_fabric_edge_exp_properties_t properties = {}; + FabricVertex *vertexA = nullptr; + FabricVertex *vertexB = nullptr; }; } // namespace L0 diff --git a/level_zero/core/source/fabric/fabric_device_interface.h b/level_zero/core/source/fabric/fabric_device_interface.h index fa0a36a9b6..bda450bf6f 100644 --- a/level_zero/core/source/fabric/fabric_device_interface.h +++ b/level_zero/core/source/fabric/fabric_device_interface.h @@ -7,19 +7,41 @@ #pragma once -#include "level_zero/core/source/fabric/fabric.h" #include #include namespace L0 { +struct Device; +struct FabricVertex; + class FabricDeviceInterface { public: + enum class Type { + Undefined, + Iaf, + Mdfi + }; virtual ~FabricDeviceInterface(){}; virtual ze_result_t enumerate() = 0; - static std::unique_ptr createFabricDeviceInterface(const FabricVertex &fabricVertex); + static std::unique_ptr createFabricDeviceInterfaceIaf(const FabricVertex *fabricVertex); + static std::unique_ptr createFabricDeviceInterfaceMdfi(const FabricVertex *fabricVertex); + virtual bool getEdgeProperty(FabricVertex *neighborVertex, ze_fabric_edge_exp_properties_t &edgeProperty) = 0; +}; + +class FabricDeviceMdfi : public FabricDeviceInterface { + public: + FabricDeviceMdfi(Device *device) : device(device) {} + ~FabricDeviceMdfi() override = default; + ze_result_t enumerate() override { + return ZE_RESULT_SUCCESS; + } + bool getEdgeProperty(FabricVertex *neighborVertex, ze_fabric_edge_exp_properties_t &edgeProperty) override; + + protected: + Device *device = nullptr; }; } // namespace L0 diff --git a/level_zero/core/source/fabric/fabric_device_mdfi.cpp b/level_zero/core/source/fabric/fabric_device_mdfi.cpp new file mode 100644 index 0000000000..d390c652e8 --- /dev/null +++ b/level_zero/core/source/fabric/fabric_device_mdfi.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/core/source/device/device.h" +#include "level_zero/core/source/device/device_imp.h" +#include "level_zero/core/source/fabric/fabric.h" +#include "level_zero/core/source/fabric/fabric_device_interface.h" + +namespace L0 { + +bool FabricDeviceMdfi::getEdgeProperty(FabricVertex *neighborVertex, ze_fabric_edge_exp_properties_t &edgeProperty) { + + DeviceImp *currentDeviceImp = static_cast(device); + DeviceImp *neighborDeviceImp = static_cast(neighborVertex->device); + + // Ignore root devices + if (!currentDeviceImp->isSubdevice || !neighborDeviceImp->isSubdevice) { + return false; + } + + const uint32_t currRootDeviceIndex = device->getRootDeviceIndex(); + const uint32_t neighborRootDeviceIndex = neighborVertex->device->getRootDeviceIndex(); + const uint32_t currSubDeviceId = static_cast(device)->getPhysicalSubDeviceId(); + const uint32_t neighborSubDeviceId = static_cast(neighborVertex->device)->getPhysicalSubDeviceId(); + + if (currRootDeviceIndex == neighborRootDeviceIndex && + currSubDeviceId < neighborSubDeviceId) { + + ze_uuid_t &uuid = edgeProperty.uuid; + + std::memset(uuid.id, 0, ZE_MAX_UUID_SIZE); + // Copy current Root DeviceIndex and SubDeviceId + memcpy_s(&uuid.id[0], 4, &currRootDeviceIndex, 4); + memcpy_s(&uuid.id[4], 1, &currSubDeviceId, 1); + // Copy neighboring Root DeviceIndex and SubDeviceId + memcpy_s(&uuid.id[8], 4, &neighborRootDeviceIndex, 4); + memcpy_s(&uuid.id[12], 1, &neighborSubDeviceId, 1); + + memcpy_s(edgeProperty.model, ZE_MAX_FABRIC_EDGE_MODEL_EXP_SIZE, "MDFI", 5); + edgeProperty.bandwidth = 0; + edgeProperty.bandwidthUnit = ZE_BANDWIDTH_UNIT_UNKNOWN; + edgeProperty.latency = 0; + edgeProperty.latencyUnit = ZE_LATENCY_UNIT_UNKNOWN; + edgeProperty.duplexity = ZE_FABRIC_EDGE_EXP_DUPLEXITY_FULL_DUPLEX; + return true; + } + return false; +} + +std::unique_ptr FabricDeviceInterface::createFabricDeviceInterfaceMdfi(const FabricVertex *fabricVertex) { + + return std::unique_ptr(new (std::nothrow) FabricDeviceMdfi(fabricVertex->device)); +} + +} // namespace L0 diff --git a/level_zero/core/source/fabric/linux/fabric_device_iaf.cpp b/level_zero/core/source/fabric/linux/fabric_device_iaf.cpp index a13c151640..34678d25bf 100644 --- a/level_zero/core/source/fabric/linux/fabric_device_iaf.cpp +++ b/level_zero/core/source/fabric/linux/fabric_device_iaf.cpp @@ -45,6 +45,51 @@ ze_result_t FabricDeviceIaf::enumerate() { return result; } +bool FabricDeviceIaf::getEdgeProperty(FabricVertex *neighborVertex, ze_fabric_edge_exp_properties_t &edgeProperty) { + + bool isConnected = false; + + std::vector subDeviceEdgeProperties = {}; + for (auto &subDeviceIaf : subDeviceIafs) { + + ze_fabric_edge_exp_properties_t subDeviceEdgeProperty = {}; + bool isSubdeviceConnected = subDeviceIaf->getEdgeProperty(neighborVertex, subDeviceEdgeProperty); + if (isSubdeviceConnected) { + subDeviceEdgeProperties.push_back(subDeviceEdgeProperty); + } + } + + if (subDeviceEdgeProperties.size() > 0) { + + ze_uuid_t &uuid = edgeProperty.uuid; + std::memset(uuid.id, 0, ZE_MAX_UUID_SIZE); + + // Copy current device fabric and attach id + memcpy_s(&uuid.id[0], 4, &subDeviceEdgeProperties[0].uuid.id[0], 4); + // Use 255 (impossible tile (attach) id to identify root device) + uuid.id[4] = 255; + // Copy neighboring device fabric id + memcpy_s(&uuid.id[8], 4, &subDeviceEdgeProperties[0].uuid.id[8], 4); + memcpy_s(&uuid.id[12], 1, &subDeviceEdgeProperties[0].uuid.id[12], 1); + + uint32_t accumulatedBandwidth = 0; + for (const auto &subEdgeProperty : subDeviceEdgeProperties) { + accumulatedBandwidth += subEdgeProperty.bandwidth; + } + + memcpy_s(edgeProperty.model, ZE_MAX_FABRIC_EDGE_MODEL_EXP_SIZE, "XeLink", 7); + edgeProperty.bandwidth = accumulatedBandwidth; + edgeProperty.bandwidthUnit = ZE_BANDWIDTH_UNIT_BYTES_PER_NANOSEC; + edgeProperty.latency = 0; + edgeProperty.latencyUnit = ZE_LATENCY_UNIT_UNKNOWN; + edgeProperty.duplexity = ZE_FABRIC_EDGE_EXP_DUPLEXITY_FULL_DUPLEX; + + isConnected = true; + } + + return isConnected; +} + FabricSubDeviceIaf::FabricSubDeviceIaf(Device *device) : device(device) { pIafNlApi = std::make_unique(); UNRECOVERABLE_IF(nullptr == pIafNlApi); @@ -146,26 +191,111 @@ ze_result_t FabricSubDeviceIaf::getConnection(IafPort &port, FabricPortConnectio return ZE_RESULT_SUCCESS; } +bool FabricSubDeviceIaf::getEdgeProperty(FabricSubDeviceIaf *pNeighbourInterface, + ze_fabric_edge_exp_properties_t &edgeProperty) { + bool isConnected = false; + uint32_t accumulatedBandwidth = 0; + for (auto &connection : connections) { + if (connection.neighbourGuid == pNeighbourInterface->guid) { + accumulatedBandwidth += connection.bandwidthInBytesPerNanoSecond; + } + } + + if (accumulatedBandwidth != 0) { + ze_uuid_t &uuid = edgeProperty.uuid; + DEBUG_BREAK_IF(pNeighbourInterface->connections.size() == 0); + + std::memset(uuid.id, 0, ZE_MAX_UUID_SIZE); + memcpy_s(&uuid.id[0], 4, &connections[0].currentid.fabricId, 4); + memcpy_s(&uuid.id[4], 1, &connections[0].currentid.attachId, 1); + + // Considering the neighboring port is attached on a subdevice, fabricId and attachId could be used from + // any of the connection + memcpy_s(&uuid.id[8], 4, &pNeighbourInterface->connections[0].currentid.fabricId, 4); + memcpy_s(&uuid.id[12], 1, &pNeighbourInterface->connections[0].currentid.attachId, 1); + + memcpy_s(edgeProperty.model, ZE_MAX_FABRIC_EDGE_MODEL_EXP_SIZE, "XeLink", 7); + edgeProperty.bandwidth = accumulatedBandwidth; + edgeProperty.bandwidthUnit = ZE_BANDWIDTH_UNIT_BYTES_PER_NANOSEC; + edgeProperty.latency = 0; + edgeProperty.latencyUnit = ZE_LATENCY_UNIT_UNKNOWN; + edgeProperty.duplexity = ZE_FABRIC_EDGE_EXP_DUPLEXITY_FULL_DUPLEX; + isConnected = true; + } + + return isConnected; +} + +bool FabricSubDeviceIaf::getEdgeProperty(FabricVertex *neighborVertex, + ze_fabric_edge_exp_properties_t &edgeProperty) { + + ze_uuid_t &uuid = edgeProperty.uuid; + bool isConnected = false; + uint32_t accumulatedBandwidth = 0; + DeviceImp *neighborDeviceImp = static_cast(neighborVertex->device); + + // If the neighbor is a root device + if (neighborDeviceImp->isSubdevice == false) { + + std::vector subEdgeProperties = {}; + + FabricDeviceIaf *deviceIaf = static_cast(neighborVertex->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Iaf].get()); + // Get the edges to the neighbors subVertices + for (auto &subDeviceIaf : deviceIaf->subDeviceIafs) { + ze_fabric_edge_exp_properties_t edgeProperty = {}; + bool subDevicesConnected = getEdgeProperty(subDeviceIaf.get(), edgeProperty); + if (subDevicesConnected) { + subEdgeProperties.push_back(edgeProperty); + } + } + + // Add an edge for this subVertex to the neighbor root + if (subEdgeProperties.size() > 0) { + + std::memset(uuid.id, 0, ZE_MAX_UUID_SIZE); + // Copy current device fabric and attach id + memcpy_s(&uuid.id[0], 4, &subEdgeProperties[0].uuid.id[0], 4); + memcpy_s(&uuid.id[4], 1, &subEdgeProperties[0].uuid.id[4], 1); + // Copy neighboring device fabric id + memcpy_s(&uuid.id[8], 4, &subEdgeProperties[0].uuid.id[8], 4); + // Use 255 (impossible tile (attach) id to identify root device) + uuid.id[12] = 255; + + for (const auto &subEdgeProperty : subEdgeProperties) { + accumulatedBandwidth += subEdgeProperty.bandwidth; + } + + memcpy_s(edgeProperty.model, ZE_MAX_FABRIC_EDGE_MODEL_EXP_SIZE, "XeLink", 7); + edgeProperty.bandwidth = accumulatedBandwidth; + edgeProperty.bandwidthUnit = ZE_BANDWIDTH_UNIT_BYTES_PER_NANOSEC; + edgeProperty.latency = 0; + edgeProperty.latencyUnit = ZE_LATENCY_UNIT_UNKNOWN; + edgeProperty.duplexity = ZE_FABRIC_EDGE_EXP_DUPLEXITY_FULL_DUPLEX; + + isConnected = true; + } + } else { + FabricSubDeviceIaf *pNeighbourInterface = + static_cast(neighborVertex->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Iaf].get()); + isConnected = getEdgeProperty(pNeighbourInterface, edgeProperty); + } + + return isConnected; +} + void FabricSubDeviceIaf::setIafNlApi(IafNlApi *iafNlApi) { pIafNlApi.reset(iafNlApi); } -std::unique_ptr FabricDeviceInterface::createFabricDeviceInterface(const FabricVertex &fabricVertex) { +std::unique_ptr FabricDeviceInterface::createFabricDeviceInterfaceIaf(const FabricVertex *fabricVertex) { - ze_fabric_vertex_exp_properties_t vertexProperties = {}; - fabricVertex.getProperties(&vertexProperties); + DeviceImp *deviceImp = static_cast(fabricVertex->device); - ze_device_handle_t hDevice = nullptr; - fabricVertex.getDevice(&hDevice); - DEBUG_BREAK_IF(hDevice == nullptr); - - DeviceImp *deviceImp = static_cast(hDevice); - Device *device = static_cast(hDevice); if (deviceImp->isSubdevice) { - return std::unique_ptr(new (std::nothrow) FabricSubDeviceIaf(device)); + return std::unique_ptr(new (std::nothrow) FabricSubDeviceIaf(fabricVertex->device)); } - return std::unique_ptr(new (std::nothrow) FabricDeviceIaf(device)); + return std::unique_ptr(new (std::nothrow) FabricDeviceIaf(fabricVertex->device)); } } // namespace L0 diff --git a/level_zero/core/source/fabric/linux/fabric_device_iaf.h b/level_zero/core/source/fabric/linux/fabric_device_iaf.h index 1ed5a5ad64..5c4e868436 100644 --- a/level_zero/core/source/fabric/linux/fabric_device_iaf.h +++ b/level_zero/core/source/fabric/linux/fabric_device_iaf.h @@ -31,6 +31,7 @@ class FabricDeviceIaf : public FabricDeviceInterface { FabricDeviceIaf(Device *device); ~FabricDeviceIaf() override = default; ze_result_t enumerate() override; + bool getEdgeProperty(FabricVertex *neighborVertex, ze_fabric_edge_exp_properties_t &edgeProperty) override; std::vector> subDeviceIafs = {}; protected: @@ -44,14 +45,16 @@ class FabricSubDeviceIaf : public FabricDeviceInterface { ~FabricSubDeviceIaf() override = default; ze_result_t enumerate() override; void setIafNlApi(IafNlApi *iafNlApi); + bool getEdgeProperty(FabricVertex *neighborVertex, ze_fabric_edge_exp_properties_t &edgeProperty) override; std::vector connections = {}; + uint64_t guid = 0ull; protected: + bool getEdgeProperty(FabricSubDeviceIaf *pNeighbourInterface, + ze_fabric_edge_exp_properties_t &edgeProperty); ze_result_t getConnection(IafPort &port, FabricPortConnection &connection); - std::unique_ptr pIafNlApi = nullptr; Device *device = nullptr; - uint64_t guid = 0ull; }; -} // namespace L0 \ No newline at end of file +} // namespace L0 diff --git a/level_zero/core/source/fabric/linux/fabric_device_iaf_stub.cpp b/level_zero/core/source/fabric/linux/fabric_device_iaf_stub.cpp index d47ff04d24..02599d3a70 100644 --- a/level_zero/core/source/fabric/linux/fabric_device_iaf_stub.cpp +++ b/level_zero/core/source/fabric/linux/fabric_device_iaf_stub.cpp @@ -11,7 +11,7 @@ namespace L0 { -std::unique_ptr FabricDeviceInterface::createFabricDeviceInterface(const FabricVertex &fabricVertex) { +std::unique_ptr FabricDeviceInterface::createFabricDeviceInterfaceIaf(const FabricVertex *fabricVertex) { return std::unique_ptr(new (std::nothrow) FabricDeviceIafStub()); } diff --git a/level_zero/core/source/fabric/linux/fabric_device_iaf_stub.h b/level_zero/core/source/fabric/linux/fabric_device_iaf_stub.h index 54f7e52b95..8c858a1471 100644 --- a/level_zero/core/source/fabric/linux/fabric_device_iaf_stub.h +++ b/level_zero/core/source/fabric/linux/fabric_device_iaf_stub.h @@ -20,6 +20,9 @@ class FabricDeviceIafStub : public FabricDeviceInterface { ze_result_t enumerate() override { return ZE_RESULT_SUCCESS; } + bool getEdgeProperty(FabricVertex *neighborVertex, ze_fabric_edge_exp_properties_t &edgeProperty) override { + return false; + } }; } // namespace L0 \ No newline at end of file diff --git a/level_zero/core/source/fabric/windows/fabric_device_iaf.cpp b/level_zero/core/source/fabric/windows/fabric_device_iaf.cpp index 95faeb24d5..507dc8d614 100644 --- a/level_zero/core/source/fabric/windows/fabric_device_iaf.cpp +++ b/level_zero/core/source/fabric/windows/fabric_device_iaf.cpp @@ -11,7 +11,7 @@ namespace L0 { -std::unique_ptr FabricDeviceInterface::createFabricDeviceInterface(const FabricVertex &fabricVertex) { +std::unique_ptr FabricDeviceInterface::createFabricDeviceInterfaceIaf(const FabricVertex *fabricVertex) { return std::unique_ptr(new (std::nothrow) FabricDeviceIaf()); } diff --git a/level_zero/core/source/fabric/windows/fabric_device_iaf.h b/level_zero/core/source/fabric/windows/fabric_device_iaf.h index 9c937c8ced..39c5ff7ae3 100644 --- a/level_zero/core/source/fabric/windows/fabric_device_iaf.h +++ b/level_zero/core/source/fabric/windows/fabric_device_iaf.h @@ -20,6 +20,9 @@ class FabricDeviceIaf : public FabricDeviceInterface { ze_result_t enumerate() override { return ZE_RESULT_SUCCESS; } + bool getEdgeProperty(FabricVertex *neighborVertex, ze_fabric_edge_exp_properties_t &edgeProperty) { + return false; + } }; } // namespace L0 \ No newline at end of file diff --git a/level_zero/core/test/black_box_tests/CMakeLists.txt b/level_zero/core/test/black_box_tests/CMakeLists.txt index f7800bd519..0988e637f7 100644 --- a/level_zero/core/test/black_box_tests/CMakeLists.txt +++ b/level_zero/core/test/black_box_tests/CMakeLists.txt @@ -54,6 +54,7 @@ set(TEST_TARGETS zello_world_gpu zello_world_jitc_ocloc zello_world_usm + zello_fabric ) include_directories(common) diff --git a/level_zero/core/test/black_box_tests/zello_fabric.cpp b/level_zero/core/test/black_box_tests/zello_fabric.cpp new file mode 100644 index 0000000000..57ab626cc1 --- /dev/null +++ b/level_zero/core/test/black_box_tests/zello_fabric.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "zello_common.h" + +#include + +bool showFabricConnectivityMatrix(ze_driver_handle_t &hDriver, bool isIncludeSubDevicesEnabled) { + + std::cout << " \n -- Displaying Fabric Connectivity matrix -- \n"; + + bool isIncludeDevices = true; + + uint32_t vertexCount = 0; + std::vector> allVertices; + SUCCESS_OR_TERMINATE(zeFabricVertexGetExp(hDriver, &vertexCount, nullptr)); + std::vector vertices(vertexCount); + SUCCESS_OR_TERMINATE(zeFabricVertexGetExp(hDriver, &vertexCount, vertices.data())); + + for (auto &vertex : vertices) { + if (isIncludeDevices) { + allVertices.push_back(std::make_pair(vertex, 'R')); + } + if (isIncludeSubDevicesEnabled) { + uint32_t count = 0; + SUCCESS_OR_TERMINATE(zeFabricVertexGetSubVerticesExp(vertex, &count, nullptr)); + std::vector subVertices(count); + SUCCESS_OR_TERMINATE(zeFabricVertexGetSubVerticesExp(vertex, &count, subVertices.data())); + for (auto &subVertex : subVertices) { + allVertices.push_back(std::make_pair(subVertex, 'S')); + } + } + } + + if (allVertices.size() == 0) { + std::cout << " -- No Fabric Vertices !! -- \n"; + return false; + } + + const uint32_t elementWidth = 15; + // Print Header + for (uint32_t i = 0; i < allVertices.size(); i++) { + std::cout << std::setw(elementWidth) << "[" << allVertices[i].second << "]" << allVertices[i].first; + } + std::cout << "\n"; + + for (uint32_t vertexAIndex = 0; vertexAIndex < allVertices.size(); vertexAIndex++) { + std::cout << "[" << allVertices[vertexAIndex].second << "]" << allVertices[vertexAIndex].first; + for (uint32_t vertexBIndex = 0; vertexBIndex < allVertices.size(); vertexBIndex++) { + + if (vertexAIndex == vertexBIndex) { + std::cout << std::setw(elementWidth) << "X"; + continue; + } + uint32_t edgeCount = 0; + SUCCESS_OR_TERMINATE(zeFabricEdgeGetExp(allVertices[vertexAIndex].first, allVertices[vertexBIndex].first, &edgeCount, nullptr)); + std::cout << std::setw(elementWidth) << edgeCount; + } + std::cout << "\n"; + } + + return true; +} + +bool showFabricConnectivityProperties(ze_driver_handle_t &hDriver) { + + std::cout << " \n -- Displaying Fabric Connectivity Properties -- \n"; + + uint32_t vertexCount = 0; + std::vector> allVertices; + SUCCESS_OR_TERMINATE(zeFabricVertexGetExp(hDriver, &vertexCount, nullptr)); + std::vector vertices(vertexCount); + SUCCESS_OR_TERMINATE(zeFabricVertexGetExp(hDriver, &vertexCount, vertices.data())); + + for (auto &vertex : vertices) { + allVertices.push_back(std::make_pair(vertex, 'R')); + uint32_t count = 0; + SUCCESS_OR_TERMINATE(zeFabricVertexGetSubVerticesExp(vertex, &count, nullptr)); + std::vector subVertices(count); + SUCCESS_OR_TERMINATE(zeFabricVertexGetSubVerticesExp(vertex, &count, subVertices.data())); + for (auto &subVertex : subVertices) { + allVertices.push_back(std::make_pair(subVertex, 'S')); + } + } + + if (allVertices.size() == 0) { + std::cout << " -- No Fabric Vertices !! -- \n"; + return false; + } + + // Print the Sub Vertices and Vertices + for (uint32_t i = 0; i < allVertices.size(); i++) { + if (allVertices[i].second == 'S') { + std::cout << "\t" << allVertices[i].first << "\n"; + } else { + std::cout << allVertices[i].first << "\n"; + } + } + + // Show properties of all edges + for (uint32_t vertexAIndex = 0; vertexAIndex < allVertices.size(); vertexAIndex++) { + for (uint32_t vertexBIndex = vertexAIndex + 1; vertexBIndex < allVertices.size(); vertexBIndex++) { + uint32_t edgeCount = 0; + SUCCESS_OR_TERMINATE(zeFabricEdgeGetExp(allVertices[vertexAIndex].first, allVertices[vertexBIndex].first, &edgeCount, nullptr)); + std::vector edges(edgeCount); + SUCCESS_OR_TERMINATE(zeFabricEdgeGetExp(allVertices[vertexAIndex].first, allVertices[vertexBIndex].first, &edgeCount, edges.data())); + + if (edgeCount == 0) { + continue; + } + + std::cout << "Edge A: " << allVertices[vertexAIndex].first << " -- B: " << allVertices[vertexBIndex].first << "\n"; + for (auto &edge : edges) { + ze_fabric_edge_exp_properties_t edgeProperties = {}; + SUCCESS_OR_TERMINATE(zeFabricEdgeGetPropertiesExp(edge, &edgeProperties)); + std::cout << "Uuid: "; + for (uint32_t i = 0; i < ZE_MAX_UUID_SIZE; i++) { + std::cout << static_cast(edgeProperties.uuid.id[i]) << " "; + } + std::cout << "\n"; + std::cout << "Model : " << edgeProperties.model << "\n"; + std::cout << "Bandwidth : " << edgeProperties.bandwidth << " | units: " << static_cast(edgeProperties.bandwidthUnit) << "\n"; + std::cout << "Latency : " << edgeProperties.latency << " | units: " << static_cast(edgeProperties.latencyUnit) << "\n"; + std::cout << "Duplexity : " << static_cast(edgeProperties.duplexity) << "\n"; + std::cout << "\n"; + } + } + std::cout << " --- \n"; + } + + return true; +} + +int main(int argc, char *argv[]) { + + const std::string blackBoxName = "Zello Fabric"; + ze_context_handle_t context = nullptr; + ze_driver_handle_t driverHandle = nullptr; + auto devices = zelloInitContextAndGetDevices(context, driverHandle); + + const bool isSubDeviceDisplayEnabled = isParamEnabled(argc, argv, "-s", "--subDeviceEnable"); + bool status = true; + + status &= showFabricConnectivityMatrix(driverHandle, isSubDeviceDisplayEnabled); + status &= showFabricConnectivityProperties(driverHandle); + + printResult(false, status, blackBoxName); + return (status ? 0 : 1); +} diff --git a/level_zero/core/test/unit_tests/mocks/mock_device.h b/level_zero/core/test/unit_tests/mocks/mock_device.h index 21b6d472aa..36dda7c1c6 100644 --- a/level_zero/core/test/unit_tests/mocks/mock_device.h +++ b/level_zero/core/test/unit_tests/mocks/mock_device.h @@ -82,6 +82,7 @@ struct Mock : public Device { ADDMETHOD_NOBASE_VOIDRETURN(removeDebugSession, ()); ADDMETHOD_NOBASE(obtainReusableAllocation, NEO::GraphicsAllocation *, nullptr, (size_t requiredSize, NEO::AllocationType type)) ADDMETHOD_NOBASE_VOIDRETURN(storeReusableAllocation, (NEO::GraphicsAllocation & alloc)); + ADDMETHOD_CONST_NOBASE(getFabricVertex, ze_result_t, ZE_RESULT_SUCCESS, (ze_fabric_vertex_handle_t * phVertex)); DebugSession *createDebugSession(const zet_debug_config_t &config, ze_result_t &result, bool isRootAttach) override { result = ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; diff --git a/level_zero/core/test/unit_tests/sources/fabric/linux/test_fabric_iaf.cpp b/level_zero/core/test/unit_tests/sources/fabric/linux/test_fabric_iaf.cpp index 52323d5d6e..ce2c9732bb 100644 --- a/level_zero/core/test/unit_tests/sources/fabric/linux/test_fabric_iaf.cpp +++ b/level_zero/core/test/unit_tests/sources/fabric/linux/test_fabric_iaf.cpp @@ -5,9 +5,13 @@ * */ +#include "shared/source/os_interface/device_factory.h" #include "shared/test/common/helpers/debug_manager_state_restore.h" #include "shared/test/common/libult/linux/drm_mock.h" +#include "shared/test/common/mocks/ult_device_factory.h" +#include "shared/test/common/test_macros/test.h" +#include "level_zero/core/source/fabric/fabric.h" #include "level_zero/core/source/fabric/linux/fabric_device_iaf.h" #include "level_zero/core/test/unit_tests/fixtures/device_fixture.h" @@ -227,5 +231,269 @@ TEST_F(TestFabricIaf, GivenIafFabricAvailableWhenGetPortsReturnsErrorThenReturnE delete subDeviceFabric; } +using FabricIafEdgeFixture = Test; +TEST_F(FabricIafEdgeFixture, GivenMultipleDevicesAndSubDevicesWhenCreatingEdgesThenEdgesCreatedAreCorrect) { + + // IAF port connection configuration + // Device | SubDevice | Port -- Connected to -- Device | SubDevice | Port + // 0 0 1 1 0 2 + // 0 0 5 1 0 4 + // 0 1 1 1 1 8 + // 0 1 2 1 1 7 + // + // Guids: + // Device 0, subdevice 0 = 0xA + // Device 0, subdevice 1 = 0xAB + // Device 1, subdevice 0 = 0xABC + // Device 1, subdevice 1 = 0xABCD + + std::vector connection00To10; + { + FabricPortConnection connection; + connection.currentid = IafPortId(0, 0, 1); + connection.neighbourPortNumber = 2; + connection.neighbourGuid = 0xABC; + connection.bandwidthInBytesPerNanoSecond = 1; + connection.isDuplex = true; + connection00To10.push_back(connection); + } + + { + FabricPortConnection connection; + connection.currentid = IafPortId(0, 0, 5); + connection.neighbourPortNumber = 4; + connection.neighbourGuid = 0xABC; + connection.bandwidthInBytesPerNanoSecond = 1; + connection.isDuplex = true; + connection00To10.push_back(connection); + } + + std::vector connection01To11; + { + FabricPortConnection connection; + connection.currentid = IafPortId(0, 1, 1); + connection.neighbourPortNumber = 8; + connection.neighbourGuid = 0xABCD; + connection.bandwidthInBytesPerNanoSecond = 1; + connection.isDuplex = true; + connection01To11.push_back(connection); + } + + { + FabricPortConnection connection; + connection.currentid = IafPortId(0, 1, 2); + connection.neighbourPortNumber = 7; + connection.neighbourGuid = 0xABCD; + connection.bandwidthInBytesPerNanoSecond = 1; + connection.isDuplex = true; + connection01To11.push_back(connection); + } + + std::vector connection10To00; + { + FabricPortConnection connection; + connection.currentid = IafPortId(1, 0, 2); + connection.neighbourPortNumber = 1; + connection.neighbourGuid = 0xA; + connection.bandwidthInBytesPerNanoSecond = 1; + connection.isDuplex = true; + connection10To00.push_back(connection); + } + { + FabricPortConnection connection; + connection.currentid = IafPortId(1, 0, 4); + connection.neighbourPortNumber = 5; + connection.neighbourGuid = 0xA; + connection.bandwidthInBytesPerNanoSecond = 1; + connection.isDuplex = true; + connection10To00.push_back(connection); + } + + std::vector connection11To01; + { + FabricPortConnection connection; + connection.currentid = IafPortId(1, 1, 8); + connection.neighbourPortNumber = 1; + connection.neighbourGuid = 0xAB; + connection.bandwidthInBytesPerNanoSecond = 1; + connection.isDuplex = true; + connection11To01.push_back(connection); + } + { + FabricPortConnection connection; + connection.currentid = IafPortId(1, 1, 7); + connection.neighbourPortNumber = 2; + connection.neighbourGuid = 0xAB; + connection.bandwidthInBytesPerNanoSecond = 1; + connection.isDuplex = true; + connection11To01.push_back(connection); + } + + auto &fabricVertex0 = driverHandle->fabricVertices[0]; + { + auto fabricDeviceIaf = static_cast(fabricVertex0->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Iaf].get()); + auto &fabricSubDeviceIaf0 = fabricDeviceIaf->subDeviceIafs[0]; + fabricSubDeviceIaf0->connections.clear(); + fabricSubDeviceIaf0->connections = connection00To10; + fabricSubDeviceIaf0->guid = 0xA; + + auto &fabricSubDeviceIaf1 = fabricDeviceIaf->subDeviceIafs[1]; + fabricSubDeviceIaf1->connections.clear(); + fabricSubDeviceIaf1->connections = connection01To11; + fabricSubDeviceIaf1->guid = 0xAB; + + //SubVertices + auto &fabricVertex00 = fabricVertex0->subVertices[0]; + auto fabricSubDeviceIaf00 = static_cast(fabricVertex00->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Iaf].get()); + fabricSubDeviceIaf00->connections.clear(); + fabricSubDeviceIaf00->connections = connection00To10; + fabricSubDeviceIaf00->guid = 0xA; + + auto &fabricVertex01 = fabricVertex0->subVertices[1]; + auto fabricSubDeviceIaf01 = static_cast(fabricVertex01->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Iaf].get()); + fabricSubDeviceIaf01->connections.clear(); + fabricSubDeviceIaf01->connections = connection01To11; + fabricSubDeviceIaf01->guid = 0xAB; + } + + auto fabricVertex1 = static_cast(driverHandle->fabricVertices[1]); + { + auto fabricDeviceIaf = static_cast(fabricVertex1->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Iaf].get()); + auto &fabricSubDeviceIaf0 = fabricDeviceIaf->subDeviceIafs[0]; + fabricSubDeviceIaf0->connections.clear(); + fabricSubDeviceIaf0->connections = connection10To00; + fabricSubDeviceIaf0->guid = 0xABC; + + auto &fabricSubDeviceIaf1 = fabricDeviceIaf->subDeviceIafs[1]; + fabricSubDeviceIaf1->connections.clear(); + fabricSubDeviceIaf1->connections = connection11To01; + fabricSubDeviceIaf1->guid = 0xABCD; + + //SubVertices + auto &fabricVertex00 = fabricVertex1->subVertices[0]; + auto fabricSubDeviceIaf00 = static_cast(fabricVertex00->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Iaf].get()); + fabricSubDeviceIaf00->connections.clear(); + fabricSubDeviceIaf00->connections = connection10To00; + fabricSubDeviceIaf00->guid = 0xABC; + + auto &fabricVertex01 = fabricVertex1->subVertices[1]; + auto fabricSubDeviceIaf01 = static_cast(fabricVertex01->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Iaf].get()); + fabricSubDeviceIaf01->connections.clear(); + fabricSubDeviceIaf01->connections = connection11To01; + fabricSubDeviceIaf01->guid = 0xABCD; + } + + for (auto &edge : driverHandle->fabricEdges) { + delete edge; + } + driverHandle->fabricEdges.clear(); + FabricEdge::createEdgesFromVertices(driverHandle->fabricVertices, driverHandle->fabricEdges); + + constexpr uint32_t root2root = 1; + constexpr uint32_t subDevice2root = 4; // 2 root to 2 sub-devices each + constexpr uint32_t subDevice2SubDevice = 4 + 2; //4 MDFI (considering 4 roots with 2 sub-devices); 2 sub-device to sub-device XeLink + + EXPECT_EQ(static_cast(driverHandle->fabricEdges.size()), root2root + subDevice2root + subDevice2SubDevice); + + uint32_t count = 0; + std::vector edges(30); + + // Root to Root Connection + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex1->toHandle(), fabricVertex0->toHandle(), &count, nullptr)); + EXPECT_EQ(count, 1u); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex1->toHandle(), fabricVertex0->toHandle(), &count, edges.data())); + ze_fabric_vertex_handle_t vertexA = nullptr, vertexB = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetVerticesExp(edges[0], &vertexA, &vertexB)); + EXPECT_EQ(vertexA, fabricVertex0); + EXPECT_EQ(vertexB, fabricVertex1); + ze_fabric_edge_exp_properties_t edgeProperties = {}; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetPropertiesExp(edges[0], &edgeProperties)); + EXPECT_EQ(edgeProperties.bandwidth, 4u); + EXPECT_EQ(edgeProperties.bandwidthUnit, ZE_BANDWIDTH_UNIT_BYTES_PER_NANOSEC); + EXPECT_EQ(edgeProperties.latency, 0u); + EXPECT_EQ(edgeProperties.latencyUnit, ZE_LATENCY_UNIT_UNKNOWN); + EXPECT_EQ(strcmp(edgeProperties.model, "XeLink"), 0); + EXPECT_EQ(edgeProperties.duplexity, ZE_FABRIC_EDGE_EXP_DUPLEXITY_FULL_DUPLEX); + + // Root to Sub-Devices Connection + count = 0; + + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex0->toHandle(), fabricVertex1->subVertices[0], &count, nullptr)); + EXPECT_EQ(count, 1u); + edges.clear(); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex0->toHandle(), fabricVertex1->subVertices[0], &count, edges.data())); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetPropertiesExp(edges[0], &edgeProperties)); + EXPECT_EQ(edgeProperties.bandwidth, 2u); + EXPECT_EQ(strcmp(edgeProperties.model, "XeLink"), 0); + + count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex0->toHandle(), fabricVertex1->subVertices[1], &count, nullptr)); + EXPECT_EQ(count, 1u); + edges.clear(); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex0->toHandle(), fabricVertex1->subVertices[1], &count, edges.data())); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetPropertiesExp(edges[0], &edgeProperties)); + EXPECT_EQ(edgeProperties.bandwidth, 2u); + EXPECT_EQ(strcmp(edgeProperties.model, "XeLink"), 0); + + // Sub-Devices to Root Connection + count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex0->subVertices[0], fabricVertex1->toHandle(), &count, nullptr)); + EXPECT_EQ(count, 1u); + edges.clear(); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex0->subVertices[0], fabricVertex1->toHandle(), &count, edges.data())); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetPropertiesExp(edges[0], &edgeProperties)); + EXPECT_EQ(edgeProperties.bandwidth, 2u); + EXPECT_EQ(strcmp(edgeProperties.model, "XeLink"), 0); + + count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex0->subVertices[1], fabricVertex1->toHandle(), &count, nullptr)); + EXPECT_EQ(count, 1u); + edges.clear(); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex0->subVertices[1], fabricVertex1->toHandle(), &count, edges.data())); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetPropertiesExp(edges[0], &edgeProperties)); + EXPECT_EQ(edgeProperties.bandwidth, 2u); + EXPECT_EQ(strcmp(edgeProperties.model, "XeLink"), 0); + + // Sub-Devices to Sub-Devices Connection + count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex0->subVertices[0], fabricVertex0->subVertices[1], &count, nullptr)); + EXPECT_EQ(count, 1u); + edges.clear(); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex0->subVertices[0], fabricVertex0->subVertices[1], &count, edges.data())); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetPropertiesExp(edges[0], &edgeProperties)); + EXPECT_EQ(edgeProperties.bandwidth, 0u); + EXPECT_EQ(edgeProperties.bandwidthUnit, ZE_BANDWIDTH_UNIT_UNKNOWN); + EXPECT_EQ(edgeProperties.latency, 0u); + EXPECT_EQ(edgeProperties.latencyUnit, ZE_LATENCY_UNIT_UNKNOWN); + EXPECT_EQ(strcmp(edgeProperties.model, "MDFI"), 0); + EXPECT_EQ(edgeProperties.duplexity, ZE_FABRIC_EDGE_EXP_DUPLEXITY_FULL_DUPLEX); + + count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex1->subVertices[0], fabricVertex1->subVertices[1], &count, nullptr)); + EXPECT_EQ(count, 1u); + edges.clear(); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex1->subVertices[0], fabricVertex1->subVertices[1], &count, edges.data())); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetPropertiesExp(edges[0], &edgeProperties)); + EXPECT_EQ(strcmp(edgeProperties.model, "MDFI"), 0); + + count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex1->subVertices[0], fabricVertex0->subVertices[0], &count, nullptr)); + EXPECT_EQ(count, 1u); + edges.clear(); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex1->subVertices[0], fabricVertex0->subVertices[0], &count, edges.data())); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetPropertiesExp(edges[0], &edgeProperties)); + EXPECT_EQ(edgeProperties.bandwidth, 2u); + EXPECT_EQ(strcmp(edgeProperties.model, "XeLink"), 0); + + count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex1->subVertices[1], fabricVertex0->subVertices[1], &count, nullptr)); + EXPECT_EQ(count, 1u); + edges.clear(); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(fabricVertex1->subVertices[1], fabricVertex0->subVertices[1], &count, edges.data())); + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetPropertiesExp(edges[0], &edgeProperties)); + EXPECT_EQ(edgeProperties.bandwidth, 2u); + EXPECT_EQ(strcmp(edgeProperties.model, "XeLink"), 0); +} + } // namespace ult } // namespace L0 \ No newline at end of file diff --git a/level_zero/core/test/unit_tests/sources/fabric/test_fabric.cpp b/level_zero/core/test/unit_tests/sources/fabric/test_fabric.cpp index b929d6811b..54faa1777c 100644 --- a/level_zero/core/test/unit_tests/sources/fabric/test_fabric.cpp +++ b/level_zero/core/test/unit_tests/sources/fabric/test_fabric.cpp @@ -11,11 +11,29 @@ #include "shared/test/common/test_macros/test.h" #include "level_zero/core/source/fabric/fabric.h" +#include "level_zero/core/source/fabric/fabric_device_interface.h" #include "level_zero/core/test/unit_tests/fixtures/device_fixture.h" namespace L0 { +class FabricDeviceMdfi; namespace ult { +class MockFabricDeviceInterface { + + ze_result_t enumerate() { return ZE_RESULT_SUCCESS; } + bool getEdgeProperty(FabricVertex *neighborVertex, ze_fabric_edge_exp_properties_t &edgeProperty) { + + if (mockEdgeProperties.size() > mockEdgePropertiesCounter) { + edgeProperty = mockEdgeProperties[mockEdgePropertiesCounter]; + } + return getEdgePropertyResult; + } + + std::vector mockEdgeProperties = {}; + uint32_t mockEdgePropertiesCounter = 0; + bool getEdgePropertyResult = true; +}; + using FabricVertexFixture = Test; TEST_F(FabricVertexFixture, WhenDevicesAreCreatedThenVerifyFabricVerticesAreCreated) { @@ -159,5 +177,117 @@ TEST(FabricEngineInstanceTest, GivenEngineInstancedDeviceWhenFabricVerticesAreCr EXPECT_EQ(count, 0u); } +TEST_F(FabricVertexFixture, GivenDevicesAreCreatedWhenZeDeviceGetFabricVertexExpIsCalledThenExpectValidVertices) { + + for (auto l0Device : driverHandle->devices) { + ze_fabric_vertex_handle_t hVertex = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeDeviceGetFabricVertexExp(l0Device->toHandle(), &hVertex)); + EXPECT_NE(hVertex, nullptr); + + auto deviceImp = static_cast(l0Device); + for (auto l0SubDevice : deviceImp->subDevices) { + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeDeviceGetFabricVertexExp(l0SubDevice->toHandle(), &hVertex)); + EXPECT_NE(hVertex, nullptr); + } + } +} + +TEST_F(FabricVertexFixture, GivenDevicesAreCreatedWhenFabricVertexIsNotSetToDeviceThenZeDeviceGetFabricVertexExpReturnsError) { + auto l0Device = driverHandle->devices[0]; + auto deviceImp = static_cast(l0Device); + deviceImp->setFabricVertex(nullptr); + + ze_fabric_vertex_handle_t hVertex = nullptr; + EXPECT_EQ(ZE_RESULT_EXP_ERROR_DEVICE_IS_NOT_VERTEX, L0::zeDeviceGetFabricVertexExp(l0Device->toHandle(), &hVertex)); + EXPECT_EQ(hVertex, nullptr); +} + +using FabricEdgeFixture = Test; + +TEST_F(FabricEdgeFixture, GivenFabricVerticesAreCreatedWhenZeFabricEdgeGetExpIsCalledThenReturnSuccess) { + + // Delete existing fabric edges + for (auto edge : driverHandle->fabricEdges) { + delete edge; + } + driverHandle->fabricEdges.clear(); + + ze_fabric_edge_exp_properties_t dummyProperties = {}; + driverHandle->fabricEdges.push_back(FabricEdge::create(driverHandle->fabricVertices[0], driverHandle->fabricVertices[1], dummyProperties)); + driverHandle->fabricEdges.push_back(FabricEdge::create(driverHandle->fabricVertices[0], driverHandle->fabricVertices[1], dummyProperties)); + driverHandle->fabricEdges.push_back(FabricEdge::create(driverHandle->fabricVertices[0], driverHandle->fabricVertices[1], dummyProperties)); + + std::vector edgeHandles(10); + uint32_t count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(driverHandle->fabricVertices[0]->toHandle(), + driverHandle->fabricVertices[1]->toHandle(), + &count, + edgeHandles.data())); + EXPECT_EQ(count, 3u); + count = 2; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(driverHandle->fabricVertices[1]->toHandle(), + driverHandle->fabricVertices[0]->toHandle(), + &count, + edgeHandles.data())); +} + +TEST_F(FabricEdgeFixture, GivenFabricEdgesAreCreatedWhenZeFabricEdgeGetVerticesExpIsCalledThenReturnCorrectVertices) { + + // Delete existing fabric edges + for (auto edge : driverHandle->fabricEdges) { + delete edge; + } + driverHandle->fabricEdges.clear(); + + ze_fabric_edge_exp_properties_t dummyProperties = {}; + driverHandle->fabricEdges.push_back(FabricEdge::create(driverHandle->fabricVertices[0], driverHandle->fabricVertices[1], dummyProperties)); + + std::vector edgeHandles(10); + uint32_t count = 1; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(driverHandle->fabricVertices[1]->toHandle(), + driverHandle->fabricVertices[0]->toHandle(), + &count, + edgeHandles.data())); + ze_fabric_vertex_handle_t hVertexA = nullptr; + ze_fabric_vertex_handle_t hVertexB = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetVerticesExp(edgeHandles[0], &hVertexA, &hVertexB)); + EXPECT_EQ(hVertexA, driverHandle->fabricVertices[0]); + EXPECT_EQ(hVertexB, driverHandle->fabricVertices[1]); +} + +TEST_F(FabricEdgeFixture, GivenFabricEdgesAreCreatedWhenZeFabricEdgeGetPropertiesExpIsCalledThenReturnCorrectProperties) { + + // Delete existing fabric edges + for (auto edge : driverHandle->fabricEdges) { + delete edge; + } + driverHandle->fabricEdges.clear(); + + ze_fabric_edge_exp_properties_t properties = {}; + properties.bandwidth = 10; + properties.latency = 20; + driverHandle->fabricEdges.push_back(FabricEdge::create(driverHandle->fabricVertices[0], driverHandle->fabricVertices[1], properties)); + + std::vector edgeHandles(10); + uint32_t count = 1; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetExp(driverHandle->fabricVertices[1]->toHandle(), + driverHandle->fabricVertices[0]->toHandle(), + &count, + edgeHandles.data())); + ze_fabric_edge_exp_properties_t getProperties = {}; + EXPECT_EQ(ZE_RESULT_SUCCESS, L0::zeFabricEdgeGetPropertiesExp(edgeHandles[0], &getProperties)); + EXPECT_EQ(getProperties.bandwidth, 10u); + EXPECT_EQ(getProperties.latency, 20u); +} + +TEST_F(FabricEdgeFixture, GivenMdfiLinksAreAvailableWhenEdgesAreCreatedThenVerifyThatBiDirectionalEdgesAreNotCreated) { + + auto &fabricSubVertex1 = driverHandle->fabricVertices[0]->subVertices[1]; + auto fabricDeviceMdfi = static_cast(fabricSubVertex1->pFabricDeviceInterfaces[FabricDeviceInterface::Type::Mdfi].get()); + + ze_fabric_edge_exp_properties_t unusedProperty = {}; + EXPECT_FALSE(fabricDeviceMdfi->getEdgeProperty(driverHandle->fabricVertices[0]->subVertices[0], unusedProperty)); +} + } // namespace ult -} // namespace L0 \ No newline at end of file +} // namespace L0