2011-01-16 2 views
4

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

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

ответ

5

Вот некоторые варианты для снижения накладных расходов:

  1. Declare функции, как fastcall (или нечто подобное), чтобы уменьшить накладные расходов аргумента проходящих
  2. Используйте большой переключатель случай вместо таблицы (компилятор будет оптимизирован для таблицы перехода, и вы удалите накладные расходы от фактического вызова функции)
  3. Скопируйте весь код для процедуры виртуальной машины в одно место, чтобы она могла работать последовательно, а не возвращаться к интерпретатору после каждой инструкции.

В конце концов вы достигнете точки JIT-компиляции, он-лайн профилирования и повторной оптимизации, а также всевозможные другие потрясающие вещи.

+0

Я бы пошел с 'switch' пока. Он чистый, простой и портативный. –

+0

++ Именно поэтому C имеет оператор 'switch'. Поэтому, если вам нужна таблица перехода, вы говорите компилятору, что она может ее создать. И зачем вообще беспокоиться о функциях? Просто расширьте их на месте в инструкции switch или, по крайней мере, наиболее часто исполняемые. Таким образом, вам не нужно надеяться, что оптимизатор сделает то, что вы хотите. –

2

Есть много хороших техник, которые вы, возможно, захотите изучить. Вот два, что я знаком с:

  1. Inline caching - По сути, найти то, что продолжает получать называется, то переход от поиска, чтобы виртуальных таблиц, просто добавив кучу если заявления, отправляющих на статический известное место. Этот метод был использован для значительного эффекта на языке Self и является одной из основных оптимизаций JVM.

  2. Трассировка. Компиляция одной версии части полиморфной рассылки для каждого типа, которая может быть использована, но откладывает компиляцию до тех пор, пока код не будет запущен достаточно много раз. Mozilla's TraceMonkey JavaScript-интерпретатор использует это, чтобы получить огромный выигрыш в производительности во многих случаях.

Надеюсь, это поможет!

+0

Встроенное кэширование поможет, если он использует JIT, который делает это (в том, что он будет встроить функции opcode), но это C, поэтому нет JIT. – delnan

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