/*
 * Copyright (c) 2016, 2017, Oracle and/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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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.
 */
package com.oracle.svm.core.util;

import org.graalvm.word.UnsignedWord;
import org.graalvm.word.WordFactory;

import com.oracle.svm.core.annotate.Uninterruptible;
import com.oracle.svm.core.jdk.UninterruptibleUtils;
import com.oracle.svm.core.log.Log;

public class TimeUtils {

    public static final long millisPerSecond = 1_000L;
    public static final long microsPerSecond = 1_000_000L;
    public static final long nanosPerSecond = 1_000_000_000L;
    public static final long nanosPerMilli = nanosPerSecond / millisPerSecond;
    public static final long microsPerNano = nanosPerSecond / microsPerSecond;

    
Convert the given number of seconds to milliseconds.
/** Convert the given number of seconds to milliseconds. */
public static long secondsToMillis(long seconds) { return multiplyOrMaxValue(seconds, millisPerSecond); }
Convert the given number of seconds to nanoseconds.
/** Convert the given number of seconds to nanoseconds. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static long secondsToNanos(long seconds) { return multiplyOrMaxValue(seconds, nanosPerSecond); }
Convert the given number of milliseconds to nanoseconds.
/** Convert the given number of milliseconds to nanoseconds. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static long millisToNanos(long millis) { return multiplyOrMaxValue(millis, nanosPerMilli); }
Convert the given number of microseconds to nanoseconds.
/** Convert the given number of microseconds to nanoseconds. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static long microsToNanos(long micros) { return multiplyOrMaxValue(micros, microsPerNano); }
Nanoseconds since a previous System.nanoTime() call.
/** Nanoseconds since a previous {@link System#nanoTime()} call. */
public static long nanoSecondsSince(long startNanos) { return (System.nanoTime() - startNanos); }
Milliseconds since a previous System.currentTimeMillis() call.
/** Milliseconds since a previous {@link System#currentTimeMillis()} call. */
public static long milliSecondsSince(long startMillis) { return (System.currentTimeMillis() - startMillis); }
Compare two nanosecond times. Do not compare System.nanoTime() results as signed longs! Only subtract them.
/** * Compare two nanosecond times. * * Do not compare {@link System#nanoTime()} results as signed longs! Only subtract them. */
public static boolean nanoTimeLessThan(long leftNanos, long rightNanos) { return ((leftNanos - rightNanos) < 0L); }
Turn an absolute deadline in milliseconds, or a relative delay in nanoseconds, into a relative delay in nanoseconds.
/** * Turn an absolute deadline in milliseconds, or a relative delay in nanoseconds, into a * relative delay in nanoseconds. */
public static long delayNanos(boolean isAbsolute, long time) { if (isAbsolute) { /* Absolute deadline, in milliseconds. */ return millisToNanos(time - System.currentTimeMillis()); } else { /* Relative delay, in nanoseconds. */ return time; } }
Return the number of seconds in the given number of nanoseconds.
/** Return the number of seconds in the given number of nanoseconds. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static long divideNanosToSeconds(long nanos) { return (nanos / nanosPerSecond); }
Return the nanoseconds remaining after taking out all the seconds.
/** Return the nanoseconds remaining after taking out all the seconds. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static long remainderNanosToSeconds(long nanos) { return (nanos % nanosPerSecond); }
Return the number of milliseconds in the given number of nanoseconds.
/** Return the number of milliseconds in the given number of nanoseconds. */
public static long divideNanosToMillis(long nanos) { return (nanos / nanosPerMilli); }
Round the number of nanoseconds to milliseconds.
/** Round the number of nanoseconds to milliseconds. */
public static long roundNanosToMillis(long nanos) { return roundedDivide(nanos, nanosPerMilli); }
Round the number of nanoseconds up to the next-highest number of milliseconds.
/** Round the number of nanoseconds up to the next-highest number of milliseconds. */
public static long roundUpNanosToMillis(long nanos) { return roundedUpDivide(nanos, nanosPerMilli); }
Round the number of nanoseconds to seconds.
/** Round the number of nanoseconds to seconds. */
public static long roundNanosToSeconds(long nanos) { return roundedDivide(nanos, nanosPerSecond); } /* Divide, rounding to the nearest long. */ public static long roundedDivide(long numerator, long denominator) { final long halfStep = denominator / 2L; final long addition = addOrMaxValue(numerator, halfStep); return (addition / denominator); } /* Divide, rounding to the next-highest long. */ public static long roundedUpDivide(long numerator, long denominator) { long almostStep = denominator - 1L; long sum = addOrMaxValue(numerator, almostStep); return (sum / denominator); }
Weight a nanosecond value by a percentage between 0 and 100.
/** Weight a nanosecond value by a percentage between 0 and 100. */
public static long weightedNanos(int percent, long nanos) { final UnsignedWord unweightedNanos = WordFactory.unsigned(nanos); return unweightedNanos.unsignedDivide(100).multiply(percent).rawValue(); }
Add two long values, or return Long.MAX_VALUE if the sum overflows.
/** Add two long values, or return Long.MAX_VALUE if the sum overflows. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static long addOrMaxValue(long x, long y) { /* Not using Math.addExact because it allocates. */ long r = x + y; // HD 2-12 Overflow iff both arguments have the opposite sign of the result if (((x ^ r) & (y ^ r)) < 0) { r = Long.MAX_VALUE; } return r; }
Multiply two long values, or result Long.MAX_VALUE if the product overflows.
/** Multiply two long values, or result Long.MAX_VALUE if the product overflows. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static long multiplyOrMaxValue(long x, long y) { /* Not using Math.multiplyExact because it allocates. */ long r = x * y; long ax = UninterruptibleUtils.Math.abs(x); long ay = UninterruptibleUtils.Math.abs(y); if (((ax | ay) >>> 31 != 0)) { // Some bits greater than 2^31 that might cause overflow // Check the result using the divide operator // and check for the special case of Long.MIN_VALUE * -1 if (((y != 0) && (r / y != x)) || (x == Long.MIN_VALUE && y == -1)) { r = Long.MAX_VALUE; } } return r; }
Have I looped for too long? If so, complain, but reset the wait.
/** Have I looped for too long? If so, complain, but reset the wait. */
public static long doNotLoopTooLong(long startNanos, long loopNanos, long warningNanos, String message) { long result = loopNanos; final long waitedNanos = TimeUtils.nanoSecondsSince(loopNanos); if ((0 < warningNanos) && TimeUtils.nanoTimeLessThan(warningNanos, waitedNanos)) { Log.log().string("[TimeUtils.doNotLoopTooLong:") .string(" startNanos: ").signed(startNanos) .string(" warningNanos: ").signed(warningNanos).string(" < ").string(" waitedNanos: ").signed(waitedNanos) .string(" reason: ").string(message) .string("]").newline(); result = System.nanoTime(); } return result; }
Have I taken too long? Returns true if I have, false otherwise.
/** Have I taken too long? Returns true if I have, false otherwise. */
public static boolean maybeFatallyTooLong(long startNanos, long failureNanos, String reason) { if (0 < failureNanos) { /* If a promptness limit was set. */ final long nanosSinceStart = TimeUtils.nanoSecondsSince(startNanos); if (TimeUtils.nanoTimeLessThan(failureNanos, nanosSinceStart)) { /* If the promptness limit was exceeded. */ Log.log().string("[TimeUtils.maybeFatallyTooLong:") .string(" startNanos: ").signed(startNanos) .string(" failureNanos: ").signed(failureNanos).string(" < nanosSinceStart: ").signed(nanosSinceStart) .string(" reason: ").string(reason).string("]").newline(); return true; } } return false; } }