Подтвердить что ты не робот

(Как) компилятор Java JIT оптимизирует мой код?

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

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

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, чтобы можно было ожидать, что хороший компилятор С++ оптимизирует эквивалентный код на С++? Могу ли я повлиять на этот процесс? Настройка -XX:+AggressiveOpts, похоже, не имеет значения.

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

4b9b3361

Ответ 2

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

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

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

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

Ответ 3

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

Ответ 4

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