Merge changes I2dfa0347,I951ff7a7
* changes:
Do not blindly emplace in interner.
Use unordered_set for interner.
diff --git a/src/profiling/memory/bookkeeping.h b/src/profiling/memory/bookkeeping.h
index 32166c2..1559459 100644
--- a/src/profiling/memory/bookkeeping.h
+++ b/src/profiling/memory/bookkeeping.h
@@ -17,6 +17,7 @@
#ifndef SRC_PROFILING_MEMORY_BOOKKEEPING_H_
#define SRC_PROFILING_MEMORY_BOOKKEEPING_H_
+#include <functional>
#include <map>
#include <string>
#include <vector>
@@ -110,6 +111,11 @@
std::tie(other.build_id, other.offset, other.start, other.end,
other.load_bias, other.path_components);
}
+ bool operator==(const Mapping& other) const {
+ return std::tie(build_id, offset, start, end, load_bias, path_components) ==
+ std::tie(other.build_id, other.offset, other.start, other.end,
+ other.load_bias, other.path_components);
+ }
};
struct Frame {
@@ -123,6 +129,11 @@
return std::tie(mapping, function_name, rel_pc) <
std::tie(other.mapping, other.function_name, other.rel_pc);
}
+
+ bool operator==(const Frame& other) const {
+ return std::tie(mapping, function_name, rel_pc) ==
+ std::tie(other.mapping, other.function_name, other.rel_pc);
+ }
};
// Graph of function callsites. This is shared between heap dumps for
@@ -366,4 +377,35 @@
} // namespace profiling
} // namespace perfetto
+namespace std {
+template <>
+struct hash<::perfetto::profiling::Mapping> {
+ using argument_type = ::perfetto::profiling::Mapping;
+ using result_type = size_t;
+ result_type operator()(const argument_type& mapping) {
+ size_t h =
+ std::hash<::perfetto::profiling::InternID>{}(mapping.build_id.id());
+ h ^= std::hash<uint64_t>{}(mapping.offset);
+ h ^= std::hash<uint64_t>{}(mapping.start);
+ h ^= std::hash<uint64_t>{}(mapping.end);
+ h ^= std::hash<uint64_t>{}(mapping.load_bias);
+ for (const auto& path : mapping.path_components)
+ h ^= std::hash<uint64_t>{}(path.id());
+ return h;
+ }
+};
+
+template <>
+struct hash<::perfetto::profiling::Frame> {
+ using argument_type = ::perfetto::profiling::Frame;
+ using result_type = size_t;
+ result_type operator()(const argument_type& frame) {
+ size_t h = std::hash<::perfetto::profiling::InternID>{}(frame.mapping.id());
+ h ^= std::hash<::perfetto::profiling::InternID>{}(frame.function_name.id());
+ h ^= std::hash<uint64_t>{}(frame.rel_pc);
+ return h;
+ }
+};
+} // namespace std
+
#endif // SRC_PROFILING_MEMORY_BOOKKEEPING_H_
diff --git a/src/profiling/memory/interner.h b/src/profiling/memory/interner.h
index e5b6ed1..e67fcb5 100644
--- a/src/profiling/memory/interner.h
+++ b/src/profiling/memory/interner.h
@@ -19,7 +19,8 @@
#include <stddef.h>
#include <stdint.h>
-#include <set>
+#include <functional>
+#include <unordered_set>
#include "perfetto/base/logging.h"
@@ -37,6 +38,13 @@
: data(std::forward<U...>(args...)), id(i), interner(in) {}
bool operator<(const Entry& other) const { return data < other.data; }
+ bool operator==(const Entry& other) const { return data == other.data; }
+
+ struct Hash {
+ size_t operator()(const Entry& e) const noexcept {
+ return std::hash<T>{}(e.data);
+ }
+ };
const T data;
size_t ref_count = 0;
@@ -77,6 +85,10 @@
return entry_ < other.entry_;
}
+ bool operator==(const Interned& other) const {
+ return entry_ == other.entry_;
+ }
+
const T* operator->() const { return &entry_->data; }
private:
@@ -85,11 +97,17 @@
template <typename... U>
Interned Intern(U... args) {
- auto itr_and_inserted =
- entries_.emplace(this, next_id, std::forward<U...>(args...));
- if (itr_and_inserted.second)
+ Entry item(this, next_id, std::forward<U...>(args...));
+ auto it = entries_.find(item);
+ if (it == entries_.cend()) {
+ // This does not invalidate pointers to entries we hold in Interned. See
+ // https://timsong-cpp.github.io/cppwp/n3337/unord.req#8
+ auto it_and_inserted = entries_.emplace(std::move(item));
next_id++;
- Entry& entry = const_cast<Entry&>(*itr_and_inserted.first);
+ it = it_and_inserted.first;
+ PERFETTO_DCHECK(it_and_inserted.second);
+ }
+ Entry& entry = const_cast<Entry&>(*it);
entry.ref_count++;
return Interned(&entry);
}
@@ -104,7 +122,7 @@
entries_.erase(*entry);
}
uint64_t next_id = 1;
- std::set<Entry> entries_;
+ std::unordered_set<Entry, typename Entry::Hash> entries_;
static_assert(sizeof(Interned) == sizeof(void*),
"interned things should be small");
};
diff --git a/src/profiling/memory/interner_unittest.cc b/src/profiling/memory/interner_unittest.cc
index dd166cb..6b239fd 100644
--- a/src/profiling/memory/interner_unittest.cc
+++ b/src/profiling/memory/interner_unittest.cc
@@ -129,25 +129,6 @@
ASSERT_EQ(interner.entry_count_for_testing(), 0);
}
-class NoCopyOrMove {
- public:
- NoCopyOrMove(const NoCopyOrMove&) = delete;
- NoCopyOrMove& operator=(const NoCopyOrMove&) = delete;
- NoCopyOrMove(const NoCopyOrMove&&) = delete;
- NoCopyOrMove& operator=(const NoCopyOrMove&&) = delete;
- NoCopyOrMove(int d) : data(d) {}
- ~NoCopyOrMove() {}
- bool operator<(const NoCopyOrMove& other) const { return data < other.data; }
-
- private:
- int data;
-};
-
-TEST(InternerStringTest, NoCopyOrMove) {
- Interner<NoCopyOrMove> interner;
- Interned<NoCopyOrMove> interned_str = interner.Intern(1);
-}
-
} // namespace
} // namespace profiling
} // namespace perfetto