赞
踩
jit_enabled
打开 且 生成计划成本超过jit_above_cost
启动JIT
。
jit_optimize_above_cost
,执行PGJIT_OPT3
使用O3对IR进行优化。jit_inline_above_cost
,执行PGJIT_INLINE
。jit_expressions
开关如果打开,执行PGJIT_EXPR
表达式优化。jit_tuple_deforming
开关如果打开,执行PGJIT_DEFORM
优化拆解元组流程。standard_planner ... ... result->jitFlags = PGJIT_NONE; if (jit_enabled && jit_above_cost >= 0 && top_plan->total_cost > jit_above_cost) { result->jitFlags |= PGJIT_PERFORM; /* * Decide how much effort should be put into generating better code. */ if (jit_optimize_above_cost >= 0 && top_plan->total_cost > jit_optimize_above_cost) result->jitFlags |= PGJIT_OPT3; if (jit_inline_above_cost >= 0 && top_plan->total_cost > jit_inline_above_cost) result->jitFlags |= PGJIT_INLINE; /* * Decide which operations should be JITed. */ if (jit_expressions) result->jitFlags |= PGJIT_EXPR; if (jit_tuple_deforming) result->jitFlags |= PGJIT_DEFORM; }
《Postgresql源码(113)表达式JIT计算简单分析》
#0 jit_compile_expr (state=0x1deae18) at jit.c:180
#1 0x000000000071fa6b in ExecReadyExpr (state=0x1deae18) at execExpr.c:874
#2 0x000000000071e60b in ExecInitExpr (node=0x1dfabb8, parent=0x0) at execExpr.c:152
#3 0x00000000008b3395 in evaluate_expr (expr=0x1dfabb8, result_type=23, result_typmod=-1, result_collation=0) at clauses.c:4892
#4 0x00000000008b26f8 in evaluate_function (funcid=1397, result_type=23, result_typmod=-1, result_collid=0, input_collid=0, args=0x1dfab68, funcvariadic=false, func_tuple=0x7fd9588871a8, context=0x7ffdd8867f20) at clauses.c:4409
...
jit_compile_expr
provider_init
load_external_function(path, "_PG_jit_provider_init", true, NULL)
dlopen动态加载llvmjit.so,并调用so中的_PG_jit_provider_init
初始化:
void
_PG_jit_provider_init(JitProviderCallbacks *cb)
{
cb->reset_after_error = llvm_reset_after_error;
cb->release_context = llvm_release_context;
cb->compile_expr = llvm_compile_expr;
}
为provider配置入口函数:
typedef struct JitProviderCallbacks JitProviderCallbacks;
struct JitProviderCallbacks
{
JitProviderResetAfterErrorCB reset_after_error;
JitProviderReleaseContextCB release_context;
JitProviderCompileExprCB compile_expr;
};
static JitProviderCallbacks provider;
jit_compile_expr继续调用hook:provider.compile_expr进入llvm逻辑:
jit_compile_expr
provider_init
provider.compile_expr(state) -> llvm_compile_expr
llvm_create_context
初始化生成LLVMJitContext
结构:
typedef struct JitContext { /* see PGJIT_* above */ int flags; ResourceOwner resowner; JitInstrumentation instr; } JitContext; typedef struct LLVMJitContext { JitContext base; // 上面的JIT FLAG、ResourceOwner size_t module_generation; // 当前context存了几个Module? LLVMModuleRef module; // 当前正在使用的module bool compiled; // 已经编译过了? List *handles; // 所有挂在当前context下的module } LLVMJitContext;
llvm_create_context
初始化流程
llvm_create_context llvm_session_initialize 【库函数】LLVMInitializeNativeTarget 【库函数】LLVMInitializeNativeAsmPrinter 【库函数】LLVMInitializeNativeAsmParser 【库函数】LLVMContextSetOpaquePointers 读取llvmjit_types.bc中需要的类型、函数签名:llvm_create_types LLVMCreateMemoryBufferWithContentsOfFile LLVMParseBitcode2 LLVMDisposeMemoryBuffer 【库函数】LLVMGetTargetFromTriple ... 【库函数】LLVMLoadLibraryPermanently llvm_ts_context = LLVMOrcCreateNewThreadSafeContext llvm_opt0_orc = llvm_create_jit_instance 【库函数】若干 传入机器信息,构造LLVMJIT环境 【库函数】若干 LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine 【库函数】若干 LLVMOrcCreateLLJIT llvm_opt3_orc = llvm_create_jit_instance 【库函数】若干 传入机器信息,构造LLVMJIT环境 【库函数】若干 LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine 【库函数】若干 LLVMOrcCreateLLJIT ResourceOwnerEnlargeJIT
从llvmjit_types.bc
读取的类型、函数
/* * Load triple & layout from clang emitted file so we're guaranteed to be * compatible. */ llvm_triple = pstrdup(LLVMGetTarget(llvm_types_module)); llvm_layout = pstrdup(LLVMGetDataLayoutStr(llvm_types_module)); TypeSizeT = llvm_pg_var_type("TypeSizeT"); TypeParamBool = load_return_type(llvm_types_module, "FunctionReturningBool"); TypeStorageBool = llvm_pg_var_type("TypeStorageBool"); TypePGFunction = llvm_pg_var_type("TypePGFunction"); StructNullableDatum = llvm_pg_var_type("StructNullableDatum"); StructExprContext = llvm_pg_var_type("StructExprContext"); StructExprEvalStep = llvm_pg_var_type("StructExprEvalStep"); StructExprState = llvm_pg_var_type("StructExprState"); StructFunctionCallInfoData = llvm_pg_var_type("StructFunctionCallInfoData"); StructMemoryContextData = llvm_pg_var_type("StructMemoryContextData"); StructTupleTableSlot = llvm_pg_var_type("StructTupleTableSlot"); StructHeapTupleTableSlot = llvm_pg_var_type("StructHeapTupleTableSlot"); StructMinimalTupleTableSlot = llvm_pg_var_type("StructMinimalTupleTableSlot"); StructHeapTupleData = llvm_pg_var_type("StructHeapTupleData"); StructTupleDescData = llvm_pg_var_type("StructTupleDescData"); StructAggState = llvm_pg_var_type("StructAggState"); StructAggStatePerGroupData = llvm_pg_var_type("StructAggStatePerGroupData"); StructAggStatePerTransData = llvm_pg_var_type("StructAggStatePerTransData"); AttributeTemplate = LLVMGetNamedFunction(llvm_types_module, "AttributeTemplate");
读取到的所有类型、函数指针等记录在全局变量llvm_types_module中,用llvm_pg_var_type等函数调用LLVM库函数转换为LLVM能识别的类型、函数。
创建Module需要的llvm_triple、llvm_layout都来自llvm_create_types
函数,读取llvmjit_types.bc
拿到的信息。
LLVMModuleRef llvm_mutable_module(LLVMJitContext *context) { llvm_assert_in_fatal_section(); /* * If there's no in-progress module, create a new one. */ if (!context->module) { context->compiled = false; context->module_generation = llvm_generation++; context->module = LLVMModuleCreateWithName("pg"); LLVMSetTarget(context->module, llvm_triple); LLVMSetDataLayout(context->module, llvm_layout); } return context->module; }
llvm_compile_expr
新增函数到module
eval_fn = LLVMAddFunction(mod, funcname,
llvm_pg_var_func_type("TypeExprStateEvalFunc"));
函数中加BB
entry = LLVMAppendBasicBlock(eval_fn, "entry");
按表达式分支逻辑为BB添加代码
case EEOP_FUNCEXPR_STRICT: { FunctionCallInfo fcinfo = op->d.func.fcinfo_data; LLVMValueRef v_fcinfo_isnull; LLVMValueRef v_retval; if (opcode == EEOP_FUNCEXPR_STRICT) { LLVMBasicBlockRef b_nonull; LLVMBasicBlockRef *b_checkargnulls; LLVMValueRef v_fcinfo; /* * Block for the actual function call, if args are * non-NULL. */ b_nonull = l_bb_before_v(opblocks[opno + 1], "b.%d.no-null-args", opno); /* should make sure they're optimized beforehand */ if (op->d.func.nargs == 0) elog(ERROR, "argumentless strict functions are pointless"); v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData)); /* * set resnull to true, if the function is actually * called, it'll be reset */ LLVMBuildStore(b, l_sbool_const(1), v_resnullp); /* create blocks for checking args, one for each */ b_checkargnulls = palloc(sizeof(LLVMBasicBlockRef *) * op->d.func.nargs); for (int argno = 0; argno < op->d.func.nargs; argno++) b_checkargnulls[argno] = l_bb_before_v(b_nonull, "b.%d.isnull.%d", opno, argno); /* jump to check of first argument */ LLVMBuildBr(b, b_checkargnulls[0]); /* check each arg for NULLness */ for (int argno = 0; argno < op->d.func.nargs; argno++) { LLVMValueRef v_argisnull; LLVMBasicBlockRef b_argnotnull; LLVMPositionBuilderAtEnd(b, b_checkargnulls[argno]); /* * Compute block to jump to if argument is not * null. */ if (argno + 1 == op->d.func.nargs) b_argnotnull = b_nonull; else b_argnotnull = b_checkargnulls[argno + 1]; /* and finally load & check NULLness of arg */ v_argisnull = l_funcnull(b, v_fcinfo, argno); LLVMBuildCondBr(b, LLVMBuildICmp(b, LLVMIntEQ, v_argisnull, l_sbool_const(1), ""), opblocks[opno + 1], b_argnotnull); } LLVMPositionBuilderAtEnd(b, b_nonull); } v_retval = BuildV1Call(context, b, mod, fcinfo, &v_fcinfo_isnull); LLVMBuildStore(b, v_retval, v_resvaluep); LLVMBuildStore(b, v_fcinfo_isnull, v_resnullp); LLVMBuildBr(b, opblocks[opno + 1]); break; }
ExecRunCompiledExpr找到jit函数并执行,惰性编译、优化。
ExecRunCompiledExpr
llvm_get_function
重要:llvm_compile_module
LLVMOrcLLJITLookup
在找函数执行时,编译这一步是核心逻辑,编译会对上面逻辑进行优化处理:
llvm_compile_module
llvm_inline
llvm_optimize_module
优化一:llvm_inline
、llvm_build_inline_plan会
查询module里面的function,到函数目录查找对应的bc文件,并加载bc文件中函数的逻辑(增加LLVM编译后,所有源码文件都会用clang额外生成一个bc文件,提供给inline使用)。function_inlinable
函数会检查当前函数引用的其他函数时候能inline。
优化二:llvm_optimize_module
将IR过一遍PASS,下一篇继续分析后面的流程。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。