25 июл. 2009 г.

Общие приёмы повышения производительности кода на Lua 5.1

Примерно в порядке убывания эффективности.
  1. Использовать более эффективные алгоритмы. Проверять эффективность бенчмарками, а не на глазок.
  2. Помнить, что компилятор Луа не делает никаких оптимизаций (кроме constant folding'а в некоторых случаях). В прикладном коде по возможности использовать LuaJIT / llvm-lua.
  3. Минимизировать число конкатенаций строк в несколько приёмов, особенно в циклах. Строки в Луа — константные, так что конкатенации в несколько приёмов засоряют память мёртвыми объектами. Заменять на table.concat() и, в прикладном коде, rope'ы. Множественные конкатенации в один приём (a = a .. b .. c) — дают одну инструкцию виртуальной машины, не страшно.
  4. Минимизировать число создаваемых таблиц. Каждый конструктор таблицы — аллокация.
  5. Минимизировать число создаваемых функций (замыканий) и корутин. Каждое такое создание — аллокация. Избегать необоснованного создания функций внутри функций и в циклах (однако это слишком полезный приём, чтобы от него отказываться полностью).
  6. Минимизировать число операций индексации таблиц, особенно hash-части таблицы. Помнить, что обращение к глобальной переменной — также индексация (глобального окружения), операторы "." и ":" — тоже индексация. По возможности кешировать результаты индексации в локальных переменных.
  7. Предпочитать хвостовую рекурсию. Вызов function() return foo() end эффективнее function() foo() end.
  8. Numeric for от 1 до размера таблицы дешевле pairs, pairs — дешевле ipairs.
  9. Выносить (там, где это осмысленно) создание объектов (таблиц, функций, корутин, юзердат) в глобальный chunk файла (но максимально ограничивать их область видимости).
  10. При использовании LuaJIT минимизировать число вызовов из Lua в C — маршаллинг в этом случае довольно дорогой. При использовании классического интерпретатора Lua маршаллинг практически бесплатный — наоборот может иметь смысл переписать на C наиболее медленные части кода.
Дополнительное чтение:
  1. Статья Р. Иерусалимского в Lua Programming Gems "Lua Performance Tips".
  2. Lua Users Wiki: Optimization Tips
  3. Unofficial Lua FAQ 1.8: Optimization tips?
  4. A No Frills Introduction to Lua 5.1 VM Instructions
  5. The implementation of Lua 5.0
  6. Lua - an extensible extension language

4 комментария:

edo комментирует...

7 - а в чём секрет?

9 - честно говоря не понял, можно подробнее?

Александр Гладыш комментирует...

7. Секрет в том, что return foo() -- tail call. При этом не создаётся запись в стеке вызовов.

Александр Гладыш комментирует...

9. Всё просто. Наивный пример:

-- Медленнее
local one_two_or_three = function()
local t = { 1, 2, 3 }
return t[math.random(#t)]
end

-- Быстрее
local one_two_or_three
do
local t = { 1, 2, 3 }
one_two_or_three = function()
return t[math.random(#t)]
end
end

edo комментирует...

спасибо