RFR(XXS): 8244278: Excessive code cache flushes and sweeps

Nils Eliasson nils.eliasson at oracle.com
Wed May 6 09:52:05 UTC 2020



On 2020-05-05 20:57, Man Cao wrote:
> Hi Laurent, Nils,
>
> > Using 40mb code cache looks quite small compared to default values 
> (256mb ?).
> The 40MB code cache size is for -XX:-TieredCompilation, for the DaCapo 
> runs.
> "java -XX:-TieredCompilation -XX:+PrintFlagsFinal |& grep 
> ReservedCodeCacheSize" shows the default size is 48MB for 
> -TieredCompilation.
> So 40MB is not particularly small compared to 48MB.
>
> The Blaze runs use "-XX:+TieredCompilation" and a Google-default code 
> cache size of 480MB (we have doubled the default size).
> This actually tests a case that is closer to the OpenJDK default.
>
> > Could you run 1 quick experiment with default code cache settings to 
> see if there is no regression in the main use case?
> Yes, I just launched an experiment running DaCapo at JDK source tip, 
> only with "-Xms4g -Xmx4g" and some logging flags.
> This is a meaningful experiment as it uses the real OpenJDK default 
> flags, and the most up-to-date source.
>
> > Why do you expect code cache usage would increase a lot? The sweeper
> > still wakes up regularly and cleans the code cache. The code path fixed
> > is just about sweeping extra aggressively under some circumstances. Some
> > nmethod might live a little longer, but they will still be cleaned.
> I found the aggressive sweeping deoptimized a non-trivial number of 
> nmethods, which kept the usage low.
> After my bugfix, the sweeper only wakes up when the usage reaches 
> (100-StartAggressiveSweepingAt)% of code cache capacity, which default 
> to 90%.
> This means many nmethods will not be cleaned until there is pressure 
> in code cache usage.
>
> > One number you could add to your benchmark numbers is the number of
> > nmethods reclaimed and code cache usage. I expect both to remain the 
> same.
> The benchmark result htmls already show the code cache usage (Code 
> Cache Used (MB)).
> You can CTRL-F for "Code Cache" in the browser.
>
> There is a significant increase in code cache usage:
> For DaCapo, up to 13.5MB (for tradesoap) increase for the 40MB 
> ReservedCodeCacheSize.
> For Blaze, the increase is 33MB-80MB for the 480MB ReservedCodeCacheSize.
> The code cache usage metric is measure like this (we added an 
> hsperfdata counter for it), at the end of a benchmark run:
>   size_t result = 0;
>   FOR_ALL_ALLOCABLE_HEAPS(heap) {
>     result += (*heap)->allocated_capacity();
>   }
>   _code_cache_used_size->set_value(result);
>
> I also looked at the logs, it shows that the bugfix eliminated almost 
> all of the code cache flushes. They also contain the number of 
> nmethods reclaimed.
> E.g., for tradesoap:
>
> Without the fix:
> Code cache sweeper statistics:
>    Total sweep time:                1902 ms
>    Total number of full sweeps:     23301
>    Total number of flushed methods: 7080 (thereof 7080 C2 methods)
>    Total size of flushed methods:   20468 kB
> With the fix:
> Code cache sweeper statistics:
>    Total sweep time:                0 ms
>    Total number of full sweeps:     0
>    Total number of flushed methods: 0 (thereof 0 C2 methods)
>    Total size of flushed methods:   0 kB
>

Interesting results and a clear indication that something is broken in 
the sweeper heuristics - Nmethods should still be flushed!

Looking at sweeper.cpp I see something that looks wrong. The _last_sweep 
counter is updated even if no sweep was done. In low code cache usage 
scenarios that means will might never reach the threshold.

I think the curly brace should be moved done like this:

--- a/src/hotspot/share/runtime/sweeper.cpp     Tue May 05 21:28:46 2020 
+0200
+++ b/src/hotspot/share/runtime/sweeper.cpp     Wed May 06 11:46:01 2020 
+0200
@@ -445,16 +445,17 @@
    if (_should_sweep || forced) {
      init_sweeper_log();
      sweep_code_cache();
+
+    // We are done with sweeping the code cache once.
+    _total_nof_code_cache_sweeps++;
+    _last_sweep = _time_counter;
+    // Reset flag; temporarily disables sweeper
+    _should_sweep = false;
+    // If there was enough state change, 'possibly_enable_sweeper()'
+    // sets '_should_sweep' to true
+    possibly_enable_sweeper();
    }

-  // We are done with sweeping the code cache once.
-  _total_nof_code_cache_sweeps++;
-  _last_sweep = _time_counter;
-  // Reset flag; temporarily disables sweeper
-  _should_sweep = false;
-  // If there was enough state change, 'possibly_enable_sweeper()'
-  // sets '_should_sweep' to true
-  possibly_enable_sweeper();
    // Reset _bytes_changed only if there was enough state change. 
_bytes_changed
    // can further increase by calls to 'report_state_change'.
    if (_should_sweep) {

Can you try it out and see if things improve?

Best regards,
Nils Eliasson


> Anyway, just to reiterate, we think the improvement in throughput and 
> CPU usage is well worth the increase in code cache usage.
> If the increase causes any problem, we would advise users to accept 
> the increase and fully provision memory for the 
> entire ReservedCodeCacheSize.
>
> -Man
>
>
> On Tue, May 5, 2020 at 3:18 AM Nils Eliasson <nils.eliasson at oracle.com 
> <mailto:nils.eliasson at oracle.com>> wrote:
>
>     Hi Man,
>
>     Why do you expect code cache usage would increase a lot? The sweeper
>     still wakes up regularly and cleans the code cache. The code path
>     fixed
>     is just about sweeping extra aggressively under some
>     circumstances. Some
>     nmethod might live a little longer, but they will still be cleaned.
>
>     Without your bugfix the sweeper will be notified for every new
>     allocation in the codecache as soon as code cache usages has gone
>     beyond
>     10%. That could in the worst case be one sweep for every allocation.
>
>     One number you could add to your benchmark numbers is the number of
>     nmethods reclaimed and code cache usage. I expect both to remain
>     the same.
>
>     Best regards,
>     Nils
>
>
>
>     On 2020-05-04 21:21, Man Cao wrote:
>     > Hi,
>     >
>     > Thanks for the review!
>     > Yes, the code change is trivial, but runtime behavior change is
>     > considerable.
>     > In particular, throughput and CPU usage could improve, but code
>     cache usage
>     > could increase a lot. In our experience, the improvement in
>     throughput and
>     > CPU is well worth the code cache increase.
>     >
>     > I have attached some benchmarking results in JBS. They are based
>     on JDK11.
>     > We have not rolled out this fix to our production JDK11 yet, as
>     I'd like to
>     > confirm that this large change in runtime behavior is OK with
>     the OpenJDK
>     > community.
>     > We are happy to share some performance numbers from production
>     workload
>     > once we have them.
>     >
>     > -Man
>     >
>     >
>     > On Mon, May 4, 2020 at 4:11 AM Laurent Bourgès
>     <bourges.laurent at gmail.com <mailto:bourges.laurent at gmail.com>>
>     > wrote:
>     >
>     >> Hi,
>     >>
>     >> Do you have performance results to justify your assumption "could
>     >> significantly improve performance" ?
>     >>
>     >> Please share numbers in the jbs bug
>     >>
>     >> Laurent
>     >>
>     >> Le sam. 2 mai 2020 à 07:35, Man Cao <manc at google.com
>     <mailto:manc at google.com>> a écrit :
>     >>
>     >>> Hi all,
>     >>>
>     >>> Can I have reviews for this one-line change that fixes a bug
>     and could
>     >>> significantly improve performance?
>     >>> Webrev: https://cr.openjdk.java.net/~manc/8244278/webrev.00/
>     >>> Bug: https://bugs.openjdk.java.net/browse/JDK-8244278
>     >>>
>     >>> It passes tier-1 tests locally, as well as
>     >>> "vm/mlvm/meth/stress/compiler/deoptimize" (for the original
>     JDK-8046809).
>     >>>
>     >>> -Man
>     >>>
>



More information about the hotspot-compiler-dev mailing list