aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/java/com/jogamp/common/os/Clock.java98
-rw-r--r--src/java/com/jogamp/common/util/PerfCounterCtrl.java14
-rw-r--r--src/native/common/jau_sys_Clock.c100
3 files changed, 168 insertions, 44 deletions
diff --git a/src/java/com/jogamp/common/os/Clock.java b/src/java/com/jogamp/common/os/Clock.java
index 756d1d1..466b3fc 100644
--- a/src/java/com/jogamp/common/os/Clock.java
+++ b/src/java/com/jogamp/common/os/Clock.java
@@ -27,21 +27,35 @@ package com.jogamp.common.os;
import java.time.Instant;
public class Clock {
- private static long t0;
+ private static final Instant t0;
static {
Platform.initSingleton(); // loads native gluegen_rt library
- t0 = currentTimeMillis();
+ {
+ final long[/*2*/] val = { 0, 0 };
+ getMonotonicStartupTimeImpl(val);
+ t0 = Instant.ofEpochSecond(val[0], val[1]);
+ }
}
/**
* Returns current monotonic time since Unix Epoch `00:00:00 UTC on 1970-01-01`.
- *
- * Returned fraction_timespec is passing machine precision and range of the underlying native API.
- *
+ * <p>
+ * Returned timespec is passing machine precision and range of the underlying native API.
+ * </p>
+ * <p>
* Monotonic time shall be used for high-performance measurements of durations,
* since the underlying OS shall support fast calls.
- *
- * @see getWallClockTime()
+ * </p>
+ * <p>
+ * Note that {@link #currentTimeNanos()} and {@link #getMonotonicNanos()}
+ * perform much better than this method, since they only return one long nanosecond value
+ * since module startup. <br/>
+ * The implementation of this method needs to write two long values into an array.
+ * </p>
+ * @see #getMonotonicStartupTime()
+ * @see #currentTimeNanos()
+ * @see #getMonotonicNanos()
+ * @see #getWallClockTime()
*/
public static Instant getMonotonicTime() {
final long[/*2*/] val = { 0, 0 };
@@ -52,13 +66,17 @@ public class Clock {
/**
* Returns current wall-clock real-time since Unix Epoch `00:00:00 UTC on 1970-01-01`.
- *
+ * <p>
* Returned Instant is passing machine precision and range of the underlying native API.
- *
+ * </p>
+ * <p>
* Wall-Clock time shall be used for accurate measurements of the actual time only,
* since the underlying OS unlikely supports fast calls.
- *
- * @see getMonotonicTime()
+ * </p>
+ * @see #getMonotonicStartupTime()
+ * @see #currentTimeNanos()
+ * @see #getMonotonicNanos()
+ * @see #getMonotonicTime()
*/
public static Instant getWallClockTime() {
final long[/*2*/] val = { 0, 0 };
@@ -68,29 +86,63 @@ public class Clock {
private static native void getWallClockTimeImpl(final long[/*2*/] val);
/**
- * Returns current monotonic time in milliseconds.
+ * Returns the monotonic startup time since module startup as used in {@link #currentTimeNanos()} and {@link #getMonotonicNanos()}.
+ * @see #currentTimeNanos()
+ * @see #getMonotonicNanos()
*/
- public static native long currentTimeMillis();
+ public static Instant getMonotonicStartupTime() { return t0; }
+ private static native void getMonotonicStartupTimeImpl(final long[/*2*/] val);
/**
- * Returns current wall-clock system `time of day` in seconds since Unix Epoch
- * `00:00:00 UTC on 1 January 1970`.
+ * Returns current monotonic time in nanoseconds since start of this application.
+ * <p>
+ * Monotonic time shall be used for high-performance measurements of durations,
+ * since the underlying OS shall support fast calls.
+ * </p>
+ * <p>
+ * Since the returned nanoseconds are counted not from Unix Epoch but start of this application,
+ * it lasts for 9'223'372'036 seconds or 292 years using the 64-bit type `long`.
+ * </p>
+ * @see #getMonotonicStartupTime()
+ * @see #getMonotonicNanos()
*/
- public static native long wallClockSeconds();
+ public static native long currentTimeNanos();
/**
- * Returns the startup time in monotonic time in milliseconds of the native module.
+ * Returns the Instant presentation of monotonic {@link #currentTimeNanos()}.
+ * <p>
+ * Monotonic time shall be used for high-performance measurements of durations,
+ * since the underlying OS shall support fast calls.
+ * </p>
+ * <p>
+ * Note that the represented time is not from Unix epoch as claimed,
+ * but monotonic module startup time.
+ * </p>
+ * @see #getMonotonicStartupTime()
+ * @see #currentTimeNanos()
*/
- public static long startupTimeMillis() { return t0; }
+ public static Instant getMonotonicNanos() {
+ final long nanos = currentTimeNanos();
+ return Instant.ofEpochSecond(nanos/1000000000L, nanos%1000000000L);
+ }
/**
- * Returns current elapsed monotonic time in milliseconds since module startup, see {@link #startupTimeMillis()}.
+ * Returns current monotonic time in milliseconds.
+ *
+ * @see #getMonotonicStartupTime()
+ * @see #currentTimeNanos()
+ * @see #getMonotonicNanos()
*/
- public static long elapsedTimeMillis() { return currentTimeMillis() - t0; }
+ public static native long currentTimeMillis();
/**
- * Returns elapsed monotonic time in milliseconds since module startup comparing against the given timestamp, see {@link #startupTimeMillis()}.
+ * Returns current wall-clock system `time of day` in seconds since Unix Epoch
+ * `00:00:00 UTC on 1 January 1970`.
+ *
+ * @see #getWallClockTime()
+ * @see #getMonotonicTime()
+ * @see #currentTimeNanos()
+ * @see #getMonotonicNanos()
*/
- public static long elapsedTimeMillis(final long current_ts) { return current_ts - t0; }
-
+ public static native long wallClockSeconds();
}
diff --git a/src/java/com/jogamp/common/util/PerfCounterCtrl.java b/src/java/com/jogamp/common/util/PerfCounterCtrl.java
index 486c248..30290f8 100644
--- a/src/java/com/jogamp/common/util/PerfCounterCtrl.java
+++ b/src/java/com/jogamp/common/util/PerfCounterCtrl.java
@@ -26,9 +26,15 @@
package com.jogamp.common.util;
import java.io.PrintStream;
-import java.time.Duration;
+import com.jogamp.common.os.Clock;
-/** Simple performance counter controller. */
+/**
+ * Simple performance counter controller.
+ * <p>
+ * Implementation is expected to utilize nanosecond counter since module start,
+ * e.g. {@link Clock#currentTimeNanos()}.
+ * </p>
+ */
public interface PerfCounterCtrl {
/** Enable or disable performance counter. */
void enable(final boolean enable);
@@ -36,8 +42,8 @@ public interface PerfCounterCtrl {
/** Clear performance counter. */
void clear();
- /** Return the total duration, covering all sub-counter. */
- Duration getTotalDuration();
+ /** Return the total duration in nanoseconds, covering all sub-counter. */
+ long getTotalDuration();
/** Print performance counter. */
void print(final PrintStream out);
diff --git a/src/native/common/jau_sys_Clock.c b/src/native/common/jau_sys_Clock.c
index 27ee10b..b2d93eb 100644
--- a/src/native/common/jau_sys_Clock.c
+++ b/src/native/common/jau_sys_Clock.c
@@ -25,6 +25,8 @@
*/
#include <jni.h>
+#include <stdlib.h>
+#include <string.h>
#include <assert.h>
@@ -35,31 +37,95 @@
// #include <sys/time.h>
#include <time.h>
-static const int64_t NanoPerMilli = 1000000L;
-static const int64_t MilliPerOne = 1000L;
+static const int64_t NanoPerMilli = 1000000L;
+static const int64_t MilliPerOne = 1000L;
+static const int64_t NanoPerSec = 1000000000L;
+
+static struct timespec startup_t = { .tv_sec = 0, .tv_nsec = 0 };
+
+static void throwNewRuntimeException(JNIEnv *env, const char* msg, ...) {
+ char buffer[512];
+ va_list ap;
+
+ if( NULL != msg ) {
+ va_start(ap, msg);
+ vsnprintf(buffer, sizeof(buffer), msg, ap);
+ va_end(ap);
+
+ fprintf(stderr, "RuntimeException: %s\n", buffer);
+ if(NULL != env) {
+ (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"), buffer);
+ }
+ }
+}
+
+static jboolean throwNewRuntimeExceptionOnException(JNIEnv *env) {
+ if( (*env)->ExceptionCheck(env) ) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ throwNewRuntimeException(env, "An exception occured from JNI as shown.");
+ return JNI_TRUE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
JNIEXPORT void JNICALL
Java_com_jogamp_common_os_Clock_getMonotonicTimeImpl(JNIEnv *env, jclass clazz, jlongArray jval) {
(void)clazz;
- {
- // Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime()
- struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
- clock_gettime(CLOCK_MONOTONIC, &t);
- const jlong val[] = { (jlong)t.tv_sec, (jlong)t.tv_nsec };
- (*env)->SetLongArrayRegion(env, jval, 0, 2, val);
- }
+
+ // Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime()
+ struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ const jlong val[] = { (jlong)t.tv_sec, (jlong)t.tv_nsec };
+ (*env)->SetLongArrayRegion(env, jval, 0, 2, val);
}
JNIEXPORT void JNICALL
Java_com_jogamp_common_os_Clock_getWallClockTimeImpl(JNIEnv *env, jclass clazz, jlongArray jval) {
(void)clazz;
- {
- // Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime()
- struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
- clock_gettime(CLOCK_REALTIME, &t);
- const jlong val[] = { (jlong)t.tv_sec, (jlong)t.tv_nsec };
- (*env)->SetLongArrayRegion(env, jval, 0, 2, val);
+
+ // Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime()
+ struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
+ clock_gettime(CLOCK_REALTIME, &t);
+ const jlong val[] = { (jlong)t.tv_sec, (jlong)t.tv_nsec };
+ (*env)->SetLongArrayRegion(env, jval, 0, 2, val);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jogamp_common_os_Clock_getMonotonicStartupTimeImpl(JNIEnv *env, jclass clazz, jlongArray jval) {
+ (void)clazz;
+
+ // Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime()
+ clock_gettime(CLOCK_MONOTONIC, &startup_t);
+ const jlong val[] = { (jlong)startup_t.tv_sec, (jlong)startup_t.tv_nsec };
+ (*env)->SetLongArrayRegion(env, jval, 0, 2, val);
+ throwNewRuntimeExceptionOnException(env);
+}
+
+/**
+ * See <http://man7.org/linux/man-pages/man2/clock_gettime.2.html>
+ * <p>
+ * Regarding avoiding kernel via VDSO,
+ * see <http://man7.org/linux/man-pages/man7/vdso.7.html>,
+ * clock_gettime seems to be well supported at least on kernel >= 4.4.
+ * Only bfin and sh are missing, while ia64 seems to be complicated.
+ */
+JNIEXPORT jlong JNICALL
+Java_com_jogamp_common_os_Clock_currentTimeNanos(JNIEnv *env, jclass clazz) {
+ (void)env;
+ (void)clazz;
+
+ struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ struct timespec d = { .tv_sec = t.tv_sec - startup_t.tv_sec,
+ .tv_nsec = t.tv_nsec - startup_t.tv_nsec };
+ if ( 0 > d.tv_nsec ) {
+ d.tv_nsec += NanoPerSec;
+ d.tv_sec -= 1;
}
+ return (jlong) ( (int64_t)d.tv_sec * NanoPerSec + (int64_t)d.tv_nsec );
}
/**
@@ -77,8 +143,8 @@ Java_com_jogamp_common_os_Clock_currentTimeMillis(JNIEnv *env, jclass clazz) {
struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
clock_gettime(CLOCK_MONOTONIC, &t);
- int64_t res = (int64_t)( t.tv_sec ) * MilliPerOne +
- (int64_t)( t.tv_nsec ) / NanoPerMilli;
+ int64_t res = (int64_t)t.tv_sec * MilliPerOne +
+ (int64_t)t.tv_nsec / NanoPerMilli;
return (jlong)res;
}