Request review: 4360113: Evict nmethods when code cache gets full

Vladimir Kozlov Vladimir.Kozlov at Sun.COM
Wed Jan 6 15:42:54 PST 2010


I like these changes. The only question left:

Is it possible to avoid VM exit if (CompileTheWorld || ExitOnFullCodeCache)
before code cache cleanup attempt? If it requires a lot of changes leave as it is.

In compileBroker.cpp don't mix int with boolean (some compilers may complain):

+ volatile jint CompileBroker::_should_compile_new_jobs = 1;

+   static bool should_compile_new_jobs() { return UseCompiler && (_should_compile_new_jobs == 1); }


Eric Caspole wrote:
> Hi Vladimir,
> I updated my webrev to .02: I added a new field into CompileBroker to 
> use for toggling the compiler on/off when the code cache gets full or 
> when enough space is later cleared, to avoid changing UseCompiler on the 
> fly. Also I consolidated all the places that had some "turn off 
> compiler" code into one place in CompileBroker as we discussed before 
> the holidays.
> Regards,
> Eric
> On Dec 16, 2009, at 3:29 PM, Vladimir Kozlov wrote:
>> Eric Caspole wrote:
>>> I see what you mean. If there are other already disconnected methods 
>>> (nm->method()->code() != nm) due to normal operation, can I safely 
>>> assume they are already marked not entrant and they will go away by 
>>> normal sweeping? Or should I hurry them along here? I  see how not
>> The assert(nm->method()->code()->is_not_entrant() is enough, I think.
>>> having the extra check means I might reset the counters many times 
>>> for no reason, I'll change that.
>>>> It seems other thread set UseCompiler to false between the check and 
>>>> assert.
>>> So that means this could have happened in the existing system if the 
>>> broker shut off the compiler due to fullness, racing with the java 
>>> thread making this call. Yuck.
>> Yes. With your changes it could happened more frequently.
>> I think, it is related to what we talked about today on meeting:
>> # Consolidate "shut off compiler" logic into one place, and reconsider 
>> logic to turn compilers on and off.  Currently this logic is spread 
>> across three different places even without the unloading change.
>> May be we should use separate flag SuspendCompilation when we think
>> codecache could be freed and switch of UseCompiler when we give up.
>> Thanks,
>> Vladimir
>>>> Vladimir
>>>>>> % java -XX:ReservedCodeCacheSize=6M -XX:+PrintCodeCacheExtension 
>>>>>> -XX:+UseCodeCacheFlushing -XX:MinCodeCacheFlushingInterval=300 
>>>>>> -XX:+PrintCompilation -XX:+PrintMethodFlushing -jar 
>>>>>> SPECjvm2008.jar -ikv compiler.sunflow compiler.compiler
>>>>>> #  Internal Error 
>>>>>> (/net/irkutsk/export/home/kvn/work2/hg/4360113/src/share/vm/runtime/compilationPolicy.cpp:124), 
>>>>>> pid=26531, tid=51
>>>>>> #  Error: assert(UseCompiler || CompileTheWorld,"UseCompiler 
>>>>>> should be set by now.")
>>>>>> Current thread (0x08c84400):  JavaThread "BenchmarkThread 
>>>>>> compiler.sunflow 6" [_thread_in_vm, id=51, 
>>>>>> stack(0xfa2c9000,0xfa319000)]
>>>>>> Stack: [0xfa2c9000,0xfa319000],  sp=0xfa317ad8,  free 
>>>>>> space=13afa319000k
>>>>>> Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, 
>>>>>> C=native code)
>>>>>> V  [] void VMError::report(outputStream*) + 0x5be
>>>>>> V  [] void VMError::report_and_die() + 0x586
>>>>>> V  [] void report_assertion_failure(const 
>>>>>> char*,int,const char*) + 0x61
>>>>>> V  [] void 
>>>>>> SimpleCompPolicy::method_invocation_event(methodHandle,Thread*) + 
>>>>>> 0x20a
>>>>>> V  [] 
>>>>>> nmethod*InterpreterRuntime::frequency_counter_overflow_inner(JavaThread*,unsigned 
>>>>>> char*) + 0x1551
>>>>>> Eric Caspole wrote:
>>>>>>> 4360113: Evict nmethods when code cache gets full
>>>>>>> In this change, under a flag and off by default, when compilers 
>>>>>>> notice the code cache is getting full, they will call a vm op 
>>>>>>> that calls new code that attempts to speculatively unload the 
>>>>>>> oldest half of the nmethods (based on the compile job id) by 
>>>>>>> hiding the methodOop's ref to the nmethod in the new _saved_code 
>>>>>>> field. Then execution resumes. After inline cache cleaning, 
>>>>>>> callers will have to go back to the methodOop to get the verified 
>>>>>>> entry point.
>>>>>>> At that point, the methodOop's _code field is restored from the 
>>>>>>> _saved_code field and the methodOop/nmethod go back to their 
>>>>>>> normal state.
>>>>>>> If a method so marked is not called by the second sweep cycle 
>>>>>>> after the one where forced unloading happened, the nmethod will 
>>>>>>> be marked non-entrant and got rid of by normal sweeping. That 
>>>>>>> gives the app a few seconds to make progress and call its hottest 
>>>>>>> methods.
>>>>>>> We chose to target the oldest half of nmethods due to a customer 
>>>>>>> experience with a long-running app server, and despite multiple 
>>>>>>> redeployments of the same web app, something was preventing old 
>>>>>>> instances of the web app from ever getting unloaded. In that 
>>>>>>> case, they ran into the code cache full problem so the most 
>>>>>>> recent redeployment was running interpreter only. We have also 
>>>>>>> observed that for many applications a lot of methods get compiled 
>>>>>>> and used during the startup phase that are never used again.
>>>>>>> In this change there is also a timer based backoff, default of 30 
>>>>>>> seconds, so that if the normal state of the app is constantly 
>>>>>>> triggering unloading, the unloading will stop and it will fall 
>>>>>>> back to the existing situation of disabling the compiler.
>>>>>>> In my testing, this allows the program to quickly resume normal 
>>>>>>> operation with no noticeable performance degradation.
>>>>>>> Thanks for your comments,
>>>>>>> Eric

More information about the hotspot-compiler-dev mailing list