Понимание вывода -XX: + PrintCompilation

183
24

Я запускаю некоторые микро-тесты на итерационный код Java-списка. Я использовал -XX: + PrintCompilation и -verbose: gc flags, чтобы гарантировать, что в фоновом режиме ничего не происходит, когда выполняется время. Однако я вижу что-то в выходе, которое я не могу понять.


Здесь код, я запускаю тест на:


import java.util.ArrayList;
import java.util.List;

public class PerformantIteration {

private static int theSum = 0;

public static void main(String[] args) {
System.out.println("Starting microbenchmark on iterating over collections with a call to size() in each iteration");
List<Integer> nums = new ArrayList<Integer>();
for(int i=0; i<50000; i++) {
nums.add(i);
}

System.out.println("Warming up ...");
//warmup... make sure all JIT comliling is done before the actual benchmarking starts
for(int i=0; i<10; i++) {
iterateWithConstantSize(nums);
iterateWithDynamicSize(nums);
}

//actual
System.out.println("Starting the actual test");
long constantSizeBenchmark = iterateWithConstantSize(nums);
long dynamicSizeBenchmark = iterateWithDynamicSize(nums);
System.out.println("Test completed... printing results");

System.out.println("constantSizeBenchmark : " + constantSizeBenchmark);
System.out.println("dynamicSizeBenchmark : " + dynamicSizeBenchmark);
System.out.println("dynamicSizeBenchmark/constantSizeBenchmark : " + ((double)dynamicSizeBenchmark/(double)constantSizeBenchmark));
}

private static long iterateWithDynamicSize(List<Integer> nums) {
int sum=0;
long start = System.nanoTime();
for(int i=0; i<nums.size(); i++) {
// appear to do something useful
sum += nums.get(i);
}
long end = System.nanoTime();
setSum(sum);
return end-start;
}

private static long iterateWithConstantSize(List<Integer> nums) {
int count = nums.size();
int sum=0;
long start = System.nanoTime();
for(int i=0; i<count; i++) {
// appear to do something useful
sum += nums.get(i);
}
long end = System.nanoTime();
setSum(sum);
return end-start;
}

// invocations to this method simply exist to fool the VM into thinking that we are doing something useful in the loop
private static void setSum(int sum) {
theSum = sum;
}

}



Здесь вывод.


    152   1       java.lang.String::charAt (33 bytes)
160 2 java.lang.String::indexOf (151 bytes)
165 3Starting microbenchmark on iterating over collections with a call to size() in each iteration java.lang.String::hashCode (60 bytes)
171 4 sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (490 bytes)
183 5
java.lang.String::lastIndexOf (156 bytes)
197 6 java.io.UnixFileSystem::normalize (75 bytes)
200 7 java.lang.Object::<init> (1 bytes)
205 8 java.lang.Number::<init> (5 bytes)
206 9 java.lang.Integer::<init> (10 bytes)
211 10 java.util.ArrayList::add (29 bytes)
211 11 java.util.ArrayList::ensureCapacity (58 bytes)
217 12 java.lang.Integer::valueOf (35 bytes)
221 1% performance.api.PerformantIteration::main @ 21 (173 bytes)
Warming up ...
252 13 java.util.ArrayList::get (11 bytes)
252 14 java.util.ArrayList::rangeCheck (22 bytes)
253 15 java.util.ArrayList::elementData (7 bytes)
260 2% performance.api.PerformantIteration::iterateWithConstantSize @ 19 (59 bytes)
268 3% performance.api.PerformantIteration::iterateWithDynamicSize @ 12 (57 bytes)
272 16 performance.api.PerformantIteration::iterateWithConstantSize (59 bytes)
278 17 performance.api.PerformantIteration::iterateWithDynamicSize (57 bytes)
Starting the actual test
Test completed... printing results
constantSizeBenchmark : 301688
dynamicSizeBenchmark : 782602
dynamicSizeBenchmark/constantSizeBenchmark : 2.5940773249184588


Я не понимаю эти четыре строки из вывода.


260   2%      performance.api.PerformantIteration::iterateWithConstantSize @ 19 (59 bytes)
268 3% performance.api.PerformantIteration::iterateWithDynamicSize @ 12 (57 bytes)
272 16 performance.api.PerformantIteration::iterateWithConstantSize (59 bytes)
278 17 performance.api.PerformantIteration::iterateWithDynamicSize (57 bytes)



    Почему оба эти метода скомпилированы дважды?
    Как я могу прочитать этот вывод... что означают различные цифры?

спросил(а) 2021-01-25T19:47:24+03:00 4 месяца, 3 недели назад
1
Решение
175

Я попытаюсь ответить на свой вопрос с помощью этой ссылка, отправленной Thomas Jungblut.


260   2%      performance.api.PerformantIteration::iterateWithConstantSize @ 19 (59 bytes)
268 3% performance.api.PerformantIteration::iterateWithDynamicSize @ 12 (57 bytes)
272 16 performance.api.PerformantIteration::iterateWithConstantSize (59 bytes)
278 17 performance.api.PerformantIteration::iterateWithDynamicSize (57 bytes)

Первый столбец


Первый столбец "260" - это метка времени.


Второй столбец


Второй столбец - это атрибуты compilation_id и method_attributes. Когда компиляция HotSpot запускается, каждый модуль компиляции получает идентификатор компиляции. Число во втором столбце - это идентификатор компиляции. Компиляция JIT и компиляция OSR имеют две разные последовательности для идентификатора компиляции. Таким образом, 1% и 1 являются разными единицами компиляции. % В первых двух строках ссылаются на то, что это компиляция OSR. Компиляция OSR была вызвана, потому что код был циклическим по большому циклу, и VM определила, что этот код является горячим. Таким образом, была создана компиляция OSR, которая позволила бы виртуальной машине выполнить замену на стопку и перейти к оптимизированному коду после ее готовности.


Третий столбец

Третий столбец performance.api.PerformantIteration::iterateWithConstantSize - это имя метода.


Четвертый столбец


Четвертый столбец снова отличается при компиляции OSR, а когда нет. Сначала рассмотрим общие части. Конец четвертого столбца (59 байт) относится к размеру блока компиляции в байт-коде (не размер скомпилированного кода). Компонент @19 в компиляции OSR относится к osr_bci. Я приведу цитату из упомянутой выше ссылки -


"Место" в методе Java определяется его индексом байткода (BCI) и место, вызвавшее компиляцию OSR, называется "osr_bci". Скомпилированный метод NSR может быть введен только из osr_bci; там может быть несколько версий, скомпилированных с помощью OSR того же метода, на одном и том же время, пока их osr_bci отличаются.



Наконец, почему метод был скомпилирован дважды?


Первая - это компиляция OSR, которая предположительно произошла, когда цикл работал из-за кода прогрева (в примере), а вторая компиляция - это компиляция JIT, предположительно для дальнейшей оптимизации скомпилированного кода?

ответил(а) 2021-01-25T19:47:24+03:00 4 месяца, 3 недели назад
-5

Я думаю, что впервые возникла OSR, затем она изменила метод Tigger Counter Invoice
(PS: извините, мой английский - это пул)

ответил(а) 2021-01-25T19:47:24+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема