/* * Copyright (C) 2018-2022 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "shared/source/memory_manager/internal_allocation_storage.h" #include "shared/source/utilities/arrayref.h" #include "shared/test/common/mocks/mock_csr.h" #include "shared/test/common/mocks/mock_device.h" #include "opencl/source/event/event_builder.h" #include "opencl/source/event/user_event.h" #include "opencl/source/helpers/task_information.h" #include "opencl/test/unit_test/mocks/mock_cl_device.h" #include "opencl/test/unit_test/mocks/mock_command_queue.h" #include "opencl/test/unit_test/mocks/mock_context.h" #include "opencl/test/unit_test/mocks/mock_event.h" #include "opencl/test/unit_test/mocks/mock_kernel.h" #include "gtest/gtest.h" namespace NEO { struct SmallEventBuilderEventMock : MockEvent { SmallEventBuilderEventMock(CommandQueue *commandQueue, int param1, float param2) : MockEvent(commandQueue, CL_COMMAND_NDRANGE_KERNEL, 0, 0), constructionParam1(param1), constructionParam2(param2) { } SmallEventBuilderEventMock(CommandQueue *commandQueue) : SmallEventBuilderEventMock(commandQueue, 1, 2.0f) { } void overrideMagic(cl_long newMagic) { this->magic = newMagic; } int constructionParam1 = 1; float constructionParam2 = 2.0f; }; struct SmallEventBuilderMock : EventBuilder { void clear() { EventBuilder::clear(); } void clearEvent() { event = nullptr; } ArrayRef getParentEvents() { return this->parentEvents; } }; TEST(EventBuilder, whenCreatingNewEventThenForwardArgumentsToEventConstructor) { auto device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); MockContext context(device.get()); MockCommandQueue cmdQ(&context, device.get(), nullptr, false); EventBuilder eventBuilder; EXPECT_EQ(nullptr, eventBuilder.getEvent()); constexpr int constrParam1 = 7; constexpr float constrParam2 = 13.0f; eventBuilder.create(&cmdQ, constrParam1, constrParam2); Event *peekedEvent = eventBuilder.getEvent(); ASSERT_NE(nullptr, peekedEvent); auto finalizedEvent = static_cast(eventBuilder.finalizeAndRelease()); EXPECT_EQ(peekedEvent, peekedEvent); EXPECT_EQ(constrParam1, finalizedEvent->constructionParam1); EXPECT_EQ(constrParam2, finalizedEvent->constructionParam2); finalizedEvent->release(); } TEST(EventBuilder, givenVirtualEventWithCommandThenFinalizeAddChild) { class MockCommandComputeKernel : public CommandComputeKernel { public: using CommandComputeKernel::eventsWaitlist; MockCommandComputeKernel(CommandQueue &commandQueue, std::unique_ptr &kernelOperation, std::vector &surfaces, Kernel *kernel) : CommandComputeKernel(commandQueue, kernelOperation, surfaces, false, false, false, nullptr, PreemptionMode::Disabled, kernel, 0) {} }; auto device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); MockContext context(device.get()); MockCommandQueue cmdQ(&context, device.get(), nullptr, false); MockKernelWithInternals kernel(*device); IndirectHeap *ih1 = nullptr, *ih2 = nullptr, *ih3 = nullptr; cmdQ.allocateHeapMemory(IndirectHeap::Type::DYNAMIC_STATE, 1, ih1); cmdQ.allocateHeapMemory(IndirectHeap::Type::INDIRECT_OBJECT, 1, ih2); cmdQ.allocateHeapMemory(IndirectHeap::Type::SURFACE_STATE, 1, ih3); auto cmdStream = new LinearStream(device->getMemoryManager()->allocateGraphicsMemoryWithProperties({device->getRootDeviceIndex(), 1, AllocationType::COMMAND_BUFFER, device->getDeviceBitfield()})); std::vector surfaces; auto kernelOperation = std::make_unique(cmdStream, *device->getDefaultEngine().commandStreamReceiver->getInternalAllocationStorage()); kernelOperation->setHeaps(ih1, ih2, ih3); std::unique_ptr command = std::make_unique(cmdQ, kernelOperation, surfaces, kernel); VirtualEvent virtualEvent(&cmdQ); virtualEvent.setCommand(std::move(command)); EventBuilder eventBuilder; EXPECT_EQ(nullptr, eventBuilder.getEvent()); constexpr int constrParam1 = 7; constexpr float constrParam2 = 13.0f; eventBuilder.create(&cmdQ, constrParam1, constrParam2); Event *peekedEvent = eventBuilder.getEvent(); ASSERT_NE(nullptr, peekedEvent); virtualEvent.taskLevel = CL_SUBMITTED; eventBuilder.addParentEvent(&virtualEvent); eventBuilder.finalize(); peekedEvent->release(); } TEST(EventBuilder, givenVirtualEventWithSubmittedCommandAsParentThenFinalizeNotAddChild) { class MockVirtualEvent : public VirtualEvent { public: using VirtualEvent::eventWithoutCommand; using VirtualEvent::submittedCmd; }; class MockCommandComputeKernel : public CommandComputeKernel { public: using CommandComputeKernel::eventsWaitlist; MockCommandComputeKernel(CommandQueue &commandQueue, std::unique_ptr &kernelOperation, std::vector &surfaces, Kernel *kernel) : CommandComputeKernel(commandQueue, kernelOperation, surfaces, false, false, false, nullptr, PreemptionMode::Disabled, kernel, 0) {} }; auto device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); MockContext context(device.get()); MockCommandQueue cmdQ(&context, device.get(), nullptr, false); MockKernelWithInternals kernel(*device); IndirectHeap *ih1 = nullptr, *ih2 = nullptr, *ih3 = nullptr; cmdQ.allocateHeapMemory(IndirectHeap::Type::DYNAMIC_STATE, 1, ih1); cmdQ.allocateHeapMemory(IndirectHeap::Type::INDIRECT_OBJECT, 1, ih2); cmdQ.allocateHeapMemory(IndirectHeap::Type::SURFACE_STATE, 1, ih3); auto cmdStream = new LinearStream(device->getMemoryManager()->allocateGraphicsMemoryWithProperties({device->getRootDeviceIndex(), 4096, AllocationType::COMMAND_BUFFER, device->getDeviceBitfield()})); std::vector surfaces; auto kernelOperation = std::make_unique(cmdStream, *device->getDefaultEngine().commandStreamReceiver->getInternalAllocationStorage()); kernelOperation->setHeaps(ih1, ih2, ih3); std::unique_ptr command = std::make_unique(cmdQ, kernelOperation, surfaces, kernel); MockVirtualEvent virtualEvent; virtualEvent.eventWithoutCommand = false; virtualEvent.submittedCmd.exchange(command.release()); EventBuilder eventBuilder; EXPECT_EQ(nullptr, eventBuilder.getEvent()); constexpr int constrParam1 = 7; constexpr float constrParam2 = 13.0f; eventBuilder.create(&cmdQ, constrParam1, constrParam2); Event *peekedEvent = eventBuilder.getEvent(); ASSERT_NE(nullptr, peekedEvent); virtualEvent.taskLevel = CL_SUBMITTED; eventBuilder.addParentEvent(&virtualEvent); eventBuilder.finalize(); peekedEvent->release(); } TEST(EventBuilder, whenDestroyingEventBuilderThenImplicitFinalizeIsCalled) { auto device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); MockContext context(device.get()); MockCommandQueue cmdQ(&context, device.get(), nullptr, false); SmallEventBuilderEventMock *ev = nullptr; auto parentEvent = new UserEvent; { EventBuilder eventBuilder{}; eventBuilder.create(&cmdQ); eventBuilder.addParentEvent(*parentEvent); ev = static_cast(eventBuilder.getEvent()); ASSERT_NE(nullptr, ev); EXPECT_EQ(0U, ev->peekNumEventsBlockingThis()); } // make sure that finalize was called on EventBuilder's d-tor and parent was added properly EXPECT_EQ(1U, ev->peekNumEventsBlockingThis()); ev->release(); parentEvent->release(); } TEST(EventBuilder, whenFinalizeIsCalledTwiceOnEventBuilderThenSecondRequestIsDropped) { auto device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); MockContext context(device.get()); MockCommandQueue cmdQ(&context, device.get(), nullptr, false); SmallEventBuilderEventMock *ev = nullptr; EventBuilder eventBuilder{}; eventBuilder.create(&cmdQ); ev = static_cast(eventBuilder.getEvent()); ASSERT_NE(nullptr, ev); eventBuilder.finalize(); auto *falseParentEvent = new UserEvent(); auto *falseChildEvent = new SmallEventBuilderEventMock(&cmdQ); auto numParents = ev->peekNumEventsBlockingThis(); auto numChildren = (ev->peekChildEvents() != nullptr) ? 1U + ev->peekChildEvents()->countSuccessors() : 0; eventBuilder.addParentEvent(*falseParentEvent); eventBuilder.finalize(); // make sure that new parent was not added in second finalize EXPECT_EQ(numParents, ev->peekNumEventsBlockingThis()); EXPECT_EQ(numChildren, (ev->peekChildEvents() != nullptr) ? 1U + ev->peekChildEvents()->countSuccessors() : 0); falseParentEvent->release(); falseChildEvent->release(); ev->release(); } TEST(EventBuilder, whenFinalizeAndReleaseIsCalledThenEventBuilderReleasesReferenceToEvent) { auto device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); MockContext context(device.get()); MockCommandQueue cmdQ(&context, device.get(), nullptr, false); EventBuilder eventBuilder; eventBuilder.create(&cmdQ); auto ev = static_cast(eventBuilder.finalizeAndRelease()); ASSERT_NE(nullptr, ev); ASSERT_EQ(nullptr, eventBuilder.getEvent()); ASSERT_EQ(nullptr, eventBuilder.finalizeAndRelease()); ev->release(); } TEST(EventBuilder, whenClearIsCalledThenAllEventsAndReferencesAreDropped) { auto parentEvent = new UserEvent(); SmallEventBuilderMock eventBuilder; eventBuilder.addParentEvent(*parentEvent); eventBuilder.clear(); EXPECT_EQ(0U, eventBuilder.getParentEvents().size()); EXPECT_EQ(nullptr, eventBuilder.getEvent()); parentEvent->release(); } TEST(EventBuilder, whenCParentEventsGetAddedThenTheirReferenceCountGetsIncreasedUntilFinalizeIsCalled) { auto device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); MockContext context(device.get()); MockCommandQueue cmdQ(&context, device.get(), nullptr, false); UserEvent evParent1; UserEvent evParent2; EXPECT_EQ(1, evParent1.getRefInternalCount()); EXPECT_EQ(1, evParent2.getRefInternalCount()); EventBuilder eventBuilder; eventBuilder.create(&cmdQ); eventBuilder.addParentEvent(evParent1); EXPECT_EQ(2, evParent1.getRefInternalCount()); eventBuilder.addParentEvent(evParent2); EXPECT_EQ(2, evParent2.getRefInternalCount()); auto createdEvent = static_cast(eventBuilder.finalizeAndRelease()); EXPECT_EQ(2U, createdEvent->peekNumEventsBlockingThis()); createdEvent->release(); evParent1.setStatus(CL_COMPLETE); evParent2.setStatus(CL_COMPLETE); EXPECT_EQ(1, evParent1.getRefInternalCount()); EXPECT_EQ(1, evParent2.getRefInternalCount()); } TEST(EventBuilder, whenFinalizeIsCalledWithEmptyEventsListsThenParentAndChildListsAreEmpty) { EventBuilder eventBuilder; eventBuilder.create>(nullptr, CL_COMMAND_MARKER, 0, 0); Event *event = eventBuilder.finalizeAndRelease(); EXPECT_EQ(0U, event->peekNumEventsBlockingThis()); EXPECT_EQ(nullptr, event->peekChildEvents()); event->release(); } TEST(EventBuilder, whenFinalizeIsCalledAndBuildersEventsListAreNotEmptyThenEventsListsAreAddedToEvent) { MockEvent *parentEvent = new MockEvent(); EventBuilder eventBuilder; eventBuilder.create>(nullptr, CL_COMMAND_MARKER, 0, 0); eventBuilder.addParentEvent(*parentEvent); Event *event = eventBuilder.finalizeAndRelease(); EXPECT_EQ(1U, event->peekNumEventsBlockingThis()); ASSERT_NE(nullptr, parentEvent->peekChildEvents()); EXPECT_EQ(event, parentEvent->peekChildEvents()->ref); parentEvent->setStatus(CL_COMPLETE); EXPECT_EQ(0U, event->peekNumEventsBlockingThis()); EXPECT_EQ(nullptr, parentEvent->peekChildEvents()); event->release(); parentEvent->release(); } TEST(EventBuilder, whenFinalizeIsCalledAndParentsListContainsManyEventsFromWhichOnlyFirstOnesAreCompletedThenEventIsNotCompleted) { MockEvent *userEventNotCompleted = new MockEvent(); MockEvent *userEventCompleted = new MockEvent(); userEventCompleted->setStatus(CL_COMPLETE); EventBuilder eventBuilder; eventBuilder.create>(nullptr, CL_COMMAND_MARKER, 0, 0); eventBuilder.addParentEvent(*userEventCompleted); eventBuilder.addParentEvent(*userEventNotCompleted); Event *event = eventBuilder.finalizeAndRelease(); EXPECT_FALSE(event->updateStatusAndCheckCompletion()); EXPECT_EQ(1U, event->peekNumEventsBlockingThis()); ASSERT_EQ(nullptr, userEventCompleted->peekChildEvents()); ASSERT_NE(nullptr, userEventNotCompleted->peekChildEvents()); EXPECT_EQ(event, userEventNotCompleted->peekChildEvents()->ref); userEventNotCompleted->setStatus(CL_COMPLETE); EXPECT_EQ(0U, event->peekNumEventsBlockingThis()); EXPECT_EQ(nullptr, userEventNotCompleted->peekChildEvents()); event->release(); userEventCompleted->release(); userEventNotCompleted->release(); } TEST(EventBuilder, whenAddingNullptrAsNewParentEventThenItIsIgnored) { SmallEventBuilderMock eventBuilder; EXPECT_EQ(0U, eventBuilder.getParentEvents().size()); eventBuilder.addParentEvent(nullptr); EXPECT_EQ(0U, eventBuilder.getParentEvents().size()); } TEST(EventBuilder, whenAddingValidEventAsNewParentEventThenItIsProperlyAddedToParentsList) { auto device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); MockContext context(device.get()); MockCommandQueue cmdQ(&context, device.get(), nullptr, false); auto event = new SmallEventBuilderEventMock(&cmdQ); SmallEventBuilderMock eventBuilder; eventBuilder.create>(nullptr, CL_COMMAND_MARKER, 0, 0); EXPECT_EQ(0U, eventBuilder.getParentEvents().size()); eventBuilder.addParentEvent(event); EXPECT_EQ(1U, eventBuilder.getParentEvents().size()); event->release(); eventBuilder.finalize(); eventBuilder.getEvent()->release(); } TEST(EventBuilder, whenAddingMultipleEventsAsNewParentsThenOnlyValidOnesAreInsertedIntoParentsList) { auto device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); MockContext context(device.get()); MockCommandQueue cmdQ(&context, device.get(), nullptr, false); auto event = new SmallEventBuilderEventMock(&cmdQ); auto invalidEvent = new SmallEventBuilderEventMock(&cmdQ); invalidEvent->overrideMagic(0); cl_event eventsList[] = {nullptr, event, invalidEvent}; SmallEventBuilderMock eventBuilder; eventBuilder.create>(nullptr, CL_COMMAND_MARKER, 0, 0); EXPECT_EQ(0U, eventBuilder.getParentEvents().size()); eventBuilder.addParentEvents(ArrayRef(eventsList)); ASSERT_EQ(1U, eventBuilder.getParentEvents().size()); EXPECT_EQ(event, *eventBuilder.getParentEvents().begin()); invalidEvent->release(); event->release(); eventBuilder.finalize(); eventBuilder.getEvent()->release(); } TEST(EventBuilder, WhenAddingParentEventThenDuplicatesAreIgnored) { auto mockDevice = std::make_unique(MockDevice::createWithNewExecutionEnvironment(nullptr)); MockContext mockContext; MockCommandQueue mockCommandQueue(&mockContext, mockDevice.get(), nullptr, false); SmallEventBuilderMock *eventBuilder = new SmallEventBuilderMock; eventBuilder->create>(&mockCommandQueue, CL_COMMAND_MARKER, 0, 0); Event *event = eventBuilder->getEvent(); Event *parentEvent = new Event(&mockCommandQueue, CL_COMMAND_NDRANGE_KERNEL, 0, 0); Event *parentEvent2 = new Event(&mockCommandQueue, CL_COMMAND_NDRANGE_KERNEL, 0, 0); Event *parentEvent3 = new Event(&mockCommandQueue, CL_COMMAND_NDRANGE_KERNEL, 0, 0); eventBuilder->addParentEvent(parentEvent); eventBuilder->addParentEvent(parentEvent2); eventBuilder->addParentEvent(parentEvent3); // add duplicate eventBuilder->addParentEvent(parentEvent); auto parents = eventBuilder->getParentEvents(); size_t numberOfParents = parents.size(); EXPECT_EQ(3u, numberOfParents); event->release(); parentEvent->release(); parentEvent2->release(); parentEvent3->release(); eventBuilder->clear(); eventBuilder->clearEvent(); delete eventBuilder; } } // namespace NEO