Skip to content
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a69eb66
Fix failing CRaC tests
rvansa Feb 22, 2023
3b9598b
Remove somebody's forgotten overrides
rvansa Feb 22, 2023
b3e377f
Convert CRaC tests from shell scripts to Java
rvansa Feb 22, 2023
ef6170b
Rename enum for `simengine` to SIMULATE
rvansa Feb 24, 2023
9099c8e
Add docker to CracBuilder
rvansa Mar 1, 2023
36daa4d
Merge remote-tracking branch 'origin/crac' into test-crac-java
rvansa Mar 2, 2023
b56d6ba
Use default main and args from CracTest
rvansa Mar 2, 2023
57954cc
Remove test name from the @run JTreg tag
rvansa Mar 2, 2023
3cfa1cf
Merge remote-tracking branch 'origin/crac' into test-crac-java
rvansa Mar 2, 2023
b36ac48
Adjust System.nanoTime() to keep consistent time origin after restore
rvansa Feb 28, 2023
b7f5460
Merge remote-tracking branch 'origin/crac' into nanotime
rvansa Mar 23, 2023
35a9b12
Correct time since restore
rvansa Mar 30, 2023
b59d738
Reset nanotime offset before calculating it again
rvansa Apr 6, 2023
5cc8196
Set nanotime only if bootid changes
rvansa Apr 14, 2023
725c672
Ensure monotonicity for the same boot
rvansa Apr 27, 2023
c42768b
Use image under ghcr.io/crac
rvansa Apr 27, 2023
028c315
Fix whitespaces
rvansa May 11, 2023
87d19a1
Merge branch 'crac' into nanotime
rvansa May 11, 2023
9efee37
Do not use negative monotonic offset
rvansa May 12, 2023
4c85031
Merge branch 'crac' into nanotime
rvansa May 12, 2023
dd57f35
More checks when reading boot ID
rvansa May 16, 2023
0b45ade
Merge branch 'crac' into nanotime
rvansa May 16, 2023
7d7a410
Merge branch 'crac' into nanotime
rvansa May 19, 2023
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
3 changes: 3 additions & 0 deletions src/hotspot/os/linux/os_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6021,6 +6021,7 @@ class CracSHM {
};

static int checkpoint_restore(int *shmid) {
os::record_time_before_checkpoint();

int cres = call_crengine();
if (cres < 0) {
Expand All @@ -6038,6 +6039,8 @@ static int checkpoint_restore(int *shmid) {
} while (sig == -1 && errno == EINTR);
assert(sig == RESTORE_SIGNAL, "got what requested");

os::update_javaTimeNanos_offset();

if (CRTraceStartupTime) {
tty->print_cr("STARTUPTIME " JLONG_FORMAT " restore-native", os::javaTimeNanos());
}
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/os/posix/os_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1410,7 +1410,7 @@ jlong os::javaTimeNanos() {
struct timespec tp;
int status = clock_gettime(CLOCK_MONOTONIC, &tp);
assert(status == 0, "clock_gettime error: %s", os::strerror(errno));
jlong result = jlong(tp.tv_sec) * NANOSECS_PER_SEC + jlong(tp.tv_nsec);
jlong result = jlong(tp.tv_sec) * NANOSECS_PER_SEC + jlong(tp.tv_nsec) + javaTimeNanos_offset;
return result;
}

Expand Down
27 changes: 27 additions & 0 deletions src/hotspot/share/runtime/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ int os::_processor_count = 0;
int os::_initial_active_processor_count = 0;
os::PageSizes os::_page_sizes;

// Timestamps recorded before checkpoint
jlong os::checkpoint_millis = -1;
jlong os::checkpoint_nanos;
// Value based on wall clock time difference that will guarantee monotonic
// System.nanoTime() close to actual wall-clock time difference.
jlong os::javaTimeNanos_offset = 0;

#ifndef PRODUCT
julong os::num_mallocs = 0; // # of calls to malloc/realloc
julong os::alloc_bytes = 0; // # of bytes allocated
Expand Down Expand Up @@ -2023,3 +2030,23 @@ void os::PageSizes::print_on(outputStream* st) const {
st->print("empty");
}
}

void os::record_time_before_checkpoint() {
// If CRaC supports multiple checkpoint - restore - checkpoint - restore cycles
// we want to record the timestamps only on the first checkpoint, but update
// the offset after each restore
if (checkpoint_millis < 0) {
checkpoint_millis = javaTimeMillis();
checkpoint_nanos = javaTimeNanos();
}
}

void os::update_javaTimeNanos_offset() {
assert(checkpoint_millis >= 0, "Restore without a checkpoint?");
long diff_millis = javaTimeMillis() - checkpoint_millis;
// If the wall clock has gone backwards we won't add it to the offset
if (diff_millis < 0) {
diff_millis = 0;
}
javaTimeNanos_offset = checkpoint_nanos - javaTimeNanos() + diff_millis * 1000000L;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please explain why isn't javaTimeNanos_offset = checkpoint_nanos - javaTimeNanos() sufficient? What am I missing here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ashu-mehra Had we ignored the diff_millis part, the diff of nanotime before and after checkpoint would indicate that no time elapsed between checkpoint and restore. With this in place the difference does not have the expected accuracy but at least it's monotonic; wall clock time difference gives us the best possible estimate.

}
7 changes: 7 additions & 0 deletions src/hotspot/share/runtime/os.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ class os: AllStatic {
static address _polling_page;
static PageSizes _page_sizes;

static jlong checkpoint_millis;
static jlong checkpoint_nanos;
static jlong javaTimeNanos_offset;

static char* pd_reserve_memory(size_t bytes, bool executable);

static char* pd_attempt_reserve_memory_at(char* addr, size_t bytes, bool executable);
Expand Down Expand Up @@ -199,6 +203,9 @@ class os: AllStatic {
static void javaTimeSystemUTC(jlong &seconds, jlong &nanos);
static void run_periodic_checks();

static void record_time_before_checkpoint();
static void update_javaTimeNanos_offset();

// Returns the elapsed time in seconds since the vm started.
static double elapsedTime();

Expand Down
2 changes: 2 additions & 0 deletions src/java.base/share/classes/java/lang/System.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import java.util.function.Supplier;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

import jdk.internal.misc.Unsafe;
import jdk.internal.util.StaticProperty;
import jdk.internal.module.ModuleBootstrap;
Expand Down Expand Up @@ -2449,4 +2450,5 @@ public void exit(int statusCode) {
}
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ java/lang/System::lineSeparator()
java/lang/System::load(Ljava/lang/String;)
java/lang/System::loadLibrary(Ljava/lang/String;)
java/lang/System::mapLibraryName(Ljava/lang/String;)
java/lang/System::nanoTime()
java/lang/System::nanoTime0()
java/lang/annotation/IncompleteAnnotationException::IncompleteAnnotationException(Ljava/lang/Class;Ljava/lang/String;)
java/util/AbstractSet::toString()
java/util/HashSet::toString()
111 changes: 111 additions & 0 deletions test/jdk/jdk/crac/java/lang/System/NanoTimeTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2023, Azul Systems, Inc. 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 jdk.crac.*;
import jdk.test.lib.containers.docker.Common;
import jdk.test.lib.containers.docker.DockerTestUtils;
import jdk.test.lib.crac.CracBuilder;
import jdk.test.lib.crac.CracTest;
import jdk.test.lib.crac.CracTestArg;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
* @test NanoTimeTest
* @requires (os.family == "linux")
* @requires docker.support
* @library /test/lib
* @build NanoTimeTest
* @run driver jdk.test.lib.crac.CracTest 0
* @run driver jdk.test.lib.crac.CracTest 86400
* @run driver jdk.test.lib.crac.CracTest -86400
*/
public class NanoTimeTest implements CracTest {
private static final String imageName = Common.imageName("system-nanotime");

@CracTestArg
long monotonicOffset;

public static void main(String[] args) throws Exception {
CracTest.run(NanoTimeTest.class, args);
}

@Override
public void test() throws Exception {
if (!DockerTestUtils.canTestDocker()) {
return;
}
CracBuilder builder = new CracBuilder().inDockerImage(imageName).main(NanoTimeTest.class).args(CracTest.args());
try {
builder.doCheckpoint();

builder.startRestore(Arrays.asList("docker", "exec", CracBuilder.CONTAINER_NAME,
"unshare", "--fork", "--time", "--boottime", "86400", "--monotonic", String.valueOf(monotonicOffset),
CracBuilder.DOCKER_JAVA)).waitForSuccess();
} finally {
builder.ensureContainerKilled();
}
}

@Override
public void exec() throws Exception {
System.out.println("Expected offset: " + monotonicOffset);
// We use uptime to assert that changing the clock worked
long boottimeBefore = readSystemUptime();

long before = System.nanoTime();
Core.checkpointRestore();
long after = System.nanoTime();
System.out.println("Before: " + before);
System.out.println("After: " + after);
if (after < before) {
throw new AssertionError("After < Before");
} else if (after > before + TimeUnit.HOURS.toNanos(1)) {
// Even though we have shifted the monotic offset by a day the difference
// is adjusted by difference between wall clock time before and after;
// the difference in monotonic time is considered "random"
throw new AssertionError("After too late");
}

long boottimeAfter = readSystemUptime();
if (boottimeAfter < boottimeBefore + 86_400_000) {
throw new AssertionError("Boottime was not changed");
}
RuntimeMXBean runtimeMX = ManagementFactory.getRuntimeMXBean();
if (runtimeMX.getUptime() < 0) {
throw new AssertionError("VM Uptime is negative!");
}
}

private long readSystemUptime() throws IOException {
String uptimeStr = Files.readString(Path.of("/proc/uptime"));
String[] parts = uptimeStr.split(" ");
return (long)(Double.parseDouble(parts[0]) * 1000);
}
}