a_jelly: (Default)
[personal profile] a_jelly
1. Введение

Недавно я задался вопросом сравнения производительности bytecode виртуальных машин (VM). Таких как JVM, LLVM, .Net, etc.
Прямое сравнение трудно было произвести по нескольким причинам. Во-первых, нужен был подходящий набор тестов, который хоть как-то покрывает предоставляемые VM функции. Во-вторых, нужно было найти язык, который бы компилировался в байт-код всех тех VM, которые я хотел протестировать, и наконец - нужно было просто выкроить время. Не прошло и полгода, как я решил эти проблемы, хоть и не в полной мере.


В качестве языка для примеров я выбрал Lua (5.1), т.к. компиляторы в байткод с него существуют для всех интересных мне машин. В качестве же тестов я взял исходники с The Computer Language Benchmarks Game, и кое-где доработал их рашпилем (правда, должен заранее сказать, что не знаю Lua). Предпочтение отдавалось "straightforward" реализациям, не имеющим системных завязок и минимально зависящим от библиотек языка. Понятно, что несложно приделать к любому языку быстродействующую библиотеку (к примеру на С), но тогда сравниваться будет совсем не то, что нам нужно.

Вот четыре теста, которые я использовал:
Binary tree - бинарные деревья, тест на работу с памятью
Heap sort - сортировка кучи, память + работа с целыми
Sieve - решето Эратосфена, битовые операции
Pi-digit - вычисление знаков числа Пи, числодробилка

Эти примеры были взяты из источника выше, с минимальными модификациями.
Какие же виртуальные машины были протестированы? Это:


  • .Net CLR от Microsoft - без комментариев (использовался компилятор Lua2IL)

  • Parrot VM - относительно новая и подающая надежды регистровая VM общего назначения (использовался компилятор Lua on Parrot)

  • LLVM - одна из наиболее развитых регистровых VM общего назначения (использовался компилятор LLVM-Lua 2.7)

  • JVM (последняя Sun-овская версия) - классика жанра (использовался компилятор LuaJ)


Также в качестве референсных имплементаций были использованы "pure Java" и "pure Lua". Первая - это код из того же источника, но на Java, вторая - версия на Lua, но интерпретируемая стандартным интерпретатором Lua. Также в тест был включен весьма продвинутый (но языково-специфичный) компилятор и VM LuaJIT (2.0). Результаты, которых достиг этот компилятор всего за пару лет разработки весьма впечатляют (первый релиз версии 2.0 был в 2009 году).

Тесты прогонялись на моем компьютере на базе Intel Core 2 Duo. Первая VM запускалась под Windows XP (что логично) остальные - под Linux. Каждый тест занимавший более 30 секунд прогонялся три раза. В таблицу записывалось значение медианы. В случае, если дождаться результата для данной VM и входных параметров было проблематично, тест не проводился.

2. Собственно результаты
2.1. Цифры (время в секундах)

Binary tree Pure Lua Lua .Net Lua Parrot Lua LLVM Lua JVM LuaJIT Pure Java Java (no JIT)
13 2.480 10.797 218.190 3.590 4.360 0.740 0.146 0.740
15 13.440 58.813
18.520 17.700 3.310 0.416 3.470
17 65.210 300.000
89.330 79.600 15.650 1.510 16.240
Heap sort Pure Lua Lua .Net Lua Parrot Lua LLVM Lua JVM LuaJIT Pure Java Java (no JIT)
100000 0.710 0.704 119.280 0.460 2.000 0.060 0.031 0.162
1000000 8.860 9.109
6.120 16.200 0.700 0.457 2.413
10000000 107.580 118.328
75.650 193.300 28.440 8.122 31.440
Sieve Pure Lua Lua .Net Lua Parrot Lua LLVM Lua JVM LuaJIT Pure Java Java (no JIT)
8 0.400 8.093 69.560 0.510 2.715 0.030 0.019 0.058
12 7.160 140.891
8.920 33.025 0.480 0.124 0.975
16 121.500

154.960 539.000 8.900 2.678 18.650
Pi-digits Pure Lua Lua .Net Lua Parrot Lua LLVM Lua JVM LuaJIT Pure Java Java (no JIT)
1000 1.520
460.630 1.140 13.840 0.100 0.989 5.530
2000 14.590

5.230 59.700 0.420 3.045 23.600
4000 64.790

22.660 270.700 1.840 12.020 99.800
8000




9.260 50.500


2.2. Графики






3. Обсуждение результатов

Многие графики далеки от линейности, поскольку тесты таковы, что даже при линейном увеличении входных параметров, вычислительная сложность растет нелинейно. В любом случае - лидеры нашего сравнения вполне очевидны, это LLVM и JVM. Microsoft-овский .Net не сильно уступает, а вот реализация Parrot пока может рассматриваться разве что в качестве proof of concept.

Не кажется странным и то, что машины специально заточенные под язык (такие как JVM и LuaJit) значительно обгоняют "универсальные" машины, деля между собой первенство в общем зачете. То, что JVM, которую вылизывают уже больше 10 лет быстро работает для pure Java реализации говорит еще и о том, что ее компилятор достаточно хорошо осведомлен о внутренней структуре виртуальной машины и способен сгенерировать оптимальный код. Если же код генерируется другим компилятором и для другого языка, то производительность резко падает. Это можно увидеть сравнив Pure Java реализации и Lua JVM.

Также наглядно видно, насколько большого выигрыша удается достичь используя технологию JIT. Мы видим, что LuaJIT близок к Java, а на одном тесте даже опережает ее. Отключение JIT в Java снижает производительность в 4-10 раз.

Наконец, имеет место довольно странный результат, который я пока не могу обьяснить в тесте Heap sort. А именно - при том, что рост времени с очевидностью должен быть линеен, мы наблюдаем странный провал на границе между миллионом и десятью миллионами item-ов как у Java так и у LuaJIT. Исследовав ситуацию более детально я обнаружил следующее.
У LuaJIT излом находится между 5 и 6 миллионами (5*10^6=4.67 sec, 6*10^6=16.7 sec) у Pure Java - между 4 и 10 (4*10^6=2.63 sec, 10*10^6=8.122 sec). Такое ощущение, что в этот момент VM (или даже OS?) меняет механизм выделения памяти.

4. Resume

Итак, исходя из результатов можно дать очевидные рекомендации: если вам нужна language-specific VM и ваш язык - Lua, то следует использовать LuaJIT, показавший очень высокую скорость. Если вам нужна универсальная машина - то больше подойдет LLVM. И наконец, если вы уже пользуетесь Java, то нет нужды мигрировать на другие решения, поскольку пока производительность JVM для "родного" языка не уступает другим VM (хотя перемены в будущем похоже грядут).

January 2026

S M T W T F S
    123
4 5678910
11121314151617
18192021222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 6th, 2026 08:29 pm
Powered by Dreamwidth Studios