JMH - почему JIT не устраняет мой мертвый код

Я написал два теста, чтобы продемонстрировать, что JIT может быть проблемой при написании хорошего теста (пожалуйста, пропустите, что я не использую здесь @State):

@Fork(value = 1)
@Warmup(iterations = 2, time = 10)
@Measurement(iterations = 3, time = 2)
@BenchmarkMode(Mode.AverageTime)
public class DeadCodeTraps {

    @Benchmark
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public static void summaryStatistics_standardDeviationForFourNumbers() {
        final SummaryStatistics summaryStatistics = new SummaryStatistics();
        summaryStatistics.addValue(10.0);
        summaryStatistics.addValue(20.0);
        summaryStatistics.addValue(30.0);
        summaryStatistics.addValue(40.0);
        summaryStatistics.getStandardDeviation();
    }

    @Benchmark
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public static void summaryStatistics_standardDeviationForTenNumbers() {
        final SummaryStatistics summaryStatistics = new SummaryStatistics();
        summaryStatistics.addValue(10.0);
        summaryStatistics.addValue(20.0);
        summaryStatistics.addValue(30.0);
        summaryStatistics.addValue(40.0);
        summaryStatistics.addValue(50.0);
        summaryStatistics.addValue(60.0);
        summaryStatistics.addValue(70.0);
        summaryStatistics.addValue(80.0);
        summaryStatistics.addValue(90.0);
        summaryStatistics.addValue(100.0);
        summaryStatistics.getStandardDeviation();
    }

}

Я думал, что JIT устранит мертвый код, поэтому два метода будут выполняться одновременно. Но в итоге у меня:

summaryStatistics_standardDeviationForFourNumbers 0,158 ± 0,046 DeadCodeTraps.summaryStatistics_standardDeviationForTenNumbers 0,359 ± 0,294

Почему JIT не оптимизирует его? Результат summaryStatistics.getStandardDeviation(); нигде вне метода не используется и им не возвращается.

(Я использую сборку OpenJDK 10.0.2+13-Ubuntu-1ubuntu0.18.04.4)


person ByeBye    schedule 14.01.2019    source источник
comment
Какой код мертв здесь? Вы ожидаете, что оба кода займут одинаковое время?   -  person kutschkem    schedule 14.01.2019
comment
Чего конкретно вы ожидаете? я совсем не удивлен такому результату   -  person luk2302    schedule 14.01.2019
comment
summaryStatistics.getStandardDeviation(); нигде не используется вне области действия метода и не возвращается, поэтому нет смысла сохранять этот код после JIT-оптимизации? Или, может быть, он хранит его, поскольку не может решить, есть ли у этого кода какие-либо побочные эффекты?   -  person ByeBye    schedule 14.01.2019


Ответы (1)


Если вы говорите об Apache Commons Math SummaryStatistics, то это массивный класс. Его конструкция наверняка не будет встроена. Чтобы понять почему, запустите -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -XX:-BackgroundCompilation

Устранение мертвого кода происходит после инлайнинга. Неиспользуемые объекты будут распространяться обратно, но невстроенный конструктор разорвет цепочку, потому что оптимизатор JIT больше не может быть уверен в отсутствии побочных эффектов.

Другими словами, код, который вы ожидаете удалить, слишком велик.

person rustyx    schedule 14.01.2019
comment
Да, ты прав. Во-первых, я хотел использовать DoubleSummaryStatistics из java.util, но напортачил с импортом. В случае DoubleSummaryStatistics ЭТО встроено и дает почти такой же результат, как и пустой метод. Спасибо! - person ByeBye; 14.01.2019