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

JIT компилятор против автономных компиляторов

Существуют ли сценарии, в которых компилятор JIT быстрее других компиляторов, таких как С++?

Считаете ли вы, что в будущем компилятор JIT просто увидит незначительные оптимизации, функции, но будет следовать аналогичной производительности, или будут ли прорывы, которые сделают его бесконечно превосходящим другие компиляторы?

Похоже, что многоядерная парадигма имеет некоторые обещания, но это не универсальная магия.

Любые идеи?

4b9b3361

Ответ 1

Да, конечно, есть такие сценарии.

  • Компиляция JIT может использовать профилирование во время выполнения для оптимизации конкретных случаев на основе измерения характеристик того, что действительно делает код на данный момент, и при необходимости может перекомпилировать "горячий" код. Это не теоретическое; Java HotSpot на самом деле делает это.
  • JITters могут оптимизироваться для конкретной конфигурации процессора и памяти, используемой на самом аппаратном обеспечении, на котором программа выполняется. Например, многие приложения .NET будут работать либо в 32-разрядном, либо в 64-битном коде, в зависимости от того, где они находятся JIT. На 64-битном оборудовании они будут использовать больше регистров, памяти и лучшего набора инструкций.
  • Виртуальные вызовы методов внутри жесткого цикла могут быть заменены статическими вызовами, основанными на знаниях времени выполнения типа ссылки.

Я думаю, что в будущем будут прорывы. В частности, я думаю, что комбинация компиляции JIT и динамического ввода будет значительно улучшена. Мы уже видим это в пространстве JavaScript с помощью Chrome V8 и TraceMonkey. Я ожидаю увидеть другие улучшения аналогичной величины в недалеком будущем. Это важно, потому что даже так называемые "статически типизированные" языки имеют ряд динамических функций.

Ответ 2

Да, компиляторы JIT могут создавать более быстрый машинный код, оптимизированный для текущей среды. Но практически программы VM медленнее, чем Native, потому что JITing сам потребляет время (больше Optimization == больше времени), и для многих методов JITing их может потреблять больше времени, чем их выполнение. И вот почему GAC представлен в .NET

Побочным эффектом для JITing является большое потребление памяти. Однако это не связано со скоростью вычислений, это может замедлить выполнение всей программы, поскольку большое потребление памяти увеличивает вероятность того, что ваш код будет выгружен в вторичное хранилище.

Извините меня за мой плохой английский.

Ответ 3

JIT имеет свои преимущества, но я не вижу, чтобы он полностью перестал. Обычные компиляторы могут тратить больше времени на оптимизацию, в то время как JIT должен балансировать между слишком большой оптимизацией (занимая больше времени, чем сохраняется оптимизацией) и слишком мало (слишком много времени занимает прямое выполнение).

Очевидный ответ - использовать каждый, где он превосходит. JIT могут легче использовать профилирование во время выполнения, чем обычные оптимизаторы (хотя есть компиляторы, которые могут использовать профили времени выполнения в качестве входных данных для оптимизации маршрутов), и обычно могут позволить себе делать больше оптимизации по ЦП (опять же, много обычных компиляторы делают это, но если вы планируете запускать исполняемый файл в разных системах, они не могут полностью использовать его). Обычные компиляторы могут тратить больше времени и делать это по-разному.

Поэтому языковая система будущего будет иметь хорошие оптимизирующие компиляторы, которые будут испускать исполняемый код, предназначенный для использования хорошими оптимизирующими компиляторами JIT. (Это также для многих людей - языковая система настоящего.) (Языковая система будущего также будет поддерживать все, от современных сценариев Python/VB до самого ужасного высокоскоростного хруста.)

Как и во многих вещах, это было предварено Lisp. Совсем недавно некоторые системы Lisp (на самом деле не могут сказать много, не было всего того, что многие реализации Common Lisp) интерпретировали функции Lisp, скомпилировав их на лету. Lisp S-выражения (какой код написан) представляют собой довольно простые описания деревьев синтаксического анализа, поэтому компиляция может идти довольно быстро. В то же время оптимизирующий компилятор Lisp может скомпрометировать код, в котором производительность была действительно важна заблаговременно.

Ответ 4

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

Почему это имеет значение?

//code before
if(errorCondition)
{
  //error handling
}
//code after

Получает преобразование в нечто вроде:

//code before
Branch if not error to Code After
//error handling
Code After:
//Code After

И процессоры x86 не предсказывали бы условный переход вперед в отсутствие информации из блока прогнозирования ветвлений. Это означает, что он прогнозирует запуск кода обработки ошибок, и процессор должен будет очистить конвейер, когда выяснит, что условие ошибки не произошло.

Компилятор JIT мог это увидеть и вставить подсказку для ветки, чтобы CPU предсказал в правильном направлении. Конечно, автономные компиляторы могут структурировать код таким образом, чтобы избежать ошибочного предсказания, но если вам когда-нибудь понадобится посмотреть на сборку, вам может не понравиться, что он прыгает повсюду...

Ответ 5

Еще одна вещь, которая была пропущена в этом разговоре, заключается в том, что когда вы добавляете фрагмент кода, его можно скомпилировать в свободное место в памяти. На языке, подобном С++, если DLL основана на том, что эта часть памяти недоступна, ей придется пройти через дорогостоящий процесс восстановления. Это быстрее, чем JIT-код в неиспользуемый адрес, а затем перекомпилировать скомпилированную DLL в свободное пространство. Чтобы ухудшить ситуацию, переустановленная DLL больше не может использоваться. (см. http://msdn.microsoft.com/en-us/magazine/cc163610.aspx)

Я не очень впечатлен некоторыми оптимизациями в С# 3.5 JIT-коде. Простые вещи, такие как бит-скручивание, которые необходимы для сжатия, ужасно неэффективны (он отказался кэшировать значения в регистре CPU и вместо этого переходил в память для каждой операции). Я не знаю, почему это будет сделано, но это имеет огромное значение, и я ничего не могу с этим поделать.

Лично я считаю, что хорошим решением будет уровень оптимизации (1-100), который вы могли бы задать для компилятора JIT, сколько времени вы думаете, что он должен потратить на оптимизацию вашего кода. Единственным другим решением будет компилятор AOT (Ahead of Time), а затем вы потеряете много преимуществ JIT-кода.

Ответ 6

JIT-компиляторы знают больше о системах, чем статических компиляторах. Добавление многозадачности на лету, характерное для машины, может быть гигантским улучшением скорости, когда они заработают.

JIT-компиляторы вообще имеют немного задержки запуска, когда первый запуск программы/кода может быть намного медленнее, чем предварительно скомпилированный код. Недостаток холодного запуска.

Еще одно большое преимущество компиляции JIT заключается в том, что компилятор может быть обновлен после сборки вашей программы и получения новых трюков компилятора без необходимости полного развертывания новой программы.

Ответ 7

Многие люди ответили, может быть, я скупился (возможно, у меня есть неправильный конец палки), но для меня это две разные вещи:

AFAIK нет ничего, что остановило бы вас JIT'ing скомпилировал С++, например, код машинного кода Dynamo JIT:

http://arstechnica.com/reviews/1q00/dynamo/dynamo-1.html

И это действительно обеспечило ускорение скорости при определенных обстоятельствах.

Компиляция кода в смысле компилятора С++ означает принятие кода, написанного на языке, и превращение его в набор инструкций (или, в некоторых случаях, другой язык для последующего компиляции), которые могут выполняться с помощью какого-то логического устройство.

например. С++ компиляция для сборки (я думаю;-) или С# компиляция в IL или компиляция Java в байтовый код

JIT - это процесс, который происходит во время выполнения. Машина, выполняющая код, анализирует ее, чтобы увидеть, может ли она ее улучшить. Java и С# могут использовать их как в том случае, когда компилятор готовит команды для виртуальной машины, а затем у VM есть возможность, по крайней мере, попытаться оптимизировать ее.

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

Итак, чтобы ответить на ваш вопрос, я не думаю, что JIT заменит статические компиляторы. Я думаю, что всегда будет (пока есть программирование) место для представления представления программы и преобразования его в набор инструкций для машины определенного типа. (потенциально оптимизируя, пока он это делает)

ОДНАКО, я думаю, что JIT может стать большей частью истории, так как время выполнения Java и время выполнения .net развиваются. Я уверен, что JIT улучшится и получит такие вещи, как проект Dynamo. Я предполагаю, что есть возможности для аппаратного обеспечения так что все, что делает ваш процессор, повторно оптимизировано на основе среды времени выполнения.

Ответ 8

Одно из преимуществ JITing, о котором еще не упоминалось, заключается в том, что программа может определять бесконечное число общих типов. Например:

interface IGenericAction { bool Act<T>(); }

struct Blah<T>
{
  public static void ActUpon(IGenericAction action)
  {
     if (action.Act<T>())
       Blah<Blah<T>>.ActUpon(action);
  }
}

Вызов Blah<Int32>.ActUpon(act) вызывает act.Act<Int32>(). Если этот метод вернет true, он вызовет Blah<Blah<Int32>>.ActUpon(act), который, в свою очередь, вызовет act.Act<Blah<Int32>>(). Если это возвращает true, больше вызовов будет выполняться с еще более глубоко вложенным типом. Создание кода для всех методов ActUpon, которые можно было бы назвать, было бы невозможно, но, к счастью, это не было необходимо. Типы не должны генерироваться до тех пор, пока они не будут использоваться. Если action<Blah<...50 levels deep...>>.Act() возвращает false, то Blah<Blah<...50 levels deep...>>.ActUpon не будет вызывать Blah<Blah<...51 levels deep...>>.ActUpon, и последний тип не нужно будет создавать.

Ответ 9

Точка, которая еще не упоминалась, которая поддерживает "автономные" компиляторы, заключается в том, что такие компиляторы могут с пользой ориентироваться на платформы с небольшим объемом ОЗУ - даже до шестнадцати BYTES. Разумеется, все, что даже удаленно совместимо с ПК, может иметь (в буквальном смысле) в миллионы раз больше оперативной памяти, чем это, но я думаю, что будет некоторое время, прежде чем можно будет найти машину со многими мегабайтами ОЗУ, которая стоит менее $0,50 и потребляет менее милливатт мощности во время работы.

Обратите внимание, что 16 байт ОЗУ не настолько слабы, насколько это звучит, поскольку чипы с такой небольшой ОЗУ не хранят код в ОЗУ - имеют отдельную энергонезависимую область памяти для хранения кода (384 байты - это наименьшее, о котором я знаю). Разумеется, этого не много, но этого достаточно, чтобы позволить процессору 0,25 доллара выполнять функции, которые в противном случае требовали бы дискретных компонентов стоимостью 1,00 долларов.

Ответ 10

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