49b91bc3fae1c168ff84f90809d5644ef8f21383
[WebKit-https.git] / PerformanceTests / MallocBench / MallocBench / stress_aligned.cpp
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 #include "Benchmark.h"
27 #include "CPUCount.h"
28 #include "stress_aligned.h"
29 #include <array>
30 #include <chrono>
31 #include <cmath>
32 #include <cstdlib>
33 #include <memory>
34 #include <stddef.h>
35 #include <vector>
36
37 #include "mbmalloc.h"
38
39 namespace {
40
41 static const size_t kB = 1024;
42 static const size_t MB = kB * kB;
43
44 struct Object {
45     Object(void* pointer, size_t size, long uuid)
46         : pointer(pointer)
47         , size(size)
48         , uuid(uuid)
49     {
50     }
51
52     void* pointer;
53     size_t size;
54     long uuid;
55 };
56
57 class SizeStream {
58 public:
59     SizeStream()
60         : m_state(Small)
61         , m_count(0)
62     {
63     }
64
65     size_t next()
66     {
67         switch (m_state) {
68         case Small: {
69             if (++m_count == smallCount) {
70                 m_state = Medium;
71                 m_count = 0;
72             }
73             return random() % smallMax;
74         }
75
76         case Medium: {
77             if (++m_count == mediumCount) {
78                 m_state = Large;
79                 m_count = 0;
80             }
81             return random() % mediumMax;
82         }
83
84         case Large: {
85             if (++m_count == largeCount) {
86                 m_state = Small;
87                 m_count = 0;
88             }
89             return random() % largeMax;
90         }
91         }
92     }
93
94 private:
95     static const size_t smallCount = 1000;
96     static const size_t smallMax = 16 * kB;
97
98     static const size_t mediumCount = 100;
99     static const size_t mediumMax = 512 * kB;
100     
101     static const size_t largeCount = 10;
102     static const size_t largeMax = 4 * MB;
103
104     enum { Small, Medium, Large } m_state;
105     size_t m_count;
106 };
107
108 Object allocate(size_t alignment, size_t size)
109 {
110     Object object(mbmemalign(alignment, size), size, random());
111     if ((uintptr_t)object.pointer & (alignment - 1))
112         abort();
113     for (size_t i = 0; i < size / sizeof(long); ++i)
114         (static_cast<long*>(object.pointer))[i] = object.uuid;
115     return object;
116 }
117
118 void deallocate(const Object& object)
119 {
120     for (size_t i = 0; i < object.size / sizeof(long); ++i) {
121         if ((static_cast<long*>(object.pointer))[i] != object.uuid)
122             abort();
123     }
124
125     mbfree(object.pointer, object.size);
126 }
127
128 size_t randomAlignment()
129 {
130     switch (random() % 32) {
131     case 0:
132         return pow(2, random() % 26);
133     default:
134         return pow(2, random() % 14);
135     }
136 }
137
138 }
139
140 void benchmark_stress_aligned(CommandLine&)
141 {
142     const size_t heapSize = 100 * MB;
143     const size_t churnSize = .05 * heapSize;
144     const size_t churnCount = 100;
145     
146     srandom(1); // For consistency between runs.
147
148     size_t limit = 0x00001ffffffffffful;
149     
150     for (size_t size = 0; size < limit; size = std::max(size, sizeof(void*)) * 2) {
151         for (size_t alignment = sizeof(void*); alignment < limit; alignment *= 2) {
152             void* object = mbmemalign(alignment, size);
153             if (reinterpret_cast<uintptr_t>(object) & (alignment - 1))
154                 abort();
155             mbfree(object, size);
156         }
157
158         for (size_t alignment = sizeof(void*); alignment < limit; alignment *= 2) {
159             void* object = mbmemalign(alignment, size + 128);
160             if (reinterpret_cast<uintptr_t>(object) & (alignment - 1))
161                 abort();
162             mbfree(object, size + 128);
163         }
164     }
165
166     std::vector<Object> objects;
167     
168     SizeStream sizeStream;
169     
170     size_t size = 0;
171     for (size_t remaining = heapSize; remaining; remaining -= std::min(remaining, size)) {
172         size = sizeStream.next();
173         objects.push_back(allocate(randomAlignment(), size));
174     }
175     
176     for (size_t i = 0; i < churnCount; ++i) {
177         std::vector<Object> objectsToFree;
178         for (size_t remaining = churnSize; remaining; remaining -= std::min(remaining, size)) {
179             size = sizeStream.next();
180             Object object = allocate(randomAlignment(), size);
181
182             size_t index = random() % objects.size();
183             objectsToFree.push_back(objects[index]);
184             objects[index] = object;
185         }
186
187         for (auto& object : objectsToFree)
188             deallocate(object);
189         
190         mbscavenge();
191     }
192     
193     for (auto& object : objects)
194         mbfree(object.pointer, object.size);
195 }