reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef CONTENT_COMMON_DISCARDABLE_SHARED_MEMORY_HEAP_H_ |
| 6 | #define CONTENT_COMMON_DISCARDABLE_SHARED_MEMORY_HEAP_H_ |
| 7 | |
avi | a9aa7a8 | 2015-12-25 03:06:31 | [diff] [blame] | 8 | #include <stddef.h> |
| 9 | #include <stdint.h> |
| 10 | |
reveman | 1500e1a7 | 2015-03-17 02:31:30 | [diff] [blame] | 11 | #include "base/callback.h" |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 12 | #include "base/containers/hash_tables.h" |
| 13 | #include "base/containers/linked_list.h" |
avi | a9aa7a8 | 2015-12-25 03:06:31 | [diff] [blame] | 14 | #include "base/macros.h" |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 15 | #include "base/memory/scoped_ptr.h" |
| 16 | #include "base/memory/scoped_vector.h" |
ssid | 3c7fbd4b | 2015-05-05 17:43:00 | [diff] [blame] | 17 | #include "base/trace_event/process_memory_dump.h" |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 18 | #include "content/common/content_export.h" |
| 19 | |
| 20 | namespace base { |
| 21 | class DiscardableSharedMemory; |
| 22 | } |
| 23 | |
| 24 | namespace content { |
| 25 | |
reveman | 3e0e72c0 | 2015-03-11 03:55:59 | [diff] [blame] | 26 | // Implements a heap of discardable shared memory. An array of free lists |
| 27 | // is used to keep track of free blocks. |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 28 | class CONTENT_EXPORT DiscardableSharedMemoryHeap { |
| 29 | public: |
| 30 | class CONTENT_EXPORT Span : public base::LinkNode<Span> { |
| 31 | public: |
| 32 | ~Span(); |
| 33 | |
reveman | 549bd27a | 2015-02-18 02:52:19 | [diff] [blame] | 34 | base::DiscardableSharedMemory* shared_memory() { return shared_memory_; } |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 35 | size_t start() const { return start_; } |
| 36 | size_t length() const { return length_; } |
ssid | b16ac46 | 2015-10-13 20:10:27 | [diff] [blame] | 37 | void set_is_locked(bool is_locked) { is_locked_ = is_locked; } |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 38 | |
| 39 | private: |
| 40 | friend class DiscardableSharedMemoryHeap; |
| 41 | |
reveman | 549bd27a | 2015-02-18 02:52:19 | [diff] [blame] | 42 | Span(base::DiscardableSharedMemory* shared_memory, |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 43 | size_t start, |
| 44 | size_t length); |
| 45 | |
reveman | 549bd27a | 2015-02-18 02:52:19 | [diff] [blame] | 46 | base::DiscardableSharedMemory* shared_memory_; |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 47 | size_t start_; |
| 48 | size_t length_; |
ssid | b16ac46 | 2015-10-13 20:10:27 | [diff] [blame] | 49 | bool is_locked_; |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 50 | |
| 51 | DISALLOW_COPY_AND_ASSIGN(Span); |
| 52 | }; |
| 53 | |
| 54 | explicit DiscardableSharedMemoryHeap(size_t block_size); |
| 55 | ~DiscardableSharedMemoryHeap(); |
| 56 | |
reveman | 549bd27a | 2015-02-18 02:52:19 | [diff] [blame] | 57 | // Grow heap using |shared_memory| and return a span for this new memory. |
| 58 | // |shared_memory| must be aligned to the block size and |size| must be a |
reveman | 1500e1a7 | 2015-03-17 02:31:30 | [diff] [blame] | 59 | // multiple of the block size. |deleted_callback| is called when |
| 60 | // |shared_memory| has been deleted. |
reveman | 549bd27a | 2015-02-18 02:52:19 | [diff] [blame] | 61 | scoped_ptr<Span> Grow(scoped_ptr<base::DiscardableSharedMemory> shared_memory, |
reveman | 1500e1a7 | 2015-03-17 02:31:30 | [diff] [blame] | 62 | size_t size, |
ssid | 3c7fbd4b | 2015-05-05 17:43:00 | [diff] [blame] | 63 | int32_t id, |
reveman | 1500e1a7 | 2015-03-17 02:31:30 | [diff] [blame] | 64 | const base::Closure& deleted_callback); |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 65 | |
reveman | 3e0e72c0 | 2015-03-11 03:55:59 | [diff] [blame] | 66 | // Merge |span| into the free lists. This will coalesce |span| with |
| 67 | // neighboring free spans when possible. |
| 68 | void MergeIntoFreeLists(scoped_ptr<Span> span); |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 69 | |
| 70 | // Split an allocated span into two spans, one of length |blocks| followed |
| 71 | // by another span of length "span->length - blocks" blocks. Modifies |span| |
| 72 | // to point to the first span of length |blocks|. Return second span. |
| 73 | scoped_ptr<Span> Split(Span* span, size_t blocks); |
| 74 | |
reveman | 3e0e72c0 | 2015-03-11 03:55:59 | [diff] [blame] | 75 | // Search free lists for span that satisfies the request for |blocks| of |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 76 | // memory. If found, the span is removed from the free list and returned. |
reveman | 3e0e72c0 | 2015-03-11 03:55:59 | [diff] [blame] | 77 | // |slack| determines the fitness requirement. Only spans that are less |
| 78 | // or equal to |blocks| + |slack| are considered, worse fitting spans are |
| 79 | // ignored. |
| 80 | scoped_ptr<Span> SearchFreeLists(size_t blocks, size_t slack); |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 81 | |
reveman | 2ce0228 | 2015-03-09 23:57:26 | [diff] [blame] | 82 | // Release free shared memory segments. |
| 83 | void ReleaseFreeMemory(); |
| 84 | |
| 85 | // Release shared memory segments that have been purged. |
| 86 | void ReleasePurgedMemory(); |
| 87 | |
| 88 | // Returns total bytes of memory in heap. |
| 89 | size_t GetSize() const; |
| 90 | |
reveman | 3e0e72c0 | 2015-03-11 03:55:59 | [diff] [blame] | 91 | // Returns bytes of memory currently in the free lists. |
| 92 | size_t GetSizeOfFreeLists() const; |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 93 | |
ssid | 3c7fbd4b | 2015-05-05 17:43:00 | [diff] [blame] | 94 | // Dumps memory statistics for chrome://tracing. |
| 95 | bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd); |
| 96 | |
primiano | c255f38d | 2015-07-01 16:17:47 | [diff] [blame] | 97 | // Returns a unique identifier for a given tuple of (process id, segment id) |
| 98 | // that can be used to match memory dumps across different processes. |
| 99 | static base::trace_event::MemoryAllocatorDumpGuid GetSegmentGUIDForTracing( |
avi | a9aa7a8 | 2015-12-25 03:06:31 | [diff] [blame] | 100 | uint64_t tracing_process_id, |
| 101 | int32_t segment_id); |
primiano | c255f38d | 2015-07-01 16:17:47 | [diff] [blame] | 102 | |
ssid | 3e37155 | 2015-08-25 15:33:20 | [diff] [blame] | 103 | // Returns a MemoryAllocatorDump for a given span on |pmd| with the size of |
| 104 | // the span. |
| 105 | base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( |
| 106 | Span* span, |
| 107 | const char* name, |
| 108 | base::trace_event::ProcessMemoryDump* pmd) const; |
| 109 | |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 110 | private: |
reveman | 2ce0228 | 2015-03-09 23:57:26 | [diff] [blame] | 111 | class ScopedMemorySegment { |
| 112 | public: |
| 113 | ScopedMemorySegment(DiscardableSharedMemoryHeap* heap, |
| 114 | scoped_ptr<base::DiscardableSharedMemory> shared_memory, |
reveman | 1500e1a7 | 2015-03-17 02:31:30 | [diff] [blame] | 115 | size_t size, |
ssid | 3c7fbd4b | 2015-05-05 17:43:00 | [diff] [blame] | 116 | int32_t id, |
reveman | 1500e1a7 | 2015-03-17 02:31:30 | [diff] [blame] | 117 | const base::Closure& deleted_callback); |
reveman | 2ce0228 | 2015-03-09 23:57:26 | [diff] [blame] | 118 | ~ScopedMemorySegment(); |
| 119 | |
| 120 | bool IsUsed() const; |
| 121 | bool IsResident() const; |
| 122 | |
ssid | 3e37155 | 2015-08-25 15:33:20 | [diff] [blame] | 123 | bool ContainsSpan(Span* span) const; |
| 124 | |
| 125 | base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( |
| 126 | Span* span, |
ssid | 053b1f2 | 2015-08-27 11:14:59 | [diff] [blame] | 127 | size_t block_size, |
ssid | 3e37155 | 2015-08-25 15:33:20 | [diff] [blame] | 128 | const char* name, |
| 129 | base::trace_event::ProcessMemoryDump* pmd) const; |
| 130 | |
ssid | 3c7fbd4b | 2015-05-05 17:43:00 | [diff] [blame] | 131 | // Used for dumping memory statistics from the segment to chrome://tracing. |
| 132 | void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) const; |
| 133 | |
reveman | 2ce0228 | 2015-03-09 23:57:26 | [diff] [blame] | 134 | private: |
| 135 | DiscardableSharedMemoryHeap* const heap_; |
| 136 | scoped_ptr<base::DiscardableSharedMemory> shared_memory_; |
| 137 | const size_t size_; |
ssid | 3c7fbd4b | 2015-05-05 17:43:00 | [diff] [blame] | 138 | const int32_t id_; |
reveman | 1500e1a7 | 2015-03-17 02:31:30 | [diff] [blame] | 139 | const base::Closure deleted_callback_; |
reveman | 2ce0228 | 2015-03-09 23:57:26 | [diff] [blame] | 140 | |
| 141 | DISALLOW_COPY_AND_ASSIGN(ScopedMemorySegment); |
| 142 | }; |
| 143 | |
reveman | 3e0e72c0 | 2015-03-11 03:55:59 | [diff] [blame] | 144 | void InsertIntoFreeList(scoped_ptr<Span> span); |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 145 | scoped_ptr<Span> RemoveFromFreeList(Span* span); |
| 146 | scoped_ptr<Span> Carve(Span* span, size_t blocks); |
| 147 | void RegisterSpan(Span* span); |
reveman | 549bd27a | 2015-02-18 02:52:19 | [diff] [blame] | 148 | void UnregisterSpan(Span* span); |
reveman | 2ce0228 | 2015-03-09 23:57:26 | [diff] [blame] | 149 | bool IsMemoryUsed(const base::DiscardableSharedMemory* shared_memory, |
| 150 | size_t size); |
| 151 | bool IsMemoryResident(const base::DiscardableSharedMemory* shared_memory); |
| 152 | void ReleaseMemory(const base::DiscardableSharedMemory* shared_memory, |
| 153 | size_t size); |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 154 | |
ssid | 3c7fbd4b | 2015-05-05 17:43:00 | [diff] [blame] | 155 | // Dumps memory statistics about a memory segment for chrome://tracing. |
| 156 | void OnMemoryDump(const base::DiscardableSharedMemory* shared_memory, |
| 157 | size_t size, |
primiano | c255f38d | 2015-07-01 16:17:47 | [diff] [blame] | 158 | int32_t segment_id, |
ssid | 3c7fbd4b | 2015-05-05 17:43:00 | [diff] [blame] | 159 | base::trace_event::ProcessMemoryDump* pmd); |
| 160 | |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 161 | size_t block_size_; |
reveman | 2ce0228 | 2015-03-09 23:57:26 | [diff] [blame] | 162 | size_t num_blocks_; |
| 163 | size_t num_free_blocks_; |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 164 | |
reveman | 2ce0228 | 2015-03-09 23:57:26 | [diff] [blame] | 165 | // Vector of memory segments. |
| 166 | ScopedVector<ScopedMemorySegment> memory_segments_; |
reveman | 549bd27a | 2015-02-18 02:52:19 | [diff] [blame] | 167 | |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 168 | // Mapping from first/last block of span to Span instance. |
| 169 | typedef base::hash_map<size_t, Span*> SpanMap; |
| 170 | SpanMap spans_; |
| 171 | |
reveman | 3e0e72c0 | 2015-03-11 03:55:59 | [diff] [blame] | 172 | // Array of linked-lists with free discardable memory regions. For i < 256, |
| 173 | // where the 1st entry is located at index 0 of the array, the kth entry |
| 174 | // is a free list of runs that consist of k blocks. The 256th entry is a |
| 175 | // free list of runs that have length >= 256 blocks. |
| 176 | base::LinkedList<Span> free_spans_[256]; |
reveman | 94ff17c | 2014-12-24 00:52:30 | [diff] [blame] | 177 | |
| 178 | DISALLOW_COPY_AND_ASSIGN(DiscardableSharedMemoryHeap); |
| 179 | }; |
| 180 | |
| 181 | } // namespace content |
| 182 | |
| 183 | #endif // CONTENT_COMMON_DISCARDABLE_SHARED_MEMORY_HEAP_H_ |