0

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

map<string, int> user_settings; 
//somewhere at run-time user_settings are populated 
for(i=0; i < 1000000000000; i++) { 
    if (user_settings["do_stuff"] == 1) { do some stuff... } 
    else { do other stuff } 
} 

Проблема здесь состоит в том, что мы будем делать много нагрузок внутри цикла во время выполнения какой-то вещи, то есть «константа времени выполнения» (а именно, некоторое значение пользовательской настройки). Существует потенциал для доставки значения с помощью непосредственной нагрузки или даже полностью оптимизировать ненужную ветвь и использовать только код необходимой ветки then-else.
Существуют ли языки системы/программирования/jit-компиляторы, которые выполняют такую ​​оптимизацию? Только связанная работа, которую я мог найти, была тезисом какого-то парня MIT: http://groups.csail.mit.edu/cag/rio/josh-meng-thesis.pdf
P.S. Я не прошу оптимизировать это код. Я знаю, что вы можете загрузить значение заранее, которое будет загружено в локальный регистр. Бывают случаи, когда вы не можете выполнить такую ​​«оптимизацию» вручную.

+0

Существует не требование, чтобы результат был «константой времени выполнения» - все, что имеет значение, состоит в том, что тело цикла не меняет его. Перемещение таких инвариантных оценок из цикла в почти стандартном для каждого оптимизатора. – Holger

+0

@ Хольгер вы могли бы привести примеры? потому что, насколько я мог найти только CS-исследования, jit-компиляторы делают это, но нет готового к выпуску языка – artemonster

+0

Я не уверен, какую оптимизацию вы считаете препятствием. Признавая, что выражения представляют собой циклические инварианты, требуется вложение их кода, поэтому встраивание выполняется агрессивно, например. внутри JVM. Остальное - это современное состояние, например.[Справочный документ Hotspot] (http://www.oracle.com/technetwork/java/whitepaper-135217.html) говорит: «* Оптимизатор выполняет все классические оптимизации, включая устранение мертвого кода, подъем инвариантности цикла, устранение общего подвыражения, постоянное распространение, глобальная нумерация значений и движение глобального кода * «... – Holger

ответ

0

Один аккуратный подход, который используется, например, в динамических линкеров могут быть полезны здесь:

Сделайте ваш компилятор генерировать динамический код, чтобы он знает, кто назвал его.

Таким образом, если динамический код обнаружит, что полученные данные никогда не могут измениться, он может просто переписать код на сайте вызова. Поэтому вместо CALL get_user_setting "do_stuff" он заменит инструкцию PUSH int 1 или что-то еще, и, возможно, несколько NOP s, чтобы выставить размер инструкции CALL.

Динамические линкеры часто это делают. В первый раз, когда вы пытаетесь вызвать динамически связанную функцию, они фактически прыгают в загрузчик. Он загружает фактическую функцию, затем перезаписывает инструкцию CALL, поэтому она вызывает загруженную функцию вместо подпрограммы для загрузки функции. Любые будущие вызовы тогда не обязательно будут искать второй раз. (Я писал об этом here)

0

Хороший шаг оптимизации компиляторов бы потенциально преднагрузки и тест «делать вещи» из словаря и падение итерации все вместе. Это сделало бы это, если бы он мог определить, что нет побочного эффекта, который бы изменил значение слова «do stuff» в словаре.

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

Например, на большинстве функциональных языков я уверен, что содержание большинства объявленных типов данных (списки, наборы, карты) не изменятся (будут постоянными) со временем. В некоторых случаях эти языки поддерживают побочные или мутативные возможности, и в этом случае ваши оптимизации также должны учитывать это.

Смежные вопросы