Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/gtest/metaspace/test_chunkManager_stress.cpp
41144 views
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/chunkManager.hpp"
28
#include "memory/metaspace/metaspaceSettings.hpp"
29
#include "memory/metaspace/virtualSpaceList.hpp"
30
//#define LOG_PLEASE
31
#include "metaspaceGtestCommon.hpp"
32
#include "metaspaceGtestContexts.hpp"
33
#include "metaspaceGtestRangeHelpers.hpp"
34
#include "metaspaceGtestSparseArray.hpp"
35
36
using metaspace::ChunkManager;
37
using metaspace::Settings;
38
39
class ChunkManagerRandomChunkAllocTest {
40
41
static const size_t max_footprint_words = 8 * M;
42
43
ChunkGtestContext _context;
44
45
// All allocated live chunks
46
typedef SparseArray<Metachunk*> SparseArrayOfChunks;
47
SparseArrayOfChunks _chunks;
48
49
const ChunkLevelRange _chunklevel_range;
50
const float _commit_factor;
51
52
// Depending on a probability pattern, come up with a reasonable limit to number of live chunks
53
static int max_num_live_chunks(ChunkLevelRange r, float commit_factor) {
54
// Assuming we allocate only the largest type of chunk, committed to the fullest commit factor,
55
// how many chunks can we accomodate before hitting max_footprint_words?
56
const size_t largest_chunk_size = word_size_for_level(r.lowest());
57
int max_chunks = (max_footprint_words * commit_factor) / largest_chunk_size;
58
// .. but cap at (min) 50 and (max) 1000
59
max_chunks = MIN2(1000, max_chunks);
60
max_chunks = MAX2(50, max_chunks);
61
return max_chunks;
62
}
63
64
// Return true if, after an allocation error happened, a reserve error seems likely.
65
bool could_be_reserve_error() {
66
return _context.vslist().is_full();
67
}
68
69
// Return true if, after an allocation error happened, a commit error seems likely.
70
bool could_be_commit_error(size_t additional_word_size) {
71
72
// could it be commit limit hit?
73
74
if (Settings::new_chunks_are_fully_committed()) {
75
// For all we know we may have just failed to fully-commit a new root chunk.
76
additional_word_size = MAX_CHUNK_WORD_SIZE;
77
}
78
79
// Note that this is difficult to verify precisely, since there are
80
// several layers of truth:
81
// a) at the lowest layer (RootChunkArea) we have a bitmap of committed granules;
82
// b) at the vslist layer, we keep running counters of committed/reserved words;
83
// c) at the chunk layer, we keep a commit watermark (committed_words).
84
//
85
// (a) should mirror reality.
86
// (a) and (b) should be precisely in sync. This is tested by
87
// VirtualSpaceList::verify().
88
// (c) can be, by design, imprecise (too low).
89
//
90
// Here, I check (b) and trust it to be correct. We also call vslist::verify().
91
DEBUG_ONLY(_context.verify();)
92
93
const size_t commit_add = align_up(additional_word_size, Settings::commit_granule_words());
94
if (_context.commit_limit() <= (commit_add + _context.vslist().committed_words())) {
95
return true;
96
}
97
98
return false;
99
100
}
101
102
// Given a chunk level and a factor, return a random commit size.
103
static size_t random_committed_words(chunklevel_t lvl, float commit_factor) {
104
const size_t sz = word_size_for_level(lvl) * commit_factor;
105
if (sz < 2) {
106
return 0;
107
}
108
return MIN2(SizeRange(sz).random_value(), sz);
109
}
110
111
//// Chunk allocation ////
112
113
// Given an slot index, allocate a random chunk and set it into that slot. Slot must be empty.
114
// Returns false if allocation fails.
115
bool allocate_random_chunk_at(int slot) {
116
117
DEBUG_ONLY(_chunks.check_slot_is_null(slot);)
118
119
const ChunkLevelRange r = _chunklevel_range.random_subrange();
120
const chunklevel_t pref_level = r.lowest();
121
const chunklevel_t max_level = r.highest();
122
const size_t min_committed = random_committed_words(max_level, _commit_factor);
123
124
Metachunk* c = NULL;
125
_context.alloc_chunk(&c, r.lowest(), r.highest(), min_committed);
126
if (c == NULL) {
127
EXPECT_TRUE(could_be_reserve_error() ||
128
could_be_commit_error(min_committed));
129
LOG("Alloc chunk at %d failed.", slot);
130
return false;
131
}
132
133
_chunks.set_at(slot, c);
134
135
LOG("Allocated chunk at %d: " METACHUNK_FORMAT ".", slot, METACHUNK_FORMAT_ARGS(c));
136
137
return true;
138
139
}
140
141
// Allocates a random number of random chunks
142
bool allocate_random_chunks() {
143
int to_alloc = 1 + IntRange(MAX2(1, _chunks.size() / 8)).random_value();
144
bool success = true;
145
int slot = _chunks.first_null_slot();
146
while (to_alloc > 0 && slot != -1 && success) {
147
success = allocate_random_chunk_at(slot);
148
slot = _chunks.next_null_slot(slot);
149
to_alloc --;
150
}
151
return success && to_alloc == 0;
152
}
153
154
bool fill_all_slots_with_random_chunks() {
155
bool success = true;
156
for (int slot = _chunks.first_null_slot();
157
slot != -1 && success; slot = _chunks.next_null_slot(slot)) {
158
success = allocate_random_chunk_at(slot);
159
}
160
return success;
161
}
162
163
//// Chunk return ////
164
165
// Given an slot index, return the chunk in that slot to the chunk manager.
166
void return_chunk_at(int slot) {
167
Metachunk* c = _chunks.at(slot);
168
LOG("Returning chunk at %d: " METACHUNK_FORMAT ".", slot, METACHUNK_FORMAT_ARGS(c));
169
_context.return_chunk(c);
170
_chunks.set_at(slot, NULL);
171
}
172
173
// return a random number of chunks (at most a quarter of the full slot range)
174
void return_random_chunks() {
175
int to_free = 1 + IntRange(MAX2(1, _chunks.size() / 8)).random_value();
176
int index = _chunks.first_non_null_slot();
177
while (to_free > 0 && index != -1) {
178
return_chunk_at(index);
179
index = _chunks.next_non_null_slot(index);
180
to_free --;
181
}
182
}
183
184
void return_all_chunks() {
185
for (int slot = _chunks.first_non_null_slot();
186
slot != -1; slot = _chunks.next_non_null_slot(slot)) {
187
return_chunk_at(slot);
188
}
189
}
190
191
// adjust test if we change levels
192
STATIC_ASSERT(HIGHEST_CHUNK_LEVEL == CHUNK_LEVEL_1K);
193
STATIC_ASSERT(LOWEST_CHUNK_LEVEL == CHUNK_LEVEL_4M);
194
195
void one_test() {
196
197
fill_all_slots_with_random_chunks();
198
_chunks.shuffle();
199
200
IntRange rand(100);
201
202
for (int j = 0; j < 1000; j++) {
203
204
bool force_alloc = false;
205
bool force_free = true;
206
207
bool do_alloc =
208
force_alloc ? true :
209
(force_free ? false : rand.random_value() >= 50);
210
force_alloc = force_free = false;
211
212
if (do_alloc) {
213
if (!allocate_random_chunks()) {
214
force_free = true;
215
}
216
} else {
217
return_random_chunks();
218
}
219
220
_chunks.shuffle();
221
222
}
223
224
return_all_chunks();
225
226
}
227
228
public:
229
230
// A test with no limits
231
ChunkManagerRandomChunkAllocTest(ChunkLevelRange r, float commit_factor) :
232
_context(),
233
_chunks(max_num_live_chunks(r, commit_factor)),
234
_chunklevel_range(r),
235
_commit_factor(commit_factor)
236
{}
237
238
// A test with no reserve limit but commit limit
239
ChunkManagerRandomChunkAllocTest(size_t commit_limit,
240
ChunkLevelRange r, float commit_factor) :
241
_context(commit_limit),
242
_chunks(max_num_live_chunks(r, commit_factor)),
243
_chunklevel_range(r),
244
_commit_factor(commit_factor)
245
{}
246
247
// A test with both reserve and commit limit
248
// ChunkManagerRandomChunkAllocTest(size_t commit_limit, size_t reserve_limit,
249
// ChunkLevelRange r, float commit_factor)
250
// : _helper(commit_limit, reserve_limit),
251
// _chunks(max_num_live_chunks(r, commit_factor)),
252
// _chunklevel_range(r),
253
// _commit_factor(commit_factor)
254
// {}
255
256
void do_tests() {
257
const int num_runs = 5;
258
for (int n = 0; n < num_runs; n++) {
259
one_test();
260
}
261
}
262
263
};
264
265
#define DEFINE_TEST(name, range, commit_factor) \
266
TEST_VM(metaspace, chunkmanager_random_alloc_##name) { \
267
ChunkManagerRandomChunkAllocTest test(range, commit_factor); \
268
test.do_tests(); \
269
}
270
271
DEFINE_TEST(test_nolimit_1, ChunkLevelRanges::small_chunks(), 0.0f)
272
DEFINE_TEST(test_nolimit_2, ChunkLevelRanges::small_chunks(), 0.5f)
273
DEFINE_TEST(test_nolimit_3, ChunkLevelRanges::small_chunks(), 1.0f)
274
275
DEFINE_TEST(test_nolimit_4, ChunkLevelRanges::all_chunks(), 0.0f)
276
DEFINE_TEST(test_nolimit_5, ChunkLevelRanges::all_chunks(), 0.5f)
277
DEFINE_TEST(test_nolimit_6, ChunkLevelRanges::all_chunks(), 1.0f)
278
279
#define DEFINE_TEST_2(name, range, commit_factor) \
280
TEST_VM(metaspace, chunkmanager_random_alloc_##name) { \
281
const size_t commit_limit = 256 * K; \
282
ChunkManagerRandomChunkAllocTest test(commit_limit, range, commit_factor); \
283
test.do_tests(); \
284
}
285
286
DEFINE_TEST_2(test_with_limit_1, ChunkLevelRanges::small_chunks(), 0.0f)
287
DEFINE_TEST_2(test_with_limit_2, ChunkLevelRanges::small_chunks(), 0.5f)
288
DEFINE_TEST_2(test_with_limit_3, ChunkLevelRanges::small_chunks(), 1.0f)
289
290
DEFINE_TEST_2(test_with_limit_4, ChunkLevelRanges::all_chunks(), 0.0f)
291
DEFINE_TEST_2(test_with_limit_5, ChunkLevelRanges::all_chunks(), 0.5f)
292
DEFINE_TEST_2(test_with_limit_6, ChunkLevelRanges::all_chunks(), 1.0f)
293
294
295