Files
openvino/inference-engine/tests/unit/inference_engine/ie_compilation_context_test.cpp
Gleb Kazantaev a16cc81233 Remove VariantWrapper for simple attr classes (#7771)
* Remove VariantWrapper for simple attr classes

* Code style
2021-10-01 08:03:37 +03:00

408 lines
16 KiB
C++

// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <string>
#include <gtest/gtest.h>
#include <fstream>
#include <thread>
#include <chrono>
#include "compilation_context.hpp"
#include "ngraph/function.hpp"
#include "ngraph/ops.hpp"
#include "ngraph/variant.hpp"
#include "ngraph/opsets/opset6.hpp"
#include "transformations/rt_info/fused_names_attribute.hpp"
#include "transformations/rt_info/primitives_priority_attribute.hpp"
#include "cpp/ie_cnn_network.h"
#include "common_test_utils/test_constants.hpp"
using namespace InferenceEngine;
using namespace ngraph;
using namespace ::testing;
using namespace std::chrono;
static std::string generateTestFilePrefix() {
// Generate unique file names based on test name, thread id and timestamp
// This allows execution of tests in parallel (stress mode)
auto testInfo = UnitTest::GetInstance()->current_test_info();
std::string testName = testInfo->test_case_name();
testName += testInfo->name();
testName = std::to_string(std::hash<std::string>()(testName));
std::stringstream ss;
auto ts = duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch());
ss << testName << "_" << std::this_thread::get_id() << "_" << ts.count();
testName = ss.str();
return testName;
}
class FileGuard {
std::string m_fileName;
public:
FileGuard(const std::string& name): m_fileName(name) {}
~FileGuard() { std::remove(m_fileName.c_str()); }
};
class NetworkContext_CalcFileInfoTests : public Test {
public:
std::string m_fileName = "test.blob";
static void createFile(const std::string& fileName, std::size_t size = 1) {
std::ofstream str(fileName, std::ios::binary);
if (!str.good()) {
GTEST_SKIP();
}
for (std::size_t i = 0; i < size; i++)
str.put('a');
}
// Sets up the test fixture.
void SetUp() override {
auto testName = generateTestFilePrefix();
m_fileName = testName + m_fileName;
createFile(m_fileName);
}
// Tears down the test fixture.
void TearDown() override {
std::remove(m_fileName.c_str());
}
};
TEST_F(NetworkContext_CalcFileInfoTests, NoFile) {
ASSERT_NE(NetworkCompilationContext::calculateFileInfo("notexisting.abc"),
NetworkCompilationContext::calculateFileInfo("notexisting2.abc"));
std::string fileName(100, 'a');
std::string fileName2(fileName);
ASSERT_EQ(NetworkCompilationContext::calculateFileInfo(fileName),
NetworkCompilationContext::calculateFileInfo(fileName2));
}
TEST_F(NetworkContext_CalcFileInfoTests, ExistingFile) {
ASSERT_EQ(NetworkCompilationContext::calculateFileInfo(m_fileName),
NetworkCompilationContext::calculateFileInfo(m_fileName));
}
TEST_F(NetworkContext_CalcFileInfoTests, ExistingDiffFiles) {
auto hash1 = NetworkCompilationContext::calculateFileInfo(m_fileName);
std::string newName = m_fileName + "2";
std::rename(m_fileName.c_str(), newName.c_str());
m_fileName = std::move(newName);
auto hash2 = NetworkCompilationContext::calculateFileInfo(m_fileName);
ASSERT_NE(hash1, hash2);
}
TEST_F(NetworkContext_CalcFileInfoTests, ExistingFile_sameAbsPath) {
std::string file1 = m_fileName;
std::string file2 = std::string(".") + CommonTestUtils::FileSeparator + m_fileName;
ASSERT_EQ(NetworkCompilationContext::calculateFileInfo(file1),
NetworkCompilationContext::calculateFileInfo(file2)) <<
"Hash of [" << file1 << "] is not equal to hash of [" << file2 << "]";
}
TEST_F(NetworkContext_CalcFileInfoTests, DateModified) {
auto info1 = NetworkCompilationContext::calculateFileInfo(m_fileName);
std::this_thread::sleep_for(std::chrono::seconds(2));
createFile(m_fileName);
auto info2 = NetworkCompilationContext::calculateFileInfo(m_fileName);
ASSERT_NE(info1, info2);
}
TEST_F(NetworkContext_CalcFileInfoTests, SizeModified) {
createFile(m_fileName, 1);
auto info1 = NetworkCompilationContext::calculateFileInfo(m_fileName);
createFile(m_fileName, 2);
auto info2 = NetworkCompilationContext::calculateFileInfo(m_fileName);
ASSERT_NE(info1, info2);
}
////////////////////////////////////////////////////
static std::shared_ptr<ngraph::Function> create_simple_function() {
// This example is taken from docs, shows how to create ngraph::Function
//
// Parameter--->Multiply--->Add--->Result
// Constant---' /
// Constant---'
// Create opset6::Parameter operation with static shape
auto data = std::make_shared<ngraph::opset6::Parameter>(ngraph::element::i8, ngraph::Shape{3, 1, 2});
data->set_friendly_name("Parameter");
data->get_output_tensor(0).set_names({"parameter"});
auto mul_constant = ngraph::opset6::Constant::create(ngraph::element::i8, ngraph::Shape{1}, {3});
mul_constant->set_friendly_name("mul_constant");
mul_constant->get_output_tensor(0).set_names({"mul_constant"});
auto mul = std::make_shared<ngraph::opset6::Multiply>(data, mul_constant);
mul->set_friendly_name("mul");
mul->get_output_tensor(0).set_names({"mul"});
auto add_constant = ngraph::opset6::Constant::create(ngraph::element::i8, ngraph::Shape{1}, {2});
add_constant->set_friendly_name("add_constant");
add_constant->get_output_tensor(0).set_names({"add_constant"});
auto add = std::make_shared<ngraph::opset6::Add>(mul, add_constant);
add->set_friendly_name("add");
add->get_output_tensor(0).set_names({"add"});
// Create opset3::Result operation
auto res = std::make_shared<ngraph::opset6::Result>(add);
res->set_friendly_name("res");
// Create nGraph function
auto func = std::make_shared<ngraph::Function>(ngraph::ResultVector{res}, ngraph::ParameterVector{data});
func->set_friendly_name("function");
return func;
}
static CNNNetwork createNetwork() {
CNNNetwork res(create_simple_function());
return res;
}
static void checkCustomRt(std::function<void(Node::RTMap&)> emptyCb,
std::function<void(Node::RTMap&, const std::string& name)> nameCb) {
auto net1 = createNetwork();
auto net2 = createNetwork();
auto & op1 = net1.getFunction()->get_ops().front()->get_rt_info();
auto & op2 = net2.getFunction()->get_ops().front()->get_rt_info();
emptyCb(op2);
ASSERT_NE(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
emptyCb(op1);
ASSERT_EQ(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
nameCb(op1, "test");
ASSERT_NE(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
nameCb(op2, "test");
ASSERT_EQ(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
nameCb(op1, "test2");
ASSERT_NE(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
}
TEST(NetworkContext_CNNNetwork, HashOfSame) {
auto net1 = createNetwork();
auto net2 = createNetwork();
ASSERT_EQ(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
}
TEST(NetworkContext_CNNNetwork, HashWithConfig) {
auto net1 = createNetwork();
auto net2 = createNetwork();
ASSERT_NE(NetworkCompilationContext::computeHash(net1, {{"key", "value"}}),
NetworkCompilationContext::computeHash(net2, {}));
ASSERT_EQ(NetworkCompilationContext::computeHash(net1, {{"key", "value"}}),
NetworkCompilationContext::computeHash(net2, {{"key", "value"}}));
}
TEST(NetworkContext_CNNNetwork, HashWithPrimitivesPriority) {
auto net1 = createNetwork();
auto net2 = createNetwork();
auto net3 = createNetwork();
auto & op2 = net2.getFunction()->get_ops().front()->get_rt_info();
op2["PrimitivesPriority"] = std::make_shared<ngraph::VariantWrapper<std::string> > ("testPriority");
auto & op3 = net3.getFunction()->get_ops().front()->get_rt_info();
op3["PrimitivesPriority"] = std::make_shared<ngraph::VariantWrapper<std::string> > ("testPriority");
ASSERT_NE(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
ASSERT_EQ(NetworkCompilationContext::computeHash(net2, {}),
NetworkCompilationContext::computeHash(net3, {}));
}
TEST(NetworkContext_CNNNetwork, HashWithFusedNames) {
auto setFusedEmpty = [&](Node::RTMap& rtInfo) {
rtInfo[VariantWrapper<ngraph::FusedNames>::get_type_info_static()] =
std::make_shared<VariantWrapper<ngraph::FusedNames>>(ngraph::FusedNames());
};
auto setFused = [&](Node::RTMap& rtInfo, const std::string& name) {
rtInfo[VariantWrapper<ngraph::FusedNames>::get_type_info_static()] =
std::make_shared<VariantWrapper<ngraph::FusedNames>>(ngraph::FusedNames(name));
};
checkCustomRt(setFusedEmpty, setFused);
}
TEST(NetworkContext_CNNNetwork, HashWithPrimitivesPriorityType) {
auto setPrimEmpty = [&](Node::RTMap& rtInfo) {
rtInfo[ov::PrimitivesPriority::get_type_info_static()] =
std::make_shared<ov::PrimitivesPriority>("");
};
auto setPrim = [&](Node::RTMap& rtInfo, const std::string& name) {
rtInfo[ov::PrimitivesPriority::get_type_info_static()] =
std::make_shared<ov::PrimitivesPriority>(name);
};
checkCustomRt(setPrimEmpty, setPrim);
}
TEST(NetworkContext_CNNNetwork, HashWithAffinity) {
auto net1 = createNetwork();
auto net2 = createNetwork();
auto net3 = createNetwork();
auto & op2 = net2.getFunction()->get_ops().front()->get_rt_info();
op2["affinity"] = std::make_shared<ngraph::VariantWrapper<std::string>>("testAffinity");
auto & op3 = net3.getFunction()->get_ops().front()->get_rt_info();
op3["affinity"] = std::make_shared<ngraph::VariantWrapper<std::string>>("testAffinity");
ASSERT_NE(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
ASSERT_EQ(NetworkCompilationContext::computeHash(net2, {}),
NetworkCompilationContext::computeHash(net3, {}));
}
TEST(NetworkContext_CNNNetwork, HashWithFutureRt_string) {
auto net1 = createNetwork();
auto net2 = createNetwork();
auto net3 = createNetwork();
auto & op1 = net1.getFunction()->get_ops().front()->get_rt_info();
op1["someFutureKey"] = std::make_shared<ngraph::VariantWrapper<std::string>>("hello");
auto & op2 = net2.getFunction()->get_ops().front()->get_rt_info();
op2["someFutureKey"] = std::make_shared<ngraph::VariantWrapper<std::string>>("hello");
auto & op3 = net3.getFunction()->get_ops().front()->get_rt_info();
op3["someFutureKey"] = std::make_shared<ngraph::VariantWrapper<std::string>>("olleh");
ASSERT_EQ(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
ASSERT_NE(NetworkCompilationContext::computeHash(net2, {}),
NetworkCompilationContext::computeHash(net3, {}));
}
TEST(NetworkContext_CNNNetwork, HashWithFutureRt_int64) {
auto net1 = createNetwork();
auto net2 = createNetwork();
auto net3 = createNetwork();
auto & op1 = net1.getFunction()->get_ops().front()->get_rt_info();
op1["someFutureKey"] = std::make_shared<ngraph::VariantWrapper<int64_t>>(42);
auto & op2 = net2.getFunction()->get_ops().front()->get_rt_info();
op2["someFutureKey"] = std::make_shared<ngraph::VariantWrapper<int64_t>>(42);
auto & op3 = net3.getFunction()->get_ops().front()->get_rt_info();
op3["someFutureKey"] = std::make_shared<ngraph::VariantWrapper<int64_t>>(43);
ASSERT_EQ(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
ASSERT_NE(NetworkCompilationContext::computeHash(net2, {}),
NetworkCompilationContext::computeHash(net3, {}));
}
TEST(NetworkContext_CNNNetwork, HashWithDifferentResults) {
auto net1 = createNetwork();
auto net2 = createNetwork();
net2.getFunction()->remove_result(net2.getFunction()->get_results().front());
auto net3 = createNetwork();
net3.getFunction()->remove_result(net3.getFunction()->get_results().front());
ASSERT_NE(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
ASSERT_EQ(NetworkCompilationContext::computeHash(net2, {}),
NetworkCompilationContext::computeHash(net3, {}));
}
TEST(NetworkContext_CNNNetwork, HashWithDifferentMeanValues) {
auto updatePreprocess = [&](CNNNetwork& cnnNet) {
auto &preProcess = cnnNet.getInputsInfo().begin()->second->getPreProcess();
preProcess.init(3);
preProcess[0]->stdScale = 2;
preProcess[1]->stdScale = 3;
preProcess[2]->stdScale = 4;
preProcess[0]->meanValue = 0;
preProcess[1]->meanValue = 1;
preProcess[2]->meanValue = 2;
preProcess.setVariant(InferenceEngine::MEAN_VALUE);
};
auto net1 = createNetwork();
auto net2 = createNetwork();
updatePreprocess(net2);
auto net3 = createNetwork();
updatePreprocess(net3);
ASSERT_NE(NetworkCompilationContext::computeHash(net1, {}),
NetworkCompilationContext::computeHash(net2, {}));
ASSERT_EQ(NetworkCompilationContext::computeHash(net2, {}),
NetworkCompilationContext::computeHash(net3, {}));
}
// Verify all internal hash calculations are thread-safe (like ngraph::function serialization)
TEST(NetworkContext_CNNNetwork, HashOfSameMultiThreading) {
auto net1 = createNetwork();
auto net2 = createNetwork();
std::atomic_bool fail{false};
const auto TEST_DURATION_MS = 1000;
auto start = high_resolution_clock::now();
int t1Count = 0, t2Count = 0;
auto threadFun = [&](int& count) {
do {
count++;
auto hash1 = NetworkCompilationContext::computeHash(net1, {});
auto hash2 = NetworkCompilationContext::computeHash(net2, {});
if (hash1 != hash2) {
fail = true;
break;
}
} while (!fail && duration_cast<milliseconds>(high_resolution_clock::now() - start).count() < TEST_DURATION_MS);
};
std::thread t1(threadFun, std::ref(t1Count));
std::thread t2(threadFun, std::ref(t2Count));
t1.join();
t2.join();
std::cout << "Hash threading test finished. Total runs = " << t1Count + t2Count << std::endl;
ASSERT_FALSE(fail);
}
////////////////////////////////////////////
TEST(NetworkContext_ModelName, HashOfSame) {
ASSERT_EQ(NetworkCompilationContext::computeHash("model1", {}),
NetworkCompilationContext::computeHash("model1", {}));
ASSERT_NE(NetworkCompilationContext::computeHash("model1", {}),
NetworkCompilationContext::computeHash("model2", {}));
ASSERT_NE(NetworkCompilationContext::computeHash("model1", {{"key", "value"}}),
NetworkCompilationContext::computeHash("model1", {}));
ASSERT_EQ(NetworkCompilationContext::computeHash("model1", {{"key", "value"}}),
NetworkCompilationContext::computeHash("model1", {{"key", "value"}}));
}
TEST(NetworkContext_ModelName, HashOfExistingFile) {
auto file1 = generateTestFilePrefix() + ".xml";
auto file2 = std::string(".") + CommonTestUtils::FileSeparator + file1;
FileGuard guard(file1);
{
std::ofstream os(file1);
os << "test";
}
ASSERT_EQ(NetworkCompilationContext::computeHash(file1, {}),
NetworkCompilationContext::computeHash(file1, {}));
ASSERT_EQ(NetworkCompilationContext::computeHash(file1, {}),
NetworkCompilationContext::computeHash(file2, {}));
ASSERT_NE(NetworkCompilationContext::computeHash(file1, {{"key", "value"}}),
NetworkCompilationContext::computeHash(file2, {}));
ASSERT_EQ(NetworkCompilationContext::computeHash(file1, {{"key", "value"}}),
NetworkCompilationContext::computeHash(file2, {{"key", "value"}}));
}