Added hash to type_info (#8175)

* Added hash to type_info

* Fast hash

* Fixed tests

* Added new tests

* Fixed build

* Fix centos

* Fixed segfault

* Fixed test

* Fixed build

* Revert "Fix centos"

This reverts commit c739e923aa.

* Try to fix cent os

* Fixed style

* Fixed GCC 4.8

* Try to fix build

* Fixed code style

* remove constexpr from type construction

* Fixed tests

* Revert "Fixed tests"

This reverts commit 50aec37f95.

* Revert "remove constexpr from type construction"

This reverts commit 6c22d7ecfa.
This commit is contained in:
Ilya Churaev 2021-11-11 12:59:37 +03:00 committed by GitHub
parent abc554513f
commit 0017ec71fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 179 additions and 62 deletions

View File

@ -27,10 +27,15 @@ namespace ov {
/// A user-defined function. /// A user-defined function.
class OPENVINO_API Function : public std::enable_shared_from_this<Function> { class OPENVINO_API Function : public std::enable_shared_from_this<Function> {
public: public:
static constexpr ov::DiscreteTypeInfo type_info{"Function", 0}; static const ::ov::DiscreteTypeInfo& get_type_info_static() {
const ov::DiscreteTypeInfo& get_type_info() const { static const ::ov::DiscreteTypeInfo type_info{"Function", 0};
return type_info; return type_info;
} }
const ::ov::DiscreteTypeInfo& get_type_info() const {
return get_type_info_static();
}
OPENVINO_DEPRECATED("This member was deprecated. Please use ::get_type_info_static() instead.")
static const ov::DiscreteTypeInfo type_info;
Function(const ov::NodeVector& results, const ov::ParameterVector& parameters, const std::string& name = ""); Function(const ov::NodeVector& results, const ov::ParameterVector& parameters, const std::string& name = "");
Function(const ov::OutputVector& results, const ov::ParameterVector& parameters, const std::string& name = ""); Function(const ov::OutputVector& results, const ov::ParameterVector& parameters, const std::string& name = "");

View File

@ -147,14 +147,11 @@ OPENVINO_API std::int64_t width_idx(const Layout& layout);
template <> template <>
class OPENVINO_API AttributeAdapter<Layout> : public ValueAccessor<std::string> { class OPENVINO_API AttributeAdapter<Layout> : public ValueAccessor<std::string> {
public: public:
OPENVINO_RTTI("AttributeAdapter<Layout>");
explicit AttributeAdapter(Layout& value) : m_ref(value) {} explicit AttributeAdapter(Layout& value) : m_ref(value) {}
const std::string& get() override; const std::string& get() override;
void set(const std::string& value) override; void set(const std::string& value) override;
static constexpr DiscreteTypeInfo type_info{"AttributeAdapter<Layout>", 0};
const DiscreteTypeInfo& get_type_info() const override {
return type_info;
}
explicit operator Layout&() { explicit operator Layout&() {
return m_ref; return m_ref;
} }

View File

@ -11,13 +11,14 @@
#define _OPENVINO_RTTI_WITH_TYPE(TYPE_NAME) _OPENVINO_RTTI_WITH_TYPE_VERSION(TYPE_NAME, "util") #define _OPENVINO_RTTI_WITH_TYPE(TYPE_NAME) _OPENVINO_RTTI_WITH_TYPE_VERSION(TYPE_NAME, "util")
#define _OPENVINO_RTTI_WITH_TYPE_VERSION(TYPE_NAME, VERSION_NAME) \ #define _OPENVINO_RTTI_WITH_TYPE_VERSION(TYPE_NAME, VERSION_NAME) \
static const ::ov::DiscreteTypeInfo& get_type_info_static() { \ static const ::ov::DiscreteTypeInfo& get_type_info_static() { \
static const ::ov::DiscreteTypeInfo type_info{TYPE_NAME, 0, VERSION_NAME}; \ static ::ov::DiscreteTypeInfo type_info{TYPE_NAME, 0, VERSION_NAME}; \
return type_info; \ type_info.hash(); \
} \ return type_info; \
const ::ov::DiscreteTypeInfo& get_type_info() const override { \ } \
return get_type_info_static(); \ const ::ov::DiscreteTypeInfo& get_type_info() const override { \
return get_type_info_static(); \
} }
#define _OPENVINO_RTTI_WITH_TYPE_VERSION_PARENT(TYPE_NAME, VERSION_NAME, PARENT_CLASS) \ #define _OPENVINO_RTTI_WITH_TYPE_VERSION_PARENT(TYPE_NAME, VERSION_NAME, PARENT_CLASS) \
@ -25,10 +26,11 @@
#define _OPENVINO_RTTI_WITH_TYPE_VERSIONS_PARENT(TYPE_NAME, VERSION_NAME, PARENT_CLASS, OLD_VERSION) \ #define _OPENVINO_RTTI_WITH_TYPE_VERSIONS_PARENT(TYPE_NAME, VERSION_NAME, PARENT_CLASS, OLD_VERSION) \
static const ::ov::DiscreteTypeInfo& get_type_info_static() { \ static const ::ov::DiscreteTypeInfo& get_type_info_static() { \
static const ::ov::DiscreteTypeInfo type_info{TYPE_NAME, \ static ::ov::DiscreteTypeInfo type_info{TYPE_NAME, \
OLD_VERSION, \ OLD_VERSION, \
VERSION_NAME, \ VERSION_NAME, \
&PARENT_CLASS::get_type_info_static()}; \ &PARENT_CLASS::get_type_info_static()}; \
type_info.hash(); \
return type_info; \ return type_info; \
} \ } \
const ::ov::DiscreteTypeInfo& get_type_info() const override { \ const ::ov::DiscreteTypeInfo& get_type_info() const override { \

View File

@ -39,7 +39,8 @@ struct OPENVINO_API DiscreteTypeInfo {
: name(_name), : name(_name),
version(_version), version(_version),
version_id(nullptr), version_id(nullptr),
parent(_parent) {} parent(_parent),
hash_value(0) {}
constexpr DiscreteTypeInfo(const char* _name, constexpr DiscreteTypeInfo(const char* _name,
uint64_t _version, uint64_t _version,
@ -48,22 +49,12 @@ struct OPENVINO_API DiscreteTypeInfo {
: name(_name), : name(_name),
version(_version), version(_version),
version_id(_version_id), version_id(_version_id),
parent(_parent) {} parent(_parent),
hash_value(0) {}
bool is_castable(const DiscreteTypeInfo& target_type) const { bool is_castable(const DiscreteTypeInfo& target_type) const;
return *this == target_type || (parent && parent->is_castable(target_type));
}
std::string get_version() const { std::string get_version() const;
if (version_id) {
return std::string(version_id);
}
return std::to_string(version);
}
operator std::string() const {
return std::string(name) + "_" + get_version();
}
// For use as a key // For use as a key
bool operator<(const DiscreteTypeInfo& b) const; bool operator<(const DiscreteTypeInfo& b) const;
@ -72,6 +63,14 @@ struct OPENVINO_API DiscreteTypeInfo {
bool operator>=(const DiscreteTypeInfo& b) const; bool operator>=(const DiscreteTypeInfo& b) const;
bool operator==(const DiscreteTypeInfo& b) const; bool operator==(const DiscreteTypeInfo& b) const;
bool operator!=(const DiscreteTypeInfo& b) const; bool operator!=(const DiscreteTypeInfo& b) const;
operator std::string() const;
size_t hash() const;
size_t hash();
private:
size_t hash_value;
}; };
OPENVINO_API OPENVINO_API

View File

@ -31,7 +31,8 @@ protected:
public: public:
static const ::ov::Node::type_info_t& get_type_info_static() { static const ::ov::Node::type_info_t& get_type_info_static() {
static const ::ov::Node::type_info_t info{"Op", 0, "util"}; static ::ov::Node::type_info_t info{"Op", 0, "util"};
info.hash();
return info; return info;
} }
const ::ov::Node::type_info_t& get_type_info() const override { const ::ov::Node::type_info_t& get_type_info() const override {

View File

@ -87,6 +87,10 @@ ngraph::ParameterVector auto_detect_parameters(const std::vector<std::shared_ptr
} // namespace } // namespace
OPENVINO_SUPPRESS_DEPRECATED_START
const ov::DiscreteTypeInfo ov::Function::type_info = ov::Function::get_type_info_static();
OPENVINO_SUPPRESS_DEPRECATED_END
ov::Function::Function(const ResultVector& results, const ngraph::ParameterVector& parameters, const std::string& name) ov::Function::Function(const ResultVector& results, const ngraph::ParameterVector& parameters, const std::string& name)
: m_name(name), : m_name(name),
m_unique_name("Function_" + to_string(m_next_instance_id.fetch_add(1))), m_unique_name("Function_" + to_string(m_next_instance_id.fetch_add(1))),

View File

@ -346,8 +346,6 @@ std::int64_t width_idx(const Layout& layout) {
} // namespace layout } // namespace layout
constexpr DiscreteTypeInfo AttributeAdapter<ov::Layout>::type_info;
const std::string& AttributeAdapter<ov::Layout>::get() { const std::string& AttributeAdapter<ov::Layout>::get() {
m_dump = m_ref.to_string(); m_dump = m_ref.to_string();
return m_dump; return m_dump;
@ -364,4 +362,4 @@ bool LayoutAttribute::visit_attributes(AttributeVisitor& visitor) {
return true; return true;
} }
} // namespace ov } // namespace ov

View File

@ -4,20 +4,47 @@
#include "ngraph/type.hpp" #include "ngraph/type.hpp"
#include "ngraph/util.hpp" #include "openvino/util/common_util.hpp"
namespace std { namespace std {
size_t std::hash<ngraph::DiscreteTypeInfo>::operator()(const ngraph::DiscreteTypeInfo& k) const { size_t std::hash<ngraph::DiscreteTypeInfo>::operator()(const ngraph::DiscreteTypeInfo& k) const {
NGRAPH_SUPPRESS_DEPRECATED_START return k.hash();
size_t name_hash = hash<string>()(string(k.name));
size_t version_hash = hash<decltype(k.version)>()(k.version);
// don't use parent for hash calculation, it is not a part of type (yet)
return ngraph::hash_combine(vector<size_t>{name_hash, version_hash});
NGRAPH_SUPPRESS_DEPRECATED_END
} }
} // namespace std } // namespace std
namespace ov { namespace ov {
size_t DiscreteTypeInfo::hash() const {
if (hash_value != 0)
return hash_value;
size_t name_hash = name ? std::hash<std::string>()(std::string(name)) : 0;
size_t version_hash = std::hash<decltype(version)>()(version);
size_t version_id_hash = version_id ? std::hash<std::string>()(std::string(version_id)) : 0;
return ov::util::hash_combine(std::vector<size_t>{name_hash, version_hash, version_id_hash});
}
size_t DiscreteTypeInfo::hash() {
if (hash_value == 0)
hash_value = static_cast<const DiscreteTypeInfo*>(this)->hash();
return hash_value;
}
bool DiscreteTypeInfo::is_castable(const DiscreteTypeInfo& target_type) const {
return *this == target_type || (parent && parent->is_castable(target_type));
}
std::string DiscreteTypeInfo::get_version() const {
if (version_id) {
return std::string(version_id);
}
return std::to_string(version);
}
DiscreteTypeInfo::operator std::string() const {
return std::string(name) + "_" + get_version();
}
std::ostream& operator<<(std::ostream& s, const DiscreteTypeInfo& info) { std::ostream& operator<<(std::ostream& s, const DiscreteTypeInfo& info) {
std::string version_id = info.version_id ? info.version_id : "(empty)"; std::string version_id = info.version_id ? info.version_id : "(empty)";
s << "DiscreteTypeInfo{name: " << info.name << ", version_id: " << version_id << ", old_version: " << info.version s << "DiscreteTypeInfo{name: " << info.name << ", version_id: " << version_id << ", old_version: " << info.version
@ -33,22 +60,26 @@ std::ostream& operator<<(std::ostream& s, const DiscreteTypeInfo& info) {
// parent is commented to fix type relaxed operations // parent is commented to fix type relaxed operations
bool DiscreteTypeInfo::operator<(const DiscreteTypeInfo& b) const { bool DiscreteTypeInfo::operator<(const DiscreteTypeInfo& b) const {
if (version_id == nullptr || b.version_id == nullptr) if (version < b.version)
return version < b.version || return true;
(version == b.version && strcmp(name, b.name) < 0); // || if (version == b.version && name != nullptr && b.name != nullptr) {
// (version == b.version && strcmp(name, b.name) == int cmp_status = strcmp(name, b.name);
// 0 && parent && b.parent && *parent < *b.parent); if (cmp_status < 0)
else return true;
return strcmp(version_id, b.version_id) < 0 || if (cmp_status == 0) {
(strcmp(version_id, b.version_id) == 0 && strcmp(name, b.name) < 0); // || std::string v_id(version_id == nullptr ? "" : version_id);
// (strcmp(version_id, b.version_id) == 0 && strcmp(name, b.name) == 0 && parent && b.parent && std::string bv_id(b.version_id == nullptr ? "" : b.version_id);
// *parent < *b.parent); if (v_id < bv_id)
return true;
}
}
return false;
} }
bool DiscreteTypeInfo::operator==(const DiscreteTypeInfo& b) const { bool DiscreteTypeInfo::operator==(const DiscreteTypeInfo& b) const {
if (version_id == nullptr || b.version_id == nullptr) if (hash_value != 0 && b.hash_value != 0)
return version == b.version && strcmp(name, b.name) == 0; // && parent == b.parent; return hash() == b.hash();
else return version == b.version && strcmp(name, b.name) == 0;
return strcmp(version_id, b.version_id) == 0 && strcmp(name, b.name) == 0; // && parent == b.parent;
} }
bool DiscreteTypeInfo::operator<=(const DiscreteTypeInfo& b) const { bool DiscreteTypeInfo::operator<=(const DiscreteTypeInfo& b) const {
return *this == b || *this < b; return *this == b || *this < b;

View File

@ -78,11 +78,7 @@ vector<string> ngraph::split(const string& src, char delimiter, bool do_trim) {
} }
size_t ngraph::hash_combine(const std::vector<size_t>& list) { size_t ngraph::hash_combine(const std::vector<size_t>& list) {
size_t seed = 0; return ov::util::hash_combine(list);
for (size_t v : list) {
seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
} }
void* ngraph::ngraph_malloc(size_t size) { void* ngraph::ngraph_malloc(size_t size) {

View File

@ -5,6 +5,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "openvino/core/type.hpp" #include "openvino/core/type.hpp"
#include "openvino/opsets/opset.hpp"
#include "openvino/util/common_util.hpp"
TEST(type_info, compare_old_type) { TEST(type_info, compare_old_type) {
ov::DiscreteTypeInfo type1("type1", 0); ov::DiscreteTypeInfo type1("type1", 0);
@ -47,3 +49,75 @@ TEST(type_info, compare_new_with_old_type) {
ov::DiscreteTypeInfo type1_o("type1", 0); ov::DiscreteTypeInfo type1_o("type1", 0);
ASSERT_TRUE(type1 == type1_o); ASSERT_TRUE(type1 == type1_o);
} }
TEST(type_info, check_hash_value) {
const auto& hash_val = [](const char* name, const char* version_id, uint64_t version) -> size_t {
size_t name_hash = name ? std::hash<std::string>()(std::string(name)) : 0;
size_t version_hash = std::hash<decltype(version)>()(version);
size_t version_id_hash = version_id ? std::hash<std::string>()(std::string(version_id)) : 0;
// don't use parent for hash calculation, it is not a part of type (yet)
return ov::util::hash_combine(std::vector<size_t>{name_hash, version_hash, version_id_hash});
};
ov::DiscreteTypeInfo type("type1", 0, "version1");
ov::DiscreteTypeInfo type_old("type1", 1);
ov::DiscreteTypeInfo type_with_version("type1", 1, "version1");
ov::DiscreteTypeInfo type_empty_name("", 0);
ov::DiscreteTypeInfo type_empty_ver("type", 0, "");
EXPECT_EQ(hash_val(type.name, type.version_id, type.version), type.hash());
EXPECT_EQ(hash_val(type_old.name, type_old.version_id, type_old.version), type_old.hash());
EXPECT_EQ(hash_val(type_with_version.name, type_with_version.version_id, type_with_version.version),
type_with_version.hash());
EXPECT_EQ(hash_val(type_empty_name.name, type_empty_name.version_id, type_empty_name.version),
type_empty_name.hash());
EXPECT_EQ(hash_val(type_empty_ver.name, type_empty_ver.version_id, type_empty_ver.version), type_empty_ver.hash());
}
TEST(type_info, find_in_map) {
std::vector<std::string> vector_names;
ov::DiscreteTypeInfo a("Mod", 1, "opset1");
ov::DiscreteTypeInfo b("Prelu", 0, "opset1");
ov::DiscreteTypeInfo c("Vector", 0);
ov::DiscreteTypeInfo d("Mod", 1, "opset3");
ov::DiscreteTypeInfo f("Mod", 2);
std::map<ov::DiscreteTypeInfo, int> test_map;
test_map[a] = 1;
test_map[b] = 1;
test_map[c] = 1;
const auto& opset = ov::get_opset8();
// Reserve memory to avoid reallocation and copy of strings
// because type info uses pointers from the original memory
vector_names.reserve(opset.size() * 3);
for (const auto& type : opset.get_types_info()) {
test_map[type] = 2;
std::string name = type.name;
vector_names.emplace_back(name);
ov::DiscreteTypeInfo t(vector_names.rbegin()->c_str(), 1000);
ov::DiscreteTypeInfo t2(vector_names.rbegin()->c_str(), 0);
test_map[t] = 3;
test_map[t2] = 4;
std::string name1 = "a" + name;
vector_names.emplace_back(name1);
ov::DiscreteTypeInfo t3(vector_names.rbegin()->c_str(), 1000);
ov::DiscreteTypeInfo t4(vector_names.rbegin()->c_str(), 0);
test_map[t3] = 5;
test_map[t4] = 6;
std::string name2 = name + "z";
vector_names.emplace_back(name2);
ov::DiscreteTypeInfo t5(vector_names.rbegin()->c_str(), 1000);
ov::DiscreteTypeInfo t6(vector_names.rbegin()->c_str(), 0);
test_map[t5] = 7;
test_map[t6] = 8;
}
for (const auto& it : test_map) {
ASSERT_NE(test_map.end(), test_map.find(it.first));
}
ASSERT_NE(test_map.end(), test_map.find(a));
ASSERT_NE(test_map.end(), test_map.find(b));
ASSERT_NE(test_map.end(), test_map.find(c));
ASSERT_EQ(test_map.end(), test_map.find(d));
ASSERT_EQ(test_map.end(), test_map.find(f));
}

View File

@ -37,6 +37,8 @@ std::string to_lower(const std::string& s);
std::string to_upper(const std::string& s); std::string to_upper(const std::string& s);
size_t hash_combine(const std::vector<size_t>& list);
/** /**
* @brief trim from start (in place) * @brief trim from start (in place)
* @param s - string to trim * @param s - string to trim

View File

@ -40,3 +40,11 @@ std::vector<std::string> ov::util::split(const std::string& src, char delimiter,
} }
return rc; return rc;
} }
size_t ov::util::hash_combine(const std::vector<size_t>& list) {
size_t seed = 0;
for (size_t v : list) {
seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}