Skip to content

8307766: Linux: Provide the option to override the timer slack #1631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/hotspot/os/linux/globals_linux.hpp
Original file line number Diff line number Diff line change
@@ -86,7 +86,19 @@
"Use CPU_ALLOC code path in os::active_processor_count ") \
\
product(bool, DumpPerfMapAtExit, false, DIAGNOSTIC, \
"Write map file for Linux perf tool at exit")
"Write map file for Linux perf tool at exit") \
\
product(intx, TimerSlack, -1, EXPERIMENTAL, \
"Overrides the timer slack value to the given number of " \
"nanoseconds. Lower value provides more accurate " \
"high-precision timers, at the expense of (possibly) worse " \
"power efficiency. In current Linux, 0 means using the " \
"system-wide default, which would disable the override, but " \
"VM would still print the current timer slack values. Use -1 "\
"to disable both the override and the printouts." \
"See prctl(PR_SET_TIMERSLACK) for more info.") \
\


// end of RUNTIME_OS_FLAGS

20 changes: 20 additions & 0 deletions src/hotspot/os/linux/os_linux.cpp
Original file line number Diff line number Diff line change
@@ -108,6 +108,7 @@
# include <inttypes.h>
# include <sys/ioctl.h>
# include <linux/elf-em.h>
# include <sys/prctl.h>
#ifdef __GLIBC__
# include <malloc.h>
#endif
@@ -913,6 +914,16 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
if (ret == 0) {
log_info(os, thread)("Thread \"%s\" started (pthread id: " UINTX_FORMAT ", attributes: %s). ",
thread->name(), (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));

// Print current timer slack if override is enabled and timer slack value is available.
// Avoid calling prctl otherwise for extra safety.
if (TimerSlack >= 0) {
int slack = prctl(PR_GET_TIMERSLACK);
if (slack >= 0) {
log_info(os, thread)("Thread \"%s\" (pthread id: " UINTX_FORMAT ") timer slack: %dns",
thread->name(), (uintx) tid, slack);
}
}
} else {
log_warning(os, thread)("Failed to start thread \"%s\" - pthread_create failed (%s) for attributes: %s.",
thread->name(), os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
@@ -4684,6 +4695,15 @@ jint os::init_2(void) {
FLAG_SET_DEFAULT(UseCodeCacheFlushing, false);
}

// Override the timer slack value if needed. The adjustment for the main
// thread will establish the setting for child threads, which would be
// most threads in JDK/JVM.
if (TimerSlack >= 0) {
if (prctl(PR_SET_TIMERSLACK, TimerSlack) < 0) {
vm_exit_during_initialization("Setting timer slack failed: %s", os::strerror(errno));
}
}

return JNI_OK;
}

143 changes: 143 additions & 0 deletions test/hotspot/jtreg/runtime/os/TestTimerSlack.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

import java.util.regex.Pattern;
import java.util.regex.Matcher;

import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;

/**
* @test
* @summary Check that timer slack options work
* @requires os.family == "linux"
* @requires vm.flagless
* @library /test/lib
* @run driver TestTimerSlack
*/
public class TestTimerSlack {

public static void main(String[] args) throws Exception {
int defaultSlack;

// Check the timer slack value is not printed by default
{
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+thread",
"TestTimerSlack$TestMain");

OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldNotContain("timer slack:");
}

// Check the timer slack value is not printed when explicitly disabled
{
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+thread",
"-XX:+UnlockExperimentalVMOptions",
"-XX:TimerSlack=-1",
"TestTimerSlack$TestMain");

OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldNotContain("timer slack:");
}

// Check the timer slack value is good when system-wide default is requested
{
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+thread",
"-XX:+UnlockExperimentalVMOptions",
"-XX:TimerSlack=0",
"TestTimerSlack$TestMain");

OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldContain("timer slack:");

defaultSlack = parseSlackValue(output);

if (defaultSlack == 0) {
fail(output, "Default slack value (" + defaultSlack + ") is unexpected");
}
}

// Check the timer slack value is accepted by all threads
for (int slack : new int[] {1, 10, 100, 1000, 10000, 100000, 1000000}) {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+thread",
"-XX:+UnlockExperimentalVMOptions",
"-XX:TimerSlack=" + slack,
"TestTimerSlack$TestMain");

OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldContain("timer slack:");

int actualSlack = parseSlackValue(output);
if (actualSlack != slack) {
fail(output, "Actual slack value (" + actualSlack + ") is not the requested one (" + slack + ")");
}
}
}

static final Pattern EXTRACT_PATTERN = Pattern.compile("(.*)timer slack: ([0-9]+)ns(.*)");

public static int parseSlackValue(OutputAnalyzer output) {
Integer value = null;
for (String s : output.asLines()) {
Matcher m = EXTRACT_PATTERN.matcher(s);
if (m.matches()) {
Integer parsedValue = Integer.parseInt(m.group(2));
if (value == null) {
value = parsedValue;
} else if (!value.equals(parsedValue)) {
fail(output, "Multiple timer slack values detected");
}
}
}
if (value == null) {
fail(output, "No timer slack values detected");
}
return value;
}

private static void fail(OutputAnalyzer output, String msg) {
output.reportDiagnosticSummary();
throw new IllegalStateException(msg);
}

public static class TestMain {
static final int THREADS = 8;

public static void main(String... args) throws Exception {
Thread[] ts = new Thread[THREADS];
for (int c = 0; c < THREADS; c++) {
ts[c] = new Thread();
ts[c].start();
}

for (int c = 0; c < THREADS; c++) {
ts[c].join();
}
}
}

}