JDK-8321939 : [GenShen] ShenandoahOldEvacRatioPercent=100 fails with divide-by-zero
  • Type: Bug
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: repo-shenandoah
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2023-12-13
  • Updated: 2023-12-28
  • Resolved: 2023-12-28
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
repo-shenandoahFixed
Related Reports
Blocks :  
Relates :  
Description
I stumbled upon the following issue when working on JDK-8314599.

SPECjbb run with -XX:ShenandoahOldEvacRatioPercent=100 fails with the following error:

```
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGFPE (0x8) at pc=0x00007f8c7cadc130, pid=46666, tid=46720
#
# JRE version: OpenJDK Runtime Environment (22.0) (build 22-internal-adhoc.ysr.shenandoah)
# Java VM: OpenJDK 64-Bit Server VM (22-internal-adhoc.ysr.shenandoah, mixed mode, tiered, compressed oops, compressed class ptrs, shenandoah gc, linux-amd64)
# Problematic frame:
# V  [libjvm.so+0xe0e130]  ShenandoahGeneration::compute_evacuation_budgets(ShenandoahHeap*, bool*, ShenandoahCollectionSet*, unsigned long&)+0x130
#
# No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# If you would like to submit a bug report, please visit:
#   https://bugreport.java.com/bugreport/crash.jsp
#

---------------  S U M M A R Y ------------

Command Line: -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-ShenandoahPacing -Xmx30g -Xms30g -XX:+AlwaysPreTouch -Xlog:async -Xlog:gc*=info,gc+age=trace,gc+phases=debug -XX:+DisableExplicitGC -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -XX:ShenandoahOldEvacRatioPercent=100 ../specjbb2015.jar -m COMPOSITE

Host: Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz, 40 cores, 157G, Amazon Linux release 2 (Karoo)
Time: Tue Dec 12 07:32:43 2023 UTC elapsed time: 6.132387 seconds (0d 0h 0m 6s)

---------------  T H R E A D  ---------------

Current thread (0x00007f8c7421fbb0):  VMThread "VM Thread"          [id=46720, stack(0x00007f8b8797a000,0x00007f8b87a7a000) (1024K)]

Stack: [0x00007f8b8797a000,0x00007f8b87a7a000],  sp=0x00007f8b87a77470,  free space=1013k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0xe0e130]  ShenandoahGeneration::compute_evacuation_budgets(ShenandoahHeap*, bool*, ShenandoahCollectionSet*, unsigned long&)+0x130  (shenandoahGeneration.cpp:284)
V  [libjvm.so+0xe0f05c]  ShenandoahGeneration::prepare_regions_and_collection_set(bool)+0x18c  (shenandoahGeneration.cpp:726)
V  [libjvm.so+0xde979f]  ShenandoahConcurrentGC::op_final_mark()+0x8f  (shenandoahConcurrentGC.cpp:744)
V  [libjvm.so+0xdec9bf]  ShenandoahConcurrentGC::entry_final_mark()+0x9f  (shenandoahConcurrentGC.cpp:350)
V  [libjvm.so+0xe93efd]  VM_ShenandoahFinalMarkStartEvac::doit()+0x2d  (shenandoahVMOperations.cpp:59)
V  [libjvm.so+0x103fa21]  VM_Operation::evaluate()+0x101  (vmOperations.cpp:73)
V  [libjvm.so+0x1042cf2]  VMThread::evaluate_operation(VM_Operation*)+0xb2  (vmThread.cpp:281)
V  [libjvm.so+0x10439f7]  VMThread::inner_execute(VM_Operation*)+0x357  (vmThread.cpp:435)
V  [libjvm.so+0x1043cf7]  VMThread::run()+0xb7  (vmThread.cpp:502)
V  [libjvm.so+0xfb1a38]  Thread::call_run()+0xa8  (thread.cpp:220)
V  [libjvm.so+0xcef4ea]  thread_native_entry(Thread*)+0xda  (os_linux.cpp:787)


```

The issue is that although the option's legal range is [0,100], the following code in shenandoahGeneration.cpp::ShenandoahGeneration::compute_evacuation_budgets is problematic when the option value is 100:

-  // maximum_old_evacuation_reserve is an upper bound on memory evacuated from old and evacuated to old (promoted).
-  size_t maximum_old_evacuation_reserve =
-    maximum_young_evacuation_reserve * ShenandoahOldEvacRatioPercent / (100 - ShenandoahOldEvacRatioPercent);
-  // Here's the algebra:
-  //  TotalEvacuation = OldEvacuation + YoungEvacuation
-  //  OldEvacuation = TotalEvacuation * (ShenandoahOldEvacRatioPercent/100)
-  //  OldEvacuation = YoungEvacuation * (ShenandoahOldEvacRatioPercent/100)/(1 - ShenandoahOldEvacRatioPercent/100)
-  //  OldEvacuation = YoungEvacuation * ShenandoahOldEvacRatioPercent/(100 - ShenandoahOldEvacRatioPercent)
-

A similar flaw exists also in shenandoahHeap.cpp::ShenandoahHeap::adjust_generation_sizes_for_next_cycle:


-  // We can limit the reserve to the size of anticipated promotions
-  size_t max_old_reserve = young_reserve * ShenandoahOldEvacRatioPercent / (100 - ShenandoahOldEvacRatioPercent);
-  // Here's the algebra:
-  //  TotalEvacuation = OldEvacuation + YoungEvacuation
-  //  OldEvacuation = TotalEvacuation*(ShenandoahOldEvacRatioPercent/100)
-  //  OldEvacuation = YoungEvacuation * (ShenandoahOldEvacRatioPercent/100)/(1 - ShenandoahOldEvacRatioPercent/100)
-  //  OldEvacuation = YoungEvacuation * ShenandoahOldEvacRatioPercent/(100 - ShenandoahOldEvacRatioPercent)
-



Comments
Pushed as commit https://github.com/openjdk/shenandoah/commit/2c77c16ef32d95f59a631e4a51836f4d6ccf4d39.
28-12-2023

PR: https://github.com/openjdk/shenandoah/pull/369
13-12-2023