30
Компилируемые в реальном времени DSL для С++ Юрий Ефимочев

Dsl for c++

Embed Size (px)

Citation preview

Page 1: Dsl for c++

Компилируемые в реальном времени DSL

для С++

Юрий Ефимочев

Page 2: Dsl for c++

О себе

Архитектор в LogicNowСпециализация: высоконагруженные отказоустойчивые системы на C++

Бэкап-решение

Page 3: Dsl for c++

Что такое DSL?Domain-specific language - это язык программирования с ограниченными возможностями, ориентированный на конкретную предметную область.

Page 4: Dsl for c++

Достоинства и недостатки DSLДостоинства: • управление сложностью • скорость разработки • комуникация с экспертами • альтернативные парадигмы • динамическое выполнение Недостатки: • порог вхождения • эволюция в язык общего назначения • разработка и поддержка

Page 5: Dsl for c++

Классификация DSL

• Внутренние• Внешние • Визуальные

• Интерпретируемые

• Компилируемые

Page 6: Dsl for c++

Пример: тестированиеGiven( Node("a") (Node("b") (Node("c")) (Node("d"))) (Node("e") (Node("f")) (Node("g"))));

When().Filter("%f%");

Expect( Node("a") (Node("e") (Node("f"))));

a

b

c d

e

f g

a

e

f

Page 7: Dsl for c++

Архитектура DSL

Программа

наDSL

Семантическаямодель

Целевойкод

Опционально

Page 8: Dsl for c++

Постановка задачиДано:

~ 100 000 объектов

~ 500 параметров у объекта

Требуется:

получение актуальной статистики по произвольной выборке объектов

Page 9: Dsl for c++

Примеры запросов

Count(true)

Count(LastSession.Timestamp < 2.days().ago())

Count(Version like ‘15.12.%’)

Count(LastSession.Status == SessionStatus::Failed)

Average(LastSession.Duration)

Sum(UsedStorage)

Page 10: Dsl for c++

Архитектура решения

Expression AST Result

Data

Page 11: Dsl for c++

Синтаксический анализ

Инструментарий:• flex & bison• antlr• boost::spirit

Page 12: Dsl for c++

Синтаксический анализ%start Start;

AtomicExpression:IntegerNumber { $$.Value = m_builder.CreateInteger($1.Name); } |Identifier { $$.Value = m_builder.CreateVariable($1.Name) };

AddSubExpression:AtomicExpression |AddSubExpression Plus AddSubExpression { m_builder.CreateAddNode(...); } |AddSubExpression Minus AddSubExpression { m_builder.CreateSubNode(...); };

Start:AddSubExpression { result.AstTree.reset($1.Value); };

Page 13: Dsl for c++

AST

Count(time > 2.days().ago()) Count

time ago

days

2

>

2.days().ago() = now - 2.days()

2.days() = 2 * 86400

Page 14: Dsl for c++

AST

Count(time > 2.days().ago()) Count

time -

*

86400

>

now

2.days().ago() = now - 2.days()

2.days() = 2 * 864002

Page 15: Dsl for c++

Реализация объектов AST class IntegerNode : public IAstNode { public: IntegerNode(int const value) : m_value(value) { }

private: virtual Variant Compile(IDataProvider& /*dataProvider*/) const { return Variant(m_value); }

int const m_value; };

Page 16: Dsl for c++

Реализация объектов AST class VariableNode : public IAstNode { public: VariableNode(std::string const& name) : m_name(name) { }

private: virtual Variant Compile(IDataProvider& dataProvider) const { return Variant(dataProvider.GetVariableValue(m_name)); }

private: std::string const m_name; };

Page 17: Dsl for c++

Реализация объектов AST class AddNode : public IAstNode { public: AddNode(IAstNodePtr left, IAstNodePtr right) : m_left(std::move(left)), m_right(std::move(right)) { }

private: virtual Variant Compile(IDataProvider& dataProvider) const { return m_left->Compile(dataProvider) + m_right->Compile(dataProvider); }

private: IAstNodePtr m_left; IAstNodePtr m_right;};

Page 18: Dsl for c++

AST

Count(time > 2.days().ago()) Count

time -

*

86400

>

now

2.days().ago() = now - 2.days()

2.days() = 2 * 864002

Page 19: Dsl for c++

Архитектура LLVM

Page 20: Dsl for c++

Что такое LLVM IR?Особенности: • обобщенная система команд • функции • типы данных

• простые типы• указатели • массивы

• статическая типизация • SSA(static single assignment) нотация

Page 21: Dsl for c++

LLVM IR bool MoveNext(); int GetValue();

int main() { int sum = 0;

while (MoveNext()) { sum += GetValue(); }

return sum; }

1 declare i1 @move_next() 2 declare i64 @get_value() 3 4 define i64 @main() 5 { 6 entry: 7 br label %loop_condition 8 9 loop_condition: 10 %1 = phi i64 [ 0, %entry ], [ %4, %loop_body ] 11 %2 = call i1 @move_next() 12 br i1 %2, label %loop_body, label %loop_exit 13 14 loop_body: 15 %3 = call i64 @get_value() 16 %4 = add i64 %3, %1 17 br label %loop_condition 18 19 loop_exit: 20 ret i64 %1 21 }

Page 22: Dsl for c++

Архитектура решения

Expression AST LLVM IR AST

Native code

Data descriptor

Data provider

Result

Data

Page 23: Dsl for c++

Реализация AST class IntegerNode : public IAstNode { public: IntegerNode(int const value) : m_value(value) { }

private: virtual CompiledNode Compile(IDataProvider& context) const { return CompiledNode(DataType::Integer, context.GetBuilder().getInt64(m_value)); }

int const m_value; };

Page 24: Dsl for c++

Реализация AST class VariableNode : public IAstNode { public: VariableNode(std::string const& name) : m_name(name) { }

private: virtual CompiledNode Compile(ICompilationContext& context) const { return context.GetVariable(m_name); }

private: std::string const m_name; };

Page 25: Dsl for c++

Реализация AST class AddNode : public IAstNode { public: AddNode(IAstNodePtr left, IAstNodePtr right) : m_left(std::move(left)), m_right(std::move(right)) { }

private: virtual CompiledNode Compile(ICompilationContext& context) const { CompiledNode left = m_left->Compile(context); CompiledNode right = m_right->Compile(context); DataType::Enum const effectiveType = GetEffectiveType(left, right); return CompiledNode(effectiveType, context.GetBuilder().CreateAdd(left, right)); }

private: IAstNodePtr m_left; IAstNodePtr m_right;};

Page 26: Dsl for c++

Производительность

Interpreted 1734 мсLLVM 31 мсLLVM(precompiled) 28 мсNative 21 мс

Count(x < 50 && x > 22 || x == 77), size = 1000000

Page 27: Dsl for c++

Кодогенерация

Инструментарий:• LLVM• Lua• Chrome V8

Page 28: Dsl for c++

Производительность

Interpreted 1734 мсLua 309 мсLua(precompiled) 276 мсLLVM 31 мсLLVM(precompiled) 28 мсNative 21 мс

Count(x < 50 && x > 22 || x == 77), size = 1000000

Page 29: Dsl for c++

Итоги

Плюсы:• простота• скорость разработки• Производительность

Минусы:• размер бинарного файла (~ 15 Mb)• реализация местами сложна• нативный код

Page 30: Dsl for c++

?