bmalloc: Misc improvements to MallocBench
[WebKit.git] / PerformanceTests / MallocBench / MallocBench / stress.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.h"
29 #include <array>
30 #include <chrono>
31 #include <cstdlib>
32 #include <memory>
33 #include <stddef.h>
34 #include <vector>
35
36 #include "mbmalloc.h"
37
38 static const size_t kB = 1024;
39 static const size_t MB = kB * kB;
40
41 struct Object {
42     Object(void* pointer, size_t size, long uuid)
43         : pointer(pointer)
44         , size(size)
45         , uuid(uuid)
46     {
47     }
48
49     void* pointer;
50     size_t size;
51     long uuid;
52 };
53
54 class SizeStream {
55 public:
56     SizeStream()
57         : m_state(Small)
58         , m_count(0)
59     {
60     }
61
62     size_t next()
63     {
64         switch (m_state) {
65         case Small: {
66             if (++m_count == smallCount) {
67                 m_state = Medium;
68                 m_count = 0;
69             }
70             return random() % smallMax;
71         }
72                 
73         case Medium: {
74             if (++m_count == mediumCount) {
75                 m_state = Large;
76                 m_count = 0;
77             }
78             return random() % mediumMax;
79         }
80                 
81         case Large: {
82             if (++m_count == largeCount) {
83                 m_state = Small;
84                 m_count = 0;
85             }
86             return random() % largeMax;
87         }
88         }
89     }
90
91 private:
92     static const size_t smallCount = 1000;
93     static const size_t smallMax = 16 * kB;
94
95     static const size_t mediumCount = 100;
96     static const size_t mediumMax = 512 * kB;
97     
98     static const size_t largeCount = 10;
99     static const size_t largeMax = 4 * MB;
100
101     enum { Small, Medium, Large } m_state;
102     size_t m_count;
103 };
104
105 Object allocate(size_t size)
106 {
107     Object object(mbmalloc(size), size, random());
108     for (size_t i = 0; i < size / sizeof(long); ++i)
109         (static_cast<long*>(object.pointer))[i] = object.uuid;
110     return object;
111 }
112
113 void deallocate(const Object& object)
114 {
115     for (size_t i = 0; i < object.size / sizeof(long); ++i) {
116         if ((static_cast<long*>(object.pointer))[i] != object.uuid)
117             abort();
118     }
119
120     mbfree(object.pointer, object.size);
121 }
122
123 void benchmark_stress(CommandLine&)
124 {
125     const size_t heapSize = 100 * MB;
126     const size_t churnSize = .05 * heapSize;
127     const size_t churnCount = 100;
128     
129     srandom(1); // For consistency between runs.
130
131     std::vector<Object> objects;
132     
133     SizeStream sizeStream;
134     
135     size_t size = 0;
136     for (size_t remaining = heapSize; remaining; remaining -= std::min(remaining, size)) {
137         size = sizeStream.next();
138         objects.push_back(allocate(size));
139     }
140     
141     for (size_t i = 0; i < churnCount; ++i) {
142         std::vector<Object> objectsToFree;
143         for (size_t remaining = churnSize; remaining; remaining -= std::min(remaining, size)) {
144             size = sizeStream.next();
145             Object object = allocate(size);
146
147             size_t index = random() % objects.size();
148             objectsToFree.push_back(objects[index]);
149             objects[index] = object;
150         }
151
152         for (auto& object : objectsToFree)
153             deallocate(object);
154         
155         mbscavenge();
156     }
157     
158     for (auto& object : objects)
159         mbfree(object.pointer, object.size);
160 }