RFR(S): 8020151: PSR:PERF Large performance regressions when code cache is filled

Albert Noll albert.noll at oracle.com
Tue Aug 27 06:03:32 PDT 2013

Hi Chris,

thanks a lot for your feedback. I will do the performance evaluation 
that you proposed
to validate that the code changes also perform well for small code cache 

On 22.08.2013 23:29, Chris Plummer wrote:
> Hi Albert,
> sort_nmentod_by_hotness should be sort_nmethod_by_hotness.
Thanks, I will fix the type error.
> We already store NMethodSweeper::_traversal_count in 
> nmethod::_stack_traversal_mark each time scan_stacks() is called. Why 
> not just use that to determine how long it's been since an nmethod was 
> active? No need to decrement it. Just look at 
> nmethod::_stack_traversal_mark when sorting.
_stack_traversal_mark is only set for not-entrant methods. However, the 
hotness counter should
also be available for all methods, including methods that have the state 
'in_use'. As a result, we
need _hotness_counter.
> Also, keep in mind that how long it's been since a method was last 
> used does not always equate to how hot it is. You might have a method 
> that is called once every second, and another that is called 1000 
> times every 10 seconds. The later is actually hotter, but your 
> algorithm would favor sweeping the former. Not a deal breaker, but 
> something to consider when trying to improve your criteria for 
> selecting how hot a method is.
I cannot follow your example. Since we use stack scanning to determine 
the hotness of a method,
it is irrelevant how often a method is called. The probability that a 
method 'M' is hot depends only
on the time that is spent executing 'M'; the more time we spend in 'M', 
the more likely it is that we
hit 'M' during stack scanning. For example, assume that a program spends 
10ms/second in 'M'.
If 'M' is called 1 time/second and the execution time of 'M'=10ms, or M 
is called 10 times/second
and the execution time of 'M'=1ms is likely to yield the same hotness.

Using stack scanning to determine the hotness of a method is only an 
approximation based on
sampling. I.e., if we are unlucky and never see a hot method on the 
stack, the hot method will
eventually be flushed.

> Please verify your results with specjvm98 using an artificially small 
> codecache size. First do a run to get code cache usage using 
> -XX:+PrintCodeCache. For example:
> CodeCache: size=32768Kb used=3758Kb max_used=3758Kb free=29009Kb
> Take the "used" size, divide by 2, and then add 1500k 
> (CodeCacheFlushingMinimumFreeSpace). Use that for your new 
> ReservedCodeCacheSize. From my recent experience, you should see less 
> than a 10% performance degradation than when not constraining the 
> codecache size in this manner. However, what's most important is that 
> performance using this configuration is the same or better than 
> without your changes. Take another 500-1000k off the code cache size 
> and measure again. You'll see much bigger performance degradation, but 
> once again what is important is that with your change in place, 
> performance has not gotten any worse. Do the same running Nashorn with 
> the v8 benchmarks.
> thanks,
> Chris
> On 8/21/13 7:41 AM, hotspot-compiler-dev-request at openjdk.java.net wrote:
>> Hi all,
>> could I have reviews for this patch? Please note
>> that I do not yet feel very confident with the sweeper,
>> so please take a close look.
>> jbs:https://jbs.oracle.com/bugs/browse/JDK-8020151
>> webrev:http://cr.openjdk.java.net/~anoll/8020151/webrev.00/ 
>> <http://cr.openjdk.java.net/%7Eanoll/8020151/webrev.00/>
>> Many thanks in advance,
>> Albert
>> Problem: There can be large performance regressions when the code cache
>> fills up. There are
>> several reasons for the performance regression: First (1), when the code
>> cache is full and methods
>> are speculatively disconnected, the oldest methods (based on compilation
>> ID) are scheduled for
>> flushing. This can result in flushing hot methods. Second (2), when
>> compilation is disabled due to a full
>> code cache, the number of sweeps can go down. A lower number of sweep
>> operations results
>> in slower method flushing.
>> Solution:
>> Introduce a hotness counter that is set to a particular value (e.g.,
>> 100) when there is an activation
>> of the method during stack scanning. The counter is decremented by 1
>> every time the sweeper
>> is invoked.
>> ad (1):
>>     A VM operation that speculatively disconnects nmethods, selects the
>> methods that should be
>>     flushed based on the hotness. For example, if 50% of the code cache
>> shall be flushed, we flush
>>     those methods that have not been active while stack scanning for the
>> longest time. Note that
>>     while this strategy is more likely to flush cold methods, it is not
>> clear to what extent the new
>>     strategy fragments the code cache.
>>     Changes in NMethodSweeper::speculative_disconnect_nmethods(bool 
>> is_full)
>> ad (2)
>>     Currently, methods are removed from the code cache if:
>>       a) code cache is full
>>       b) class is unloaded
>>       c) method is replaced by another version (i.e., compiled with a
>> different tier)
>>       d) deopt
>>      The current patch adds a 5-th possibility to remove a method from
>> the code cache.
>>      In particular, if a method has not been active during stack 
>> scanning
>> for a long-enough
>>      amount of time, the method is removed from the code cache. The
>> amount of time
>>      required to flush the method depends on the available space in the
>> code cache.
>>      Here is one example: If a method was seen on a stack the hotness
>> counter
>>      is set to 100. A sweep operation takes roughly place every 100ms.
>> I.e., it takes
>>      100ms * 100 = 10s until the hotness counter reaches 0. The 
>> threshold
>> that determines
>>      if a method should be removed from the code cache is calculated as
>> follows:
>>      threshold = -100 + (CodeCache::reverse_free_ratio() *
>> NMethodSweepActivity)
>>       For example, if 25% of the code cache is free, reverse_free_ratio
>> returns 4.
>>       The default value of NMethodSweepActivity is 10. As a result,
>> threshold = -60.
>>       Consequently, all methods that have a hotness value smaller than
>> -60 (which
>>       means they have not been seen on the stack for 16s) are scheduled
>> to be flushed
>>       from the code cache. See an illustration of the threshold as a
>> function of the available
>>       code cache in threshold.pdf
>>       Note that NMethodSweepActivity is a parameter that can be 
>> specified
>> via a -XX
>>       flag.
>> Changes in NMethodSweeper::sweep_code_cache()
>> A very preliminary performance evaluation looks promising. I used the
>> DaCapo
>> benchmarks where a series of benchmarks is executed in the same VM 
>> instance.
>> See performance.pdf . The x-axis shows the benchmarks. Assume we have 2
>> benchmarks
>> (BM). The execution sequence is as follows:
>> BM1 (Run 1-1)
>> BM1 (Run 2-1)
>> BM2 (Run 1-1)
>> BM2 (Run 2-1)
>> BM1 (Run 1-2)
>> BM1 (Run 2-2)
>> BM2 (Run 1-2)
>> BM2 (Run 2-2)
>> A value larger than 0 on the x-axis indicates that the version including
>> the proposed patch is faster.
>> I.e., the values are calculated as follows: (T_original / T_with_patch)
>> - 1. T is the execution time
>> (wall clock time) of the benchmark. ReservedCodeCacheSize is set to
>> 50m.  I used three runs and
>> the arithmetic average to compare the numbers. I know, we need much more
>> data, however,
>> I think we can see a trend.
>> The current patch does not trigger a warning that the code cache is full
>> and compilation has been
>> disabled.
>> Please let me know that you think.
>> -------------- next part --------------
>> An HTML attachment was scrubbed...
>> URL:http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20130821/6478f023/attachment.html 
>> -------------- next part --------------
>> A non-text attachment was scrubbed...
>> Name: threshold.pdf
>> Type: application/pdf
>> Size: 13321 bytes
>> Desc: not available
>> Url 
>> :http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20130821/6478f023/threshold.pdf 
>> -------------- next part --------------
>> A non-text attachment was scrubbed...
>> Name: performance.pdf
>> Type: application/pdf
>> Size: 14641 bytes
>> Desc: not available
>> Url 
>> :http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20130821/6478f023/performance.pdf 

More information about the hotspot-compiler-dev mailing list