openGauss源码解析(137)
openGauss源码解析:执行器解析(30)
openGauss GodeGen的整体编译流程如图7-25所示。
图7-25 openGauss CodeGen编译执行流程
数据库启动后,首先对LLVM初始化,其中CodeGenProcessInitialize函数对LLVM的环境进行初始化,包括通过isCPUFeatureSupportCodegen函数和canInitCodegenInvironment函数检查CPU是否支持CodeGen、是否能够进行环境初始化。然后通过“GsCodeGen::InitializeLlvm”函数对本地环境检查,检查环境是否为Aarch64或x86架构,并返回全局变量gscodegen_initialized。
CodeGenThreadInitialize函数在本线程中创建一个新的GsCodeGen对象,并创建内存。如果创建失败,要返回原来的内存上下文给系统,当前线程中codegen的部分保存在knl_t_codegen_context中,具体结构代码为:
typedef struct knl_t_codegen_context {
void* thr_codegen_obj;
bool g_runningInFmgr;
long codegen_IRload_thr_count;
} knl_t_codegen_context;
其中thr_codegen_obj字段保存代码中LLVM对象,在初始化和调用时通常转换成GsCodeGen类,GsCodeGen保存了LLVM全部封装好的LLVM函数、内存和成员变量等。g_runningInFmgr字段表示函数是否运行在function manager中。codegen_IRload_thr_count字段是IR载入计数。
当所有的LLVM执行环境设置完成后,执行器初始化阶段可根据解析器和优化器提供的查询计划去检查当前的计划是否可以进行LLVM代码生成优化。以gsql客户端为例,整个运行过程内嵌在执行引擎运行过程内,函数的调用从函数exec_simple_plan函数为入口,LLVM运行的3个阶段分别对应executor的3个阶段:ExecutorStart、ExecutorRun以及ExecutorEnd(从其他客户端输入的查询,最终也会走到ExecutorStart、ExecutorRun以及ExecutorEnd阶段)。
(1) ExecutorStart阶段:为运行准备阶段,初始化查询级别的GsCodeGen类对象,并在InitPlan阶段按照优化器产生的执行计划遍历其中各个算子节点初始化函数,生成IR函数。
(2) ExecutorRun阶段:为运行阶段,若已成功生成LLVM IR函数,则对该IR函数进行编译,生成可执行的机器码,并在具体的算子运行阶段用机器码替换到原本的执行函数入口。
(3) ExecutorEnd阶段:为运行完清理环境阶段,在ExecutorEnd函数中将第一阶段生成的LLVMCodeGen对象及其相关资源进行释放。
GsCodeGen的接口定义在文件“codegen/gscodegen.h”中,GsCodeGen中接口说明如表7-31所示。
表7-31 GsCodeGen接口汇总
接口名称 |
接口类型 |
职责描述 |
---|---|---|
initialize |
API |
分配Codegen使用内存使用环境 |
InitializeLLVM |
API |
初始化LLVM运行环境 |
parseIRFile |
API |
解析IR文件 |
cleanupLlvm |
API |
停止LLVM调用线程 |
createNewModule |
API |
创建一个新的LLVM模板 |
compileCurrentModule |
API |
编译当前指定LLVM模块中的函数 |
compileModule |
API |
编译模板并依据相关选项对模板中未用的IR函数进行优化 |
releaseResource |
API |
释放LLVM模块占用的系统资源 |
FinalizeFunction |
API |
确定最后的IR函数是否可用 |
getType |
API |
从openGauss的类型转换到LLVM内部对应的类型 |
verifyFunction |
API |
检查输入的LLVM IR函数的有效性 |
getPtrType |
API |
从openGauss的类型转换到LLVM内部对应该类型的指针类型 |
castPtrToLlvmPtr |
API |
将openGauss的指针转换为LLVM的指针 |
getIntConstant |
API |
将openGauss对应类型的常数转换为LLVM对应类型的常数 |
generatePrototype |
API |
创建要加入当前LLVM模块的函数原型 |
replaceCallSites |
API |
替换LLVM当前模块的函数 |
optimizeModule |
API |
优化LLVM当前模块中的函数 |
addFunctionToMCJit |
API |
外部函数调用接口 |
canInitCodegenInvironment |
API |
判断当前可否初始化CodeGen环境 |
canInitThreadCodeGen |
API |
判断当前可否初始化CodeGen线程 |
CodeGenReleaseResource |
API |
删除当前模板和LLVM执行引擎 |
CodeGenProcessInitialize |
API |
初始化LLVM服务进程 |
CodeGenThreadInitilize |
API |
初始化LLVM服务线程 |
CodeGenThreadRuntimeSetup |
API |
初始化LLVM服务对象 |
CodeGenThreadRuntimeCodeGenerate |
API |
编译当前LLVM模板中的IR函数 |
CodeGenThreadTearDown |
API |
释放LLVM模块占用的系统资源接口 |
CodeGenThreadObjectReady |
API |
判断当前LLVM服务对象是否有效 |
CodeGenThreadReset |
API |
清空当前内存中的机器码 |
CodeGenPassThreshold |
API |
根据返回行数判断是否需要CodeGen |