Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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" | |
| 6 | |
| 5 #include <config.h> | 7 #include <config.h> |
| 6 | 8 |
| 7 // When defined, different heap allocators can be used via an environment | 9 // When defined, different heap allocators can be used via an environment |
| 8 // variable set before running the program. This may reduce the amount | 10 // variable set before running the program. This may reduce the amount |
| 9 // of inlining that we get with malloc/free/etc. Disabling makes it | 11 // of inlining that we get with malloc/free/etc. Disabling makes it |
| 10 // so that only tcmalloc can be used. | 12 // so that only tcmalloc can be used. |
| 11 #define ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 13 #define ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 12 | 14 |
| 13 // TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth | 15 // TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth |
| 14 // from the "user code" so that debugging tools (HeapChecker) can work. | 16 // from the "user code" so that debugging tools (HeapChecker) can work. |
| 15 | 17 |
| 16 // __THROW is defined in glibc systems. It means, counter-intuitively, | 18 // __THROW is defined in glibc systems. It means, counter-intuitively, |
| 17 // "This function will never throw an exception." It's an optional | 19 // "This function will never throw an exception." It's an optional |
| 18 // optimization tool, but we may need to use it to match glibc prototypes. | 20 // optimization tool, but we may need to use it to match glibc prototypes. |
| 19 #ifndef __THROW // I guess we're not on a glibc system | 21 #ifndef __THROW // I guess we're not on a glibc system |
| 20 # define __THROW // __THROW is just an optimization, so ok to make it "" | 22 # define __THROW // __THROW is just an optimization, so ok to make it "" |
| 21 #endif | 23 #endif |
| 22 | 24 |
| 23 // new_mode behaves similarly to MSVC's _set_new_mode. | 25 // new_mode behaves similarly to MSVC's _set_new_mode. |
| 24 // If flag is 0 (default), calls to malloc will behave normally. | 26 // If flag is 0 (default), calls to malloc will behave normally. |
| 25 // If flag is 1, calls to malloc will behave like calls to new, | 27 // If flag is 1, calls to malloc will behave like calls to new, |
| 26 // and the std_new_handler will be invoked on failure. | 28 // and the std_new_handler will be invoked on failure. |
| 27 // Can be set by calling _set_new_mode(). | 29 // Can be set by calling _set_new_mode(). |
| 28 static int new_mode = 0; | 30 static int new_mode = 0; |
| 29 | 31 |
| 30 typedef enum { | 32 typedef enum { |
| 31 TCMALLOC, // TCMalloc is the default allocator. | 33 TCMALLOC, // TCMalloc is the default allocator. |
| 32 JEMALLOC, // JEMalloc | 34 JEMALLOC, // JEMalloc. |
| 33 WINDEFAULT, // Windows Heap | 35 WINHEAP, // Windows Heap (standard Windows allocator). |
| 34 WINLFH, // Windows LFH Heap | 36 WINLFH, // Windows LFH Heap. |
| 35 } Allocator; | 37 } Allocator; |
| 36 | 38 |
| 37 // This is the default allocator. | 39 // This is the default allocator. This value can be changed at startup by |
| 38 static Allocator allocator = TCMALLOC; | 40 // specifying environment variables shown below it. |
| 41 // See SetupSubprocessAllocator() to specify a default secondary (subprocess) | |
| 42 // allocator. | |
| 43 static Allocator allocator = WINHEAP; | |
| 44 | |
| 45 // The names of the environment variables that can optionally control the | |
| 46 // selection of the allocator. The primary may be used to control overall | |
| 47 // allocator selection, and the secondary can be used to specify an allocator | |
| 48 // to use in sub-processes. | |
| 49 static const char* primary_name = "CHROME_ALLOCATOR"; | |
| 50 static const char* secondary_name = "CHROME_ALLOCATOR_2"; | |
| 39 | 51 |
| 40 // We include tcmalloc and the win_allocator to get as much inlining as | 52 // We include tcmalloc and the win_allocator to get as much inlining as |
| 41 // possible. | 53 // possible. |
| 42 #include "tcmalloc.cc" | 54 #include "tcmalloc.cc" |
| 43 #include "win_allocator.cc" | 55 #include "win_allocator.cc" |
| 44 | 56 |
| 45 // Forward declarations from jemalloc. | 57 // Forward declarations from jemalloc. |
| 46 extern "C" { | 58 extern "C" { |
| 47 void* je_malloc(size_t s); | 59 void* je_malloc(size_t s); |
| 48 void* je_realloc(void* p, size_t s); | 60 void* je_realloc(void* p, size_t s); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 } | 106 } |
| 95 | 107 |
| 96 void* malloc(size_t size) __THROW { | 108 void* malloc(size_t size) __THROW { |
| 97 void* ptr; | 109 void* ptr; |
| 98 for (;;) { | 110 for (;;) { |
| 99 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 111 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 100 switch (allocator) { | 112 switch (allocator) { |
| 101 case JEMALLOC: | 113 case JEMALLOC: |
| 102 ptr = je_malloc(size); | 114 ptr = je_malloc(size); |
| 103 break; | 115 break; |
| 104 case WINDEFAULT: | 116 case WINHEAP: |
| 105 case WINLFH: | 117 case WINLFH: |
| 106 ptr = win_heap_malloc(size); | 118 ptr = win_heap_malloc(size); |
| 107 break; | 119 break; |
| 108 case TCMALLOC: | 120 case TCMALLOC: |
| 109 default: | 121 default: |
| 110 ptr = do_malloc(size); | 122 ptr = do_malloc(size); |
| 111 break; | 123 break; |
| 112 } | 124 } |
| 113 #else | 125 #else |
| 114 // TCMalloc case. | 126 // TCMalloc case. |
| 115 ptr = do_malloc(size); | 127 ptr = do_malloc(size); |
| 116 #endif | 128 #endif |
| 117 if (ptr) | 129 if (ptr) |
| 118 return ptr; | 130 return ptr; |
| 119 | 131 |
| 120 if (!new_mode || !call_new_handler(true)) | 132 if (!new_mode || !call_new_handler(true)) |
| 121 break; | 133 break; |
| 122 } | 134 } |
| 123 return ptr; | 135 return ptr; |
| 124 } | 136 } |
| 125 | 137 |
| 126 void free(void* p) __THROW { | 138 void free(void* p) __THROW { |
| 127 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 139 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 128 switch (allocator) { | 140 switch (allocator) { |
| 129 case JEMALLOC: | 141 case JEMALLOC: |
| 130 je_free(p); | 142 je_free(p); |
| 131 return; | 143 return; |
| 132 case WINDEFAULT: | 144 case WINHEAP: |
| 133 case WINLFH: | 145 case WINLFH: |
| 134 win_heap_free(p); | 146 win_heap_free(p); |
| 135 return; | 147 return; |
| 136 } | 148 } |
| 137 #endif | 149 #endif |
| 138 // TCMalloc case. | 150 // TCMalloc case. |
| 139 do_free(p); | 151 do_free(p); |
| 140 } | 152 } |
| 141 | 153 |
| 142 void* realloc(void* ptr, size_t size) __THROW { | 154 void* realloc(void* ptr, size_t size) __THROW { |
| 143 // Webkit is brittle for allocators that return NULL for malloc(0). The | 155 // Webkit is brittle for allocators that return NULL for malloc(0). The |
| 144 // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure | 156 // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure |
| 145 // to call malloc for this case. | 157 // to call malloc for this case. |
| 146 if (!ptr) | 158 if (!ptr) |
| 147 return malloc(size); | 159 return malloc(size); |
| 148 | 160 |
| 149 void* new_ptr; | 161 void* new_ptr; |
| 150 for (;;) { | 162 for (;;) { |
| 151 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 163 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 152 switch (allocator) { | 164 switch (allocator) { |
| 153 case JEMALLOC: | 165 case JEMALLOC: |
| 154 new_ptr = je_realloc(ptr, size); | 166 new_ptr = je_realloc(ptr, size); |
| 155 break; | 167 break; |
| 156 case WINDEFAULT: | 168 case WINHEAP: |
| 157 case WINLFH: | 169 case WINLFH: |
| 158 new_ptr = win_heap_realloc(ptr, size); | 170 new_ptr = win_heap_realloc(ptr, size); |
| 159 break; | 171 break; |
| 160 case TCMALLOC: | 172 case TCMALLOC: |
| 161 default: | 173 default: |
| 162 new_ptr = do_realloc(ptr, size); | 174 new_ptr = do_realloc(ptr, size); |
| 163 break; | 175 break; |
| 164 } | 176 } |
| 165 #else | 177 #else |
| 166 // TCMalloc case. | 178 // TCMalloc case. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 178 return new_ptr; | 190 return new_ptr; |
| 179 } | 191 } |
| 180 | 192 |
| 181 // TODO(mbelshe): Implement this for other allocators. | 193 // TODO(mbelshe): Implement this for other allocators. |
| 182 void malloc_stats(void) __THROW { | 194 void malloc_stats(void) __THROW { |
| 183 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 195 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 184 switch (allocator) { | 196 switch (allocator) { |
| 185 case JEMALLOC: | 197 case JEMALLOC: |
| 186 // No stats. | 198 // No stats. |
| 187 return; | 199 return; |
| 188 case WINDEFAULT: | 200 case WINHEAP: |
| 189 case WINLFH: | 201 case WINLFH: |
| 190 // No stats. | 202 // No stats. |
| 191 return; | 203 return; |
| 192 } | 204 } |
| 193 #endif | 205 #endif |
| 194 tc_malloc_stats(); | 206 tc_malloc_stats(); |
| 195 } | 207 } |
| 196 | 208 |
| 197 #ifdef WIN32 | 209 #ifdef WIN32 |
| 198 | 210 |
| 199 extern "C" size_t _msize(void* p) { | 211 extern "C" size_t _msize(void* p) { |
| 200 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 212 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 201 switch (allocator) { | 213 switch (allocator) { |
| 202 case JEMALLOC: | 214 case JEMALLOC: |
| 203 return je_msize(p); | 215 return je_msize(p); |
| 204 case WINDEFAULT: | 216 case WINHEAP: |
| 205 case WINLFH: | 217 case WINLFH: |
| 206 return win_heap_msize(p); | 218 return win_heap_msize(p); |
| 207 } | 219 } |
| 208 #endif | 220 #endif |
| 209 return MallocExtension::instance()->GetAllocatedSize(p); | 221 return MallocExtension::instance()->GetAllocatedSize(p); |
| 210 } | 222 } |
| 211 | 223 |
| 212 // This is included to resolve references from libcmt. | 224 // This is included to resolve references from libcmt. |
| 213 extern "C" intptr_t _get_heap_handle() { | 225 extern "C" intptr_t _get_heap_handle() { |
| 214 return 0; | 226 return 0; |
| 215 } | 227 } |
| 216 | 228 |
| 217 // The CRT heap initialization stub. | 229 // The CRT heap initialization stub. |
| 218 extern "C" int _heap_init() { | 230 extern "C" int _heap_init() { |
| 219 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 231 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 220 const char* override = GetenvBeforeMain("CHROME_ALLOCATOR"); | 232 const char* environment_value = GetenvBeforeMain(primary_name); |
| 221 if (override) { | 233 if (environment_value) { |
| 222 if (!stricmp(override, "jemalloc")) | 234 if (!stricmp(environment_value, "jemalloc")) |
| 223 allocator = JEMALLOC; | 235 allocator = JEMALLOC; |
| 224 else if (!stricmp(override, "winheap")) | 236 else if (!stricmp(environment_value, "winheap")) |
| 225 allocator = WINDEFAULT; | 237 allocator = WINHEAP; |
| 226 else if (!stricmp(override, "winlfh")) | 238 else if (!stricmp(environment_value, "winlfh")) |
| 227 allocator = WINLFH; | 239 allocator = WINLFH; |
| 228 else if (!stricmp(override, "tcmalloc")) | 240 else if (!stricmp(environment_value, "tcmalloc")) |
| 229 allocator = TCMALLOC; | 241 allocator = TCMALLOC; |
| 230 } | 242 } |
| 231 | 243 |
| 232 switch (allocator) { | 244 switch (allocator) { |
| 233 case JEMALLOC: | 245 case JEMALLOC: |
| 234 return je_malloc_init_hard() ? 0 : 1; | 246 return je_malloc_init_hard() ? 0 : 1; |
| 235 case WINDEFAULT: | 247 case WINHEAP: |
| 236 return win_heap_init(false) ? 1 : 0; | 248 return win_heap_init(false) ? 1 : 0; |
| 237 case WINLFH: | 249 case WINLFH: |
| 238 return win_heap_init(true) ? 1 : 0; | 250 return win_heap_init(true) ? 1 : 0; |
| 239 case TCMALLOC: | 251 case TCMALLOC: |
| 240 default: | 252 default: |
| 241 // fall through | 253 // fall through |
| 242 break; | 254 break; |
| 243 } | 255 } |
| 244 #endif | 256 #endif |
| 245 // Initializing tcmalloc. | 257 // Initializing tcmalloc. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 257 // to test whether the CRT has been initialized. Once we've ripped out | 269 // to test whether the CRT has been initialized. Once we've ripped out |
| 258 // the allocators from libcmt, we need to provide this definition so that | 270 // the allocators from libcmt, we need to provide this definition so that |
| 259 // the rest of the CRT is still usable. | 271 // the rest of the CRT is still usable. |
| 260 extern "C" void* _crtheap = reinterpret_cast<void*>(1); | 272 extern "C" void* _crtheap = reinterpret_cast<void*>(1); |
| 261 | 273 |
| 262 #endif // WIN32 | 274 #endif // WIN32 |
| 263 | 275 |
| 264 #include "generic_allocators.cc" | 276 #include "generic_allocators.cc" |
| 265 | 277 |
| 266 } // extern C | 278 } // extern C |
| 279 | |
| 280 namespace base { | |
| 281 namespace allocator { | |
| 282 | |
| 283 void SetupSubprocessAllocator() { | |
| 284 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | |
| 285 size_t primary_length = 0; | |
| 286 getenv_s(&primary_length, NULL, 0, primary_name); | |
| 287 | |
| 288 size_t secondary_length = 0; | |
| 289 char buffer[20]; | |
| 290 getenv_s(&secondary_length, buffer, sizeof(buffer), secondary_name); | |
|
Mike Belshe
2011/03/07 22:37:16
nit: not sure if this API provides null terminatio
jar (doing other things)
2011/03/07 22:45:07
Added safety net null termination (especially sinc
| |
| 291 DCHECK_GT(sizeof(buffer), secondary_length); | |
| 292 | |
| 293 if (secondary_length || !primary_length) { | |
| 294 char* secondary_value = secondary_length ? buffer : "TCMALLOC"; | |
| 295 // Force renderer (or other subprocesses) to use secondary_value. | |
| 296 int ret_val = _putenv_s(primary_name, secondary_value); | |
| 297 CHECK_EQ(0, ret_val); | |
| 298 } | |
| 299 #endif // ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | |
| 300 } | |
| 301 | |
| 302 } // namespace base. | |
| 303 } // namespace allocator. | |
| OLD | NEW |