#jvm #java-native-interface #trigonometry #jvm-hotspot
Вопрос:
У меня есть свой собственный тестовый класс, который должен выполнять синхронизацию без удаления JVM. Некоторые примеры тестового времени в 100 000 000 повторений сравнивают родной язык, который Java вызывает из StrictMath.sin (), с моим собственным:
30 градусов
Синенатив(): 18,342,858 нс (#1), 1,574,331 нс (#10)
sinCosTanNew6(): 13,751,140 нс (#1), 1,569,848 нс (#10)
60 градусов
Синенативный(): 2,520,327,020 нс (#1), 2,520,108,337 нс (#10)
, sinCosTanNew6(): 12,935,959 нс (#1), 1,565,365 нс (#10)
С 30 до 60 собственное время стремительно растет * 137, в то время как мое ~постоянно. Кроме того, в некоторых случаях количество повторений невероятно мало, даже когда repsDone возвращает == повторений. Я ожидаю, что они должны быть > 1*повторений.
Процессор: G3258 @ 4 ГГц
ОС: Windows 7 HB SP1
Путь сборки: jre1.8.0_211
Reprex:
public final class MathTest {
private static int sysReps = 1_000_000;
private static double value = 0;
private static final double DRAD_ANGLE_30 = 0.52359877559829887307710723054658d;
private static final double DRAD_ANGLE_60 = 1.0471975511965977461542144610932d;
private static double sineNative(double angle ) {
int reps = sysReps * 100;
//int repsDone = 0;
value = 0;
long startTime, endTime, timeDif;
startTime = System.nanoTime();
for (int index = reps - 1; index >= 0; index--) {
value = Math.sin(angle);
//repsDone ;
}
endTime = System.nanoTime();
timeDif = endTime - startTime;
System.out.println("sineNative(): " timeDif "ns for " reps " sine " value " of angle " angle);
//System.out.println("reps done: " repsDone);
return value;
}
private static void testSines() {
sineNative(DRAD_ANGLE_30);
//sinCosTanNew6(IBIT_ANGLE_30);
}
/* Warm Up */
private static void repeatAll(int reps) {
for (int index = reps - 1; index >= 0; index--) {
testSines();
}
}
public static void main(String[] args) {
repeatAll(10);
}
}
Я попытался добавить angle в цикл, и это умножает время до более разумного уровня, но это мешает математике. Мне нужен способ обмануть его, чтобы запустить весь код все x раз. Время одного прохода чрезвычайно изменчиво, а вызов nanotime() требует времени, поэтому мне нужно среднее значение большого числа.
Комментарии:
1. Ваша собственная реализация, на которую ссылается вопрос, по-видимому, отсутствует в опубликованном коде. Мы не знаем, какова его точность, мы не знаем, какой из дюжины возможных способов вычисления тригонометрических функций используется. Я бы предложил опубликовать минимальный, полный, автономный пример кода, который воспроизводит наблюдения и который могут запускать другие.
2. Я изменил опубликованный код специально для собственного теста. Мое здесь не важно. Проблема в том, как работает собственный метод.
3. Я не думаю, что вы измеряете то, что, как вам кажется, вы измеряете. baeldung.com/java-microbenchmark-harness
4. Говорить, что вы используете Eclipse, не имеет большого смысла. Eclipse-это IDE; это инструмент для компиляции, отладки и запуска приложений, а также других задач для разработки программного обеспечения. Более актуальным является фактический движок Java. Я не знаком с реализациями Java, но они могут иметь свои собственные реализации математических процедур или использовать реализации хост-системы. Поэтому вам придется определить, какую реализацию Java вы используете, и надеяться, что кто-то, знакомый с ней, увидит этот вопрос.
5. Глядя на ваше время, скажем, 5 485 984 нс для 100 000 000 повторений синуса 1 степени, то есть 5 485 984/1e8 = 0,05485984 нс на синус. То есть на процессоре с частотой 4 ГГц . 22 цикла процессора на синус. Как вы думаете, это реалистично или в ваших измерениях что-то не так?
Ответ №1:
Проблема в том, что вы никогда не используете/не ссылаетесь на результаты, возвращаемые sineNative. Компилятор JIT достаточно умен, чтобы понять, что вы никогда не используете возвращаемое значение, поэтому в конечном итоге он просто ничего не сделает. Очень простой способ исправить это-добавить фиктивную проверку возвращаемого значения. (например, если (Математический грех(угол) > 1) { System.out.println(«Невозможно!»); })
Если вы пишете такой тест, было бы полезно использовать что-то вроде JMH (https://github.com/openjdk/jmh), который автоматически создаст черную дыру для вашей возвращаемой переменной, чтобы компилятор JIT не оптимизировал значение. (см. Пример https://github.com/openjdk/jmh/blob/master/jmh-samples/src/main/java/org/openjdk/jmh/samples/JMHSample_09_Blackholes.java)