src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp

changeset 6925
82693fb204a5
parent 6680
78bbf4d43a14
child 6932
828056cf311f
equal deleted inserted replaced
6924:3a62cd59c8d8 6925: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 }

mercurial