diff options
author | Sven Gothel <[email protected]> | 2023-03-06 22:16:58 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-03-06 22:16:58 +0100 |
commit | 0836295b52aaad1dce10a31a13cb544802d7de03 (patch) | |
tree | 22c3993b50a2783d8ac87084936f24661ae0ff1c /src/native | |
parent | a26445909b3677a8c2de669992a13de2053fa821 (diff) |
Fix Clock for performance counter: Add currentTimeNanos() since module startup, retrievable via getMonotonicStartupTime(). (performance)
Settings two long fields in getMonotonicTime() and creating Instant and using Duration
for high-frequency counter is too expensive.
currentTimeNanos() subtracts the startup time from the current monotonic time and returns the
resulting duration in nanoseconds, which lasts for 292 years since module startup.
This satisfies performance counter requirements.
Diffstat (limited to 'src/native')
-rw-r--r-- | src/native/common/jau_sys_Clock.c | 100 |
1 files changed, 83 insertions, 17 deletions
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; } |