[VPU][GT] Refine edges methods (#550)

* [VPU][GT] Extract order manipulation into separate methods

* [VPU][GT] Rename data -> dependency

* [VPU][GT] Extend unit tests

* [VPU][GT] Introduce replacement and removal methods for StageDependency

* [VPU][GT] Update DataToShape connection methods
This commit is contained in:
Andrew Bakalin 2020-05-27 11:14:02 +03:00 committed by GitHub
parent 5c2eb05990
commit d337b4ed97
6 changed files with 723 additions and 97 deletions

View File

@ -45,7 +45,7 @@ private:
class StageDependencyEdge final :
public EnableHandle,
public EnableCustomAttributes {
VPU_MODEL_ATTRIBUTE(Data, data, nullptr)
VPU_MODEL_ATTRIBUTE(Data, dependency, nullptr)
VPU_MODEL_ATTRIBUTE(Stage, dependentStage, nullptr)
private:

View File

@ -157,6 +157,16 @@ public:
const StageOutput& edge,
const Data& newOutput);
void replaceStageDependency(
const StageDependency& edge,
const Data& newDependency);
void replaceDependentStage(
const StageDependency& edge,
const Stage& newDependentStage);
void removeStageDependency(const StageDependency& edge);
//
// Stage <-> Stage edges
//
@ -288,6 +298,10 @@ public:
void reorderStages(const StageComparator& comparator = {});
void setStagesOrder(const Stage& parent, const Stage& child);
void removeStagesOrder(const Stage& parent, const Stage& child);
//
// Nodes accessors
//

View File

@ -316,8 +316,7 @@ StageInput ModelObj::addStageInput(
if (data->_producerEdge != nullptr) {
IE_ASSERT(stage->_parentStageEdge == nullptr);
IE_ASSERT(data->_producerEdge->_producer->_parentStageEdge == nullptr);
++data->_producerEdge->_producer->_nextStages[stage];
++stage->_prevStages[data->_producerEdge->_producer];
setStagesOrder(data->producerEdge()->producer(), stage);
}
if (stage->_prevStages.empty()) {
@ -381,8 +380,7 @@ StageOutput ModelObj::addStageOutput(
for (const auto& consumerEdge : data->_consumerEdges) {
IE_ASSERT(stage->_parentStageEdge == nullptr);
IE_ASSERT(consumerEdge->_consumer->_parentStageEdge == nullptr);
++consumerEdge->_consumer->_prevStages[stage];
++stage->_nextStages[consumerEdge->_consumer];
setStagesOrder(stage, consumerEdge->consumer());
_initialStages.erase(consumerEdge->_consumer);
}
@ -391,22 +389,33 @@ StageOutput ModelObj::addStageOutput(
}
StageDependency ModelObj::addStageDependency(const Stage& stage, const Data& data) {
for (const auto& dependentStageEdge : data->dependentStagesEdges()) {
VPU_THROW_UNLESS(dependentStageEdge->dependentStage() != stage,
"Adding stage dependency for {} with type {} failed: data {} with usage {} is already its dependency",
stage->name(), stage->type(), data->name(), data->usage());
}
for (const auto& input : stage->inputs()) {
VPU_THROW_UNLESS(data != input,
"Adding stage dependency for {} with type {} failed: data {} with usage {} is already its input",
stage->name(), stage->type(), data->name(), data->usage());
}
VPU_THROW_UNLESS(data->producer() != nullptr,
"Adding stage dependency for {} with type {} failed: data {} with usage {} should have producer, "
"but actually it doesn't", stage->name(), stage->type(), data->name(), data->usage());
_resetStageOrder = true;
std::shared_ptr<StageDependencyEdge> edge(new StageDependencyEdge);
edge->_ptrPosInModel = _stageDependencyEdgePtrList.emplace(_stageDependencyEdgePtrList.end(), edge);
edge->_data = data;
edge->_dependency = data;
edge->_dependentStage = stage;
data->_dependentStagesEdges.push_back(edge);
VPU_THROW_UNLESS(data->_producerEdge != nullptr,
"Adding stage dependency for {} with type {} failed: data {} with usage {} should have producer, "
"but actually it doesn't", stage->name(), stage->type(), data->name(), data->usage());
++data->_producerEdge->_producer->_nextStages[stage];
++stage->_prevStages[data->_producerEdge->_producer];
setStagesOrder(data->producerEdge()->producer(), stage);
return edge;
}
@ -501,19 +510,7 @@ void ModelObj::replaceStageInput(
//
if (edge->_input->_producerEdge != nullptr) {
auto it1 = edge->_input->_producerEdge->_producer->_nextStages.find(edge->_consumer);
IE_ASSERT(it1 != edge->_input->_producerEdge->_producer->_nextStages.end());
--it1->second;
if (it1->second <= 0) {
edge->_input->_producerEdge->_producer->_nextStages.erase(it1);
}
auto it2 = edge->_consumer->_prevStages.find(edge->_input->_producerEdge->_producer);
IE_ASSERT(it2 != edge->_consumer->_prevStages.end());
--it2->second;
if (it2->second <= 0) {
edge->_consumer->_prevStages.erase(it2);
}
removeStagesOrder(edge->input()->producer(), edge->consumer());
}
//
@ -530,8 +527,7 @@ void ModelObj::replaceStageInput(
if (newInput->_producerEdge != nullptr) {
IE_ASSERT(edge->_consumer->_parentStageEdge == nullptr);
IE_ASSERT(newInput->_producerEdge->_producer->_parentStageEdge == nullptr);
++newInput->_producerEdge->_producer->_nextStages[edge->_consumer];
++edge->_consumer->_prevStages[newInput->_producerEdge->_producer];
setStagesOrder(newInput->producerEdge()->producer(), edge->consumer());
_initialStages.erase(edge->_consumer);
}
@ -608,19 +604,7 @@ void ModelObj::replaceStageOutput(
//
for (const auto& consumerEdge : edge->_output->_consumerEdges) {
auto it1 = consumerEdge->_consumer->_prevStages.find(edge->_producer);
IE_ASSERT(it1 != consumerEdge->_consumer->_prevStages.end());
--it1->second;
if (it1->second <= 0) {
consumerEdge->_consumer->_prevStages.erase(it1);
}
auto it2 = edge->_producer->_nextStages.find(consumerEdge->_consumer);
IE_ASSERT(it2 != edge->_producer->_nextStages.end());
--it2->second;
if (it2->second <= 0) {
edge->_producer->_nextStages.erase(it2);
}
removeStagesOrder(edge->producer(), consumerEdge->consumer());
if (consumerEdge->_consumer->_prevStages.empty()) {
_initialStages.emplace(consumerEdge->_consumer);
@ -643,13 +627,109 @@ void ModelObj::replaceStageOutput(
for (const auto& consumerEdge : newOutput->_consumerEdges) {
IE_ASSERT(edge->_producer->_parentStageEdge == nullptr);
IE_ASSERT(consumerEdge->_consumer->_parentStageEdge == nullptr);
++consumerEdge->_consumer->_prevStages[edge->_producer];
++edge->_producer->_nextStages[consumerEdge->_consumer];
setStagesOrder(edge->producer(), consumerEdge->consumer());
_initialStages.erase(consumerEdge->_consumer);
}
}
void ModelObj::replaceStageDependency(
const StageDependency& edge,
const Data& newDependency) {
const auto previousDependency = edge->dependency();
const auto dependentStage = edge->dependentStage();
for (const auto& dependentStageEdge : newDependency->dependentStagesEdges()) {
VPU_THROW_UNLESS(dependentStageEdge->dependentStage() != dependentStage,
"replaceStageDependency failed for dependency {} with usage {} and dependentStage {} with type {}: "
"new dependency {} with usage {} is already dependency for dependent stage", previousDependency->name(), previousDependency->usage(),
dependentStage->name(), dependentStage->type(), newDependency->name(), newDependency->usage());
}
for (const auto& input : dependentStage->inputs()) {
VPU_THROW_UNLESS(newDependency != input,
"replaceStageDependency failed for dependency {} with usage {} and dependentStage {} with type {}: "
"new dependency {} with usage {} is already input for dependent stage", previousDependency->name(), previousDependency->usage(),
dependentStage->name(), dependentStage->type(), newDependency->name(), newDependency->usage());
}
VPU_THROW_UNLESS(newDependency->producer() != nullptr,
"replaceStageDependency failed for dependency {} with usage {} and dependentStage {} with type {}: "
"newDependency {} with usage {} has no producer", previousDependency->name(), previousDependency->usage(),
dependentStage->name(), dependentStage->type(), newDependency->name(), newDependency->usage());
VPU_THROW_UNLESS(previousDependency->producer() != nullptr,
"replaceStageDependency failed for dependency {} with usage {} and dependentStage {} with type {}: "
"previous dependency has no producer",
previousDependency->name(), previousDependency->usage(), dependentStage->name(), dependentStage->type());
_resetStageOrder = true;
previousDependency->_dependentStagesEdges.erase(edge);
removeStagesOrder(previousDependency->producer(), dependentStage);
edge->_dependency = newDependency;
newDependency->_dependentStagesEdges.push_back(edge);
setStagesOrder(newDependency->producerEdge()->producer(), dependentStage);
}
void ModelObj::replaceDependentStage(
const StageDependency& edge,
const Stage& newDependentStage) {
const auto dependency = edge->dependency();
const auto previousDependentStage = edge->dependentStage();
for (const auto& dependentStageEdge : dependency->dependentStagesEdges()) {
VPU_THROW_UNLESS(dependentStageEdge->dependentStage() != newDependentStage,
"replaceDependentStage failed for dependency {} with usage {} and dependentStage {} with type {}: "
"new dependent stage {} with type {} is already dependent stage for dependency", dependency->name(), dependency->usage(),
previousDependentStage->name(), previousDependentStage->type(), newDependentStage->name(), newDependentStage->type());
}
for (const auto& input : newDependentStage->inputs()) {
VPU_THROW_UNLESS(dependency != input,
"replaceDependentStage failed for dependency {} with usage {} and dependentStage {} with type {}: "
"new dependent stage {} with type {} already has dependency as its input", dependency->name(), dependency->usage(),
previousDependentStage->name(), previousDependentStage->type(), newDependentStage->name(), newDependentStage->type());
}
VPU_THROW_UNLESS(dependency->producer() != nullptr,
"replaceDependentStage failed for dependency {} with usage {} and dependentStage {} with type {}: "
"dependency has no producer",
dependency->name(), dependency->usage(), previousDependentStage->name(), previousDependentStage->type());
_resetStageOrder = true;
removeStagesOrder(dependency->producer(), previousDependentStage);
edge->_dependentStage = newDependentStage;
setStagesOrder(dependency->producer(), newDependentStage);
}
void ModelObj::removeStageDependency(const StageDependency& edge) {
const auto dependency = edge->dependency();
const auto dependentStage = edge->dependentStage();
VPU_THROW_UNLESS(dependency->producer(),
"removeStageDependency failed for dependency {} with usage {} and dependentStage {} with type {}: dependency has no producer",
dependency->name(), dependency->usage(), dependentStage->name(), dependentStage->type());
_resetStageOrder = true;
dependency->_dependentStagesEdges.erase(edge);
removeStagesOrder(dependency->producer(), dependentStage);
VPU_THROW_UNLESS(edge->_ptrPosInModel != _stageDependencyEdgePtrList.end(),
"removeStageDependency failed for dependency {} with usage {} and dependentStage {} with type {}: no such edge in Model's DataToShapeEdges list",
dependency->name(), dependency->usage(), dependentStage->name(), dependentStage->type());
_stageDependencyEdgePtrList.erase(edge->_ptrPosInModel);
}
ModelObj::InjectStageHelper::~InjectStageHelper() {
//
// Check that `done` was called.
@ -1511,6 +1591,39 @@ DataToDataAllocation ModelObj::connectDataWithDataImpl(
return edge;
}
namespace {
bool isStageDependencyNeeded(
const Stage& dependentStage,
const Data& dependency) {
const auto& dependencyProducer = dependency->producer();
if (dependencyProducer == nullptr) {
return false;
}
if (dependentStage == dependencyProducer) {
return false;
}
// Check one level above, it covers current cases while checking all the levels might be computationally expensive
for (const auto& prevStage : dependencyProducer->prevStages()) {
if (prevStage == dependentStage) {
return false;
}
}
for (const auto& prevStage : dependentStage->prevStages()) {
if (prevStage == dependencyProducer) {
return false;
}
}
return true;
}
} // namespace
DataToShapeAllocation ModelObj::connectDataWithShape(
const Data& parent,
const Data& child) {
@ -1528,16 +1641,11 @@ DataToShapeAllocation ModelObj::connectDataWithShape(
parent->_childDataToShapeEdges.push_back(edge);
child->_parentDataToShapeEdge = edge;
const auto& parentStage = parent->producer();
const auto& childStage = child->producer();
const auto& childProducer = child->producer();
const auto& areStagesDifferent = [](const Stage& lhs, const Stage& rhs) {
return lhs && rhs && lhs != rhs;
};
if (areStagesDifferent(parentStage, childStage)) {
if (childProducer && isStageDependencyNeeded(childProducer, parent)) {
// Shape and data are produced from different stages, make sure that shape is calculated before data
addStageDependency(childStage, parent);
addStageDependency(childProducer, parent);
}
return edge;
@ -1546,18 +1654,41 @@ DataToShapeAllocation ModelObj::connectDataWithShape(
void ModelObj::replaceDataToShapeParent(
const DataToShapeAllocation& edge,
const Data& newParent) {
auto oldParent = edge->parent();
auto child = edge->child();
const auto oldParent = edge->parent();
const auto child = edge->child();
oldParent->_childDataToShapeEdges.erase(edge);
edge->_parent = newParent;
newParent->_childDataToShapeEdges.push_back(edge);
const auto& childProducer = child->producer();
if (childProducer != nullptr) {
const auto& dependentStagesEdges = oldParent->dependentStagesEdges();
const auto it = std::find_if(dependentStagesEdges.begin(), dependentStagesEdges.end(), [&childProducer](const StageDependency& edge) {
return edge->dependentStage() == childProducer;
});
if (it != dependentStagesEdges.end()) {
const auto edge = *it;
removeStageDependency(edge);
}
if (isStageDependencyNeeded(childProducer, newParent)) {
// Shape and data are produced from different stages, make sure that shape is calculated before data
addStageDependency(childProducer, newParent);
}
}
}
void ModelObj::replaceDataToShapeChild(
const DataToShapeAllocation& edge,
const Data& newChild) {
edge->_child->_parentDataToShapeEdge = nullptr;
const auto parent = edge->parent();
const auto oldChild = edge->child();
oldChild->_parentDataToShapeEdge = nullptr;
edge->_child = newChild;
VPU_THROW_UNLESS(newChild->_parentDataToShapeEdge == nullptr,
@ -1565,6 +1696,28 @@ void ModelObj::replaceDataToShapeChild(
newChild->name(), newChild->usage(), newChild->_parentDataToShapeEdge->parent()->name(), newChild->_parentDataToShapeEdge->parent()->usage());
newChild->_parentDataToShapeEdge = edge;
const auto& oldChildProducer = oldChild->producer();
if (oldChildProducer != nullptr) {
const auto &dependentStagesEdges = parent->dependentStagesEdges();
const auto it = std::find_if(dependentStagesEdges.begin(), dependentStagesEdges.end(), [&oldChildProducer](const StageDependency &edge) {
return edge->dependentStage() == oldChildProducer;
});
if (it != dependentStagesEdges.end()) {
const auto edge = *it;
removeStageDependency(edge);
}
}
const auto& newChildProducer = newChild->producer();
if (newChildProducer && isStageDependencyNeeded(newChildProducer, parent)) {
// Shape and data are produced from different stages, make sure that shape is calculated before data
addStageDependency(newChildProducer, parent);
}
}
void ModelObj::replaceDataToDataParent(
@ -1638,8 +1791,26 @@ void ModelObj::disconnectDatas(const DataToShapeAllocation& edge) {
child->_parentDataToShapeEdge = nullptr;
parent->_childDataToShapeEdges.erase(edge);
IE_ASSERT(edge->_ptrPosInModel != _shapeEdgePtrList.end());
VPU_THROW_UNLESS(edge->_ptrPosInModel != _shapeEdgePtrList.end(),
"disconnect Datas (parent {} with usage {} and child {} with usage {}) with DataToShape connection failed: "
"no such edge in Model's DataToShapeEdges list", parent->name(), parent->usage(), child->name(), child->usage());
_shapeEdgePtrList.erase(edge->_ptrPosInModel);
const auto& childProducer = child->producer();
if (childProducer != nullptr) {
const auto &dependentStagesEdges = parent->dependentStagesEdges();
const auto it = std::find_if(dependentStagesEdges.begin(), dependentStagesEdges.end(), [&childProducer](const StageDependency &edge) {
return edge->dependentStage() == childProducer;
});
if (it != dependentStagesEdges.end()) {
const auto edge = *it;
removeStageDependency(edge);
}
}
}
void ModelObj::disconnectStage(const Stage& stage) {
@ -1824,6 +1995,31 @@ void ModelObj::reorderStages(
_resetStageOrder = true;
}
void ModelObj::setStagesOrder(const Stage& parent, const Stage& child) {
++parent->_nextStages[child];
++child->_prevStages[parent];
}
void ModelObj::removeStagesOrder(const Stage& parent, const Stage& child) {
auto parentNextStage = parent->_nextStages.find(child);
VPU_THROW_UNLESS(parentNextStage != parent->_nextStages.end(),
"removeStagesOrder failed: parent {} with type {} doesn't have {} with type {} as its next stage",
parent->name(), parent->type(), child->name(), child->type());
--parentNextStage->second;
if (parentNextStage->second <= 0) {
parent->_nextStages.erase(parentNextStage);
}
auto childPrevStage = child->_prevStages.find(parent);
VPU_THROW_UNLESS(childPrevStage != child->_prevStages.end(),
"removeStagesOrder failed: child {} with type {} doesn't have {} with type {} as its previous stage",
child->name(), child->type(), parent->name(), parent->type());
--childPrevStage->second;
if (childPrevStage->second <= 0) {
child->_prevStages.erase(childPrevStage);
}
}
void ModelObj::runDFS(
const Stage& stage,
StageMap<bool>& visitedMap) const {

View File

@ -33,7 +33,6 @@ void FrontEnd::parseDSR(const Model& model, const ie::CNNLayerPtr& layer, const
VPU_THROW_UNLESS(shapeProducerEdge != nullptr, "Parsing layer {} of type {} failed: input with index {} (of name {}) must have a producer",
layer->name, layer->type, 1, shape->name());
model->replaceStageOutput(dataProducerEdge, dataOutput);
if (auto dataToShapeEdge = data->parentDataToShapeEdge()) {
const auto& parent = dataToShapeEdge->parent();
VPU_THROW_UNLESS(parent == shape, "Myriad plugin encountered layer of type \"{}\" and name \"{}\" with input #{} (data input with name \"{}\") that "
@ -44,6 +43,7 @@ void FrontEnd::parseDSR(const Model& model, const ie::CNNLayerPtr& layer, const
layer->type, layer->name, 0, data->name(), 1, shape->name(), layer->type, parent->name(), layer->type, layer->type);
model->disconnectDatas(dataToShapeEdge);
}
model->replaceStageOutput(dataProducerEdge, dataOutput);
model->removeUnusedData(data);
if (dataOutput->usage() == DataUsage::Output) {

View File

@ -114,15 +114,14 @@ TEST_F(DataToShapeEdgeProcessingTests, DataToShapeEdgeSharesMemory) {
ASSERT_NO_THROW(_middleEnd->run(model));
Stage shapeProducer = nullptr;
for (const auto& stage : model->getStages()) {
// Find shape produced stage
if (stage->numOutputs() == 2) {
shapeProducer = stage;
}
}
// Find shape producer
auto it = std::find_if(model->getStages().begin(), model->getStages().end(), [](const Stage& stage) {
return stage->numOutputs() == 2;
});
ASSERT_NE(shapeProducer, nullptr);
ASSERT_NE(it, model->getStages().end());
auto shapeProducer = *it;
const auto& data = shapeProducer->output(0);
const auto& shape = shapeProducer->output(1);
@ -147,15 +146,14 @@ TEST_F(DataToShapeEdgeProcessingTests, ShapeProcessingOnceSharesMemory) {
ASSERT_NO_THROW(_middleEnd->run(model));
Stage shapeProducer = nullptr;
for (const auto& stage : model->getStages()) {
// Find shape produced stage
if (stage->numOutputs() == 2) {
shapeProducer = stage;
}
}
// Find shape producer
auto it = std::find_if(model->getStages().begin(), model->getStages().end(), [](const Stage& stage) {
return stage->numOutputs() == 2;
});
ASSERT_NE(shapeProducer, nullptr);
ASSERT_NE(it, model->getStages().end());
auto shapeProducer = *it;
const auto& data = shapeProducer->output(0);
const auto& shape = shapeProducer->output(1);
@ -183,15 +181,14 @@ TEST_F(DataToShapeEdgeProcessingTests, ShapeProcessingOnceHasCorrectExecutionOrd
ASSERT_NO_THROW(_middleEnd->run(model));
Stage shapeProducer = nullptr;
for (const auto& stage : model->getStages()) {
// Find shape produced stage
if (stage->numOutputs() == 2) {
shapeProducer = stage;
}
}
// Find shape producer
auto it = std::find_if(model->getStages().begin(), model->getStages().end(), [](const Stage& stage) {
return stage->numOutputs() == 2;
});
ASSERT_NE(shapeProducer, nullptr);
ASSERT_NE(it, model->getStages().end());
auto shapeProducer = *it;
const auto dataProcessor = shapeProducer->output(0)->singleConsumer();
const auto shapeProcessor = shapeProducer->output(1)->singleConsumer();
@ -212,15 +209,14 @@ TEST_F(DataToShapeEdgeProcessingTests, ShapeProcessingTwiceSharesMemory) {
ASSERT_NO_THROW(_middleEnd->run(model));
Stage shapeProducer = nullptr;
for (const auto& stage : model->getStages()) {
// Find shape produced stage
if (stage->numOutputs() == 2) {
shapeProducer = stage;
}
}
// Find shape producer
auto it = std::find_if(model->getStages().begin(), model->getStages().end(), [](const Stage& stage) {
return stage->numOutputs() == 2;
});
ASSERT_NE(shapeProducer, nullptr);
ASSERT_NE(it, model->getStages().end());
auto shapeProducer = *it;
const auto& data = shapeProducer->output(0);
const auto& shape = shapeProducer->output(1);
@ -257,15 +253,14 @@ TEST_F(DataToShapeEdgeProcessingTests, ShapeProcessingTwiceHasCorrectExecutionOr
ASSERT_NO_THROW(_middleEnd->run(model));
Stage shapeProducer = nullptr;
for (const auto& stage : model->getStages()) {
// Find shape produced stage
if (stage->numOutputs() == 2) {
shapeProducer = stage;
}
}
// Find shape producer
auto it = std::find_if(model->getStages().begin(), model->getStages().end(), [](const Stage& stage) {
return stage->numOutputs() == 2;
});
ASSERT_NE(shapeProducer, nullptr);
ASSERT_NE(it, model->getStages().end());
auto shapeProducer = *it;
const auto dataFirstProcessor = shapeProducer->output(0)->singleConsumer();
const auto shapeFirstProcessor = shapeProducer->output(1)->singleConsumer();
@ -278,4 +273,123 @@ TEST_F(DataToShapeEdgeProcessingTests, ShapeProcessingTwiceHasCorrectExecutionOr
ASSERT_TRUE(checkExecutionOrder(model, {shapeSecondProcessor->id(), dataSecondProcessor->id()}));
}
TEST_F(DataToShapeEdgeProcessingTests, ReplaceDataToShapeParentReplacesConnections) {
//
// -> [Shape] -> (ShapeProc) -> [Shape]
// |
// [Input] -> (Stage) -> [Data] -> (DataProc) -> [Data]
// |
// -> [Shape] -> (ShapeProc) -> [Shape]
//
const auto& desc = DataDesc({1});
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc, desc});
const auto dataAndShapeParent = _testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
const auto firstShapeProcessor = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
const auto dataProcessor = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
const auto secondShapeProcessor = _testModel.addStage({InputInfo::fromPrevStage(0).output(2)}, {OutputInfo::fromNetwork(2)});
const auto& model = _testModel.getBaseModel();
const auto& processedData = dataProcessor->output(0);
const auto& initialShape = firstShapeProcessor->output(0);
const auto& finalShape = secondShapeProcessor->output(0);
ASSERT_NO_THROW(model->connectDataWithShape(initialShape, processedData));
const auto& dataToShapeEdge = processedData->parentDataToShapeEdge();
ASSERT_NE(dataToShapeEdge, nullptr);
ASSERT_NO_THROW(model->replaceDataToShapeParent(dataToShapeEdge, finalShape));
ASSERT_TRUE(initialShape->childDataToShapeEdges().empty());
ASSERT_EQ(finalShape->childDataToShapeEdges().front(), dataToShapeEdge);
ASSERT_EQ(dataToShapeEdge->parent(), finalShape);
ASSERT_TRUE(initialShape->dependentStagesEdges().empty());
ASSERT_FALSE(finalShape->dependentStagesEdges().empty());
const auto& stageDependencyEdge = finalShape->dependentStagesEdges().front();
ASSERT_EQ(stageDependencyEdge->dependentStage(), dataProcessor);
ASSERT_EQ(stageDependencyEdge->dependency(), finalShape);
}
TEST_F(DataToShapeEdgeProcessingTests, ReplaceDataToShapeChildReplacesConnections) {
//
// -> [Data] -> (DataProc) -> [Data]
// |
// [Input] -> (Stage) -> [Shape] -> (ShapeProc) -> [Shape]
// |
// -> [Data] -> (DataProc) -> [Data]
//
const auto& desc = DataDesc({1});
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc, desc});
const auto dataAndShapeParent = _testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
const auto firstDataProcessor = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
const auto shapeProcessor = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
const auto secondDataProcessor = _testModel.addStage({InputInfo::fromPrevStage(0).output(2)}, {OutputInfo::fromNetwork(2)});
const auto& model = _testModel.getBaseModel();
const auto& processedShape = shapeProcessor->output(0);
const auto& initialData = firstDataProcessor->output(0);
const auto& finalData = secondDataProcessor->output(0);
ASSERT_NO_THROW(model->connectDataWithShape(processedShape, initialData));
const auto& dataToShapeEdge = processedShape->childDataToShapeEdges().front();
ASSERT_NE(dataToShapeEdge, nullptr);
ASSERT_NO_THROW(model->replaceDataToShapeChild(dataToShapeEdge, finalData));
ASSERT_EQ(initialData->parentDataToShapeEdge(), nullptr);
ASSERT_EQ(finalData->parentDataToShapeEdge(), dataToShapeEdge);
ASSERT_EQ(dataToShapeEdge->child(), finalData);
ASSERT_FALSE(processedShape->dependentStagesEdges().empty());
const auto& stageDependencyEdge = processedShape->dependentStagesEdges().front();
ASSERT_EQ(stageDependencyEdge->dependentStage(), secondDataProcessor);
ASSERT_EQ(stageDependencyEdge->dependency(), processedShape);
}
TEST_F(DataToShapeEdgeProcessingTests, DisconnectDatasRemovesConnections) {
//
// -> [Shape] -> (ShapeProc) -> [Shape]
// [Input] -> (Stage) |
// -> [Data] -> (DataProc) -> [Data]
//
const auto& desc = DataDesc({1});
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
const auto dataAndShapeParent = _testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
const auto dataProcessor = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
const auto shapeProcessor = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
const auto& model = _testModel.getBaseModel();
const auto& processedData = dataProcessor->output(0);
const auto& processedShape = shapeProcessor->output(0);
ASSERT_NO_THROW(model->connectDataWithShape(processedShape, processedData));
const auto& dataToShapeEdge = processedShape->childDataToShapeEdges().front();
ASSERT_NE(dataToShapeEdge, nullptr);
ASSERT_NO_THROW(model->disconnectDatas(dataToShapeEdge));
ASSERT_EQ(processedData->parentDataToShapeEdge(), nullptr);
ASSERT_TRUE(processedShape->childDataToShapeEdges().empty());
ASSERT_TRUE(processedShape->dependentStagesEdges().empty());
}
} // namespace vpu

View File

@ -15,15 +15,54 @@ protected:
ASSERT_NO_FATAL_FAILURE(InitCompileEnv());
_middleEnd = passManager->buildMiddleEnd();
_testModel = CreateTestModel();
}
protected:
TestModel _testModel;
PassSet::Ptr _middleEnd = nullptr;
};
TEST_F(StageDependencyEdgeProcessingTests, AddStageDependencyAssertsOnNetworkInput) {
//
// -> [Output]
// [Input] -> (Stage)
// -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
auto stage = _testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::fromNetwork(0),
OutputInfo::fromNetwork(1)});
auto model = _testModel.getBaseModel();
ASSERT_ANY_THROW(model->addStageDependency(stage, _testModel.getInputs().front()));
}
TEST_F(StageDependencyEdgeProcessingTests, AddStageDependencyAssertsOnStageInput) {
//
// -> [Output]
// [Input] -> (Stage)
// -> [Data] -> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
_testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::fromNetwork(1)});
auto stage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto model = _testModel.getBaseModel();
ASSERT_ANY_THROW(model->addStageDependency(stage, stage->input(0)));
}
TEST_F(StageDependencyEdgeProcessingTests, AddStageDependencyDoesNotAssertOnOutputData) {
//
// -> [Data] -> (Stage) -> [Output]
@ -46,6 +85,29 @@ TEST_F(StageDependencyEdgeProcessingTests, AddStageDependencyDoesNotAssertOnOutp
ASSERT_NO_THROW(model->addStageDependency(dependentStage, dependencyProducer->output(0)));
}
TEST_F(StageDependencyEdgeProcessingTests, AddStageDependencyAssertsIfDependencyExists) {
//
// -> [Data] -> (Stage) -> [Output]
// [Input] -> (Stage) |
// -> [Data] ------------> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
_testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
auto dependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto dependencyProducer = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
auto model = _testModel.getBaseModel();
ASSERT_NO_THROW(model->addStageDependency(dependentStage, dependencyProducer->output(0)));
ASSERT_ANY_THROW(model->addStageDependency(dependentStage, dependencyProducer->output(0)));
}
TEST_F(StageDependencyEdgeProcessingTests, NetWithTwoStagesHasCorrectExecOrder) {
//
// -> [Data] -> (Stage) -> [Data] -> (Stage) -> [Output]
@ -101,4 +163,244 @@ TEST_F(StageDependencyEdgeProcessingTests, NetWithThreeStagesHasCorrectExecOrder
ASSERT_TRUE(checkExecutionOrder(model, {dependencyProducer->id(), dependentStage->id()}));
}
TEST_F(StageDependencyEdgeProcessingTests, ReplaceStageDependencyAssertsOnNetworkInput) {
//
// -> [Data] -> (Stage) -> [Output]
// [Input] -> (Stage) |
// -> [Data] ------------> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
_testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
auto dependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto dependencyProducer = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
auto model = _testModel.getBaseModel();
ASSERT_NO_THROW(model->addStageDependency(dependentStage, dependencyProducer->output(0)));
const auto edge = dependencyProducer->output(0)->dependentStagesEdges().front();
ASSERT_ANY_THROW(model->replaceStageDependency(edge, _testModel.getInputs().front()));
}
TEST_F(StageDependencyEdgeProcessingTests, ReplaceStageDependencyAssertsOnStageInput) {
//
// -> [Data] -> (Stage) -> [Output]
// [Input] -> (Stage) |
// -> [Data] ------------> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
_testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
auto dependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto dependencyProducer = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
auto model = _testModel.getBaseModel();
ASSERT_NO_THROW(model->addStageDependency(dependentStage, dependencyProducer->output(0)));
const auto edge = dependencyProducer->output(0)->dependentStagesEdges().front();
ASSERT_ANY_THROW(model->replaceStageDependency(edge, dependentStage->input(0)));
}
TEST_F(StageDependencyEdgeProcessingTests, ReplaceStageDependencyAssertsIfDependencyExists) {
//
// -> [Data] -> (Stage) -> [Output]
// [Input] -> (Stage) |
// -> [Data] ------------> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
_testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
auto dependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto dependencyProducer = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
auto model = _testModel.getBaseModel();
ASSERT_NO_THROW(model->addStageDependency(dependentStage, dependencyProducer->output(0)));
const auto edge = dependencyProducer->output(0)->dependentStagesEdges().front();
ASSERT_ANY_THROW(model->replaceStageDependency(edge, dependencyProducer->output(0)));
}
TEST_F(StageDependencyEdgeProcessingTests, ReplaceStageDependencyReplacesConnection) {
//
// -> [Data] -> (Stage) -> [Output]
//
// [Input] -> (Stage) -> [Data] -> (Stage) -> [Output]
// |
// -> [Data] ------------> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc, desc});
_testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
auto dependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto initialDependencyProducer = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
auto resultDependencyProducer = _testModel.addStage({InputInfo::fromPrevStage(0).output(2)}, {OutputInfo::fromNetwork(2)});
auto model = _testModel.getBaseModel();
ASSERT_NO_THROW(model->addStageDependency(dependentStage, initialDependencyProducer->output(0)));
ASSERT_TRUE(checkExecutionOrder(model, {initialDependencyProducer->id(), dependentStage->id()}));
ASSERT_TRUE(checkExecutionOrder(model, {dependentStage->id(), resultDependencyProducer->id()}));
const auto edge = initialDependencyProducer->output(0)->dependentStagesEdges().front();
ASSERT_NO_THROW(model->replaceStageDependency(edge, resultDependencyProducer->output(0)));
ASSERT_EQ(initialDependencyProducer->output(0)->dependentStagesEdges().size(), 0);
ASSERT_EQ(edge->dependency(), resultDependencyProducer->output(0));
ASSERT_TRUE(checkExecutionOrder(model, {resultDependencyProducer->id(), dependentStage->id()}));
}
TEST_F(StageDependencyEdgeProcessingTests, ReplaceDependentStageAssertsOnStageInput) {
//
// -----------> [Data] -> (Stage) -> [Output]
// [Input] -> (Stage) |
// -> [Data] -> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
auto dependencyProducer = _testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
auto initialDependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto resultDependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
auto model = _testModel.getBaseModel();
ASSERT_NO_THROW(model->addStageDependency(initialDependentStage, dependencyProducer->output(1)));
const auto edge = dependencyProducer->output(1)->dependentStagesEdges().front();
ASSERT_ANY_THROW(model->replaceDependentStage(edge, resultDependentStage));
}
TEST_F(StageDependencyEdgeProcessingTests, ReplaceDependentStageAssertsIfDependencyExists) {
//
// -> [Data] -> (Stage) -> [Output]
// [Input] -> (Stage) |
// -> [Data] ------------> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
_testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
auto dependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto dependencyProducer = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
auto model = _testModel.getBaseModel();
ASSERT_NO_THROW(model->addStageDependency(dependentStage, dependencyProducer->output(0)));
const auto edge = dependencyProducer->output(0)->dependentStagesEdges().front();
ASSERT_ANY_THROW(model->replaceDependentStage(edge, dependentStage));
}
TEST_F(StageDependencyEdgeProcessingTests, ReplaceDependentStageReplacesConnection) {
//
// -> [Data] -> (Stage) -> [Output]
//
// [Input] -> (Stage) -> [Data] -> (Stage) -> [Output]
// |
// -> [Data] ------------> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc, desc});
_testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
auto initialDependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto resultDependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
auto dependencyProducer = _testModel.addStage({InputInfo::fromPrevStage(0).output(2)}, {OutputInfo::fromNetwork(2)});
auto model = _testModel.getBaseModel();
ASSERT_NO_THROW(model->addStageDependency(initialDependentStage, dependencyProducer->output(0)));
ASSERT_TRUE(checkExecutionOrder(model, {dependencyProducer->id(), initialDependentStage->id()}));
ASSERT_TRUE(checkExecutionOrder(model, {resultDependentStage->id(), dependencyProducer->id()}));
const auto edge = dependencyProducer->output(0)->dependentStagesEdges().front();
ASSERT_NO_THROW(model->replaceDependentStage(edge, resultDependentStage));
ASSERT_EQ(edge->dependentStage(), resultDependentStage);
ASSERT_TRUE(checkExecutionOrder(model, {dependencyProducer->id(), resultDependentStage->id()}));
}
TEST_F(StageDependencyEdgeProcessingTests, RemoveStageDependencyUpdatesNextPrevStages) {
//
// -> [Data] -> (Stage) -> [Output]
// [Input] -> (Stage) |
// -> [Data] ------------> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
_testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
auto dependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto dependencyProducer = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
auto model = _testModel.getBaseModel();
ASSERT_NO_THROW(model->addStageDependency(dependentStage, dependencyProducer->output(0)));
const auto edge = dependencyProducer->output(0)->dependentStagesEdges().front();
ASSERT_NO_THROW(model->removeStageDependency(edge));
const auto prevStages = dependentStage->prevStages();
const auto nextStages = dependencyProducer->prevStages();
auto it = std::find(prevStages.begin(), prevStages.end(), dependencyProducer);
ASSERT_EQ(it, prevStages.end());
it = std::find(nextStages.begin(), nextStages.end(), dependentStage);
ASSERT_EQ(it, nextStages.end());
}
} // namespace vpu