Mercurial > hg > truffle
comparison src/share/vm/runtime/sweeper.cpp @ 1644:2a47bd84841f
6965184: possible races in make_not_entrant_or_zombie
Reviewed-by: kvn
author | never |
---|---|
date | Thu, 08 Jul 2010 14:29:44 -0700 |
parents | ff38d05ea86f |
children | 8d5934a77f10 |
comparison
equal
deleted
inserted
replaced
1635:a693e51ac197 | 1644:2a47bd84841f |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. | 2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | 4 * |
5 * This code is free software; you can redistribute it and/or modify it | 5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as | 6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
25 # include "incls/_precompiled.incl" | 25 # include "incls/_precompiled.incl" |
26 # include "incls/_sweeper.cpp.incl" | 26 # include "incls/_sweeper.cpp.incl" |
27 | 27 |
28 long NMethodSweeper::_traversals = 0; // No. of stack traversals performed | 28 long NMethodSweeper::_traversals = 0; // No. of stack traversals performed |
29 nmethod* NMethodSweeper::_current = NULL; // Current nmethod | 29 nmethod* NMethodSweeper::_current = NULL; // Current nmethod |
30 int NMethodSweeper::_seen = 0 ; // No. of blobs we have currently processed in current pass of CodeCache | 30 int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache |
31 int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass | 31 |
32 volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass | |
33 volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progress. | |
32 | 34 |
33 jint NMethodSweeper::_locked_seen = 0; | 35 jint NMethodSweeper::_locked_seen = 0; |
34 jint NMethodSweeper::_not_entrant_seen_on_stack = 0; | 36 jint NMethodSweeper::_not_entrant_seen_on_stack = 0; |
35 bool NMethodSweeper::_rescan = false; | 37 bool NMethodSweeper::_rescan = false; |
36 bool NMethodSweeper::_do_sweep = false; | 38 bool NMethodSweeper::_do_sweep = false; |
37 jint NMethodSweeper::_sweep_started = 0; | |
38 bool NMethodSweeper::_was_full = false; | 39 bool NMethodSweeper::_was_full = false; |
39 jint NMethodSweeper::_advise_to_sweep = 0; | 40 jint NMethodSweeper::_advise_to_sweep = 0; |
40 jlong NMethodSweeper::_last_was_full = 0; | 41 jlong NMethodSweeper::_last_was_full = 0; |
41 uint NMethodSweeper::_highest_marked = 0; | 42 uint NMethodSweeper::_highest_marked = 0; |
42 long NMethodSweeper::_was_full_traversal = 0; | 43 long NMethodSweeper::_was_full_traversal = 0; |
106 | 107 |
107 // Update the _last_was_full time so we can tell how fast the | 108 // Update the _last_was_full time so we can tell how fast the |
108 // code cache is filling up | 109 // code cache is filling up |
109 _last_was_full = os::javaTimeMillis(); | 110 _last_was_full = os::javaTimeMillis(); |
110 | 111 |
111 if (PrintMethodFlushing) { | 112 log_sweep("restart_compiler"); |
112 tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler", | |
113 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
114 } | |
115 if (LogCompilation && (xtty != NULL)) { | |
116 ttyLocker ttyl; | |
117 xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
118 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
119 xtty->stamp(); | |
120 xtty->end_elem(); | |
121 } | |
122 } | 113 } |
123 } | 114 } |
124 } | 115 } |
125 } | 116 } |
126 | 117 |
127 void NMethodSweeper::possibly_sweep() { | 118 void NMethodSweeper::possibly_sweep() { |
119 assert(JavaThread::current()->thread_state() == _thread_in_vm, "must run in vm mode"); | |
128 if ((!MethodFlushing) || (!_do_sweep)) return; | 120 if ((!MethodFlushing) || (!_do_sweep)) return; |
129 | 121 |
130 if (_invocations > 0) { | 122 if (_invocations > 0) { |
131 // Only one thread at a time will sweep | 123 // Only one thread at a time will sweep |
132 jint old = Atomic::cmpxchg( 1, &_sweep_started, 0 ); | 124 jint old = Atomic::cmpxchg( 1, &_sweep_started, 0 ); |
133 if (old != 0) { | 125 if (old != 0) { |
134 return; | 126 return; |
135 } | 127 } |
136 sweep_code_cache(); | 128 if (_invocations > 0) { |
137 } | 129 sweep_code_cache(); |
138 _sweep_started = 0; | 130 _invocations--; |
131 } | |
132 _sweep_started = 0; | |
133 } | |
139 } | 134 } |
140 | 135 |
141 void NMethodSweeper::sweep_code_cache() { | 136 void NMethodSweeper::sweep_code_cache() { |
142 #ifdef ASSERT | 137 #ifdef ASSERT |
143 jlong sweep_start; | 138 jlong sweep_start; |
144 if(PrintMethodFlushing) { | 139 if (PrintMethodFlushing) { |
145 sweep_start = os::javaTimeMillis(); | 140 sweep_start = os::javaTimeMillis(); |
146 } | 141 } |
147 #endif | 142 #endif |
148 if (PrintMethodFlushing && Verbose) { | 143 if (PrintMethodFlushing && Verbose) { |
149 tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_blobs(), _invocations); | 144 tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations); |
150 } | 145 } |
151 | 146 |
152 // We want to visit all nmethods after NmethodSweepFraction invocations. | 147 // We want to visit all nmethods after NmethodSweepFraction |
153 // If invocation is 1 we do the rest | 148 // invocations so divide the remaining number of nmethods by the |
154 int todo = CodeCache::nof_blobs(); | 149 // remaining number of invocations. This is only an estimate since |
155 if (_invocations > 1) { | 150 // the number of nmethods changes during the sweep so the final |
156 todo = (CodeCache::nof_blobs() - _seen) / _invocations; | 151 // stage must iterate until it there are no more nmethods. |
157 } | 152 int todo = (CodeCache::nof_nmethods() - _seen) / _invocations; |
158 | |
159 // Compilers may check to sweep more often than stack scans happen, | |
160 // don't keep trying once it is all scanned | |
161 _invocations--; | |
162 | 153 |
163 assert(!SafepointSynchronize::is_at_safepoint(), "should not be in safepoint when we get here"); | 154 assert(!SafepointSynchronize::is_at_safepoint(), "should not be in safepoint when we get here"); |
164 assert(!CodeCache_lock->owned_by_self(), "just checking"); | 155 assert(!CodeCache_lock->owned_by_self(), "just checking"); |
165 | 156 |
166 { | 157 { |
167 MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); | 158 MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); |
168 | 159 |
169 for(int i = 0; i < todo && _current != NULL; i++) { | 160 // The last invocation iterates until there are no more nmethods |
170 | 161 for (int i = 0; (i < todo || _invocations == 1) && _current != NULL; i++) { |
171 // Since we will give up the CodeCache_lock, always skip ahead to an nmethod. | 162 |
172 // Other blobs can be deleted by other threads | 163 // Since we will give up the CodeCache_lock, always skip ahead |
173 // Read next before we potentially delete current | 164 // to the next nmethod. Other blobs can be deleted by other |
165 // threads but nmethods are only reclaimed by the sweeper. | |
174 nmethod* next = CodeCache::next_nmethod(_current); | 166 nmethod* next = CodeCache::next_nmethod(_current); |
175 | 167 |
176 // Now ready to process nmethod and give up CodeCache_lock | 168 // Now ready to process nmethod and give up CodeCache_lock |
177 { | 169 { |
178 MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); | 170 MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); |
180 } | 172 } |
181 _seen++; | 173 _seen++; |
182 _current = next; | 174 _current = next; |
183 } | 175 } |
184 } | 176 } |
177 | |
178 assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache"); | |
185 | 179 |
186 if (_current == NULL && !_rescan && (_locked_seen || _not_entrant_seen_on_stack)) { | 180 if (_current == NULL && !_rescan && (_locked_seen || _not_entrant_seen_on_stack)) { |
187 // we've completed a scan without making progress but there were | 181 // we've completed a scan without making progress but there were |
188 // nmethods we were unable to process either because they were | 182 // nmethods we were unable to process either because they were |
189 // locked or were still on stack. We don't have to aggresively | 183 // locked or were still on stack. We don't have to aggresively |
199 if(PrintMethodFlushing) { | 193 if(PrintMethodFlushing) { |
200 jlong sweep_end = os::javaTimeMillis(); | 194 jlong sweep_end = os::javaTimeMillis(); |
201 tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, sweep_end - sweep_start); | 195 tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, sweep_end - sweep_start); |
202 } | 196 } |
203 #endif | 197 #endif |
198 | |
199 if (_invocations == 1) { | |
200 log_sweep("finished"); | |
201 } | |
204 } | 202 } |
205 | 203 |
206 | 204 |
207 void NMethodSweeper::process_nmethod(nmethod *nm) { | 205 void NMethodSweeper::process_nmethod(nmethod *nm) { |
208 assert(!CodeCache_lock->owned_by_self(), "just checking"); | 206 assert(!CodeCache_lock->owned_by_self(), "just checking"); |
221 } | 219 } |
222 | 220 |
223 if (nm->is_zombie()) { | 221 if (nm->is_zombie()) { |
224 // If it is first time, we see nmethod then we mark it. Otherwise, | 222 // If it is first time, we see nmethod then we mark it. Otherwise, |
225 // we reclame it. When we have seen a zombie method twice, we know that | 223 // we reclame it. When we have seen a zombie method twice, we know that |
226 // there are no inline caches that referes to it. | 224 // there are no inline caches that refer to it. |
227 if (nm->is_marked_for_reclamation()) { | 225 if (nm->is_marked_for_reclamation()) { |
228 assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); | 226 assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); |
229 if (PrintMethodFlushing && Verbose) { | 227 if (PrintMethodFlushing && Verbose) { |
230 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); | 228 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); |
231 } | 229 } |
318 jlong now = os::javaTimeMillis(); | 316 jlong now = os::javaTimeMillis(); |
319 jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000; | 317 jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000; |
320 jlong curr_interval = now - _last_was_full; | 318 jlong curr_interval = now - _last_was_full; |
321 if (curr_interval < max_interval) { | 319 if (curr_interval < max_interval) { |
322 _rescan = true; | 320 _rescan = true; |
323 if (PrintMethodFlushing) { | 321 log_sweep("disable_compiler", "flushing_interval='" UINT64_FORMAT "'", |
324 tty->print_cr("### handle full too often, turning off compiler"); | 322 curr_interval/1000); |
325 } | |
326 if (LogCompilation && (xtty != NULL)) { | |
327 ttyLocker ttyl; | |
328 xtty->begin_elem("disable_compiler flushing_interval='" UINT64_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
329 curr_interval/1000, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
330 xtty->stamp(); | |
331 xtty->end_elem(); | |
332 } | |
333 return; | 323 return; |
334 } | 324 } |
335 } | 325 } |
336 | 326 |
337 VM_HandleFullCodeCache op(is_full); | 327 VM_HandleFullCodeCache op(is_full); |
347 | 337 |
348 debug_only(jlong start = os::javaTimeMillis();) | 338 debug_only(jlong start = os::javaTimeMillis();) |
349 | 339 |
350 if ((!was_full()) && (is_full)) { | 340 if ((!was_full()) && (is_full)) { |
351 if (!CodeCache::needs_flushing()) { | 341 if (!CodeCache::needs_flushing()) { |
352 if (PrintMethodFlushing) { | 342 log_sweep("restart_compiler"); |
353 tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler", | |
354 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
355 } | |
356 if (LogCompilation && (xtty != NULL)) { | |
357 ttyLocker ttyl; | |
358 xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
359 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
360 xtty->stamp(); | |
361 xtty->end_elem(); | |
362 } | |
363 CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); | 343 CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); |
364 return; | 344 return; |
365 } | 345 } |
366 } | 346 } |
367 | 347 |
368 // Traverse the code cache trying to dump the oldest nmethods | 348 // Traverse the code cache trying to dump the oldest nmethods |
369 uint curr_max_comp_id = CompileBroker::get_compilation_id(); | 349 uint curr_max_comp_id = CompileBroker::get_compilation_id(); |
370 uint flush_target = ((curr_max_comp_id - _highest_marked) >> 1) + _highest_marked; | 350 uint flush_target = ((curr_max_comp_id - _highest_marked) >> 1) + _highest_marked; |
371 if (PrintMethodFlushing && Verbose) { | 351 log_sweep("start_cleaning"); |
372 tty->print_cr("### Cleaning code cache: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes", | |
373 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
374 } | |
375 if (LogCompilation && (xtty != NULL)) { | |
376 ttyLocker ttyl; | |
377 xtty->begin_elem("start_cleaning_code_cache live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
378 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
379 xtty->stamp(); | |
380 xtty->end_elem(); | |
381 } | |
382 | 352 |
383 nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); | 353 nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); |
384 jint disconnected = 0; | 354 jint disconnected = 0; |
385 jint made_not_entrant = 0; | 355 jint made_not_entrant = 0; |
386 while ((nm != NULL)){ | 356 while ((nm != NULL)){ |
409 } | 379 } |
410 } | 380 } |
411 nm = CodeCache::alive_nmethod(CodeCache::next(nm)); | 381 nm = CodeCache::alive_nmethod(CodeCache::next(nm)); |
412 } | 382 } |
413 | 383 |
414 if (LogCompilation && (xtty != NULL)) { | 384 log_sweep("stop_cleaning", |
415 ttyLocker ttyl; | 385 "disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "'", |
416 xtty->begin_elem("stop_cleaning_code_cache disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | 386 disconnected, made_not_entrant); |
417 disconnected, made_not_entrant, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
418 xtty->stamp(); | |
419 xtty->end_elem(); | |
420 } | |
421 | 387 |
422 // Shut off compiler. Sweeper will start over with a new stack scan and | 388 // Shut off compiler. Sweeper will start over with a new stack scan and |
423 // traversal cycle and turn it back on if it clears enough space. | 389 // traversal cycle and turn it back on if it clears enough space. |
424 if (was_full()) { | 390 if (was_full()) { |
425 _last_was_full = os::javaTimeMillis(); | 391 _last_was_full = os::javaTimeMillis(); |
433 if(PrintMethodFlushing && Verbose) { | 399 if(PrintMethodFlushing && Verbose) { |
434 tty->print_cr("### sweeper: unload time: " INT64_FORMAT, end-start); | 400 tty->print_cr("### sweeper: unload time: " INT64_FORMAT, end-start); |
435 } | 401 } |
436 #endif | 402 #endif |
437 } | 403 } |
404 | |
405 | |
406 // Print out some state information about the current sweep and the | |
407 // state of the code cache if it's requested. | |
408 void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) { | |
409 if (PrintMethodFlushing) { | |
410 ttyLocker ttyl; | |
411 tty->print("### sweeper: %s ", msg); | |
412 if (format != NULL) { | |
413 va_list ap; | |
414 va_start(ap, format); | |
415 tty->vprint(format, ap); | |
416 va_end(ap); | |
417 } | |
418 tty->print_cr(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'" | |
419 " adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
420 CodeCache::nof_blobs(), CodeCache::nof_nmethods(), CodeCache::nof_adapters(), CodeCache::unallocated_capacity()); | |
421 } | |
422 | |
423 if (LogCompilation && (xtty != NULL)) { | |
424 ttyLocker ttyl; | |
425 xtty->begin_elem("sweeper state='%s' traversals=`" INTX_FORMAT "' ", msg, (intx)traversal_count()); | |
426 if (format != NULL) { | |
427 va_list ap; | |
428 va_start(ap, format); | |
429 xtty->vprint(format, ap); | |
430 va_end(ap); | |
431 } | |
432 xtty->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'" | |
433 " adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
434 CodeCache::nof_blobs(), CodeCache::nof_nmethods(), CodeCache::nof_adapters(), CodeCache::unallocated_capacity()); | |
435 xtty->stamp(); | |
436 xtty->end_elem(); | |
437 } | |
438 } |