comparison src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp @ 20211:82693fb204a5

8038930: G1CodeRootSet::test fails with assert(_num_chunks_handed_out == 0) failed: No elements must have been handed out yet Summary: The test incorrectly assumed that it had been started with no other previous compilation activity. Fix this by allowing multiple code root free chunk lists, and use one separate from the global one to perform the test. Reviewed-by: brutisso
author tschatzl
date Wed, 16 Apr 2014 10:14:50 +0200
parents 78bbf4d43a14
children 828056cf311f
comparison
equal deleted inserted replaced
20210:3a62cd59c8d8 20211:82693fb204a5
45 cl->do_code_blob(*cur); 45 cl->do_code_blob(*cur);
46 cur++; 46 cur++;
47 } 47 }
48 } 48 }
49 49
50 FreeList<G1CodeRootChunk> G1CodeRootSet::_free_list; 50 G1CodeRootChunkManager::G1CodeRootChunkManager() : _free_list(), _num_chunks_handed_out(0) {
51 size_t G1CodeRootSet::_num_chunks_handed_out = 0; 51 _free_list.initialize();
52 52 _free_list.set_size(G1CodeRootChunk::word_size());
53 G1CodeRootChunk* G1CodeRootSet::new_chunk() { 53 }
54 G1CodeRootChunk* result = _free_list.get_chunk_at_head(); 54
55 if (result == NULL) { 55 size_t G1CodeRootChunkManager::fl_mem_size() {
56 result = new G1CodeRootChunk(); 56 return _free_list.count() * _free_list.size();
57 } 57 }
58 G1CodeRootSet::_num_chunks_handed_out++; 58
59 result->reset(); 59 void G1CodeRootChunkManager::free_all_chunks(FreeList<G1CodeRootChunk>* list) {
60 return result; 60 _num_chunks_handed_out -= list->count();
61 } 61 _free_list.prepend(list);
62 62 }
63 void G1CodeRootSet::free_chunk(G1CodeRootChunk* chunk) { 63
64 void G1CodeRootChunkManager::free_chunk(G1CodeRootChunk* chunk) {
64 _free_list.return_chunk_at_head(chunk); 65 _free_list.return_chunk_at_head(chunk);
65 G1CodeRootSet::_num_chunks_handed_out--; 66 _num_chunks_handed_out--;
66 } 67 }
67 68
68 void G1CodeRootSet::free_all_chunks(FreeList<G1CodeRootChunk>* list) { 69 void G1CodeRootChunkManager::purge_chunks(size_t keep_ratio) {
69 G1CodeRootSet::_num_chunks_handed_out -= list->count(); 70 size_t keep = _num_chunks_handed_out * keep_ratio / 100;
70 _free_list.prepend(list);
71 }
72
73 void G1CodeRootSet::purge_chunks(size_t keep_ratio) {
74 size_t keep = G1CodeRootSet::_num_chunks_handed_out * keep_ratio / 100;
75
76 if (keep >= (size_t)_free_list.count()) { 71 if (keep >= (size_t)_free_list.count()) {
77 return; 72 return;
78 } 73 }
79 74
80 FreeList<G1CodeRootChunk> temp; 75 FreeList<G1CodeRootChunk> temp;
88 delete cur; 83 delete cur;
89 cur = temp.get_chunk_at_head(); 84 cur = temp.get_chunk_at_head();
90 } 85 }
91 } 86 }
92 87
88 size_t G1CodeRootChunkManager::static_mem_size() {
89 return sizeof(this);
90 }
91
92
93 G1CodeRootChunk* G1CodeRootChunkManager::new_chunk() {
94 G1CodeRootChunk* result = _free_list.get_chunk_at_head();
95 if (result == NULL) {
96 result = new G1CodeRootChunk();
97 }
98 _num_chunks_handed_out++;
99 result->reset();
100 return result;
101 }
102
103 #ifndef PRODUCT
104
105 size_t G1CodeRootChunkManager::num_chunks_handed_out() const {
106 return _num_chunks_handed_out;
107 }
108
109 size_t G1CodeRootChunkManager::num_free_chunks() const {
110 return (size_t)_free_list.count();
111 }
112
113 #endif
114
115 G1CodeRootChunkManager G1CodeRootSet::_default_chunk_manager;
116
117 void G1CodeRootSet::purge_chunks(size_t keep_ratio) {
118 _default_chunk_manager.purge_chunks(keep_ratio);
119 }
120
93 size_t G1CodeRootSet::static_mem_size() { 121 size_t G1CodeRootSet::static_mem_size() {
94 return sizeof(_free_list) + sizeof(_num_chunks_handed_out); 122 return _default_chunk_manager.static_mem_size();
95 } 123 }
96 124
97 size_t G1CodeRootSet::fl_mem_size() { 125 size_t G1CodeRootSet::free_chunks_mem_size() {
98 return _free_list.count() * _free_list.size(); 126 return _default_chunk_manager.fl_mem_size();
99 } 127 }
100 128
101 void G1CodeRootSet::initialize() { 129 G1CodeRootSet::G1CodeRootSet(G1CodeRootChunkManager* manager) : _manager(manager), _list(), _length(0) {
102 _free_list.initialize(); 130 if (_manager == NULL) {
103 _free_list.set_size(G1CodeRootChunk::word_size()); 131 _manager = &_default_chunk_manager;
104 } 132 }
105
106 G1CodeRootSet::G1CodeRootSet() : _list(), _length(0) {
107 _list.initialize(); 133 _list.initialize();
108 _list.set_size(G1CodeRootChunk::word_size()); 134 _list.set_size(G1CodeRootChunk::word_size());
109 } 135 }
110 136
111 G1CodeRootSet::~G1CodeRootSet() { 137 G1CodeRootSet::~G1CodeRootSet() {
194 } 220 }
195 221
196 #ifndef PRODUCT 222 #ifndef PRODUCT
197 223
198 void G1CodeRootSet::test() { 224 void G1CodeRootSet::test() {
199 initialize(); 225 G1CodeRootChunkManager mgr;
200 226
201 assert(_free_list.count() == 0, "Free List must be empty"); 227 assert(mgr.num_chunks_handed_out() == 0, "Must not have handed out chunks yet");
202 assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet");
203 228
204 // The number of chunks that we allocate for purge testing. 229 // The number of chunks that we allocate for purge testing.
205 size_t const num_chunks = 10; 230 size_t const num_chunks = 10;
231
206 { 232 {
207 G1CodeRootSet set1; 233 G1CodeRootSet set1(&mgr);
208 assert(set1.is_empty(), "Code root set must be initially empty but is not."); 234 assert(set1.is_empty(), "Code root set must be initially empty but is not.");
209 235
210 set1.add((nmethod*)1); 236 set1.add((nmethod*)1);
211 assert(_num_chunks_handed_out == 1, 237 assert(mgr.num_chunks_handed_out() == 1,
212 err_msg("Must have allocated and handed out one chunk, but handed out " 238 err_msg("Must have allocated and handed out one chunk, but handed out "
213 SIZE_FORMAT" chunks", _num_chunks_handed_out)); 239 SIZE_FORMAT" chunks", mgr.num_chunks_handed_out()));
214 assert(set1.length() == 1, err_msg("Added exactly one element, but set contains " 240 assert(set1.length() == 1, err_msg("Added exactly one element, but set contains "
215 SIZE_FORMAT" elements", set1.length())); 241 SIZE_FORMAT" elements", set1.length()));
216 242
217 // G1CodeRootChunk::word_size() is larger than G1CodeRootChunk::num_entries which 243 // G1CodeRootChunk::word_size() is larger than G1CodeRootChunk::num_entries which
218 // we cannot access. 244 // we cannot access.
219 for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) { 245 for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) {
220 set1.add((nmethod*)1); 246 set1.add((nmethod*)1);
221 } 247 }
222 assert(_num_chunks_handed_out == 1, 248 assert(mgr.num_chunks_handed_out() == 1,
223 err_msg("Duplicate detection must have prevented allocation of further " 249 err_msg("Duplicate detection must have prevented allocation of further "
224 "chunks but contains "SIZE_FORMAT, _num_chunks_handed_out)); 250 "chunks but allocated "SIZE_FORMAT, mgr.num_chunks_handed_out()));
225 assert(set1.length() == 1, 251 assert(set1.length() == 1,
226 err_msg("Duplicate detection should not have increased the set size but " 252 err_msg("Duplicate detection should not have increased the set size but "
227 "is "SIZE_FORMAT, set1.length())); 253 "is "SIZE_FORMAT, set1.length()));
228 254
229 size_t num_total_after_add = G1CodeRootChunk::word_size() + 1; 255 size_t num_total_after_add = G1CodeRootChunk::word_size() + 1;
230 for (size_t i = 0; i < num_total_after_add - 1; i++) { 256 for (size_t i = 0; i < num_total_after_add - 1; i++) {
231 set1.add((nmethod*)(2 + i)); 257 set1.add((nmethod*)(uintptr_t)(2 + i));
232 } 258 }
233 assert(_num_chunks_handed_out > 1, 259 assert(mgr.num_chunks_handed_out() > 1,
234 "After adding more code roots, more than one chunks should have been handed out"); 260 "After adding more code roots, more than one additional chunk should have been handed out");
235 assert(set1.length() == num_total_after_add, 261 assert(set1.length() == num_total_after_add,
236 err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they " 262 err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they "
237 "need to be in the set, but there are only "SIZE_FORMAT, 263 "need to be in the set, but there are only "SIZE_FORMAT,
238 num_total_after_add, set1.length())); 264 num_total_after_add, set1.length()));
239 265
242 num_popped++; 268 num_popped++;
243 } 269 }
244 assert(num_popped == num_total_after_add, 270 assert(num_popped == num_total_after_add,
245 err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" " 271 err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" "
246 "were added", num_popped, num_total_after_add)); 272 "were added", num_popped, num_total_after_add));
247 assert(_num_chunks_handed_out == 0, 273 assert(mgr.num_chunks_handed_out() == 0,
248 err_msg("After popping all elements, all chunks must have been returned " 274 err_msg("After popping all elements, all chunks must have been returned "
249 "but are still "SIZE_FORMAT, _num_chunks_handed_out)); 275 "but there are still "SIZE_FORMAT" additional", mgr.num_chunks_handed_out()));
250 276
251 purge_chunks(0); 277 mgr.purge_chunks(0);
252 assert(_free_list.count() == 0, 278 assert(mgr.num_free_chunks() == 0,
253 err_msg("After purging everything, the free list must be empty but still " 279 err_msg("After purging everything, the free list must be empty but still "
254 "contains "SIZE_FORMAT" chunks", _free_list.count())); 280 "contains "SIZE_FORMAT" chunks", mgr.num_free_chunks()));
255 281
256 // Add some more handed out chunks. 282 // Add some more handed out chunks.
257 size_t i = 0; 283 size_t i = 0;
258 while (_num_chunks_handed_out < num_chunks) { 284 while (mgr.num_chunks_handed_out() < num_chunks) {
259 set1.add((nmethod*)i); 285 set1.add((nmethod*)i);
260 i++; 286 i++;
261 } 287 }
262 288
263 { 289 {
264 // Generate chunks on the free list. 290 // Generate chunks on the free list.
265 G1CodeRootSet set2; 291 G1CodeRootSet set2(&mgr);
266 size_t i = 0; 292 size_t i = 0;
267 while (_num_chunks_handed_out < num_chunks * 2) { 293 while (mgr.num_chunks_handed_out() < (num_chunks * 2)) {
268 set2.add((nmethod*)i); 294 set2.add((nmethod*)i);
269 i++; 295 i++;
270 } 296 }
271 // Exit of the scope of the set2 object will call the destructor that generates 297 // Exit of the scope of the set2 object will call the destructor that generates
272 // num_chunks elements on the free list. 298 // num_chunks elements on the free list.
273 } 299 }
274 300
275 assert(_num_chunks_handed_out == num_chunks, 301 assert(mgr.num_chunks_handed_out() == num_chunks,
276 err_msg("Deletion of the second set must have resulted in giving back " 302 err_msg("Deletion of the second set must have resulted in giving back "
277 "those, but there is still "SIZE_FORMAT" handed out, expecting " 303 "those, but there are still "SIZE_FORMAT" additional handed out, expecting "
278 SIZE_FORMAT, _num_chunks_handed_out, num_chunks)); 304 SIZE_FORMAT, mgr.num_chunks_handed_out(), num_chunks));
279 assert((size_t)_free_list.count() == num_chunks, 305 assert(mgr.num_free_chunks() == num_chunks,
280 err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list " 306 err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
281 "but there are only "SIZE_FORMAT, num_chunks, _free_list.count())); 307 "but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks()));
282 308
283 size_t const test_percentage = 50; 309 size_t const test_percentage = 50;
284 purge_chunks(test_percentage); 310 mgr.purge_chunks(test_percentage);
285 assert(_num_chunks_handed_out == num_chunks, 311 assert(mgr.num_chunks_handed_out() == num_chunks,
286 err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT, 312 err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT,
287 _num_chunks_handed_out)); 313 mgr.num_chunks_handed_out()));
288 assert((size_t)_free_list.count() == (ssize_t)(num_chunks * test_percentage / 100), 314 assert(mgr.num_free_chunks() == (size_t)(mgr.num_chunks_handed_out() * test_percentage / 100),
289 err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks" 315 err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks"
290 "but there are "SSIZE_FORMAT, test_percentage, num_chunks, 316 "but there are "SIZE_FORMAT, test_percentage, num_chunks,
291 _free_list.count())); 317 mgr.num_free_chunks()));
292 // Purge the remainder of the chunks on the free list. 318 // Purge the remainder of the chunks on the free list.
293 purge_chunks(0); 319 mgr.purge_chunks(0);
294 assert(_free_list.count() == 0, "Free List must be empty"); 320 assert(mgr.num_free_chunks() == 0, "Free List must be empty");
295 assert(_num_chunks_handed_out == num_chunks, 321 assert(mgr.num_chunks_handed_out() == num_chunks,
296 err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set " 322 err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set "
297 "but there are "SIZE_FORMAT, num_chunks, _num_chunks_handed_out)); 323 "but there are "SIZE_FORMAT, num_chunks, mgr.num_chunks_handed_out()));
298 324
299 // Exit of the scope of the set1 object will call the destructor that generates 325 // Exit of the scope of the set1 object will call the destructor that generates
300 // num_chunks additional elements on the free list. 326 // num_chunks additional elements on the free list.
301 } 327 }
302 328
303 assert(_num_chunks_handed_out == 0, 329 assert(mgr.num_chunks_handed_out() == 0,
304 err_msg("Deletion of the only set must have resulted in no chunks handed " 330 err_msg("Deletion of the only set must have resulted in no chunks handed "
305 "out, but there is still "SIZE_FORMAT" handed out", _num_chunks_handed_out)); 331 "out, but there is still "SIZE_FORMAT" handed out", mgr.num_chunks_handed_out()));
306 assert((size_t)_free_list.count() == num_chunks, 332 assert(mgr.num_free_chunks() == num_chunks,
307 err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list " 333 err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
308 "but there are only "SSIZE_FORMAT, num_chunks, _free_list.count())); 334 "but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks()));
309 335
310 // Restore initial state. 336 // Restore initial state.
311 purge_chunks(0); 337 mgr.purge_chunks(0);
312 assert(_free_list.count() == 0, "Free List must be empty"); 338 assert(mgr.num_free_chunks() == 0, "Free List must be empty");
313 assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet"); 339 assert(mgr.num_chunks_handed_out() == 0, "No additional elements must have been handed out yet");
314 } 340 }
315 341
316 void TestCodeCacheRemSet_test() { 342 void TestCodeCacheRemSet_test() {
317 G1CodeRootSet::test(); 343 G1CodeRootSet::test();
318 } 344 }