Юрий Ефимочев, Компилируемые в реальном времени dsl для...
TRANSCRIPT
![Page 1: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/1.jpg)
Компилируемые в реальном времени DSL для С++
Юрий Ефимочев
![Page 2: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/2.jpg)
О себе
Архитектор в LogicNowСпециализация: высоконагруженные отказоустойчивые системы на C++
Бэкап-решение
![Page 3: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/3.jpg)
Что такое DSL?
Domain-specific language - это язык программирования с ограниченными возможностями, ориентированный на конкретную предметную область.
![Page 4: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/4.jpg)
Плюсы DSL
➢ управление сложностью➢ скорость разработки➢ комуникация с экспертами➢ альтернативные парадигмы➢ динамическое выполнение
![Page 5: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/5.jpg)
Минусы DSL
➢ порог вхождения
➢ эволюция в язык общего назначения
➢ разработка и поддержка
![Page 6: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/6.jpg)
Классификация DSL
➢ Внешние
➢ Внутренние
![Page 7: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/7.jpg)
Внутренний DSLGiven(
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 8: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/8.jpg)
Классификация DSL
➢ Интерпретируемые
➢ Компилируемые
![Page 9: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/9.jpg)
Архитектура DSL
ПрограмманаDSL
Семантическаямодель
Целевойкод
Опционально
![Page 10: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/10.jpg)
Архитектура бэкап-решения
Cloudstorage
Support
Integration
Customers
Development
Sales
Finances
BackupclientBackupclientBackupclientBackupclient
~ 100 000 клиентов
~ 500 параметров у каждого
![Page 11: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/11.jpg)
Примеры запросов
Count(true)
Sum(UsedStorage)
Count(LastSession.Timestamp < 2.days().ago())
Count(LastSession.Status == SessionStatus::Failed)
Average(LastSession.Duration)
![Page 12: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/12.jpg)
Архитектура решения
Expression AST Result
Data
![Page 13: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/13.jpg)
Синтаксический анализ
Flex & Bison
Antlr
boost::Spirit
![Page 14: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/14.jpg)
Bison: грамматика
%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 15: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/15.jpg)
AST
Count(time > 2.days().ago())Count
time ago
days
2
>
x.ago() = now - x
![Page 16: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/16.jpg)
AST
Count(time > 2.days().ago())Count
time -
days
2
>
x.ago() = now - x
x.days() = x * 86400 now
![Page 17: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/17.jpg)
AST
Count(time > 2.days().ago())Count
time -
*
86400
>
x.ago() = now - x
x.days() = x * 86400 now
2
![Page 18: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/18.jpg)
Реализация объектов AST
1 class IntegerNode : public IAstNode 2 { 3 public: 4 IntegerNode(int const value) : 5 m_value(value) 6 { 7 } 8 9 private:10 virtual Variant Evaluate(IDataProvider& /*dataProvider*/) const11 {12 return Variant(m_value);13 }1415 int const m_value;16 };
![Page 19: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/19.jpg)
Реализация объектов AST
1 class VariableNode : public IAstNode 2 { 3 public: 4 VariableNode(std::string const& name) : 5 m_name(name) 6 { 7 } 8 9 private:10 virtual Variant Evaluate(IDataProvider& dataProvider) const11 {12 return Variant(dataProvider.GetVariableValue(m_name));13 }1415 private:16 std::string const m_name;17 };
![Page 20: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/20.jpg)
Реализация объектов AST
1 class AddNode : public IAstNode 2 { 3 public: 4 AddNode(IAstNodePtr left, IAstNodePtr right) : 5 m_left(std::move(left)), 6 m_right(std::move(right)) 7 { 8 } 910 private:11 virtual Variant Evaluate(IDataProvider& dataProvider) const12 {13 return m_left->Compile(dataProvider) + m_right->Compile(dataProvider);14 }1516 private:17 IAstNodePtr m_left;18 IAstNodePtr m_right;19 };
![Page 21: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/21.jpg)
Итоги: первая версия
Плюсы:
➢ простота использования➢ скорость разработки➢ простота реализации
Минусы:
➢ производительность
![Page 22: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/22.jpg)
AST
Count(time > 2.days().ago())Count
time -
*
86400
>
now
2
![Page 23: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/23.jpg)
Архитектура LLVM
![Page 24: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/24.jpg)
Что такое LLVM IR?LLVM IR(Intermediate representation) - апаратно независимый низкоуровневый язык прогрммирования.
![Page 25: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/25.jpg)
LLVM IR
i1, … ,i32, … , i1942652 Целочисленные типы
half, float, double Типы с плавающей точкой
[40 x i32] Массивы
<4 x i32> Векторы (SIMD)
{ i32, i32, i32 } Структуры
i32*, [4 x i32]* Указатили
➢ функции
➢ типы данных(статическая строгая типизация)
➢ платформонезависимый
➢ SSA(static single assignment) нотация
![Page 26: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/26.jpg)
LLVM IR 1 bool MoveNext(); 2 int GetValue(); 3 4 int main() 5 { 6 int sum = 0; 7 8 while (MoveNext()) 9 {10 sum += GetValue();11 }1213 return sum;14 }
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 27: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/27.jpg)
Архитектура решения
Expression AST LLVM IR AST
Native code
Data descriptor
Data provider
Result
Data
![Page 28: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/28.jpg)
1 class Expression 2 { 3 public: 4 Expression(std::string const& expression); 5 6 std::int64_t Evaluate(IDataProvider& dataProvider); 7 8 private: 9 typedef std::int64_t(*CompiledExpression)();1011 LLVMContext m_llvmContext;12 ExecutionEnginePtr m_executionEngine;13 CompiledExpression m_expression;14 ExecutionContext m_executionContext;15 };
Реализация
![Page 29: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/29.jpg)
1 std::int64_t Expression::Evaluate(IDataProvider& dataProvider) 2 { 3 m_executionContext.Reset(dataProvider); 4 5 std::int64_t const result = m_expression(); 6 7 m_executionContext.ThrowIfError(); 8 9 return result;10 }
Реализация
![Page 30: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/30.jpg)
1 Expression::Expression(std::string const& expression) 2 { 3 IAstNodePtr astTree = BuildAst(expression); 4 5 IRBuilder builder(m_llvmContext); 6 Module* module = new Module("module", m_llvmContext); 7 8 m_executionEngine.reset(ExecutionEngine::createJIT(module)); 910 FunctionType* mainType = FunctionType::get(builder.getInt64Ty(), Arguments(), false);11 Function* main = Function::Create(mainType, Function::ExternalLinkage, "main", module);12 BasicBlock* mainEntry = BasicBlock::Create(m_llvmContext, "entry", main);1314 builder.SetInsertPoint(mainEntry);1516 CompilationContext compilationContext(builder, *m_executionEngine, m_executionContext, module);17 Value* returnValue = astTree->Compile(compilationContext);18 builder.CreateRet(returnValue);1920 m_expression = reinterpret_cast<CompiledExpression>(m_executionEngine->getPointerToFunction(main));21 }
Реализация
![Page 31: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/31.jpg)
Реализация: константы 1 class IntegerNode : public IAstNode 2 { 3 public: 4 IntegerNode(int const value) : 5 m_value(value) 6 { 7 } 8 9 private:10 virtual Value* Compile(IDataProvider& context) const11 {12 return context.GetBuilder().getInt64(m_value);13 }1415 int const m_value;16 };
![Page 32: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/32.jpg)
Реализация: сложение 1 class AddNode : public IAstNode 2 { 3 public: 4 AddNode(IAstNodePtr left, IAstNodePtr right) : 5 m_left(std::move(left)), 6 m_right(std::move(right)) 7 { 8 } 910 private:11 virtual Value* Compile(ICompilationContext& context) const12 {13 Value* left = m_left->Compile(context);14 Value* right = m_right->Compile(context);15 return context.GetBuilder().CreateAdd(left, right);16 }1718 private:19 IAstNodePtr m_left;20 IAstNodePtr m_right;21 };
![Page 33: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/33.jpg)
Реализация: переменные 1 class VariableNode : public IAstNode 2 { 3 public: 4 VariableNode(std::string const& name) : 5 m_name(name) 6 { 7 } 8 9 private: 10 virtual Value* Compile(ICompilationContext& context) const 11 { 12 return context.GetHelper().GetVariable(m_name); 13 } 14 15 private: 16 std::string const m_name; 17 };
![Page 34: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/34.jpg)
Реализация: переменные 1 extern "C" std::int64_t GetVariableValue(std::int64_t const context, char const* const variableName) 2 { 3 ExecutionContext& executionContext = *reinterpret_cast<ExecutionContext*>(context); 4 std::int64_t const result = executionContext.GetVariableValue(variableName); 5 return result; 6 } 7 8 Value* LlvmHelper::GetVariable(std::string const& name) 9 {10 Value*& variable = m_variables[name];1112 if (variable == nullptr)13 {14 Function* llvmFunction = Export("get_value", &GetVariableValue);15 variable = Call(llvmFunction, &m_executionContext, name);16 }1718 return variable;19 }
![Page 35: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/35.jpg)
Реализация: переменные 1 template<typename ReturnType, typename... ArgumentTypes> 2 Function* LlvmHelper::Export(std::string const& name, ReturnType (*nativeFunction)(ArgumentTypes...)) 3 { 4 std::vector<Type*> llvmArgumentTypes = { (GetLlvmType<ArgumentTypes>())... }; 5 Type* llvmReturnType = GetLlvmType<ReturnType>(); 6 7 Function* function = Function::Create(functionType, Function::ExternalLinkage, name, m_module); 8 function->setCallingConv(llvm::CallingConv::C); 910 m_executionEngine.addGlobalMapping(function, (void*)nativeFunction);1112 return function;13 }1415 template<typename... ArgumentTypes>16 Value* LlvmHelper::Call(Function* llvmFunction, Arguments... arguments)17 {18 std::vector<Value*> llvmArguments = { (ToLlvmValue(arguments))... };19 return m_builder.CreateCall(llvmFunction, llvmArguments);20 }
![Page 36: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/36.jpg)
Реализация: отрицание
1 Value* NotNode::Compile(ICompilationContext& context) const 2 { 3 CompiledNode child = m_value->Compile(context); 4 5 IRBuilder& builder = context.GetBuilder(); 6 7 Value* one = builder.getInt64(1); 8 Value* zero = builder.getInt64(0); 9 Value* notEqualZero = builder.CreateICmpNE(zero, child.Value); 10 notEqualZero = builder.CreateZExt(notEqualZero, builder.getInt64Ty()); 11 12 Value* value = builder.CreateXor(one, nonEqualZero); 13 value = builder.CreateZExt(value, builder.getInt64Ty()); 14 15 return value; 16 }
not x == 1 xor (x != 0)
![Page 37: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/37.jpg)
ПроизводительностьCount(x < 50 && x > 22 || x == 77), size = 1000000
Interpreted 1734 мс
LLVM 31 мс
Native 21 мс
![Page 38: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/38.jpg)
Кодогенерация
LLVM
Google V8
Lua
![Page 39: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/39.jpg)
ПроизводительностьCount(x < 50 && x > 22 || x == 77), size = 1000000
Interpreted 1734 мс
V8 402 мс
Lua 309 мс
LLVM 31 мс
Native 21 мс
![Page 40: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/40.jpg)
Итоги: вторая версия
Плюсы:
➢ простота использования➢ скорость разработки➢ производительность
![Page 41: Юрий Ефимочев, Компилируемые в реальном времени DSL для С++](https://reader034.vdocuments.net/reader034/viewer/2022051404/586fb21c1a28abe57d8b677b/html5/thumbnails/41.jpg)
Итоги: вторая версия
Минусы:
➢ размер бинарного файла (~ 15 Mb)➢ сложность реализации➢ нативный код