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