Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
+ void enter_critical() { assert(Thread::current() == this ||
+ Thread::current()->is_VM_thread() && SafepointSynchronize::is_synchronizing(),
+ "this must be current thread or synchronizing");
и, самое главное, метод должен завершаться за короткое время
Меня больше интересует сколько времени эти вызовы занимают по сравнению со временем работы самого алгоритма.Так из графиков же видно. Сравните arrayElementsCritical (стандартный JNI) с javaCritical: делают они одно и то же, значит, вся разница — и есть накладные расходы. Собственно, абзац после графиков отвечает на вопрос.
Это сколько?Зависит от приложения. Для одних паузы в 100 мс критичны, другие и 5 секунд могут подождать.
Так из графиков же видно. Сравните arrayElementsCritical (стандартный JNI) с javaCritical: делают они одно и то же, значит, вся разница — и есть накладные расходы. Собственно, абзац после графиков отвечает на вопрос.
package com;
public final class PreciseTimestamp {
static {
try {
System.loadLibrary("precisetimestamp");
} catch (Throwable e){
throw new RuntimeException(e.getMessage(), e);
}
}
public static native long getMicros();
public static native long getCMicros();
public static void main(String[] args) {
System.out.println(PreciseTimestamp.getMicros());
System.out.println(PreciseTimestamp.getCMicros());
System.out.println(System.currentTimeMillis());
}
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_PreciseTimestamp */
#ifndef _Included_com_PreciseTimestamp
#define _Included_com_PreciseTimestamp
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_PreciseTimestamp
* Method: getMicros
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_com_PreciseTimestamp_getMicros
(JNIEnv *, jclass);
/*
* Class: com_PreciseTimestamp
* Method: getCMicros
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_com_PreciseTimestamp_getCMicros
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include "com_PreciseTimestamp.h"
JNIEXPORT jlong JNICALL Java_com_PreciseTimestamp_getMicros
(JNIEnv * env, jclass jc)
{
//#if defined(_POSIX_TIMERS)
// {
// struct timespec ts;
// if ( 0 == clock_gettime(CLOCK_REALTIME, &ts) )
// {
// return ((((jlong) ts.tv_sec) * 1000000) +
// (((jlong) ts.tv_nsec)) / 1000);
// }
// }
//#endif
// otherwise use gettimeofday
struct timeval tv;
gettimeofday(&tv, NULL);
return (((jlong) tv.tv_sec) * 1000000) + ((jlong) tv.tv_usec);
}
JNIEXPORT jlong JNICALL Java_com_PreciseTimestamp_getCMicros
(JNIEnv * env, jclass jc)
{
//#if defined(_POSIX_TIMERS)
// {
// struct timespec ts;
// if ( 0 == clock_gettime(CLOCK_REALTIME, &ts) )
// {
// return ((((jlong) ts.tv_sec) * 1000000) +
// (((jlong) ts.tv_nsec)) / 1000);
// }
// }
//#endif
// otherwise use gettimeofday
struct timeval tv;
gettimeofday(&tv, NULL);
return (((jlong) tv.tv_sec) * 1000000) + ((jlong) tv.tv_usec);
}
JNIEXPORT jlong JNICALL JavaCritical_com_PreciseTimestamp_getCMicros
()
{
//#if defined(_POSIX_TIMERS)
// {
// struct timespec ts;
// if ( 0 == clock_gettime(CLOCK_REALTIME, &ts) )
// {
// return ((((jlong) ts.tv_sec) * 1000000) +
// (((jlong) ts.tv_nsec)) / 1000);
// }
// }
//#endif
// otherwise use gettimeofday
struct timeval tv;
gettimeofday(&tv, NULL);
return (((jlong) tv.tv_sec) * 1000000) + ((jlong) tv.tv_usec);
}
package com;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* @author vladimir.dolzhenko@gmail.com
* @since 2016-11-17
*/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(1)
@Warmup(iterations = 3, time = 10000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 3, time = 10000, timeUnit = TimeUnit.MILLISECONDS)
@Threads(1)
public class PerfTiming {
@Benchmark
public void testSystemNano(Blackhole bh){
long v = 0;
for(int i = 0; i < 30_000; i++){
v += System.nanoTime();
}
bh.consume(v);
}
@Benchmark
public void testJni(Blackhole bh){
long v = 0;
for(int i = 0; i < 30_000; i++){
v += PreciseTimestamp.getMicros();
}
bh.consume(v);
}
@Benchmark
public void testCriticalJni(Blackhole bh){
long v = 0;
for(int i = 0; i < 30_000; i++){
v += PreciseTimestamp.getCMicros();
}
bh.consume(v);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(PerfTiming.class.getSimpleName())
.warmupIterations(5)
.measurementIterations(5)
.build();
new Runner(opt).run();
}
}
Benchmark Mode Cnt Score Error Units
PerfTiming.testCriticalJni avgt 5 1636.577 ± 40.370 us/op
PerfTiming.testJni avgt 5 1673.504 ± 86.489 us/op
PerfTiming.testSystemNano avgt 5 1179.510 ± 31.920 us/op
JavaCritical_ функции, к сожалению, не работают на Windows:
https://bugs.openjdk.java.net/browse/JDK-8167408
Фикс отложен до JDK 10.
Дорог ли native метод? «Секретное» расширение JNI