(Как) компилятор Java JIT оптимизирует мой код? - PullRequest
17 голосов
/ 24 ноября 2011

Я пишу код довольно низкого уровня, который должен быть сильно оптимизирован для скорости. Каждый цикл процессора имеет значение. Поскольку код написан на Java, я не могу писать на таком же низком уровне, как, например, на C, но я хочу извлечь из ВМ все, что могу.

Я обрабатываю массив байтов. В настоящий момент меня интересуют две части моего кода. Первый из них:

int key =  (data[i]     & 0xff)
        | ((data[i + 1] & 0xff) <<  8)
        | ((data[i + 2] & 0xff) << 16)
        | ((data[i + 3] & 0xff) << 24);

а второй:

key = (key << 15) | (key >>> 17);

Судя по производительности, я предполагаю, что эти заявления не оптимизированы так, как я ожидаю. Второе утверждение в основном ROTL 15, key. Первый оператор загружает 4 байта в int. Маски 0xff предназначены только для компенсации добавленных знаковых битов, возникающих в результате неявного преобразования типа int, если получаемый байт оказывается отрицательным. Это должно быть легко перевести на эффективный машинный код, но, к моему удивлению, производительность возрастет, если я сниму маски. (Что, конечно, нарушает мой код, но мне было интересно посмотреть, что произойдет.)

Что здесь происходит? Оптимизируют ли наиболее распространенные виртуальные машины Java этот код во время JIT так, как можно ожидать, что хороший компилятор C ++ оптимизирует эквивалентный код C ++? Могу ли я повлиять на этот процесс? Установка -XX:+AggressiveOpts, кажется, не имеет значения.

(ЦП: x64, платформа: Linux / HotSpot)

Ответы [ 4 ]

7 голосов
/ 24 ноября 2011
5 голосов
/ 24 ноября 2011

Я сделал много кода производительности на Java, я даже закодировал непосредственно в Байт-код, достаточно, чтобы быть уверенным в нескольких вещах: JIT - это черный ящик с непонятным поведением, JIT и компиляторы невероятноэффективный, а самый простой код обычно дает наилучшую производительность.

Это нормально, если задуматься о ЦЕЛЕ JIT: извлечь максимально возможную производительность из любого кода Java.Когда вы добавите, что Java является довольно простым и понятным языком, простой код будет оптимизирован, и любой дальнейший трюк, как правило, не принесет пользы.

Конечно, есть некоторые распространенные подводные камни и недостатки, которые вы должны знатьНо я не вижу ничего в ваших примерах кода.Если бы я оптимизировал ваш код, я бы пошел прямо на более высокий уровень: алгоритм.Какова сложность вашего кода?Можно ли кэшировать некоторые данные?Какие API используются?И т. Д. Существует, казалось бы, бесконечная пропасть производительности, которую можно извлечь из одних только алгоритмических приемов.

И если даже этого недостаточно, если язык недостаточно быстр, если ваш компьютер недостаточно быстр, если ваш алгоритм не может быть выполнен быстрее, ответ не будет заключаться в «тактовые циклы»Потому что вы можете снизить эффективность на 20%, но 20% никогда не будет достаточно, когда ваши данные будут расти.Чтобы быть уверенным, что вы никогда не достигнете (снова) стены производительности, окончательный ответ заключается в масштабируемости: сделайте свой алгоритм и ваши данные бесконечно распространяемыми, чтобы вы могли просто привлечь больше работников к выполнению задачи.

3 голосов
/ 24 ноября 2011

Я согласен с solendil, но если вы хотите копать глубже на низком уровне, попробуйте получить код, созданный JIT, как описано здесь .

0 голосов
/ 24 ноября 2011

Вам не нужно (& 0xff) перед сдвигом 24 бит влево.

...