Do not use peekIsCompleted in isQueueBlocked.

- This causes event tree update if virtual event is holding commands or
callbacks
- That causes race between other threads that may be updating the tree

Change-Id: Ic80a8b71ed1e1c1deab8af1bc64f8ce81c21de1b
This commit is contained in:
Mrozek, Michal 2017-12-20 10:20:17 +01:00
parent 7e9ad41290
commit 3284efff86
5 changed files with 45 additions and 9 deletions

2
Jenkinsfile vendored
View File

@ -2,4 +2,4 @@
neoDependenciesRev='716918-671' neoDependenciesRev='716918-671'
strategy='EQUAL' strategy='EQUAL'
allowedF=49 allowedF=49
allowedCD=381 allowedCD=380

View File

@ -164,7 +164,7 @@ bool CommandQueue::isQueueBlocked() {
TakeOwnershipWrapper<CommandQueue> takeOwnershipWrapper(*this); TakeOwnershipWrapper<CommandQueue> takeOwnershipWrapper(*this);
//check if we have user event and if so, if it is in blocked state. //check if we have user event and if so, if it is in blocked state.
if (this->virtualEvent) { if (this->virtualEvent) {
if (this->virtualEvent->peekIsCompleted()) { if (this->virtualEvent->peekExecutionStatus() <= CL_COMPLETE) {
UNRECOVERABLE_IF(this->virtualEvent == nullptr); UNRECOVERABLE_IF(this->virtualEvent == nullptr);
if (this->virtualEvent->peekIsCompletedByTermination() == false) { if (this->virtualEvent->peekIsCompletedByTermination() == false) {

View File

@ -534,7 +534,11 @@ inline void Event::unblockEventBy(Event &event, uint32_t taskLevel, int32_t tran
} }
DBG_LOG(EventsDebugEnable, "Event", this, "is unblocked by", &event); DBG_LOG(EventsDebugEnable, "Event", this, "is unblocked by", &event);
this->taskLevel = taskLevel; if (this->taskLevel == Event::eventNotReady) {
this->taskLevel = taskLevel;
} else {
this->taskLevel = std::max(this->taskLevel.load(), taskLevel);
}
int32_t statusToPropagate = CL_SUBMITTED; int32_t statusToPropagate = CL_SUBMITTED;
if (peekIsCompletedByTermination(&blockerStatus)) { if (peekIsCompletedByTermination(&blockerStatus)) {

View File

@ -723,7 +723,6 @@ HWTEST_F(CommandQueueHwTest, givenBlockedInOrderCmdQueueAndAsynchronouslyComplet
}; };
Event event(cmdQHw, CL_COMMAND_NDRANGE_KERNEL, 10, 0); Event event(cmdQHw, CL_COMMAND_NDRANGE_KERNEL, 10, 0);
event.setStatus(CL_SUBMITTED);
uint32_t virtualEventTaskLevel = 77; uint32_t virtualEventTaskLevel = 77;
uint32_t virtualEventTaskCount = 80; uint32_t virtualEventTaskCount = 80;
@ -734,16 +733,24 @@ HWTEST_F(CommandQueueHwTest, givenBlockedInOrderCmdQueueAndAsynchronouslyComplet
// Put Queue in blocked state by assigning virtualEvent // Put Queue in blocked state by assigning virtualEvent
virtualEvent.incRefInternal(); virtualEvent.incRefInternal();
event.addChild(virtualEvent);
cmdQHw->virtualEvent = &virtualEvent; cmdQHw->virtualEvent = &virtualEvent;
cmdQHw->incRefInternal(); cmdQHw->incRefInternal();
cmdQHw->taskLevel = 23; cmdQHw->taskLevel = 23;
cmdQHw->enqueueKernel(mockKernel, 1, &offset, &size, &size, 1, &blockedEvent, nullptr); cmdQHw->enqueueKernel(mockKernel, 1, &offset, &size, &size, 1, &blockedEvent, nullptr);
//new virtual event is created on enqueue, bind it to the created virtual event
EXPECT_NE(cmdQHw->virtualEvent, &virtualEvent);
event.setStatus(CL_SUBMITTED);
virtualEvent.Event::updateExecutionStatus();
EXPECT_FALSE(cmdQHw->isQueueBlocked());
// +1 for next level after virtualEvent is unblocked // +1 for next level after virtualEvent is unblocked
// +1 for dependence on eventWaitlist // +1 as virtualEvent was a parent for event with actual command that is being submitted
EXPECT_EQ(virtualEventTaskLevel + 2, cmdQHw->taskLevel); EXPECT_EQ(virtualEventTaskLevel + 2, cmdQHw->taskLevel);
EXPECT_EQ(virtualEventTaskLevel + 2, mockCSR->lastTaskLevelToFlushTask); //command being submitted was dependant only on virtual event hence only +1
EXPECT_EQ(virtualEventTaskLevel + 1, mockCSR->lastTaskLevelToFlushTask);
} }
HWTEST_F(OOQueueHwTest, givenBlockedOutOfOrderCmdQueueAndAsynchronouslyCompletedEventWhenEnqueueCompletesVirtualEventThenUpdatedTaskLevelIsPassedToEnqueueAndFlushTask) { HWTEST_F(OOQueueHwTest, givenBlockedOutOfOrderCmdQueueAndAsynchronouslyCompletedEventWhenEnqueueCompletesVirtualEventThenUpdatedTaskLevelIsPassedToEnqueueAndFlushTask) {
@ -769,7 +776,6 @@ HWTEST_F(OOQueueHwTest, givenBlockedOutOfOrderCmdQueueAndAsynchronouslyCompleted
}; };
Event event(cmdQHw, CL_COMMAND_NDRANGE_KERNEL, 10, 0); Event event(cmdQHw, CL_COMMAND_NDRANGE_KERNEL, 10, 0);
event.setStatus(CL_SUBMITTED);
uint32_t virtualEventTaskLevel = 77; uint32_t virtualEventTaskLevel = 77;
uint32_t virtualEventTaskCount = 80; uint32_t virtualEventTaskCount = 80;
@ -780,12 +786,22 @@ HWTEST_F(OOQueueHwTest, givenBlockedOutOfOrderCmdQueueAndAsynchronouslyCompleted
// Put Queue in blocked state by assigning virtualEvent // Put Queue in blocked state by assigning virtualEvent
virtualEvent.incRefInternal(); virtualEvent.incRefInternal();
event.addChild(virtualEvent);
cmdQHw->virtualEvent = &virtualEvent; cmdQHw->virtualEvent = &virtualEvent;
cmdQHw->incRefInternal(); cmdQHw->incRefInternal();
cmdQHw->taskLevel = 23; cmdQHw->taskLevel = 23;
cmdQHw->enqueueKernel(mockKernel, 1, &offset, &size, &size, 1, &blockedEvent, nullptr); cmdQHw->enqueueKernel(mockKernel, 1, &offset, &size, &size, 1, &blockedEvent, nullptr);
//new virtual event is created on enqueue, bind it to the created virtual event
EXPECT_NE(cmdQHw->virtualEvent, &virtualEvent);
EXPECT_EQ(virtualEventTaskLevel, cmdQHw->taskLevel); event.setStatus(CL_SUBMITTED);
EXPECT_EQ(virtualEventTaskLevel, mockCSR->lastTaskLevelToFlushTask);
virtualEvent.Event::updateExecutionStatus();
EXPECT_FALSE(cmdQHw->isQueueBlocked());
//+1 due to dependency between virtual event & new virtual event
//new virtual event is actually responsible for command delivery
EXPECT_EQ(virtualEventTaskLevel + 1, cmdQHw->taskLevel);
EXPECT_EQ(virtualEventTaskLevel + 1, mockCSR->lastTaskLevelToFlushTask);
} }

View File

@ -373,6 +373,22 @@ TEST_F(EventTests, twoUserEventInjectsCountOnNDR1whichIsPropagatedToNDR2viaVirtu
EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(CL_SUCCESS, retVal);
} }
TEST_F(EventTests, givenQueueThatIsBlockedByUserEventWhenIsQueueBlockedIsCalledThenVirtualEventOnlyQueriesForExecutionStatus) {
struct mockEvent : public Event {
using Event::Event;
void updateExecutionStatus() override {
updateExecutionStatusCalled = true;
}
bool updateExecutionStatusCalled = false;
};
mockEvent mockedVirtualEvent(pCmdQ, CL_COMMAND_NDRANGE_KERNEL, Event::eventNotReady, 0);
pCmdQ->virtualEvent = &mockedVirtualEvent;
EXPECT_TRUE(pCmdQ->isQueueBlocked());
EXPECT_FALSE(mockedVirtualEvent.updateExecutionStatusCalled);
pCmdQ->virtualEvent = nullptr;
}
TEST_F(EventTests, finishDoesntBlockAfterUserEventSignaling) { TEST_F(EventTests, finishDoesntBlockAfterUserEventSignaling) {
UserEvent uEvent(context); UserEvent uEvent(context);
UserEvent uEvent2(context); UserEvent uEvent2(context);