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.
class OPENVINO_API Function : public std::enable_shared_from_this<Function> {
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 = "");

View File

@ -147,14 +147,11 @@ OPENVINO_API std::int64_t width_idx(const Layout& layout);
template <>
class OPENVINO_API AttributeAdapter<Layout> : public ValueAccessor<std::string> {
public:
OPENVINO_RTTI("AttributeAdapter<Layout>");
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<Layout>", 0};
const DiscreteTypeInfo& get_type_info() const override {
return type_info;
}
explicit operator Layout&() {
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_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 { \

View File

@ -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

View File

@ -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 {

View File

@ -87,6 +87,10 @@ ngraph::ParameterVector auto_detect_parameters(const std::vector<std::shared_ptr
} // 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)
: m_name(name),
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
constexpr DiscreteTypeInfo AttributeAdapter<ov::Layout>::type_info;
const std::string& AttributeAdapter<ov::Layout>::get() {
m_dump = m_ref.to_string();
return m_dump;

View File

@ -4,20 +4,47 @@
#include "ngraph/type.hpp"
#include "ngraph/util.hpp"
#include "openvino/util/common_util.hpp"
namespace std {
size_t std::hash<ngraph::DiscreteTypeInfo>::operator()(const ngraph::DiscreteTypeInfo& k) const {
NGRAPH_SUPPRESS_DEPRECATED_START
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
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>()(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::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;

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 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) {

View File

@ -5,6 +5,8 @@
#include <gtest/gtest.h>
#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>()(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);
size_t hash_combine(const std::vector<size_t>& list);
/**
* @brief trim from start (in place)
* @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;
}
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;
}