memory.hpp (6167B)
1 /* Relacy Race Detector 2 * Copyright (c) 2008-2013, Dmitry S. Vyukov 3 * All rights reserved. 4 * This software is provided AS-IS with no warranty, either express or implied. 5 * This software is distributed under a license and may not be copied, 6 * modified or distributed except as expressly authorized under the 7 * terms of the license contained in the file LICENSE in this distribution. 8 */ 9 10 #ifndef RL_MEMORY_HPP 11 #define RL_MEMORY_HPP 12 #ifdef _MSC_VER 13 # pragma once 14 #endif 15 16 #include "base.hpp" 17 18 19 namespace rl 20 { 21 22 23 class memory_mgr : nocopy<> 24 { 25 public: 26 memory_mgr() 27 { 28 memset(deferred_free_, 0, sizeof(deferred_free_)); 29 memset(deferred_free_size_, 0, sizeof(deferred_free_size_)); 30 deferred_index_ = 0; 31 } 32 33 ~memory_mgr() 34 { 35 /* 36 while (allocs_.size()) 37 { 38 size_t* p = (size_t*)(allocs_.begin()->first); 39 free(p - 1, false); 40 allocs_.erase(allocs_.begin()); 41 } 42 */ 43 } 44 45 #ifndef RL_GC 46 void* alloc(size_t size) 47 #else 48 void* alloc(size_t size, void (*dtor)(void*)) 49 #endif 50 { 51 void* pp = 0; 52 for (size_t i = 0; i != alloc_cache_.size(); ++i) 53 { 54 if (alloc_cache_[i].first == size) 55 { 56 if (alloc_cache_[i].second.size()) 57 { 58 pp = alloc_cache_[i].second.top(); 59 alloc_cache_[i].second.pop(); 60 } 61 break; 62 } 63 } 64 if (0 == pp) 65 pp = (::malloc)(size + alignment); 66 67 if (pp) 68 { 69 RL_VERIFY(alignment >= sizeof(void*)); 70 *(size_t*)pp = size; 71 void* p = (char*)pp + alignment; 72 #ifndef RL_GC 73 allocs_.insert(std::make_pair(p, size)); 74 #else 75 alloc_desc_t desc = {p, size, dtor}; 76 gc_allocs_.push_back(desc); 77 #endif 78 return p; 79 } 80 else 81 { 82 throw std::bad_alloc(); 83 } 84 } 85 86 bool free(void* pp, bool defer) 87 { 88 if (0 == pp) 89 return true; 90 91 #ifndef RL_GC 92 map<void*, size_t>::type::iterator iter = allocs_.find(pp); 93 if (allocs_.end() == iter) 94 return false; 95 96 allocs_.erase(iter); 97 98 void* p = (char*)pp - alignment; 99 size_t size = *(size_t*)p; 100 101 if (defer) 102 { 103 deferred_free_[deferred_index_ % deferred_count] = p; 104 deferred_free_size_[deferred_index_ % deferred_count] = size; 105 deferred_index_ += 1; 106 p = deferred_free_[deferred_index_ % deferred_count]; 107 size = deferred_free_size_[deferred_index_ % deferred_count]; 108 if (p) 109 rl_free_impl(p, size); 110 } 111 else 112 { 113 rl_free_impl(p, size); 114 } 115 return true; 116 #else 117 (void)defer; 118 for (size_t i = 0; i != gc_allocs_.size(); ++i) 119 { 120 alloc_desc_t const& desc = gc_allocs_[i]; 121 if (desc.addr == pp) 122 { 123 void* p = (char*)desc.addr - alignment; 124 rl_free_impl(p, desc.size); 125 gc_allocs_.erase(gc_allocs_.begin() + i); 126 return true; 127 } 128 } 129 return false; 130 #endif 131 } 132 133 bool iteration_end() 134 { 135 #ifndef RL_GC 136 return allocs_.empty(); 137 #else 138 for (size_t i = 0; i != gc_allocs_.size(); ++i) 139 { 140 alloc_desc_t const& desc = gc_allocs_[i]; 141 if (desc.dtor) 142 desc.dtor(desc.addr); 143 void* p = (char*)desc.addr - alignment; 144 rl_free_impl(p, desc.size); 145 } 146 gc_allocs_.clear(); 147 return true; 148 #endif 149 } 150 151 #ifndef RL_GC 152 void output_allocs(std::ostream& stream) 153 { 154 stream << "memory allocations:" << std::endl; 155 map<void*, size_t>::type::iterator iter = allocs_.begin(); 156 map<void*, size_t>::type::iterator end = allocs_.end(); 157 for (; iter != end; ++iter) 158 { 159 stream << iter->first << " [" << (unsigned)iter->second << "]" << std::endl; 160 } 161 stream << std::endl; 162 } 163 #endif 164 165 private: 166 typedef stack<void*>::type freelist_t; 167 typedef std::pair<size_t, freelist_t> alloc_entry_t; 168 typedef vector<alloc_entry_t>::type alloc_t; 169 170 static size_t const deferred_count = 64; 171 172 alloc_t alloc_cache_; 173 size_t deferred_index_; 174 void* deferred_free_ [deferred_count]; 175 size_t deferred_free_size_ [deferred_count]; 176 177 #ifndef RL_GC 178 map<void*, size_t>::type allocs_; 179 #else 180 struct alloc_desc_t 181 { 182 void* addr; 183 size_t size; 184 void (*dtor)(void*); 185 }; 186 vector<alloc_desc_t>::type gc_allocs_; 187 #endif 188 189 void rl_free_impl(void* p, size_t size) 190 { 191 bool found = false; 192 for (size_t i = 0; i != alloc_cache_.size(); ++i) 193 { 194 if (alloc_cache_[i].first == size) 195 { 196 found = true; 197 alloc_cache_[i].second.push(p); 198 break; 199 } 200 } 201 if (!found) 202 { 203 alloc_cache_.push_back(std::make_pair(size, freelist_t())); 204 alloc_cache_.back().second.push(p); 205 } 206 } 207 }; 208 209 210 211 212 struct memory_alloc_event 213 { 214 void* addr_; 215 size_t size_; 216 bool is_array_; 217 218 void output(std::ostream& s) const 219 { 220 s << "memory allocation: addr=" << std::hex << (void*)((char*)addr_ + (is_array_ ? alignment : 0)) << std::dec 221 << ", size=" << (unsigned)size_; 222 } 223 }; 224 225 226 struct memory_free_event 227 { 228 void* addr_; 229 bool is_array_; 230 231 void output(std::ostream& s) const 232 { 233 s << "memory deallocation: addr=" << std::hex << (void*)((char*)addr_ + (is_array_ ? alignment : 0)) << std::dec; 234 } 235 }; 236 237 238 239 } 240 241 #endif