1 /*
2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2020 SAP SE. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #include "precompiled.hpp"
27 #include "memory/metaspace/counters.hpp"
28 #include "memory/metaspace/freeBlocks.hpp"
29 //#define LOG_PLEASE
30 #include "metaspaceGtestCommon.hpp"
31
32 using metaspace::FreeBlocks;
33 using metaspace::SizeCounter;
34
35 #define CHECK_CONTENT(fb, num_blocks_expected, word_size_expected) \
36 { \
37 if (word_size_expected > 0) { \
38 EXPECT_FALSE(fb.is_empty()); \
39 } else { \
40 EXPECT_TRUE(fb.is_empty()); \
41 } \
42 EXPECT_EQ(fb.total_size(), (size_t)word_size_expected); \
43 EXPECT_EQ(fb.count(), (int)num_blocks_expected); \
44 }
45
46 class FreeBlocksTest {
47
48 FeederBuffer _fb;
49 FreeBlocks _freeblocks;
50
51 // random generator for block feeding
52 RandSizeGenerator _rgen_feeding;
53
54 // random generator for allocations (and, hence, deallocations)
55 RandSizeGenerator _rgen_allocations;
56
57 SizeCounter _allocated_words;
58
59 struct allocation_t {
60 allocation_t* next;
61 size_t word_size;
62 MetaWord* p;
63 };
64
65 // Array of the same size as the pool max capacity; holds the allocated elements.
66 allocation_t* _allocations;
67
68 int _num_allocs;
69 int _num_deallocs;
70 int _num_feeds;
71
feed_some()72 bool feed_some() {
73 size_t word_size = _rgen_feeding.get();
74 MetaWord* p = _fb.get(word_size);
75 if (p != NULL) {
76 _freeblocks.add_block(p, word_size);
77 return true;
78 }
79 return false;
80 }
81
deallocate_top()82 void deallocate_top() {
83
84 allocation_t* a = _allocations;
85 if (a != NULL) {
86 _allocations = a->next;
87 check_marked_range(a->p, a->word_size);
88 _freeblocks.add_block(a->p, a->word_size);
89 delete a;
90 DEBUG_ONLY(_freeblocks.verify();)
91 }
92 }
93
allocate()94 bool allocate() {
95
96 size_t word_size = MAX2(_rgen_allocations.get(), _freeblocks.MinWordSize);
97 MetaWord* p = _freeblocks.remove_block(word_size);
98 if (p != NULL) {
99 _allocated_words.increment_by(word_size);
100 allocation_t* a = new allocation_t;
101 a->p = p; a->word_size = word_size;
102 a->next = _allocations;
103 _allocations = a;
104 DEBUG_ONLY(_freeblocks.verify();)
105 mark_range(p, word_size);
106 return true;
107 }
108 return false;
109 }
110
test_all_marked_ranges()111 void test_all_marked_ranges() {
112 for (allocation_t* a = _allocations; a != NULL; a = a->next) {
113 check_marked_range(a->p, a->word_size);
114 }
115 }
116
test_loop()117 void test_loop() {
118 // We loop and in each iteration execute one of three operations:
119 // - allocation from fbl
120 // - deallocation to fbl of a previously allocated block
121 // - feeding a new larger block into the fbl (mimicks chunk retiring)
122 // When we have fed all large blocks into the fbl (feedbuffer empty), we
123 // switch to draining the fbl completely (only allocs)
124 bool forcefeed = false;
125 bool draining = false;
126 bool stop = false;
127 int iter = 100000; // safety stop
128 while (!stop && iter > 0) {
129 iter --;
130 int surprise = (int)os::random() % 10;
131 if (!draining && (surprise >= 7 || forcefeed)) {
132 forcefeed = false;
133 if (feed_some()) {
134 _num_feeds++;
135 } else {
136 // We fed all input memory into the fbl. Now lets proceed until the fbl is drained.
137 draining = true;
138 }
139 } else if (!draining && surprise < 1) {
140 deallocate_top();
141 _num_deallocs++;
142 } else {
143 if (allocate()) {
144 _num_allocs++;
145 } else {
146 if (draining) {
147 stop = _freeblocks.total_size() < 512;
148 } else {
149 forcefeed = true;
150 }
151 }
152 }
153 if ((iter % 1000) == 0) {
154 DEBUG_ONLY(_freeblocks.verify();)
155 test_all_marked_ranges();
156 LOG("a %d (" SIZE_FORMAT "), d %d, f %d", _num_allocs, _allocated_words.get(), _num_deallocs, _num_feeds);
157 #ifdef LOG_PLEASE
158 _freeblocks.print(tty, true);
159 tty->cr();
160 #endif
161 }
162 }
163
164 // Drain
165
166 }
167
168 public:
169
FreeBlocksTest(size_t avg_alloc_size)170 FreeBlocksTest(size_t avg_alloc_size) :
171 _fb(512 * K), _freeblocks(),
172 _rgen_feeding(128, 4096),
173 _rgen_allocations(avg_alloc_size / 4, avg_alloc_size * 2, 0.01f, avg_alloc_size / 3, avg_alloc_size * 30),
174 _allocations(NULL),
175 _num_allocs(0),
176 _num_deallocs(0),
177 _num_feeds(0)
178 {
179 CHECK_CONTENT(_freeblocks, 0, 0);
180 // some initial feeding
181 _freeblocks.add_block(_fb.get(1024), 1024);
182 CHECK_CONTENT(_freeblocks, 1, 1024);
183 }
184
test_small_allocations()185 static void test_small_allocations() {
186 FreeBlocksTest test(10);
187 test.test_loop();
188 }
189
test_medium_allocations()190 static void test_medium_allocations() {
191 FreeBlocksTest test(30);
192 test.test_loop();
193 }
194
test_large_allocations()195 static void test_large_allocations() {
196 FreeBlocksTest test(150);
197 test.test_loop();
198 }
199
200 };
201
TEST_VM(metaspace,freeblocks_basics)202 TEST_VM(metaspace, freeblocks_basics) {
203
204 FreeBlocks fbl;
205 MetaWord tmp[1024];
206 CHECK_CONTENT(fbl, 0, 0);
207
208 fbl.add_block(tmp, 1024);
209 DEBUG_ONLY(fbl.verify();)
210 ASSERT_FALSE(fbl.is_empty());
211 CHECK_CONTENT(fbl, 1, 1024);
212
213 MetaWord* p = fbl.remove_block(1024);
214 EXPECT_EQ(p, tmp);
215 DEBUG_ONLY(fbl.verify();)
216 CHECK_CONTENT(fbl, 0, 0);
217
218 }
219
TEST_VM(metaspace,freeblocks_small)220 TEST_VM(metaspace, freeblocks_small) {
221 FreeBlocksTest::test_small_allocations();
222 }
223
TEST_VM(metaspace,freeblocks_medium)224 TEST_VM(metaspace, freeblocks_medium) {
225 FreeBlocksTest::test_medium_allocations();
226 }
227
TEST_VM(metaspace,freeblocks_large)228 TEST_VM(metaspace, freeblocks_large) {
229 FreeBlocksTest::test_large_allocations();
230 }
231
232