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(std::ptrdiff_t increment) { | 64 extern "C" PERFTOOLS_DLL_DECL void* __sbrk(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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 } | 142 } |
143 | 143 |
144 static void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) { | 144 static void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) { |
145 if (dwReason == DLL_THREAD_DETACH) { // thread is being destroyed! | 145 if (dwReason == DLL_THREAD_DETACH) { // thread is being destroyed! |
146 on_process_term(); | 146 on_process_term(); |
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 for the | 152 // extern "C" suppresses C++ name mangling so we know the symbol names |
153 // 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 // Use CRT$XLY instead of CRT$XLB to ensure we're called LATER in sequence. | 157 #pragma data_seg(".CRT$XLB") |
158 #pragma data_seg(".CRT$XLY") | |
159 void (NTAPI *p_thread_callback_tcmalloc)( | 158 void (NTAPI *p_thread_callback_tcmalloc)( |
160 HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback; | 159 HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback; |
161 #pragma data_seg(".CRT$XTU") | 160 #pragma data_seg(".CRT$XTU") |
162 int (*p_process_term_tcmalloc)(void) = on_process_term; | 161 int (*p_process_term_tcmalloc)(void) = on_process_term; |
163 #pragma data_seg(pop, old_seg) | 162 #pragma data_seg(pop, old_seg) |
164 } // extern "C" | 163 } // extern "C" |
165 | 164 |
166 #else // #ifdef _MSC_VER [probably msys/mingw] | 165 #else // #ifdef _MSC_VER [probably msys/mingw] |
167 | 166 |
168 // We have to try the DllMain solution here, because we can't use the | 167 // We have to try the DllMain solution here, because we can't use the |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 } | 211 } |
213 } | 212 } |
214 } | 213 } |
215 return 0; | 214 return 0; |
216 } | 215 } |
217 | 216 |
218 | 217 |
219 // ----------------------------------------------------------------------- | 218 // ----------------------------------------------------------------------- |
220 // These functions replace system-alloc.cc | 219 // These functions replace system-alloc.cc |
221 | 220 |
222 // The current system allocator. Because we don't link with system-alloc.cc, | |
223 // we need to define our own. | |
224 SysAllocator* sys_alloc = NULL; | |
225 | |
226 // This is mostly like MmapSysAllocator::Alloc, except it does these weird | 221 // This is mostly like MmapSysAllocator::Alloc, except it does these weird |
227 // munmap's in the middle of the page, which is forbidden in windows. | 222 // munmap's in the middle of the page, which is forbidden in windows. |
228 extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, | 223 extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, |
229 size_t alignment) { | 224 size_t alignment) { |
230 // Align on the pagesize boundary | 225 // Align on the pagesize boundary |
231 const int pagesize = getpagesize(); | 226 const int pagesize = getpagesize(); |
232 if (alignment < pagesize) alignment = pagesize; | 227 if (alignment < pagesize) alignment = pagesize; |
233 size = ((size + alignment - 1) / alignment) * alignment; | 228 size = ((size + alignment - 1) / alignment) * alignment; |
234 | 229 |
235 // Report the total number of bytes the OS actually delivered. This might be | 230 // Safest is to make actual_size same as input-size. |
236 // greater than |size| because of alignment concerns. The full size is | |
237 // necessary so that adjacent spans can be coalesced. | |
238 // TODO(antonm): proper processing of alignments | |
239 // in actual_size and decommitting. | |
240 if (actual_size) { | 231 if (actual_size) { |
241 *actual_size = size; | 232 *actual_size = size; |
242 } | 233 } |
243 | 234 |
244 // We currently do not support alignments larger than the pagesize or | 235 // Ask for extra memory if alignment > pagesize |
245 // alignments that are not multiples of the pagesize after being floored. | 236 size_t extra = 0; |
246 // If this ability is needed it can be done by the caller (assuming it knows | 237 if (alignment > pagesize) { |
247 // the page size). | 238 extra = alignment - pagesize; |
248 assert(alignment <= pagesize); | 239 } |
249 | 240 |
250 void* result = VirtualAlloc(0, size, | 241 void* result = VirtualAlloc(0, size + extra, |
251 MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); | 242 MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); |
252 if (result == NULL) | 243 if (result == NULL) |
253 return NULL; | 244 return NULL; |
254 | 245 |
255 // If the result is not aligned memory fragmentation will result which can | 246 // Adjust the return memory so it is aligned |
256 // lead to pathological memory use. | 247 uintptr_t ptr = reinterpret_cast<uintptr_t>(result); |
257 assert((reinterpret_cast<uintptr_t>(result) & (alignment - 1)) == 0); | 248 size_t adjust = 0; |
258 | 249 if ((ptr & (alignment - 1)) != 0) { |
259 return result; | 250 adjust = alignment - (ptr & (alignment - 1)); |
260 } | |
261 | |
262 size_t TCMalloc_SystemAddGuard(void* start, size_t size) { | |
263 static size_t pagesize = 0; | |
264 if (pagesize == 0) { | |
265 SYSTEM_INFO system_info; | |
266 GetSystemInfo(&system_info); | |
267 pagesize = system_info.dwPageSize; | |
268 } | 251 } |
269 | 252 |
270 // We know that TCMalloc_SystemAlloc will give us a correct page alignment | 253 ptr += adjust; |
271 // regardless, so we can just assert to detect erroneous callers. | 254 return reinterpret_cast<void*>(ptr); |
272 assert(reinterpret_cast<size_t>(start) % pagesize == 0); | |
273 | |
274 // Add a guard page to catch metadata corruption. We're using the | |
275 // PAGE_GUARD flag rather than NO_ACCESS because we want the unique | |
276 // exception in crash reports. | |
277 DWORD permissions = 0; | |
278 if (size > pagesize && | |
279 VirtualProtect(start, pagesize, PAGE_READONLY | PAGE_GUARD, | |
280 &permissions)) { | |
281 return pagesize; | |
282 } | |
283 | |
284 return 0; | |
285 } | 255 } |
286 | 256 |
287 void TCMalloc_SystemRelease(void* start, size_t length) { | 257 void TCMalloc_SystemRelease(void* start, size_t length) { |
288 if (VirtualFree(start, length, MEM_DECOMMIT)) | 258 // TODO(csilvers): should I be calling VirtualFree here? |
289 return; | |
290 | |
291 // The decommit may fail if the memory region consists of allocations | |
292 // from more than one call to VirtualAlloc. In this case, fall back to | |
293 // using VirtualQuery to retrieve the allocation boundaries and decommit | |
294 // them each individually. | |
295 | |
296 char* ptr = static_cast<char*>(start); | |
297 char* end = ptr + length; | |
298 MEMORY_BASIC_INFORMATION info; | |
299 while (ptr < end) { | |
300 size_t resultSize = VirtualQuery(ptr, &info, sizeof(info)); | |
301 assert(resultSize == sizeof(info)); | |
302 size_t decommitSize = std::min<size_t>(info.RegionSize, end - ptr); | |
303 BOOL success = VirtualFree(ptr, decommitSize, MEM_DECOMMIT); | |
304 assert(success == TRUE); | |
305 ptr += decommitSize; | |
306 } | |
307 } | |
308 | |
309 void TCMalloc_SystemCommit(void* start, size_t length) { | |
310 if (VirtualAlloc(start, length, MEM_COMMIT, PAGE_READWRITE) == start) | |
311 return; | |
312 | |
313 // The commit may fail if the memory region consists of allocations | |
314 // from more than one call to VirtualAlloc. In this case, fall back to | |
315 // using VirtualQuery to retrieve the allocation boundaries and commit them | |
316 // each individually. | |
317 | |
318 char* ptr = static_cast<char*>(start); | |
319 char* end = ptr + length; | |
320 MEMORY_BASIC_INFORMATION info; | |
321 while (ptr < end) { | |
322 size_t resultSize = VirtualQuery(ptr, &info, sizeof(info)); | |
323 assert(resultSize == sizeof(info)); | |
324 | |
325 size_t commitSize = std::min<size_t>(info.RegionSize, end - ptr); | |
326 void* newAddress = VirtualAlloc(ptr, commitSize, MEM_COMMIT, | |
327 PAGE_READWRITE); | |
328 assert(newAddress == ptr); | |
329 ptr += commitSize; | |
330 } | |
331 } | 259 } |
332 | 260 |
333 bool RegisterSystemAllocator(SysAllocator *allocator, int priority) { | 261 bool RegisterSystemAllocator(SysAllocator *allocator, int priority) { |
334 return false; // we don't allow registration on windows, right now | 262 return false; // we don't allow registration on windows, right now |
335 } | 263 } |
336 | 264 |
337 void DumpSystemAllocatorStats(TCMalloc_Printer* printer) { | 265 void DumpSystemAllocatorStats(TCMalloc_Printer* printer) { |
338 // We don't dump stats on windows, right now | 266 // We don't dump stats on windows, right now |
339 } | 267 } |
340 | 268 |
| 269 // The current system allocator |
| 270 SysAllocator* sys_alloc = NULL; |
| 271 |
341 | 272 |
342 // ----------------------------------------------------------------------- | 273 // ----------------------------------------------------------------------- |
343 // These functions rework existing functions of the same name in the | 274 // These functions rework existing functions of the same name in the |
344 // Google codebase. | 275 // Google codebase. |
345 | 276 |
346 // A replacement for HeapProfiler::CleanupOldProfiles. | 277 // A replacement for HeapProfiler::CleanupOldProfiles. |
347 void DeleteMatchingFiles(const char* prefix, const char* full_glob) { | 278 void DeleteMatchingFiles(const char* prefix, const char* full_glob) { |
348 WIN32_FIND_DATAA found; // that final A is for Ansi (as opposed to Unicode) | 279 WIN32_FIND_DATAA found; // that final A is for Ansi (as opposed to Unicode) |
349 HANDLE hFind = FindFirstFileA(full_glob, &found); // A is for Ansi | 280 HANDLE hFind = FindFirstFileA(full_glob, &found); // A is for Ansi |
350 if (hFind != INVALID_HANDLE_VALUE) { | 281 if (hFind != INVALID_HANDLE_VALUE) { |
351 const int prefix_length = strlen(prefix); | 282 const int prefix_length = strlen(prefix); |
352 do { | 283 do { |
353 const char *fname = found.cFileName; | 284 const char *fname = found.cFileName; |
354 if ((strlen(fname) >= prefix_length) && | 285 if ((strlen(fname) >= prefix_length) && |
355 (memcmp(fname, prefix, prefix_length) == 0)) { | 286 (memcmp(fname, prefix, prefix_length) == 0)) { |
356 RAW_VLOG(0, "Removing old heap profile %s\n", fname); | 287 RAW_VLOG(0, "Removing old heap profile %s\n", fname); |
357 // TODO(csilvers): we really need to unlink dirname + fname | 288 // TODO(csilvers): we really need to unlink dirname + fname |
358 _unlink(fname); | 289 _unlink(fname); |
359 } | 290 } |
360 } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi | 291 } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi |
361 FindClose(hFind); | 292 FindClose(hFind); |
362 } | 293 } |
363 } | 294 } |
OLD | NEW |