OLD | NEW |
1 /* Copyright (c) 2007, Google Inc. | 1 /* Copyright (c) 2007, Google Inc. |
2 * All rights reserved. | 2 * All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 static int pagesize = 0; | 54 static int pagesize = 0; |
55 if (pagesize == 0) { | 55 if (pagesize == 0) { |
56 SYSTEM_INFO system_info; | 56 SYSTEM_INFO system_info; |
57 GetSystemInfo(&system_info); | 57 GetSystemInfo(&system_info); |
58 pagesize = std::max(system_info.dwPageSize, | 58 pagesize = std::max(system_info.dwPageSize, |
59 system_info.dwAllocationGranularity); | 59 system_info.dwAllocationGranularity); |
60 } | 60 } |
61 return pagesize; | 61 return pagesize; |
62 } | 62 } |
63 | 63 |
64 extern "C" PERFTOOLS_DLL_DECL void* __sbrk(ptrdiff_t increment) { | 64 extern "C" PERFTOOLS_DLL_DECL void* __sbrk(std::ptrdiff_t increment) { |
65 LOG(FATAL, "Windows doesn't implement sbrk!\n"); | 65 LOG(FATAL, "Windows doesn't implement sbrk!\n"); |
66 return NULL; | 66 return NULL; |
67 } | 67 } |
68 | 68 |
69 // We need to write to 'stderr' without having windows allocate memory. | 69 // We need to write to 'stderr' without having windows allocate memory. |
70 // The safest way is via a low-level call like WriteConsoleA(). But | 70 // The safest way is via a low-level call like WriteConsoleA(). But |
71 // even then we need to be sure to print in small bursts so as to not | 71 // even then we need to be sure to print in small bursts so as to not |
72 // require memory allocation. | 72 // require memory allocation. |
73 extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) { | 73 extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) { |
74 // Looks like windows allocates for writes of >80 bytes | 74 // Looks like windows allocates for writes of >80 bytes |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 } | 147 } |
148 } | 148 } |
149 | 149 |
150 #ifdef _MSC_VER | 150 #ifdef _MSC_VER |
151 | 151 |
152 // extern "C" suppresses C++ name mangling so we know the symbol names | 152 // extern "C" suppresses C++ name mangling so we know the symbol names |
153 // for the linker /INCLUDE:symbol pragmas above. | 153 // for the linker /INCLUDE:symbol pragmas above. |
154 extern "C" { | 154 extern "C" { |
155 // This tells the linker to run these functions. | 155 // This tells the linker to run these functions. |
156 #pragma data_seg(push, old_seg) | 156 #pragma data_seg(push, old_seg) |
157 #pragma data_seg(".CRT$XLB") | 157 // Use CRT$XLY instead of CRT$XLB to ensure we're called LATER in sequence. |
| 158 #pragma data_seg(".CRT$XLY") |
158 void (NTAPI *p_thread_callback_tcmalloc)( | 159 void (NTAPI *p_thread_callback_tcmalloc)( |
159 HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback; | 160 HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback; |
160 #pragma data_seg(".CRT$XTU") | 161 #pragma data_seg(".CRT$XTU") |
161 int (*p_process_term_tcmalloc)(void) = on_process_term; | 162 int (*p_process_term_tcmalloc)(void) = on_process_term; |
162 #pragma data_seg(pop, old_seg) | 163 #pragma data_seg(pop, old_seg) |
163 } // extern "C" | 164 } // extern "C" |
164 | 165 |
165 #else // #ifdef _MSC_VER [probably msys/mingw] | 166 #else // #ifdef _MSC_VER [probably msys/mingw] |
166 | 167 |
167 // We have to try the DllMain solution here, because we can't use the | 168 // We have to try the DllMain solution here, because we can't use the |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 | 221 |
221 // This is mostly like MmapSysAllocator::Alloc, except it does these weird | 222 // This is mostly like MmapSysAllocator::Alloc, except it does these weird |
222 // munmap's in the middle of the page, which is forbidden in windows. | 223 // munmap's in the middle of the page, which is forbidden in windows. |
223 extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, | 224 extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, |
224 size_t alignment) { | 225 size_t alignment) { |
225 // Align on the pagesize boundary | 226 // Align on the pagesize boundary |
226 const int pagesize = getpagesize(); | 227 const int pagesize = getpagesize(); |
227 if (alignment < pagesize) alignment = pagesize; | 228 if (alignment < pagesize) alignment = pagesize; |
228 size = ((size + alignment - 1) / alignment) * alignment; | 229 size = ((size + alignment - 1) / alignment) * alignment; |
229 | 230 |
230 // Safest is to make actual_size same as input-size. | 231 // Report the total number of bytes the OS actually delivered. This might be |
| 232 // greater than |size| because of alignment concerns. The full size is |
| 233 // necessary so that adjacent spans can be coalesced. |
| 234 // TODO(antonm): proper processing of alignments |
| 235 // in actual_size and decommitting. |
231 if (actual_size) { | 236 if (actual_size) { |
232 *actual_size = size; | 237 *actual_size = size; |
233 } | 238 } |
234 | 239 |
235 // Ask for extra memory if alignment > pagesize | 240 // We currently do not support alignments larger than the pagesize or |
236 size_t extra = 0; | 241 // alignments that are not multiples of the pagesize after being floored. |
237 if (alignment > pagesize) { | 242 // If this ability is needed it can be done by the caller (assuming it knows |
238 extra = alignment - pagesize; | 243 // the page size). |
239 } | 244 assert(alignment <= pagesize); |
240 | 245 |
241 void* result = VirtualAlloc(0, size + extra, | 246 void* result = VirtualAlloc(0, size, |
242 MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); | 247 MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); |
243 if (result == NULL) | 248 if (result == NULL) |
244 return NULL; | 249 return NULL; |
245 | 250 |
246 // Adjust the return memory so it is aligned | 251 // If the result is not aligned memory fragmentation will result which can |
247 uintptr_t ptr = reinterpret_cast<uintptr_t>(result); | 252 // lead to pathological memory use. |
248 size_t adjust = 0; | 253 assert((reinterpret_cast<uintptr_t>(result) & (alignment - 1)) == 0); |
249 if ((ptr & (alignment - 1)) != 0) { | 254 |
250 adjust = alignment - (ptr & (alignment - 1)); | 255 return result; |
| 256 } |
| 257 |
| 258 size_t TCMalloc_SystemAddGuard(void* start, size_t size) { |
| 259 static size_t pagesize = 0; |
| 260 if (pagesize == 0) { |
| 261 SYSTEM_INFO system_info; |
| 262 GetSystemInfo(&system_info); |
| 263 pagesize = system_info.dwPageSize; |
251 } | 264 } |
252 | 265 |
253 ptr += adjust; | 266 // We know that TCMalloc_SystemAlloc will give us a correct page alignment |
254 return reinterpret_cast<void*>(ptr); | 267 // regardless, so we can just assert to detect erroneous callers. |
| 268 assert(reinterpret_cast<size_t>(start) % pagesize == 0); |
| 269 |
| 270 // Add a guard page to catch metadata corruption. We're using the |
| 271 // PAGE_GUARD flag rather than NO_ACCESS because we want the unique |
| 272 // exception in crash reports. |
| 273 DWORD permissions = 0; |
| 274 if (size > pagesize && |
| 275 VirtualProtect(start, pagesize, PAGE_READONLY | PAGE_GUARD, |
| 276 &permissions)) { |
| 277 return pagesize; |
| 278 } |
| 279 |
| 280 return 0; |
255 } | 281 } |
256 | 282 |
257 void TCMalloc_SystemRelease(void* start, size_t length) { | 283 void TCMalloc_SystemRelease(void* start, size_t length) { |
258 // TODO(csilvers): should I be calling VirtualFree here? | 284 if (VirtualFree(start, length, MEM_DECOMMIT)) |
| 285 return; |
| 286 |
| 287 // The decommit may fail if the memory region consists of allocations |
| 288 // from more than one call to VirtualAlloc. In this case, fall back to |
| 289 // using VirtualQuery to retrieve the allocation boundaries and decommit |
| 290 // them each individually. |
| 291 |
| 292 char* ptr = static_cast<char*>(start); |
| 293 char* end = ptr + length; |
| 294 MEMORY_BASIC_INFORMATION info; |
| 295 while (ptr < end) { |
| 296 size_t resultSize = VirtualQuery(ptr, &info, sizeof(info)); |
| 297 assert(resultSize == sizeof(info)); |
| 298 size_t decommitSize = std::min<size_t>(info.RegionSize, end - ptr); |
| 299 BOOL success = VirtualFree(ptr, decommitSize, MEM_DECOMMIT); |
| 300 assert(success == TRUE); |
| 301 ptr += decommitSize; |
| 302 } |
| 303 } |
| 304 |
| 305 void TCMalloc_SystemCommit(void* start, size_t length) { |
| 306 if (VirtualAlloc(start, length, MEM_COMMIT, PAGE_READWRITE) == start) |
| 307 return; |
| 308 |
| 309 // The commit may fail if the memory region consists of allocations |
| 310 // from more than one call to VirtualAlloc. In this case, fall back to |
| 311 // using VirtualQuery to retrieve the allocation boundaries and commit them |
| 312 // each individually. |
| 313 |
| 314 char* ptr = static_cast<char*>(start); |
| 315 char* end = ptr + length; |
| 316 MEMORY_BASIC_INFORMATION info; |
| 317 while (ptr < end) { |
| 318 size_t resultSize = VirtualQuery(ptr, &info, sizeof(info)); |
| 319 assert(resultSize == sizeof(info)); |
| 320 |
| 321 size_t commitSize = std::min<size_t>(info.RegionSize, end - ptr); |
| 322 void* newAddress = VirtualAlloc(ptr, commitSize, MEM_COMMIT, |
| 323 PAGE_READWRITE); |
| 324 assert(newAddress == ptr); |
| 325 ptr += commitSize; |
| 326 } |
259 } | 327 } |
260 | 328 |
261 bool RegisterSystemAllocator(SysAllocator *allocator, int priority) { | 329 bool RegisterSystemAllocator(SysAllocator *allocator, int priority) { |
262 return false; // we don't allow registration on windows, right now | 330 return false; // we don't allow registration on windows, right now |
263 } | 331 } |
264 | 332 |
265 void DumpSystemAllocatorStats(TCMalloc_Printer* printer) { | 333 void DumpSystemAllocatorStats(TCMalloc_Printer* printer) { |
266 // We don't dump stats on windows, right now | 334 // We don't dump stats on windows, right now |
267 } | 335 } |
268 | 336 |
(...skipping 16 matching lines...) Expand all Loading... |
285 if ((strlen(fname) >= prefix_length) && | 353 if ((strlen(fname) >= prefix_length) && |
286 (memcmp(fname, prefix, prefix_length) == 0)) { | 354 (memcmp(fname, prefix, prefix_length) == 0)) { |
287 RAW_VLOG(0, "Removing old heap profile %s\n", fname); | 355 RAW_VLOG(0, "Removing old heap profile %s\n", fname); |
288 // TODO(csilvers): we really need to unlink dirname + fname | 356 // TODO(csilvers): we really need to unlink dirname + fname |
289 _unlink(fname); | 357 _unlink(fname); |
290 } | 358 } |
291 } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi | 359 } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi |
292 FindClose(hFind); | 360 FindClose(hFind); |
293 } | 361 } |
294 } | 362 } |
OLD | NEW |