Язык Lua — секреты производительности / Ник Заварицкий...

41
Lua: секреты производительности NICK ZAVARITSKY [email protected]

Transcript of Язык Lua — секреты производительности / Ник Заварицкий...

О докладчике• занимаюсь Tarantool

• это СУБД

• вместо языка запросов — Lua

• сейчас работаем над SQL

• in-memory DB ⇒ SQL JIT

Agenda

• как устроен LUAJIT

• доступные JIT-технологии

JIT в Lua• по скорости не уступает V8 / HHVM / …

• надо уметь готовить

• LUAJIT: 78 KSLOC

• V8: 2100 KSLOC

Доступные JIT-технологии

• кодогенерация в язык с JIT

• LLVM

• наш опыт: JIT в production за 6 месяцев

Язык Lua

Perl-5.22.1

Python-2.7.11

Ruby-2.2.5

Java (openjdk-1.8 -Xint)

JavaScriptCore-1.12.3 (LLint)

LuaJit-2.1.0-beta2 (-j off)

PHP-7.1.0-dev

Java (openjdk-1.8)

PyPy-4.0.1

SpiderMonrey-1.8.5

V8-3.14.5.10

JavaScriptCore-1.12.3

LuaJit-2.1.0-beta2

PHP/llvm-jit

GCC-5.3 -O31 100 10000

1111

131416

2730

469298

190243

609940

2 063

-- dynamically typed local v v = 1 v = "string" v = true v = { } -- table v = function () end

local p = { "Hello, world!", "", RIPJSB = 1750, [":)"] = 1963 }

print(p[0]) -- nil print(p[1]) -- Hello, world! print(p.RIPJSB) -- 1750 print(p["RIPJSB"]) -- 1750

-- closures function uniqueid (prefix) local counter = 0 return function () counter = counter + 1 return (prefix or "_")..counter end end

local u = uniqueid("awesome") print(u()) -- awesome1 print(u()) -- awesome2

LUAJIT FFI

ffi.cdef [[ struct Complex { double real; double imag; }; ]] local vec = ffi.new("struct Complex[?]", 1000) vec[0].real = 42.0

ffi.cdef [[ int getpid(); int kill(int pid, int sig); ]] ffi.C.kill(ffi.C.getpid(), 9) -- Ouch!

LUAJIT: интерпретатор

function clamp(x) return math.max(x, 0) end

GGET 1 0 ; "math" TGETS 1 1 1 ; "max" MOV 2 0 KSHORT 3 0 CALLT 1 3

0:

1:

2:

3:

param_x

_G["math"]["max"]

param_x

0

0:

1:

2:

3:

param_x

_G["math"]["max"]

param_x

0

/* {foo = "bar"} */ lua_newtable(L); lua_pushstring(L, "foo"); lua_pushstring(L, "bar"); lua_settable(L, -2);

IEEE 754 Double

11111111111

NaN0 / 0 ∞ - ∞

51 бит

tag, value

знак: 1 экспонента: 11 мантисса: 52

LUAJIT: компилятор

Perl-5.22.1

LuaJit-2.1.0-beta2 (-j off)

LuaJit-2.1.0-beta2

GCC-5.3 -O3

1 100 10000

11

13

98

2 063

JIT-компилятор• профилирует код на лету

• находит хотспоты

• компилирует горячий код

• холодный код не компилирует

• full-method vs. tracing JIT

Что такое “трасса”?• последовательность байткодов в порядке выполнения

• видны типы переменных

• посещаем одну ветку в if-then-else

• линейная — легко оптимизировать

• если потом типы изменятся?

• если нужна другая ветка в if? — guard

Откуда берутся трассы?• нагретая инcтрукция FORI/LOOP/FUNC* включает запись трассы

• когда останавливать запись?

• FORI/LOOP/FUNC* заменяем на JFORI/JLOOP/JFUNC*

• возврат в интерпретатор — по выходу из функции или по guard

Side-трассы

• для guard-ов собирается статистика

• из горячего guard вырастает дочерняя трасса

• JFORI/JLOOP/JFUNC* во время записи?

Где спотыкается JIT• NYI

• сложные ветвления

• равновероятные ветвления в цикле

• циклы с малым числом итераций

• нестабильные типы

• LuaC

Как лечить?

$ luajit -jdump=tx test.lua ---- TRACE 1 start test.lua:1 ---- TRACE 1 abort test.lua:2 -- NYI: FastFunc print

Takeaway #1• Lua — современный и высокоуровневый

• легко встраивается

• работает быстро

• any sufficiently complicated C program contains …

an implementation of half of Common Lisp —Greenspun’s 10th rule

Takeaway #2• LUAJIT: 78 KSLOC / 0.013 секунд на тесте CLBG/M

• V8: 2100 KSLOC / 0.016 секунд

• трассирующий JIT проще в реализации

• у программиста больше забот

• Emscripten для LUAJIT?

Takeaway #3

• LUAJIT легко похачить

• идеальный объект для изучения*

sql("SELECT * FROM orders WHERE id = %", id)

Доступные JIT-технологии

наш опыт: JIT в production за 6 месяцев

Схемы Avro{ "First": "John", "Last": "Doe" }

{ "name": "Person", "type": "record", "fields": [

{ "name": "First", "type": "string" },

{ "name": "Last", "type": "string" }

] }

Хранится как: ["John", "Doe"]

[ "John", "Doe", "Was here!" ]

{ "First": "John", "Last": "Doe" "Notes": "Was here!" }

v2 v2

Avro: версионирование

[ "John", "Doe", "Was here!" ]

{ "First": "Jane", "Last": "Doe" }

v2 v1

Avro: версионирование

[ "Jane", "Doe" ]

{ "First": "Jane", "Last": "Doe" "Notes": "" }

v1 v2

Avro: версионирование

DOM?

SAX-подобный формат

ARRAY(3) John Doe Was here

{ "First": "John", "Last": "Doe" "Notes": "Was here!" }

["John", "Doe", "Was here!"]

DICT(3) First John Last Doe Notes Was here

ARRAY(3) John Doe Was here

DICT(3) First John Last Doe Notes Was here

CHECK in[0].type == ARRAY CHECK in[0].length == 3 CHECK in[1].type == STRING CHECK in[2].type == STRING CHECK in[3].type == STRING

out[0].type = DICT out[1].length = 3 out[2] = "First" out[3] = in[1] out[4] = "Last" out[5] = in[2] out[6] = "Notes" out[7] = in[3]

RPS (×1000)

500

1000

1500

2000

2500

3000

3500

Baseline (C) Codegen (LuaJIT) Codegen (LLVM)

v1v2

v3 v4

v5

LuaJIT

LLVM

%

0 25 50 75 100

Program Decode Encode

Final Takeaway• any sufficiently complicated C program contains …

an implementation of half of Common Lisp — Greenspun’s 10th rule

• Lua — современный и высокоуровневый

• работает быстро, легко встраивается

Ссылки• http://luajit.org/list.html

• Vyacheslav Egorov: What I learned from LUAJIT https://youtu.be/EaLboOUG9VQ

• terralang.org

• Андрей Дроздов: Хранение json-документов в Tarantool

• Дмитрий Стогов: Развитие ветки PHP-7 https://youtu.be/WIcdjJbFuCs

HighLoad, 8 окт. 18:00

HighLoad, 8 окт. 12:00

Вопросы?

NICK ZAVARITSKY [email protected]