| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATOR_H_ | 5 #ifndef BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATOR_H_ |
| 6 #define BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATOR_H_ | 6 #define BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATOR_H_ |
| 7 | 7 |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <array> | 10 #include <array> |
| 11 #include <deque> |
| 11 #include <list> | 12 #include <list> |
| 12 #include <map> | 13 #include <map> |
| 13 #include <memory> | 14 #include <memory> |
| 15 #include <queue> |
| 14 #include <set> | 16 #include <set> |
| 17 #include <stack> |
| 15 #include <string> | 18 #include <string> |
| 16 #include <type_traits> | 19 #include <type_traits> |
| 17 #include <unordered_map> | 20 #include <unordered_map> |
| 18 #include <unordered_set> | 21 #include <unordered_set> |
| 19 #include <vector> | 22 #include <vector> |
| 20 | 23 |
| 21 #include "base/base_export.h" | 24 #include "base/base_export.h" |
| 22 #include "base/strings/string16.h" | 25 #include "base/strings/string16.h" |
| 23 #include "base/template_util.h" | 26 #include "base/template_util.h" |
| 24 | 27 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 | 128 |
| 126 template <class T, class H, class KE, class A> | 129 template <class T, class H, class KE, class A> |
| 127 size_t EstimateMemoryUsage(const std::unordered_multiset<T, H, KE, A>& set); | 130 size_t EstimateMemoryUsage(const std::unordered_multiset<T, H, KE, A>& set); |
| 128 | 131 |
| 129 template <class K, class V, class H, class KE, class A> | 132 template <class K, class V, class H, class KE, class A> |
| 130 size_t EstimateMemoryUsage(const std::unordered_map<K, V, H, KE, A>& map); | 133 size_t EstimateMemoryUsage(const std::unordered_map<K, V, H, KE, A>& map); |
| 131 | 134 |
| 132 template <class K, class V, class H, class KE, class A> | 135 template <class K, class V, class H, class KE, class A> |
| 133 size_t EstimateMemoryUsage(const std::unordered_multimap<K, V, H, KE, A>& map); | 136 size_t EstimateMemoryUsage(const std::unordered_multimap<K, V, H, KE, A>& map); |
| 134 | 137 |
| 138 template <class T, class A> |
| 139 size_t EstimateMemoryUsage(const std::deque<T, A>& deque); |
| 140 |
| 141 template <class T, class C> |
| 142 size_t EstimateMemoryUsage(const std::queue<T, C>& queue); |
| 143 |
| 144 template <class T, class C> |
| 145 size_t EstimateMemoryUsage(const std::priority_queue<T, C>& queue); |
| 146 |
| 147 template <class T, class C> |
| 148 size_t EstimateMemoryUsage(const std::stack<T, C>& stack); |
| 149 |
| 135 // TODO(dskiba): | 150 // TODO(dskiba): |
| 136 // std::forward_list | 151 // std::forward_list |
| 137 // std::deque | |
| 138 // std::queue | |
| 139 // std::stack | |
| 140 // std::queue | |
| 141 // std::priority_queue | |
| 142 | 152 |
| 143 // Definitions | 153 // Definitions |
| 144 | 154 |
| 145 namespace internal { | 155 namespace internal { |
| 146 | 156 |
| 147 // HasEMU<T>::value is true iff EstimateMemoryUsage(T) is available. | 157 // HasEMU<T>::value is true iff EstimateMemoryUsage(T) is available. |
| 148 // (This is the default version, which is false.) | 158 // (This is the default version, which is false.) |
| 149 template <class T, class X = void> | 159 template <class T, class X = void> |
| 150 struct HasEMU : std::false_type {}; | 160 struct HasEMU : std::false_type {}; |
| 151 | 161 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 }; | 200 }; |
| 191 | 201 |
| 192 template <class T> | 202 template <class T> |
| 193 struct EMUCaller< | 203 struct EMUCaller< |
| 194 T, | 204 T, |
| 195 typename std::enable_if<!HasEMU<T>::value && | 205 typename std::enable_if<!HasEMU<T>::value && |
| 196 is_trivially_destructible<T>::value>::type> { | 206 is_trivially_destructible<T>::value>::type> { |
| 197 static size_t Call(const T& value) { return 0; } | 207 static size_t Call(const T& value) { return 0; } |
| 198 }; | 208 }; |
| 199 | 209 |
| 210 // Returns reference to the underlying container of a container adapter. |
| 211 // Works for std::stack, std::queue and std::priority_queue. |
| 212 template <class A> |
| 213 const typename A::container_type& GetUnderlyingContainer(const A& adapter) { |
| 214 struct ExposedAdapter : A { |
| 215 using A::c; |
| 216 }; |
| 217 return adapter.*&ExposedAdapter::c; |
| 218 } |
| 219 |
| 200 } // namespace internal | 220 } // namespace internal |
| 201 | 221 |
| 202 // Proxy that deducts T and calls EMUCaller<T>. | 222 // Proxy that deducts T and calls EMUCaller<T>. |
| 203 // To be used by EstimateMemoryUsage() implementations for containers. | 223 // To be used by EstimateMemoryUsage() implementations for containers. |
| 204 template <class T> | 224 template <class T> |
| 205 size_t EstimateItemMemoryUsage(const T& value) { | 225 size_t EstimateItemMemoryUsage(const T& value) { |
| 206 return internal::EMUCaller<T>::Call(value); | 226 return internal::EMUCaller<T>::Call(value); |
| 207 } | 227 } |
| 208 | 228 |
| 209 template <class I> | 229 template <class I> |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 | 452 |
| 433 template <class K, class V, class H, class KE, class A> | 453 template <class K, class V, class H, class KE, class A> |
| 434 size_t EstimateMemoryUsage(const std::unordered_multimap<K, V, H, KE, A>& map) { | 454 size_t EstimateMemoryUsage(const std::unordered_multimap<K, V, H, KE, A>& map) { |
| 435 using value_type = | 455 using value_type = |
| 436 typename std::unordered_multimap<K, V, H, KE, A>::value_type; | 456 typename std::unordered_multimap<K, V, H, KE, A>::value_type; |
| 437 return EstimateHashMapMemoryUsage<value_type>(map.bucket_count(), | 457 return EstimateHashMapMemoryUsage<value_type>(map.bucket_count(), |
| 438 map.size()) + | 458 map.size()) + |
| 439 EstimateIterableMemoryUsage(map); | 459 EstimateIterableMemoryUsage(map); |
| 440 } | 460 } |
| 441 | 461 |
| 462 // std::deque |
| 463 |
| 464 template <class T, class A> |
| 465 size_t EstimateMemoryUsage(const std::deque<T, A>& deque) { |
| 466 // Since std::deque implementations are wildly different |
| 467 // (see crbug.com/674287), we can't have one "good enough" |
| 468 // way to estimate. |
| 469 |
| 470 // kBlockSize - minimum size of a block, in bytes |
| 471 // kMinBlockLength - number of elements in a block |
| 472 // if sizeof(T) > kBlockSize |
| 473 #if defined(_LIBCPP_VERSION) |
| 474 size_t kBlockSize = 4096; |
| 475 size_t kMinBlockLength = 16; |
| 476 #elif defined(__GLIBCXX__) |
| 477 size_t kBlockSize = 512; |
| 478 size_t kMinBlockLength = 1; |
| 479 #elif defined(_MSC_VER) |
| 480 size_t kBlockSize = 16; |
| 481 size_t kMinBlockLength = 1; |
| 482 #else |
| 483 size_t kBlockSize = 0; |
| 484 size_t kMinBlockLength = 1; |
| 485 #endif |
| 486 |
| 487 size_t block_length = |
| 488 (sizeof(T) > kBlockSize) ? kMinBlockLength : kBlockSize / sizeof(T); |
| 489 |
| 490 size_t blocks = (deque.size() + block_length - 1) / block_length; |
| 491 |
| 492 #if defined(__GLIBCXX__) |
| 493 // libstdc++: deque always has at least one block |
| 494 if (!blocks) |
| 495 blocks = 1; |
| 496 #endif |
| 497 |
| 498 #if defined(_LIBCPP_VERSION) |
| 499 // libc++: deque keeps at most two blocks when it shrinks, |
| 500 // so even if the size is zero, deque might be holding up |
| 501 // to 4096 * 2 bytes. One way to know whether deque has |
| 502 // ever allocated (and hence has 1 or 2 blocks) is to check |
| 503 // iterator's pointer. Non-zero value means that deque has |
| 504 // at least one block. |
| 505 if (!blocks && deque.begin().operator->()) |
| 506 blocks = 1; |
| 507 #endif |
| 508 |
| 509 return (blocks * block_length * sizeof(T)) + |
| 510 EstimateIterableMemoryUsage(deque); |
| 511 } |
| 512 |
| 513 // Container adapters |
| 514 |
| 515 template <class T, class C> |
| 516 size_t EstimateMemoryUsage(const std::queue<T, C>& queue) { |
| 517 return EstimateMemoryUsage(internal::GetUnderlyingContainer(queue)); |
| 518 } |
| 519 |
| 520 template <class T, class C> |
| 521 size_t EstimateMemoryUsage(const std::priority_queue<T, C>& queue) { |
| 522 return EstimateMemoryUsage(internal::GetUnderlyingContainer(queue)); |
| 523 } |
| 524 |
| 525 template <class T, class C> |
| 526 size_t EstimateMemoryUsage(const std::stack<T, C>& stack) { |
| 527 return EstimateMemoryUsage(internal::GetUnderlyingContainer(stack)); |
| 528 } |
| 529 |
| 442 } // namespace trace_event | 530 } // namespace trace_event |
| 443 } // namespace base | 531 } // namespace base |
| 444 | 532 |
| 445 #endif // BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATOR_H_ | 533 #endif // BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATOR_H_ |
| OLD | NEW |