bmalloc: Pathological madvise churn on the free(malloc(x)) benchmark
[WebKit-https.git] / Source / bmalloc / bmalloc / VMAllocate.h
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef VMAllocate_h
27 #define VMAllocate_h
28
29 #include "BAssert.h"
30 #include "Range.h"
31 #include "Sizes.h"
32 #include "Syscall.h"
33 #include <algorithm>
34 #include <sys/mman.h>
35 #include <unistd.h>
36
37 #if BOS(DARWIN)
38 #include <mach/vm_statistics.h>
39 #endif
40
41 namespace bmalloc {
42
43 #if BOS(DARWIN)
44 #define BMALLOC_VM_TAG VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
45 #else
46 #define BMALLOC_VM_TAG -1
47 #endif
48
49 inline size_t vmSize(size_t size)
50 {
51     return roundUpToMultipleOf<vmPageSize>(size);
52 }
53
54 inline void vmValidate(size_t vmSize)
55 {
56     // We use getpagesize() here instead of vmPageSize because vmPageSize is
57     // allowed to be larger than the OS's true page size.
58
59     UNUSED(vmSize);
60     BASSERT(vmSize);
61     BASSERT(vmSize == roundUpToMultipleOf(static_cast<size_t>(getpagesize()), vmSize));
62 }
63
64 inline void vmValidate(void* p, size_t vmSize)
65 {
66     // We use getpagesize() here instead of vmPageSize because vmPageSize is
67     // allowed to be larger than the OS's true page size.
68
69     vmValidate(vmSize);
70     
71     UNUSED(p);
72     BASSERT(p);
73     BASSERT(p == mask(p, ~(getpagesize() - 1)));
74 }
75
76 inline void* vmAllocate(size_t vmSize)
77 {
78     vmValidate(vmSize);
79     void* result = mmap(0, vmSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, BMALLOC_VM_TAG, 0);
80     RELEASE_BASSERT(result != MAP_FAILED);
81     return result;
82 }
83
84 inline void vmDeallocate(void* p, size_t vmSize)
85 {
86     vmValidate(p, vmSize);
87     munmap(p, vmSize);
88 }
89
90 // Allocates vmSize bytes at a specified power-of-two alignment.
91 // Use this function to create maskable memory regions.
92
93 inline void* vmAllocate(size_t vmAlignment, size_t vmSize)
94 {
95     vmValidate(vmSize);
96     vmValidate(vmAlignment);
97
98     size_t mappedSize = std::max(vmSize, vmAlignment) + vmAlignment;
99     char* mapped = static_cast<char*>(vmAllocate(mappedSize));
100     char* mappedEnd = mapped + mappedSize;
101
102     char* aligned = roundUpToMultipleOf(vmAlignment, mapped);
103     char* alignedEnd = aligned + vmSize;
104     
105     if (size_t leftExtra = aligned - mapped)
106         vmDeallocate(mapped, leftExtra);
107     
108     if (size_t rightExtra = mappedEnd - alignedEnd)
109         vmDeallocate(alignedEnd, rightExtra);
110
111     return aligned;
112 }
113
114 inline void vmDeallocatePhysicalPages(void* p, size_t vmSize)
115 {
116     vmValidate(p, vmSize);
117 #if BOS(DARWIN)
118     SYSCALL(madvise(p, vmSize, MADV_FREE_REUSABLE));
119 #else
120     SYSCALL(madvise(p, vmSize, MADV_DONTNEED));
121 #endif
122 }
123
124 inline void vmAllocatePhysicalPages(void* p, size_t vmSize)
125 {
126     vmValidate(p, vmSize);
127 #if BOS(DARWIN)
128     SYSCALL(madvise(p, vmSize, MADV_FREE_REUSE));
129 #else
130     SYSCALL(madvise(p, vmSize, MADV_NORMAL));
131 #endif
132 }
133
134 // Trims requests that are un-page-aligned.
135 inline void vmDeallocatePhysicalPagesSloppy(void* p, size_t size)
136 {
137     char* begin = roundUpToMultipleOf<vmPageSize>(static_cast<char*>(p));
138     char* end = roundDownToMultipleOf<vmPageSize>(static_cast<char*>(p) + size);
139
140     if (begin >= end)
141         return;
142
143     vmDeallocatePhysicalPages(begin, end - begin);
144 }
145
146 // Expands requests that are un-page-aligned. NOTE: Allocation must proceed left-to-right.
147 inline void vmAllocatePhysicalPagesSloppy(void* p, size_t size)
148 {
149     char* begin = roundUpToMultipleOf<vmPageSize>(static_cast<char*>(p));
150     char* end = roundUpToMultipleOf<vmPageSize>(static_cast<char*>(p) + size);
151
152     if (begin >= end)
153         return;
154
155     vmAllocatePhysicalPages(begin, end - begin);
156 }
157
158 } // namespace bmalloc
159
160 #endif // VMAllocate_h