Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: base/allocator/allocator_shim.cc

Issue 47873005: Cleanup allocator_shim.cc from ENABLE_DYNAMIC_ALLOCATOR_SWITCHING (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 #include "base/allocator/allocator_shim.h" 5 #include "base/allocator/allocator_shim.h"
6 6
7 #include <config.h> 7 #include <config.h>
8 #include "base/allocator/allocator_extension_thunks.h" 8 #include "base/allocator/allocator_extension_thunks.h"
9 #include "base/logging.h"
9 #include "base/profiler/alternate_timer.h" 10 #include "base/profiler/alternate_timer.h"
10 #include "base/sysinfo.h" 11 #include "base/sysinfo.h"
11 #include "jemalloc.h" 12 #include "jemalloc.h"
12 13
13 // When defined, different heap allocators can be used via an environment 14 // This shim make it possible to use different allocators via an environment
14 // variable set before running the program. This may reduce the amount 15 // variable set before running the program. This may reduce the
15 // of inlining that we get with malloc/free/etc. Disabling makes it 16 // amount of inlining that we get with malloc/free/etc.
16 // so that only tcmalloc can be used.
17 #define ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
18 17
19 // TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth 18 // TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth
20 // from the "user code" so that debugging tools (HeapChecker) can work. 19 // from the "user code" so that debugging tools (HeapChecker) can work.
21 20
22 // __THROW is defined in glibc systems. It means, counter-intuitively, 21 // __THROW is defined in glibc systems. It means, counter-intuitively,
23 // "This function will never throw an exception." It's an optional 22 // "This function will never throw an exception." It's an optional
24 // optimization tool, but we may need to use it to match glibc prototypes. 23 // optimization tool, but we may need to use it to match glibc prototypes.
25 #ifndef __THROW // I guess we're not on a glibc system 24 #ifndef __THROW // I guess we're not on a glibc system
26 # define __THROW // __THROW is just an optimization, so ok to make it "" 25 # define __THROW // __THROW is just an optimization, so ok to make it ""
27 #endif 26 #endif
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 return true; 111 return true;
113 } 112 }
114 #endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPT IONS) && !_HAS_EXCEPTIONS) 113 #endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPT IONS) && !_HAS_EXCEPTIONS)
115 return false; 114 return false;
116 } 115 }
117 116
118 extern "C" { 117 extern "C" {
119 void* malloc(size_t size) __THROW { 118 void* malloc(size_t size) __THROW {
120 void* ptr; 119 void* ptr;
121 for (;;) { 120 for (;;) {
122 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
123 switch (allocator) { 121 switch (allocator) {
124 case JEMALLOC: 122 case JEMALLOC:
125 ptr = je_malloc(size); 123 ptr = je_malloc(size);
126 break; 124 break;
127 case WINHEAP: 125 case WINHEAP:
128 case WINLFH: 126 case WINLFH:
129 ptr = win_heap_malloc(size); 127 ptr = win_heap_malloc(size);
130 break; 128 break;
131 case TCMALLOC: 129 case TCMALLOC:
132 default: 130 default:
133 ptr = do_malloc(size); 131 ptr = do_malloc(size);
134 break; 132 break;
135 } 133 }
136 #else
137 // TCMalloc case.
138 ptr = do_malloc(size);
139 #endif
140 if (ptr) 134 if (ptr)
141 return ptr; 135 return ptr;
142 136
143 if (!new_mode || !call_new_handler(true)) 137 if (!new_mode || !call_new_handler(true))
144 break; 138 break;
145 } 139 }
146 return ptr; 140 return ptr;
147 } 141 }
148 142
149 void free(void* p) __THROW { 143 void free(void* p) __THROW {
150 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
151 switch (allocator) { 144 switch (allocator) {
152 case JEMALLOC: 145 case JEMALLOC:
153 je_free(p); 146 je_free(p);
154 return; 147 return;
155 case WINHEAP: 148 case WINHEAP:
156 case WINLFH: 149 case WINLFH:
157 win_heap_free(p); 150 win_heap_free(p);
158 return; 151 return;
152 case TCMALLOC:
153 do_free(p);
154 return;
159 } 155 }
160 #endif
161 // TCMalloc case.
162 do_free(p);
163 } 156 }
164 157
165 void* realloc(void* ptr, size_t size) __THROW { 158 void* realloc(void* ptr, size_t size) __THROW {
166 // Webkit is brittle for allocators that return NULL for malloc(0). The 159 // Webkit is brittle for allocators that return NULL for malloc(0). The
167 // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure 160 // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure
168 // to call malloc for this case. 161 // to call malloc for this case.
169 if (!ptr) 162 if (!ptr)
170 return malloc(size); 163 return malloc(size);
171 164
172 void* new_ptr; 165 void* new_ptr;
173 for (;;) { 166 for (;;) {
174 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
175 switch (allocator) { 167 switch (allocator) {
176 case JEMALLOC: 168 case JEMALLOC:
177 new_ptr = je_realloc(ptr, size); 169 new_ptr = je_realloc(ptr, size);
178 break; 170 break;
179 case WINHEAP: 171 case WINHEAP:
180 case WINLFH: 172 case WINLFH:
181 new_ptr = win_heap_realloc(ptr, size); 173 new_ptr = win_heap_realloc(ptr, size);
182 break; 174 break;
183 case TCMALLOC: 175 case TCMALLOC:
184 default: 176 default:
185 new_ptr = do_realloc(ptr, size); 177 new_ptr = do_realloc(ptr, size);
186 break; 178 break;
187 } 179 }
188 #else
189 // TCMalloc case.
190 new_ptr = do_realloc(ptr, size);
191 #endif
192 180
193 // Subtle warning: NULL return does not alwas indicate out-of-memory. If 181 // Subtle warning: NULL return does not alwas indicate out-of-memory. If
194 // the requested new size is zero, realloc should free the ptr and return 182 // the requested new size is zero, realloc should free the ptr and return
195 // NULL. 183 // NULL.
196 if (new_ptr || !size) 184 if (new_ptr || !size)
197 return new_ptr; 185 return new_ptr;
198 if (!new_mode || !call_new_handler(true)) 186 if (!new_mode || !call_new_handler(true))
199 break; 187 break;
200 } 188 }
201 return new_ptr; 189 return new_ptr;
202 } 190 }
203 191
204 // TODO(mbelshe): Implement this for other allocators. 192 // TODO(mbelshe): Implement this for other allocators.
205 void malloc_stats(void) __THROW { 193 void malloc_stats(void) __THROW {
206 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
207 switch (allocator) { 194 switch (allocator) {
208 case JEMALLOC: 195 case JEMALLOC:
209 // No stats. 196 // No stats.
210 return; 197 return;
211 case WINHEAP: 198 case WINHEAP:
212 case WINLFH: 199 case WINLFH:
213 // No stats. 200 // No stats.
214 return; 201 return;
202 case TCMALLOC:
203 tc_malloc_stats();
204 return;
215 } 205 }
216 #endif
217 tc_malloc_stats();
218 } 206 }
219 207
220 #ifdef WIN32 208 #ifdef WIN32
221 209
222 extern "C" size_t _msize(void* p) { 210 extern "C" size_t _msize(void* p) {
223 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
224 switch (allocator) { 211 switch (allocator) {
225 case JEMALLOC: 212 case JEMALLOC:
226 return je_msize(p); 213 return je_msize(p);
227 case WINHEAP: 214 case WINHEAP:
228 case WINLFH: 215 case WINLFH:
229 return win_heap_msize(p); 216 return win_heap_msize(p);
217 case TCMALLOC:
218 return MallocExtension::instance()->GetAllocatedSize(p);
230 } 219 }
231 #endif 220
232 return MallocExtension::instance()->GetAllocatedSize(p); 221 NOTREACHED();
jar (doing other things) 2013/11/07 19:22:37 Although this is a reasonable debug check.... it i
222 return 0;
233 } 223 }
234 224
235 // This is included to resolve references from libcmt. 225 // This is included to resolve references from libcmt.
236 extern "C" intptr_t _get_heap_handle() { 226 extern "C" intptr_t _get_heap_handle() {
237 return 0; 227 return 0;
238 } 228 }
239 229
240 static bool get_allocator_waste_size_thunk(size_t* size) { 230 static bool get_allocator_waste_size_thunk(size_t* size) {
241 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
242 switch (allocator) { 231 switch (allocator) {
243 case JEMALLOC: 232 case JEMALLOC:
244 case WINHEAP: 233 case WINHEAP:
245 case WINLFH: 234 case WINLFH:
246 // TODO(alexeif): Implement for allocators other than tcmalloc. 235 // TODO(alexeif): Implement for allocators other than tcmalloc.
247 return false; 236 return false;
248 } 237 }
249 #endif
250 size_t heap_size, allocated_bytes, unmapped_bytes; 238 size_t heap_size, allocated_bytes, unmapped_bytes;
251 MallocExtension* ext = MallocExtension::instance(); 239 MallocExtension* ext = MallocExtension::instance();
252 if (ext->GetNumericProperty("generic.heap_size", &heap_size) && 240 if (ext->GetNumericProperty("generic.heap_size", &heap_size) &&
253 ext->GetNumericProperty("generic.current_allocated_bytes", 241 ext->GetNumericProperty("generic.current_allocated_bytes",
254 &allocated_bytes) && 242 &allocated_bytes) &&
255 ext->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes", 243 ext->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes",
256 &unmapped_bytes)) { 244 &unmapped_bytes)) {
257 *size = heap_size - allocated_bytes - unmapped_bytes; 245 *size = heap_size - allocated_bytes - unmapped_bytes;
258 return true; 246 return true;
259 } 247 }
260 return false; 248 return false;
261 } 249 }
262 250
263 static void get_stats_thunk(char* buffer, int buffer_length) { 251 static void get_stats_thunk(char* buffer, int buffer_length) {
264 MallocExtension::instance()->GetStats(buffer, buffer_length); 252 MallocExtension::instance()->GetStats(buffer, buffer_length);
265 } 253 }
266 254
267 static void release_free_memory_thunk() { 255 static void release_free_memory_thunk() {
268 MallocExtension::instance()->ReleaseFreeMemory(); 256 MallocExtension::instance()->ReleaseFreeMemory();
269 } 257 }
270 258
271 // The CRT heap initialization stub. 259 // The CRT heap initialization stub.
272 extern "C" int _heap_init() { 260 extern "C" int _heap_init() {
273 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
274 // Don't use the environment variable if ADDRESS_SANITIZER is defined on 261 // Don't use the environment variable if ADDRESS_SANITIZER is defined on
275 // Windows, as the implementation requires Winheap to be the allocator. 262 // Windows, as the implementation requires Winheap to be the allocator.
276 #if !(defined(ADDRESS_SANITIZER) && defined(OS_WIN)) 263 #if !(defined(ADDRESS_SANITIZER) && defined(OS_WIN))
277 const char* environment_value = GetenvBeforeMain(primary_name); 264 const char* environment_value = GetenvBeforeMain(primary_name);
278 if (environment_value) { 265 if (environment_value) {
279 if (!stricmp(environment_value, "jemalloc")) 266 if (!stricmp(environment_value, "jemalloc"))
280 allocator = JEMALLOC; 267 allocator = JEMALLOC;
281 else if (!stricmp(environment_value, "winheap")) 268 else if (!stricmp(environment_value, "winheap"))
282 allocator = WINHEAP; 269 allocator = WINHEAP;
283 else if (!stricmp(environment_value, "winlfh")) 270 else if (!stricmp(environment_value, "winlfh"))
284 allocator = WINLFH; 271 allocator = WINLFH;
285 else if (!stricmp(environment_value, "tcmalloc")) 272 else if (!stricmp(environment_value, "tcmalloc"))
286 allocator = TCMALLOC; 273 allocator = TCMALLOC;
287 } 274 }
288 #endif 275 #endif
289 276
290 switch (allocator) { 277 switch (allocator) {
291 case JEMALLOC: 278 case JEMALLOC:
292 return je_malloc_init_hard() ? 0 : 1; 279 return je_malloc_init_hard() ? 0 : 1;
293 case WINHEAP: 280 case WINHEAP:
294 return win_heap_init(false) ? 1 : 0; 281 return win_heap_init(false) ? 1 : 0;
295 case WINLFH: 282 case WINLFH:
296 return win_heap_init(true) ? 1 : 0; 283 return win_heap_init(true) ? 1 : 0;
297 case TCMALLOC: 284 case TCMALLOC:
298 default: 285 default:
299 // fall through 286 // fall through
300 break; 287 break;
301 } 288 }
302 #endif 289
303 // Initializing tcmalloc. 290 // Initializing tcmalloc.
304 // We intentionally leak this object. It lasts for the process 291 // We intentionally leak this object. It lasts for the process
305 // lifetime. Trying to teardown at _heap_term() is so late that 292 // lifetime. Trying to teardown at _heap_term() is so late that
306 // you can't do anything useful anyway. 293 // you can't do anything useful anyway.
307 new TCMallocGuard(); 294 new TCMallocGuard();
308 295
309 // Provide optional hook for monitoring allocation quantities on a per-thread 296 // Provide optional hook for monitoring allocation quantities on a per-thread
310 // basis. Only set the hook if the environment indicates this needs to be 297 // basis. Only set the hook if the environment indicates this needs to be
311 // enabled. 298 // enabled.
312 const char* profiling = 299 const char* profiling =
(...skipping 26 matching lines...) Expand all
339 void* _aligned_malloc(size_t size, size_t alignment) { 326 void* _aligned_malloc(size_t size, size_t alignment) {
340 // _aligned_malloc guarantees parameter validation, so do so here. These 327 // _aligned_malloc guarantees parameter validation, so do so here. These
341 // checks are somewhat stricter than _aligned_malloc() since we're effectively 328 // checks are somewhat stricter than _aligned_malloc() since we're effectively
342 // using memalign() under the hood. 329 // using memalign() under the hood.
343 DCHECK_GT(size, 0U); 330 DCHECK_GT(size, 0U);
344 DCHECK_EQ(alignment & (alignment - 1), 0U); 331 DCHECK_EQ(alignment & (alignment - 1), 0U);
345 DCHECK_EQ(alignment % sizeof(void*), 0U); 332 DCHECK_EQ(alignment % sizeof(void*), 0U);
346 333
347 void* ptr; 334 void* ptr;
348 for (;;) { 335 for (;;) {
349 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
350 switch (allocator) { 336 switch (allocator) {
351 case JEMALLOC: 337 case JEMALLOC:
352 ptr = je_memalign(alignment, size); 338 ptr = je_memalign(alignment, size);
353 break; 339 break;
354 case WINHEAP: 340 case WINHEAP:
355 case WINLFH: 341 case WINLFH:
356 ptr = win_heap_memalign(alignment, size); 342 ptr = win_heap_memalign(alignment, size);
357 break; 343 break;
358 case TCMALLOC: 344 case TCMALLOC:
359 default: 345 default:
360 ptr = tc_memalign(alignment, size); 346 ptr = tc_memalign(alignment, size);
361 break; 347 break;
362 } 348 }
363 #else 349
364 // TCMalloc case.
365 ptr = tc_memalign(alignment, size);
366 #endif
367 if (ptr) { 350 if (ptr) {
368 // Sanity check alignment. 351 // Sanity check alignment.
369 DCHECK_EQ(reinterpret_cast<uintptr_t>(ptr) & (alignment - 1), 0U); 352 DCHECK_EQ(reinterpret_cast<uintptr_t>(ptr) & (alignment - 1), 0U);
370 return ptr; 353 return ptr;
371 } 354 }
372 355
373 if (!new_mode || !call_new_handler(true)) 356 if (!new_mode || !call_new_handler(true))
374 break; 357 break;
375 } 358 }
376 return ptr; 359 return ptr;
377 } 360 }
378 361
379 void _aligned_free(void* p) { 362 void _aligned_free(void* p) {
380 // Both JEMalloc and TCMalloc return pointers from memalign() that are safe to 363 // Both JEMalloc and TCMalloc return pointers from memalign() that are safe to
381 // use with free(). Pointers allocated with win_heap_memalign() MUST be freed 364 // use with free(). Pointers allocated with win_heap_memalign() MUST be freed
382 // via win_heap_memalign_free() since the aligned pointer is not the real one. 365 // via win_heap_memalign_free() since the aligned pointer is not the real one.
383 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
384 switch (allocator) { 366 switch (allocator) {
385 case JEMALLOC: 367 case JEMALLOC:
386 je_free(p); 368 je_free(p);
387 return; 369 return;
388 case WINHEAP: 370 case WINHEAP:
389 case WINLFH: 371 case WINLFH:
390 win_heap_memalign_free(p); 372 win_heap_memalign_free(p);
391 return; 373 return;
374 case TCMALLOC:
375 do_free(p);
392 } 376 }
393 #endif
394 // TCMalloc case.
395 do_free(p);
396 } 377 }
397 378
398 #endif // WIN32 379 #endif // WIN32
399 380
400 #include "generic_allocators.cc" 381 #include "generic_allocators.cc"
401 382
402 } // extern C 383 } // extern C
403 384
404 namespace base { 385 namespace base {
405 namespace allocator { 386 namespace allocator {
406 387
407 void SetupSubprocessAllocator() { 388 void SetupSubprocessAllocator() {
408 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
409 size_t primary_length = 0; 389 size_t primary_length = 0;
410 getenv_s(&primary_length, NULL, 0, primary_name); 390 getenv_s(&primary_length, NULL, 0, primary_name);
411 391
412 size_t secondary_length = 0; 392 size_t secondary_length = 0;
413 char buffer[20]; 393 char buffer[20];
414 getenv_s(&secondary_length, buffer, sizeof(buffer), secondary_name); 394 getenv_s(&secondary_length, buffer, sizeof(buffer), secondary_name);
415 DCHECK_GT(sizeof(buffer), secondary_length); 395 DCHECK_GT(sizeof(buffer), secondary_length);
416 buffer[sizeof(buffer) - 1] = '\0'; 396 buffer[sizeof(buffer) - 1] = '\0';
417 397
418 if (secondary_length || !primary_length) { 398 if (secondary_length || !primary_length) {
419 // Don't use the environment variable if ADDRESS_SANITIZER is defined on 399 // Don't use the environment variable if ADDRESS_SANITIZER is defined on
420 // Windows, as the implementation require Winheap to be the allocator. 400 // Windows, as the implementation require Winheap to be the allocator.
421 #if !(defined(ADDRESS_SANITIZER) && defined(OS_WIN)) 401 #if !(defined(ADDRESS_SANITIZER) && defined(OS_WIN))
422 const char* secondary_value = secondary_length ? buffer : "TCMALLOC"; 402 const char* secondary_value = secondary_length ? buffer : "TCMALLOC";
423 // Force renderer (or other subprocesses) to use secondary_value. 403 // Force renderer (or other subprocesses) to use secondary_value.
424 #else 404 #else
425 const char* secondary_value = "WINHEAP"; 405 const char* secondary_value = "WINHEAP";
426 #endif 406 #endif
427 int ret_val = _putenv_s(primary_name, secondary_value); 407 int ret_val = _putenv_s(primary_name, secondary_value);
428 DCHECK_EQ(0, ret_val); 408 DCHECK_EQ(0, ret_val);
429 } 409 }
430 #endif // ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
431 } 410 }
432 411
433 void* TCMallocDoMallocForTest(size_t size) { 412 void* TCMallocDoMallocForTest(size_t size) {
434 return do_malloc(size); 413 return do_malloc(size);
435 } 414 }
436 415
437 void TCMallocDoFreeForTest(void* ptr) { 416 void TCMallocDoFreeForTest(void* ptr) {
438 do_free(ptr); 417 do_free(ptr);
439 } 418 }
440 419
441 size_t ExcludeSpaceForMarkForTest(size_t size) { 420 size_t ExcludeSpaceForMarkForTest(size_t size) {
442 return ExcludeSpaceForMark(size); 421 return ExcludeSpaceForMark(size);
443 } 422 }
444 423
445 } // namespace allocator. 424 } // namespace allocator.
446 } // namespace base. 425 } // namespace base.
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698