Add deferred list to TagAllocator for nodes that are not completed

Change-Id: I0672c487315a96540184eda793132c79c7777527
Signed-off-by: Dunajski, Bartosz <bartosz.dunajski@intel.com>
This commit is contained in:
Dunajski, Bartosz
2018-09-04 09:05:55 +02:00
committed by sys_ocldev
parent 096fa0e64f
commit e3df4edb90
7 changed files with 92 additions and 18 deletions

View File

@ -35,6 +35,7 @@ struct HwTimeStamps {
GlobalCompleteTS = 0;
ContextCompleteTS = 0;
}
bool canBeReleased() const { return true; }
uint64_t GlobalStartTS;
uint64_t ContextStartTS;
uint64_t GlobalEndTS;

View File

@ -32,6 +32,7 @@ struct HwPerfCounter {
HWPerfCounters = {};
HWTimeStamp.initialize();
}
bool canBeReleased() const { return true; }
HwPerfCounters HWPerfCounters;
HwTimeStamps HWTimeStamp;
};

View File

@ -41,6 +41,11 @@ class TimestampPacket {
End
};
bool canBeReleased() const {
return data[static_cast<uint32_t>(DataIndex::ContextEnd)] != 1 &&
data[static_cast<uint32_t>(DataIndex::GlobalEnd)] != 1;
}
const uint32_t *pickDataPtr() const { return &(data[0]); }
uint64_t pickAddressForPipeControlWrite(WriteOperationType operationType) const {

View File

@ -86,6 +86,7 @@ class TagAllocator {
NodeType *getTag() {
NodeType *node = freeTags.removeFrontOne().release();
if (!node) {
std::unique_lock<std::mutex> lock(allocatorMutex);
populateFreeTags();
node = freeTags.removeFrontOne().release();
}
@ -97,13 +98,18 @@ class TagAllocator {
MOCKABLE_VIRTUAL void returnTag(NodeType *node) {
if (node->refCount.fetch_sub(1) == 1) {
return returnTagToPool(node);
if (node->tag->canBeReleased()) {
returnTagToFreePool(node);
} else {
returnTagToDeferredPool(node);
}
}
}
protected:
IDList<NodeType> freeTags;
IDList<NodeType> usedTags;
IDList<NodeType> deferredTags;
std::vector<GraphicsAllocation *> gfxAllocations;
std::vector<NodeType *> tagPoolMemory;
@ -111,23 +117,26 @@ class TagAllocator {
size_t tagCount;
size_t tagAlignment;
std::mutex allocationsMutex;
std::mutex allocatorMutex;
MOCKABLE_VIRTUAL void returnTagToPool(NodeType *node) {
MOCKABLE_VIRTUAL void returnTagToFreePool(NodeType *node) {
NodeType *usedNode = usedTags.removeOne(*node).release();
DEBUG_BREAK_IF(usedNode == nullptr);
((void)(usedNode));
freeTags.pushFrontOne(*node);
}
void populateFreeTags() {
void returnTagToDeferredPool(NodeType *node) {
NodeType *usedNode = usedTags.removeOne(*node).release();
DEBUG_BREAK_IF(!usedNode);
deferredTags.pushFrontOne(*usedNode);
}
void populateFreeTags() {
size_t tagSize = sizeof(TagType);
tagSize = alignUp(tagSize, tagAlignment);
size_t allocationSizeRequired = tagCount * tagSize;
std::unique_lock<std::mutex> lock(allocationsMutex);
GraphicsAllocation *graphicsAllocation = memoryManager->allocateGraphicsMemory(allocationSizeRequired);
gfxAllocations.push_back(graphicsAllocation);

View File

@ -1036,6 +1036,8 @@ TEST_F(EventTest, getHwTimeStampsReturnsValidPointer) {
ASSERT_EQ(0ULL, timeStamps->GlobalCompleteTS);
ASSERT_EQ(0ULL, timeStamps->ContextCompleteTS);
EXPECT_TRUE(timeStamps->canBeReleased());
HwTimeStamps *timeStamps2 = event->getHwTimeStamp();
ASSERT_EQ(timeStamps, timeStamps2);
}
@ -1090,6 +1092,8 @@ TEST_F(EventTest, getHwPerfCounterReturnsValidPointer) {
ASSERT_EQ(0ULL, perfCounter->HWTimeStamp.GlobalCompleteTS);
ASSERT_EQ(0ULL, perfCounter->HWTimeStamp.ContextCompleteTS);
EXPECT_TRUE(perfCounter->canBeReleased());
HwPerfCounter *perfCounter2 = event->getHwPerfCounter();
ASSERT_EQ(perfCounter, perfCounter2);
}

View File

@ -57,16 +57,38 @@ struct TimestampPacketTests : public ::testing::Test {
BaseClass::returnTag(node);
}
void returnTagToPool(NodeType *node) override {
returnToPoolTagNodes.push_back(node);
BaseClass::returnTagToPool(node);
void returnTagToFreePool(NodeType *node) override {
returnedToFreePoolNodes.push_back(node);
BaseClass::returnTagToFreePool(node);
}
std::vector<NodeType *> releaseReferenceNodes;
std::vector<NodeType *> returnToPoolTagNodes;
std::vector<NodeType *> returnedToFreePoolNodes;
};
};
TEST_F(TimestampPacketTests, whenEndTagIsNotOneThenCanBeReleased) {
MockTimestampPacket timestampPacket;
auto contextEndIndex = static_cast<uint32_t>(TimestampPacket::DataIndex::ContextEnd);
auto globalEndIndex = static_cast<uint32_t>(TimestampPacket::DataIndex::GlobalEnd);
timestampPacket.data[contextEndIndex] = 1;
timestampPacket.data[globalEndIndex] = 1;
EXPECT_FALSE(timestampPacket.canBeReleased());
timestampPacket.data[contextEndIndex] = 1;
timestampPacket.data[globalEndIndex] = 0;
EXPECT_FALSE(timestampPacket.canBeReleased());
timestampPacket.data[contextEndIndex] = 0;
timestampPacket.data[globalEndIndex] = 1;
EXPECT_FALSE(timestampPacket.canBeReleased());
timestampPacket.data[contextEndIndex] = 0;
timestampPacket.data[globalEndIndex] = 0;
EXPECT_TRUE(timestampPacket.canBeReleased());
}
TEST_F(TimestampPacketTests, whenNewTagIsTakenThenReinitialize) {
MockMemoryManager memoryManager;
MockTagAllocator<MockTimestampPacket> allocator(&memoryManager, 1);
@ -227,26 +249,30 @@ HWTEST_F(TimestampPacketTests, givenDebugVariableEnabledWhenEnqueueingThenObtain
auto node2 = cmdQ->timestampPacketNode;
EXPECT_NE(nullptr, node2);
EXPECT_EQ(node2, cmdQ->timestampPacketNode);
EXPECT_EQ(0u, mockTagAllocator->returnToPoolTagNodes.size()); // nothing returned. event1 owns previous node
EXPECT_EQ(1u, mockTagAllocator->releaseReferenceNodes.size()); // cmdQ released first node
EXPECT_EQ(0u, mockTagAllocator->returnedToFreePoolNodes.size()); // nothing returned. event1 owns previous node
EXPECT_EQ(1u, mockTagAllocator->releaseReferenceNodes.size()); // cmdQ released first node
EXPECT_EQ(node1, mockTagAllocator->releaseReferenceNodes.at(0));
EXPECT_NE(node1, node2);
size_t dataSize = sizeof(uint32_t) * static_cast<size_t>(TimestampPacket::DataIndex::Max);
// mark nodes as ready
memset(const_cast<uint32_t *>(node1->tag->pickDataPtr()), 0, dataSize);
memset(const_cast<uint32_t *>(node2->tag->pickDataPtr()), 0, dataSize);
clReleaseEvent(event2);
EXPECT_EQ(0u, mockTagAllocator->returnToPoolTagNodes.size()); // nothing returned. cmdQ owns node2
EXPECT_EQ(2u, mockTagAllocator->releaseReferenceNodes.size()); // event2 released node2
EXPECT_EQ(0u, mockTagAllocator->returnedToFreePoolNodes.size()); // nothing returned. cmdQ owns node2
EXPECT_EQ(2u, mockTagAllocator->releaseReferenceNodes.size()); // event2 released node2
EXPECT_EQ(node2, mockTagAllocator->releaseReferenceNodes.at(1));
clReleaseEvent(event1);
EXPECT_EQ(1u, mockTagAllocator->returnToPoolTagNodes.size()); // removed last reference on node1
EXPECT_EQ(node1, mockTagAllocator->returnToPoolTagNodes.at(0));
EXPECT_EQ(1u, mockTagAllocator->returnedToFreePoolNodes.size()); // removed last reference on node1
EXPECT_EQ(node1, mockTagAllocator->returnedToFreePoolNodes.at(0));
EXPECT_EQ(3u, mockTagAllocator->releaseReferenceNodes.size()); // event1 released node1
EXPECT_EQ(node1, mockTagAllocator->releaseReferenceNodes.at(2));
cmdQ.reset(nullptr);
EXPECT_EQ(2u, mockTagAllocator->returnToPoolTagNodes.size()); // removed last reference on node2
EXPECT_EQ(node2, mockTagAllocator->returnToPoolTagNodes.at(1));
EXPECT_EQ(2u, mockTagAllocator->returnedToFreePoolNodes.size()); // removed last reference on node2
EXPECT_EQ(node2, mockTagAllocator->returnedToFreePoolNodes.at(1));
EXPECT_EQ(4u, mockTagAllocator->releaseReferenceNodes.size()); // cmdQ released node2
EXPECT_EQ(node2, mockTagAllocator->releaseReferenceNodes.at(3));
}

View File

@ -35,13 +35,19 @@ struct timeStamps {
void initialize() {
start = 1;
end = 2;
release = true;
}
bool canBeReleased() const { return release; }
bool release;
uint64_t start;
uint64_t end;
};
class MockTagAllocator : public TagAllocator<timeStamps> {
public:
using TagAllocator<timeStamps>::populateFreeTags;
using TagAllocator<timeStamps>::deferredTags;
MockTagAllocator(MemoryManager *memMngr, size_t tagCount, size_t tagAlignment) : TagAllocator<timeStamps>(memMngr, tagCount, tagAlignment) {
}
@ -283,3 +289,25 @@ TEST_F(TagAllocatorTest, givenMultipleReferencesOnTagWhenReleasingThenReturnWhen
tagAllocator.returnTag(tag);
EXPECT_EQ(nullptr, tagAllocator.getUsedTagsHead());
}
TEST_F(TagAllocatorTest, givenNotReadyTagWhenReturnedThenMoveToDeferredList) {
MockTagAllocator tagAllocator(memoryManager, 1, 1);
auto node = tagAllocator.getTag();
node->tag->release = false;
EXPECT_TRUE(tagAllocator.deferredTags.peekIsEmpty());
tagAllocator.returnTag(node);
EXPECT_FALSE(tagAllocator.deferredTags.peekIsEmpty());
EXPECT_TRUE(tagAllocator.getFreeTags().peekIsEmpty());
}
TEST_F(TagAllocatorTest, givenReadyTagWhenReturnedThenMoveToFreeList) {
MockTagAllocator tagAllocator(memoryManager, 1, 1);
auto node = tagAllocator.getTag();
node->tag->release = true;
EXPECT_TRUE(tagAllocator.deferredTags.peekIsEmpty());
tagAllocator.returnTag(node);
EXPECT_TRUE(tagAllocator.deferredTags.peekIsEmpty());
EXPECT_FALSE(tagAllocator.getFreeTags().peekIsEmpty());
}