From 0017ec71fd42fca8f54880155f4ff279d8132a9e Mon Sep 17 00:00:00 2001 From: Ilya Churaev Date: Thu, 11 Nov 2021 12:59:37 +0300 Subject: [PATCH] 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 c739e923aa571167b1f88fb1af844cf944c5cd57. * 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 50aec37f955fbe16e693f296c5d8fae19ca87313. * Revert "remove constexpr from type construction" This reverts commit 6c22d7ecfac82e414ba5ff7965ed539ae884946c. --- .../core/include/openvino/core/function.hpp | 9 ++- ngraph/core/include/openvino/core/layout.hpp | 5 +- ngraph/core/include/openvino/core/rtti.hpp | 24 +++--- ngraph/core/include/openvino/core/type.hpp | 29 ++++---- ngraph/core/include/openvino/op/op.hpp | 3 +- ngraph/core/src/function.cpp | 4 + ngraph/core/src/layout.cpp | 4 +- ngraph/core/src/type.cpp | 73 ++++++++++++------ ngraph/core/src/util.cpp | 6 +- ngraph/test/type_info.cpp | 74 +++++++++++++++++++ .../include/openvino/util/common_util.hpp | 2 + openvino/util/src/common_util.cpp | 8 ++ 12 files changed, 179 insertions(+), 62 deletions(-) diff --git a/ngraph/core/include/openvino/core/function.hpp b/ngraph/core/include/openvino/core/function.hpp index f8eed3450b1..a94cdfd66df 100644 --- a/ngraph/core/include/openvino/core/function.hpp +++ b/ngraph/core/include/openvino/core/function.hpp @@ -27,10 +27,15 @@ namespace ov { /// A user-defined function. class OPENVINO_API Function : public std::enable_shared_from_this { public: - static constexpr ov::DiscreteTypeInfo type_info{"Function", 0}; - const ov::DiscreteTypeInfo& get_type_info() const { + static const ::ov::DiscreteTypeInfo& get_type_info_static() { + static const ::ov::DiscreteTypeInfo type_info{"Function", 0}; 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::OutputVector& results, const ov::ParameterVector& parameters, const std::string& name = ""); diff --git a/ngraph/core/include/openvino/core/layout.hpp b/ngraph/core/include/openvino/core/layout.hpp index 4f7a998c5af..cf358babd4d 100644 --- a/ngraph/core/include/openvino/core/layout.hpp +++ b/ngraph/core/include/openvino/core/layout.hpp @@ -147,14 +147,11 @@ OPENVINO_API std::int64_t width_idx(const Layout& layout); template <> class OPENVINO_API AttributeAdapter : public ValueAccessor { public: + OPENVINO_RTTI("AttributeAdapter"); explicit AttributeAdapter(Layout& value) : m_ref(value) {} const std::string& get() override; void set(const std::string& value) override; - static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; - const DiscreteTypeInfo& get_type_info() const override { - return type_info; - } explicit operator Layout&() { return m_ref; } diff --git a/ngraph/core/include/openvino/core/rtti.hpp b/ngraph/core/include/openvino/core/rtti.hpp index a39b37833b6..80064b985ba 100644 --- a/ngraph/core/include/openvino/core/rtti.hpp +++ b/ngraph/core/include/openvino/core/rtti.hpp @@ -11,13 +11,14 @@ #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) \ - static const ::ov::DiscreteTypeInfo& get_type_info_static() { \ - static const ::ov::DiscreteTypeInfo type_info{TYPE_NAME, 0, VERSION_NAME}; \ - return type_info; \ - } \ - const ::ov::DiscreteTypeInfo& get_type_info() const override { \ - return get_type_info_static(); \ +#define _OPENVINO_RTTI_WITH_TYPE_VERSION(TYPE_NAME, VERSION_NAME) \ + static const ::ov::DiscreteTypeInfo& get_type_info_static() { \ + static ::ov::DiscreteTypeInfo type_info{TYPE_NAME, 0, VERSION_NAME}; \ + type_info.hash(); \ + return type_info; \ + } \ + 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) \ @@ -25,10 +26,11 @@ #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 type_info{TYPE_NAME, \ - OLD_VERSION, \ - VERSION_NAME, \ - &PARENT_CLASS::get_type_info_static()}; \ + static ::ov::DiscreteTypeInfo type_info{TYPE_NAME, \ + OLD_VERSION, \ + VERSION_NAME, \ + &PARENT_CLASS::get_type_info_static()}; \ + type_info.hash(); \ return type_info; \ } \ const ::ov::DiscreteTypeInfo& get_type_info() const override { \ diff --git a/ngraph/core/include/openvino/core/type.hpp b/ngraph/core/include/openvino/core/type.hpp index 63f850e4199..08eb5c24070 100644 --- a/ngraph/core/include/openvino/core/type.hpp +++ b/ngraph/core/include/openvino/core/type.hpp @@ -39,7 +39,8 @@ struct OPENVINO_API DiscreteTypeInfo { : name(_name), version(_version), version_id(nullptr), - parent(_parent) {} + parent(_parent), + hash_value(0) {} constexpr DiscreteTypeInfo(const char* _name, uint64_t _version, @@ -48,22 +49,12 @@ struct OPENVINO_API DiscreteTypeInfo { : name(_name), version(_version), version_id(_version_id), - parent(_parent) {} + parent(_parent), + hash_value(0) {} - bool is_castable(const DiscreteTypeInfo& target_type) const { - return *this == target_type || (parent && parent->is_castable(target_type)); - } + bool is_castable(const DiscreteTypeInfo& target_type) 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(); - } + std::string get_version() const; // For use as a key 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; + + operator std::string() const; + + size_t hash() const; + size_t hash(); + +private: + size_t hash_value; }; OPENVINO_API diff --git a/ngraph/core/include/openvino/op/op.hpp b/ngraph/core/include/openvino/op/op.hpp index c7920537c8a..d1bae6d12fd 100644 --- a/ngraph/core/include/openvino/op/op.hpp +++ b/ngraph/core/include/openvino/op/op.hpp @@ -31,7 +31,8 @@ protected: public: 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; } const ::ov::Node::type_info_t& get_type_info() const override { diff --git a/ngraph/core/src/function.cpp b/ngraph/core/src/function.cpp index 396a68f04ed..1732d0f4352 100644 --- a/ngraph/core/src/function.cpp +++ b/ngraph/core/src/function.cpp @@ -87,6 +87,10 @@ ngraph::ParameterVector auto_detect_parameters(const std::vector::type_info; - const std::string& AttributeAdapter::get() { m_dump = m_ref.to_string(); return m_dump; @@ -364,4 +362,4 @@ bool LayoutAttribute::visit_attributes(AttributeVisitor& visitor) { return true; } -} // namespace ov \ No newline at end of file +} // namespace ov diff --git a/ngraph/core/src/type.cpp b/ngraph/core/src/type.cpp index 9efa977ccbe..876fa849634 100644 --- a/ngraph/core/src/type.cpp +++ b/ngraph/core/src/type.cpp @@ -4,20 +4,47 @@ #include "ngraph/type.hpp" -#include "ngraph/util.hpp" +#include "openvino/util/common_util.hpp" namespace std { size_t std::hash::operator()(const ngraph::DiscreteTypeInfo& k) const { - NGRAPH_SUPPRESS_DEPRECATED_START - size_t name_hash = hash()(string(k.name)); - size_t version_hash = hash()(k.version); - // don't use parent for hash calculation, it is not a part of type (yet) - return ngraph::hash_combine(vector{name_hash, version_hash}); - NGRAPH_SUPPRESS_DEPRECATED_END + return k.hash(); } } // namespace std namespace ov { + +size_t DiscreteTypeInfo::hash() const { + if (hash_value != 0) + return hash_value; + size_t name_hash = name ? std::hash()(std::string(name)) : 0; + size_t version_hash = std::hash()(version); + size_t version_id_hash = version_id ? std::hash()(std::string(version_id)) : 0; + + return ov::util::hash_combine(std::vector{name_hash, version_hash, version_id_hash}); +} + +size_t DiscreteTypeInfo::hash() { + if (hash_value == 0) + hash_value = static_cast(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::string version_id = info.version_id ? info.version_id : "(empty)"; 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 bool DiscreteTypeInfo::operator<(const DiscreteTypeInfo& b) const { - if (version_id == nullptr || b.version_id == nullptr) - return version < b.version || - (version == b.version && strcmp(name, b.name) < 0); // || - // (version == b.version && strcmp(name, b.name) == - // 0 && parent && b.parent && *parent < *b.parent); - else - return strcmp(version_id, b.version_id) < 0 || - (strcmp(version_id, b.version_id) == 0 && strcmp(name, b.name) < 0); // || - // (strcmp(version_id, b.version_id) == 0 && strcmp(name, b.name) == 0 && parent && b.parent && - // *parent < *b.parent); + if (version < b.version) + return true; + if (version == b.version && name != nullptr && b.name != nullptr) { + int cmp_status = strcmp(name, b.name); + if (cmp_status < 0) + return true; + if (cmp_status == 0) { + std::string v_id(version_id == nullptr ? "" : version_id); + std::string bv_id(b.version_id == nullptr ? "" : b.version_id); + if (v_id < bv_id) + return true; + } + } + + return false; } bool DiscreteTypeInfo::operator==(const DiscreteTypeInfo& b) const { - if (version_id == nullptr || b.version_id == nullptr) - return version == b.version && strcmp(name, b.name) == 0; // && parent == b.parent; - else - return strcmp(version_id, b.version_id) == 0 && strcmp(name, b.name) == 0; // && parent == b.parent; + if (hash_value != 0 && b.hash_value != 0) + return hash() == b.hash(); + return version == b.version && strcmp(name, b.name) == 0; } bool DiscreteTypeInfo::operator<=(const DiscreteTypeInfo& b) const { return *this == b || *this < b; diff --git a/ngraph/core/src/util.cpp b/ngraph/core/src/util.cpp index 563c63bf794..2c8b59cc5b3 100644 --- a/ngraph/core/src/util.cpp +++ b/ngraph/core/src/util.cpp @@ -78,11 +78,7 @@ vector ngraph::split(const string& src, char delimiter, bool do_trim) { } size_t ngraph::hash_combine(const std::vector& list) { - size_t seed = 0; - for (size_t v : list) { - seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2); - } - return seed; + return ov::util::hash_combine(list); } void* ngraph::ngraph_malloc(size_t size) { diff --git a/ngraph/test/type_info.cpp b/ngraph/test/type_info.cpp index 45b2ae47d89..ddba89fc5d3 100644 --- a/ngraph/test/type_info.cpp +++ b/ngraph/test/type_info.cpp @@ -5,6 +5,8 @@ #include #include "openvino/core/type.hpp" +#include "openvino/opsets/opset.hpp" +#include "openvino/util/common_util.hpp" TEST(type_info, compare_old_type) { ov::DiscreteTypeInfo type1("type1", 0); @@ -47,3 +49,75 @@ TEST(type_info, compare_new_with_old_type) { ov::DiscreteTypeInfo type1_o("type1", 0); 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(name)) : 0; + size_t version_hash = std::hash()(version); + size_t version_id_hash = version_id ? std::hash()(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{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 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 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)); +} diff --git a/openvino/util/include/openvino/util/common_util.hpp b/openvino/util/include/openvino/util/common_util.hpp index 6c519f06611..60ee9e6e2a1 100644 --- a/openvino/util/include/openvino/util/common_util.hpp +++ b/openvino/util/include/openvino/util/common_util.hpp @@ -37,6 +37,8 @@ std::string to_lower(const std::string& s); std::string to_upper(const std::string& s); +size_t hash_combine(const std::vector& list); + /** * @brief trim from start (in place) * @param s - string to trim diff --git a/openvino/util/src/common_util.cpp b/openvino/util/src/common_util.cpp index b3aba13d41f..82872c486f1 100644 --- a/openvino/util/src/common_util.cpp +++ b/openvino/util/src/common_util.cpp @@ -40,3 +40,11 @@ std::vector ov::util::split(const std::string& src, char delimiter, } return rc; } + +size_t ov::util::hash_combine(const std::vector& list) { + size_t seed = 0; + for (size_t v : list) { + seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; +}