Skip to content

Commit c74c60f

Browse files
mhaessigdean-long
andcommitted
8308094: Add a compilation timeout flag to catch long running compilations
Co-authored-by: Dean Long <[email protected]> Reviewed-by: dlong, chagedorn
1 parent 78d50c0 commit c74c60f

File tree

8 files changed

+282
-3
lines changed

8 files changed

+282
-3
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
#include "compiler/compilerThread.hpp"
26+
#include "compiler/compileTask.hpp"
27+
#include "compilerThreadTimeout_linux.hpp"
28+
#include "oops/method.hpp"
29+
#include "runtime/osThread.hpp"
30+
#include "signals_posix.hpp"
31+
#include "utilities/globalDefinitions.hpp"
32+
33+
#include <pthread.h>
34+
35+
#ifdef ASSERT
36+
void compiler_signal_handler(int signo, siginfo_t* info, void* context) {
37+
CompilerThread::current()->timeout()->compiler_signal_handler(signo, info, context);
38+
}
39+
40+
void CompilerThreadTimeoutLinux::compiler_signal_handler(int signo, siginfo_t* info, void* context) {
41+
switch (signo) {
42+
case TIMEOUT_SIGNAL: {
43+
CompileTask* task = CompilerThread::current()->task();
44+
const int SIZE = 512;
45+
char method_name_buf[SIZE];
46+
task->method()->name_and_sig_as_C_string(method_name_buf, SIZE);
47+
assert(false, "compile task %d (%s) timed out after %zd ms",
48+
task->compile_id(), method_name_buf, CompileTaskTimeout);
49+
}
50+
default: {
51+
assert(false, "unexpected signal %d", signo);
52+
}
53+
}
54+
}
55+
#endif // ASSERT
56+
57+
void CompilerThreadTimeoutLinux::arm() {
58+
#ifdef ASSERT
59+
if (CompileTaskTimeout == 0) {
60+
return;
61+
}
62+
63+
const intx sec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) / NANOSECS_PER_SEC;
64+
const intx nsec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) % NANOSECS_PER_SEC;
65+
const struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec};
66+
const struct itimerspec its {.it_interval = ts, .it_value = ts};
67+
68+
// Start the timer.
69+
timer_settime(_timer, 0, &its, nullptr);
70+
#endif // ASSERT
71+
}
72+
73+
void CompilerThreadTimeoutLinux::disarm() {
74+
#ifdef ASSERT
75+
if (CompileTaskTimeout == 0) {
76+
return;
77+
}
78+
79+
// Reset the timer by setting it to zero.
80+
const struct itimerspec its {
81+
.it_interval = {.tv_sec = 0, .tv_nsec=0},
82+
.it_value = {.tv_sec = 0, .tv_nsec=0}
83+
};
84+
timer_settime(_timer, 0, &its, nullptr);
85+
#endif // ASSERT
86+
}
87+
88+
bool CompilerThreadTimeoutLinux::init_timeout() {
89+
#ifdef ASSERT
90+
if (CompileTaskTimeout == 0) {
91+
return true;
92+
}
93+
94+
JavaThread* thread = JavaThread::current();
95+
96+
// Create a POSIX timer sending SIGALRM to this thread only.
97+
sigevent_t sev;
98+
sev.sigev_value.sival_ptr = nullptr;
99+
sev.sigev_signo = TIMEOUT_SIGNAL;
100+
sev.sigev_notify = SIGEV_THREAD_ID;
101+
#ifdef MUSL_LIBC
102+
sev.sigev_notify_thread_id = thread->osthread()->thread_id();
103+
#else
104+
sev._sigev_un._tid = thread->osthread()->thread_id();
105+
#endif // MUSL_LIBC
106+
clockid_t clock;
107+
int err = pthread_getcpuclockid(thread->osthread()->pthread_id(), &clock);
108+
if (err != 0) {
109+
return false;
110+
}
111+
err = timer_create(clock, &sev, &_timer);
112+
if (err != 0) {
113+
return false;
114+
}
115+
116+
// Install the signal handler and check that we do not have a conflicting handler.
117+
struct sigaction sigact, sigact_old;
118+
err = PosixSignals::install_sigaction_signal_handler(&sigact,
119+
&sigact_old,
120+
TIMEOUT_SIGNAL,
121+
(sa_sigaction_t)::compiler_signal_handler);
122+
if (err != 0 || (sigact_old.sa_sigaction != sigact.sa_sigaction &&
123+
sigact_old.sa_handler != SIG_DFL && sigact_old.sa_handler != SIG_IGN)) {
124+
return false;
125+
}
126+
#endif // ASSERT
127+
return true;
128+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
#ifndef LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP
26+
#define LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP
27+
28+
#include "memory/allocation.hpp"
29+
#include "nmt/memTag.hpp"
30+
#include "utilities/macros.hpp"
31+
32+
#include <csignal>
33+
#include <ctime>
34+
35+
class CompilerThreadTimeoutLinux : public CHeapObj<mtCompiler> {
36+
#ifdef ASSERT
37+
public:
38+
static const int TIMEOUT_SIGNAL = SIGALRM;
39+
void compiler_signal_handler(int signo, siginfo_t* info, void* context);
40+
private:
41+
timer_t _timer;
42+
#endif // ASSERT
43+
public:
44+
CompilerThreadTimeoutLinux() DEBUG_ONLY(: _timer(nullptr)) {};
45+
46+
bool init_timeout();
47+
void arm();
48+
void disarm();
49+
};
50+
51+
#endif //LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP

src/hotspot/os/linux/globals_linux.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@
8989
product(bool, PrintMemoryMapAtExit, false, DIAGNOSTIC, \
9090
"Print an annotated memory map at exit") \
9191
\
92+
develop(intx, CompileTaskTimeout, 0, \
93+
"Set the timeout for compile tasks' CPU time in milliseconds."\
94+
" 0 = no timeout (default)") \
95+
range(0,1000000) \
96+
\
9297
// end of RUNTIME_OS_FLAGS
9398

9499
//

src/hotspot/share/compiler/compileBroker.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) {
218218
CompilerThread* thread = CompilerThread::current();
219219
thread->set_task(task);
220220
CompileLog* log = thread->log();
221+
thread->timeout()->arm();
221222
if (log != nullptr && !task->is_unloaded()) task->log_task_start(log);
222223
}
223224

@@ -228,6 +229,7 @@ CompileTaskWrapper::~CompileTaskWrapper() {
228229
if (log != nullptr && !task->is_unloaded()) task->log_task_done(log);
229230
thread->set_task(nullptr);
230231
thread->set_env(nullptr);
232+
thread->timeout()->disarm();
231233
if (task->is_blocking()) {
232234
bool free_task = false;
233235
{
@@ -1925,6 +1927,10 @@ void CompileBroker::compiler_thread_loop() {
19251927
log->end_elem();
19261928
}
19271929

1930+
if (!thread->init_compilation_timeout()) {
1931+
return;
1932+
}
1933+
19281934
// If compiler thread/runtime initialization fails, exit the compiler thread
19291935
if (!init_compiler_runtime()) {
19301936
return;

src/hotspot/share/compiler/compilerThread.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ CompilerThread::CompilerThread(CompileQueue* queue,
4040
_can_call_java = false;
4141
_compiler = nullptr;
4242
_arena_stat = nullptr;
43+
_timeout = nullptr;
4344

4445
#ifndef PRODUCT
4546
_ideal_graph_printer = nullptr;
@@ -49,6 +50,7 @@ CompilerThread::CompilerThread(CompileQueue* queue,
4950
CompilerThread::~CompilerThread() {
5051
// Delete objects which were allocated on heap.
5152
delete _counters;
53+
delete _timeout;
5254
// arenastat should have been deleted at the end of the compilation
5355
assert(_arena_stat == nullptr, "Should be null");
5456
}

src/hotspot/share/compiler/compilerThread.hpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@
2525
#ifndef SHARE_COMPILER_COMPILERTHREAD_HPP
2626
#define SHARE_COMPILER_COMPILERTHREAD_HPP
2727

28+
#include "memory/allocation.hpp"
29+
#include "nmt/memTag.hpp"
2830
#include "runtime/javaThread.hpp"
31+
#include "utilities/macros.hpp"
32+
33+
#ifdef LINUX
34+
#include "compilerThreadTimeout_linux.hpp"
35+
#endif //LINUX
2936

3037
class AbstractCompiler;
3138
class ArenaStatCounter;
@@ -38,10 +45,27 @@ class CompileQueue;
3845
class CompilerCounters;
3946
class IdealGraphPrinter;
4047

48+
#ifndef LINUX
49+
class CompilerThreadTimeoutGeneric : public CHeapObj<mtCompiler> {
50+
public:
51+
CompilerThreadTimeoutGeneric() {};
52+
void arm() {};
53+
void disarm() {};
54+
bool init_timeout() { return true; };
55+
};
56+
#endif // !LINUX
57+
4158
// A thread used for Compilation.
4259
class CompilerThread : public JavaThread {
4360
friend class VMStructs;
4461
JVMCI_ONLY(friend class CompilerThreadCanCallJava;)
62+
63+
#ifdef LINUX
64+
typedef CompilerThreadTimeoutLinux Timeout;
65+
#else // LINUX
66+
typedef CompilerThreadTimeoutGeneric Timeout;
67+
#endif // LINUX
68+
4569
private:
4670
CompilerCounters* _counters;
4771

@@ -57,6 +81,7 @@ class CompilerThread : public JavaThread {
5781

5882
ArenaStatCounter* _arena_stat;
5983

84+
Timeout* _timeout;
6085
public:
6186

6287
static CompilerThread* current() {
@@ -113,7 +138,13 @@ class CompilerThread : public JavaThread {
113138
public:
114139
IdealGraphPrinter *ideal_graph_printer() { return _ideal_graph_printer; }
115140
void set_ideal_graph_printer(IdealGraphPrinter *n) { _ideal_graph_printer = n; }
116-
#endif
141+
#endif // !PRODUCT
142+
143+
Timeout* timeout() const { return _timeout; };
144+
bool init_compilation_timeout() {
145+
_timeout = new Timeout();
146+
return _timeout->init_timeout();
147+
};
117148

118149
// Get/set the thread's current task
119150
CompileTask* task() { return _task; }
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (C) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package compiler.arguments;
25+
26+
/*
27+
* @test TestCompileTaskTimeout
28+
* @bug 8308094
29+
* @requires vm.debug & vm.flagless & os.name == "Linux"
30+
* @summary Check functionality of CompileTaskTimeout
31+
* @library /test/lib
32+
* @run driver compiler.arguments.TestCompileTaskTimeout
33+
*/
34+
35+
import jdk.test.lib.process.ProcessTools;
36+
37+
public class TestCompileTaskTimeout {
38+
39+
public static void main(String[] args) throws Throwable {
40+
ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "--version")
41+
.shouldHaveExitValue(134)
42+
.shouldContain("timed out after");
43+
44+
ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:TieredStopAtLevel=3", "--version")
45+
.shouldHaveExitValue(134)
46+
.shouldContain("timed out after");
47+
48+
ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:-TieredCompilation", "--version")
49+
.shouldHaveExitValue(134)
50+
.shouldContain("timed out after");
51+
52+
ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=200", "--version")
53+
.shouldHaveExitValue(0)
54+
.shouldContain("java version");
55+
}
56+
}

test/hotspot/jtreg/runtime/signal/TestSigalrm.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,7 @@
2424

2525
/*
2626
* @test
27-
* @requires os.family != "windows" & os.family != "aix"
27+
* @requires os.family != "windows" & os.family != "aix" & vm.flagless
2828
*
2929
* @summary converted from VM testbase runtime/signal/sigalrm01.
3030
* VM testbase keywords: [signal, runtime, linux, macosx]

0 commit comments

Comments
 (0)