Index: base/trace_event/memory_usage_estimators.h |
diff --git a/base/trace_event/memory_usage_estimators.h b/base/trace_event/memory_usage_estimators.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f49094f0b19e6cac1db5035f275d77707b094e65 |
--- /dev/null |
+++ b/base/trace_event/memory_usage_estimators.h |
@@ -0,0 +1,193 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATORS_H_ |
+#define BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATORS_H_ |
+ |
+#include <memory> |
+#include <set> |
+#include <string> |
+#include <type_traits> |
+#include <unordered_map> |
+#include <vector> |
+ |
+#include "base/strings/string16.h" |
+ |
+namespace base { |
+namespace trace_event { |
+ |
+inline size_t EstimateMemoryUsage(const std::string& string) { |
+#if defined(__GLIBCXX__) && _GLIBCXX_USE_CXX11_ABI == 0 |
+ // libstdc++ with COW std::string - each string allocates a header |
+ // (see std::basic_string::_Rep_base). We don't take into account |
+ // number of references, but we do handle 'empty string' case. |
+ struct _Rep_base { |
+ std::basic_string::size_type length; |
+ std::basic_string::size_type capacity; |
+ int refcount; |
+ }; |
+ static const char* empty_cstr = nullptr; |
+ if (!empty_cstr) empty_cstr = std::string().c_str(); |
+ return (string.c_str() == empty_cstr) ? |
+ 0 : |
+ sizeof(_Rep_base) + (string.capacity() + 1); |
+#else |
+ const char* cstr = string.c_str(); |
+ const char* inline_cstr = reinterpret_cast<const char*>(&string); |
+ if (cstr >= inline_cstr && cstr < inline_cstr + sizeof(string)) { |
+ // Inline string |
+ return 0; |
+ } |
+ return string.capacity(); |
+#endif |
+} |
+ |
+// TODO(dskiba): EstimateMemoryUsage(std::basic_string<T>) |
+inline size_t EstimateMemoryUsage(const base::string16& string) { |
+#if defined(__GLIBCXX__) && _GLIBCXX_USE_CXX11_ABI == 0 |
+ // See comment in EstimateMemoryUsage(std::string). |
+ static const char16* empty_cstr = nullptr; |
+ if (!empty_cstr) empty_cstr = base::string16().c_str(); |
+ return (string.c_str() == empty_cstr) ? |
+ 0 : |
+ 3 * sizeof(size_t) + (string.capacity() + 1) * sizeof(char16); |
+#else |
+ const char* cstr = reinterpret_cast<const char*>(string.c_str()); |
+ const char* inline_cstr = reinterpret_cast<const char*>(&string); |
+ if (cstr >= inline_cstr && cstr < inline_cstr + sizeof(string)) { |
+ // Inline string |
+ return 0; |
+ } |
+ return string.capacity() * sizeof(char16); |
+#endif |
+} |
+ |
+template <class T> |
+typename std::enable_if< |
+ std::is_arithmetic<T>::value || std::is_enum<T>::value, |
+ size_t>::type |
+EstimateMemoryUsage(T) { return 0; } |
+ |
+template <class T> |
+auto EstimateMemoryUsage(const T& object) -> |
+ decltype(object.EstimateMemoryUsage()) { |
+ static_assert(std::is_same<decltype(object.EstimateMemoryUsage()), |
+ size_t>::value, |
+ "EstimateMemoryUsage() must return size_t"); |
+ return object.EstimateMemoryUsage(); |
+} |
+ |
+// Any template that recursively calls EstimateMemoryUsage() should be |
+// declared here first. |
+ |
+template <class T> |
+size_t EstimateMemoryUsage(const std::unique_ptr<T>& ptr); |
+ |
+template <class F, class S> |
+size_t EstimateMemoryUsage(const std::pair<F, S>& pair); |
+ |
+template <class T, size_t N> |
+size_t EstimateMemoryUsage(T (&array)[N]); |
+ |
+template <class T, class A> |
+size_t EstimateMemoryUsage(const std::vector<T, A>& vector); |
+ |
+template <class T, class C, class A> |
+size_t EstimateMemoryUsage(const std::set<T, C, A>& set); |
+ |
+template <class K, class V, class H, class KE, class A> |
+size_t EstimateMemoryUsage( |
+ const std::unordered_map<K, V, H, KE, A>& map); |
+ |
+// Definitions |
+ |
+template <class T> |
+size_t InternalEstimateItemMemoryUsage(T* pointer) { |
+ // By default pointers treated as not owning |
+ return 0; |
+} |
+ |
+template <class T> |
+size_t InternalEstimateItemMemoryUsage(const T& value) { |
+ return EstimateMemoryUsage(value); |
+} |
+ |
+template <class T> |
+size_t EstimateMemoryUsage(const std::unique_ptr<T>& ptr) { |
+ return ptr ? (sizeof(T) + EstimateMemoryUsage(*ptr)) : 0; |
+} |
+ |
+template <class F, class S> |
+size_t EstimateMemoryUsage(const std::pair<F, S>& pair) { |
+ return EstimateMemoryUsage(pair.first) + |
+ EstimateMemoryUsage(pair.second); |
+} |
+ |
+template <class T, size_t N> |
+size_t EstimateMemoryUsage(T (&array)[N]) { |
+ size_t memory_usage = 0; |
+ for (const auto& item: array) { |
+ memory_usage += EstimateMemoryUsage(item); |
+ } |
+ return memory_usage; |
+} |
+ |
+template <class T, class A> |
+size_t EstimateMemoryUsage(const std::vector<T, A>& vector) { |
+ size_t memory_usage = vector.capacity() * sizeof(T); |
+ for (const auto& element: vector) { |
+ memory_usage += EstimateMemoryUsage(element); |
+ } |
+ return memory_usage; |
+} |
+ |
+template <class T, class C, class A> |
+size_t EstimateMemoryUsage(const std::set<T, C, A>& set) { |
+ // TODO(dskiba): revisit, likely not accurate enough |
+ size_t memory_usage = set.size() * sizeof(T); |
+ for (const auto& element: set) { |
+ memory_usage += EstimateMemoryUsage(element); |
+ } |
+ return memory_usage; |
+} |
+ |
+template <class K, class V, class H, class KE, class A> |
+size_t InternalEstimateShallowMemoryUsage( |
+ const std::unordered_map<K, V, H, KE, A>& map) { |
+ struct Node { |
+ typename std::unordered_map<K, V, H, KE, A>::value_type value; |
+ Node* next; |
+ Node* prev; |
+ }; |
+ using Bucket = Node*; |
+ return map.bucket_count() * sizeof(Bucket) + map.size() * sizeof(Node); |
+} |
+ |
+template <class K, class V, class H, class KE, class A> |
+size_t EstimateMemoryUsage( |
+ const std::unordered_map<K, V, H, KE, A>& map) { |
+ size_t memory_usage = InternalEstimateShallowMemoryUsage(map); |
+ for (const auto& item: map) { |
+ memory_usage += InternalEstimateItemMemoryUsage(item.first) + |
+ InternalEstimateItemMemoryUsage(item.second); |
+ } |
+ return memory_usage; |
+} |
+ |
+template <class K, class V, class H, class KE, class A, class Estimator> |
+size_t EstimateMemoryUsage( |
+ const std::unordered_map<K, V, H, KE, A>& map, |
+ Estimator estimator) { |
+ size_t memory_usage = InternalEstimateShallowMemoryUsage(map); |
+ for (const auto& item: map) { |
+ memory_usage += estimator(item.first) + |
+ estimator(item.second); |
+ } |
+ return memory_usage; |
+} |
+ |
+} // namespace trace_event |
+} // namespace base |
+ |
+#endif // BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATORS_H_ |