-
Couldn't load subscription status.
- Fork 41
Correct System.nanotime() value after restore #53
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
Changes from 11 commits
a69eb66
3b9598b
b3e377f
ef6170b
9099c8e
36daa4d
b56d6ba
57954cc
3cfa1cf
b36ac48
b7f5460
35a9b12
b59d738
5cc8196
725c672
c42768b
028c315
87d19a1
9efee37
4c85031
dd57f35
0b45ade
7d7a410
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
|
@@ -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; | ||
|
||
| } | ||
rvansa marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.