diff --git a/level_zero/api/core/ze_core_loader.cpp b/level_zero/api/core/ze_core_loader.cpp index 01fc3b04ac..7697aee6fc 100644 --- a/level_zero/api/core/ze_core_loader.cpp +++ b/level_zero/api/core/ze_core_loader.cpp @@ -427,6 +427,22 @@ zeGetEventProcAddrTable( return result; } +ZE_APIEXPORT ze_result_t ZE_APICALL +zeGetEventExpProcAddrTable( + ze_api_version_t version, + ze_event_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->pfnQueryTimestampsExp = zeEventQueryTimestampsExp; + + return result; +} + ZE_APIEXPORT ze_result_t ZE_APICALL zeGetImageProcAddrTable( ze_api_version_t version, diff --git a/level_zero/api/core/ze_event.cpp b/level_zero/api/core/ze_event.cpp index a1eade437e..ebcd6ba3a0 100644 --- a/level_zero/api/core/ze_event.cpp +++ b/level_zero/api/core/ze_event.cpp @@ -111,4 +111,4 @@ zeEventQueryKernelTimestamp( ze_event_handle_t hEvent, ze_kernel_timestamp_result_t *timestampType) { return L0::Event::fromHandle(hEvent)->queryKernelTimestamp(timestampType); -} +} \ 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 e2e1a5965c..744ccb4bbc 100644 --- a/level_zero/api/extensions/public/ze_exp_ext.cpp +++ b/level_zero/api/extensions/public/ze_exp_ext.cpp @@ -7,6 +7,7 @@ #include "level_zero/api/extensions/public/ze_exp_ext.h" +#include "level_zero/core/source/event/event.h" #include "level_zero/core/source/image/image.h" #include "level_zero/core/source/kernel/kernel.h" @@ -40,6 +41,15 @@ zeImageViewCreateExp( return L0::Image::fromHandle(hImage)->createView(L0::Device::fromHandle(hDevice), desc, phImageView); } +ZE_APIEXPORT ze_result_t ZE_APICALL +zeEventQueryTimestampsExp( + ze_event_handle_t hEvent, + ze_device_handle_t hDevice, + uint32_t *pCount, + ze_kernel_timestamp_result_t *pTimestamps) { + return L0::Event::fromHandle(hEvent)->queryTimestampsExp(L0::Device::fromHandle(hDevice), pCount, pTimestamps); +} + #if defined(__cplusplus) } // extern "C" #endif diff --git a/level_zero/core/source/event/event.h b/level_zero/core/source/event/event.h index 15cb031a2b..30a48674f4 100644 --- a/level_zero/core/source/event/event.h +++ b/level_zero/core/source/event/event.h @@ -37,6 +37,7 @@ struct Event : _ze_event_handle_t { virtual ze_result_t queryStatus() = 0; virtual ze_result_t reset() = 0; virtual ze_result_t queryKernelTimestamp(ze_kernel_timestamp_result_t *dstptr) = 0; + virtual ze_result_t queryTimestampsExp(Device *device, uint32_t *pCount, ze_kernel_timestamp_result_t *pTimestamps) = 0; enum State : uint32_t { STATE_SIGNALED = 0u, STATE_CLEARED = static_cast(-1), @@ -119,6 +120,7 @@ struct EventImp : public Event { ze_result_t reset() override; ze_result_t queryKernelTimestamp(ze_kernel_timestamp_result_t *dstptr) override; + ze_result_t queryTimestampsExp(Device *device, uint32_t *pCount, ze_kernel_timestamp_result_t *pTimestamps) override; NEO::GraphicsAllocation &getAllocation(Device *device) override; diff --git a/level_zero/core/source/event/event_impl.inl b/level_zero/core/source/event/event_impl.inl index 80266c2b20..79632f07dc 100644 --- a/level_zero/core/source/event/event_impl.inl +++ b/level_zero/core/source/event/event_impl.inl @@ -250,6 +250,49 @@ ze_result_t EventImp::queryKernelTimestamp(ze_kernel_timestamp_result_ return ZE_RESULT_SUCCESS; } +template +ze_result_t EventImp::queryTimestampsExp(Device *device, uint32_t *pCount, ze_kernel_timestamp_result_t *pTimestamps) { + uint32_t timestampPacket = 0; + uint64_t globalStartTs, globalEndTs, contextStartTs, contextEndTs; + globalStartTs = globalEndTs = contextStartTs = contextEndTs = Event::STATE_INITIAL; + auto deviceImp = static_cast(device); + bool isStaticPartitioning = true; + + if (NEO::DebugManager.flags.EnableStaticPartitioning.get() == 0) { + isStaticPartitioning = false; + } + + if (deviceImp->isSubdevice || !isStaticPartitioning) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + if ((*pCount == 0) || + (*pCount > kernelTimestampsData[timestampPacket].getPacketsUsed())) { + *pCount = this->getPacketsInUse(); + return ZE_RESULT_SUCCESS; + } + + for (auto packetId = 0u; packetId < *pCount; packetId++) { + ze_kernel_timestamp_result_t &result = *(pTimestamps + packetId); + + auto queryTsEventAssignFunc = [&](uint64_t ×tampFieldForWriting, uint64_t ×tampFieldToCopy) { + memcpy_s(×tampFieldForWriting, sizeof(uint64_t), static_cast(×tampFieldToCopy), sizeof(uint64_t)); + }; + + globalStartTs = kernelTimestampsData[timestampPacket].getGlobalStartValue(packetId); + contextStartTs = kernelTimestampsData[timestampPacket].getContextStartValue(packetId); + contextEndTs = kernelTimestampsData[timestampPacket].getContextEndValue(packetId); + globalEndTs = kernelTimestampsData[timestampPacket].getGlobalEndValue(packetId); + + queryTsEventAssignFunc(result.global.kernelStart, globalStartTs); + queryTsEventAssignFunc(result.context.kernelStart, contextStartTs); + queryTsEventAssignFunc(result.global.kernelEnd, globalEndTs); + queryTsEventAssignFunc(result.context.kernelEnd, contextEndTs); + } + + return ZE_RESULT_SUCCESS; +} + template void EventImp::resetPackets() { for (uint32_t i = 0; i < kernelCount; i++) { diff --git a/level_zero/core/test/unit_tests/mocks/mock_event.h b/level_zero/core/test/unit_tests/mocks/mock_event.h index 53c7320755..e33e22025c 100644 --- a/level_zero/core/test/unit_tests/mocks/mock_event.h +++ b/level_zero/core/test/unit_tests/mocks/mock_event.h @@ -50,6 +50,7 @@ struct Mock : public Event { MOCK_METHOD0(queryStatus, ze_result_t()); MOCK_METHOD0(reset, ze_result_t()); MOCK_METHOD1(queryKernelTimestamp, ze_result_t(ze_kernel_timestamp_result_t *dstptr)); + MOCK_METHOD3(queryTimestampsExp, ze_result_t(::L0::Device *device, uint32_t *pCount, ze_kernel_timestamp_result_t *pTimestamps)); // Fake an allocation for event memory alignas(16) uint32_t memory = -1; diff --git a/level_zero/core/test/unit_tests/sources/cmdlist/test_cmdlist_5.cpp b/level_zero/core/test/unit_tests/sources/cmdlist/test_cmdlist_5.cpp index 90584fcb6a..24858a8d71 100644 --- a/level_zero/core/test/unit_tests/sources/cmdlist/test_cmdlist_5.cpp +++ b/level_zero/core/test/unit_tests/sources/cmdlist/test_cmdlist_5.cpp @@ -58,6 +58,9 @@ class MockEvent : public ::L0::Event { ze_result_t queryKernelTimestamp(ze_kernel_timestamp_result_t *dstptr) override { return ZE_RESULT_SUCCESS; }; + ze_result_t queryTimestampsExp(L0::Device *device, uint32_t *pCount, ze_kernel_timestamp_result_t *pTimestamps) override { + return ZE_RESULT_SUCCESS; + }; size_t getTimestampSizeInDw() const override { return 1; diff --git a/level_zero/core/test/unit_tests/sources/event/test_event.cpp b/level_zero/core/test/unit_tests/sources/event/test_event.cpp index 28cbc45e27..c907f139d6 100644 --- a/level_zero/core/test/unit_tests/sources/event/test_event.cpp +++ b/level_zero/core/test/unit_tests/sources/event/test_event.cpp @@ -654,6 +654,75 @@ TEST_F(TimestampEventCreate, givenEventWhenSignaledAndResetFromTheHostThenCorrec EXPECT_EQ(1u, event->kernelCount); } +TEST_F(TimestampEventCreate, givenpCountZeroCallingQueryTimestampExpThenpCountSetProperly) { + uint32_t pCount = 0; + auto result = event->queryTimestampsExp(device, &pCount, nullptr); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_NE(0u, pCount); +} + +TEST_F(TimestampEventCreate, givenpCountLargerThanSupportedWhenCallingQueryTimestampExpThenpCountSetProperly) { + uint32_t pCount = 10; + event->setPacketsInUse(2u); + auto result = event->queryTimestampsExp(device, &pCount, nullptr); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(2u, pCount); +} + +TEST_F(TimestampEventCreate, givenEventWithStaticPartitionOffThenQueryTimestampExpReturnsUnsupported) { + DebugManagerStateRestore restore; + NEO::DebugManager.flags.EnableStaticPartitioning.set(0); + + uint32_t pCount = 0; + auto result = event->queryTimestampsExp(device, &pCount, nullptr); + + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); +} + +using EventQueryTimestampExpWithSubDevice = Test; + +TEST_F(EventQueryTimestampExpWithSubDevice, givenEventWhenQuerytimestampExpWithSubDeviceThenReturnsUnsupported) { + std::unique_ptr eventPool; + std::unique_ptr> event; + + uint32_t deviceCount = 1; + ze_device_handle_t rootDeviceHandle; + + ze_result_t result = zeDeviceGet(driverHandle.get(), &deviceCount, &rootDeviceHandle); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + deviceCount = 0; + result = zeDeviceGetSubDevices(rootDeviceHandle, &deviceCount, nullptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_TRUE(deviceCount >= 2); + + auto subDeviceHandle = std::make_unique(deviceCount); + result = zeDeviceGetSubDevices(rootDeviceHandle, &deviceCount, subDeviceHandle.get()); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + ze_event_pool_desc_t eventPoolDesc = {}; + eventPoolDesc.count = 1; + eventPoolDesc.flags = ZE_EVENT_POOL_FLAG_HOST_VISIBLE | ZE_EVENT_POOL_FLAG_KERNEL_TIMESTAMP; + + ze_event_desc_t eventDesc = {}; + eventDesc.index = 0; + eventDesc.signal = 0; + eventDesc.wait = 0; + + auto subdevice = L0::Device::fromHandle(subDeviceHandle[0]); + eventPool = std::unique_ptr(L0::EventPool::create(driverHandle.get(), context, 1, &subDeviceHandle[0], &eventPoolDesc)); + ASSERT_NE(nullptr, eventPool); + event = std::unique_ptr>(static_cast *>(L0::Event::create(eventPool.get(), &eventDesc, subdevice))); + ASSERT_NE(nullptr, event); + + uint32_t pCount = 0; + result = event->queryTimestampsExp(subdevice, &pCount, nullptr); + + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); +} + HWCMDTEST_F(IGFX_GEN9_CORE, TimestampEventCreate, givenEventTimestampsWhenQueryKernelTimestampThenCorrectDataAreSet) { class MockTimestampPackets32 : public TimestampPackets { public: @@ -676,6 +745,46 @@ HWCMDTEST_F(IGFX_GEN9_CORE, TimestampEventCreate, givenEventTimestampsWhenQueryK EXPECT_EQ(data.globalEnd, result.global.kernelEnd); } +TEST_F(TimestampEventCreate, givenEventWhenQueryingTimestampExpThenCorrectDataSet) { + class MockTimestampPackets32 : public TimestampPackets { + public: + using typename TimestampPackets::Packet; + }; + + typename MockTimestampPackets32::Packet packetData[2]; + event->setPacketsInUse(2u); + + packetData[0].contextStart = 1u; + packetData[0].contextEnd = 2u; + packetData[0].globalStart = 3u; + packetData[0].globalEnd = 4u; + + packetData[1].contextStart = 5u; + packetData[1].contextEnd = 6u; + packetData[1].globalStart = 7u; + packetData[1].globalEnd = 8u; + + event->hostAddress = packetData; + + ze_kernel_timestamp_result_t results[2]; + uint32_t pCount = 2; + + for (uint32_t packetId = 0; packetId < pCount; packetId++) { + event->kernelTimestampsData[0].assignDataToAllTimestamps(packetId, event->hostAddress); + event->hostAddress = ptrOffset(event->hostAddress, NEO::TimestampPackets::getSinglePacketSize()); + } + + auto result = event->queryTimestampsExp(device, &pCount, results); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + for (uint32_t i = 0; i < pCount; i++) { + EXPECT_EQ(packetData[i].contextStart, results[i].context.kernelStart); + EXPECT_EQ(packetData[i].contextEnd, results[i].context.kernelEnd); + EXPECT_EQ(packetData[i].globalStart, results[i].global.kernelStart); + EXPECT_EQ(packetData[i].globalEnd, results[i].global.kernelEnd); + } +} + HWTEST_EXCLUDE_PRODUCT(TimestampEventCreate, givenEventTimestampsWhenQueryKernelTimestampThenCorrectDataAreSet, IGFX_GEN12LP_CORE); TEST_F(TimestampEventCreate, givenEventWhenQueryKernelTimestampThenNotReadyReturned) {