JDK-8308094 : Add a compilation timeout flag to catch long running compilations
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 21,24
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2023-05-15
  • Updated: 2024-11-12
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
tbdUnresolved
Related Reports
Relates :  
Relates :  
Relates :  
Description
We should add a compilation timeout flag to the VM to catch long running compilations. We could piggy-back on -XX:+CITime

--- a/src/hotspot/share/runtime/timerTrace.cpp
+++ b/src/hotspot/share/runtime/timerTrace.cpp
@@ -75,6 +75,9 @@ TraceTime::~TraceTime() {
   if (_accum != NULL) {
     _accum->add(_t);
   }
+  if (_t.seconds() > 3) {
+    assert(false, "Compilation timeout in phase %s", _title);
+  }
   if (!_verbose) {
     return;
   }

As part of this, or with a separate change, we might also want to improve CITime/CITimeVerbose/CITimeEach to narrow down the cause of the timout.

The disadvantage of above solution is that it would not catch endless looping compilations. For that, we would need a watcher thread (or maybe we can use an existing VM thread for that?).
Comments
We don't need a separate thread to detect infinite loops. We could set an alarm/timer, based on CPU time, that sends a signal to the thread when it expires, just like profiling with SIGPROF. The signal handler could set a flag on the CompilerThread that the compiler would need to poll. Or we could integrate it into the bailout mechanism so we only have to do one kind of poll.
12-11-2024

This would have also caught JDK-8343944 when the memlimit was disabled or when running with a product build.
12-11-2024

Another idea would be to have the CompileBroker check if all compiler threads are still making progress: - Every time a compiler thread queries the CompileBroker for a compile task, check the duration of the compile tasks that the other threads are busy with - If a certain threshold is reached, assume that this thread is stuck in an endless loop - We could then assert in debug or potentially bail out in product (but that would require that we have a safe way of shutting down a compiler thread from the outside - probably not feasible) This would have the advantage that we not only catch long running compilation but also compilations stuck in an endless loop (and especially those that don't hit the mem limit because they don't allocate any new memory). Something we often won't notice because it just keeps a single compiler thread busy while the other compiler threads are still making progress.
11-11-2024

Note that if the compilation time goes hand in hand with an increase in arena memory, as it often does, we already have the MemLimit command to achieve something similar. In the cited cases, it would have caught JDK-8324205, but probably not JDK-8308103. E.g. '-XX:CompileCommand=memlimit,*.*,100m' will abort any compilation that needs more than 100mb. We also can let a JVM crash at that point with '-XX:CompileCommand=memlimit,*.*,100m~crash', which proposed previously as a default for debug builds [1] Combining the (non-crashing variant) of memlimit with `-XX:CompileCommand=memstat,*.*,print` will print out a final report marking all aborted compilations with "oom" [1] https://mail.openjdk.org/pipermail/hotspot-compiler-dev/2024-April/074787.html
19-04-2024

Another good use case: JDK-8324205
19-01-2024

This would have caught JDK-8308103.
15-05-2023