Mercurial > hg > truffle
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 } |